go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/milo/ui/src/test_verdict/pages/recent_regressions_page/recent_regressions.test.tsx (about)

     1  // Copyright 2024 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    ChangepointsClientImpl,
    25    QueryChangepointGroupSummariesResponse,
    26  } from '@/proto/go.chromium.org/luci/analysis/proto/v1/changepoints.pb';
    27  import { FakeContextProvider } from '@/testing_tools/fakes/fake_context_provider';
    28  import { URLObserver } from '@/testing_tools/url_observer';
    29  import { NEVER_PROMISE } from '@/testing_tools/utils';
    30  
    31  import { RecentRegressions } from './recent_regressions';
    32  
    33  const mockedResponse = QueryChangepointGroupSummariesResponse.fromJSON({
    34    groupSummaries: [
    35      {
    36        canonicalChangepoint: {
    37          project: 'proj',
    38          testId: 'prefix/testid',
    39          variantHash: 'vhash',
    40          refHash: 'refhash',
    41          ref: {
    42            gitiles: {
    43              host: 'chromium.googlesource.com',
    44              project: 'chromium/src',
    45              ref: 'refs/heads/main',
    46            },
    47          },
    48          startHour: '2020-01-01',
    49          startPositionLowerBound99th: '123',
    50          startPositionUpperBound99th: '125',
    51          nominalStartPosition: '124',
    52          previousSegmentNominalEndPosition: '120',
    53        },
    54        statistics: {
    55          count: 1,
    56          unexpectedVerdictRateBefore: {
    57            average: 0.012269938,
    58            buckets: {
    59              countLess5Percent: 1,
    60            },
    61          },
    62          unexpectedVerdictRateAfter: {
    63            average: 0.0625,
    64            buckets: {
    65              countAbove5LessThan95Percent: 1,
    66            },
    67          },
    68          unexpectedVerdictRateCurrent: {
    69            average: 0.0625,
    70            buckets: {
    71              countAbove5LessThan95Percent: 1,
    72            },
    73          },
    74          unexpectedVerdictRateChange: {
    75            countIncreased0To20Percent: 1,
    76          },
    77        },
    78      },
    79    ],
    80  });
    81  
    82  describe('<RecentRegressions />', () => {
    83    let queryChangepointGroupSummariesMock: jest.SpiedFunction<
    84      ChangepointsClientImpl['QueryChangepointGroupSummaries']
    85    >;
    86  
    87    beforeEach(() => {
    88      jest.useFakeTimers();
    89      queryChangepointGroupSummariesMock = jest
    90        .spyOn(ChangepointsClientImpl.prototype, 'QueryChangepointGroupSummaries')
    91        .mockResolvedValue(NEVER_PROMISE);
    92    });
    93  
    94    afterEach(() => {
    95      cleanup();
    96      queryChangepointGroupSummariesMock.mockClear();
    97      jest.useRealTimers();
    98    });
    99  
   100    it('can set predicate via search param', () => {
   101      render(
   102        <FakeContextProvider
   103          mountedPath="/"
   104          routerOptions={{
   105            initialEntries: ['/?cp=%7B"testIdPrefix"%3A"prefix"%7D'],
   106          }}
   107        >
   108          <RecentRegressions project="proj" />
   109        </FakeContextProvider>,
   110      );
   111      const prefixInputEle = screen.getByLabelText('Test ID prefix');
   112      expect(prefixInputEle).toHaveValue('prefix');
   113    });
   114  
   115    it('can save predicate to search param', () => {
   116      const urlCallback = jest.fn();
   117      render(
   118        <FakeContextProvider mountedPath="/">
   119          <RecentRegressions project="proj" />
   120          <URLObserver callback={urlCallback} />
   121        </FakeContextProvider>,
   122      );
   123  
   124      const prefixInputEle = screen.getByLabelText('Test ID prefix');
   125      fireEvent.change(prefixInputEle, { target: { value: 'prefix' } });
   126      fireEvent.click(screen.getByText('Apply Filter'));
   127  
   128      expect(urlCallback).toHaveBeenLastCalledWith(
   129        expect.objectContaining({
   130          search: {
   131            cp: JSON.stringify({ testIdPrefix: 'prefix' }),
   132          },
   133        }),
   134      );
   135    });
   136  
   137    it('can pass predicate to regression details link', async () => {
   138      queryChangepointGroupSummariesMock.mockResolvedValue(mockedResponse);
   139      render(
   140        <FakeContextProvider
   141          mountedPath="test"
   142          routerOptions={{
   143            initialEntries: ['/test?cp=%7B"testIdPrefix"%3A"prefix"%7D'],
   144          }}
   145        >
   146          <RecentRegressions project="proj" />
   147        </FakeContextProvider>,
   148      );
   149  
   150      await act(() => jest.runAllTimersAsync());
   151      const link = screen.getByText('details').getAttribute('href')!;
   152      const url = new URL(link, 'http://placeholder.com');
   153      const searchParams = Object.fromEntries(url.searchParams.entries());
   154      expect(searchParams).toEqual({
   155        cp: JSON.stringify({ testIdPrefix: 'prefix' }),
   156        nsp: '124',
   157        sh: '2020-01-01',
   158        tvb: 'projects/proj/tests/prefix%2Ftestid/variants/vhash/refs/refhash',
   159      });
   160    });
   161  });