Browse Source

test(ui): Fix various act warnings in tests (#67217)

Scott Cooper 11 months ago
parent
commit
ee93e2cec7

+ 6 - 5
static/app/components/dropdownLink.spec.tsx

@@ -1,4 +1,5 @@
 import {
+  act,
   render,
   screen,
   userEvent,
@@ -237,23 +238,23 @@ describe('DropdownLink', function () {
       await userEvent.unhover(screen.getByText('nested'), {delay: null});
 
       // Nested menus have close delay
-      jest.advanceTimersByTime(MENU_CLOSE_DELAY - 1);
+      act(() => jest.advanceTimersByTime(MENU_CLOSE_DELAY - 1));
 
       // Re-entering nested menu will cancel close
       await userEvent.hover(screen.getByText('nested'), {delay: null});
-      jest.advanceTimersByTime(2);
+      act(() => jest.advanceTimersByTime(2));
       expect(screen.getByText('nested #2')).toBeInTheDocument();
 
       // Re-entering an actor will also cancel close
-      jest.advanceTimersByTime(MENU_CLOSE_DELAY - 1);
+      act(() => jest.advanceTimersByTime(MENU_CLOSE_DELAY - 1));
 
-      jest.advanceTimersByTime(2);
+      act(() => jest.advanceTimersByTime(2));
       await userEvent.hover(screen.getByText('parent'), {delay: null});
       expect(screen.getByText('nested #2')).toBeInTheDocument();
 
       // Leave menu
       await userEvent.unhover(screen.getByText('nested'), {delay: null});
-      jest.runAllTimers();
+      act(jest.runAllTimers);
       expect(screen.queryByText('nested #2')).not.toBeInTheDocument();
     });
 

+ 2 - 2
static/app/components/hovercard.spec.tsx

@@ -44,7 +44,7 @@ describe('Hovercard', () => {
     expect(screen.queryByText(/Hovercard Header/)).not.toBeInTheDocument();
   });
 
-  it('Always displays card', () => {
+  it('Always displays card', async () => {
     render(
       <Hovercard
         position="top"
@@ -57,7 +57,7 @@ describe('Hovercard', () => {
       </Hovercard>
     );
 
-    expect(screen.getByText(/Hovercard Body/)).toBeInTheDocument();
+    expect(await screen.findByText(/Hovercard Body/)).toBeInTheDocument();
     expect(screen.getByText(/Hovercard Header/)).toBeInTheDocument();
   });
 

+ 3 - 1
static/app/components/modals/inviteMembersModal/index.spec.tsx

@@ -420,7 +420,9 @@ describe('InviteMembersModal', function () {
         },
       });
 
-      expect(await screen.findByText(initialEmail)).toBeInTheDocument();
+      await waitFor(() => {
+        expect(screen.getByText(initialEmail)).toBeInTheDocument();
+      });
       await userEvent.click(screen.getByRole('button', {name: 'Send invite request'}));
       const apiMock = mocks[1];
       expect(apiMock).toHaveBeenCalledTimes(1);

+ 2 - 2
static/app/components/organizations/environmentPageFilter/index.spec.tsx

@@ -115,14 +115,14 @@ describe('EnvironmentPageFilter', function () {
     expect(onReset).toHaveBeenCalled();
   });
 
-  it('responds to page filter changes, async e.g. from back button nav', function () {
+  it('responds to page filter changes, async e.g. from back button nav', async function () {
     render(<EnvironmentPageFilter />, {
       context: routerContext,
       organization,
     });
 
     // Confirm initial selection
-    expect(screen.getByRole('button', {name: 'All Envs'})).toBeInTheDocument();
+    expect(await screen.findByRole('button', {name: 'All Envs'})).toBeInTheDocument();
 
     // Edit store value
     act(() => updateEnvironments(['prod'], router));

+ 6 - 4
static/app/components/timeRangeSelector/index.spec.tsx

@@ -46,14 +46,16 @@ describe('TimeRangeSelector', function () {
     onChange.mockReset();
   });
 
-  it('renders when given relative period', function () {
+  it('renders when given relative period', async function () {
     renderComponent({relative: '9d'});
-    expect(screen.getByRole('button', {name: '9D'})).toBeInTheDocument();
+    expect(await screen.findByRole('button', {name: '9D'})).toBeInTheDocument();
   });
 
-  it('renders when given an invalid relative period', function () {
+  it('renders when given an invalid relative period', async function () {
     render(<TimeRangeSelector relative="1y" />, {context: routerContext, organization});
-    expect(screen.getByRole('button', {name: 'Invalid Period'})).toBeInTheDocument();
+    expect(
+      await screen.findByRole('button', {name: 'Invalid Period'})
+    ).toBeInTheDocument();
   });
 
   it('hides relative options', async function () {

+ 1 - 6
static/app/views/dashboards/widgetBuilder/buildSteps/visualizationStep.spec.tsx

@@ -1,9 +1,8 @@
 import {TagsFixture} from 'sentry-fixture/tags';
 
 import {initializeOrg} from 'sentry-test/initializeOrg';
-import {act, render, screen, userEvent, waitFor} from 'sentry-test/reactTestingLibrary';
+import {render, screen, userEvent, waitFor} from 'sentry-test/reactTestingLibrary';
 
-import {DEFAULT_DEBOUNCE_DURATION} from 'sentry/constants';
 import ProjectsStore from 'sentry/stores/projectsStore';
 import type {Organization} from 'sentry/types';
 import {DashboardWidgetSource} from 'sentry/views/dashboards/types';
@@ -95,8 +94,6 @@ describe('VisualizationStep', function () {
   it('debounce works as expected and requests are not triggered often', async function () {
     const {eventsMock} = mockRequests(organization.slug);
 
-    jest.useFakeTimers();
-
     render(
       <WidgetBuilder
         route={{}}
@@ -130,8 +127,6 @@ describe('VisualizationStep', function () {
     await userEvent.type(await screen.findByPlaceholderText('Alias'), 'abc', {
       delay: null,
     });
-    act(() => jest.advanceTimersByTime(DEFAULT_DEBOUNCE_DURATION + 1));
-    jest.useRealTimers();
 
     await waitFor(() => expect(eventsMock).toHaveBeenCalledTimes(1));
   });

+ 4 - 2
static/app/views/discover/queryList.spec.tsx

@@ -104,7 +104,7 @@ describe('Discover > QueryList', function () {
     expect(screen.getByText('No saved queries match that filter')).toBeInTheDocument();
   });
 
-  it('renders pre-built queries and saved ones', function () {
+  it('renders pre-built queries and saved ones', async function () {
     render(
       <QueryList
         savedQuerySearchQuery=""
@@ -118,7 +118,9 @@ describe('Discover > QueryList', function () {
       />
     );
 
-    expect(screen.getAllByTestId(/card-.*/)).toHaveLength(5);
+    await waitFor(() => {
+      expect(screen.getAllByTestId(/card-.*/)).toHaveLength(5);
+    });
   });
 
   it('can duplicate and trigger change callback', async function () {

+ 21 - 9
static/app/views/issueDetails/groupEvents.spec.tsx

@@ -7,6 +7,7 @@ import {
   render,
   screen,
   userEvent,
+  waitFor,
   waitForElementToBeRemoved,
 } from 'sentry-test/reactTestingLibrary';
 
@@ -169,7 +170,7 @@ describe('groupEvents', () => {
     }
   });
 
-  it('handles environment filtering', () => {
+  it('handles environment filtering', async () => {
     render(
       <GroupEvents
         {...baseProps}
@@ -177,6 +178,9 @@ describe('groupEvents', () => {
       />,
       {context: routerContext, organization}
     );
+    await waitFor(() => {
+      expect(screen.getByText('transaction')).toBeInTheDocument();
+    });
     expect(requests.discover).toHaveBeenCalledWith(
       '/organizations/org-slug/events/',
       expect.objectContaining({
@@ -185,7 +189,7 @@ describe('groupEvents', () => {
     );
   });
 
-  it('renders events table for performance issue', () => {
+  it('renders events table for performance issue', async () => {
     const group = GroupFixture();
     group.issueCategory = IssueCategory.PERFORMANCE;
 
@@ -205,8 +209,9 @@ describe('groupEvents', () => {
         }),
       })
     );
-    const perfEventsColumn = screen.getByText('transaction');
-    expect(perfEventsColumn).toBeInTheDocument();
+    await waitFor(() => {
+      expect(screen.getByText('transaction')).toBeInTheDocument();
+    });
   });
 
   it('renders event and trace link correctly', async () => {
@@ -341,7 +346,7 @@ describe('groupEvents', () => {
     expect(requests.attachments).toHaveBeenCalled();
   });
 
-  it('renders events table for error', () => {
+  it('renders events table for error', async () => {
     render(
       <GroupEvents
         {...baseProps}
@@ -359,11 +364,12 @@ describe('groupEvents', () => {
       })
     );
 
-    const perfEventsColumn = screen.getByText('transaction');
-    expect(perfEventsColumn).toBeInTheDocument();
+    await waitFor(() => {
+      expect(screen.getByText('transaction')).toBeInTheDocument();
+    });
   });
 
-  it('removes sort if unsupported by the events table', () => {
+  it('removes sort if unsupported by the events table', async () => {
     render(
       <GroupEvents
         {...baseProps}
@@ -375,9 +381,12 @@ describe('groupEvents', () => {
       '/organizations/org-slug/events/',
       expect.objectContaining({query: expect.not.objectContaining({sort: 'user'})})
     );
+    await waitFor(() => {
+      expect(screen.getByText('transaction')).toBeInTheDocument();
+    });
   });
 
-  it('only request for a single projectId', () => {
+  it('only request for a single projectId', async () => {
     const group = GroupFixture();
 
     render(
@@ -401,6 +410,9 @@ describe('groupEvents', () => {
         query: expect.objectContaining({project: [group.project.id]}),
       })
     );
+    await waitFor(() => {
+      expect(screen.getByText('transaction')).toBeInTheDocument();
+    });
   });
 
   it('shows discover query error message', async () => {

+ 8 - 5
static/app/views/settings/project/projectOwnership/index.spec.tsx

@@ -45,7 +45,7 @@ describe('Project Ownership', () => {
   });
 
   describe('without codeowners', () => {
-    it('renders', () => {
+    it('renders', async () => {
       render(
         <ProjectOwnership
           {...routerProps}
@@ -54,13 +54,14 @@ describe('Project Ownership', () => {
           project={project}
         />
       );
+      expect(await screen.findByText('No ownership rules found')).toBeInTheDocument();
       // Does not render codeowners for orgs without 'integrations-codeowners' feature
       expect(
         screen.queryByRole('button', {name: 'Add CODEOWNERS'})
       ).not.toBeInTheDocument();
     });
 
-    it('renders allows users to edit ownership rules', () => {
+    it('renders allows users to edit ownership rules', async () => {
       render(
         <ProjectOwnership
           {...routerProps}
@@ -71,8 +72,8 @@ describe('Project Ownership', () => {
         {organization: OrganizationFixture({access: ['project:read']})}
       );
 
+      expect(await screen.findByTestId('project-permission-alert')).toBeInTheDocument();
       expect(screen.queryByRole('button', {name: 'Edit Rules'})).toBeEnabled();
-      expect(screen.getByTestId('project-permission-alert')).toBeInTheDocument();
       // eslint-disable-next-line jest-dom/prefer-in-document
       expect(screen.getAllByTestId('project-permission-alert')).toHaveLength(1);
     });
@@ -95,7 +96,9 @@ describe('Project Ownership', () => {
       );
 
       // Renders button
-      expect(screen.getByRole('button', {name: 'Import CODEOWNERS'})).toBeInTheDocument();
+      expect(
+        await screen.findByRole('button', {name: 'Import CODEOWNERS'})
+      ).toBeInTheDocument();
 
       // Opens modal
       await userEvent.click(screen.getByRole('button', {name: 'Import CODEOWNERS'}));
@@ -125,7 +128,7 @@ describe('Project Ownership', () => {
       );
 
       // Switch to Assign To Issue Owner
-      await userEvent.click(screen.getByText('Auto-assign to suspect commits'));
+      await userEvent.click(await screen.findByText('Auto-assign to suspect commits'));
       await userEvent.click(screen.getByText('Auto-assign to issue owner'));
 
       await waitFor(() => {

+ 8 - 4
static/app/views/settings/projectGeneralSettings/index.spec.tsx

@@ -332,7 +332,6 @@ describe('projectGeneralSettings', function () {
 
   describe('Non-"save on blur" Field', function () {
     beforeEach(function () {
-      const params = {projectId: project.slug};
       ProjectsStore.loadInitialData([project]);
 
       putMock = MockApiClient.addMockResponse({
@@ -343,7 +342,10 @@ describe('projectGeneralSettings', function () {
           slug: 'new-project',
         },
       });
+    });
 
+    function renderProjectGeneralSettings() {
+      const params = {projectId: project.slug};
       render(
         <ProjectContext projectSlug={project.slug}>
           <ProjectGeneralSettings
@@ -355,12 +357,13 @@ describe('projectGeneralSettings', function () {
         </ProjectContext>,
         {context: routerContext, organization}
       );
-    });
+    }
 
     it('can cancel unsaved changes for a field', async function () {
+      renderProjectGeneralSettings();
       expect(screen.queryByRole('button', {name: 'Cancel'})).not.toBeInTheDocument();
 
-      const autoResolveSlider = getField('slider', 'Auto Resolve');
+      const autoResolveSlider = await screen.findByRole('slider', {name: 'Auto Resolve'});
       expect(autoResolveSlider).toHaveValue('19');
 
       // Change value
@@ -381,9 +384,10 @@ describe('projectGeneralSettings', function () {
     });
 
     it('saves when value is changed and "Save" clicked', async function () {
+      renderProjectGeneralSettings();
       expect(screen.queryByRole('button', {name: 'Save'})).not.toBeInTheDocument();
 
-      const autoResolveSlider = getField('slider', 'Auto Resolve');
+      const autoResolveSlider = await screen.findByRole('slider', {name: 'Auto Resolve'});
       expect(autoResolveSlider).toHaveValue('19');
 
       // Change value