Skip to content

Commit

Permalink
chore: aligned act usage with RTL recommendations to avoid obfuscatin…
Browse files Browse the repository at this point in the history
…g test issues

Signed-off-by: Manuel Zedel <manuel.zedel@northern.tech>
  • Loading branch information
mzedel committed Jun 5, 2024
1 parent 39f5f96 commit 54c4a2d
Show file tree
Hide file tree
Showing 25 changed files with 671 additions and 445 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ describe('PortForward Component', () => {
}
}
});
await act(async () => {});
await waitFor(() => rerender(ui));
await act(async () => {
jest.runOnlyPendingTimers();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,10 @@ describe('PhysicalDeviceOnboarding Component', () => {
const view = baseElement.firstChild;
expect(view).toMatchSnapshot();
expect(view).toEqual(expect.not.stringMatching(undefineds));
await act(async () => {});
await waitFor(() => expect(store.getState().onboarding.approach === 'physical').toBeTruthy());
await act(async () => {
jest.runOnlyPendingTimers();
jest.runAllTicks();
});
});
});
4 changes: 1 addition & 3 deletions src/js/components/common/forms/fileupload.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,7 @@ describe('FileUpload Component', () => {
expect(screen.getByText(/test placeholder/i)).toBeInTheDocument();
// container.querySelector doesn't work in this scenario for some reason -> but querying document seems to work
const uploadInput = document.querySelector('.dropzone input');
await act(async () => {
await user.upload(uploadInput, menderFile);
});
await act(async () => await user.upload(uploadInput, menderFile));
await waitFor(() => rerender(ui));

expect(uploadInput.files).toHaveLength(1);
Expand Down
30 changes: 22 additions & 8 deletions src/js/components/dashboard/dashboard.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
import React from 'react';
import { Route, Routes } from 'react-router-dom';

import { screen, waitFor } from '@testing-library/react';
import { act, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

import { defaultState, undefineds } from '../../../../tests/mockData';
Expand All @@ -26,13 +26,31 @@ import Dashboard from './dashboard';
const reportsSpy = jest.spyOn(DeviceActions, 'deriveReportsData');

describe('Dashboard Component', () => {
afterEach(async () => {
// wait for all requests to settle
await act(async () => {
jest.runOnlyPendingTimers();
jest.runAllTicks();
});
});
it('renders correctly', async () => {
const preloadedState = {
...defaultState,
deployments: {
...defaultState.deployments,
byStatus: {
...defaultState.deployments.byStatus,
finished: { deploymentIds: ['d1', 'd2'], total: 2 },
inprogress: { deploymentIds: ['d1', 'd2'], total: 2 },
pending: { deploymentIds: ['d1', 'd2'], total: 2 }
}
}
};
const ui = <Dashboard />;
const { baseElement, rerender } = render(ui);
const { baseElement, rerender } = render(ui, { preloadedState });
await waitFor(() => expect(reportsSpy).toHaveBeenCalled());
await waitFor(() => rerender(ui));
const view = baseElement.firstChild;
await act(async () => {});
expect(view).toMatchSnapshot();
expect(view).toEqual(expect.not.stringMatching(undefineds));
reportsSpy.mockClear();
Expand All @@ -59,7 +77,7 @@ describe('Dashboard Component', () => {
const { rerender, store } = render(ui, { preloadedState });
await waitFor(() => expect(reportsSpy).toHaveBeenCalled());
await waitFor(() => rerender(ui));
store.dispatch({ type: SET_ACCEPTED_DEVICES_COUNT, status: 'accepted', count: 0 });
await act(() => store.dispatch({ type: SET_ACCEPTED_DEVICES_COUNT, status: 'accepted', count: 0 }));
await user.click(screen.getByText(/pending devices/i));
await waitFor(() => screen.queryByText(/pendings route/i));
expect(screen.getByText(/pendings route/i)).toBeVisible();
Expand All @@ -74,11 +92,9 @@ describe('Dashboard Component', () => {
<Route path="/devices/*" element={<div>accepted devices route</div>} />
</Routes>
);
await act(async () => {});
const { rerender } = render(ui);
await waitFor(() => expect(reportsSpy).toHaveBeenCalled());
await waitFor(() => rerender(ui));
await act(async () => {});
await user.click(screen.getByText(/Accepted devices/i));
await waitFor(() => screen.queryByText(/accepted devices route/i));
expect(screen.getByText(/accepted devices route/i)).toBeVisible();
Expand All @@ -103,11 +119,9 @@ describe('Dashboard Component', () => {
<Route path="/deployments/*" element={<div>deployments route</div>} />
</Routes>
);
await act(async () => {});
const { rerender } = render(ui, { preloadedState });
await waitFor(() => expect(reportsSpy).toHaveBeenCalled());
await waitFor(() => rerender(ui));
await act(async () => {});
await user.click(screen.getAllByText('test deployment 2')[0]);
await waitFor(() => screen.queryByText(/deployments route/i));
expect(screen.getByText(/deployments route/i)).toBeVisible();
Expand Down
68 changes: 27 additions & 41 deletions src/js/components/deployments/deployments.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,23 +67,23 @@ describe('Deployments Component', () => {
}
};

it('renders correctly', async () => {
const get = jest.spyOn(GeneralApi, 'get');
const ui = <Deployments {...defaultLocationProps} />;
const { asFragment, rerender } = render(ui, { state: mockState });
afterEach(async () => {
await act(async () => {
jest.runAllTicks();
jest.advanceTimersByTime(2000);
jest.runAllTicks();
});
await waitFor(() => rerender(ui));
await act(async () => {});
});

it('renders correctly', async () => {
const get = jest.spyOn(GeneralApi, 'get');
const ui = <Deployments {...defaultLocationProps} />;
const { asFragment } = render(ui, { preloadedState: mockState });
await waitFor(() => expect(screen.getAllByRole('button', { name: /View details/i })).toBeTruthy());
const view = asFragment();
expect(view).toMatchSnapshot();
expect(view).toEqual(expect.not.stringMatching(undefineds));
await act(async () => {});
await waitFor(() => expect(get).toHaveBeenCalledWith('/api/management/v2/inventory/filters?per_page=500'));
expect(get).toHaveBeenCalledWith('/api/management/v2/inventory/filters?per_page=500');
await act(async () => {});
});

it('works as expected', async () => {
Expand Down Expand Up @@ -177,23 +177,20 @@ describe('Deployments Component', () => {
await waitFor(() => expect(screen.queryByPlaceholderText(/Select a Release/i)).toBeInTheDocument(), { timeout: 3000 });
const releaseSelect = screen.getByPlaceholderText(/Select a Release/i);
expect(within(releaseSelect).queryByDisplayValue(releaseId)).not.toBeInTheDocument();
await user.click(releaseSelect);
await act(async () => await user.click(releaseSelect));
await user.keyboard(specialKeys.ArrowDown);
await user.keyboard(specialKeys.Enter);
act(() => jest.advanceTimersByTime(2000));
const groupSelect = screen.getByPlaceholderText(/Select a device group/i);
await user.click(groupSelect);
await act(async () => await user.click(groupSelect));
await user.keyboard(specialKeys.Enter);
await waitFor(() => rerender(ui));
// await waitFor(() => rerender(ui));
expect(groupSelect).toHaveValue(ALL_DEVICES);
const post = jest.spyOn(GeneralApi, 'post');
await user.click(screen.getByRole('button', { name: 'Create deployment' }));
act(() => {
await act(async () => {
jest.runOnlyPendingTimers();
jest.runAllTicks();
jest.advanceTimersByTime(2000);
});
await waitFor(() => rerender(ui));
await act(async () => {});
await user.click(screen.getByRole('button', { name: 'Create deployment' }));
expect(post).toHaveBeenCalledWith('/api/management/v1/deployments/deployments', {
all_devices: true,
artifact_name: releaseId,
Expand All @@ -206,9 +203,7 @@ describe('Deployments Component', () => {
phases: undefined,
update_control_map: undefined
});
await jest.runAllTicks();
await waitFor(() => rerender(ui));
act(() => jest.advanceTimersByTime(1000));
await act(() => jest.advanceTimersByTime(1000));
expect(screen.queryByText(/Cancel/i)).not.toBeInTheDocument();
}, 20000);

Expand Down Expand Up @@ -257,22 +252,15 @@ describe('Deployments Component', () => {
const { rerender } = render(ui, { preloadedState });
await user.click(screen.getByRole('button', { name: /Create a deployment/i }));
const releaseId = 'release-998';
act(() => {
jest.runAllTicks();
jest.advanceTimersByTime(2000);
});
await waitFor(() => rerender(ui));
const groupSelect = screen.getByPlaceholderText(/Select a device group/i);
await user.click(groupSelect);
await act(async () => await user.click(groupSelect));
await user.keyboard(specialKeys.Enter);
expect(groupSelect).toHaveValue(ALL_DEVICES);
await waitFor(() => expect(screen.queryByPlaceholderText(/Select a Release/i)).toBeInTheDocument(), { timeout: 3000 });
const releaseSelect = screen.getByPlaceholderText(/Select a Release/i);
await user.click(releaseSelect);
await act(async () => await user.click(releaseSelect));
await user.keyboard(specialKeys.ArrowDown);
await user.keyboard(specialKeys.Enter);
act(() => jest.advanceTimersByTime(2000));
await waitFor(() => rerender(ui));
await user.click(screen.getByRole('button', { name: /advanced options/i }));
await user.click(screen.getByRole('checkbox', { name: /select a rollout pattern/i }));
await waitFor(() => rerender(ui));
Expand All @@ -281,21 +269,22 @@ describe('Deployments Component', () => {
await selectMaterialUiSelectOption(within(firstPhase).getByDisplayValue(/hours/i), /minutes/i, user);
fireEvent.change(within(firstPhase).getByDisplayValue(20), { target: { value: '50' } });
fireEvent.change(within(firstPhase).getByDisplayValue('2'), { target: { value: '30' } });
await act(async () => {
await user.click(screen.getByText(/Add a phase/i));
});
await user.click(screen.getByText(/Add a phase/i));
const secondPhase = screen.getByText(/Phase 2/i).parentElement.parentElement.parentElement;
await selectMaterialUiSelectOption(within(secondPhase).getByDisplayValue(/hours/i), /days/i, user);
expect(within(secondPhase).getByText(/Phases must have at least 1 device/i)).toBeTruthy();
fireEvent.change(within(secondPhase).getByDisplayValue(10), { target: { value: '25' } });
fireEvent.change(within(secondPhase).getByDisplayValue('2'), { target: { value: '25' } });
await user.click(screen.getByRole('checkbox', { name: /save as default/i }));
const retrySelect = document.querySelector('#deployment-retries-selection');
await user.click(retrySelect);
await act(async () => await user.click(retrySelect));
await user.keyboard(specialKeys.ArrowDown);
await user.keyboard(specialKeys.Enter);
await user.keyboard('{Tab}');
act(() => jest.advanceTimersByTime(1000));
await user.tab();
await act(async () => {
jest.advanceTimersByTime(1000);
jest.runAllTicks();
});
expect(retrySelect).toHaveValue(2);

// extra explicit here as the general date mocking seems to be ignored by the moment/ date combination
Expand All @@ -305,14 +294,11 @@ describe('Deployments Component', () => {
const post = jest.spyOn(GeneralApi, 'post');
const creationButton = screen.getByText(/Create deployment/i);
await user.click(creationButton);
await waitFor(() => rerender(ui));
expect(creationButton).toBeDisabled();
act(() => {
jest.runAllTicks();
await act(async () => {
jest.advanceTimersByTime(1000);
jest.runAllTicks();
});
await waitFor(() => rerender(ui));
await act(async () => {});
expect(post).toHaveBeenCalledWith('/api/management/v1/deployments/deployments', {
all_devices: true,
artifact_name: releaseId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,7 @@ describe('ConfigImportDialog Component', () => {

// container.querySelector doesn't work in this scenario for some reason -> but querying document seems to work
const uploadInput = document.querySelector('.dropzone input');
await act(async () => {
await user.upload(uploadInput, menderFile);
});
await act(async () => await user.upload(uploadInput, menderFile));
await waitFor(() => rerender(ui));
expect(uploadInput.files).toHaveLength(1);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,7 @@ describe('Configuration Component', () => {
expect(fabButton).not.toBeDisabled();
await user.click(screen.getByRole('checkbox', { name: /save/i }));
await user.click(screen.getByRole('button', { name: /save/i }));
await waitFor(() => rerender(ui));

await act(async () => jest.runOnlyPendingTimers());
expect(screen.getByText(/Configuration could not be updated on device/i)).toBeInTheDocument();
await user.click(screen.getByRole('button', { name: /Retry/i }));
await waitFor(() => rerender(ui));
Expand Down
21 changes: 9 additions & 12 deletions src/js/components/devices/dialogs/preauth-dialog.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ describe('PreauthDialog Component', () => {
});

it('works as intended', async () => {
const user = userEvent.setup({ advanceTimers: jest.advanceTimersByTime });
const user = userEvent.setup({ advanceTimers: jest.advanceTimersByTime, applyAccept: false });
const submitMock = jest.fn();
const menderFile = new File(['testContent plain'], 'test.pem');
const preAuthSpy = jest.spyOn(DeviceActions, 'preauthDevice');
Expand All @@ -61,24 +61,23 @@ describe('PreauthDialog Component', () => {
expect(screen.getByText(/upload a public key file/i)).toBeInTheDocument();
// container.querySelector doesn't work in this scenario for some reason -> but querying document seems to work
const uploadInput = document.querySelector(dropzone);
await act(async () => {
await user.upload(uploadInput, menderFile);
});
await act(async () => await user.upload(uploadInput, menderFile));
await waitFor(() => rerender(ui));

expect(uploadInput.files).toHaveLength(1);
await waitFor(() => expect(document.querySelector(dropzone)).not.toBeInTheDocument());
expect(screen.getByDisplayValue('test.pem')).toBeInTheDocument();
const fabSelector = '.MuiFab-root';
expect(document.querySelector(fabSelector)).toBeDisabled();
await act(async () => {
await user.type(screen.getByPlaceholderText(/key/i), 'testKey');
await user.type(screen.getByPlaceholderText(/value/i), 'testValue');
});
await user.type(screen.getByPlaceholderText(/key/i), 'testKey');
await user.type(screen.getByPlaceholderText(/value/i), 'testValue');
expect(document.querySelector(fabSelector)).not.toBeDisabled();
await user.click(document.querySelector(fabSelector));
await waitFor(() => rerender(ui));
await waitFor(() => expect(screen.queryByText(errorText)).not.toBeInTheDocument());
await act(async () => {
jest.runOnlyPendingTimers();
jest.runAllTicks();
});
submitMock.mockRejectedValueOnce(errorText);
await user.click(screen.getByRole('button', { name: 'Save' }));
act(() => {
Expand Down Expand Up @@ -107,9 +106,7 @@ describe('PreauthDialog Component', () => {
const { rerender } = render(ui);
// container.querySelector doesn't work in this scenario for some reason -> but querying document seems to work
const uploadInput = document.querySelector(dropzone);
await act(async () => {
await user.upload(uploadInput, menderFile);
});
await act(async () => await user.upload(uploadInput, menderFile));
await waitFor(() => rerender(ui));
await user.type(screen.getByPlaceholderText(/key/i), 'testKey');
await user.type(screen.getByPlaceholderText(/value/i), 'testValue');
Expand Down
3 changes: 2 additions & 1 deletion src/js/components/header/header.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
// limitations under the License.
import React from 'react';

import { screen, waitFor, within } from '@testing-library/react';
import { act, screen, waitFor, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

import { defaultState, undefineds } from '../../../../tests/mockData';
Expand Down Expand Up @@ -62,6 +62,7 @@ describe('Header Component', () => {
const listbox = document.body.querySelector('ul[role=menu]');
const listItem = within(listbox).getByText(/log out/i);
await user.click(listItem);
await act(async () => jest.runAllTicks());
await waitFor(() => rerender(view));
expect(screen.queryByText(defaultState.users.byId[defaultState.users.currentUser].email)).not.toBeInTheDocument();
});
Expand Down
1 change: 0 additions & 1 deletion src/js/components/helptips/onboardingcompletetip.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ describe('OnboardingCompleteTip Component', () => {
</MemoryRouter>
);
const { baseElement, rerender } = testingLibRender(ui);
await act(async () => {});
await waitFor(() => rerender(ui));
const view = baseElement;
expect(view).toMatchSnapshot();
Expand Down
5 changes: 4 additions & 1 deletion src/js/components/login/login.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
// limitations under the License.
import React from 'react';

import { screen, waitFor } from '@testing-library/react';
import { act, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

import { defaultState, undefineds } from '../../../../tests/mockData';
Expand Down Expand Up @@ -46,6 +46,7 @@ describe('Login Component', () => {
const ui = <Login />;
const { rerender } = render(ui, { preloadedState });
await user.type(screen.getByLabelText(/your email/i), 'something-2fa@example.com');
await waitFor(() => rerender(ui));
await user.click(screen.getByRole('button', { name: /Log in/i }));
expect(loginSpy).toHaveBeenCalled();
await waitFor(() => rerender(ui));
Expand All @@ -54,11 +55,13 @@ describe('Login Component', () => {
await user.click(screen.getByRole('button', { name: /Log in/i }));
expect(loginSpy).toHaveBeenCalled();
await waitFor(() => rerender(ui));
await act(async () => jest.runAllTicks());
expect(await screen.findByLabelText(/Two Factor Authentication Code/i)).toBeVisible();
const input = screen.getByDisplayValue('something-2fa@example.com');
await user.clear(input);
await user.type(input, 'something@example.com');
await user.type(screen.getByLabelText(/Two Factor Authentication Code/i), '123456');
await waitFor(() => rerender(ui));
await user.click(screen.getByRole('button', { name: /Log in/i }));
await act(async () => jest.runAllTicks());
expect(loginSpy).toHaveBeenCalledWith({ email: 'something@example.com', password: 'mysecretpassword!123', token2fa: '123456' }, false);
Expand Down
3 changes: 2 additions & 1 deletion src/js/components/login/password.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
// limitations under the License.
import React from 'react';

import { act, screen, waitFor } from '@testing-library/react';
import { screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

import { undefineds } from '../../../../tests/mockData';
Expand All @@ -35,6 +35,7 @@ describe('Password Component', () => {
const ui = <Password />;
const { rerender } = render(ui);
await user.type(screen.queryByLabelText(/your email/i), 'something@example.com');
await waitFor(() => rerender(ui));
await user.click(screen.getByRole('button', { name: /Send password reset link/i }));
await waitFor(() => expect(startSpy).toHaveBeenCalledWith('something@example.com'));
await waitFor(() => rerender(ui));
Expand Down
Loading

0 comments on commit 54c4a2d

Please sign in to comment.