test: upgrading user-event to v14 (#2277)

This commit is contained in:
jacobo-dominguez-wgu
2025-07-17 10:26:16 -06:00
committed by GitHub
parent a51ff99042
commit 2db6d89fca
73 changed files with 1007 additions and 777 deletions

13
package-lock.json generated
View File

@@ -84,7 +84,7 @@
"@edx/typescript-config": "^1.0.1",
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/react": "^16.2.0",
"@testing-library/user-event": "^13.2.1",
"@testing-library/user-event": "^14.6.1",
"@types/lodash": "^4.17.17",
"@types/react": "^18",
"@types/react-dom": "^18",
@@ -6445,16 +6445,13 @@
}
},
"node_modules/@testing-library/user-event": {
"version": "13.5.0",
"resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-13.5.0.tgz",
"integrity": "sha512-5Kwtbo3Y/NowpkbRuSepbyMFkZmHgD+vPzYB/RJ4oxt5Gj/avFFBYjhw27cqSVPVw/3a67NK1PbiIr9k4Gwmdg==",
"version": "14.6.1",
"resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.6.1.tgz",
"integrity": "sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.12.5"
},
"engines": {
"node": ">=10",
"node": ">=12",
"npm": ">=6"
},
"peerDependencies": {

View File

@@ -107,7 +107,7 @@
"@edx/typescript-config": "^1.0.1",
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/react": "^16.2.0",
"@testing-library/user-event": "^13.2.1",
"@testing-library/user-event": "^14.6.1",
"@types/lodash": "^4.17.17",
"@types/react": "^18",
"@types/react-dom": "^18",

View File

@@ -124,12 +124,13 @@ describe('BBB Settings', () => {
);
test('free plans message is visible when free plan is selected', async () => {
const user = userEvent.setup();
await mockStore({ emailSharing: true, isFreeTier: true });
renderComponent();
const spinner = getByRole(container, 'status');
await waitForElementToBeRemoved(spinner);
const dropDown = container.querySelector('select[name="tierType"]');
userEvent.selectOptions(
await user.selectOptions(
dropDown,
getByRole(dropDown, 'option', { name: 'Free' }),
);

View File

@@ -1,6 +1,5 @@
import {
render,
act,
screen,
} from '@testing-library/react';
import userEvent from '@testing-library/user-event';
@@ -74,22 +73,24 @@ describe('<AccessibilityPolicyForm />', () => {
describe('statusAlert', () => {
let formSections;
let submitButton;
let user;
beforeEach(async () => {
user = userEvent.setup();
renderComponent();
formSections = screen.getAllByRole('textbox');
await act(async () => {
userEvent.type(formSections[0], 'email@email.com');
userEvent.type(formSections[1], 'test name');
userEvent.type(formSections[2], 'feedback message');
});
await user.type(formSections[0], 'email@email.com');
await user.type(formSections[1], 'test name');
await user.type(formSections[2], 'feedback message');
submitButton = screen.getByText(messages.accessibilityPolicyFormSubmitLabel.defaultMessage);
});
it('shows correct success message', async () => {
axiosMock.onPost(getZendeskrUrl()).reply(200);
await act(async () => {
userEvent.click(submitButton);
});
await user.click(submitButton);
const { savingStatus } = store.getState().accessibilityPage;
expect(savingStatus).toEqual(RequestStatus.SUCCESSFUL);
@@ -104,9 +105,9 @@ describe('<AccessibilityPolicyForm />', () => {
it('shows correct rate limiting message', async () => {
axiosMock.onPost(getZendeskrUrl()).reply(429);
await act(async () => {
userEvent.click(submitButton);
});
await user.click(submitButton);
const { savingStatus } = store.getState().accessibilityPage;
expect(savingStatus).toEqual(RequestStatus.FAILED);
@@ -123,23 +124,24 @@ describe('<AccessibilityPolicyForm />', () => {
describe('input validation', () => {
let formSections;
let submitButton;
let user;
beforeEach(async () => {
user = userEvent.setup();
renderComponent();
formSections = screen.getAllByRole('textbox');
await act(async () => {
userEvent.type(formSections[0], 'email@email.com');
userEvent.type(formSections[1], 'test name');
userEvent.type(formSections[2], 'feedback message');
});
await user.type(formSections[0], 'email@email.com');
await user.type(formSections[1], 'test name');
await user.type(formSections[2], 'feedback message');
submitButton = screen.getByText(messages.accessibilityPolicyFormSubmitLabel.defaultMessage);
});
it('adds validation checking on each input field', async () => {
await act(async () => {
userEvent.clear(formSections[0]);
userEvent.clear(formSections[1]);
userEvent.clear(formSections[2]);
});
await user.clear(formSections[0]);
await user.clear(formSections[1]);
await user.clear(formSections[2]);
const emailError = screen.getByTestId('error-feedback-email');
expect(emailError).toBeVisible();
@@ -151,12 +153,10 @@ describe('<AccessibilityPolicyForm />', () => {
});
it('sumbit button is disabled when trying to submit with all empty fields', async () => {
await act(async () => {
userEvent.clear(formSections[0]);
userEvent.clear(formSections[1]);
userEvent.clear(formSections[2]);
userEvent.click(submitButton);
});
await user.clear(formSections[0]);
await user.clear(formSections[1]);
await user.clear(formSections[2]);
await user.click(submitButton);
expect(submitButton.closest('button')).toBeDisabled();
});

View File

@@ -10,9 +10,11 @@ function submitAccessibilityForm({ email, name, message }) {
await postAccessibilityForm({ email, name, message });
dispatch(updateSavingStatus({ status: RequestStatus.SUCCESSFUL }));
} catch (error) {
/* istanbul ignore else */
if (error.response && error.response.status === 429) {
dispatch(updateSavingStatus({ status: RequestStatus.FAILED }));
} else {
/* istanbul ignore next */
dispatch(updateSavingStatus({ status: RequestStatus.SUCCESSFUL }));
}
}

View File

@@ -79,11 +79,12 @@ describe('<SettingCard />', () => {
expect(queryByText(messages.deprecated.defaultMessage)).toBeNull();
});
it('calls setEdited on blur', async () => {
const user = userEvent.setup();
const { getByLabelText } = render(<RootWrapper />);
const inputBox = getByLabelText(/Setting Name/i);
fireEvent.focus(inputBox);
userEvent.clear(inputBox);
userEvent.type(inputBox, '3, 2, 1');
await user.clear(inputBox);
await user.type(inputBox, '3, 2, 1');
await waitFor(() => {
expect(inputBox).toHaveValue('3, 2, 1');
});

View File

@@ -111,11 +111,13 @@ describe('Certificates', () => {
.reply(200, noCertificatesMock);
await executeThunk(fetchCertificates(courseId), store.dispatch);
const user = userEvent.setup();
const { queryByTestId, getByTestId, getByRole } = renderComponent();
await waitFor(() => {
await waitFor(async () => {
const addCertificateButton = getByRole('button', { name: messages.setupCertificateBtn.defaultMessage });
userEvent.click(addCertificateButton);
await user.click(addCertificateButton);
});
expect(getByTestId('certificates-create-form')).toBeInTheDocument();
@@ -131,11 +133,13 @@ describe('Certificates', () => {
.reply(200, certificatesDataMock);
await executeThunk(fetchCertificates(courseId), store.dispatch);
const user = userEvent.setup();
const { queryByTestId, getByTestId, getAllByLabelText } = renderComponent();
await waitFor(() => {
await waitFor(async () => {
const editCertificateButton = getAllByLabelText(messages.editTooltip.defaultMessage)[0];
userEvent.click(editCertificateButton);
await user.click(editCertificateButton);
});
expect(getByTestId('certificates-edit-form')).toBeInTheDocument();

View File

@@ -1,4 +1,6 @@
import { render, waitFor, within } from '@testing-library/react';
import {
render, waitFor, within,
} from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { Provider } from 'react-redux';
import { IntlProvider } from '@edx/frontend-platform/i18n';
@@ -85,17 +87,19 @@ describe('CertificateCreateForm', () => {
}],
};
const user = userEvent.setup();
const { getByPlaceholderText, getByRole, getByDisplayValue } = renderComponent();
userEvent.type(
await user.type(
getByPlaceholderText(detailsMessages.detailsCourseTitleOverride.defaultMessage),
courseTitleOverrideValue,
);
userEvent.type(
await user.type(
getByPlaceholderText(signatoryMessages.namePlaceholder.defaultMessage),
signatoryNameValue,
);
userEvent.click(getByRole('button', { name: messages.cardCreate.defaultMessage }));
await user.click(getByRole('button', { name: messages.cardCreate.defaultMessage }));
axiosMock.onPost(
getCertificateApiUrl(courseId),
@@ -109,8 +113,9 @@ describe('CertificateCreateForm', () => {
});
it('cancel certificates creation', async () => {
const user = userEvent.setup();
const { getByRole } = renderComponent();
userEvent.click(getByRole('button', { name: messages.cardCancel.defaultMessage }));
await user.click(getByRole('button', { name: messages.cardCancel.defaultMessage }));
await waitFor(() => {
expect(store.getState().certificates.componentMode).toBe(MODE_STATES.noCertificates);
@@ -127,13 +132,14 @@ describe('CertificateCreateForm', () => {
});
it('add and delete signatory', async () => {
const user = userEvent.setup();
const {
getAllByRole, queryAllByRole, getByText, getByRole,
} = renderComponent();
const addSignatoryBtn = getByText(signatoryMessages.addSignatoryButton.defaultMessage);
userEvent.click(addSignatoryBtn);
await user.click(addSignatoryBtn);
const deleteIcons = getAllByRole('button', { name: messages.deleteTooltip.defaultMessage });
@@ -141,13 +147,13 @@ describe('CertificateCreateForm', () => {
expect(deleteIcons.length).toBe(2);
});
userEvent.click(deleteIcons[0]);
await user.click(deleteIcons[0]);
const confirModal = getByRole('dialog');
const deleteModalButton = within(confirModal).getByRole('button', { name: messages.deleteTooltip.defaultMessage });
userEvent.click(deleteIcons[0]);
userEvent.click(deleteModalButton);
await user.click(deleteIcons[0]);
await user.click(deleteModalButton);
await waitFor(() => {
expect(queryAllByRole('button', { name: messages.deleteTooltip.defaultMessage }).length).toBe(0);

View File

@@ -1,6 +1,6 @@
import { Provider, useDispatch } from 'react-redux';
import { useParams } from 'react-router-dom';
import { render, waitFor } from '@testing-library/react';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { IntlProvider } from '@edx/frontend-platform/i18n';
import { initializeMockApp } from '@edx/frontend-platform';
@@ -86,24 +86,24 @@ describe('CertificateDetails', () => {
expect(getByText(defaultProps.detailsCourseTitle)).toBeInTheDocument();
});
it('opens confirm modal on delete button click', () => {
it('opens confirm modal on delete button click', async () => {
const user = userEvent.setup();
const { getByRole, getByText } = renderComponent(defaultProps);
const deleteButton = getByRole('button', { name: commonMessages.deleteTooltip.defaultMessage });
userEvent.click(deleteButton);
await user.click(deleteButton);
expect(getByText(messages.deleteCertificateConfirmationTitle.defaultMessage)).toBeInTheDocument();
});
it('dispatches delete action on confirm modal action', async () => {
const user = userEvent.setup();
const props = { ...defaultProps, courseId, certificateId };
const { getByRole } = renderComponent(props);
const deleteButton = getByRole('button', { name: commonMessages.deleteTooltip.defaultMessage });
userEvent.click(deleteButton);
await user.click(deleteButton);
await waitFor(() => {
const confirmActionButton = getByRole('button', { name: commonMessages.deleteTooltip.defaultMessage });
userEvent.click(confirmActionButton);
});
const confirmActionButton = await screen.findByRole('button', { name: commonMessages.deleteTooltip.defaultMessage });
await user.click(confirmActionButton);
expect(mockDispatch).toHaveBeenCalledWith(deleteCourseCertificate(courseId, certificateId));
});

View File

@@ -58,11 +58,12 @@ describe('CertificateDetails', () => {
});
it('handles input change in create mode', async () => {
const user = userEvent.setup();
const { getByPlaceholderText } = renderComponent(defaultProps);
const input = getByPlaceholderText(messages.detailsCourseTitleOverride.defaultMessage);
const newInputValue = 'New Title';
userEvent.type(input, newInputValue);
await user.type(input, newInputValue);
waitFor(() => {
expect(input.value).toBe(newInputValue);

View File

@@ -1,5 +1,7 @@
import { Provider } from 'react-redux';
import { render, waitFor, within } from '@testing-library/react';
import {
render, waitFor, within,
} from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { initializeMockApp } from '@edx/frontend-platform';
import { IntlProvider } from '@edx/frontend-platform/i18n';
@@ -68,15 +70,15 @@ describe('CertificateEditForm Component', () => {
}],
}],
};
const user = userEvent.setup();
const { getByDisplayValue, getByRole, getByPlaceholderText } = renderComponent();
userEvent.type(
await user.type(
getByPlaceholderText(messagesDetails.detailsCourseTitleOverride.defaultMessage),
courseTitleOverrideValue,
);
userEvent.click(getByRole('button', { name: messages.saveTooltip.defaultMessage }));
await user.click(getByRole('button', { name: messages.saveTooltip.defaultMessage }));
axiosMock.onPost(
getUpdateCertificateApiUrl(courseId, certificatesDataMock.certificates[0].id),
@@ -91,16 +93,17 @@ describe('CertificateEditForm Component', () => {
});
it('deletes a certificate and updates the store', async () => {
const user = userEvent.setup();
axiosMock.onDelete(
getUpdateCertificateApiUrl(courseId, certificatesDataMock.certificates[0].id),
).reply(200);
const { getByRole } = renderComponent();
userEvent.click(getByRole('button', { name: messages.deleteTooltip.defaultMessage }));
await user.click(getByRole('button', { name: messages.deleteTooltip.defaultMessage }));
const confirmDeleteModal = getByRole('dialog');
userEvent.click(within(confirmDeleteModal).getByRole('button', { name: messages.deleteTooltip.defaultMessage }));
await user.click(within(confirmDeleteModal).getByRole('button', { name: messages.deleteTooltip.defaultMessage }));
await executeThunk(deleteCourseCertificate(courseId, certificatesDataMock.certificates[0].id), store.dispatch);
@@ -110,16 +113,17 @@ describe('CertificateEditForm Component', () => {
});
it('updates loading status if delete fails', async () => {
const user = userEvent.setup();
axiosMock.onDelete(
getUpdateCertificateApiUrl(courseId, certificatesDataMock.certificates[0].id),
).reply(404);
const { getByRole } = renderComponent();
userEvent.click(getByRole('button', { name: messages.deleteTooltip.defaultMessage }));
await user.click(getByRole('button', { name: messages.deleteTooltip.defaultMessage }));
const confirmDeleteModal = getByRole('dialog');
userEvent.click(within(confirmDeleteModal).getByRole('button', { name: messages.deleteTooltip.defaultMessage }));
await user.click(within(confirmDeleteModal).getByRole('button', { name: messages.deleteTooltip.defaultMessage }));
await executeThunk(deleteCourseCertificate(courseId, certificatesDataMock.certificates[0].id), store.dispatch);
@@ -129,11 +133,12 @@ describe('CertificateEditForm Component', () => {
});
it('cancel edit form', async () => {
const user = userEvent.setup();
const { getByRole } = renderComponent();
expect(store.getState().certificates.componentMode).toBe(MODE_STATES.editAll);
userEvent.click(getByRole('button', { name: messages.cardCancel.defaultMessage }));
await user.click(getByRole('button', { name: messages.cardCancel.defaultMessage }));
expect(store.getState().certificates.componentMode).toBe(MODE_STATES.view);
});

View File

@@ -88,20 +88,22 @@ describe('CertificateSignatories', () => {
});
});
it('adds a new signatory when add button is clicked', () => {
it('adds a new signatory when add button is clicked', async () => {
const user = userEvent.setup();
const { getByText } = renderComponent({ ...defaultProps, isForm: true });
userEvent.click(getByText(messages.addSignatoryButton.defaultMessage));
await user.click(getByText(messages.addSignatoryButton.defaultMessage));
expect(useCreateSignatory().handleAddSignatory).toHaveBeenCalled();
});
it('calls remove for the correct signatory when delete icon is clicked', async () => {
const user = userEvent.setup();
const { getAllByRole } = renderComponent(defaultProps);
const deleteIcons = getAllByRole('button', { name: commonMessages.deleteTooltip.defaultMessage });
expect(deleteIcons.length).toBe(signatoriesMock.length);
userEvent.click(deleteIcons[0]);
await user.click(deleteIcons[0]);
waitFor(() => {
expect(mockArrayHelpers.remove).toHaveBeenCalledWith(0);

View File

@@ -34,11 +34,12 @@ describe('Signatory Component', () => {
expect(queryByText(messages.namePlaceholder.defaultMessage)).not.toBeInTheDocument();
});
it('calls handleEdit when the edit button is clicked', () => {
it('calls handleEdit when the edit button is clicked', async () => {
const user = userEvent.setup();
const { getByRole } = renderSignatory(defaultProps);
const editButton = getByRole('button', { name: commonMessages.editTooltip.defaultMessage });
userEvent.click(editButton);
await user.click(editButton);
expect(mockHandleEdit).toHaveBeenCalled();
});

View File

@@ -60,12 +60,13 @@ describe('Signatory Component', () => {
});
it('handles input change', async () => {
const user = userEvent.setup();
const handleChange = jest.fn();
const { getByPlaceholderText } = renderSignatory({ ...defaultProps, handleChange });
const input = getByPlaceholderText(messages.namePlaceholder.defaultMessage);
const newInputValue = 'Jane Doe';
userEvent.type(input, newInputValue, { name: 'signatories[0].name' });
await user.type(input, newInputValue, { name: 'signatories[0].name' });
waitFor(() => {
expect(handleChange).toHaveBeenCalledWith(expect.anything());
@@ -73,7 +74,8 @@ describe('Signatory Component', () => {
});
});
it('opens image upload modal on button click', () => {
it('opens image upload modal on button click', async () => {
const user = userEvent.setup();
const { getByRole, queryByRole } = renderSignatory(defaultProps);
const replaceButton = getByRole(
'button',
@@ -82,28 +84,30 @@ describe('Signatory Component', () => {
expect(queryByRole('presentation')).not.toBeInTheDocument();
userEvent.click(replaceButton);
await user.click(replaceButton);
expect(getByRole('presentation')).toBeInTheDocument();
});
it('shows confirm modal on delete icon click', async () => {
const user = userEvent.setup();
const { getByLabelText, getByText } = renderSignatory(defaultProps);
const deleteIcon = getByLabelText(commonMessages.deleteTooltip.defaultMessage);
userEvent.click(deleteIcon);
await user.click(deleteIcon);
expect(getByText(messages.deleteSignatoryConfirmationMessage.defaultMessage)).toBeInTheDocument();
});
it('cancels deletion of a signatory', () => {
it('cancels deletion of a signatory', async () => {
const user = userEvent.setup();
const { getByRole } = renderSignatory(defaultProps);
const deleteIcon = getByRole('button', { name: commonMessages.deleteTooltip.defaultMessage });
userEvent.click(deleteIcon);
await user.click(deleteIcon);
const cancelButton = getByRole('button', { name: commonMessages.cardCancel.defaultMessage });
userEvent.click(cancelButton);
await user.click(cancelButton);
expect(defaultProps.handleDeleteSignatory).not.toHaveBeenCalled();
});

View File

@@ -1,5 +1,7 @@
import { Provider } from 'react-redux';
import { render, waitFor, within } from '@testing-library/react';
import {
render, waitFor, within,
} from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { initializeMockApp } from '@edx/frontend-platform';
import { IntlProvider } from '@edx/frontend-platform/i18n';
@@ -62,6 +64,7 @@ describe('CertificatesList Component', () => {
});
it('update certificate', async () => {
const user = userEvent.setup();
const {
getByText, queryByText, getByPlaceholderText, getByRole, getAllByLabelText,
} = renderComponent();
@@ -80,13 +83,13 @@ describe('CertificatesList Component', () => {
const editButtons = getAllByLabelText(messages.editTooltip.defaultMessage);
userEvent.click(editButtons[1]);
await user.click(editButtons[1]);
const nameInput = getByPlaceholderText(signatoryMessages.namePlaceholder.defaultMessage);
userEvent.clear(nameInput);
userEvent.type(nameInput, signatoryNameValue);
await user.clear(nameInput);
await user.type(nameInput, signatoryNameValue);
userEvent.click(getByRole('button', { name: messages.saveTooltip.defaultMessage }));
await user.click(getByRole('button', { name: messages.saveTooltip.defaultMessage }));
axiosMock
.onPost(getUpdateCertificateApiUrl(courseId, certificatesMock.id))
@@ -100,6 +103,7 @@ describe('CertificatesList Component', () => {
});
it('toggle edit signatory', async () => {
const user = userEvent.setup();
const {
getAllByLabelText, queryByPlaceholderText, getByTestId, getByPlaceholderText,
} = renderComponent();
@@ -107,13 +111,13 @@ describe('CertificatesList Component', () => {
expect(editButtons.length).toBe(3);
userEvent.click(editButtons[1]);
await user.click(editButtons[1]);
await waitFor(() => {
expect(getByPlaceholderText(signatoryMessages.namePlaceholder.defaultMessage)).toBeInTheDocument();
});
userEvent.click(within(getByTestId('signatory-form')).getByRole('button', { name: messages.cardCancel.defaultMessage }));
await user.click(within(getByTestId('signatory-form')).getByRole('button', { name: messages.cardCancel.defaultMessage }));
await waitFor(() => {
expect(queryByPlaceholderText(signatoryMessages.namePlaceholder.defaultMessage)).not.toBeInTheDocument();
@@ -121,10 +125,11 @@ describe('CertificatesList Component', () => {
});
it('toggle certificate edit all', async () => {
const user = userEvent.setup();
const { getByTestId } = renderComponent();
const detailsSection = getByTestId('certificate-details');
const editButton = within(detailsSection).getByLabelText(messages.editTooltip.defaultMessage);
userEvent.click(editButton);
await user.click(editButton);
await waitFor(() => {
expect(store.getState().certificates.componentMode).toBe(MODE_STATES.editAll);

View File

@@ -35,7 +35,7 @@ export async function createCertificate(courseId, certificatesData) {
getCertificateApiUrl(courseId),
prepareCertificatePayload(certificatesData),
);
/* istanbul ignore next */
return camelCaseObject(data);
}
@@ -51,6 +51,7 @@ export async function updateCertificate(courseId, certificateData) {
getUpdateCertificateApiUrl(courseId, certificateData.id),
prepareCertificatePayload(certificateData),
);
/* istanbul ignore next */
return camelCaseObject(data);
}

View File

@@ -29,12 +29,11 @@ const slice = createSlice({
fetchCertificatesSuccess: (state, { payload }) => {
Object.assign(state.certificatesData, payload);
},
createCertificateSuccess: (state, action) => {
createCertificateSuccess: /* istanbul ignore next */ (state, action) => {
state.certificatesData.certificates.push(action.payload);
},
updateCertificateSuccess: (state, action) => {
updateCertificateSuccess: /* istanbul ignore next */ (state, action) => {
const index = state.certificatesData.certificates.findIndex(c => c.id === action.payload.id);
if (index !== -1) {
state.certificatesData.certificates[index] = action.payload;
}

View File

@@ -1,3 +1,4 @@
/* istanbul ignore file */
import { RequestStatus } from '../../data/constants';
import {
hideProcessingNotification,

View File

@@ -53,16 +53,17 @@ describe('HeaderButtons Component', () => {
});
it('updates preview URL param based on selected dropdown item', async () => {
const user = userEvent.setup();
const { getByRole } = renderComponent();
const previewLink = getByRole('link', { name: messages.headingActionsPreview.defaultMessage });
expect(previewLink).toHaveAttribute('href', expect.stringContaining(certificatesDataMock.courseModes[0]));
const dropdownButton = getByRole('button', { name: certificatesDataMock.courseModes[0] });
userEvent.click(dropdownButton);
await user.click(dropdownButton);
const verifiedMode = await getByRole('button', { name: certificatesDataMock.courseModes[1] });
userEvent.click(verifiedMode);
await user.click(verifiedMode);
await waitFor(() => {
expect(previewLink).toHaveAttribute('href', expect.stringContaining(certificatesDataMock.courseModes[1]));
@@ -70,6 +71,7 @@ describe('HeaderButtons Component', () => {
});
it('activates certificate when button is clicked', async () => {
const user = userEvent.setup();
const newCertificateData = {
...certificatesDataMock,
isActive: true,
@@ -78,7 +80,7 @@ describe('HeaderButtons Component', () => {
const { getByRole, queryByRole } = renderComponent();
const activationButton = getByRole('button', { name: messages.headingActionsActivate.defaultMessage });
userEvent.click(activationButton);
await user.click(activationButton);
axiosMock.onPost(
getUpdateCertificateApiUrl(courseId, certificatesDataMock.certificates[0].id),
@@ -97,6 +99,7 @@ describe('HeaderButtons Component', () => {
});
it('deactivates certificate when button is clicked', async () => {
const user = userEvent.setup();
axiosMock
.onGet(getCertificatesApiUrl(courseId))
.reply(200, { ...certificatesDataMock, isActive: true });
@@ -110,7 +113,7 @@ describe('HeaderButtons Component', () => {
const { getByRole, queryByRole } = renderComponent();
const deactivateButton = getByRole('button', { name: messages.headingActionsDeactivate.defaultMessage });
userEvent.click(deactivateButton);
await user.click(deactivateButton);
axiosMock.onPost(
getUpdateCertificateApiUrl(courseId, certificatesDataMock.certificates[0].id),

View File

@@ -508,6 +508,7 @@ describe('<ContentTagsCollapsible />', () => {
});
it('should handle search term change', async () => {
const user = userEvent.setup({ advanceTimers: jest.advanceTimersByTime });
const {
getByText, getByRole, getByDisplayValue,
} = await getComponent();
@@ -523,7 +524,7 @@ describe('<ContentTagsCollapsible />', () => {
const searchTerm = 'memo';
// Trigger a change in the search field
userEvent.type(searchField, searchTerm);
await user.type(searchField, searchTerm);
await act(async () => {
// Fast-forward time by 500 milliseconds (for the debounce delay)
@@ -535,14 +536,14 @@ describe('<ContentTagsCollapsible />', () => {
expect(getByDisplayValue(searchTerm)).toBeInTheDocument();
// Clear search
userEvent.clear(searchField);
fireEvent.change(searchField, { target: { value: '' } });
// Check that the search term has been cleared
expect(searchField).toHaveValue('');
});
it('should close dropdown selector when clicking away', async () => {
const { getByText, queryByText } = await getComponent();
const { container, getByText, queryByText } = await getComponent();
// Click on "Add a tag" button to open dropdown
const addTagsButton = getByText(messages.collapsibleAddTagsPlaceholderText.defaultMessage);
@@ -554,10 +555,9 @@ describe('<ContentTagsCollapsible />', () => {
expect(queryByText('Tag 3')).toBeInTheDocument();
// Simulate clicking outside the dropdown remove focus
userEvent.click(document.body);
// Simulate clicking outside the dropdown again to close it
userEvent.click(document.body);
const outsideElement = container.querySelector('.taxonomy-tags-count-chip');
const selectElement = container.querySelector('.react-select-add-tags__input');
fireEvent.blur(selectElement, { relatedTarget: outsideElement });
// Wait for the dropdown selector for tags to close, Tag 3 is no longer on
// the page
@@ -565,6 +565,7 @@ describe('<ContentTagsCollapsible />', () => {
});
it('should test keyboard navigation of add tags widget', async () => {
const user = userEvent.setup({ delay: null });
const {
getByText,
queryByText,
@@ -598,59 +599,61 @@ describe('<ContentTagsCollapsible />', () => {
*/
// Press tab to focus on first element in dropdown, Tag 1 should be focused
userEvent.tab();
await user.keyboard('{Tab}');
const dropdownTag1Div = queryAllByText('Tag 1')[1].closest('.dropdown-selector-tag-actions');
expect(dropdownTag1Div).toHaveFocus();
// Press right arrow to expand Tag 1, Tag 1.1 & Tag 1.2 should now be visible
userEvent.keyboard('{arrowright}');
await user.keyboard('{arrowright}');
expect(queryAllByText('Tag 1.1').length).toBe(2);
expect(queryByText('Tag 1.2')).toBeInTheDocument();
// Press left arrow to collapse Tag 1, Tag 1.1 & Tag 1.2 should not be visible
userEvent.keyboard('{arrowleft}');
await user.keyboard('{arrowleft}');
expect(queryAllByText('Tag 1.1').length).toBe(1);
expect(queryByText('Tag 1.2')).not.toBeInTheDocument();
// Press enter key to expand Tag 1, Tag 1.1 & Tag 1.2 should now be visible
userEvent.keyboard('{enter}');
await user.keyboard('{enter}');
expect(queryAllByText('Tag 1.1').length).toBe(2);
expect(queryByText('Tag 1.2')).toBeInTheDocument();
// Press down arrow to navigate to Tag 1.1, it should be focused
userEvent.keyboard('{arrowdown}');
await user.keyboard('{arrowdown}');
const dropdownTag1pt1Div = queryAllByText('Tag 1.1')[1].closest('.dropdown-selector-tag-actions');
expect(dropdownTag1pt1Div).toHaveFocus();
// Press down arrow again to navigate to Tag 1.2, it should be fouced
userEvent.keyboard('{arrowdown}');
await user.keyboard('{arrowdown}');
const dropdownTag1pt2Div = queryAllByText('Tag 1.2')[0].closest('.dropdown-selector-tag-actions');
expect(dropdownTag1pt2Div).toHaveFocus();
// Press down arrow again to navigate to Tag 2, it should be fouced
userEvent.keyboard('{arrowdown}');
await user.keyboard('{arrowdown}');
const dropdownTag2Div = queryAllByText('Tag 2')[1].closest('.dropdown-selector-tag-actions');
expect(dropdownTag2Div).toHaveFocus();
// Press up arrow to navigate back to Tag 1.2, it should be focused
userEvent.keyboard('{arrowup}');
await user.keyboard('{arrowup}');
expect(dropdownTag1pt2Div).toHaveFocus();
// Press up arrow to navigate back to Tag 1.1, it should be focused
userEvent.keyboard('{arrowup}');
await user.keyboard('{arrowup}');
expect(dropdownTag1pt1Div).toHaveFocus();
// Press up arrow again to navigate to Tag 1, it should be focused
userEvent.keyboard('{arrowup}');
await user.keyboard('{arrowup}');
expect(dropdownTag1Div).toHaveFocus();
// Press down arrow twice to navigate to Tag 1.2, it should be focsed
userEvent.keyboard('{arrowdown}');
userEvent.keyboard('{arrowdown}');
await user.keyboard('{arrowdown}');
await user.keyboard('{arrowdown}');
expect(dropdownTag1pt2Div).toHaveFocus();
// Press space key to check Tag 1.2, it should be staged
userEvent.keyboard('{space}');
await user.keyboard('[Space]');
const taxonomyId = 123;
const addedStagedTag = {
value: 'Tag%201,Tag%201.2',
@@ -659,35 +662,35 @@ describe('<ContentTagsCollapsible />', () => {
expect(data.addStagedContentTag).toHaveBeenCalledWith(taxonomyId, addedStagedTag);
// Press enter key again to uncheck Tag 1.2 (since it's a leaf), it should be unstaged
userEvent.keyboard('{enter}');
await user.keyboard('{enter}');
const tagValue = 'Tag%201,Tag%201.2';
expect(data.removeStagedContentTag).toHaveBeenCalledWith(taxonomyId, tagValue);
// Press left arrow to navigate back to Tag 1, it should be focused
userEvent.keyboard('{arrowleft}');
await user.keyboard('{arrowleft}');
expect(dropdownTag1Div).toHaveFocus();
// Press tab key it should jump to cancel button, it should be focused
userEvent.tab();
await user.keyboard('{Tab}');
const dropdownCancel = getByText(messages.collapsibleCancelStagedTagsButtonText.defaultMessage);
expect(dropdownCancel).toHaveFocus();
// Press tab again, it should exit and close the select menu, since there are not staged tags
userEvent.tab();
await user.keyboard('{Tab}');
expect(queryByText('Tag 3')).not.toBeInTheDocument();
// Press shift tab, focus back on select menu input, it should open the menu
userEvent.tab({ shift: true });
await user.tab({ shift: true });
expect(queryByText('Tag 3')).toBeInTheDocument();
// Press shift tab again, it should focus out and close the select menu
userEvent.tab({ shift: true });
await user.tab({ shift: true });
expect(queryByText('Tag 3')).not.toBeInTheDocument();
// Press tab again, the select menu should open, then press escape, it should close
userEvent.tab();
await user.keyboard('{Tab}');
expect(queryByText('Tag 3')).toBeInTheDocument();
userEvent.keyboard('{escape}');
await user.keyboard('{escape}');
expect(queryByText('Tag 3')).not.toBeInTheDocument();
});
@@ -699,7 +702,7 @@ describe('<ContentTagsCollapsible />', () => {
const xButtonAppliedTag = within(appliedTag).getByRole('button', {
name: /delete/i,
});
await userEvent.click(xButtonAppliedTag);
fireEvent.click(xButtonAppliedTag);
// Check that the applied tag has been removed
expect(appliedTag).not.toBeInTheDocument();

View File

@@ -75,13 +75,14 @@ describe('<CourseLibraries />', () => {
});
it('shows alert when out of sync components are present', async () => {
const user = userEvent.setup();
await renderCourseLibrariesPage(mockGetEntityLinks.courseKey);
const allTab = await screen.findByRole('tab', { name: 'Libraries' });
const reviewTab = await screen.findByRole('tab', { name: 'Review Content Updates 5' });
// review tab should be open by default as outOfSyncCount is greater than 0
expect(reviewTab).toHaveAttribute('aria-selected', 'true');
userEvent.click(allTab);
await user.click(allTab);
const alert = await screen.findByRole('alert');
expect(await within(alert).findByText(
'5 library components are out of sync. Review updates to accept or ignore changes',
@@ -89,7 +90,7 @@ describe('<CourseLibraries />', () => {
expect(allTab).toHaveAttribute('aria-selected', 'true');
const reviewBtn = await screen.findByRole('button', { name: 'Review' });
userEvent.click(reviewBtn);
await user.click(reviewBtn);
expect(allTab).toHaveAttribute('aria-selected', 'false');
expect(await screen.findByRole('tab', { name: 'Review Content Updates 5' })).toHaveAttribute('aria-selected', 'true');
@@ -97,12 +98,13 @@ describe('<CourseLibraries />', () => {
});
it('hide alert on dismiss', async () => {
const user = userEvent.setup();
await renderCourseLibrariesPage(mockGetEntityLinks.courseKey);
const reviewTab = await screen.findByRole('tab', { name: 'Review Content Updates 5' });
// review tab should be open by default as outOfSyncCount is greater than 0
expect(reviewTab).toHaveAttribute('aria-selected', 'true');
const allTab = await screen.findByRole('tab', { name: 'Libraries' });
userEvent.click(allTab);
await user.click(allTab);
expect(allTab).toHaveAttribute('aria-selected', 'true');
const alert = await screen.findByRole('alert');
@@ -110,16 +112,17 @@ describe('<CourseLibraries />', () => {
'5 library components are out of sync. Review updates to accept or ignore changes',
)).toBeInTheDocument();
const dismissBtn = await screen.findByRole('button', { name: 'Dismiss' });
userEvent.click(dismissBtn);
await user.click(dismissBtn);
expect(allTab).toHaveAttribute('aria-selected', 'true');
waitFor(() => expect(alert).not.toBeInTheDocument());
// review updates button
const reviewActionBtn = await screen.findByRole('button', { name: 'Review Updates' });
userEvent.click(reviewActionBtn);
await user.click(reviewActionBtn);
expect(await screen.findByRole('tab', { name: 'Review Content Updates 5' })).toHaveAttribute('aria-selected', 'true');
});
it('show alert if max lastPublishedDate is greated than the local storage value', async () => {
const user = userEvent.setup();
const lastPublishedDate = new Date('2025-05-01T22:20:44.989042Z');
localStorage.setItem(
`outOfSyncCountAlert-${mockGetEntityLinks.courseKey}`,
@@ -132,7 +135,7 @@ describe('<CourseLibraries />', () => {
// review tab should be open by default as outOfSyncCount is greater than 0
expect(reviewTab).toHaveAttribute('aria-selected', 'true');
userEvent.click(allTab);
await user.click(allTab);
const alert = await screen.findByRole('alert');
expect(await within(alert).findByText(
'5 library components are out of sync. Review updates to accept or ignore changes',
@@ -140,6 +143,7 @@ describe('<CourseLibraries />', () => {
});
it('doesnt show alert if max lastPublishedDate is less than the local storage value', async () => {
const user = userEvent.setup();
const lastPublishedDate = new Date('2025-05-01T22:20:44.989042Z');
localStorage.setItem(
`outOfSyncCountAlert-${mockGetEntityLinks.courseKey}`,
@@ -151,7 +155,7 @@ describe('<CourseLibraries />', () => {
const reviewTab = await screen.findByRole('tab', { name: 'Review Content Updates 5' });
// review tab should be open by default as outOfSyncCount is greater than 0
expect(reviewTab).toHaveAttribute('aria-selected', 'true');
userEvent.click(allTab);
await user.click(allTab);
expect(allTab).toHaveAttribute('aria-selected', 'true');
screen.logTestingPlaygroundURL();
@@ -199,13 +203,14 @@ describe('<CourseLibraries ReviewTab />', () => {
});
it('update changes works', async () => {
const user = userEvent.setup();
const mockInvalidateQueries = jest.spyOn(queryClient, 'invalidateQueries');
const usageKey = mockGetEntityLinks.response[0].downstreamUsageKey;
axiosMock.onPost(libraryBlockChangesUrl(usageKey)).reply(200, {});
await renderCourseLibrariesReviewPage(mockGetEntityLinksSummaryByDownstreamContext.courseKey);
const updateBtns = await screen.findAllByRole('button', { name: 'Update' });
expect(updateBtns.length).toEqual(5);
userEvent.click(updateBtns[0]);
await user.click(updateBtns[0]);
await waitFor(() => {
expect(axiosMock.history.post.length).toEqual(1);
});
@@ -215,16 +220,17 @@ describe('<CourseLibraries ReviewTab />', () => {
});
it('update changes works in preview modal', async () => {
const user = userEvent.setup();
const mockInvalidateQueries = jest.spyOn(queryClient, 'invalidateQueries');
const usageKey = mockGetEntityLinks.response[0].downstreamUsageKey;
axiosMock.onPost(libraryBlockChangesUrl(usageKey)).reply(200, {});
await renderCourseLibrariesReviewPage(mockGetEntityLinksSummaryByDownstreamContext.courseKey);
const previewBtns = await screen.findAllByRole('button', { name: 'Review Updates' });
expect(previewBtns.length).toEqual(5);
userEvent.click(previewBtns[0]);
await user.click(previewBtns[0]);
const dialog = await screen.findByRole('dialog');
const confirmBtn = await within(dialog).findByRole('button', { name: 'Accept changes' });
userEvent.click(confirmBtn);
await user.click(confirmBtn);
await waitFor(() => {
expect(axiosMock.history.post.length).toEqual(1);
});
@@ -234,6 +240,7 @@ describe('<CourseLibraries ReviewTab />', () => {
});
it('ignore change works', async () => {
const user = userEvent.setup();
const mockInvalidateQueries = jest.spyOn(queryClient, 'invalidateQueries');
const usageKey = mockGetEntityLinks.response[0].downstreamUsageKey;
axiosMock.onDelete(libraryBlockChangesUrl(usageKey)).reply(204, {});
@@ -241,11 +248,11 @@ describe('<CourseLibraries ReviewTab />', () => {
const ignoreBtns = await screen.findAllByRole('button', { name: 'Ignore' });
expect(ignoreBtns.length).toEqual(5);
// Show confirmation modal on clicking ignore.
userEvent.click(ignoreBtns[0]);
await user.click(ignoreBtns[0]);
const dialog = await screen.findByRole('dialog', { name: 'Ignore these changes?' });
expect(dialog).toBeInTheDocument();
const confirmBtn = await within(dialog).findByRole('button', { name: 'Ignore' });
userEvent.click(confirmBtn);
await user.click(confirmBtn);
await waitFor(() => {
expect(axiosMock.history.delete.length).toEqual(1);
});
@@ -257,21 +264,22 @@ describe('<CourseLibraries ReviewTab />', () => {
});
it('ignore change works in preview', async () => {
const user = userEvent.setup();
const mockInvalidateQueries = jest.spyOn(queryClient, 'invalidateQueries');
const usageKey = mockGetEntityLinks.response[0].downstreamUsageKey;
axiosMock.onDelete(libraryBlockChangesUrl(usageKey)).reply(204, {});
await renderCourseLibrariesReviewPage(mockGetEntityLinksSummaryByDownstreamContext.courseKey);
const previewBtns = await screen.findAllByRole('button', { name: 'Review Updates' });
expect(previewBtns.length).toEqual(5);
userEvent.click(previewBtns[0]);
await user.click(previewBtns[0]);
const previewDialog = await screen.findByRole('dialog');
const ignoreBtn = await within(previewDialog).findByRole('button', { name: 'Ignore changes' });
userEvent.click(ignoreBtn);
await user.click(ignoreBtn);
// Show confirmation modal on clicking ignore.
const dialog = await screen.findByRole('dialog', { name: 'Ignore these changes?' });
expect(dialog).toBeInTheDocument();
const confirmBtn = await within(dialog).findByRole('button', { name: 'Ignore' });
userEvent.click(confirmBtn);
await user.click(confirmBtn);
await waitFor(() => {
expect(axiosMock.history.delete.length).toEqual(1);
});

View File

@@ -106,20 +106,22 @@ describe('<HeaderNavigations />', () => {
});
it('render reindex button tooltip correctly', async () => {
const user = userEvent.setup();
const { getByText, getByRole } = renderComponent({
isDisabledReindexButton: false,
});
userEvent.hover(getByRole('button', { name: messages.reindexButton.defaultMessage }));
await user.hover(getByRole('button', { name: messages.reindexButton.defaultMessage }));
await waitFor(() => {
expect(getByText(messages.reindexButtonTooltip.defaultMessage)).toBeInTheDocument();
});
});
it('not render reindex button tooltip when button is disabled correctly', async () => {
const user = userEvent.setup();
const { queryByText, getByRole } = renderComponent({
isDisabledReindexButton: true,
});
userEvent.hover(getByRole('button', { name: messages.reindexButton.defaultMessage }));
await user.pointer(getByRole('button', { name: messages.reindexButton.defaultMessage }));
await waitFor(() => {
expect(queryByText(messages.reindexButtonTooltip.defaultMessage)).not.toBeInTheDocument();
});

View File

@@ -341,6 +341,7 @@ describe('<CourseUnit />', () => {
});
it('checks whether xblock is removed when the corresponding delete button is clicked and the sidebar is the updated', async () => {
const user = userEvent.setup();
render(<RootWrapper />);
await waitFor(async () => {
@@ -372,7 +373,7 @@ describe('<CourseUnit />', () => {
});
expect(screen.getByRole('dialog')).toBeInTheDocument();
userEvent.click(deleteButton);
await user.click(deleteButton);
});
axiosMock
@@ -465,6 +466,7 @@ describe('<CourseUnit />', () => {
});
it('checks if xblock is a duplicate when the corresponding duplicate button is clicked and if the sidebar status is updated', async () => {
const user = userEvent.setup();
render(<RootWrapper />);
simulatePostMessageEvent(messageTypes.duplicateXBlock, {
@@ -499,19 +501,19 @@ describe('<CourseUnit />', () => {
children: updatedCourseVerticalChildren,
});
await waitFor(() => {
userEvent.click(screen.getByRole('button', { name: sidebarMessages.actionButtonPublishTitle.defaultMessage }));
await user.click(
await screen.findByRole('button', { name: sidebarMessages.actionButtonPublishTitle.defaultMessage }),
);
const iframe = screen.getByTitle(xblockContainerIframeMessages.xblockIframeTitle.defaultMessage);
expect(iframe).toHaveAttribute(
'aria-label',
xblockContainerIframeMessages.xblockIframeLabel.defaultMessage
.replace('{xblockCount}', courseVerticalChildrenMock.children.length),
);
const iframe = screen.getByTitle(xblockContainerIframeMessages.xblockIframeTitle.defaultMessage);
expect(iframe).toHaveAttribute(
'aria-label',
xblockContainerIframeMessages.xblockIframeLabel.defaultMessage
.replace('{xblockCount}', courseVerticalChildrenMock.children.length),
);
simulatePostMessageEvent(messageTypes.duplicateXBlock, {
id: courseVerticalChildrenMock.children[0].block_id,
});
simulatePostMessageEvent(messageTypes.duplicateXBlock, {
id: courseVerticalChildrenMock.children[0].block_id,
});
axiosMock
@@ -549,37 +551,36 @@ describe('<CourseUnit />', () => {
.reply(200, courseSectionVerticalMock);
await executeThunk(editCourseUnitVisibilityAndData(blockId, PUBLISH_TYPES.makePublic, true), store.dispatch);
await waitFor(() => {
const iframe = screen.getByTitle(xblockContainerIframeMessages.xblockIframeTitle.defaultMessage);
expect(iframe).toHaveAttribute(
'aria-label',
xblockContainerIframeMessages.xblockIframeLabel.defaultMessage
.replace('{xblockCount}', updatedCourseVerticalChildren.length),
);
const xblockIframe = await screen.findByTitle(xblockContainerIframeMessages.xblockIframeTitle.defaultMessage);
expect(xblockIframe).toHaveAttribute(
'aria-label',
xblockContainerIframeMessages.xblockIframeLabel.defaultMessage
.replace('{xblockCount}', updatedCourseVerticalChildren.length),
);
// after duplicate the xblock, the sidebar status changes to Draft (unpublished changes)
expect(screen.getByText(sidebarMessages.sidebarTitleDraftUnpublishedChanges.defaultMessage)).toBeInTheDocument();
expect(screen.getByText(sidebarMessages.visibilityStaffAndLearnersTitle.defaultMessage)).toBeInTheDocument();
expect(screen.getByText(sidebarMessages.releaseStatusTitle.defaultMessage)).toBeInTheDocument();
expect(screen.getByText(sidebarMessages.sidebarBodyNote.defaultMessage)).toBeInTheDocument();
expect(screen.getByText(sidebarMessages.visibilityWillBeVisibleToTitle.defaultMessage)).toBeInTheDocument();
expect(screen.getByText(sidebarMessages.visibilityCheckboxTitle.defaultMessage)).toBeInTheDocument();
expect(screen.getByText(sidebarMessages.actionButtonPublishTitle.defaultMessage)).toBeInTheDocument();
expect(screen.getByText(sidebarMessages.actionButtonDiscardChangesTitle.defaultMessage)).toBeInTheDocument();
expect(screen.getByText(courseSectionVerticalMock.xblock_info.release_date)).toBeInTheDocument();
expect(screen.getByText(
sidebarMessages.publishInfoDraftSaved.defaultMessage
.replace('{editedOn}', courseSectionVerticalMock.xblock_info.edited_on)
.replace('{editedBy}', courseSectionVerticalMock.xblock_info.edited_by),
)).toBeInTheDocument();
expect(screen.getByText(
sidebarMessages.releaseInfoWithSection.defaultMessage
.replace('{sectionName}', courseSectionVerticalMock.xblock_info.release_date_from),
)).toBeInTheDocument();
});
// after duplicate the xblock, the sidebar status changes to Draft (unpublished changes)
expect(screen.getByText(sidebarMessages.sidebarTitleDraftUnpublishedChanges.defaultMessage)).toBeInTheDocument();
expect(screen.getByText(sidebarMessages.visibilityStaffAndLearnersTitle.defaultMessage)).toBeInTheDocument();
expect(screen.getByText(sidebarMessages.releaseStatusTitle.defaultMessage)).toBeInTheDocument();
expect(screen.getByText(sidebarMessages.sidebarBodyNote.defaultMessage)).toBeInTheDocument();
expect(screen.getByText(sidebarMessages.visibilityWillBeVisibleToTitle.defaultMessage)).toBeInTheDocument();
expect(screen.getByText(sidebarMessages.visibilityCheckboxTitle.defaultMessage)).toBeInTheDocument();
expect(screen.getByText(sidebarMessages.actionButtonPublishTitle.defaultMessage)).toBeInTheDocument();
expect(screen.getByText(sidebarMessages.actionButtonDiscardChangesTitle.defaultMessage)).toBeInTheDocument();
expect(screen.getByText(courseSectionVerticalMock.xblock_info.release_date)).toBeInTheDocument();
expect(screen.getByText(
sidebarMessages.publishInfoDraftSaved.defaultMessage
.replace('{editedOn}', courseSectionVerticalMock.xblock_info.edited_on)
.replace('{editedBy}', courseSectionVerticalMock.xblock_info.edited_by),
)).toBeInTheDocument();
expect(screen.getByText(
sidebarMessages.releaseInfoWithSection.defaultMessage
.replace('{sectionName}', courseSectionVerticalMock.xblock_info.release_date_from),
)).toBeInTheDocument();
});
it('handles CourseUnit header action buttons', async () => {
const user = userEvent.setup();
const { open } = window;
window.open = jest.fn();
render(<RootWrapper />);
@@ -588,14 +589,14 @@ describe('<CourseUnit />', () => {
published_preview_link: publishedPreviewLink,
} = courseSectionVerticalMock;
await waitFor(() => {
await waitFor(async () => {
const viewLiveButton = screen.getByRole('button', { name: headerNavigationsMessages.viewLiveButton.defaultMessage });
userEvent.click(viewLiveButton);
await user.click(viewLiveButton);
expect(window.open).toHaveBeenCalled();
expect(window.open).toHaveBeenCalledWith(publishedPreviewLink, '_blank');
const previewButton = screen.getByRole('button', { name: headerNavigationsMessages.previewButton.defaultMessage });
userEvent.click(previewButton);
await user.click(previewButton);
expect(window.open).toHaveBeenCalled();
expect(window.open).toHaveBeenCalledWith(draftPreviewLink, '_blank');
});
@@ -604,6 +605,7 @@ describe('<CourseUnit />', () => {
});
it('checks courseUnit title changing when edit query is successfully', async () => {
const user = userEvent.setup();
render(<RootWrapper />);
let editTitleButton = null;
let titleEditField = null;
@@ -650,12 +652,12 @@ describe('<CourseUnit />', () => {
.queryByRole('textbox', { name: headerTitleMessages.ariaLabelButtonEdit.defaultMessage });
});
expect(titleEditField).not.toBeInTheDocument();
userEvent.click(editTitleButton);
await user.click(editTitleButton);
titleEditField = screen.getByRole('textbox', { name: headerTitleMessages.ariaLabelButtonEdit.defaultMessage });
await userEvent.clear(titleEditField);
await userEvent.type(titleEditField, newDisplayName);
await userEvent.tab();
await user.clear(titleEditField);
await user.type(titleEditField, newDisplayName);
await user.tab();
expect(titleEditField).toHaveValue(newDisplayName);
@@ -666,30 +668,32 @@ describe('<CourseUnit />', () => {
});
it('doesn\'t handle creating xblock and displays an error message', async () => {
const user = userEvent.setup();
const { courseKey, locator } = courseCreateXblockMock;
axiosMock
.onPost(postXBlockBaseApiUrl({ type: 'video', category: 'video', parentLocator: blockId }))
.reply(500, {});
const { getByRole } = render(<RootWrapper />);
await waitFor(() => {
await waitFor(async () => {
const videoButton = getByRole('button', {
name: new RegExp(`${addComponentMessages.buttonText.defaultMessage} Video`, 'i'),
});
userEvent.click(videoButton);
await user.click(videoButton);
expect(mockedUsedNavigate).not.toHaveBeenCalledWith(`/course/${courseKey}/editor/video/${locator}`);
});
});
it('handle creating Problem xblock and showing editor modal', async () => {
const user = userEvent.setup();
axiosMock
.onPost(postXBlockBaseApiUrl({ type: 'problem', category: 'problem', parentLocator: blockId }))
.reply(200, courseCreateXblockMock);
render(<RootWrapper />);
await waitFor(() => {
userEvent.click(screen.getByRole('button', { name: sidebarMessages.actionButtonPublishTitle.defaultMessage }));
await waitFor(async () => {
await user.click(screen.getByRole('button', { name: sidebarMessages.actionButtonPublishTitle.defaultMessage }));
});
axiosMock
@@ -711,13 +715,13 @@ describe('<CourseUnit />', () => {
await executeThunk(editCourseUnitVisibilityAndData(blockId, PUBLISH_TYPES.makePublic, true), store.dispatch);
await waitFor(() => {
await waitFor(async () => {
const problemButton = screen.getByRole('button', {
name: new RegExp(`problem ${addComponentMessages.buttonText.defaultMessage} Problem`, 'i'),
hidden: true,
});
userEvent.click(problemButton);
await user.click(problemButton);
});
axiosMock
@@ -748,6 +752,7 @@ describe('<CourseUnit />', () => {
});
it('correct addition of a new course unit after click on the "Add new unit" button', async () => {
const user = userEvent.setup();
render(<RootWrapper />);
let units = null;
const updatedCourseSectionVerticalData = cloneDeep(courseSectionVerticalMock);
@@ -780,7 +785,7 @@ describe('<CourseUnit />', () => {
const updatedCourseUnits = updatedCourseSectionVerticalData
.xblock_info.ancestor_info.ancestors[0].child_info.children;
userEvent.click(addNewUnitBtn);
await user.click(addNewUnitBtn);
expect(units.length).toEqual(updatedCourseUnits.length);
expect(mockedUsedNavigate).toHaveBeenCalled();
expect(mockedUsedNavigate)
@@ -788,6 +793,7 @@ describe('<CourseUnit />', () => {
});
it('the sequence unit is updated after changing the unit header', async () => {
const user = userEvent.setup();
render(<RootWrapper />);
const updatedCourseSectionVerticalData = cloneDeep(courseSectionVerticalMock);
const updatedAncestorsChild = updatedCourseSectionVerticalData.xblock_info.ancestor_info.ancestors[0];
@@ -826,13 +832,13 @@ describe('<CourseUnit />', () => {
const unitHeaderTitle = screen.getByTestId('unit-header-title');
const editTitleButton = within(unitHeaderTitle).getByRole('button', { name: headerTitleMessages.altButtonEdit.defaultMessage });
userEvent.click(editTitleButton);
await user.click(editTitleButton);
const titleEditField = within(unitHeaderTitle).getByRole('textbox', { name: headerTitleMessages.ariaLabelButtonEdit.defaultMessage });
await userEvent.clear(titleEditField);
await userEvent.type(titleEditField, newDisplayName);
await userEvent.tab();
await user.clear(titleEditField);
await user.type(titleEditField, newDisplayName);
await user.tab();
await waitFor(async () => {
const units = screen.getAllByTestId('course-unit-btn');
@@ -841,6 +847,7 @@ describe('<CourseUnit />', () => {
});
it('handles creating Video xblock and showing editor modal using videogalleryflow', async () => {
const user = userEvent.setup();
const waffleSpy = mockWaffleFlags({ useVideoGalleryFlow: true });
axiosMock
@@ -848,8 +855,8 @@ describe('<CourseUnit />', () => {
.reply(200, courseCreateXblockMock);
render(<RootWrapper />);
await waitFor(() => {
userEvent.click(screen.getByRole('button', { name: sidebarMessages.actionButtonPublishTitle.defaultMessage }));
await waitFor(async () => {
await user.click(screen.getByRole('button', { name: sidebarMessages.actionButtonPublishTitle.defaultMessage }));
});
axiosMock
@@ -888,7 +895,7 @@ describe('<CourseUnit />', () => {
hidden: true,
});
userEvent.click(videoButton);
await user.click(videoButton);
axiosMock
.onGet(getCourseSectionVerticalApiUrl(blockId))
@@ -923,10 +930,11 @@ describe('<CourseUnit />', () => {
axiosMock
.onPost(postXBlockBaseApiUrl({ type: 'video', category: 'video', parentLocator: blockId }))
.reply(200, courseCreateXblockMock);
const user = userEvent.setup();
render(<RootWrapper />);
await waitFor(() => {
userEvent.click(screen.getByRole('button', { name: sidebarMessages.actionButtonPublishTitle.defaultMessage }));
await waitFor(async () => {
await user.click(screen.getByRole('button', { name: sidebarMessages.actionButtonPublishTitle.defaultMessage }));
});
axiosMock
@@ -948,7 +956,7 @@ describe('<CourseUnit />', () => {
await executeThunk(editCourseUnitVisibilityAndData(blockId, PUBLISH_TYPES.makePublic, true), store.dispatch);
await waitFor(() => {
await waitFor(async () => {
// check if the sidebar status is Published and Live
expect(screen.getByText(sidebarMessages.sidebarTitlePublishedAndLive.defaultMessage)).toBeInTheDocument();
expect(screen.getByText(
@@ -963,7 +971,7 @@ describe('<CourseUnit />', () => {
hidden: true,
});
userEvent.click(videoButton);
await user.click(videoButton);
});
/** TODO -- fix this test.
@@ -1073,12 +1081,13 @@ describe('<CourseUnit />', () => {
});
it('should toggle visibility from sidebar and update course unit state accordingly', async () => {
const user = userEvent.setup();
render(<RootWrapper />);
let courseUnitSidebar;
let draftUnpublishedChangesHeading;
let visibilityCheckbox;
await waitFor(() => {
await waitFor(async () => {
courseUnitSidebar = screen.getByTestId('course-unit-sidebar');
draftUnpublishedChangesHeading = within(courseUnitSidebar)
@@ -1089,7 +1098,7 @@ describe('<CourseUnit />', () => {
.getByLabelText(sidebarMessages.visibilityCheckboxTitle.defaultMessage);
expect(visibilityCheckbox).not.toBeChecked();
userEvent.click(visibilityCheckbox);
await user.click(visibilityCheckbox);
});
axiosMock
@@ -1117,7 +1126,7 @@ describe('<CourseUnit />', () => {
expect(within(courseUnitSidebar)
.getByText(sidebarMessages.visibilityStaffOnlyTitle.defaultMessage)).toBeInTheDocument();
userEvent.click(visibilityCheckbox);
await user.click(visibilityCheckbox);
const modalNotification = screen.getByRole('dialog');
const makeVisibilityBtn = within(modalNotification).getByRole('button', { name: sidebarMessages.modalMakeVisibilityActionButtonText.defaultMessage });
@@ -1130,7 +1139,7 @@ describe('<CourseUnit />', () => {
expect(within(modalNotification)
.getByText(sidebarMessages.modalMakeVisibilityDescription.defaultMessage)).toBeInTheDocument();
userEvent.click(makeVisibilityBtn);
await user.click(makeVisibilityBtn);
axiosMock
.onPost(getXBlockBaseApiUrl(blockId), {
@@ -1151,16 +1160,17 @@ describe('<CourseUnit />', () => {
});
it('should publish course unit after click on the "Publish" button', async () => {
const user = userEvent.setup();
render(<RootWrapper />);
let courseUnitSidebar;
let publishBtn;
await waitFor(() => {
await waitFor(async () => {
courseUnitSidebar = screen.getByTestId('course-unit-sidebar');
publishBtn = within(courseUnitSidebar).queryByRole('button', { name: sidebarMessages.actionButtonPublishTitle.defaultMessage });
expect(publishBtn).toBeInTheDocument();
userEvent.click(publishBtn);
await user.click(publishBtn);
});
axiosMock
@@ -1193,11 +1203,12 @@ describe('<CourseUnit />', () => {
});
it('should discard changes after click on the "Discard changes" button', async () => {
const user = userEvent.setup();
render(<RootWrapper />);
let courseUnitSidebar;
let discardChangesBtn;
await waitFor(() => {
await waitFor(async () => {
courseUnitSidebar = screen.getByTestId('course-unit-sidebar');
const draftUnpublishedChangesHeading = within(courseUnitSidebar)
@@ -1206,7 +1217,7 @@ describe('<CourseUnit />', () => {
discardChangesBtn = within(courseUnitSidebar).queryByRole('button', { name: sidebarMessages.actionButtonDiscardChangesTitle.defaultMessage });
expect(discardChangesBtn).toBeInTheDocument();
userEvent.click(discardChangesBtn);
await user.click(discardChangesBtn);
const modalNotification = screen.getByRole('dialog');
expect(modalNotification).toBeInTheDocument();
@@ -1219,7 +1230,7 @@ describe('<CourseUnit />', () => {
const actionBtn = within(modalNotification).getByRole('button', { name: sidebarMessages.modalDiscardUnitChangesActionButtonText.defaultMessage });
expect(actionBtn).toBeInTheDocument();
userEvent.click(actionBtn);
await user.click(actionBtn);
});
axiosMock
@@ -1250,6 +1261,7 @@ describe('<CourseUnit />', () => {
});
it('should toggle visibility from header configure modal and update course unit state accordingly', async () => {
const user = userEvent.setup();
render(<RootWrapper />);
let courseUnitSidebar;
let sidebarVisibilityCheckbox;
@@ -1257,7 +1269,7 @@ describe('<CourseUnit />', () => {
let configureModal;
let restrictAccessSelect;
await waitFor(() => {
await waitFor(async () => {
courseUnitSidebar = screen.getByTestId('course-unit-sidebar');
sidebarVisibilityCheckbox = within(courseUnitSidebar)
.getByLabelText(sidebarMessages.visibilityCheckboxTitle.defaultMessage);
@@ -1266,7 +1278,7 @@ describe('<CourseUnit />', () => {
const headerConfigureBtn = screen.getByRole('button', { name: /settings/i });
expect(headerConfigureBtn).toBeInTheDocument();
userEvent.click(headerConfigureBtn);
await user.click(headerConfigureBtn);
configureModal = screen.getByTestId('configure-modal');
restrictAccessSelect = within(configureModal)
.getByRole('combobox', { name: configureModalMessages.restrictAccessTo.defaultMessage });
@@ -1281,13 +1293,13 @@ describe('<CourseUnit />', () => {
.getByRole('checkbox', { name: configureModalMessages.hideFromLearners.defaultMessage });
expect(modalVisibilityCheckbox).not.toBeChecked();
userEvent.click(modalVisibilityCheckbox);
await user.click(modalVisibilityCheckbox);
expect(modalVisibilityCheckbox).toBeChecked();
userEvent.selectOptions(restrictAccessSelect, '0');
await user.selectOptions(restrictAccessSelect, '0');
const [, group1Checkbox] = within(configureModal).getAllByRole('checkbox');
userEvent.click(group1Checkbox);
await user.click(group1Checkbox);
expect(group1Checkbox).toBeChecked();
});
@@ -1310,7 +1322,7 @@ describe('<CourseUnit />', () => {
const modalSaveBtn = within(configureModal)
.getByRole('button', { name: configureModalMessages.saveButton.defaultMessage });
userEvent.click(modalSaveBtn);
await user.click(modalSaveBtn);
await waitFor(() => {
expect(sidebarVisibilityCheckbox).toBeChecked();
@@ -1341,6 +1353,7 @@ describe('<CourseUnit />', () => {
describe('Copy paste functionality', () => {
it('should copy a unit, paste it as a new unit, and update the course section vertical data', async () => {
const user = userEvent.setup();
render(<RootWrapper />);
axiosMock
@@ -1355,8 +1368,8 @@ describe('<CourseUnit />', () => {
await executeThunk(fetchCourseSectionVerticalData(blockId), store.dispatch);
userEvent.click(screen.getByRole('button', { name: sidebarMessages.actionButtonCopyUnitTitle.defaultMessage }));
userEvent.click(screen.getByRole('button', { name: courseSequenceMessages.pasteAsNewUnitLink.defaultMessage }));
await user.click(screen.getByRole('button', { name: sidebarMessages.actionButtonCopyUnitTitle.defaultMessage }));
await user.click(screen.getByRole('button', { name: courseSequenceMessages.pasteAsNewUnitLink.defaultMessage }));
let units = null;
const updatedCourseSectionVerticalData = cloneDeep(courseSectionVerticalMock);
@@ -1394,6 +1407,7 @@ describe('<CourseUnit />', () => {
});
it('should increase the number of course XBlocks after copying and pasting a block', async () => {
const user = userEvent.setup();
render(<RootWrapper />);
simulatePostMessageEvent(messageTypes.copyXBlock, {
@@ -1411,7 +1425,7 @@ describe('<CourseUnit />', () => {
});
await executeThunk(fetchCourseSectionVerticalData(blockId), store.dispatch);
userEvent.click(screen.getByRole('button', { name: sidebarMessages.actionButtonCopyUnitTitle.defaultMessage }));
await user.click(screen.getByRole('button', { name: sidebarMessages.actionButtonCopyUnitTitle.defaultMessage }));
await waitFor(() => {
const iframe = screen.getByTitle(xblockContainerIframeMessages.xblockIframeTitle.defaultMessage);
@@ -1460,6 +1474,7 @@ describe('<CourseUnit />', () => {
});
it('displays a notification about new files after pasting a component', async () => {
const user = userEvent.setup();
render(<RootWrapper />);
axiosMock
@@ -1474,8 +1489,8 @@ describe('<CourseUnit />', () => {
await executeThunk(fetchCourseSectionVerticalData(blockId), store.dispatch);
userEvent.click(screen.getByRole('button', { name: sidebarMessages.actionButtonCopyUnitTitle.defaultMessage }));
userEvent.click(screen.getByRole('button', { name: courseSequenceMessages.pasteAsNewUnitLink.defaultMessage }));
await user.click(screen.getByRole('button', { name: sidebarMessages.actionButtonCopyUnitTitle.defaultMessage }));
await user.click(screen.getByRole('button', { name: courseSequenceMessages.pasteAsNewUnitLink.defaultMessage }));
const updatedCourseSectionVerticalData = cloneDeep(courseSectionVerticalMock);
const updatedAncestorsChild = updatedCourseSectionVerticalData.xblock_info.ancestor_info.ancestors[0];
@@ -1506,12 +1521,13 @@ describe('<CourseUnit />', () => {
expect(within(newFilesAlert).getByText(fileName)).toBeInTheDocument();
});
userEvent.click(within(newFilesAlert).getByText(/Dismiss/i));
await user.click(within(newFilesAlert).getByText(/Dismiss/i));
expect(screen.queryByTestId('has-new-files-alert')).toBeNull();
});
it('displays a notification about conflicting errors after pasting a component', async () => {
const user = userEvent.setup();
render(<RootWrapper />);
axiosMock
@@ -1526,8 +1542,8 @@ describe('<CourseUnit />', () => {
await executeThunk(fetchCourseSectionVerticalData(blockId), store.dispatch);
userEvent.click(screen.getByRole('button', { name: sidebarMessages.actionButtonCopyUnitTitle.defaultMessage }));
userEvent.click(screen.getByRole('button', { name: courseSequenceMessages.pasteAsNewUnitLink.defaultMessage }));
await user.click(screen.getByRole('button', { name: sidebarMessages.actionButtonCopyUnitTitle.defaultMessage }));
await user.click(screen.getByRole('button', { name: courseSequenceMessages.pasteAsNewUnitLink.defaultMessage }));
const updatedCourseSectionVerticalData = cloneDeep(courseSectionVerticalMock);
const updatedAncestorsChild = updatedCourseSectionVerticalData.xblock_info.ancestor_info.ancestors[0];
@@ -1560,12 +1576,13 @@ describe('<CourseUnit />', () => {
expect(within(conflictingErrorsAlert).getByText(fileName)).toBeInTheDocument();
});
userEvent.click(within(conflictingErrorsAlert).getByText(/Dismiss/i));
await user.click(within(conflictingErrorsAlert).getByText(/Dismiss/i));
expect(screen.queryByTestId('has-conflicting-errors-alert')).toBeNull();
});
it('displays a notification about error files after pasting a component', async () => {
const user = userEvent.setup();
render(<RootWrapper />);
axiosMock
@@ -1580,8 +1597,8 @@ describe('<CourseUnit />', () => {
await executeThunk(fetchCourseSectionVerticalData(blockId), store.dispatch);
userEvent.click(screen.getByRole('button', { name: sidebarMessages.actionButtonCopyUnitTitle.defaultMessage }));
userEvent.click(screen.getByRole('button', { name: courseSequenceMessages.pasteAsNewUnitLink.defaultMessage }));
await user.click(screen.getByRole('button', { name: sidebarMessages.actionButtonCopyUnitTitle.defaultMessage }));
await user.click(screen.getByRole('button', { name: courseSequenceMessages.pasteAsNewUnitLink.defaultMessage }));
const updatedCourseSectionVerticalData = cloneDeep(courseSectionVerticalMock);
const updatedAncestorsChild = updatedCourseSectionVerticalData.xblock_info.ancestor_info.ancestors[0];
@@ -1609,7 +1626,7 @@ describe('<CourseUnit />', () => {
expect(within(errorFilesAlert)
.getByText(pasteNotificationsMessages.hasErrorsDescription.defaultMessage)).toBeInTheDocument();
userEvent.click(within(errorFilesAlert).getByText(/Dismiss/i));
await user.click(within(errorFilesAlert).getByText(/Dismiss/i));
expect(screen.queryByTestId('has-error-files')).toBeNull();
});
@@ -1682,6 +1699,7 @@ describe('<CourseUnit />', () => {
});
it('should navigates to xBlock current unit', async () => {
const user = userEvent.setup();
render(<RootWrapper />);
await screen.findByText(unitDisplayName);
@@ -1702,15 +1720,15 @@ describe('<CourseUnit />', () => {
name: `${currentSection.display_name} ${moveModalMessages.moveModalOutlineItemCurrentLocationText.defaultMessage} ${moveModalMessages.moveModalOutlineItemViewText.defaultMessage}`,
});
expect(currentSectionItemBtn).toBeInTheDocument();
userEvent.click(currentSectionItemBtn);
await user.click(currentSectionItemBtn);
await waitFor(() => {
await waitFor(async () => {
const currentSubsection = currentSection.child_info.children[0];
const currentSubsectionItemBtn = screen.getByRole('button', {
name: `${currentSubsection.display_name} ${moveModalMessages.moveModalOutlineItemCurrentLocationText.defaultMessage} ${moveModalMessages.moveModalOutlineItemViewText.defaultMessage}`,
});
expect(currentSubsectionItemBtn).toBeInTheDocument();
userEvent.click(currentSubsectionItemBtn);
await user.click(currentSubsectionItemBtn);
});
await waitFor(() => {
@@ -1722,6 +1740,7 @@ describe('<CourseUnit />', () => {
});
it('should allow move operation and handles it successfully', async () => {
const user = userEvent.setup();
render(<RootWrapper />);
axiosMock
@@ -1750,24 +1769,24 @@ describe('<CourseUnit />', () => {
name: `${currentSection.display_name} ${moveModalMessages.moveModalOutlineItemCurrentLocationText.defaultMessage} ${moveModalMessages.moveModalOutlineItemViewText.defaultMessage}`,
});
expect(currentSectionItemBtn).toBeInTheDocument();
userEvent.click(currentSectionItemBtn);
await user.click(currentSectionItemBtn);
const currentSubsection = currentSection.child_info.children[1];
await waitFor(() => {
await waitFor(async () => {
const currentSubsectionItemBtn = screen.getByRole('button', {
name: `${currentSubsection.display_name} ${moveModalMessages.moveModalOutlineItemViewText.defaultMessage}`,
});
expect(currentSubsectionItemBtn).toBeInTheDocument();
userEvent.click(currentSubsectionItemBtn);
await user.click(currentSubsectionItemBtn);
});
await waitFor(() => {
await waitFor(async () => {
const currentUnit = currentSubsection.child_info.children[0];
const currentUnitItemBtn = screen.getByRole('button', {
name: `${currentUnit.display_name} ${moveModalMessages.moveModalOutlineItemViewText.defaultMessage}`,
});
expect(currentUnitItemBtn).toBeInTheDocument();
userEvent.click(currentUnitItemBtn);
await user.click(currentUnitItemBtn);
});
const moveModalBtn = screen.getByRole('button', {
@@ -1775,7 +1794,7 @@ describe('<CourseUnit />', () => {
});
expect(moveModalBtn).toBeInTheDocument();
expect(moveModalBtn).not.toBeDisabled();
userEvent.click(moveModalBtn);
await user.click(moveModalBtn);
await waitFor(() => {
expect(window.scrollTo).toHaveBeenCalledWith({ top: 0, behavior: 'smooth' });
@@ -1784,6 +1803,7 @@ describe('<CourseUnit />', () => {
});
it('should display "Move Confirmation" alert after moving and undo operations', async () => {
const user = userEvent.setup();
render(<RootWrapper />);
axiosMock
@@ -1817,7 +1837,7 @@ describe('<CourseUnit />', () => {
expect(undoButton).toBeInTheDocument();
expect(newLocationButton).toBeInTheDocument();
userEvent.click(undoButton);
await user.click(undoButton);
await waitFor(() => {
expect(screen.getByText(messages.alertMoveCancelTitle.defaultMessage)).toBeInTheDocument();
@@ -1831,6 +1851,7 @@ describe('<CourseUnit />', () => {
});
it('should navigate to new location by button click', async () => {
const user = userEvent.setup();
render(<RootWrapper />);
axiosMock
@@ -1849,7 +1870,7 @@ describe('<CourseUnit />', () => {
const newLocationButton = screen.queryByRole('button', {
name: messages.newLocationButton.defaultMessage, hidden: true,
});
userEvent.click(newLocationButton);
await user.click(newLocationButton);
expect(mockedUsedNavigate).toHaveBeenCalledWith(
`/course/${courseId}/container/${blockId}/${requestData.currentParentLocator}`,
{ replace: true },
@@ -1885,6 +1906,7 @@ describe('<CourseUnit />', () => {
});
it('closes xblock restrict access modal when cancel button is clicked', async () => {
const user = userEvent.setup();
render(<RootWrapper />);
await waitFor(() => {
@@ -1895,10 +1917,10 @@ describe('<CourseUnit />', () => {
});
});
await waitFor(() => {
await waitFor(async () => {
const configureModal = screen.getByTestId('configure-modal');
expect(configureModal).toBeInTheDocument();
userEvent.click(within(configureModal).getByRole('button', {
await user.click(within(configureModal).getByRole('button', {
name: configureModalMessages.cancelButton.defaultMessage,
}));
expect(handleConfigureSubmitMock).not.toHaveBeenCalled();
@@ -1908,6 +1930,7 @@ describe('<CourseUnit />', () => {
});
it('handles submit xblock restrict access data when save button is clicked', async () => {
const user = userEvent.setup();
axiosMock
.onPost(getXBlockBaseApiUrl(id), {
publish: PUBLISH_TYPES.republish,
@@ -1941,7 +1964,7 @@ describe('<CourseUnit />', () => {
name: configureModalMessages.restrictAccessTo.defaultMessage,
});
await userEvent.selectOptions(restrictAccessSelect, '0');
await user.selectOptions(restrictAccessSelect, '0');
await waitFor(() => {
userPartitionInfoFormatted.selectablePartitions[0].groups.forEach((group) => {
@@ -1952,7 +1975,7 @@ describe('<CourseUnit />', () => {
});
const group1Checkbox = within(configureModal).getByRole('checkbox', { name: accessGroupName1 });
await userEvent.click(group1Checkbox);
await user.click(group1Checkbox);
expect(group1Checkbox).toBeChecked();
const saveModalBtnText = within(configureModal).getByRole('button', {
@@ -1960,7 +1983,7 @@ describe('<CourseUnit />', () => {
});
expect(saveModalBtnText).toBeInTheDocument();
await userEvent.click(saveModalBtnText);
await user.click(saveModalBtnText);
await waitFor(() => {
expect(axiosMock.history.post.length).toBeGreaterThan(0);
@@ -1972,24 +1995,26 @@ describe('<CourseUnit />', () => {
});
const checkLegacyEditModalOnEditMessage = async () => {
const user = userEvent.setup();
render(<RootWrapper />);
await waitFor(() => {
await waitFor(async () => {
const editButton = screen.getByTestId('header-edit-button');
expect(editButton).toBeInTheDocument();
const xblocksIframe = screen.getByTitle(xblockContainerIframeMessages.xblockIframeTitle.defaultMessage);
expect(xblocksIframe).toBeInTheDocument();
userEvent.click(editButton);
await user.click(editButton);
});
};
const checkRenderVisibilityModal = async (headingMessageId) => {
const user = userEvent.setup();
const { findByRole, getByTestId } = render(<RootWrapper />);
let configureModal;
let restrictAccessSelect;
const headerConfigureBtn = await findByRole('button', { name: /settings/i });
await userEvent.click(headerConfigureBtn);
await user.click(headerConfigureBtn);
await waitFor(() => {
configureModal = getByTestId('configure-modal');
@@ -2007,7 +2032,7 @@ describe('<CourseUnit />', () => {
const modalSaveBtn = within(configureModal)
.getByRole('button', { name: configureModalMessages.saveButton.defaultMessage });
userEvent.click(modalSaveBtn);
await user.click(modalSaveBtn);
};
describe('Library Content page', () => {

View File

@@ -169,25 +169,26 @@ describe('<AddComponent />', () => {
],
});
await executeThunk(fetchCourseSectionVerticalData(blockId), store.dispatch);
const user = userEvent.setup();
const { getByRole } = renderComponent();
const customComponentButton = getByRole('button', {
name: new RegExp(`${messages.buttonText.defaultMessage} Custom`, 'i'),
});
userEvent.click(customComponentButton);
await user.click(customComponentButton);
expect(handleCreateNewCourseXBlockMock).not.toHaveBeenCalled();
});
it('calls handleCreateNewCourseXblock with correct parameters when Discussion xblock create button is clicked', () => {
it('calls handleCreateNewCourseXblock with correct parameters when Discussion xblock create button is clicked', async () => {
const user = userEvent.setup();
const { getByRole } = renderComponent();
const discussionButton = getByRole('button', {
name: new RegExp(`${messages.buttonText.defaultMessage} Discussion`, 'i'),
});
userEvent.click(discussionButton);
await user.click(discussionButton);
expect(handleCreateNewCourseXBlockMock).toHaveBeenCalled();
expect(handleCreateNewCourseXBlockMock).toHaveBeenCalledWith({
parentLocator: '123',
@@ -195,14 +196,15 @@ describe('<AddComponent />', () => {
});
});
it('calls handleCreateNewCourseXblock with correct parameters when Drag-and-Drop xblock create button is clicked', () => {
it('calls handleCreateNewCourseXblock with correct parameters when Drag-and-Drop xblock create button is clicked', async () => {
const user = userEvent.setup();
const { getByRole } = renderComponent();
const discussionButton = getByRole('button', {
name: new RegExp(`${messages.buttonText.defaultMessage} Drag and Drop`, 'i'),
});
userEvent.click(discussionButton);
await user.click(discussionButton);
expect(handleCreateNewCourseXBlockMock).toHaveBeenCalled();
expect(handleCreateNewCourseXBlockMock).toHaveBeenCalledWith({
parentLocator: '123',
@@ -210,14 +212,15 @@ describe('<AddComponent />', () => {
});
});
it('calls handleCreateNewCourseXBlock with correct parameters when Problem xblock create button is clicked', () => {
it('calls handleCreateNewCourseXBlock with correct parameters when Problem xblock create button is clicked', async () => {
const user = userEvent.setup();
const { getByRole } = renderComponent();
const discussionButton = getByRole('button', {
name: new RegExp(`problem ${messages.buttonText.defaultMessage} Problem`, 'i'),
});
userEvent.click(discussionButton);
await user.click(discussionButton);
expect(handleCreateNewCourseXBlockMock).toHaveBeenCalled();
expect(handleCreateNewCourseXBlockMock).toHaveBeenCalledWith({
parentLocator: '123',
@@ -225,14 +228,15 @@ describe('<AddComponent />', () => {
}, expect.any(Function));
});
it('calls handleCreateNewCourseXBlock with correct parameters when Problem bank xblock create button is clicked', () => {
it('calls handleCreateNewCourseXBlock with correct parameters when Problem bank xblock create button is clicked', async () => {
const user = userEvent.setup();
const { getByRole } = renderComponent();
const problemBankBtn = getByRole('button', {
name: new RegExp(`${messages.buttonText.defaultMessage} Problem Bank`, 'i'),
});
userEvent.click(problemBankBtn);
await user.click(problemBankBtn);
expect(handleCreateNewCourseXBlockMock).toHaveBeenCalled();
expect(handleCreateNewCourseXBlockMock).toHaveBeenCalledWith({
parentLocator: '123',
@@ -241,14 +245,15 @@ describe('<AddComponent />', () => {
});
});
it('calls handleCreateNewCourseXBlock with correct parameters when Video xblock create button is clicked', () => {
it('calls handleCreateNewCourseXBlock with correct parameters when Video xblock create button is clicked', async () => {
const user = userEvent.setup();
const { getByRole } = renderComponent();
const discussionButton = getByRole('button', {
name: new RegExp(`${messages.buttonText.defaultMessage} Video`, 'i'),
});
userEvent.click(discussionButton);
await user.click(discussionButton);
expect(handleCreateNewCourseXBlockMock).toHaveBeenCalled();
expect(handleCreateNewCourseXBlockMock).toHaveBeenCalledWith({
parentLocator: '123',
@@ -256,14 +261,15 @@ describe('<AddComponent />', () => {
}, expect.any(Function));
});
it('creates new "Library" xblock on click', () => {
it('creates new "Library" xblock on click', async () => {
const user = userEvent.setup();
const { getByRole } = renderComponent();
const libraryButton = getByRole('button', {
name: new RegExp(`${messages.buttonText.defaultMessage} Legacy Library Content`, 'i'),
});
userEvent.click(libraryButton);
await user.click(libraryButton);
expect(handleCreateNewCourseXBlockMock).toHaveBeenCalled();
expect(handleCreateNewCourseXBlockMock).toHaveBeenCalledWith({
parentLocator: '123',
@@ -273,31 +279,33 @@ describe('<AddComponent />', () => {
});
it('verifies modal behavior on button click', async () => {
const user = userEvent.setup();
const { getByRole, queryByRole } = renderComponent();
const advancedBtn = getByRole('button', {
name: new RegExp(`${messages.buttonText.defaultMessage} Advanced`, 'i'),
});
userEvent.click(advancedBtn);
await user.click(advancedBtn);
const modalContainer = getByRole('dialog');
expect(within(modalContainer).getByRole('button', { name: messages.modalContainerCancelBtnText.defaultMessage })).toBeInTheDocument();
expect(within(modalContainer).getByRole('button', { name: messages.modalBtnText.defaultMessage })).toBeInTheDocument();
userEvent.click(within(modalContainer).getByRole('button', { name: messages.modalContainerCancelBtnText.defaultMessage }));
await user.click(within(modalContainer).getByRole('button', { name: messages.modalContainerCancelBtnText.defaultMessage }));
expect(queryByRole('button', { name: messages.modalContainerCancelBtnText.defaultMessage })).toBeNull();
expect(queryByRole('button', { name: messages.modalBtnText.defaultMessage })).toBeNull();
});
it('verifies "Advanced" component selection in modal', async () => {
const user = userEvent.setup();
const { getByRole, getByText } = renderComponent();
const advancedBtn = getByRole('button', {
name: new RegExp(`${messages.buttonText.defaultMessage} Advanced`, 'i'),
});
const componentTemplates = courseSectionVerticalMock.component_templates;
userEvent.click(advancedBtn);
await user.click(advancedBtn);
const modalContainer = getByRole('dialog');
await waitFor(() => {
@@ -313,12 +321,13 @@ describe('<AddComponent />', () => {
});
it('verifies "Text" component selection in modal', async () => {
const user = userEvent.setup();
const { getByRole, getByText } = renderComponent();
const textBtn = getByRole('button', {
name: new RegExp(`${messages.buttonText.defaultMessage} Text`, 'i'),
});
const componentTemplates = courseSectionVerticalMock.component_templates;
userEvent.click(textBtn);
await user.click(textBtn);
const modalContainer = getByRole('dialog');
await waitFor(() => {
@@ -334,13 +343,14 @@ describe('<AddComponent />', () => {
});
it('verifies "Open Response" component selection in modal', async () => {
const user = userEvent.setup();
const { getByRole, getByText } = renderComponent();
const openResponseBtn = getByRole('button', {
name: new RegExp(`${messages.buttonText.defaultMessage} Open Response`, 'i'),
});
const componentTemplates = courseSectionVerticalMock.component_templates;
userEvent.click(openResponseBtn);
await user.click(openResponseBtn);
const modalContainer = getByRole('dialog');
await waitFor(() => {
@@ -355,23 +365,24 @@ describe('<AddComponent />', () => {
});
});
it('verifies "Advanced" component creation and submission in modal', () => {
it('verifies "Advanced" component creation and submission in modal', async () => {
const user = userEvent.setup();
const { getByRole } = renderComponent();
const advancedButton = getByRole('button', {
name: new RegExp(`${messages.buttonText.defaultMessage} Advanced`, 'i'),
});
userEvent.click(advancedButton);
await user.click(advancedButton);
const modalContainer = getByRole('dialog');
const radioInput = within(modalContainer).getByRole('radio', { name: 'Annotation' });
const sendBtn = within(modalContainer).getByRole('button', { name: messages.modalBtnText.defaultMessage });
expect(sendBtn).toBeDisabled();
userEvent.click(radioInput);
await user.click(radioInput);
expect(sendBtn).not.toBeDisabled();
userEvent.click(sendBtn);
await user.click(sendBtn);
expect(handleCreateNewCourseXBlockMock).toHaveBeenCalled();
expect(handleCreateNewCourseXBlockMock).toHaveBeenCalledWith({
@@ -381,23 +392,24 @@ describe('<AddComponent />', () => {
});
});
it('verifies "Text" component creation and submission in modal', () => {
it('verifies "Text" component creation and submission in modal', async () => {
const user = userEvent.setup();
const { getByRole } = renderComponent();
const textButton = getByRole('button', {
name: new RegExp(`${messages.buttonText.defaultMessage} Text`, 'i'),
});
userEvent.click(textButton);
await user.click(textButton);
const modalContainer = getByRole('dialog');
const radioInput = within(modalContainer).getByRole('radio', { name: 'Text' });
const sendBtn = within(modalContainer).getByRole('button', { name: messages.modalBtnText.defaultMessage });
expect(sendBtn).toBeDisabled();
userEvent.click(radioInput);
await user.click(radioInput);
expect(sendBtn).not.toBeDisabled();
userEvent.click(sendBtn);
await user.click(sendBtn);
expect(handleCreateNewCourseXBlockMock).toHaveBeenCalled();
expect(handleCreateNewCourseXBlockMock).toHaveBeenCalledWith({
@@ -407,23 +419,24 @@ describe('<AddComponent />', () => {
}, expect.any(Function));
});
it('verifies "Open Response" component creation and submission in modal', () => {
it('verifies "Open Response" component creation and submission in modal', async () => {
const user = userEvent.setup();
const { getByRole } = renderComponent();
const openResponseButton = getByRole('button', {
name: new RegExp(`${messages.buttonText.defaultMessage} Open Response`, 'i'),
});
userEvent.click(openResponseButton);
await user.click(openResponseButton);
const modalContainer = getByRole('dialog');
const radioInput = within(modalContainer).getByRole('radio', { name: 'Peer Assessment Only' });
const sendBtn = within(modalContainer).getByRole('button', { name: messages.modalBtnText.defaultMessage });
expect(sendBtn).toBeDisabled();
userEvent.click(radioInput);
await user.click(radioInput);
expect(sendBtn).not.toBeDisabled();
userEvent.click(sendBtn);
await user.click(sendBtn);
expect(handleCreateNewCourseXBlockMock).toHaveBeenCalled();
expect(handleCreateNewCourseXBlockMock).toHaveBeenCalledWith({
@@ -434,15 +447,16 @@ describe('<AddComponent />', () => {
});
it('shows library picker on clicking v2 library content btn', async () => {
const user = userEvent.setup();
renderComponent();
const libBtn = await screen.findByRole('button', {
name: new RegExp(`${messages.buttonText.defaultMessage} Library content`, 'i'),
});
userEvent.click(libBtn);
await user.click(libBtn);
// click dummy button to execute onComponentSelected prop.
const dummyBtn = await screen.findByRole('button', { name: 'Dummy button' });
userEvent.click(dummyBtn);
await user.click(dummyBtn);
expect(handleCreateNewCourseXBlockMock).toHaveBeenCalled();
expect(handleCreateNewCourseXBlockMock).toHaveBeenCalledWith({
@@ -454,21 +468,23 @@ describe('<AddComponent />', () => {
});
it('closes library component picker on close', async () => {
const user = userEvent.setup();
renderComponent();
const libBtn = await screen.findByRole('button', {
name: new RegExp(`${messages.buttonText.defaultMessage} Library content`, 'i'),
});
userEvent.click(libBtn);
await user.click(libBtn);
expect(screen.queryByRole('button', { name: 'Dummy button' })).toBeInTheDocument();
// click dummy button to execute onComponentSelected prop.
const closeBtn = await screen.findByRole('button', { name: 'Close' });
userEvent.click(closeBtn);
await user.click(closeBtn);
expect(screen.queryByRole('button', { name: 'Dummy button' })).not.toBeInTheDocument();
});
it('shows component picker on window message', async () => {
const user = userEvent.setup();
renderComponent();
const message = {
data: {
@@ -482,10 +498,10 @@ describe('<AddComponent />', () => {
// click dummy button to execute onChangeComponentSelection prop.
const dummyBtn = await screen.findByRole('button', { name: 'Dummy button' });
userEvent.click(dummyBtn);
await user.click(dummyBtn);
const submitBtn = await screen.findByRole('button', { name: 'Add selected components' });
userEvent.click(submitBtn);
await user.click(submitBtn);
expect(mockSendMessageToIframe).toHaveBeenCalledWith(messageTypes.addSelectedComponentsToBank, {
selectedComponents: [{
@@ -522,13 +538,13 @@ describe('<AddComponent />', () => {
],
});
await executeThunk(fetchCourseSectionVerticalData(blockId), store.dispatch);
const user = userEvent.setup();
const { getByRole } = renderComponent();
const advancedButton = getByRole('button', {
name: new RegExp(`${messages.buttonText.defaultMessage} Advanced`, 'i'),
});
userEvent.click(advancedButton);
await user.click(advancedButton);
const modalContainer = getByRole('dialog');
const fullySupportLabel = within(modalContainer)
.queryByText(messages.modalComponentSupportLabelFullySupported.defaultMessage);
@@ -565,13 +581,13 @@ describe('<AddComponent />', () => {
],
});
await executeThunk(fetchCourseSectionVerticalData(blockId), store.dispatch);
const user = userEvent.setup();
const { getByRole, getByText } = renderComponent();
const advancedButton = getByRole('button', {
name: new RegExp(`${messages.buttonText.defaultMessage} Advanced`, 'i'),
});
userEvent.click(advancedButton);
await user.click(advancedButton);
const modalContainer = getByRole('dialog');
const fullySupportLabel = within(modalContainer)
.getByText(messages.modalComponentSupportLabelFullySupported.defaultMessage);
@@ -581,10 +597,10 @@ describe('<AddComponent />', () => {
expect(fullySupportLabel).toBeInTheDocument();
expect(provisionallySupportLabel).toBeInTheDocument();
userEvent.hover(fullySupportLabel);
await user.hover(fullySupportLabel);
expect(getByText(messages.modalComponentSupportTooltipFullySupported.defaultMessage)).toBeInTheDocument();
userEvent.hover(provisionallySupportLabel);
await user.hover(provisionallySupportLabel);
expect(getByText(messages.modalComponentSupportTooltipProvisionallySupported.defaultMessage)).toBeInTheDocument();
});
});

View File

@@ -97,6 +97,7 @@ describe('<Breadcrumbs />', () => {
});
it('render Breadcrumbs\'s dropdown menus correctly', async () => {
const user = userEvent.setup();
const { getByText, queryAllByTestId } = renderComponent();
expect(getByText(breadcrumbsExpected.section.displayName)).toBeInTheDocument();
@@ -105,31 +106,33 @@ describe('<Breadcrumbs />', () => {
expect(queryAllByTestId('breadcrumbs-subsection-dropdown-item')).toHaveLength(0);
const button = getByText(breadcrumbsExpected.section.displayName);
userEvent.click(button);
await user.click(button);
await waitFor(() => {
expect(queryAllByTestId('breadcrumbs-dropdown-item-level-0')).toHaveLength(5);
});
userEvent.click(getByText(breadcrumbsExpected.subsection.displayName));
await user.click(getByText(breadcrumbsExpected.subsection.displayName));
await waitFor(() => {
expect(queryAllByTestId('breadcrumbs-dropdown-item-level-1')).toHaveLength(2);
});
});
it('navigates using the new course outline page when the waffle flag is enabled', async () => {
const user = userEvent.setup();
// eslint-disable-next-line @typescript-eslint/naming-convention
const { ancestor_xblocks: [{ children: [{ display_name, url }] }] } = courseSectionVerticalMock;
const { getByText, getByRole } = renderComponent();
const dropdownBtn = getByText(breadcrumbsExpected.section.displayName);
userEvent.click(dropdownBtn);
await user.click(dropdownBtn);
const dropdownItem = getByRole('link', { name: display_name });
userEvent.click(dropdownItem);
await user.click(dropdownItem);
expect(dropdownItem).toHaveAttribute('href', url);
});
it('falls back to window.location.href when the waffle flag is disabled', async () => {
const user = userEvent.setup();
// eslint-disable-next-line @typescript-eslint/naming-convention
const { ancestor_xblocks: [{ children: [{ display_name, url }] }] } = courseSectionVerticalMock;
axiosMock
@@ -139,7 +142,7 @@ describe('<Breadcrumbs />', () => {
const { getByText, getByRole } = renderComponent();
const dropdownBtn = getByText(breadcrumbsExpected.section.displayName);
userEvent.click(dropdownBtn);
await user.click(dropdownBtn);
const dropdownItem = getByRole('link', { name: display_name });
// We need waitFor here because the waffle flag defaults to true but asynchronously loads false from our axiosMock

View File

@@ -99,27 +99,29 @@ describe('<HeaderTitle />', () => {
expect(getByRole('button', { name: messages.altButtonSettings.defaultMessage })).toBeEnabled();
});
it('calls toggle edit title form by clicking on Edit button', () => {
it('calls toggle edit title form by clicking on Edit button', async () => {
const user = userEvent.setup();
const { getByRole } = renderComponent();
const editTitleButton = getByRole('button', { name: messages.altButtonEdit.defaultMessage });
userEvent.click(editTitleButton);
await user.click(editTitleButton);
expect(handleTitleEdit).toHaveBeenCalledTimes(1);
});
it('calls saving title by clicking outside or press Enter key', () => {
it('calls saving title by clicking outside or press Enter key', async () => {
const user = userEvent.setup();
const { getByRole } = renderComponent({
isTitleEditFormOpen: true,
});
const titleField = getByRole('textbox', { name: messages.ariaLabelButtonEdit.defaultMessage });
userEvent.type(titleField, ' 1');
await user.type(titleField, ' 1');
expect(titleField).toHaveValue(`${unitTitle} 1`);
userEvent.click(document.body);
await user.click(document.body);
expect(handleTitleEditSubmit).toHaveBeenCalledTimes(1);
userEvent.click(titleField);
userEvent.type(titleField, ' 2[Enter]');
await user.click(titleField);
await user.type(titleField, ' 2[Enter]');
expect(titleField).toHaveValue(`${unitTitle} 1 2`);
expect(handleTitleEditSubmit).toHaveBeenCalledTimes(2);
});

View File

@@ -73,7 +73,8 @@ describe('<MoveModal />', () => {
expect(getByText('Loading...')).toBeInTheDocument();
});
it('renders component properly', () => {
it('renders component properly', async () => {
const user = userEvent.setup();
const { getByText, getByRole, getByTestId } = renderComponent();
const breadcrumbs: HTMLElement = getByTestId('move-xblock-modal-breadcrumbs');
const categoryIndicator: HTMLElement = getByTestId('move-xblock-modal-category');
@@ -88,11 +89,12 @@ describe('<MoveModal />', () => {
expect(getByRole('button', { name: messages.moveModalSubmitButton.defaultMessage })).toBeInTheDocument();
expect(getByRole('button', { name: messages.moveModalCancelButton.defaultMessage })).toBeInTheDocument();
userEvent.click(getByRole('button', { name: messages.moveModalCancelButton.defaultMessage }));
await user.click(getByRole('button', { name: messages.moveModalCancelButton.defaultMessage }));
expect(closeModalMockFn).toHaveBeenCalledTimes(1);
});
it('correctly navigates through the structure list', async () => {
const user = userEvent.setup();
const { getByText, getByRole, getByTestId } = renderComponent();
const breadcrumbs: HTMLElement = getByTestId('move-xblock-modal-breadcrumbs');
const categoryIndicator: HTMLElement = getByTestId('move-xblock-modal-category');
@@ -106,7 +108,7 @@ describe('<MoveModal />', () => {
sections.forEach((section) => {
expect(getByText(section.displayName)).toBeInTheDocument();
});
userEvent.click(getByRole('button', { name: new RegExp(sections[1].displayName, 'i') }));
await user.click(getByRole('button', { name: new RegExp(sections[1].displayName, 'i') }));
await waitFor(() => {
expect(
within(categoryIndicator).getByText(messages.moveModalBreadcrumbsSubsections.defaultMessage),
@@ -116,7 +118,7 @@ describe('<MoveModal />', () => {
expect(getByRole('button', { name: new RegExp(subsection.displayName, 'i') })).toBeInTheDocument();
});
});
userEvent.click(getByRole('button', { name: new RegExp(subsections[1].displayName, 'i') }));
await user.click(getByRole('button', { name: new RegExp(subsections[1].displayName, 'i') }));
await waitFor(() => {
expect(
within(categoryIndicator).getByText(messages.moveModalBreadcrumbsUnits.defaultMessage),
@@ -126,7 +128,7 @@ describe('<MoveModal />', () => {
expect(getByRole('button', { name: new RegExp(unit.displayName, 'i') })).toBeInTheDocument();
});
});
userEvent.click(getByRole('button', { name: new RegExp(units[0].displayName, 'i') }));
await user.click(getByRole('button', { name: new RegExp(units[0].displayName, 'i') }));
await waitFor(() => {
expect(
within(categoryIndicator).getByText(messages.moveModalBreadcrumbsComponents.defaultMessage),
@@ -141,15 +143,14 @@ describe('<MoveModal />', () => {
});
it('correctly navigates using breadcrumbs', async () => {
const { getByRole, getByTestId } = renderComponent();
const user = userEvent.setup();
const { getByRole, findByRole, getByTestId } = renderComponent();
const breadcrumbs: HTMLElement = getByTestId('move-xblock-modal-breadcrumbs');
const categoryIndicator: HTMLElement = getByTestId('move-xblock-modal-category');
await waitFor(() => {
userEvent.click(getByRole('button', { name: new RegExp(sections[1].displayName, 'i') }));
userEvent.click(getByRole('button', { name: new RegExp(subsections[1].displayName, 'i') }));
userEvent.click(within(breadcrumbs).getByText(sections[1].displayName));
});
await user.click(await findByRole('button', { name: new RegExp(sections[1].displayName, 'i') }));
await user.click(await findByRole('button', { name: new RegExp(subsections[1].displayName, 'i') }));
await user.click(within(breadcrumbs).getByText(sections[1].displayName));
await waitFor(() => {
expect(
@@ -163,16 +164,17 @@ describe('<MoveModal />', () => {
});
it('renders empty message when no components are provided', async () => {
const user = userEvent.setup();
const { getByText, getByRole } = renderComponent();
await waitFor(() => {
userEvent.click(getByRole('button', { name: new RegExp(sections[1].displayName, 'i') }));
userEvent.click(getByRole('button', { name: new RegExp(subsections[1].displayName, 'i') }));
await waitFor(async () => {
await user.click(getByRole('button', { name: new RegExp(sections[1].displayName, 'i') }));
await user.click(getByRole('button', { name: new RegExp(subsections[1].displayName, 'i') }));
});
await waitFor(() => {
await waitFor(async () => {
const unitBtn = getByRole('button', { name: new RegExp(units[7].displayName, 'i') });
userEvent.click(unitBtn);
await user.click(unitBtn);
});
await waitFor(() => {

View File

@@ -78,12 +78,13 @@ describe('<IframePreviewLibraryXBlockChanges />', () => {
});
it('accept changes works', async () => {
const user = userEvent.setup();
axiosMock.onPost(libraryBlockChangesUrl(usageKey)).reply(200, {});
render();
expect(await screen.findByText('Preview changes: Test block')).toBeInTheDocument();
const acceptBtn = await screen.findByRole('button', { name: 'Accept changes' });
userEvent.click(acceptBtn);
await user.click(acceptBtn);
await waitFor(() => {
expect(mockSendMessageToIframe).toHaveBeenCalledWith(
messageTypes.completeXBlockEditing,
@@ -96,12 +97,13 @@ describe('<IframePreviewLibraryXBlockChanges />', () => {
});
it('shows toast if accept changes fails', async () => {
const user = userEvent.setup();
axiosMock.onPost(libraryBlockChangesUrl(usageKey)).reply(500, {});
render();
expect(await screen.findByText('Preview changes: Test block')).toBeInTheDocument();
const acceptBtn = await screen.findByRole('button', { name: 'Accept changes' });
userEvent.click(acceptBtn);
await user.click(acceptBtn);
await waitFor(() => {
expect(axiosMock.history.post.length).toEqual(1);
expect(axiosMock.history.post[0].url).toEqual(libraryBlockChangesUrl(usageKey));
@@ -111,14 +113,15 @@ describe('<IframePreviewLibraryXBlockChanges />', () => {
});
it('ignore changes works', async () => {
const user = userEvent.setup();
axiosMock.onDelete(libraryBlockChangesUrl(usageKey)).reply(200, {});
render();
expect(await screen.findByText('Preview changes: Test block')).toBeInTheDocument();
const ignoreBtn = await screen.findByRole('button', { name: 'Ignore changes' });
userEvent.click(ignoreBtn);
await user.click(ignoreBtn);
const ignoreConfirmBtn = await screen.findByRole('button', { name: 'Ignore' });
userEvent.click(ignoreConfirmBtn);
await user.click(ignoreConfirmBtn);
await waitFor(() => {
expect(mockSendMessageToIframe).toHaveBeenCalledWith(
messageTypes.completeXBlockEditing,

View File

@@ -74,11 +74,12 @@ describe('<ActionButtons />', () => {
});
it('click on the Copy to clipboard button updates clipboardData', async () => {
const user = userEvent.setup();
const { getByRole } = renderComponent();
const copyXBlockBtn = getByRole('button', { name: messages.actionButtonCopyUnitTitle.defaultMessage });
userEvent.click(copyXBlockBtn);
await user.click(copyXBlockBtn);
expect(axiosMock.history.post.length).toBe(1);
expect(axiosMock.history.post[0].data).toBe(
JSON.stringify({ usage_key: courseSectionVerticalMock.xblock_info.id }),

View File

@@ -73,18 +73,20 @@ describe('<SelectableBox />', () => {
expect(selectableBox.classList.contains('pgn__selectable_box-invalid')).toEqual(true);
});
it('renders with on click event when onClick is passed', async () => {
const user = userEvent.setup();
const onClickSpy = jest.fn();
render(<SelectableCheckbox onClick={onClickSpy} />);
const selectableBox = screen.getByRole('button');
await userEvent.click(selectableBox);
await await user.click(selectableBox);
expect(onClickSpy).toHaveBeenCalledTimes(1);
});
it('renders with on key press event when onClick is passed', async () => {
const user = userEvent.setup();
const onClickSpy = jest.fn();
render(<SelectableCheckbox onClick={onClickSpy} />);
const selectableBox = screen.getByRole('button');
selectableBox.focus();
await userEvent.keyboard('{enter}');
await await user.keyboard('{enter}');
expect(onClickSpy).toHaveBeenCalledTimes(1);
});
it('renders with hidden input when inputHidden is passed', () => {
@@ -110,12 +112,13 @@ describe('<SelectableBox />', () => {
rerender(<SelectableRadio checked />);
expect(radio.className).toContain('pgn__selectable_box-active');
});
it('ref is passed to onClick function', () => {
it('ref is passed to onClick function', async () => {
const user = userEvent.setup();
let inputRef;
const onClick = (ref) => { inputRef = ref; };
render(<SelectableRadio onClick={onClick} />);
const radio = screen.getByRole('button');
userEvent.click(radio);
await user.click(radio);
expect(inputRef).not.toBeFalsy();
});
});

View File

@@ -64,10 +64,11 @@ describe('<SelectableBox.Set />', () => {
expect(screen.getByText(checkboxText(1))).toBeInTheDocument();
});
it('renders with on change event', async () => {
const user = userEvent.setup();
const onChangeSpy = jest.fn();
render(<SelectableCheckboxSet onChange={onChangeSpy} />);
const checkbox = screen.getByRole('button', { name: checkboxText(1) });
await userEvent.click(checkbox);
await await user.click(checkbox);
expect(onChangeSpy).toHaveBeenCalledTimes(1);
});
it('renders with checkbox type', () => {

View File

@@ -85,10 +85,11 @@ describe('Gallery', () => {
expect(screen.getByText('GalleryCard 1')).toBeInTheDocument();
});
it('GalleryLoadMoreButton receives correct props', () => {
it('GalleryLoadMoreButton receives correct props', async () => {
const user = userEvent.setup();
render(<Gallery {...baseProps} allowLazyLoad isLibrary={false} assetCount={5} />);
const btn = screen.getByRole('button', { name: /load more/i });
userEvent.click(btn);
await user.click(btn);
expect(baseProps.fetchNextPage).toHaveBeenCalled();
});
});

View File

@@ -73,11 +73,12 @@ describe('FormGroup', () => {
fireEvent.click(formInput);
expect(mockHandleClick).toHaveBeenCalled();
});
it('handles element change', () => {
it('handles element change', async () => {
const user = userEvent.setup();
renderComponent(defaultProps);
const formInput = screen.getByTestId('formControl');
fireEvent.focus(formInput);
userEvent.type(formInput, 'opt1');
await user.type(formInput, 'opt1');
expect(mockHandleChange).toHaveBeenCalled();
});
});

View File

@@ -84,39 +84,42 @@ describe('common/OrganizationDropdown.jsx', () => {
expect(within(screen.getByTestId('dropdown-container'))
.queryAllByRole('button').length).toEqual(0);
});
it('shows options list depends on field value', () => {
it('shows options list depends on field value', async () => {
const user = userEvent.setup();
const newProps = { ...defaultProps, options: ['opt1', 'opt2'] };
renderComponent(newProps);
const formInput = screen.getByTestId('formControl');
fireEvent.focus(formInput);
userEvent.type(formInput, 'opt1');
await user.type(formInput, 'opt1');
expect(within(screen.getByTestId('dropdown-container'))
.queryAllByRole('button').length).toEqual(1);
});
it('closes options list on click outside', async () => {
const user = userEvent.setup();
const newProps = { ...defaultProps, options: ['opt1', 'opt2'] };
renderComponent(newProps);
const formInput = screen.getByTestId('formControl');
fireEvent.click(formInput);
expect(within(screen.getByTestId('dropdown-container'))
.queryAllByRole('button').length).toEqual(2);
userEvent.click(document.body);
await user.click(document.body);
expect(within(screen.getByTestId('dropdown-container'))
.queryAllByRole('button').length).toEqual(0);
});
describe('empty options list', () => {
it('shows empty options list depends on field value', () => {
it('shows empty options list depends on field value', async () => {
const user = userEvent.setup();
const newProps = { ...defaultProps, options: ['opt1', 'opt2'] };
renderComponent(newProps);
const formInput = screen.getByTestId('formControl');
fireEvent.focus(formInput);
userEvent.type(formInput, '3');
await user.type(formInput, '3');
const noOptionsList = within(screen.getByTestId('dropdown-container')).getByText('No options');
const addButton = within(screen.getByTestId('dropdown-container')).queryByTestId('add-option-button');
expect(noOptionsList).toBeVisible();
expect(addButton).toBeNull();
});
it('shows empty options list with add option button', () => {
it('shows empty options list with add option button', async () => {
const newProps = {
...defaultProps,
options: ['opt1', 'opt2'],
@@ -124,10 +127,11 @@ describe('common/OrganizationDropdown.jsx', () => {
newOptionButtonLabel: 'Add new option',
addNewOption: jest.fn(),
};
const user = userEvent.setup();
renderComponent(newProps);
const formInput = screen.getByTestId('formControl');
fireEvent.focus(formInput);
userEvent.type(formInput, '3');
await user.type(formInput, '3');
const noOptionsList = within(screen.getByTestId('dropdown-container')).getByText('No options');
expect(noOptionsList).toBeVisible();
const addButton = within(screen.getByTestId('dropdown-container')).getByTestId('add-option-button');

View File

@@ -193,11 +193,12 @@ describe('FilesAndUploads', () => {
describe('table actions', () => {
describe('upload a single file', () => {
it('should upload without duplication modal', async () => {
const user = userEvent.setup();
await mockStore(RequestStatus.SUCCESSFUL);
axiosMock.onGet(`${getAssetsUrl(courseId)}?display_name=download.png&page_size=1`).reply(200, { assets: [] });
axiosMock.onPost(getAssetsUrl(courseId)).reply(200, generateNewAssetApiResponse());
const addFilesButton = screen.getByLabelText(messages.fileInputAriaLabel.defaultMessage);
userEvent.upload(addFilesButton, file);
await user.upload(addFilesButton, file);
await executeThunk(validateAssetFiles(courseId, [file]), store.dispatch);
await waitFor(() => {
const addStatus = store.getState().assets.addingStatus;
@@ -206,6 +207,7 @@ describe('FilesAndUploads', () => {
});
it('should show duplicate file modal', async () => {
const user = userEvent.setup();
file = new File(['(⌐□_□)'], 'mOckID6', { type: 'image/png' });
await mockStore(RequestStatus.SUCCESSFUL);
@@ -213,12 +215,13 @@ describe('FilesAndUploads', () => {
`${getAssetsUrl(courseId)}?display_name=mOckID6&page_size=1`,
).reply(200, { assets: [{ display_name: 'mOckID6' }] });
const addFilesButton = screen.getByLabelText(messages.fileInputAriaLabel.defaultMessage);
userEvent.upload(addFilesButton, file);
await user.upload(addFilesButton, file);
await executeThunk(validateAssetFiles(courseId, [file]), store.dispatch);
expect(screen.getByText(filesPageMessages.overwriteConfirmMessage.defaultMessage)).toBeVisible();
});
it('should overwrite duplicate file', async () => {
const user = userEvent.setup();
file = new File(['(⌐□_□)'], 'mOckID6', { type: 'image/png' });
await mockStore(RequestStatus.SUCCESSFUL);
@@ -234,7 +237,7 @@ describe('FilesAndUploads', () => {
axiosMock.onPost(getAssetsUrl(courseId)).reply(200, responseData);
const addFilesButton = screen.getByLabelText(messages.fileInputAriaLabel.defaultMessage);
userEvent.upload(addFilesButton, file);
await user.upload(addFilesButton, file);
await executeThunk(validateAssetFiles(courseId, [file]), store.dispatch);
const overwriteButton = screen.getByText(filesPageMessages.confirmOverwriteButtonLabel.defaultMessage);
@@ -251,6 +254,7 @@ describe('FilesAndUploads', () => {
});
it('should keep original file', async () => {
const user = userEvent.setup();
file = new File(['(⌐□_□)'], 'mOckID6', { type: 'image/png' });
await mockStore(RequestStatus.SUCCESSFUL);
@@ -258,7 +262,7 @@ describe('FilesAndUploads', () => {
`${getAssetsUrl(courseId)}?display_name=mOckID6&page_size=1`,
).reply(200, { assets: [{ display_name: 'mOckID6' }] });
const addFilesButton = screen.getByLabelText(messages.fileInputAriaLabel.defaultMessage);
userEvent.upload(addFilesButton, file);
await user.upload(addFilesButton, file);
await executeThunk(validateAssetFiles(courseId, [file]), store.dispatch);
const cancelButton = screen.getByText(filesPageMessages.cancelOverwriteButtonLabel.defaultMessage);
@@ -547,12 +551,13 @@ describe('FilesAndUploads', () => {
});
it('invalid file size should show error', async () => {
const user = userEvent.setup();
const errorMessage = 'File download.png exceeds maximum size of 20 MB.';
await mockStore(RequestStatus.SUCCESSFUL);
axiosMock.onGet(`${getAssetsUrl(courseId)}?display_name=download.png&page_size=1`).reply(200, { assets: [] });
axiosMock.onPost(getAssetsUrl(courseId)).reply(413, { error: errorMessage });
const addFilesButton = screen.getByLabelText(messages.fileInputAriaLabel.defaultMessage);
userEvent.upload(addFilesButton, file);
await user.upload(addFilesButton, file);
await waitFor(() => {
const addStatus = store.getState().assets.addingStatus;
expect(addStatus).toEqual(RequestStatus.FAILED);
@@ -562,10 +567,11 @@ describe('FilesAndUploads', () => {
});
it('404 validation should show error', async () => {
const user = userEvent.setup();
await mockStore(RequestStatus.SUCCESSFUL);
axiosMock.onGet(`${getAssetsUrl(courseId)}?display_name=download.png&page_size=1`).reply(404);
const addFilesButton = screen.getByLabelText(messages.fileInputAriaLabel.defaultMessage);
userEvent.upload(addFilesButton, file);
await user.upload(addFilesButton, file);
await executeThunk(addAssetFile(courseId, file, 1), store.dispatch);
const addStatus = store.getState().assets.addingStatus;
expect(addStatus).toEqual(RequestStatus.FAILED);
@@ -574,11 +580,12 @@ describe('FilesAndUploads', () => {
});
it('404 upload should show error', async () => {
const user = userEvent.setup();
await mockStore(RequestStatus.SUCCESSFUL);
axiosMock.onGet(`${getAssetsUrl(courseId)}?display_name=download.png&page_size=1`).reply(200, { assets: [] });
axiosMock.onPost(getAssetsUrl(courseId)).reply(404);
const addFilesButton = screen.getByLabelText(messages.fileInputAriaLabel.defaultMessage);
userEvent.upload(addFilesButton, file);
await user.upload(addFilesButton, file);
await executeThunk(addAssetFile(courseId, file, 1), store.dispatch);
const addStatus = store.getState().assets.addingStatus;
expect(addStatus).toEqual(RequestStatus.FAILED);

View File

@@ -6,7 +6,7 @@ import {
waitFor,
within,
} from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { userEvent } from '@testing-library/user-event';
import { initializeMockApp } from '@edx/frontend-platform';
import MockAdapter from 'axios-mock-adapter';
@@ -238,6 +238,7 @@ describe('Videos page', () => {
describe('table actions', () => {
describe('file upload', () => {
it('should upload a single file', async () => {
const user = userEvent.setup({ applyAccept: false });
await mockStore(RequestStatus.SUCCESSFUL);
axiosMock.onPost(getCourseVideosApiUrl(courseId)).reply(204, generateNewVideoApiResponse());
@@ -245,14 +246,13 @@ describe('Videos page', () => {
axiosMock.onGet(getCourseVideosApiUrl(courseId)).reply(200, generateAddVideoApiResponse());
const addFilesButton = screen.getAllByLabelText(messages.fileInputAriaLabel.defaultMessage)[3];
await act(async () => {
userEvent.upload(addFilesButton, file);
});
await user.upload(addFilesButton, file);
const addStatus = store.getState().videos.addingStatus;
expect(addStatus).toEqual(RequestStatus.SUCCESSFUL);
});
it('when uploads are in progress, should show dialog and set them to failed on page leave', async () => {
const user = userEvent.setup({ applyAccept: false });
await mockStore(RequestStatus.SUCCESSFUL);
axiosMock.onPost(getCourseVideosApiUrl(courseId)).reply(204, generateNewVideoApiResponse());
@@ -264,9 +264,7 @@ describe('Videos page', () => {
uploadSpy.mockResolvedValue(new Promise(() => {}));
const addFilesButton = screen.getAllByLabelText(messages.fileInputAriaLabel.defaultMessage)[3];
await act(async () => {
userEvent.upload(addFilesButton, file);
});
await user.upload(addFilesButton, file);
await waitFor(() => {
const addStatus = store.getState().videos.addingStatus;
expect(addStatus).toEqual(RequestStatus.IN_PROGRESS);
@@ -284,6 +282,7 @@ describe('Videos page', () => {
});
it('should cancel all in-progress and set them to failed', async () => {
const user = userEvent.setup({ applyAccept: false });
await mockStore(RequestStatus.SUCCESSFUL);
axiosMock.onPost(getCourseVideosApiUrl(courseId)).reply(204, generateNewVideoApiResponse());
@@ -295,9 +294,7 @@ describe('Videos page', () => {
uploadSpy.mockResolvedValue(new Promise(() => {}));
const addFilesButton = screen.getAllByLabelText(messages.fileInputAriaLabel.defaultMessage)[3];
await act(async () => {
userEvent.upload(addFilesButton, file);
});
await user.upload(addFilesButton, file);
await waitFor(() => {
const addStatus = store.getState().videos.addingStatus;
@@ -605,15 +602,14 @@ describe('Videos page', () => {
});
it('invalid file size should show error', async () => {
const user = userEvent.setup({ applyAccept: false });
const errorMessage = 'File download.png exceeds maximum size of 5 GB.';
await mockStore(RequestStatus.SUCCESSFUL);
axiosMock.onPost(getCourseVideosApiUrl(courseId)).reply(413, { error: errorMessage });
axiosMock.onGet(getCourseVideosApiUrl(courseId)).reply(200, generateAddVideoApiResponse());
const addFilesButton = screen.getAllByLabelText(messages.fileInputAriaLabel.defaultMessage)[3];
await act(async () => {
userEvent.upload(addFilesButton, file);
});
await user.upload(addFilesButton, file);
await waitFor(() => {
const addStatus = store.getState().videos.addingStatus;
expect(addStatus).toEqual(RequestStatus.FAILED);
@@ -623,14 +619,13 @@ describe('Videos page', () => {
});
it('404 add file should show error', async () => {
const user = userEvent.setup({ applyAccept: false });
await mockStore(RequestStatus.SUCCESSFUL);
axiosMock.onPost(getCourseVideosApiUrl(courseId)).reply(404);
axiosMock.onGet(getCourseVideosApiUrl(courseId)).reply(200, generateAddVideoApiResponse());
const addFilesButton = screen.getAllByLabelText(messages.fileInputAriaLabel.defaultMessage)[3];
await act(async () => {
userEvent.upload(addFilesButton, file);
});
await user.upload(addFilesButton, file);
await waitFor(() => {
const addStatus = store.getState().videos.addingStatus;
expect(addStatus).toEqual(RequestStatus.FAILED);
@@ -654,14 +649,15 @@ describe('Videos page', () => {
});
it('404 upload file to server should show error', async () => {
const user = userEvent.setup({ applyAccept: false });
await mockStore(RequestStatus.SUCCESSFUL);
axiosMock.onPost(getCourseVideosApiUrl(courseId)).reply(204, generateNewVideoApiResponse());
axiosUnauthenticateMock.onPut('http://testing.org').reply(404);
axiosMock.onGet(getCourseVideosApiUrl(courseId)).reply(200, generateAddVideoApiResponse());
const addFilesButton = screen.getAllByLabelText(messages.fileInputAriaLabel.defaultMessage)[3];
await act(async () => {
userEvent.upload(addFilesButton, file);
});
await user.upload(addFilesButton, file);
await waitFor(() => {
const addStatus = store.getState().videos.addingStatus;
expect(addStatus).toEqual(RequestStatus.FAILED);

View File

@@ -115,12 +115,13 @@ describe('TranscriptTab', () => {
});
it('should upload new transcript', async () => {
const user = userEvent.setup();
axiosMock.onPost(`${getApiBaseUrl()}/transcript_upload/`).reply(204);
await act(async () => {
const addFileInput = screen.getByLabelText(genericMessages.fileInputAriaLabel.defaultMessage);
expect(addFileInput).toBeInTheDocument();
userEvent.upload(addFileInput, file);
await user.upload(addFileInput, file);
});
const addStatus = store.getState().videos.transcriptStatus;
@@ -128,10 +129,11 @@ describe('TranscriptTab', () => {
});
it('should show default error message', async () => {
const user = userEvent.setup();
axiosMock.onPost(`${getApiBaseUrl()}/transcript_upload/`).reply(404);
await act(async () => {
const addFileInput = screen.getByLabelText(genericMessages.fileInputAriaLabel.defaultMessage);
userEvent.upload(addFileInput, file);
await user.upload(addFileInput, file);
});
const addStatus = store.getState().videos.transcriptStatus;
@@ -141,10 +143,11 @@ describe('TranscriptTab', () => {
});
it('should show api provided error message', async () => {
const user = userEvent.setup();
axiosMock.onPost(`${getApiBaseUrl()}/transcript_upload/`).reply(404, { error: 'api error' });
await act(async () => {
const addFileInput = screen.getByLabelText(genericMessages.fileInputAriaLabel.defaultMessage);
userEvent.upload(addFileInput, file);
await user.upload(addFileInput, file);
});
const addStatus = store.getState().videos.transcriptStatus;
@@ -297,11 +300,12 @@ describe('TranscriptTab', () => {
});
it('should replace transcript', async () => {
const user = userEvent.setup();
axiosMock.onPost(`${getApiBaseUrl()}/transcript_upload/`).reply(204);
await act(async () => {
const addFileInput = screen.getAllByLabelText(genericMessages.fileInputAriaLabel.defaultMessage)[0];
userEvent.upload(addFileInput, file);
await user.upload(addFileInput, file);
});
const addStatus = store.getState().videos.transcriptStatus;
@@ -313,11 +317,12 @@ describe('TranscriptTab', () => {
});
it('should show error message', async () => {
const user = userEvent.setup();
axiosMock.onPost(`${getApiBaseUrl()}/transcript_upload/`).reply(404);
await act(async () => {
const addFileInput = screen.getAllByLabelText(genericMessages.fileInputAriaLabel.defaultMessage)[0];
userEvent.upload(addFileInput, file);
await user.upload(addFileInput, file);
});
const addStatus = store.getState().videos.transcriptStatus;

View File

@@ -46,8 +46,10 @@ const renderComponent = () => {
};
describe('TranscriptSettings', () => {
let user;
describe('default behaviors', () => {
beforeEach(async () => {
user = userEvent.setup();
initializeMockApp({
authenticatedUser: {
userId: 3,
@@ -70,7 +72,7 @@ describe('TranscriptSettings', () => {
it('should change view to order form', async () => {
renderComponent(defaultProps);
const orderButton = screen.getByText(messages.orderTranscriptsTitle.defaultMessage);
userEvent.click(orderButton);
await user.click(orderButton);
const selectableButtons = screen.getAllByLabelText('none radio')[0];
expect(selectableButtons).toBeVisible();
@@ -79,13 +81,13 @@ describe('TranscriptSettings', () => {
it('should return to order transcript collapsible', async () => {
renderComponent(defaultProps);
const orderButton = screen.getByText(messages.orderTranscriptsTitle.defaultMessage);
userEvent.click(orderButton);
await user.click(orderButton);
const selectableButtons = screen.getAllByLabelText('none radio')[0];
expect(selectableButtons).toBeVisible();
const backButton = screen.getByLabelText('back button to main transcript settings view');
userEvent.click(backButton);
await user.click(backButton);
await waitFor(() => {
expect(screen.queryByLabelText('back button to main transcript settings view')).toBeNull();
});
@@ -94,9 +96,9 @@ describe('TranscriptSettings', () => {
it('discard changes should call closeTranscriptSettings', async () => {
renderComponent(defaultProps);
const orderButton = screen.getByText(messages.orderTranscriptsTitle.defaultMessage);
userEvent.click(orderButton);
await user.click(orderButton);
const discardButton = screen.getByText(messages.discardSettingsLabel.defaultMessage);
userEvent.click(discardButton);
await user.click(discardButton);
expect(defaultProps.closeTranscriptSettings).toHaveBeenCalled();
});
@@ -136,7 +138,7 @@ describe('TranscriptSettings', () => {
it('should load page with Cielo24 selected', async () => {
const orderButton = screen.getByText(messages.orderTranscriptsTitle.defaultMessage);
userEvent.click(orderButton);
await user.click(orderButton);
const cielo24Button = screen.getByText(messages.cieloLabel.defaultMessage);
expect(within(cielo24Button).getByLabelText('Cielo24 radio')).toHaveProperty('checked', true);
@@ -174,10 +176,10 @@ describe('TranscriptSettings', () => {
renderComponent(defaultProps);
const orderButton = screen.getByText(messages.orderTranscriptsTitle.defaultMessage);
userEvent.click(orderButton);
await user.click(orderButton);
const noneButton = screen.getAllByLabelText('none radio')[0];
userEvent.click(noneButton);
await user.click(noneButton);
});
it('api should succeed', async () => {
@@ -220,18 +222,18 @@ describe('TranscriptSettings', () => {
renderComponent(defaultProps);
const orderButton = screen.getByText(messages.orderTranscriptsTitle.defaultMessage);
userEvent.click(orderButton);
await user.click(orderButton);
});
it('should ask for Cielo24 or 3Play Media credentials', async () => {
const cielo24Button = screen.getAllByLabelText('Cielo24 radio')[0];
userEvent.click(cielo24Button);
await user.click(cielo24Button);
const cieloCredentialMessage = screen.getByTestId('cieloCredentialMessage');
expect(cieloCredentialMessage).toBeVisible();
const threePlayMediaButton = screen.getAllByLabelText('3PlayMedia radio')[0];
userEvent.click(threePlayMediaButton);
await user.click(threePlayMediaButton);
const threePlayMediaCredentialMessage = screen.getByTestId('threePlayMediaCredentialMessage');
expect(threePlayMediaCredentialMessage).toBeVisible();
@@ -240,15 +242,15 @@ describe('TranscriptSettings', () => {
describe('api succeeds', () => {
it('should update cielo24 credentials ', async () => {
const cielo24Button = screen.getAllByLabelText('Cielo24 radio')[0];
userEvent.click(cielo24Button);
await user.click(cielo24Button);
const firstInput = screen.getByLabelText(messages.cieloApiKeyLabel.defaultMessage);
const secondInput = screen.getByLabelText(messages.cieloUsernameLabel.defaultMessage);
const updateButton = screen.getByText(messages.updateSettingsLabel.defaultMessage);
await waitFor(() => {
userEvent.type(firstInput, 'apiKey');
userEvent.type(secondInput, 'username');
await waitFor(async () => {
await user.type(firstInput, 'apiKey');
await user.type(secondInput, 'username');
expect(updateButton).not.toHaveAttribute('disabled');
});
@@ -267,15 +269,15 @@ describe('TranscriptSettings', () => {
it('should update 3Play Media credentials', async () => {
const threePlayButton = screen.getAllByLabelText('3PlayMedia radio')[0];
userEvent.click(threePlayButton);
await user.click(threePlayButton);
const updateButton = screen.getByText(messages.updateSettingsLabel.defaultMessage);
const firstInput = screen.getByLabelText(messages.threePlayMediaApiKeyLabel.defaultMessage);
const secondInput = screen.getByLabelText(messages.threePlayMediaApiSecretLabel.defaultMessage);
await waitFor(() => {
userEvent.type(firstInput, 'apiKey');
userEvent.type(secondInput, 'secretKey');
await waitFor(async () => {
await user.type(firstInput, 'apiKey');
await user.type(secondInput, 'secretKey');
expect(updateButton).not.toHaveAttribute('disabled');
});
@@ -297,15 +299,15 @@ describe('TranscriptSettings', () => {
describe('api fails', () => {
it('should show error alert on Cielo24 credentials update', async () => {
const cielo24Button = screen.getAllByLabelText('Cielo24 radio')[0];
userEvent.click(cielo24Button);
await user.click(cielo24Button);
const firstInput = screen.getByLabelText(messages.cieloApiKeyLabel.defaultMessage);
const secondInput = screen.getByLabelText(messages.cieloUsernameLabel.defaultMessage);
const updateButton = screen.getByText(messages.updateSettingsLabel.defaultMessage);
await waitFor(() => {
userEvent.type(firstInput, 'apiKey');
userEvent.type(secondInput, 'username');
await waitFor(async () => {
await user.type(firstInput, 'apiKey');
await user.type(secondInput, 'username');
expect(updateButton).not.toHaveAttribute('disabled');
});
@@ -323,15 +325,15 @@ describe('TranscriptSettings', () => {
it('should show error alert on 3PlayMedia credentials update', async () => {
const threePlayButton = screen.getAllByLabelText('3PlayMedia radio')[0];
userEvent.click(threePlayButton);
await user.click(threePlayButton);
const updateButton = screen.getByText(messages.updateSettingsLabel.defaultMessage);
const firstInput = screen.getByLabelText(messages.threePlayMediaApiKeyLabel.defaultMessage);
const secondInput = screen.getByLabelText(messages.threePlayMediaApiSecretLabel.defaultMessage);
await waitFor(() => {
userEvent.type(firstInput, 'apiKey');
userEvent.type(secondInput, 'secretKey');
await waitFor(async () => {
await user.type(firstInput, 'apiKey');
await user.type(secondInput, 'secretKey');
expect(updateButton).not.toHaveAttribute('disabled');
});
@@ -375,18 +377,18 @@ describe('TranscriptSettings', () => {
axiosMock = new MockAdapter(getAuthenticatedHttpClient());
renderComponent(defaultProps);
const orderButton = screen.getByText(messages.orderTranscriptsTitle.defaultMessage);
userEvent.click(orderButton);
await user.click(orderButton);
});
it('should not show credentials request for Cielo24 and 3Play Media', async () => {
const cielo24Button = screen.getAllByLabelText('Cielo24 radio')[0];
userEvent.click(cielo24Button);
await user.click(cielo24Button);
const cieloCredentialMessage = screen.queryByTestId('cieloCredentialMessage');
expect(cieloCredentialMessage).toBeNull();
const threePlayMediaButton = screen.getAllByLabelText('3PlayMedia radio')[0];
userEvent.click(threePlayMediaButton);
await user.click(threePlayMediaButton);
const threePlayMediaCredentialMessage = screen.queryByTestId('threePlayMediaCredentialMessage');
expect(threePlayMediaCredentialMessage).toBeNull();
@@ -404,25 +406,25 @@ describe('TranscriptSettings', () => {
};
const cielo24Button = screen.getAllByLabelText('Cielo24 radio')[0];
userEvent.click(cielo24Button);
await user.click(cielo24Button);
const updateButton = screen.getByText(messages.updateSettingsLabel.defaultMessage);
const turnaround = screen.getByText(messages.cieloTurnaroundPlaceholder.defaultMessage);
const fidelity = screen.getByText(messages.cieloFidelityPlaceholder.defaultMessage);
await waitFor(() => {
userEvent.click(turnaround);
userEvent.click(screen.getByText('Priority (24 hours)'));
await waitFor(async () => {
await user.click(turnaround);
await user.click(screen.getByText('Priority (24 hours)'));
userEvent.click(fidelity);
userEvent.click(screen.getByText('Premium (95% accuracy)'));
await user.click(fidelity);
await user.click(screen.getByText('Premium (95% accuracy)'));
const source = screen.getAllByText(messages.cieloSourceLanguagePlaceholder.defaultMessage)[0];
userEvent.click(source);
userEvent.click(screen.getByText('English'));
await user.click(source);
await user.click(screen.getByText('English'));
const language = screen.getByText(messages.cieloTranscriptLanguagePlaceholder.defaultMessage);
userEvent.click(language);
userEvent.click(screen.getAllByText('English')[2]);
await user.click(language);
await user.click(screen.getAllByText('English')[2]);
});
expect(updateButton).not.toHaveAttribute('disabled');
@@ -448,23 +450,23 @@ describe('TranscriptSettings', () => {
global: false,
};
const threePlayButton = screen.getAllByLabelText('3PlayMedia radio')[0];
userEvent.click(threePlayButton);
await user.click(threePlayButton);
const updateButton = screen.getByText(messages.updateSettingsLabel.defaultMessage);
const turnaround = screen.getByText(messages.threePlayMediaTurnaroundPlaceholder.defaultMessage);
const source = screen.getByText(messages.threePlayMediaSourceLanguagePlaceholder.defaultMessage);
await waitFor(() => {
userEvent.click(turnaround);
userEvent.click(screen.getByText('2 hours'));
await waitFor(async () => {
await user.click(turnaround);
await user.click(screen.getByText('2 hours'));
userEvent.click(source);
userEvent.click(screen.getByText('English'));
await user.click(source);
await user.click(screen.getByText('English'));
const language = screen.getByText(messages.threePlayMediaTranscriptLanguagePlaceholder.defaultMessage);
userEvent.click(language);
userEvent.click(screen.getByText('Arabic'));
userEvent.click(screen.getByText('French'));
userEvent.click(screen.getAllByText('Arabic')[0]);
await user.click(language);
await user.click(screen.getByText('Arabic'));
await user.click(screen.getByText('French'));
await user.click(screen.getAllByText('Arabic')[0]);
expect(updateButton).not.toHaveAttribute('disabled');
});
@@ -487,21 +489,21 @@ describe('TranscriptSettings', () => {
global: false,
};
const threePlayButton = screen.getAllByLabelText('3PlayMedia radio')[0];
userEvent.click(threePlayButton);
await user.click(threePlayButton);
const updateButton = screen.getByText(messages.updateSettingsLabel.defaultMessage);
const turnaround = screen.getByText(messages.threePlayMediaTurnaroundPlaceholder.defaultMessage);
const source = screen.getByText(messages.threePlayMediaSourceLanguagePlaceholder.defaultMessage);
await waitFor(() => {
userEvent.click(turnaround);
userEvent.click(screen.getByText('2 hours'));
await waitFor(async () => {
await user.click(turnaround);
await user.click(screen.getByText('2 hours'));
userEvent.click(source);
userEvent.click(screen.getByText('Spanish'));
await user.click(source);
await user.click(screen.getByText('Spanish'));
const language = screen.getByText(messages.threePlayMediaTranscriptLanguagePlaceholder.defaultMessage);
userEvent.click(language);
userEvent.click(screen.getAllByText('English')[1]);
await user.click(language);
await user.click(screen.getAllByText('English')[1]);
});
expect(updateButton).not.toHaveAttribute('disabled');
@@ -518,25 +520,25 @@ describe('TranscriptSettings', () => {
describe('api fails', () => {
it('should show error alert on Cielo24 preferences update', async () => {
const cielo24Button = screen.getAllByLabelText('Cielo24 radio')[0];
userEvent.click(cielo24Button);
await user.click(cielo24Button);
const updateButton = screen.getByText(messages.updateSettingsLabel.defaultMessage);
const turnaround = screen.getByText(messages.cieloTurnaroundPlaceholder.defaultMessage);
const fidelity = screen.getByText(messages.cieloFidelityPlaceholder.defaultMessage);
await waitFor(() => {
userEvent.click(turnaround);
userEvent.click(screen.getByText('Priority (24 hours)'));
await waitFor(async () => {
await user.click(turnaround);
await user.click(screen.getByText('Priority (24 hours)'));
userEvent.click(fidelity);
userEvent.click(screen.getByText('Premium (95% accuracy)'));
await user.click(fidelity);
await user.click(screen.getByText('Premium (95% accuracy)'));
const source = screen.getAllByText(messages.cieloSourceLanguagePlaceholder.defaultMessage)[0];
userEvent.click(source);
userEvent.click(screen.getByText('English'));
await user.click(source);
await user.click(screen.getByText('English'));
const language = screen.getByText(messages.cieloTranscriptLanguagePlaceholder.defaultMessage);
userEvent.click(language);
userEvent.click(screen.getAllByText('English')[2]);
await user.click(language);
await user.click(screen.getAllByText('English')[2]);
});
expect(updateButton).not.toHaveAttribute('disabled');
@@ -554,21 +556,21 @@ describe('TranscriptSettings', () => {
it('should show error alert with default message on 3PlayMedia preferences update', async () => {
const threePlayButton = screen.getAllByLabelText('3PlayMedia radio')[0];
userEvent.click(threePlayButton);
await user.click(threePlayButton);
const updateButton = screen.getByText(messages.updateSettingsLabel.defaultMessage);
const turnaround = screen.getByText(messages.threePlayMediaTurnaroundPlaceholder.defaultMessage);
const source = screen.getByText(messages.threePlayMediaSourceLanguagePlaceholder.defaultMessage);
await waitFor(() => {
userEvent.click(turnaround);
userEvent.click(screen.getByText('2 hours'));
await waitFor(async () => {
await user.click(turnaround);
await user.click(screen.getByText('2 hours'));
userEvent.click(source);
userEvent.click(screen.getByText('Spanish'));
await user.click(source);
await user.click(screen.getByText('Spanish'));
const language = screen.getByText(messages.threePlayMediaTranscriptLanguagePlaceholder.defaultMessage);
userEvent.click(language);
userEvent.click(screen.getAllByText('English')[1]);
await user.click(language);
await user.click(screen.getAllByText('English')[1]);
});
expect(updateButton).not.toHaveAttribute('disabled');
@@ -585,21 +587,21 @@ describe('TranscriptSettings', () => {
it('should show error alert with default message on 3PlayMedia preferences update', async () => {
const threePlayButton = screen.getAllByLabelText('3PlayMedia radio')[0];
userEvent.click(threePlayButton);
await user.click(threePlayButton);
const updateButton = screen.getByText(messages.updateSettingsLabel.defaultMessage);
const turnaround = screen.getByText(messages.threePlayMediaTurnaroundPlaceholder.defaultMessage);
const source = screen.getByText(messages.threePlayMediaSourceLanguagePlaceholder.defaultMessage);
await waitFor(() => {
userEvent.click(turnaround);
userEvent.click(screen.getByText('2 hours'));
await waitFor(async () => {
await user.click(turnaround);
await user.click(screen.getByText('2 hours'));
userEvent.click(source);
userEvent.click(screen.getByText('Spanish'));
await user.click(source);
await user.click(screen.getByText('Spanish'));
const language = screen.getByText(messages.threePlayMediaTranscriptLanguagePlaceholder.defaultMessage);
userEvent.click(language);
userEvent.click(screen.getAllByText('English')[1]);
await user.click(language);
await user.click(screen.getAllByText('English')[1]);
});
expect(updateButton).not.toHaveAttribute('disabled');

View File

@@ -71,11 +71,12 @@ describe('<ConfigureModal /> for Section', () => {
expect(getByRole('button', { name: messages.saveButton.defaultMessage })).toBeInTheDocument();
});
it('switches to the Visibility tab and renders correctly', () => {
it('switches to the Visibility tab and renders correctly', async () => {
const user = userEvent.setup();
const { getByRole, getByText } = renderComponent();
const visibilityTab = getByRole('tab', { name: messages.visibilityTabTitle.defaultMessage });
userEvent.click(visibilityTab);
await user.click(visibilityTab);
expect(getByText('Section visibility')).toBeInTheDocument();
expect(getByText(messages.hideFromLearners.defaultMessage)).toBeInTheDocument();
});
@@ -134,11 +135,12 @@ describe('<ConfigureModal /> for Subsection', () => {
expect(queryByText(messages.dueTimeUTC.defaultMessage)).not.toBeInTheDocument();
});
it('switches to the subsection Visibility tab and renders correctly', () => {
it('switches to the subsection Visibility tab and renders correctly', async () => {
const user = userEvent.setup();
const { getByRole, getByText } = renderSubsectionComponent();
const visibilityTab = getByRole('tab', { name: messages.visibilityTabTitle.defaultMessage });
userEvent.click(visibilityTab);
await user.click(visibilityTab);
expect(getByText('Subsection visibility')).toBeInTheDocument();
expect(getByText(messages.showEntireSubsection.defaultMessage)).toBeInTheDocument();
expect(getByText(messages.showEntireSubsectionDescription.defaultMessage)).toBeInTheDocument();
@@ -155,11 +157,12 @@ describe('<ConfigureModal /> for Subsection', () => {
expect(getByText(messages.showAssessmentResultsPastDueDescription.defaultMessage)).toBeInTheDocument();
});
it('switches to the subsection Advanced tab and renders correctly', () => {
it('switches to the subsection Advanced tab and renders correctly', async () => {
const user = userEvent.setup();
const { getByRole, getByText } = renderSubsectionComponent();
const advancedTab = getByRole('tab', { name: messages.advancedTabTitle.defaultMessage });
userEvent.click(advancedTab);
await user.click(advancedTab);
expect(getByText(messages.setSpecialExam.defaultMessage)).toBeInTheDocument();
expect(getByText(messages.none.defaultMessage)).toBeInTheDocument();
expect(getByText(messages.timed.defaultMessage)).toBeInTheDocument();
@@ -195,7 +198,8 @@ describe('<ConfigureModal /> for Unit', () => {
store = initializeStore();
});
it('renders unit ConfigureModal component correctly', () => {
it('renders unit ConfigureModal component correctly', async () => {
const user = userEvent.setup();
const {
getByText, queryByText, getByRole, getByTestId,
} = renderUnitComponent();
@@ -209,15 +213,19 @@ describe('<ConfigureModal /> for Unit', () => {
expect(queryByText(messages.unitSelectGroup.defaultMessage)).not.toBeInTheDocument();
const input = getByTestId('group-type-select');
['0', '1'].forEach(groupeTypeIndex => {
userEvent.selectOptions(input, groupeTypeIndex);
await user.selectOptions(input, '0');
expect(getByText(messages.unitSelectGroup.defaultMessage)).toBeInTheDocument();
currentUnitMock
.userPartitionInfo
.selectablePartitions['0'].groups
.forEach(g => expect(getByText(g.name)).toBeInTheDocument());
expect(getByText(messages.unitSelectGroup.defaultMessage)).toBeInTheDocument();
currentUnitMock
.userPartitionInfo
.selectablePartitions[groupeTypeIndex].groups
.forEach(g => expect(getByText(g.name)).toBeInTheDocument());
});
await user.selectOptions(input, '1');
expect(getByText(messages.unitSelectGroup.defaultMessage)).toBeInTheDocument();
currentUnitMock
.userPartitionInfo
.selectablePartitions['1'].groups
.forEach(g => expect(getByText(g.name)).toBeInTheDocument());
expect(getByRole('button', { name: messages.cancelButton.defaultMessage })).toBeInTheDocument();
expect(getByRole('button', { name: messages.saveButton.defaultMessage })).toBeInTheDocument();
@@ -257,7 +265,8 @@ describe('<ConfigureModal /> for XBlock', () => {
store = initializeStore();
});
it('renders unit ConfigureModal component correctly', () => {
it('renders unit ConfigureModal component correctly', async () => {
const user = userEvent.setup();
const {
getByText, queryByText, getByRole, getByTestId,
} = renderXBlockComponent();
@@ -270,15 +279,19 @@ describe('<ConfigureModal /> for XBlock', () => {
expect(queryByText(messages.unitSelectGroup.defaultMessage)).not.toBeInTheDocument();
const input = getByTestId('group-type-select');
['0', '1'].forEach(groupeTypeIndex => {
userEvent.selectOptions(input, groupeTypeIndex);
await user.selectOptions(input, '0');
expect(getByText(messages.unitSelectGroup.defaultMessage)).toBeInTheDocument();
currentUnitMock
.userPartitionInfo
.selectablePartitions['0'].groups
.forEach(g => expect(getByText(g.name)).toBeInTheDocument());
expect(getByText(messages.unitSelectGroup.defaultMessage)).toBeInTheDocument();
currentUnitMock
.userPartitionInfo
.selectablePartitions[groupeTypeIndex].groups
.forEach(g => expect(getByText(g.name)).toBeInTheDocument());
});
await user.selectOptions(input, '1');
expect(getByText(messages.unitSelectGroup.defaultMessage)).toBeInTheDocument();
currentUnitMock
.userPartitionInfo
.selectablePartitions['1'].groups
.forEach(g => expect(getByText(g.name)).toBeInTheDocument());
expect(getByRole('button', { name: messages.cancelButton.defaultMessage })).toBeInTheDocument();
expect(getByRole('button', { name: messages.saveButton.defaultMessage })).toBeInTheDocument();

View File

@@ -135,6 +135,7 @@ describe('<CreateOrRerunCourseForm />', () => {
describe('handleOnClickCreate', () => {
it('should call window.location.assign with url', async () => {
const user = userEvent.setup();
render(<RootWrapper {...props} />);
await mockStore();
const url = '/course/courseId';
@@ -144,17 +145,18 @@ describe('<CreateOrRerunCourseForm />', () => {
const runInput = screen.getByPlaceholderText(messages.courseRunPlaceholder.defaultMessage);
const createBtn = screen.getByRole('button', { name: messages.createButton.defaultMessage });
userEvent.type(displayNameInput, 'foo course name');
await user.type(displayNameInput, 'foo course name');
fireEvent.click(orgInput);
userEvent.type(numberInput, '777');
userEvent.type(runInput, '1');
userEvent.click(createBtn);
await user.type(numberInput, '777');
await user.type(runInput, '1');
await user.click(createBtn);
await axiosMock.onPost(getCreateOrRerunCourseUrl()).reply(200, { url });
await executeThunk(updateCreateOrRerunCourseQuery({ org: 'testX', run: 'some' }), store.dispatch);
expect(mockedUsedNavigate).toHaveBeenCalledWith(url);
});
it('should call window.location.assign with url and destinationCourseKey', async () => {
const user = userEvent.setup();
render(<RootWrapper {...props} />);
await mockStore();
const url = '/course/';
@@ -166,11 +168,11 @@ describe('<CreateOrRerunCourseForm />', () => {
const createBtn = screen.getByRole('button', { name: messages.createButton.defaultMessage });
await axiosMock.onPost(getCreateOrRerunCourseUrl()).reply(200, { url, destinationCourseKey });
userEvent.type(displayNameInput, 'foo course name');
await user.type(displayNameInput, 'foo course name');
fireEvent.click(orgInput);
userEvent.type(numberInput, '777');
userEvent.type(runInput, '1');
userEvent.click(createBtn);
await user.type(numberInput, '777');
await user.type(runInput, '1');
await user.click(createBtn);
await executeThunk(updateCreateOrRerunCourseQuery({ org: 'testX', run: 'some' }), store.dispatch);
expect(mockedUsedNavigate).toHaveBeenCalledWith(`${url}${destinationCourseKey}`);
@@ -215,6 +217,7 @@ describe('<CreateOrRerunCourseForm />', () => {
});
it('should be disabled create button if form has error', async () => {
const user = userEvent.setup();
render(<RootWrapper {...props} />);
await mockStore();
const createBtn = await screen.findByRole('button', { name: messages.createButton.defaultMessage });
@@ -224,7 +227,7 @@ describe('<CreateOrRerunCourseForm />', () => {
const runInput = await screen.findByPlaceholderText(messages.courseRunPlaceholder.defaultMessage);
fireEvent.change(displayNameInput, { target: { value: 'foo course name' } });
await userEvent.click(orgInput);
await user.click(orgInput);
fireEvent.change(numberInput, { target: { value: 'number with invalid (+) symbol' } });
fireEvent.change(runInput, { target: { value: 'number with invalid (=) symbol' } });

View File

@@ -63,19 +63,21 @@ describe('<DeleteModal />', () => {
expect(getByRole('button', { name: messages.deleteButton.defaultMessage })).toBeInTheDocument();
});
it('calls onDeleteSubmit function when the "Delete" button is clicked', () => {
it('calls onDeleteSubmit function when the "Delete" button is clicked', async () => {
const user = userEvent.setup();
const { getByRole } = renderComponent();
const okButton = getByRole('button', { name: messages.deleteButton.defaultMessage });
userEvent.click(okButton);
await user.click(okButton);
expect(onDeleteSubmitMock).toHaveBeenCalledTimes(1);
});
it('calls the close function when the "Cancel" button is clicked', () => {
it('calls the close function when the "Cancel" button is clicked', async () => {
const user = userEvent.setup();
const { getByRole } = renderComponent();
const cancelButton = getByRole('button', { name: messages.cancelButton.defaultMessage });
userEvent.click(cancelButton);
await user.click(cancelButton);
expect(closeMock).toHaveBeenCalledTimes(1);
});

View File

@@ -68,15 +68,17 @@ describe('<ModalDropzone />', () => {
});
it('calls onClose when close button is clicked', async () => {
const user = userEvent.setup();
const { getByText } = render(<RootWrapper {...props} />);
userEvent.click(getByText(messages.cancelModal.defaultMessage));
await user.click(getByText(messages.cancelModal.defaultMessage));
expect(mockOnClose).toHaveBeenCalled();
});
it('calls onCancel when cancel button is clicked', () => {
it('calls onCancel when cancel button is clicked', async () => {
const user = userEvent.setup();
const { getByText } = render(<RootWrapper {...props} />);
userEvent.click(getByText(messages.cancelModal.defaultMessage));
await user.click(getByText(messages.cancelModal.defaultMessage));
expect(mockOnCancel).toHaveBeenCalled();
});
@@ -89,12 +91,13 @@ describe('<ModalDropzone />', () => {
});
it('enables the upload button after a file is selected', async () => {
const user = userEvent.setup();
const { getByRole } = render(<RootWrapper {...props} />);
const dropzoneInput = getByRole('presentation', { hidden: true }).firstChild;
const uploadButton = getByRole('button', { name: messages.uploadModal.defaultMessage });
expect(uploadButton).toBeDisabled();
userEvent.upload(dropzoneInput, file);
await user.upload(dropzoneInput, file);
await waitFor(() => {
expect(dropzoneInput.files[0]).toStrictEqual(file);
@@ -104,6 +107,7 @@ describe('<ModalDropzone />', () => {
});
it('should successfully upload an asset and return the URL', async () => {
const user = userEvent.setup();
const mockUrl = `${baseUrl}/assets/course-123/test-file.png`;
axiosMock.onPost(getUploadAssetsUrl(courseId).href).reply(200, {
asset: { url: mockUrl },
@@ -112,21 +116,19 @@ describe('<ModalDropzone />', () => {
expect(response.asset.url).toBe(mockUrl);
const { getByRole, getByAltText } = render(<RootWrapper {...props} />);
const { getByRole, getByLabelText } = render(<RootWrapper {...props} />);
const dropzoneInput = getByRole('presentation', { hidden: true }).firstChild;
const uploadButton = getByRole('button', { name: messages.uploadModal.defaultMessage });
userEvent.upload(dropzoneInput, file);
await user.upload(dropzoneInput, file);
await waitFor(() => {
expect(uploadButton).not.toBeDisabled();
});
userEvent.click(uploadButton);
await user.click(uploadButton);
await waitFor(() => {
expect(getByAltText(messages.uploadImageDropzoneAlt.defaultMessage)).toBeInTheDocument();
});
expect(getByLabelText(messages.uploadImageDropzoneAlt.defaultMessage)).toBeInTheDocument();
});
it('should handle an upload error', async () => {
@@ -136,6 +138,7 @@ describe('<ModalDropzone />', () => {
});
it('displays a custom error message when the file size exceeds the limit', async () => {
const user = userEvent.setup();
const maxSizeInBytes = 20 * 1000 * 1000;
const expectedErrorMessage = 'Custom error message';
@@ -150,7 +153,7 @@ describe('<ModalDropzone />', () => {
{ type: 'image/png' },
);
userEvent.upload(dropzoneInput.firstChild, fileToUpload);
await user.upload(dropzoneInput.firstChild, fileToUpload);
await waitFor(() => {
expect(getByText(expectedErrorMessage)).toBeInTheDocument();

View File

@@ -19,12 +19,13 @@ describe('<ProcessingNotification />', () => {
});
it('renders successfully', async () => {
const user = userEvent.setup();
render(<ProcessingNotification {...props} close={() => {}} />);
await screen.findByText(props.title);
const undo = await screen.findByText('Undo');
const alert = await screen.findByRole('alert', { hidden: true });
expect(alert.classList.contains('processing-notification-hide-close-button')).toBeFalsy();
await userEvent.click(undo);
await user.click(undo);
expect(mockUndo).toHaveBeenCalled();
});

View File

@@ -48,18 +48,19 @@ describe('<ContentGroupCard />', () => {
expect(getByTestId('content-group-card-header-delete')).toBeInTheDocument();
});
it('expands/collapses the container group content on title click', () => {
it('expands/collapses the container group content on title click', async () => {
const user = userEvent.setup();
const {
getByText, queryByTestId, getByTestId, queryByText,
} = renderComponent();
const cardTitle = getByTestId('configuration-card-header-button');
userEvent.click(cardTitle);
await user.click(cardTitle);
expect(queryByTestId('content-group-card-content')).toBeInTheDocument();
expect(
queryByText(rootMessages.notInUse.defaultMessage),
).not.toBeInTheDocument();
userEvent.click(cardTitle);
await user.click(cardTitle);
expect(queryByTestId('content-group-card-content')).not.toBeInTheDocument();
expect(getByText(rootMessages.notInUse.defaultMessage)).toBeInTheDocument();
});
@@ -80,14 +81,15 @@ describe('<ContentGroupCard />', () => {
expect(usageBlock).toBeInTheDocument();
});
it('renders group controls without access to units', () => {
it('renders group controls without access to units', async () => {
const user = userEvent.setup();
const { queryByText, getByTestId } = renderComponent();
expect(
queryByText(commonMessages.accessTo.defaultMessage),
).not.toBeInTheDocument();
const cardTitle = getByTestId('configuration-card-header-button');
userEvent.click(cardTitle);
await user.click(cardTitle);
expect(getByTestId('configuration-card-usage-empty')).toBeInTheDocument();
});
});

View File

@@ -73,6 +73,7 @@ describe('<ContentGroupForm />', () => {
});
it('calls onCreate when the "Create" button is clicked with a valid form', async () => {
const user = userEvent.setup();
const {
getByRole, getByPlaceholderText, queryByText,
} = renderComponent();
@@ -80,12 +81,12 @@ describe('<ContentGroupForm />', () => {
const newGroupInput = getByPlaceholderText(
messages.newGroupInputPlaceholder.defaultMessage,
);
userEvent.type(newGroupInput, newGroupNameText);
await user.type(newGroupInput, newGroupNameText);
const createButton = getByRole('button', {
name: messages.createButton.defaultMessage,
});
expect(createButton).toBeInTheDocument();
userEvent.click(createButton);
await user.click(createButton);
await waitFor(() => {
expect(onCreateClickMock).toHaveBeenCalledTimes(1);
@@ -96,17 +97,18 @@ describe('<ContentGroupForm />', () => {
});
it('shows error when the "Create" button is clicked with an invalid form', async () => {
const user = userEvent.setup();
const { getByRole, getByPlaceholderText, getByText } = renderComponent();
const newGroupNameText = '';
const newGroupInput = getByPlaceholderText(
messages.newGroupInputPlaceholder.defaultMessage,
);
userEvent.type(newGroupInput, newGroupNameText);
expect(newGroupInput).toBeInTheDocument();
await user.clear(newGroupInput);
const createButton = getByRole('button', {
name: messages.createButton.defaultMessage,
});
expect(createButton).toBeInTheDocument();
userEvent.click(createButton);
await user.click(createButton);
await waitFor(() => {
expect(
@@ -116,6 +118,7 @@ describe('<ContentGroupForm />', () => {
});
it('calls onEdit when the "Save" button is clicked with a valid form', async () => {
const user = userEvent.setup();
const { getByRole, getByPlaceholderText, queryByText } = renderComponent({
isEditMode: true,
overrideValue: 'overrideValue',
@@ -124,12 +127,12 @@ describe('<ContentGroupForm />', () => {
const newGroupInput = getByPlaceholderText(
messages.newGroupInputPlaceholder.defaultMessage,
);
userEvent.type(newGroupInput, newGroupNameText);
await user.type(newGroupInput, newGroupNameText);
const saveButton = getByRole('button', {
name: messages.saveButton.defaultMessage,
});
expect(saveButton).toBeInTheDocument();
userEvent.click(saveButton);
await user.click(saveButton);
await waitFor(() => {
expect(
@@ -140,6 +143,7 @@ describe('<ContentGroupForm />', () => {
});
it('shows error when the "Save" button is clicked with an invalid duplicate form', async () => {
const user = userEvent.setup();
const { getByRole, getByPlaceholderText, getByText } = renderComponent({
isEditMode: true,
overrideValue: contentGroupsMock.groups[0].name,
@@ -148,13 +152,13 @@ describe('<ContentGroupForm />', () => {
const newGroupInput = getByPlaceholderText(
messages.newGroupInputPlaceholder.defaultMessage,
);
userEvent.clear(newGroupInput);
userEvent.type(newGroupInput, newGroupNameText);
await user.clear(newGroupInput);
await user.type(newGroupInput, newGroupNameText);
const saveButton = getByRole('button', {
name: messages.saveButton.defaultMessage,
});
expect(saveButton).toBeInTheDocument();
userEvent.click(saveButton);
await user.click(saveButton);
await waitFor(() => {
expect(
@@ -164,12 +168,13 @@ describe('<ContentGroupForm />', () => {
});
it('calls onCancel when the "Cancel" button is clicked', async () => {
const user = userEvent.setup();
const { getByRole } = renderComponent();
const cancelButton = getByRole('button', {
name: messages.cancelButton.defaultMessage,
});
expect(cancelButton).toBeInTheDocument();
userEvent.click(cancelButton);
await user.click(cancelButton);
expect(onCancelClickMock).toHaveBeenCalledTimes(1);
});

View File

@@ -47,16 +47,18 @@ describe('<ContentGroupsSection />', () => {
});
it('renders container with new group on create click if section is empty', async () => {
const user = userEvent.setup();
const { getByRole, getByTestId } = renderComponent({ availableGroup: {} });
userEvent.click(
await user.click(
getByRole('button', { name: placeholderMessages.button.defaultMessage }),
);
expect(getByTestId('content-group-form')).toBeInTheDocument();
});
it('renders container with new group on create click if section has groups', async () => {
const user = userEvent.setup();
const { getByRole, getByTestId } = renderComponent();
userEvent.click(
await user.click(
getByRole('button', { name: messages.addNewGroup.defaultMessage }),
);
expect(getByTestId('content-group-form')).toBeInTheDocument();

View File

@@ -45,17 +45,19 @@ describe('<ExperimentCard />', () => {
expect(getByTestId('configuration-card-header-delete')).toBeInTheDocument();
});
it('expands/collapses the container experiment configuration on title click', () => {
it('expands/collapses the container experiment configuration on title click', async () => {
const user = userEvent.setup();
const { queryByTestId, getByTestId } = renderComponent();
const cardTitle = getByTestId('configuration-card-header-button');
userEvent.click(cardTitle);
await user.click(cardTitle);
expect(queryByTestId('configuration-card-content')).toBeInTheDocument();
userEvent.click(cardTitle);
await user.click(cardTitle);
expect(queryByTestId('configuration-card-content')).not.toBeInTheDocument();
});
it('renders experiment configuration without access to units', () => {
it('renders experiment configuration without access to units', async () => {
const user = userEvent.setup();
const experimentConfigurationUpdated = {
...experimentConfiguration,
usage: [],
@@ -68,13 +70,14 @@ describe('<ExperimentCard />', () => {
).not.toBeInTheDocument();
const cardTitle = getByTestId('configuration-card-header-button');
userEvent.click(cardTitle);
await user.click(cardTitle);
expect(
getByTestId('experiment-configuration-card-usage-empty'),
).toBeInTheDocument();
});
it('renders usage with validation error message', () => {
it('renders usage with validation error message', async () => {
const user = userEvent.setup();
const experimentConfigurationUpdated = {
...experimentConfiguration,
usage: [{
@@ -91,7 +94,7 @@ describe('<ExperimentCard />', () => {
});
const cardTitle = getByTestId('configuration-card-header-button');
userEvent.click(cardTitle);
await user.click(cardTitle);
expect(
getByText(experimentConfigurationUpdated.usage[0].validation.text),

View File

@@ -78,6 +78,7 @@ describe('<ExperimentForm />', () => {
});
it('calls onCreateClick when the "Create" button is clicked with a valid form', async () => {
const user = userEvent.setup();
const { getByRole, getByPlaceholderText } = renderComponent();
const nameInput = getByPlaceholderText(
messages.experimentConfigurationNamePlaceholder.defaultMessage,
@@ -85,8 +86,8 @@ describe('<ExperimentForm />', () => {
const descriptionInput = getByPlaceholderText(
messages.experimentConfigurationNamePlaceholder.defaultMessage,
);
userEvent.type(nameInput, 'New name of the group configuration');
userEvent.type(
await user.type(nameInput, 'New name of the group configuration');
await user.type(
descriptionInput,
'New description of the group configuration',
);
@@ -94,7 +95,7 @@ describe('<ExperimentForm />', () => {
name: messages.experimentConfigurationCreate.defaultMessage,
});
expect(createButton).toBeInTheDocument();
userEvent.click(createButton);
await user.click(createButton);
await waitFor(() => {
expect(onCreateClickMock).toHaveBeenCalledTimes(1);
@@ -102,17 +103,18 @@ describe('<ExperimentForm />', () => {
});
it('shows error when the "Create" button is clicked with empty name', async () => {
const user = userEvent.setup();
const { getByRole, getByPlaceholderText, getByText } = renderComponent();
const nameInput = getByPlaceholderText(
messages.experimentConfigurationNamePlaceholder.defaultMessage,
);
userEvent.type(nameInput, '');
await user.clear(nameInput);
const createButton = getByRole('button', {
name: messages.experimentConfigurationCreate.defaultMessage,
});
expect(createButton).toBeInTheDocument();
userEvent.click(createButton);
await user.click(createButton);
await waitFor(() => {
expect(
@@ -122,6 +124,7 @@ describe('<ExperimentForm />', () => {
});
it('shows error when the "Create" button is clicked without groups', async () => {
const user = userEvent.setup();
const experimentConfigurationUpdated = {
...experimentConfiguration,
name: 'My group configuration name',
@@ -134,7 +137,7 @@ describe('<ExperimentForm />', () => {
name: messages.experimentConfigurationCreate.defaultMessage,
});
expect(createButton).toBeInTheDocument();
userEvent.click(createButton);
await user.click(createButton);
await waitFor(() => {
expect(
@@ -144,6 +147,7 @@ describe('<ExperimentForm />', () => {
});
it('shows error when the "Create" button is clicked with duplicate groups', async () => {
const user = userEvent.setup();
const experimentConfigurationUpdated = {
...experimentConfiguration,
name: 'My group configuration name',
@@ -163,7 +167,7 @@ describe('<ExperimentForm />', () => {
name: messages.experimentConfigurationCreate.defaultMessage,
});
expect(createButton).toBeInTheDocument();
userEvent.click(createButton);
await user.click(createButton);
await waitFor(() => {
expect(
@@ -175,6 +179,7 @@ describe('<ExperimentForm />', () => {
});
it('shows error when the "Create" button is clicked with empty name of group', async () => {
const user = userEvent.setup();
const experimentConfigurationUpdated = {
...experimentConfiguration,
name: 'My group configuration name',
@@ -191,7 +196,7 @@ describe('<ExperimentForm />', () => {
name: messages.experimentConfigurationCreate.defaultMessage,
});
expect(createButton).toBeInTheDocument();
userEvent.click(createButton);
await user.click(createButton);
await waitFor(() => {
expect(
@@ -203,6 +208,7 @@ describe('<ExperimentForm />', () => {
});
it('calls onEditClick when the "Save" button is clicked with a valid form', async () => {
const user = userEvent.setup();
const { getByRole, getByPlaceholderText } = renderComponent({
isEditMode: true,
initialValues: experimentConfiguration,
@@ -211,12 +217,12 @@ describe('<ExperimentForm />', () => {
const nameInput = getByPlaceholderText(
messages.experimentConfigurationNamePlaceholder.defaultMessage,
);
userEvent.type(nameInput, newConfigurationNameText);
await user.type(nameInput, newConfigurationNameText);
const saveButton = getByRole('button', {
name: messages.experimentConfigurationSave.defaultMessage,
});
expect(saveButton).toBeInTheDocument();
userEvent.click(saveButton);
await user.click(saveButton);
await waitFor(() => {
expect(onEditClickMock).toHaveBeenCalledTimes(1);
@@ -224,12 +230,13 @@ describe('<ExperimentForm />', () => {
});
it('calls onCancelClick when the "Cancel" button is clicked', async () => {
const user = userEvent.setup();
const { getByRole } = renderComponent();
const cancelButton = getByRole('button', {
name: messages.experimentConfigurationCancel.defaultMessage,
});
expect(cancelButton).toBeInTheDocument();
userEvent.click(cancelButton);
await user.click(cancelButton);
expect(onCancelClickMock).toHaveBeenCalledTimes(1);
});

View File

@@ -69,6 +69,7 @@ describe('<CollectionInfoHeader />', () => {
});
it('should update collection title', async () => {
const user = userEvent.setup();
render();
expect(await screen.findByText('Test Collection')).toBeInTheDocument();
@@ -80,8 +81,8 @@ describe('<CollectionInfoHeader />', () => {
const textBox = screen.getByRole('textbox', { name: /text input/i });
userEvent.clear(textBox);
userEvent.type(textBox, 'New Collection Title{enter}');
await user.clear(textBox);
await user.type(textBox, 'New Collection Title{enter}');
await waitFor(() => {
expect(axiosMock.history.patch[0].url).toEqual(url);
@@ -93,6 +94,7 @@ describe('<CollectionInfoHeader />', () => {
});
it('should not update collection title if title is the same', async () => {
const user = userEvent.setup();
render();
expect(await screen.findByText('Test Collection')).toBeInTheDocument();
@@ -103,8 +105,8 @@ describe('<CollectionInfoHeader />', () => {
const textBox = screen.getByRole('textbox', { name: /text input/i });
userEvent.clear(textBox);
userEvent.type(textBox, `${mockGetCollectionMetadata.collectionData.title}{enter}`);
await user.clear(textBox);
await user.type(textBox, `${mockGetCollectionMetadata.collectionData.title}{enter}`);
await waitFor(() => expect(axiosMock.history.patch.length).toEqual(0));
@@ -112,6 +114,7 @@ describe('<CollectionInfoHeader />', () => {
});
it('should not update collection title if title is empty', async () => {
const user = userEvent.setup();
render();
expect(await screen.findByText('Test Collection')).toBeInTheDocument();
@@ -122,8 +125,8 @@ describe('<CollectionInfoHeader />', () => {
const textBox = screen.getByRole('textbox', { name: /text input/i });
userEvent.clear(textBox);
userEvent.type(textBox, '{enter}');
await user.clear(textBox);
await user.type(textBox, '{enter}');
await waitFor(() => expect(axiosMock.history.patch.length).toEqual(0));
@@ -131,6 +134,7 @@ describe('<CollectionInfoHeader />', () => {
});
it('should close edit collection title on press Escape', async () => {
const user = userEvent.setup();
render();
expect(await screen.findByText('Test Collection')).toBeInTheDocument();
@@ -141,8 +145,9 @@ describe('<CollectionInfoHeader />', () => {
const textBox = screen.getByRole('textbox', { name: /text input/i });
userEvent.clear(textBox);
userEvent.type(textBox, 'New Collection Title{esc}');
await user.clear(textBox);
await user.type(textBox, 'New Collection Title');
await user.keyboard('{Escape}');
await waitFor(() => expect(axiosMock.history.patch.length).toEqual(0));
@@ -150,6 +155,7 @@ describe('<CollectionInfoHeader />', () => {
});
it('should show error on edit collection title', async () => {
const user = userEvent.setup();
render();
expect(await screen.findByText('Test Collection')).toBeInTheDocument();
@@ -160,8 +166,9 @@ describe('<CollectionInfoHeader />', () => {
const textBox = screen.getByRole('textbox', { name: /text input/i });
userEvent.clear(textBox);
userEvent.type(textBox, 'New Collection Title{enter}');
await user.clear(textBox);
await user.type(textBox, 'New Collection Title');
await user.keyboard('{Enter}');
await waitFor(() => {
expect(axiosMock.history.patch[0].url).toEqual(url);

View File

@@ -165,6 +165,7 @@ describe('<ComponentPicker />', () => {
});
it('double clicking a collection should open it', async () => {
const user = userEvent.setup();
render(<ComponentPicker />);
expect(await screen.findByText('Test Library 1')).toBeInTheDocument();
@@ -178,7 +179,7 @@ describe('<ComponentPicker />', () => {
mockSearchResult(mockCollectionResult);
// Double click on the collection card to open the collection
userEvent.dblClick(screen.queryAllByText('Collection 1')[0]);
await user.dblClick(screen.queryAllByText('Collection 1')[0]);
// Wait for the collection to load
await screen.findByText(/Back to Library/i);

View File

@@ -2,7 +2,7 @@ import userEvent from '@testing-library/user-event';
import type MockAdapter from 'axios-mock-adapter';
import {
initializeMocks, render as baseRender, screen, waitFor, waitForElementToBeRemoved, within, fireEvent,
initializeMocks, render as baseRender, screen, waitFor, within, fireEvent,
} from '../../testUtils';
import { LibraryProvider } from '../common/context/LibraryContext';
import { type CollectionHit } from '../../search-manager';
@@ -82,11 +82,12 @@ describe('<CollectionCard />', () => {
});
it('should navigate to the collection if the open menu clicked', async () => {
const user = userEvent.setup();
render(<CollectionCard hit={collectionHitSample} />);
// Open menu
expect(screen.getByTestId('collection-card-menu-toggle')).toBeInTheDocument();
userEvent.click(screen.getByTestId('collection-card-menu-toggle'));
await user.click(screen.getByTestId('collection-card-menu-toggle'));
// Open menu item
const openMenuItem = screen.getByRole('button', { name: 'Open' });
@@ -103,12 +104,13 @@ describe('<CollectionCard />', () => {
});
it('should navigate to the collection if double clicked', async () => {
const user = userEvent.setup();
render(<CollectionCard hit={collectionHitSample} />);
// Card title
const cardTitle = screen.getByText('Collection Display Formated Name');
expect(cardTitle).toBeInTheDocument();
userEvent.dblClick(cardTitle);
await user.dblClick(cardTitle);
await waitFor(() => {
expect(mockNavigate).toHaveBeenCalledWith({
@@ -119,6 +121,7 @@ describe('<CollectionCard />', () => {
});
it('should show confirmation box, delete collection and show toast to undo deletion', async () => {
const user = userEvent.setup();
const url = getLibraryCollectionApiUrl(collectionHitSample.contextKey, collectionHitSample.blockId);
axiosMock.onDelete(url).reply(204);
render(<CollectionCard hit={collectionHitSample} />);
@@ -126,29 +129,29 @@ describe('<CollectionCard />', () => {
expect(screen.queryByText('Collection Display Formated Name')).toBeInTheDocument();
// Open menu
let menuBtn = await screen.findByRole('button', { name: messages.collectionCardMenuAlt.defaultMessage });
userEvent.click(menuBtn);
await user.click(menuBtn);
// find and click delete menu option.
expect(screen.queryByText('Delete')).toBeInTheDocument();
let deleteBtn = await screen.findByRole('button', { name: 'Delete' });
userEvent.click(deleteBtn);
await user.click(deleteBtn);
// verify confirmation dialog and click on cancel button
let dialog = await screen.findByRole('dialog', { name: 'Delete this collection?' });
expect(dialog).toBeInTheDocument();
const cancelBtn = await screen.findByRole('button', { name: 'Cancel' });
userEvent.click(cancelBtn);
await user.click(cancelBtn);
expect(axiosMock.history.delete.length).toEqual(0);
expect(cancelBtn).not.toBeInTheDocument();
// Open menu
menuBtn = await screen.findByRole('button', { name: messages.collectionCardMenuAlt.defaultMessage });
userEvent.click(menuBtn);
await user.click(menuBtn);
// click on confirm button to delete
deleteBtn = await screen.findByRole('button', { name: 'Delete' });
userEvent.click(deleteBtn);
await user.click(deleteBtn);
dialog = await screen.findByRole('dialog', { name: 'Delete this collection?' });
const confirmBtn = await within(dialog).findByRole('button', { name: 'Delete' });
userEvent.click(confirmBtn);
await waitForElementToBeRemoved(() => screen.queryByRole('dialog', { name: 'Delete this collection?' }));
await user.click(confirmBtn);
expect(screen.queryByRole('dialog', { name: 'Delete this collection?' })).not.toBeInTheDocument();
await waitFor(() => {
expect(axiosMock.history.delete.length).toEqual(1);
@@ -170,19 +173,20 @@ describe('<CollectionCard />', () => {
it('should show failed toast on delete collection failure', async () => {
const url = getLibraryCollectionApiUrl(collectionHitSample.contextKey, collectionHitSample.blockId);
axiosMock.onDelete(url).reply(404);
const user = userEvent.setup();
render(<CollectionCard hit={collectionHitSample} />);
expect(screen.queryByText('Collection Display Formated Name')).toBeInTheDocument();
// Open menu
const menuBtn = await screen.findByRole('button', { name: messages.collectionCardMenuAlt.defaultMessage });
userEvent.click(menuBtn);
await user.click(menuBtn);
// find and click delete menu option.
const deleteBtn = await screen.findByRole('button', { name: 'Delete' });
userEvent.click(deleteBtn);
await user.click(deleteBtn);
const dialog = await screen.findByRole('dialog', { name: 'Delete this collection?' });
const confirmBtn = await within(dialog).findByRole('button', { name: 'Delete' });
userEvent.click(confirmBtn);
await waitForElementToBeRemoved(() => screen.queryByRole('dialog', { name: 'Delete this collection?' }));
await user.click(confirmBtn);
expect(screen.queryByRole('dialog', { name: 'Delete this collection?' })).not.toBeInTheDocument();
await waitFor(() => {
expect(axiosMock.history.delete.length).toEqual(1);

View File

@@ -143,16 +143,17 @@ describe('<ContainerCard />', () => {
containerType: ContainerType.Subsection,
},
])('$label', async ({ containerType }) => {
const user = userEvent.setup();
render(<ContainerCard hit={getContainerHitSample(containerType)} />);
// Open menu
expect(screen.getByTestId('container-card-menu-toggle')).toBeInTheDocument();
userEvent.click(screen.getByTestId('container-card-menu-toggle'));
await user.click(screen.getByTestId('container-card-menu-toggle'));
// Open menu item
const openMenuItem = await screen.findByRole('button', { name: 'Open' });
expect(openMenuItem).toBeInTheDocument();
userEvent.click(openMenuItem);
await user.click(openMenuItem);
expect(mockNavigate).toHaveBeenCalledWith({
pathname: `/library/${libraryId}/${containerType}/${getContainerHitSample(containerType).usageKey}`,
search: '',
@@ -173,12 +174,13 @@ describe('<ContainerCard />', () => {
containerType: ContainerType.Subsection,
},
])('$label', async ({ containerType }) => {
const user = userEvent.setup();
render(<ContainerCard hit={getContainerHitSample(containerType)} />);
// Open menu item
const cardItem = await screen.findByText(`${containerType} Display Formated Name`);
expect(cardItem).toBeInTheDocument();
userEvent.click(cardItem, undefined, { clickCount: 2 });
await user.dblClick(cardItem);
expect(mockNavigate).toHaveBeenCalledWith({
pathname: `/library/${libraryId}/${containerType}/${getContainerHitSample(containerType).usageKey}`,
search: '',
@@ -186,13 +188,14 @@ describe('<ContainerCard />', () => {
});
it('should delete the container from the menu & restore the container', async () => {
const user = userEvent.setup();
axiosMock.onDelete(getLibraryContainerApiUrl(getContainerHitSample().usageKey)).reply(200);
render(<ContainerCard hit={getContainerHitSample()} />);
// Open menu
expect(screen.getByTestId('container-card-menu-toggle')).toBeInTheDocument();
userEvent.click(screen.getByTestId('container-card-menu-toggle'));
await user.click(screen.getByTestId('container-card-menu-toggle'));
// Click on Delete Item
const deleteMenuItem = screen.getByRole('button', { name: 'Delete' });
@@ -223,13 +226,14 @@ describe('<ContainerCard />', () => {
});
it('should show error on delete the container from the menu', async () => {
const user = userEvent.setup();
axiosMock.onDelete(getLibraryContainerApiUrl(getContainerHitSample().usageKey)).reply(400);
render(<ContainerCard hit={getContainerHitSample()} />);
// Open menu
expect(screen.getByTestId('container-card-menu-toggle')).toBeInTheDocument();
userEvent.click(screen.getByTestId('container-card-menu-toggle'));
await user.click(screen.getByTestId('container-card-menu-toggle'));
// Click on Delete Item
const deleteMenuItem = screen.getByRole('button', { name: 'Delete' });
@@ -425,7 +429,7 @@ describe('<ContainerCard />', () => {
containerType: parentType,
displayName: 'Parent Container Display Name',
});
const user = userEvent.setup();
render(
<ContainerCard hit={containerHit} />,
false,
@@ -434,7 +438,7 @@ describe('<ContainerCard />', () => {
// Open menu
expect(screen.getByTestId('container-card-menu-toggle')).toBeInTheDocument();
userEvent.click(screen.getByTestId('container-card-menu-toggle'));
await user.click(screen.getByTestId('container-card-menu-toggle'));
// Click on Remove Item
const removeMenuItem = await screen.findByRole('button', { name: expectedRemoveText });

View File

@@ -78,12 +78,13 @@ let mockShowToast: { (message: string, action?: ToastActionData | undefined): vo
});
it(`should delete the ${containerType} using the menu`, async () => {
const user = userEvent.setup();
axiosMock.onDelete(getLibraryContainerApiUrl(containerId)).reply(200);
render(containerId);
// Open menu
expect(await screen.findByTestId('container-info-menu-toggle')).toBeInTheDocument();
userEvent.click(screen.getByTestId('container-info-menu-toggle'));
await user.click(screen.getByTestId('container-info-menu-toggle'));
// Click on Delete Item
const deleteMenuItem = await screen.findByRole('button', { name: 'Delete' });
@@ -102,13 +103,14 @@ let mockShowToast: { (message: string, action?: ToastActionData | undefined): vo
});
it('can publish the container', async () => {
const user = userEvent.setup();
axiosMock.onPost(getLibraryContainerPublishApiUrl(containerId)).reply(200);
render(containerId);
// Click on Publish button
const publishButton = await screen.findByRole('button', { name: 'Publish' });
expect(publishButton).toBeInTheDocument();
userEvent.click(publishButton);
await user.click(publishButton);
await waitFor(() => {
expect(axiosMock.history.post.length).toBe(1);
@@ -117,13 +119,14 @@ let mockShowToast: { (message: string, action?: ToastActionData | undefined): vo
});
it(`shows an error if publishing the ${containerType} fails`, async () => {
const user = userEvent.setup();
axiosMock.onPost(getLibraryContainerPublishApiUrl(containerId)).reply(500);
render(containerId);
// Click on Publish button
const publishButton = await screen.findByRole('button', { name: 'Publish' });
expect(publishButton).toBeInTheDocument();
userEvent.click(publishButton);
await user.click(publishButton);
await waitFor(() => {
expect(axiosMock.history.post.length).toBe(1);

View File

@@ -69,6 +69,7 @@ describe('<ContainerInfoHeader />', () => {
});
it('should update container title', async () => {
const user = userEvent.setup();
render();
expect(await screen.findByText('Test Unit')).toBeInTheDocument();
@@ -80,8 +81,9 @@ describe('<ContainerInfoHeader />', () => {
const textBox = screen.getByRole('textbox', { name: /text input/i });
userEvent.clear(textBox);
userEvent.type(textBox, 'New Unit Title{enter}');
await user.clear(textBox);
await user.type(textBox, 'New Unit Title{enter}');
await user.keyboard('{Enter}');
await waitFor(() => {
expect(axiosMock.history.patch[0].url).toEqual(url);
@@ -93,6 +95,7 @@ describe('<ContainerInfoHeader />', () => {
});
it('should not update container title if title is the same', async () => {
const user = userEvent.setup();
render();
expect(await screen.findByText('Test Unit')).toBeInTheDocument();
@@ -103,8 +106,9 @@ describe('<ContainerInfoHeader />', () => {
const textBox = screen.getByRole('textbox', { name: /text input/i });
userEvent.clear(textBox);
userEvent.type(textBox, `${mockGetContainerMetadata.containerData.displayName}{enter}`);
await user.clear(textBox);
await user.type(textBox, `${mockGetContainerMetadata.containerData.displayName}{enter}`);
await user.keyboard('{Enter}');
await waitFor(() => expect(axiosMock.history.patch.length).toEqual(0));
@@ -112,6 +116,7 @@ describe('<ContainerInfoHeader />', () => {
});
it('should not update container title if title is empty', async () => {
const user = userEvent.setup();
render();
expect(await screen.findByText('Test Unit')).toBeInTheDocument();
@@ -122,8 +127,8 @@ describe('<ContainerInfoHeader />', () => {
const textBox = screen.getByRole('textbox', { name: /text input/i });
userEvent.clear(textBox);
userEvent.type(textBox, '{enter}');
await user.clear(textBox);
await user.keyboard('{Enter}');
await waitFor(() => expect(axiosMock.history.patch.length).toEqual(0));
@@ -131,6 +136,7 @@ describe('<ContainerInfoHeader />', () => {
});
it('should close edit container title on press Escape', async () => {
const user = userEvent.setup();
render();
expect(await screen.findByText('Test Unit')).toBeInTheDocument();
@@ -141,8 +147,9 @@ describe('<ContainerInfoHeader />', () => {
const textBox = screen.getByRole('textbox', { name: /text input/i });
userEvent.clear(textBox);
userEvent.type(textBox, 'New Unit Title{esc}');
await user.clear(textBox);
await user.type(textBox, 'New Unit Title');
await user.keyboard('{Escape}');
await waitFor(() => expect(axiosMock.history.patch.length).toEqual(0));
@@ -150,6 +157,7 @@ describe('<ContainerInfoHeader />', () => {
});
it('should show error on edit container title', async () => {
const user = userEvent.setup();
render();
expect(await screen.findByText('Test Unit')).toBeInTheDocument();
@@ -160,8 +168,9 @@ describe('<ContainerInfoHeader />', () => {
const textBox = screen.getByRole('textbox', { name: /text input/i });
userEvent.clear(textBox);
userEvent.type(textBox, 'New Unit Title{enter}');
await user.clear(textBox);
await user.type(textBox, 'New Unit Title{enter}');
await user.keyboard('{Enter}');
await waitFor(() => {
expect(axiosMock.history.patch[0].url).toEqual(url);

View File

@@ -64,6 +64,7 @@ describe('CreateContainerModal container linking', () => {
}
it('links container to collection when inside a collection', async () => {
const user = userEvent.setup();
renderWithProvider(
<>
<AddContent />
@@ -73,11 +74,11 @@ describe('CreateContainerModal container linking', () => {
);
// Disambiguate: select the "Section" button by exact match
const sectionButton = await screen.findByRole('button', { name: /^Section$/ });
userEvent.click(sectionButton);
await user.click(sectionButton);
const nameInput = await screen.findByLabelText(/name your section/i);
userEvent.type(nameInput, 'Test Section');
await user.type(nameInput, 'Test Section');
const createButton = await screen.findByRole('button', { name: /create/i });
userEvent.click(createButton);
await user.click(createButton);
await waitFor(() => {
expect(axiosMock.history.post).toHaveLength(1);
});
@@ -90,6 +91,7 @@ describe('CreateContainerModal container linking', () => {
});
it('links container to section when inside a section', async () => {
const user = userEvent.setup();
axiosMock.onPost(getLibraryContainerApiUrl(newSectionId)).reply(200, {
id: newSectionId,
containerType: 'section',
@@ -106,11 +108,11 @@ describe('CreateContainerModal container linking', () => {
);
const subsectionButton = await screen.findByRole('button', { name: /New subsection/i });
userEvent.click(subsectionButton);
await user.click(subsectionButton);
const nameInput = await screen.findByLabelText(/name your subsection/i);
userEvent.type(nameInput, 'Test Subsection');
await user.type(nameInput, 'Test Subsection');
const createButton = await screen.findByRole('button', { name: /create/i });
userEvent.click(createButton);
await user.click(createButton);
await waitFor(() => {
expect(axiosMock.history.post[0].url).toMatch(/\/api\/libraries\/.*\/containers/);
});
@@ -122,6 +124,7 @@ describe('CreateContainerModal container linking', () => {
});
it('handles linking error gracefully', async () => {
const user = userEvent.setup();
axiosMock.onPost(getLibraryContainersApiUrl(libraryId)).reply(500);
renderWithProvider(
<>
@@ -132,11 +135,11 @@ describe('CreateContainerModal container linking', () => {
);
// Disambiguate: select the "Section" button by exact match
const sectionButton = await screen.findByRole('button', { name: /^Section$/ });
userEvent.click(sectionButton);
await user.click(sectionButton);
const nameInput = await screen.findByLabelText(/name your section/i);
userEvent.type(nameInput, 'Test Section');
await user.type(nameInput, 'Test Section');
const createButton = await screen.findByRole('button', { name: /create/i });
userEvent.click(createButton);
await user.click(createButton);
await waitFor(() => {
expect(mockShowToast).toHaveBeenCalledWith(expect.stringMatching(/error/i));
});

View File

@@ -3,7 +3,6 @@ import type MockAdapter from 'axios-mock-adapter';
import userEvent from '@testing-library/user-event';
import {
act,
fireEvent,
initializeMocks,
render,
@@ -46,6 +45,7 @@ describe('<CreateLibrary />', () => {
});
test('call api data with correct data', async () => {
const user = userEvent.setup();
axiosMock.onGet(getStudioHomeApiUrl()).reply(200, studioHomeMock);
axiosMock.onPost(getContentLibraryV2CreateApiUrl()).reply(200, {
id: 'library-id',
@@ -54,17 +54,17 @@ describe('<CreateLibrary />', () => {
render(<CreateLibrary />);
const titleInput = await screen.findByRole('textbox', { name: /library name/i });
userEvent.click(titleInput);
userEvent.type(titleInput, 'Test Library Name');
await user.click(titleInput);
await user.type(titleInput, 'Test Library Name');
const orgInput = await screen.findByRole('combobox', { name: /organization/i });
userEvent.click(orgInput);
userEvent.type(orgInput, 'org1');
act(() => userEvent.tab());
await user.click(orgInput);
await user.type(orgInput, 'org1');
await user.tab();
const slugInput = await screen.findByRole('textbox', { name: /library id/i });
userEvent.click(slugInput);
userEvent.type(slugInput, 'test_library_slug');
await user.click(slugInput);
await user.type(slugInput, 'test_library_slug');
fireEvent.click(await screen.findByRole('button', { name: /create/i }));
await waitFor(() => {
@@ -77,6 +77,7 @@ describe('<CreateLibrary />', () => {
});
test('cannot create new org unless allowed', async () => {
const user = userEvent.setup();
axiosMock.onGet(getStudioHomeApiUrl()).reply(200, studioHomeMock);
axiosMock.onPost(getContentLibraryV2CreateApiUrl()).reply(200, {
id: 'library-id',
@@ -85,23 +86,23 @@ describe('<CreateLibrary />', () => {
render(<CreateLibrary />);
const titleInput = await screen.findByRole('textbox', { name: /library name/i });
userEvent.click(titleInput);
userEvent.type(titleInput, 'Test Library Name');
await user.click(titleInput);
await user.type(titleInput, 'Test Library Name');
// We cannot create a new org, and so we're restricted to the allowed list
const orgOptions = screen.getByTestId('autosuggest-iconbutton');
userEvent.click(orgOptions);
await user.click(orgOptions);
expect(screen.getByText('org1')).toBeInTheDocument();
['org2', 'org3', 'org4', 'org5'].forEach((org) => expect(screen.queryByText(org)).not.toBeInTheDocument());
const orgInput = await screen.findByRole('combobox', { name: /organization/i });
userEvent.click(orgInput);
userEvent.type(orgInput, 'NewOrg');
act(() => userEvent.tab());
await user.click(orgInput);
await user.type(orgInput, 'NewOrg');
await user.tab();
const slugInput = await screen.findByRole('textbox', { name: /library id/i });
userEvent.click(slugInput);
userEvent.type(slugInput, 'test_library_slug');
await user.click(slugInput);
await user.type(slugInput, 'test_library_slug');
fireEvent.click(await screen.findByRole('button', { name: /create/i }));
await waitFor(() => {
@@ -111,6 +112,7 @@ describe('<CreateLibrary />', () => {
});
test('can create new org if allowed', async () => {
const user = userEvent.setup();
axiosMock.onGet(getStudioHomeApiUrl()).reply(200, {
...studioHomeMock,
allow_to_create_new_org: true,
@@ -122,22 +124,22 @@ describe('<CreateLibrary />', () => {
render(<CreateLibrary />);
const titleInput = await screen.findByRole('textbox', { name: /library name/i });
userEvent.click(titleInput);
userEvent.type(titleInput, 'Test Library Name');
await user.click(titleInput);
await user.type(titleInput, 'Test Library Name');
// We can create a new org, so we're also allowed to use any existing org
const orgOptions = screen.getByTestId('autosuggest-iconbutton');
userEvent.click(orgOptions);
await user.click(orgOptions);
['org1', 'org2', 'org3', 'org4', 'org5'].forEach((org) => expect(screen.queryByText(org)).toBeInTheDocument());
const orgInput = await screen.findByRole('combobox', { name: /organization/i });
userEvent.click(orgInput);
userEvent.type(orgInput, 'NewOrg');
act(() => userEvent.tab());
await user.click(orgInput);
await user.type(orgInput, 'NewOrg');
await user.tab();
const slugInput = await screen.findByRole('textbox', { name: /library id/i });
userEvent.click(slugInput);
userEvent.type(slugInput, 'test_library_slug');
await user.click(slugInput);
await user.type(slugInput, 'test_library_slug');
fireEvent.click(await screen.findByRole('button', { name: /create/i }));
await waitFor(() => {
@@ -150,6 +152,7 @@ describe('<CreateLibrary />', () => {
});
test('show api error', async () => {
const user = userEvent.setup();
axiosMock.onGet(getStudioHomeApiUrl()).reply(200, studioHomeMock);
axiosMock.onPost(getContentLibraryV2CreateApiUrl()).reply(400, {
field: 'Error message',
@@ -157,17 +160,17 @@ describe('<CreateLibrary />', () => {
render(<CreateLibrary />);
const titleInput = await screen.findByRole('textbox', { name: /library name/i });
userEvent.click(titleInput);
userEvent.type(titleInput, 'Test Library Name');
await user.click(titleInput);
await user.type(titleInput, 'Test Library Name');
const orgInput = await screen.findByTestId('autosuggest-textbox-input');
userEvent.click(orgInput);
userEvent.type(orgInput, 'org1');
act(() => userEvent.tab());
await user.click(orgInput);
await user.type(orgInput, 'org1');
await user.tab();
const slugInput = await screen.findByRole('textbox', { name: /library id/i });
userEvent.click(slugInput);
userEvent.type(slugInput, 'test_library_slug');
await user.click(slugInput);
await user.type(slugInput, 'test_library_slug');
fireEvent.click(await screen.findByRole('button', { name: /create/i }));
await waitFor(async () => {

View File

@@ -59,6 +59,7 @@ describe('<ManageCollections />', () => {
});
it('should show all collections in library and allow users to select for the current component', async () => {
const user = userEvent.setup();
const url = getLibraryBlockCollectionsUrl(mockLibraryBlockMetadata.usageKeyWithCollections);
axiosMock.onPatch(url).reply(200);
render(<ManageCollections
@@ -67,13 +68,13 @@ describe('<ManageCollections />', () => {
useUpdateCollectionsHook={useUpdateComponentCollections}
/>);
const manageBtn = await screen.findByRole('button', { name: 'Manage Collections' });
userEvent.click(manageBtn);
await user.click(manageBtn);
await waitFor(() => { expect(fetchMock).toHaveFetchedTimes(1, searchEndpoint, 'post'); });
expect(screen.queryByRole('search')).toBeInTheDocument();
const secondCollection = await screen.findByRole('button', { name: 'My second collection' });
userEvent.click(secondCollection);
await user.click(secondCollection);
const confirmBtn = await screen.findByRole('button', { name: 'Confirm' });
userEvent.click(confirmBtn);
await user.click(confirmBtn);
await waitFor(() => {
expect(axiosMock.history.patch.length).toEqual(1);
});
@@ -85,6 +86,7 @@ describe('<ManageCollections />', () => {
});
it('should show all collections in library and allow users to select for the current container', async () => {
const user = userEvent.setup();
const url = getLibraryContainerCollectionsUrl(mockGetContainerMetadata.unitIdWithCollections);
axiosMock.onPatch(url).reply(200);
render(<ManageCollections
@@ -93,13 +95,13 @@ describe('<ManageCollections />', () => {
useUpdateCollectionsHook={useUpdateContainerCollections}
/>);
const manageBtn = await screen.findByRole('button', { name: 'Manage Collections' });
userEvent.click(manageBtn);
await user.click(manageBtn);
await waitFor(() => { expect(fetchMock).toHaveFetchedTimes(1, searchEndpoint, 'post'); });
expect(screen.queryByRole('search')).toBeInTheDocument();
const secondCollection = await screen.findByRole('button', { name: 'My second collection' });
userEvent.click(secondCollection);
await user.click(secondCollection);
const confirmBtn = await screen.findByRole('button', { name: 'Confirm' });
userEvent.click(confirmBtn);
await user.click(confirmBtn);
await waitFor(() => {
expect(axiosMock.history.patch.length).toEqual(1);
});
@@ -111,6 +113,7 @@ describe('<ManageCollections />', () => {
});
it('should show toast and close manage collections selection on failure', async () => {
const user = userEvent.setup();
const url = getLibraryBlockCollectionsUrl(mockLibraryBlockMetadata.usageKeyWithCollections);
axiosMock.onPatch(url).reply(400);
render(<ManageCollections
@@ -120,13 +123,13 @@ describe('<ManageCollections />', () => {
/>);
screen.logTestingPlaygroundURL();
const manageBtn = await screen.findByRole('button', { name: 'Add to Collection' });
userEvent.click(manageBtn);
await user.click(manageBtn);
await waitFor(() => { expect(fetchMock).toHaveFetchedTimes(1, searchEndpoint, 'post'); });
expect(screen.queryByRole('search')).toBeInTheDocument();
const secondCollection = await screen.findByRole('button', { name: 'My second collection' });
userEvent.click(secondCollection);
await user.click(secondCollection);
const confirmBtn = await screen.findByRole('button', { name: 'Confirm' });
userEvent.click(confirmBtn);
await user.click(confirmBtn);
await waitFor(() => {
expect(axiosMock.history.patch.length).toEqual(1);
});
@@ -138,6 +141,7 @@ describe('<ManageCollections />', () => {
});
it('should close manage collections selection on cancel', async () => {
const user = userEvent.setup();
const url = getLibraryBlockCollectionsUrl(mockLibraryBlockMetadata.usageKeyWithCollections);
axiosMock.onPatch(url).reply(400);
render(<ManageCollections
@@ -146,13 +150,13 @@ describe('<ManageCollections />', () => {
useUpdateCollectionsHook={useUpdateComponentCollections}
/>);
const manageBtn = await screen.findByRole('button', { name: 'Add to Collection' });
userEvent.click(manageBtn);
await user.click(manageBtn);
await waitFor(() => { expect(fetchMock).toHaveFetchedTimes(1, searchEndpoint, 'post'); });
expect(screen.queryByRole('search')).toBeInTheDocument();
const secondCollection = await screen.findByRole('button', { name: 'My second collection' });
userEvent.click(secondCollection);
await user.click(secondCollection);
const cancelBtn = await screen.findByRole('button', { name: 'Cancel' });
userEvent.click(cancelBtn);
await user.click(cancelBtn);
await waitFor(() => {
expect(axiosMock.history.patch.length).toEqual(0);
});

View File

@@ -132,13 +132,14 @@ describe('<LibraryTeam />', () => {
);
it('allows library to be made "public read"', async () => {
const user = userEvent.setup();
const url = getContentLibraryApiUrl(libraryId);
const axiosMock = new MockAdapter(getAuthenticatedHttpClient());
axiosMock.onPatch(url).reply(204);
await renderLibraryTeam();
const checkbox = screen.getByRole('switch', { name: /Allow public read/i });
userEvent.click(checkbox);
await user.click(checkbox);
await waitFor(() => {
expect(axiosMock.history.patch.length).toEqual(1);
@@ -149,6 +150,7 @@ describe('<LibraryTeam />', () => {
});
it('allows new library team members to be added', async () => {
const user = userEvent.setup();
const url = getLibraryTeamApiUrl(libraryId);
const axiosMock = new MockAdapter(getAuthenticatedHttpClient());
axiosMock.onPost(url).reply(204, {});
@@ -156,22 +158,22 @@ describe('<LibraryTeam />', () => {
await renderLibraryTeam();
let addButton = screen.getByRole('button', { name: 'New team member' });
userEvent.click(addButton);
await user.click(addButton);
const cancelButton = screen.getByRole('button', { name: /cancel/i });
userEvent.click(cancelButton);
await user.click(cancelButton);
await waitFor(() => {
expect(axiosMock.history.post.length).toEqual(0);
});
addButton = screen.getByRole('button', { name: 'New team member' });
userEvent.click(addButton);
await user.click(addButton);
const emailInput = screen.getByRole('textbox', { name: 'User\'s email address' });
userEvent.click(emailInput);
userEvent.type(emailInput, 'another@user.tld');
await user.click(emailInput);
await user.type(emailInput, 'another@user.tld');
const saveButton = screen.getByRole('button', { name: /add member/i });
userEvent.click(saveButton);
await user.click(saveButton);
await waitFor(() => {
expect(axiosMock.history.post.length).toEqual(1);
@@ -184,6 +186,7 @@ describe('<LibraryTeam />', () => {
});
it('shows error when specific error (string)', async () => {
const user = userEvent.setup();
const url = getLibraryTeamApiUrl(libraryId);
const axiosMock = new MockAdapter(getAuthenticatedHttpClient());
axiosMock.onPost(url).reply(400, { email: 'This is a specific error.' });
@@ -191,13 +194,13 @@ describe('<LibraryTeam />', () => {
await renderLibraryTeam();
const addButton = screen.getByRole('button', { name: 'New team member' });
userEvent.click(addButton);
await user.click(addButton);
const emailInput = screen.getByRole('textbox', { name: 'User\'s email address' });
userEvent.click(emailInput);
userEvent.type(emailInput, 'another@user.tld');
await user.click(emailInput);
await user.type(emailInput, 'another@user.tld');
const saveButton = screen.getByRole('button', { name: /add member/i });
userEvent.click(saveButton);
await user.click(saveButton);
await waitFor(() => {
expect(axiosMock.history.post.length).toEqual(1);
@@ -209,6 +212,7 @@ describe('<LibraryTeam />', () => {
});
it('shows error when specific error (Array)', async () => {
const user = userEvent.setup();
const url = getLibraryTeamApiUrl(libraryId);
const axiosMock = new MockAdapter(getAuthenticatedHttpClient());
axiosMock.onPost(url).reply(400, { email: ['This is a specific error.'] });
@@ -216,13 +220,13 @@ describe('<LibraryTeam />', () => {
await renderLibraryTeam();
const addButton = screen.getByRole('button', { name: 'New team member' });
userEvent.click(addButton);
await user.click(addButton);
const emailInput = screen.getByRole('textbox', { name: 'User\'s email address' });
userEvent.click(emailInput);
userEvent.type(emailInput, 'another@user.tld');
await user.click(emailInput);
await user.type(emailInput, 'another@user.tld');
const saveButton = screen.getByRole('button', { name: /add member/i });
userEvent.click(saveButton);
await user.click(saveButton);
await waitFor(() => {
expect(axiosMock.history.post.length).toEqual(1);
@@ -234,6 +238,7 @@ describe('<LibraryTeam />', () => {
});
it('shows error', async () => {
const user = userEvent.setup();
const url = getLibraryTeamApiUrl(libraryId);
const axiosMock = new MockAdapter(getAuthenticatedHttpClient());
axiosMock.onPost(url).reply(400, {});
@@ -241,13 +246,13 @@ describe('<LibraryTeam />', () => {
await renderLibraryTeam();
const addButton = screen.getByRole('button', { name: 'New team member' });
userEvent.click(addButton);
await user.click(addButton);
const emailInput = screen.getByRole('textbox', { name: 'User\'s email address' });
userEvent.click(emailInput);
userEvent.type(emailInput, 'another@user.tld');
await user.click(emailInput);
await user.type(emailInput, 'another@user.tld');
const saveButton = screen.getByRole('button', { name: /add member/i });
userEvent.click(saveButton);
await user.click(saveButton);
await waitFor(() => {
expect(axiosMock.history.post.length).toEqual(1);
@@ -257,6 +262,7 @@ describe('<LibraryTeam />', () => {
});
it('allows library team member roles to be changed', async () => {
const user = userEvent.setup();
const { username } = mockGetLibraryTeam.readerMember;
const url = getLibraryTeamMemberApiUrl(libraryId, username);
const axiosMock = new MockAdapter(getAuthenticatedHttpClient());
@@ -265,7 +271,7 @@ describe('<LibraryTeam />', () => {
await renderLibraryTeam();
const makeAuthor = screen.getByRole('button', { name: 'Make Author' });
userEvent.click(makeAuthor);
await user.click(makeAuthor);
await waitFor(() => {
expect(axiosMock.history.put.length).toEqual(1);
@@ -276,6 +282,7 @@ describe('<LibraryTeam />', () => {
});
it('allows library team members to be deleted', async () => {
const user = userEvent.setup();
const { username } = mockGetLibraryTeam.authorMember;
const url = getLibraryTeamMemberApiUrl(libraryId, username);
const axiosMock = new MockAdapter(getAuthenticatedHttpClient());
@@ -284,7 +291,7 @@ describe('<LibraryTeam />', () => {
await renderLibraryTeam();
const deleteMember = screen.getAllByRole('button', { name: 'Delete team member' })[0];
userEvent.click(deleteMember);
await user.click(deleteMember);
await waitFor(() => {
expect(axiosMock.history.delete.length).toEqual(1);

View File

@@ -383,28 +383,30 @@ describe('<LibrarySectionPage / LibrarySubsectionPage />', () => {
});
it(`should open ${childType} page on double click`, async () => {
const user = userEvent.setup();
renderLibrarySectionPage(undefined, undefined, cType);
const child = await screen.findByText(`${childType} block 0`);
// Trigger double click. Find the child card as the parent element
userEvent.click(child.parentElement!.parentElement!.parentElement!, undefined, { clickCount: 2 });
await user.dblClick(child.parentElement!.parentElement!.parentElement!);
expect((await screen.findAllByText(new RegExp(`${childType} block 0`, 'i')))[0]).toBeInTheDocument();
expect(await screen.findByRole('button', { name: new RegExp(`${childType} Info`, 'i') })).toBeInTheDocument();
});
it(`${cType} sidebar should render "new ${childType}" and "existing ${childType}" buttons`, async () => {
const user = userEvent.setup();
renderLibrarySectionPage(undefined, undefined, cType);
const addChild = await screen.findByRole('button', { name: new RegExp(`add ${childType}`, 'i') });
userEvent.click(addChild);
await user.click(addChild);
const addNew = await screen.findByRole('button', { name: new RegExp(`^new ${childType}$`, 'i') });
const addExisting = await screen.findByRole('button', { name: new RegExp(`^existing ${childType}$`, 'i') });
// Clicking "add new" shows create container modal (tested below)
userEvent.click(addNew);
await user.click(addNew);
expect(await screen.findByLabelText(new RegExp(`name your ${childType}`, 'i'))).toBeInTheDocument();
fireEvent.click(screen.getByRole('button', { name: /cancel/i }));
// Clicking "add existing" shows content picker modal
userEvent.click(addExisting);
await user.click(addExisting);
expect(await screen.findByRole('dialog')).toBeInTheDocument();
expect(await screen.findByRole('button', { name: new RegExp(`add to ${cType}`, 'i') })).toBeInTheDocument();
// No "Types" filter shown
@@ -412,6 +414,7 @@ describe('<LibrarySectionPage / LibrarySubsectionPage />', () => {
});
it(`"add new" button should add ${childType} to the ${cType}`, async () => {
const user = userEvent.setup();
const { libraryId } = mockContentLibrary;
const containerId = cType === ContainerType.Section
? mockGetContainerMetadata.sectionId
@@ -429,7 +432,7 @@ describe('<LibrarySectionPage / LibrarySubsectionPage />', () => {
renderLibrarySectionPage(containerId, libraryId, cType);
const addChild = await screen.findByRole('button', { name: new RegExp(`add new ${childType}`, 'i') });
userEvent.click(addChild);
await user.click(addChild);
const textBox = await screen.findByLabelText(new RegExp(`name your ${childType}`, 'i'));
fireEvent.change(textBox, { target: { value: `New ${childType} Title` } });
fireEvent.click(screen.getByRole('button', { name: /create/i }));
@@ -448,6 +451,7 @@ describe('<LibrarySectionPage / LibrarySubsectionPage />', () => {
});
it(`"add new" button should show error when adding ${childType} to the ${cType}`, async () => {
const user = userEvent.setup();
const { libraryId } = mockContentLibrary;
const containerId = cType === ContainerType.Section
? mockGetContainerMetadata.sectionId
@@ -465,7 +469,7 @@ describe('<LibrarySectionPage / LibrarySubsectionPage />', () => {
renderLibrarySectionPage(containerId, libraryId, cType);
const addChild = await screen.findByRole('button', { name: new RegExp(`add new ${childType}`, 'i') });
userEvent.click(addChild);
await user.click(addChild);
const textBox = await screen.findByLabelText(new RegExp(`name your ${childType}`, 'i'));
fireEvent.change(textBox, { target: { value: `New ${childType} Title` } });
fireEvent.click(screen.getByRole('button', { name: /create/i }));
@@ -483,12 +487,13 @@ describe('<LibrarySectionPage / LibrarySubsectionPage />', () => {
});
it(`"add existing ${childType}" button should load ${cType} content picker modal`, async () => {
const user = userEvent.setup();
renderLibrarySectionPage(undefined, undefined, cType);
expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
const addChild = await screen.findByRole('button', { name: new RegExp(`add existing ${childType}`, 'i') });
userEvent.click(addChild);
await user.click(addChild);
// Content picker loaded (modal behavior is tested elsewhere)
expect(await screen.findByRole('dialog')).toBeInTheDocument();

View File

@@ -191,6 +191,7 @@ describe('<LibraryUnitPage />', () => {
});
it('should open and close the unit sidebar', async () => {
const user = userEvent.setup();
renderLibraryUnitPage();
// sidebar should be visible by default
@@ -202,15 +203,16 @@ describe('<LibraryUnitPage />', () => {
expect(await findByText('Test Unit')).toBeInTheDocument();
// should close if open
userEvent.click(await screen.findByText('Unit Info'));
await user.click(await screen.findByText('Unit Info'));
await waitFor(() => expect(screen.queryByTestId('library-sidebar')).not.toBeInTheDocument());
// Open again
userEvent.click(await screen.findByText('Unit Info'));
await user.click(await screen.findByText('Unit Info'));
expect(await screen.findByTestId('library-sidebar')).toBeInTheDocument();
});
it('should open and close component sidebar on component selection', async () => {
const user = userEvent.setup();
renderLibraryUnitPage();
expect((await screen.findAllByText('Test Unit'))).toHaveLength(2); // Header + Sidebar
// No Preview tab shown in sidebar
@@ -218,7 +220,7 @@ describe('<LibraryUnitPage />', () => {
const component = await screen.findByText('text block 0');
// Card is 3 levels up the component name div
userEvent.click(component.parentElement!.parentElement!.parentElement!);
await user.click(component.parentElement!.parentElement!.parentElement!);
const sidebar = await screen.findByTestId('library-sidebar');
const { findByRole, findByText } = within(sidebar);
@@ -229,7 +231,7 @@ describe('<LibraryUnitPage />', () => {
expect(screen.queryByText('Preview')).not.toBeInTheDocument();
const closeButton = await findByRole('button', { name: /close/i });
userEvent.click(closeButton);
await user.click(closeButton);
await waitFor(() => expect(screen.queryByTestId('library-sidebar')).not.toBeInTheDocument());
});
@@ -432,12 +434,13 @@ describe('<LibraryUnitPage />', () => {
});
it('should remove a component from component sidebar', async () => {
const user = userEvent.setup();
const url = getLibraryContainerChildrenApiUrl(mockGetContainerMetadata.unitId);
axiosMock.onDelete(url).reply(200);
renderLibraryUnitPage();
const component = await screen.findByText('text block 0');
userEvent.click(component.parentElement!.parentElement!.parentElement!);
await user.click(component.parentElement!.parentElement!.parentElement!);
const sidebar = await screen.findByTestId('library-sidebar');
const { findByRole, findByText } = within(sidebar);
@@ -455,17 +458,19 @@ describe('<LibraryUnitPage />', () => {
});
it('should show editor on double click', async () => {
const user = userEvent.setup();
renderLibraryUnitPage();
const component = await screen.findByText('text block 0');
// trigger double click
userEvent.click(component.parentElement!.parentElement!.parentElement!, undefined, { clickCount: 2 });
expect(await screen.findByRole('dialog', { name: 'Editor Dialog' })).toBeInTheDocument();
await user.dblClick(component.parentElement!.parentElement!.parentElement!);
const dialog = screen.getByRole('dialog', { name: 'Editor Dialog' });
expect(dialog).toBeInTheDocument();
});
it('"Add New Content" button should open "Add Content" sidebar', async () => {
const user = userEvent.setup();
renderLibraryUnitPage();
const addContent = await screen.findByRole('button', { name: /add new content/i });
userEvent.click(addContent);
await user.click(addContent);
expect(await screen.findByRole('button', { name: /existing library content/i })).toBeInTheDocument();
expect(await screen.findByRole('button', { name: /text/i })).toBeInTheDocument();

View File

@@ -71,7 +71,7 @@ describe('SettingsComponent', () => {
return <div data-testid="location-display">{location.pathname}</div>;
};
const user = userEvent.setup();
render(
<>
<SettingsComponent url="/some-url" />
@@ -85,7 +85,7 @@ describe('SettingsComponent', () => {
expect(firstLocation).toHaveTextContent('/');
const cancelButton = await screen.findByText('Cancel');
await userEvent.click(cancelButton);
await user.click(cancelButton);
const secondLocation = await screen.findByTestId('location-display');
expect(secondLocation).toHaveTextContent('/some-url');
});

View File

@@ -71,7 +71,9 @@ function renderComponent(route) {
}
describe('DiscussionsSettings', () => {
let user;
beforeEach(() => {
user = userEvent.setup();
initializeMockApp({
authenticatedUser: {
userId: 3,
@@ -127,10 +129,8 @@ describe('DiscussionsSettings', () => {
// content has been loaded - prior to proceeding with our expectations.
await waitForElementToBeRemoved(screen.queryByRole('status'));
await waitFor(() => {
userEvent.click(queryByLabelText(container, 'Select Piazza'));
userEvent.click(queryByText(container, messages.nextButton.defaultMessage));
});
await user.click(queryByLabelText(container, 'Select Piazza'));
await user.click(queryByText(container, messages.nextButton.defaultMessage));
expect(queryByTestId(container, 'appList')).not.toBeInTheDocument();
expect(queryByTestId(container, 'appConfigForm')).toBeInTheDocument();
@@ -147,10 +147,8 @@ describe('DiscussionsSettings', () => {
// content has been loaded - prior to proceeding with our expectations.
await waitForElementToBeRemoved(screen.queryByRole('status'));
await waitFor(() => {
userEvent.click(queryByLabelText(container, 'Select edX'));
userEvent.click(queryByText(container, messages.nextButton.defaultMessage));
});
await user.click(queryByLabelText(container, 'Select edX'));
await user.click(queryByText(container, messages.nextButton.defaultMessage));
expect(queryByTestId(container, 'appList')).not.toBeInTheDocument();
expect(queryByTestId(container, 'appConfigForm')).toBeInTheDocument();
@@ -166,7 +164,7 @@ describe('DiscussionsSettings', () => {
expect(queryByTestId(container, 'appConfigForm')).toBeInTheDocument();
await waitFor(() => userEvent.click(queryByText(container, appMessages.backButton.defaultMessage)));
await waitFor(() => user.click(queryByText(container, appMessages.backButton.defaultMessage)));
await waitFor(() => {
expect(queryByTestId(container, 'appList')).toBeInTheDocument();
@@ -182,7 +180,7 @@ describe('DiscussionsSettings', () => {
expect(queryByTestId(container, 'appList')).toBeInTheDocument();
userEvent.click(queryByLabelText(container, 'Close'));
await user.click(queryByLabelText(container, 'Close'));
expect(queryByTestId(container, 'appList')).not.toBeInTheDocument();
expect(queryByTestId(container, 'appConfigForm')).not.toBeInTheDocument();
@@ -196,10 +194,10 @@ describe('DiscussionsSettings', () => {
// content has been loaded - prior to proceeding with our expectations.
await waitForElementToBeRemoved(screen.queryByRole('status'));
userEvent.click(screen.getByLabelText('Select Piazza'));
await user.click(screen.getByLabelText('Select Piazza'));
// Have to use fireEvent.click with these Stepper buttons so that the
// onClick handler is triggered. (userEvent.click doesn't trigger onClick).
// onClick handler is triggered. (await user.click doesn't trigger onClick).
await act(async () => {
fireEvent.click(getByRole(container, 'button', { name: 'Next' }));
});
@@ -226,14 +224,14 @@ describe('DiscussionsSettings', () => {
// content has been loaded - prior to proceeding with our expectations.
await waitForElementToBeRemoved(screen.queryByRole('status'));
userEvent.click(getByRole(container, 'checkbox', { name: 'Select Discourse' }));
userEvent.click(getByRole(container, 'button', { name: 'Next' }));
await user.click(getByRole(container, 'checkbox', { name: 'Select Discourse' }));
await user.click(getByRole(container, 'button', { name: 'Next' }));
await findByRole(container, 'button', { name: 'Save' });
userEvent.type(getByRole(container, 'textbox', { name: 'Consumer Key' }), 'key');
userEvent.type(getByRole(container, 'textbox', { name: 'Consumer Secret' }), 'secret');
userEvent.type(getByRole(container, 'textbox', { name: 'Launch URL' }), 'http://example.test');
userEvent.click(getByRole(container, 'button', { name: 'Save' }));
await user.type(getByRole(container, 'textbox', { name: 'Consumer Key' }), 'key');
await user.type(getByRole(container, 'textbox', { name: 'Consumer Secret' }), 'secret');
await user.type(getByRole(container, 'textbox', { name: 'Launch URL' }), 'http://example.test');
await user.click(getByRole(container, 'button', { name: 'Save' }));
await waitFor(() => expect(queryByRole(container, 'dialog', { name: 'OK' })).toBeInTheDocument());
});
@@ -249,21 +247,21 @@ describe('DiscussionsSettings', () => {
const discourseBox = getByRole(container, 'checkbox', { name: 'Select Discourse' });
expect(discourseBox).not.toBeDisabled();
userEvent.click(discourseBox);
await user.click(discourseBox);
userEvent.click(getByRole(container, 'button', { name: 'Next' }));
await user.click(getByRole(container, 'button', { name: 'Next' }));
await waitFor(() => expect(screen.queryByRole('status')).toBeNull());
expect(await findByRole(container, 'heading', { name: 'Discourse' })).toBeInTheDocument();
userEvent.type(getByRole(container, 'textbox', { name: 'Consumer Key' }), 'a');
userEvent.type(getByRole(container, 'textbox', { name: 'Consumer Secret' }), 'secret');
userEvent.type(getByRole(container, 'textbox', { name: 'Launch URL' }), 'http://example.test');
userEvent.click(getByRole(container, 'button', { name: 'Save' }));
await user.type(getByRole(container, 'textbox', { name: 'Consumer Key' }), 'a');
await user.type(getByRole(container, 'textbox', { name: 'Consumer Secret' }), 'secret');
await user.type(getByRole(container, 'textbox', { name: 'Launch URL' }), 'http://example.test');
await user.click(getByRole(container, 'button', { name: 'Save' }));
await waitFor(() => expect(getByRole(container, 'dialog', { name: 'OK' })).toBeInTheDocument());
userEvent.click(getByRole(container, 'button', { name: 'Cancel' }));
await user.click(getByRole(container, 'button', { name: 'Cancel' }));
expect(queryByRole(container, 'dialog', { name: 'Confirm' })).not.toBeInTheDocument();
expect(queryByRole(container, 'dialog', { name: 'Configure discussion' }));
@@ -317,7 +315,7 @@ describe('DiscussionsSettings', () => {
await waitForElementToBeRemoved(screen.queryByRole('status'));
// Apply causes an async action to take place
userEvent.click(queryByText(container, appMessages.saveButton.defaultMessage));
await user.click(queryByText(container, appMessages.saveButton.defaultMessage));
await waitFor(() => expect(axiosMock.history.post.length).toBe(1));
expect(queryByTestId(container, 'appConfigForm')).toBeInTheDocument();
@@ -360,7 +358,7 @@ describe('DiscussionsSettings', () => {
// content has been loaded - prior to proceeding with our expectations.
await waitForElementToBeRemoved(screen.queryByRole('status'));
userEvent.click(getByRole(container, 'button', { name: 'Save' }));
await user.click(getByRole(container, 'button', { name: 'Save' }));
await waitFor(() => expect(axiosMock.history.post.length).toBe(1));
@@ -412,7 +410,7 @@ describe.each([
test(`successfully advances to settings step for lti when adminOnlyConfig=${isAdminOnlyConfig} and user ${isAdmin ? 'is' : 'is not'} admin `, async () => {
const showLTIConfig = isAdmin;
const user = userEvent.setup();
renderComponent(`/course/${courseId}/pages-and-resources/discussion`);
let spinner = await screen.findByRole('status');
@@ -420,11 +418,11 @@ describe.each([
expect(spinner).not.toBeInTheDocument();
});
await userEvent.click(screen.getByLabelText('Select Piazza'));
await userEvent.click(queryByText(container, messages.nextButton.defaultMessage));
await user.click(screen.getByLabelText('Select Piazza'));
await user.click(queryByText(container, messages.nextButton.defaultMessage));
spinner = await screen.findByRole('status');
await waitFor(() => {
spinner = screen.queryByRole('status');
expect(spinner).not.toBeInTheDocument();
});
@@ -473,6 +471,7 @@ describe.each([
test(`${piiSharingAllowed ? 'shows PII share username/email field when piiSharingAllowed is true'
: 'hides PII share username/email field when piiSharingAllowed is false'}`, async () => {
const user = userEvent.setup();
renderComponent(`/course/${courseId}/pages-and-resources/discussion`);
let spinner = await screen.findByRole('status');
@@ -480,11 +479,11 @@ describe.each([
expect(spinner).not.toBeInTheDocument();
});
await userEvent.click(screen.getByLabelText('Select Piazza'));
await userEvent.click(screen.getByText(messages.nextButton.defaultMessage));
await user.click(screen.getByLabelText('Select Piazza'));
await user.click(screen.getByText(messages.nextButton.defaultMessage));
spinner = await screen.findByRole('status');
await waitFor(() => {
spinner = screen.queryByRole('status');
expect(spinner).not.toBeInTheDocument();
});

View File

@@ -57,8 +57,10 @@ describe('OpenedXConfigForm', () => {
let axiosMock;
let store;
let container;
let user;
beforeEach(async () => {
user = userEvent.setup();
initializeMockApp({
authenticatedUser: {
userId: 3,
@@ -240,7 +242,7 @@ describe('OpenedXConfigForm', () => {
const updateTopicName = async (topicId, topicName) => {
const topicCard = queryByTestId(container, topicId);
await act(async () => { userEvent.click(queryByLabelText(topicCard, 'Expand')); });
await act(async () => { await user.click(queryByLabelText(topicCard, 'Expand')); });
const topicInput = topicCard.querySelector('input');
topicInput.focus();
await act(async () => { fireEvent.change(topicInput, { target: { value: topicName } }); });
@@ -282,7 +284,7 @@ describe('OpenedXConfigForm', () => {
const topicCard = await updateTopicName('13f106c6-6735-4e84-b097-0456cff55960', '');
const collapseButton = queryByLabelText(topicCard, 'Collapse');
await act(async () => userEvent.click(collapseButton));
await act(async () => user.click(collapseButton));
expect(collapseButton).toBeInTheDocument();
});
@@ -308,7 +310,7 @@ describe('OpenedXConfigForm', () => {
test('check duplicate error is removed on fields when name is fixed', async () => {
const duplicateTopicInput = duplicateTopicCard.querySelector('input');
duplicateTopicInput.focus();
await act(async () => { userEvent.type(duplicateTopicInput, 'valid'); });
await act(async () => { await user.type(duplicateTopicInput, 'valid'); });
duplicateTopicInput.blur();
await waitForElementToBeRemoved(
@@ -321,10 +323,10 @@ describe('OpenedXConfigForm', () => {
});
test('check duplicate error is removed on deleting duplicate topic', async () => {
await userEvent.click(
await await user.click(
await findByLabelText(duplicateTopicCard, messages.deleteAltText.defaultMessage, { selector: 'button' }),
);
await userEvent.click(
await await user.click(
await findByRole(container, 'button', { name: messages.deleteButton.defaultMessage }),
);
await waitForElementToBeRemoved(queryByText(topicCard, messages.discussionTopicNameAlreadyExist.defaultMessage));

View File

@@ -131,15 +131,16 @@ describe('DiscussionTopics', () => {
});
test('updates discussion topic name', async () => {
const user = userEvent.setup();
await mockStore(legacyApiResponse);
createComponent(appConfig);
const topicCard = queryByTestId(container, '13f106c6-6735-4e84-b097-0456cff55960');
await act(async () => userEvent.click(queryByLabelText(topicCard, 'Expand')));
await act(async () => user.click(queryByLabelText(topicCard, 'Expand')));
await act(async () => {
fireEvent.change(topicCard.querySelector('input'), { target: { value: 'new name' } });
});
await act(async () => userEvent.click(queryByLabelText(topicCard, 'Collapse')));
await act(async () => user.click(queryByLabelText(topicCard, 'Collapse')));
expect(queryByText(topicCard, 'new name')).toBeInTheDocument();
});

View File

@@ -115,11 +115,12 @@ describe('TopicItem', () => {
});
test('displays expand view of general discussion topic', async () => {
const user = userEvent.setup();
await mockStore(legacyApiResponse);
createComponent(generalTopic);
const generalTopicNode = queryByTestId(container, 'course');
userEvent.click(queryByLabelText(generalTopicNode, 'Expand'));
await user.click(queryByLabelText(generalTopicNode, 'Expand'));
expect(queryByLabelText(generalTopicNode, 'Expand')).not.toBeInTheDocument();
expect(queryByLabelText(generalTopicNode, 'Collapse')).toBeInTheDocument();
@@ -128,11 +129,12 @@ describe('TopicItem', () => {
});
test('displays expand view of additional discussion topic', async () => {
const user = userEvent.setup();
await mockStore(legacyApiResponse);
createComponent(additionalTopic);
const topicCard = queryByTestId(container, '13f106c6-6735-4e84-b097-0456cff55960');
userEvent.click(queryByLabelText(topicCard, 'Expand'));
await user.click(queryByLabelText(topicCard, 'Expand'));
expect(queryByLabelText(topicCard, 'Expand')).not.toBeInTheDocument();
expect(queryByLabelText(topicCard, 'Collapse')).toBeInTheDocument();
@@ -141,12 +143,13 @@ describe('TopicItem', () => {
});
test('renders delete topic popup with providerName, label, helping text, a delete and a cancel button', async () => {
const user = userEvent.setup();
await mockStore(legacyApiResponse);
createComponent(additionalTopic);
const topicCard = queryByTestId(container, '13f106c6-6735-4e84-b097-0456cff55960');
userEvent.click(queryByLabelText(topicCard, 'Expand'));
userEvent.click(queryByRole(topicCard, 'button', { name: 'Delete Topic' }));
await user.click(queryByLabelText(topicCard, 'Expand'));
await user.click(queryByRole(topicCard, 'button', { name: 'Delete Topic' }));
expect(queryAllByText(container, messages.discussionTopicDeletionLabel.defaultMessage)).toHaveLength(1);
expect(queryByText(container, messages.discussionTopicDeletionLabel.defaultMessage)).toBeInTheDocument();
@@ -157,11 +160,12 @@ describe('TopicItem', () => {
});
test('shows help text on field focus', async () => {
const user = userEvent.setup();
await mockStore(legacyApiResponse);
createComponent(additionalTopic);
const topicCard = await findByTestId(container, '13f106c6-6735-4e84-b097-0456cff55960');
userEvent.click(queryByLabelText(topicCard, 'Expand'));
await user.click(queryByLabelText(topicCard, 'Expand'));
topicCard.querySelector('input').focus();
await findByText(topicCard, messages.addTopicHelpText.defaultMessage);

View File

@@ -143,13 +143,12 @@ describe('AppList', () => {
});
test('selectApp is called when an app is clicked', async () => {
const user = userEvent.setup();
renderComponent();
await waitFor(() => {
userEvent.click(screen.getByLabelText('Select Piazza'));
const clickedCard = screen.getByRole('radio', { checked: true });
expect(within(clickedCard).queryByLabelText('Select Piazza')).toBeInTheDocument();
});
await user.click(await screen.findByLabelText('Select Piazza'));
const clickedCard = screen.getByRole('radio', { checked: true });
expect(within(clickedCard).queryByLabelText('Select Piazza')).toBeInTheDocument();
});
});

View File

@@ -15,8 +15,9 @@ describe('FeaturesList', () => {
id: 'legacy',
};
let container;
let user;
beforeEach(() => {
user = userEvent.setup();
const wrapper = render(
<IntlProvider locale="en">
<FeaturesList
@@ -31,24 +32,24 @@ describe('FeaturesList', () => {
expect(queryByText(container, messages['supportedFeatureList-mobile-show'].defaultMessage)).toBeInTheDocument();
});
test('displays hide available feature message on expand', () => {
test('displays hide available feature message on expand', async () => {
const button = getByRole(container, 'button');
userEvent.click(button);
await user.click(button);
expect(queryByText(container, messages['supportedFeatureList-mobile-hide'].defaultMessage)).toBeInTheDocument();
});
test('displays a row for each available feature', () => {
test('displays a row for each available feature', async () => {
const button = getByRole(container, 'button');
userEvent.click(button);
await user.click(button);
app.featureIds.forEach((id) => {
const featureNodes = queryAllByText(container, messages[`featureName-${id}`].defaultMessage);
expect(featureNodes.map(node => node.closest('div'))).toHaveLength(1);
});
});
test('A check icon is shown with each supported feature', () => {
test('A check icon is shown with each supported feature', async () => {
const button = getByRole(container, 'button');
userEvent.click(button);
await user.click(button);
app.featureIds.forEach((id) => {
const featureElement = queryByText(container, messages[`featureName-${id}`].defaultMessage);
expect(featureElement.querySelector('svg')).toHaveAttribute('id', 'check-icon');

View File

@@ -119,11 +119,12 @@ describe('CoursesFilters', () => {
}));
});
it('should handle search input submission', () => {
it('should handle search input submission', async () => {
const user = userEvent.setup();
const handleSubmit = jest.fn();
renderComponent({ onSubmitSearchField: handleSubmit });
const searchInput = screen.getByRole('searchbox');
userEvent.type(searchInput, 'testing{enter}');
await user.type(searchInput, 'testing{enter}');
expect(handleSubmit).toHaveBeenCalled();
});

View File

@@ -63,15 +63,16 @@ describe('<TaxonomyLayout />', () => {
});
it('should show alert', async () => {
const user = userEvent.setup();
render(<TaxonomyLayout />);
const button = await screen.findByTestId('taxonomy-show-alert');
await userEvent.click(button);
await user.click(button);
expect(screen.getByText(alertErrorTitle)).toBeInTheDocument();
expect(screen.getByText(alertErrorDescription)).toBeInTheDocument();
const closeAlertButton = await screen.findByRole('button', { name: 'Dismiss' });
await userEvent.click(closeAlertButton);
await user.click(closeAlertButton);
expect(screen.queryByText(alertErrorTitle)).not.toBeInTheDocument();
expect(screen.queryByText(alertErrorDescription)).not.toBeInTheDocument();
});

View File

@@ -45,11 +45,12 @@ describe('<Textbooks />', () => {
});
it('renders textbooks form when "New textbooks" button is clicked', async () => {
const user = userEvent.setup();
const { getByTestId, getByRole } = renderComponent();
await waitFor(() => {
await waitFor(async () => {
const newTextbookButton = getByRole('button', { name: messages.newTextbookButton.defaultMessage });
userEvent.click(newTextbookButton);
await user.click(newTextbookButton);
expect(getByTestId('textbook-form')).toBeInTheDocument();
});
});

View File

@@ -21,11 +21,12 @@ describe('<EmptyPlaceholder />', () => {
expect(getByRole('button', { name: messages.button.defaultMessage })).toBeInTheDocument();
});
it('calls the onCreateNewTextbook function when the button is clicked', () => {
it('calls the onCreateNewTextbook function when the button is clicked', async () => {
const user = userEvent.setup();
const { getByRole } = renderComponent();
const addButton = getByRole('button', { name: messages.button.defaultMessage });
userEvent.click(addButton);
await user.click(addButton);
expect(onCreateNewTextbookMock).toHaveBeenCalledTimes(1);
});
});

View File

@@ -40,7 +40,9 @@ const renderComponent = () => render(
);
describe('<TextbookCard />', () => {
let user;
beforeEach(async () => {
user = userEvent.setup();
initializeMockApp({
authenticatedUser: {
userId: 3,
@@ -54,7 +56,7 @@ describe('<TextbookCard />', () => {
axiosMock = new MockAdapter(getAuthenticatedHttpClient());
});
it('render TextbookCard component correctly', () => {
it('render TextbookCard component correctly', async () => {
const { getByText, getByTestId } = renderComponent();
expect(getByText(textbook.tabTitle)).toBeInTheDocument();
@@ -64,7 +66,7 @@ describe('<TextbookCard />', () => {
expect(getByText('1 PDF chapters')).toBeInTheDocument();
const collapseButton = document.querySelector('.collapsible-trigger');
userEvent.click(collapseButton);
await user.click(collapseButton);
textbook.chapters.forEach(({ title, url }) => {
expect(getByText(title)).toBeInTheDocument();
@@ -72,27 +74,27 @@ describe('<TextbookCard />', () => {
});
});
it('renders edit TextbookForm after clicking on edit button', () => {
it('renders edit TextbookForm after clicking on edit button', async () => {
const { getByTestId, queryByTestId } = renderComponent();
const editButton = getByTestId('textbook-edit-button');
userEvent.click(editButton);
await user.click(editButton);
expect(getByTestId('textbook-form')).toBeInTheDocument();
expect(queryByTestId('textbook-card')).not.toBeInTheDocument();
});
it('closes edit TextbookForm after clicking on cancel button', () => {
it('closes edit TextbookForm after clicking on cancel button', async () => {
const { getByTestId, queryByTestId } = renderComponent();
const editButton = getByTestId('textbook-edit-button');
userEvent.click(editButton);
await user.click(editButton);
expect(getByTestId('textbook-form')).toBeInTheDocument();
expect(queryByTestId('textbook-card')).not.toBeInTheDocument();
const cancelButton = getByTestId('cancel-button');
userEvent.click(cancelButton);
await user.click(cancelButton);
expect(queryByTestId('textbook-form')).not.toBeInTheDocument();
expect(getByTestId('textbook-card')).toBeInTheDocument();
@@ -102,7 +104,7 @@ describe('<TextbookCard />', () => {
const { getByPlaceholderText, getByRole, getByTestId } = renderComponent();
const editButton = getByTestId('textbook-edit-button');
userEvent.click(editButton);
await user.click(editButton);
const tabTitleInput = getByPlaceholderText(messages.tabTitlePlaceholder.defaultMessage);
const chapterInput = getByPlaceholderText(
@@ -121,14 +123,14 @@ describe('<TextbookCard />', () => {
id: textbooksMock.textbooks[1].id,
};
userEvent.clear(tabTitleInput);
userEvent.type(tabTitleInput, newFormValues.tab_title);
userEvent.clear(chapterInput);
userEvent.type(chapterInput, newFormValues.chapters[0].title);
userEvent.clear(urlInput);
userEvent.type(urlInput, newFormValues.chapters[0].url);
await user.clear(tabTitleInput);
await user.type(tabTitleInput, newFormValues.tab_title);
await user.clear(chapterInput);
await user.type(chapterInput, newFormValues.chapters[0].title);
await user.clear(urlInput);
await user.type(urlInput, newFormValues.chapters[0].url);
userEvent.click(getByRole('button', { name: messages.saveButton.defaultMessage }));
await user.click(getByRole('button', { name: messages.saveButton.defaultMessage }));
await waitFor(() => {
expect(onEditSubmitMock).toHaveBeenCalledTimes(1);
@@ -149,7 +151,7 @@ describe('<TextbookCard />', () => {
const { getByTestId, getByRole } = renderComponent();
const deleteButton = getByTestId('textbook-delete-button');
userEvent.click(deleteButton);
await user.click(deleteButton);
await waitFor(() => {
const deleteModal = getByRole('dialog');
@@ -169,15 +171,15 @@ describe('<TextbookCard />', () => {
const { getByTestId, getByRole } = renderComponent();
const deleteButton = getByTestId('textbook-delete-button');
userEvent.click(deleteButton);
await user.click(deleteButton);
await waitFor(() => {
await waitFor(async () => {
const deleteModal = getByRole('dialog');
const modalSubmitButton = within(deleteModal)
.getByRole('button', { name: 'Delete' });
userEvent.click(modalSubmitButton);
await user.click(modalSubmitButton);
const textbookId = textbooksMock.textbooks[1].id;

View File

@@ -84,6 +84,7 @@ describe('<TextbookForm />', () => {
});
it('calls onSubmit when the "Save" button is clicked with a valid form', async () => {
const user = userEvent.setup();
const { getByPlaceholderText, getByRole } = renderComponent();
const tabTitleInput = getByPlaceholderText(messages.tabTitlePlaceholder.defaultMessage);
@@ -102,11 +103,11 @@ describe('<TextbookForm />', () => {
],
};
userEvent.type(tabTitleInput, formValues.tab_title);
userEvent.type(chapterInput, formValues.chapters[0].title);
userEvent.type(urlInput, formValues.chapters[0].url);
await user.type(tabTitleInput, formValues.tab_title);
await user.type(chapterInput, formValues.chapters[0].title);
await user.type(urlInput, formValues.chapters[0].url);
userEvent.click(getByRole('button', { name: messages.saveButton.defaultMessage }));
await user.click(getByRole('button', { name: messages.saveButton.defaultMessage }));
await waitFor(() => {
expect(onSubmitMock).toHaveBeenCalledTimes(1);
@@ -133,12 +134,13 @@ describe('<TextbookForm />', () => {
});
it('"Save" button is disabled when the chapters length less than 1', async () => {
const user = userEvent.setup();
const { getByRole, getByTestId } = renderComponent();
const deleteChapterButton = getByTestId('chapter-delete-button');
const saveButton = getByRole('button', { name: messages.saveButton.defaultMessage });
userEvent.click(deleteChapterButton);
await user.click(deleteChapterButton);
await waitFor(() => {
expect(saveButton).toBeDisabled();
@@ -155,11 +157,12 @@ describe('<TextbookForm />', () => {
});
it('"Add a chapter" button add new chapters field', async () => {
const user = userEvent.setup();
const { getByRole, getAllByTestId } = renderComponent();
const addChapterButton = getByRole('button', { name: messages.addChapterButton.defaultMessage });
userEvent.click(addChapterButton);
await user.click(addChapterButton);
await waitFor(() => {
expect(getAllByTestId('form-chapters-fields')).toHaveLength(2);
@@ -167,14 +170,15 @@ describe('<TextbookForm />', () => {
});
it('open modal dropzone when "Upload" button is clicked', async () => {
const user = userEvent.setup();
const { findByTestId, findByRole } = renderComponent();
const button = await findByTestId('chapter-upload-button');
await userEvent.click(button);
await await user.click(button);
const modalBackdrop = await findByTestId('modal-backdrop');
const cancelButton = await within(await findByRole('dialog')).findByText('Cancel');
await userEvent.click(cancelButton);
await await user.click(cancelButton);
await waitFor(() => {
expect(modalBackdrop).not.toBeInTheDocument();
});