go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/milo/ui/src/test_verdict/pages/test_search/test_search.test.tsx (about) 1 // Copyright 2023 The LUCI Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 import { 16 act, 17 cleanup, 18 fireEvent, 19 render, 20 screen, 21 } from '@testing-library/react'; 22 23 import { 24 QueryTestsRequest, 25 TestHistoryService, 26 } from '@/common/services/luci_analysis'; 27 import { CacheOption } from '@/generic_libs/tools/cached_fn'; 28 import { FakeContextProvider } from '@/testing_tools/fakes/fake_context_provider'; 29 30 import { TestSearch } from './test_search'; 31 32 describe('TestSearch', () => { 33 beforeEach(() => { 34 jest 35 .spyOn(TestHistoryService.prototype, 'queryTests') 36 .mockImplementation((req: QueryTestsRequest, _: CacheOption = {}) => { 37 if (req.testIdSubstring === 'query') { 38 return Promise.resolve({ 39 testIds: ['test_id_1', 'test_id_2'], 40 }); 41 } else { 42 return Promise.reject(new Error('unknown test id')); 43 } 44 }); 45 jest.useFakeTimers(); 46 }); 47 afterEach(() => { 48 cleanup(); 49 jest.useRealTimers(); 50 jest.resetAllMocks(); 51 }); 52 53 it('should read params from URL', async () => { 54 render( 55 <FakeContextProvider 56 routerOptions={{ 57 initialEntries: ['/?q=query'], 58 }} 59 > 60 <TestSearch /> 61 </FakeContextProvider>, 62 ); 63 64 // Ensure that the filters are not overwritten after all event hooks are 65 // executed. 66 await act(async () => await jest.runAllTimersAsync()); 67 68 await screen.findByText('test_id_1'); 69 expect(screen.getByText('test_id_2')).toBeInTheDocument(); 70 }); 71 72 it('should sync params with URL', async () => { 73 render( 74 <FakeContextProvider> 75 <TestSearch /> 76 </FakeContextProvider>, 77 ); 78 fireEvent.change(screen.getByTestId('search-input'), { 79 target: { value: 'query' }, 80 }); 81 82 await screen.findByText('test_id_1'); 83 expect(screen.getByText('test_id_2')).toBeInTheDocument(); 84 }); 85 86 it('should throttle requests', async () => { 87 jest 88 .spyOn(TestHistoryService.prototype, 'queryTests') 89 .mockImplementation((req: QueryTestsRequest, _: CacheOption = {}) => { 90 const result = ['test_id_1', 'test_id_2'].filter((id) => 91 id.startsWith(req.testIdSubstring), 92 ); 93 return Promise.resolve({ 94 testIds: result, 95 }); 96 }); 97 98 render( 99 <FakeContextProvider> 100 <TestSearch /> 101 </FakeContextProvider>, 102 ); 103 fireEvent.change(screen.getByTestId('search-input'), { 104 target: { value: 'test_id' }, 105 }); 106 expect(screen.queryByText('test_id_1')).not.toBeInTheDocument(); 107 expect(screen.queryByText('test_id_2')).not.toBeInTheDocument(); 108 fireEvent.change(screen.getByTestId('search-input'), { 109 target: { value: 'test_id_2' }, 110 }); 111 act(() => jest.advanceTimersByTime(600)); 112 await screen.findByText('test_id_2'); 113 expect(screen.queryByText('test_id_1')).not.toBeInTheDocument(); 114 }); 115 });