cadfa70e60
* #708 apply strictier linting rules and fix simple eslint bugs * #708 fix eslint errors relate to promise * #708 fix eslint import/no-extraneous-dependencies * #708 fix eslint errors of react-hook * #708 enable eslint check for typescript --------- Co-authored-by: lethemanh <lethemanh@lethemanhs-MacBook-Pro.local>
220 lines
6.0 KiB
TypeScript
220 lines
6.0 KiB
TypeScript
import { ResourceSearch, Resource } from '@/components/Attendees/ResourceSearch'
|
|
import { searchUsers } from '@/features/User/userAPI'
|
|
import { act, screen, waitFor } from '@testing-library/react'
|
|
import userEvent from '@testing-library/user-event'
|
|
import { renderWithProviders } from '../utils/Renderwithproviders'
|
|
|
|
jest.mock('@/features/User/userAPI')
|
|
const mockedSearchUsers = searchUsers as jest.MockedFunction<typeof searchUsers>
|
|
|
|
describe('ResourceSearch', () => {
|
|
const baseResource: Resource = {
|
|
displayName: 'Projector Room'
|
|
}
|
|
|
|
function setup(
|
|
selectedResources: Resource[] = [],
|
|
props?: Partial<React.ComponentProps<typeof ResourceSearch>>
|
|
) {
|
|
const onChange = jest.fn()
|
|
renderWithProviders(
|
|
<ResourceSearch
|
|
objectTypes={['resource']}
|
|
selectedResources={selectedResources}
|
|
onChange={onChange}
|
|
{...props}
|
|
/>
|
|
)
|
|
return { onChange }
|
|
}
|
|
|
|
beforeEach(() => {
|
|
jest.useFakeTimers()
|
|
mockedSearchUsers.mockReset()
|
|
})
|
|
|
|
afterEach(() => {
|
|
jest.useRealTimers()
|
|
})
|
|
|
|
it('calls searchUsers after debounce when typing', async () => {
|
|
mockedSearchUsers.mockResolvedValueOnce([
|
|
baseResource
|
|
] as unknown as Awaited<ReturnType<typeof searchUsers>>)
|
|
setup()
|
|
|
|
const input = screen.getByRole('combobox')
|
|
await userEvent.type(input, 'Room')
|
|
await act(async () => {
|
|
jest.advanceTimersByTime(300)
|
|
})
|
|
|
|
await waitFor(() => {
|
|
expect(mockedSearchUsers).toHaveBeenCalledWith('Room', ['resource'])
|
|
})
|
|
})
|
|
|
|
it('renders search results and allows selection', async () => {
|
|
mockedSearchUsers.mockResolvedValueOnce([
|
|
baseResource
|
|
] as unknown as Awaited<ReturnType<typeof searchUsers>>)
|
|
const { onChange } = setup()
|
|
|
|
const input = screen.getByRole('combobox')
|
|
await userEvent.type(input, 'Room')
|
|
await act(async () => {
|
|
jest.advanceTimersByTime(300)
|
|
})
|
|
|
|
const option = await screen.findByText('Projector Room')
|
|
await userEvent.click(option)
|
|
|
|
await waitFor(() => {
|
|
expect(onChange).toHaveBeenCalled()
|
|
})
|
|
})
|
|
|
|
it('does not show already selected resources in options', async () => {
|
|
mockedSearchUsers.mockResolvedValueOnce([
|
|
baseResource
|
|
] as unknown as Awaited<ReturnType<typeof searchUsers>>)
|
|
setup([baseResource])
|
|
const input = screen.getByRole('combobox')
|
|
await userEvent.type(input, 'Projector')
|
|
await act(async () => {
|
|
jest.advanceTimersByTime(300)
|
|
})
|
|
|
|
await waitFor(() => {
|
|
// It shouldn't be in the dropdown options anymore
|
|
const options = screen.queryAllByRole('option')
|
|
expect(
|
|
options.find(opt => opt.textContent === 'Projector Room')
|
|
).toBeUndefined()
|
|
})
|
|
})
|
|
|
|
it('respects disabled state', () => {
|
|
setup([], { disabled: true })
|
|
expect(screen.getByRole('combobox')).toBeDisabled()
|
|
})
|
|
|
|
it("no options doesn't show dropdown when input is empty", async () => {
|
|
mockedSearchUsers.mockResolvedValueOnce([
|
|
baseResource
|
|
] as unknown as Awaited<ReturnType<typeof searchUsers>>)
|
|
setup()
|
|
const input = screen.getByRole('combobox')
|
|
|
|
await userEvent.type(input, 'Room')
|
|
await act(async () => {
|
|
jest.advanceTimersByTime(300)
|
|
})
|
|
|
|
await waitFor(() => {
|
|
expect(screen.getByRole('listbox')).toBeInTheDocument()
|
|
})
|
|
|
|
await userEvent.clear(input)
|
|
|
|
await waitFor(() => {
|
|
expect(screen.queryByRole('listbox')).not.toBeInTheDocument()
|
|
})
|
|
})
|
|
|
|
it("shows 'No results' when search succeeds but returns empty array", async () => {
|
|
mockedSearchUsers.mockResolvedValueOnce([])
|
|
setup()
|
|
|
|
const input = screen.getByRole('combobox')
|
|
await userEvent.type(input, 'Room')
|
|
|
|
await act(async () => {
|
|
jest.advanceTimersByTime(300)
|
|
await Promise.resolve()
|
|
await Promise.resolve()
|
|
})
|
|
|
|
const noResults = await screen.findByText(
|
|
'resourceSearch.noResults',
|
|
{},
|
|
{ timeout: 5000 }
|
|
)
|
|
expect(noResults).toBeInTheDocument()
|
|
})
|
|
|
|
it('clears options when search fails and shows error snackbar', async () => {
|
|
mockedSearchUsers.mockResolvedValueOnce([
|
|
baseResource
|
|
] as unknown as Awaited<ReturnType<typeof searchUsers>>)
|
|
setup()
|
|
|
|
const input = screen.getByRole('combobox')
|
|
await userEvent.type(input, 'Room')
|
|
await act(async () => {
|
|
jest.advanceTimersByTime(300)
|
|
await Promise.resolve()
|
|
})
|
|
|
|
await waitFor(() => {
|
|
expect(screen.getByText('Projector Room')).toBeInTheDocument()
|
|
})
|
|
|
|
mockedSearchUsers.mockRejectedValueOnce(new Error('Network error'))
|
|
await userEvent.clear(input)
|
|
await userEvent.type(input, 'Error')
|
|
await act(async () => {
|
|
jest.advanceTimersByTime(300)
|
|
await Promise.resolve()
|
|
})
|
|
|
|
const errorMessage = await screen.findByText('resourceSearch.searchError')
|
|
expect(errorMessage).toBeInTheDocument()
|
|
|
|
expect(screen.queryByText('Projector Room')).not.toBeInTheDocument()
|
|
|
|
mockedSearchUsers.mockResolvedValueOnce([
|
|
baseResource
|
|
] as unknown as Awaited<ReturnType<typeof searchUsers>>)
|
|
await userEvent.clear(input)
|
|
await userEvent.type(input, 'Room')
|
|
await act(async () => {
|
|
jest.advanceTimersByTime(300)
|
|
await Promise.resolve()
|
|
})
|
|
|
|
await waitFor(() => {
|
|
expect(screen.getByText('Projector Room')).toBeInTheDocument()
|
|
})
|
|
})
|
|
|
|
it('shows loading text when searching', async () => {
|
|
let resolveSearch: (value: Resource[]) => void
|
|
const searchPromise = new Promise<Resource[]>(resolve => {
|
|
resolveSearch = resolve
|
|
})
|
|
mockedSearchUsers.mockReturnValueOnce(
|
|
searchPromise as unknown as ReturnType<typeof searchUsers>
|
|
)
|
|
setup()
|
|
|
|
const input = screen.getByRole('combobox')
|
|
await userEvent.type(input, 'Room')
|
|
await act(async () => {
|
|
jest.advanceTimersByTime(300)
|
|
})
|
|
|
|
const loadingText = await screen.findByText(
|
|
'resourceSearch.loading',
|
|
{},
|
|
{ timeout: 5000 }
|
|
)
|
|
expect(loadingText).toBeInTheDocument()
|
|
|
|
await act(async () => {
|
|
resolveSearch!([baseResource])
|
|
await searchPromise
|
|
})
|
|
})
|
|
})
|