chitchatter/src/components/Room/Room.test.tsx
Jeremy Kahn 6cbfaacf1a
feat(verification): [closes #209] Verified peers (#216)
* refactor(bootstrap): add BootstrapShim
* feat(security): [#209] generate public/private keys
* refactor(encryption): move encryption utils to a service
* feat(encryption): [wip] implement convertCryptoKeyToString
* fix(user-settings): serialize crypto keys to strings
* feat(user-settings): deserialize user settings from IndexedDB
* feat(user-settings): upgrade persisted settings on boot
* feat(user-settings): automatically migrate persisted user settings
* refactor(encryption): simplify CryptoKey stringification
* refactor(encryption): DRY up EncryptionService
* feat(verification): send public key to new peers
* refactor(encryption): use class instance
* refactor(serialization): use class instance
* refactor(verification): [wip] create usePeerVerification hook
* feat(verification): encrypt verification token
* feat(verification): send encrypted token to peer
* feat(verification): verify peer
* refactor(verification): use enum for verification state
* feat(verification): expire verification requests
* fix(updatePeer): update with fresh state data
* feat(verification): display verification state
* refactor(usePeerVerification): store verification timer in Peer
* feat(verification): present tooltips explaining verification state
* feat(ui): show full page loading indicator
* feat(init): present bootup failure reasons
* refactor(init): move init to its own file
* feat(verification): show errors upon verification failure
* refactor(verification): move workaround to usePeerVerification
* feat(verification): present peer public keys
* refactor(verification): move peer public key rendering to its own component
* refactor(verification): only pass publicKey into renderer
* feat(verification): show user's own public key
* refactor(naming): rename Username to UserInfo
* refactor(loading): encapsulate height styling
* feat(verification): improve user messaging
* refactor(style): improve formatting and variable names
* feat(verification): add user info tooltip
* docs(verification): explain verification
2023-12-09 17:47:05 -06:00

150 lines
3.7 KiB
TypeScript

import { PropsWithChildren } from 'react'
import { waitFor, render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { MemoryRouter as Router, Route, Routes } from 'react-router-dom'
import { userSettingsContextStubFactory } from 'test-utils/stubs/settingsContext'
import { mockEncryptionService } from 'test-utils/mocks/mockEncryptionService'
import { SettingsContext } from 'contexts/SettingsContext'
import { Room, RoomProps } from './'
const mockUserId = 'user-id'
const mockRoomId = 'room-123'
const userSettingsStub = userSettingsContextStubFactory({
userId: mockUserId,
})
window.AudioContext = jest.fn().mockImplementation()
const mockGetUuid = jest.fn()
const mockMessagedSender = jest
.fn()
.mockImplementation(() => Promise.resolve([]))
jest.mock('trystero', () => ({
joinRoom: () => ({
makeAction: () => [mockMessagedSender, () => {}, () => {}],
ping: () => Promise.resolve(0),
leave: () => {},
getPeers: () => [],
addStream: () => [Promise.resolve()],
removeStream: () => {},
addTrack: () => [Promise.resolve()],
removeTrack: () => {},
replaceTrack: () => [Promise.resolve()],
onPeerJoin: () => {},
onPeerLeave: () => {},
onPeerStream: () => {},
onPeerTrack: () => {},
}),
}))
const RouteStub = ({ children }: PropsWithChildren) => {
return (
<Router initialEntries={['/public/abc123']}>
<SettingsContext.Provider value={userSettingsStub}>
<Routes>
<Route path="/public/:roomId" element={children}></Route>
</Routes>
</SettingsContext.Provider>
</Router>
)
}
jest.useFakeTimers().setSystemTime(100)
const RoomStub = (props: RoomProps) => {
return <Room encryptionService={mockEncryptionService} {...props} />
}
describe('Room', () => {
test('is available', () => {
render(
<RouteStub>
<RoomStub userId={mockUserId} roomId={mockRoomId} />
</RouteStub>
)
})
test('send button is disabled', () => {
render(
<RouteStub>
<RoomStub userId={mockUserId} roomId={mockRoomId} />
</RouteStub>
)
const sendButton = screen.getByLabelText('Send')
expect(sendButton).toBeDisabled()
})
test('inputting text enabled send button', async () => {
render(
<RouteStub>
<RoomStub userId={mockUserId} roomId={mockRoomId} />
</RouteStub>
)
const sendButton = screen.getByLabelText('Send')
const textInput = screen.getByPlaceholderText('Your message')
await waitFor(() => {
userEvent.type(textInput, 'hello')
})
expect(sendButton).not.toBeDisabled()
})
test('sending a message clears the text input', async () => {
render(
<RouteStub>
<RoomStub userId={mockUserId} roomId={mockRoomId} />
</RouteStub>
)
const sendButton = screen.getByLabelText('Send')
const textInput = screen.getByPlaceholderText('Your message')
await waitFor(() => {
userEvent.type(textInput, 'hello')
})
await waitFor(() => {
userEvent.click(sendButton)
})
expect(textInput).toHaveValue('')
})
test('message is sent to peer', async () => {
render(
<RouteStub>
<RoomStub
getUuid={mockGetUuid.mockImplementation(() => 'abc123')}
userId={mockUserId}
roomId={mockRoomId}
/>
</RouteStub>
)
const sendButton = screen.getByLabelText('Send')
const textInput = screen.getByPlaceholderText('Your message')
await waitFor(() => {
userEvent.type(textInput, 'hello')
})
await waitFor(() => {
userEvent.click(sendButton)
})
expect(mockMessagedSender).toHaveBeenCalledWith({
authorId: mockUserId,
text: 'hello',
timeSent: 100,
id: 'abc123',
})
})
})