go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/milo/ui/src/build/pages/builder_search_page/builder_search_page.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  import { VirtuosoMockContext } from 'react-virtuoso';
    23  
    24  import { UiPage } from '@/common/constants/view';
    25  import {
    26    ListBuildersRequest,
    27    ListBuildersResponse,
    28    MiloInternalClientImpl,
    29  } from '@/proto/go.chromium.org/luci/milo/proto/v1/rpc.pb';
    30  import { FakeContextProvider } from '@/testing_tools/fakes/fake_context_provider';
    31  
    32  import { BuilderSearchPage } from './builder_search_page';
    33  
    34  describe('<BuilderSearchPage />', () => {
    35    beforeEach(() => {
    36      jest.useFakeTimers();
    37    });
    38    afterEach(() => {
    39      cleanup();
    40      jest.useRealTimers();
    41      jest.resetAllMocks();
    42    });
    43  
    44    it('should throttle search requests', async () => {
    45      jest
    46        .spyOn(MiloInternalClientImpl.prototype, 'ListBuilders')
    47        .mockImplementation(async (_: ListBuildersRequest) =>
    48          ListBuildersResponse.fromPartial({
    49            builders: Object.freeze([
    50              {
    51                id: {
    52                  bucket: 'test_bucket',
    53                  builder: 'builder',
    54                  project: 'chromium',
    55                },
    56              },
    57              {
    58                id: {
    59                  bucket: 'test_bucket',
    60                  builder: 'builder-id',
    61                  project: 'chromium',
    62                },
    63              },
    64              {
    65                id: {
    66                  bucket: 'test_bucket',
    67                  builder: 'builder-id-with-suffix',
    68                  project: 'chromium',
    69                },
    70              },
    71              {
    72                id: {
    73                  bucket: 'test_bucket',
    74                  builder: 'another-builder',
    75                  project: 'chromium',
    76                },
    77              },
    78              {
    79                id: {
    80                  bucket: 'test_bucket',
    81                  builder: 'another-builder-id',
    82                  project: 'chromium',
    83                },
    84              },
    85            ]),
    86          }),
    87        );
    88  
    89      render(
    90        <FakeContextProvider
    91          pageMeta={{
    92            selectedPage: UiPage.Builders,
    93          }}
    94        >
    95          <VirtuosoMockContext.Provider
    96            value={{ viewportHeight: 1000, itemHeight: 1 }}
    97          >
    98            <BuilderSearchPage />
    99          </VirtuosoMockContext.Provider>
   100        </FakeContextProvider>,
   101      );
   102  
   103      fireEvent.change(screen.getByTestId('search-input'), {
   104        target: { value: 'builder' },
   105      });
   106      await act(() => jest.advanceTimersByTimeAsync(10));
   107      expect(screen.queryAllByTestId('builder-data').length).toBe(5);
   108  
   109      fireEvent.change(screen.getByTestId('search-input'), {
   110        target: { value: 'builder-id' },
   111      });
   112      await act(() => jest.advanceTimersByTimeAsync(10));
   113      expect(screen.queryAllByTestId('builder-data').length).toBe(5);
   114  
   115      fireEvent.change(screen.getByTestId('search-input'), {
   116        target: { value: 'builder-id-with-suffix' },
   117      });
   118      await act(() => jest.advanceTimersByTimeAsync(200));
   119      expect(screen.queryAllByTestId('builder-data').length).toBe(5);
   120  
   121      await act(() => jest.advanceTimersByTimeAsync(200));
   122      expect(screen.getAllByTestId('builder-data').length).toBe(1);
   123      expect(screen.getByText('builder-id-with-suffix')).toBeInTheDocument();
   124  
   125      // Using another filter.
   126      fireEvent.change(screen.getByTestId('search-input'), {
   127        target: { value: 'another-builder' },
   128      });
   129      await act(() => jest.advanceTimersByTimeAsync(10));
   130      expect(screen.getAllByTestId('builder-data').length).toBe(1);
   131      expect(screen.getByText('builder-id-with-suffix')).toBeInTheDocument();
   132  
   133      fireEvent.change(screen.getByTestId('search-input'), {
   134        target: { value: 'another-builder-id' },
   135      });
   136      act(() => jest.runAllTimers());
   137      expect(screen.getAllByTestId('builder-data').length).toBe(1);
   138      expect(screen.getByText('another-builder-id')).toBeInTheDocument();
   139    });
   140  });