From cae7b1bba04c0d564b60e01cd3380339ec96b5c4 Mon Sep 17 00:00:00 2001 From: Diana Villalvazo Date: Tue, 24 Jun 2025 11:50:11 -0500 Subject: [PATCH] test: Deprecate react-unit-test-utils 9/15 (#668) --- .../__snapshots__/index.test.jsx.snap | 72 ------ .../ConfirmEmailBanner/index.test.jsx | 53 ++++- .../__snapshots__/index.test.jsx.snap | 61 ----- .../LearnerDashboardHeader/index.test.jsx | 68 ++++-- .../__snapshots__/index.test.jsx.snap | 220 ------------------ src/containers/MasqueradeBar/index.test.jsx | 60 +++-- .../__snapshots__/index.test.jsx.snap | 169 -------------- .../components/ProgramCard.test.jsx | 46 +++- .../__snapshots__/ProgramCard.test.jsx.snap | 60 ----- .../RelatedProgramsModal/index.test.jsx | 42 ++-- 10 files changed, 193 insertions(+), 658 deletions(-) delete mode 100644 src/containers/LearnerDashboardHeader/ConfirmEmailBanner/__snapshots__/index.test.jsx.snap delete mode 100644 src/containers/LearnerDashboardHeader/__snapshots__/index.test.jsx.snap delete mode 100644 src/containers/MasqueradeBar/__snapshots__/index.test.jsx.snap delete mode 100644 src/containers/RelatedProgramsModal/__snapshots__/index.test.jsx.snap delete mode 100644 src/containers/RelatedProgramsModal/components/__snapshots__/ProgramCard.test.jsx.snap diff --git a/src/containers/LearnerDashboardHeader/ConfirmEmailBanner/__snapshots__/index.test.jsx.snap b/src/containers/LearnerDashboardHeader/ConfirmEmailBanner/__snapshots__/index.test.jsx.snap deleted file mode 100644 index 9cff65a..0000000 --- a/src/containers/LearnerDashboardHeader/ConfirmEmailBanner/__snapshots__/index.test.jsx.snap +++ /dev/null @@ -1,72 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`ConfirmEmailBanner snapshot Show on unverified 1`] = ` - - - - Confirm Now - , - } - } - /> - - - I've confirmed my email - - } - hasCloseButton={false} - heroNode={ - - confirm email background - - } - isOpen={[MockFunction showConfirmModal]} - onClose={[MockFunction closeConfirmModal]} - title="" - > -

- Confirm your email -

-

- We've sent you an email to verify your account. Please check your inbox and click on the big red button to confirm and keep learning. -

-
-
-`; - -exports[`ConfirmEmailBanner snapshot do not show on already verified 1`] = `null`; diff --git a/src/containers/LearnerDashboardHeader/ConfirmEmailBanner/index.test.jsx b/src/containers/LearnerDashboardHeader/ConfirmEmailBanner/index.test.jsx index 958484c..e029666 100644 --- a/src/containers/LearnerDashboardHeader/ConfirmEmailBanner/index.test.jsx +++ b/src/containers/LearnerDashboardHeader/ConfirmEmailBanner/index.test.jsx @@ -1,14 +1,19 @@ -import React from 'react'; -import { shallow } from '@edx/react-unit-test-utils'; +import { render, screen } from '@testing-library/react'; +import { IntlProvider } from '@edx/frontend-platform/i18n'; import hooks from './hooks'; import ConfirmEmailBanner from '.'; +import messages from './messages'; jest.mock('./hooks', () => ({ __esModule: true, default: jest.fn(), })); +jest.unmock('@openedx/paragon'); +jest.unmock('@edx/frontend-platform/i18n'); +jest.unmock('react'); + const hookProps = { isNeeded: true, showPageBanner: jest.fn().mockName('showPageBanner'), @@ -20,16 +25,44 @@ const hookProps = { }; describe('ConfirmEmailBanner', () => { - describe('snapshot', () => { - test('do not show on already verified', () => { + describe('render', () => { + it('do not show on already verified', () => { hooks.mockReturnValueOnce({ ...hookProps, isNeeded: false }); - const el = shallow(); - expect(el.snapshot).toMatchSnapshot(); + render(); + const banner = screen.queryByRole('alert'); + expect(banner).toBeNull(); }); - test('Show on unverified', () => { - hooks.mockReturnValueOnce({ ...hookProps }); - const el = shallow(); - expect(el.snapshot).toMatchSnapshot(); + describe('On unverified', () => { + beforeEach(() => { + hooks.mockReturnValueOnce({ ...hookProps }); + render(); + }); + it('show banner', () => { + const banner = screen.getByRole('alert'); + expect(banner).toContainHTML('Remember to confirm'); + }); + it('show confirm now button', () => { + const confirmButton = screen.getByRole('button', { name: messages.confirmNowButton.defaultMessage }); + expect(confirmButton).toBeInTheDocument(); + }); + it('show modal', () => { + const modal = screen.getByRole('dialog'); + expect(modal).toBeInTheDocument(); + }); + it('show modal header and body', () => { + const modalHeader = screen.getByText(messages.confirmEmailModalHeader.defaultMessage); + expect(modalHeader).toBeInTheDocument(); + const modalBody = screen.getByText(messages.confirmEmailModalBody.defaultMessage); + expect(modalBody).toBeInTheDocument(); + }); + it('show confirm image', () => { + const confirmButton = screen.getByRole('img', { name: messages.confirmEmailImageAlt.defaultMessage }); + expect(confirmButton).toBeInTheDocument(); + }); + it('show confirm email button', () => { + const confirmButton = screen.getByRole('button', { name: messages.verifiedConfirmEmailButton.defaultMessage }); + expect(confirmButton).toBeInTheDocument(); + }); }); }); }); diff --git a/src/containers/LearnerDashboardHeader/__snapshots__/index.test.jsx.snap b/src/containers/LearnerDashboardHeader/__snapshots__/index.test.jsx.snap deleted file mode 100644 index 34bcdc1..0000000 --- a/src/containers/LearnerDashboardHeader/__snapshots__/index.test.jsx.snap +++ /dev/null @@ -1,61 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`LearnerDashboardHeader render 1`] = ` - - -
- - -`; diff --git a/src/containers/LearnerDashboardHeader/index.test.jsx b/src/containers/LearnerDashboardHeader/index.test.jsx index 6c1e281..470dc64 100644 --- a/src/containers/LearnerDashboardHeader/index.test.jsx +++ b/src/containers/LearnerDashboardHeader/index.test.jsx @@ -1,15 +1,17 @@ import { mergeConfig } from '@edx/frontend-platform'; -import { shallow } from '@edx/react-unit-test-utils'; -import Header from '@edx/frontend-component-header'; +import { render, screen } from '@testing-library/react'; +import { IntlProvider } from '@edx/frontend-platform/i18n'; import urls from 'data/services/lms/urls'; import LearnerDashboardHeader from '.'; import { findCoursesNavClicked } from './hooks'; +const courseSearchUrl = '/course-search-url'; + jest.mock('hooks', () => ({ reduxHooks: { usePlatformSettingsData: jest.fn(() => ({ - courseSearchUrl: '/course-search-url', + courseSearchUrl, })), }, })); @@ -17,36 +19,54 @@ jest.mock('./hooks', () => ({ ...jest.requireActual('./hooks'), findCoursesNavClicked: jest.fn(), })); -jest.mock('containers/MasqueradeBar', () => 'MasqueradeBar'); -jest.mock('./ConfirmEmailBanner', () => 'ConfirmEmailBanner'); -jest.mock('@edx/frontend-component-header', () => 'Header'); + +jest.unmock('@openedx/paragon'); +jest.unmock('@edx/frontend-platform/i18n'); +jest.unmock('react'); + +const mockedHeaderProps = jest.fn(); +jest.mock('containers/MasqueradeBar', () => jest.fn(() =>
MasqueradeBar
)); +jest.mock('./ConfirmEmailBanner', () => jest.fn(() =>
ConfirmEmailBanner
)); +jest.mock('@edx/frontend-component-header', () => jest.fn((props) => { + mockedHeaderProps(props); + return
Header
; +})); describe('LearnerDashboardHeader', () => { - test('render', () => { + beforeEach(() => jest.clearAllMocks()); + it('renders and discover url is correct', () => { mergeConfig({ ORDER_HISTORY_URL: 'test-url' }); - const wrapper = shallow(); - expect(wrapper.snapshot).toMatchSnapshot(); - expect(wrapper.instance.findByType('ConfirmEmailBanner')).toHaveLength(1); - expect(wrapper.instance.findByType('MasqueradeBar')).toHaveLength(1); - expect(wrapper.instance.findByType(Header)).toHaveLength(1); - wrapper.instance.findByType(Header)[0].props.mainMenuItems[1].onClick(); - expect(findCoursesNavClicked).toHaveBeenCalledWith(urls.baseAppUrl('/course-search-url')); - expect(wrapper.instance.findByType(Header)[0].props.secondaryMenuItems.length).toBe(0); + render(); + expect(screen.getByText('ConfirmEmailBanner')).toBeInTheDocument(); + expect(screen.getByText('MasqueradeBar')).toBeInTheDocument(); + expect(screen.getByText('Header')).toBeInTheDocument(); + const props = mockedHeaderProps.mock.calls[0][0]; + const { mainMenuItems } = props; + const discoverUrl = mainMenuItems[1].href; + mainMenuItems[1].onClick(); + expect(discoverUrl).toBe(urls.baseAppUrl(courseSearchUrl)); + expect(findCoursesNavClicked).toHaveBeenCalledWith(urls.baseAppUrl(courseSearchUrl)); }); - test('should display Help link if SUPPORT_URL is set', () => { + it('should display Help link if SUPPORT_URL is set', () => { mergeConfig({ SUPPORT_URL: 'http://localhost:18000/support' }); - const wrapper = shallow(); - expect(wrapper.instance.findByType(Header)[0].props.secondaryMenuItems.length).toBe(1); + render(); + const props = mockedHeaderProps.mock.calls[0][0]; + const { secondaryMenuItems } = props; + expect(secondaryMenuItems.length).toBe(1); }); - test('should display Programs link if it is enabled by configuration', () => { + it('should display Programs link if it is enabled by configuration', () => { mergeConfig({ ENABLE_PROGRAMS: true }); - const wrapper = shallow(); - expect(wrapper.instance.findByType(Header)[0].props.mainMenuItems.length).toBe(3); + render(); + const props = mockedHeaderProps.mock.calls[0][0]; + const { mainMenuItems } = props; + expect(mainMenuItems.length).toBe(3); }); - test('should not display Discover New tab if it is disabled by configuration', () => { + it('should not display Discover New tab if it is disabled by configuration', () => { mergeConfig({ NON_BROWSABLE_COURSES: true }); - const wrapper = shallow(); - expect(wrapper.instance.findByType(Header)[0].props.mainMenuItems.length).toBe(2); + render(); + const props = mockedHeaderProps.mock.calls[0][0]; + const { mainMenuItems } = props; + expect(mainMenuItems.length).toBe(2); }); }); diff --git a/src/containers/MasqueradeBar/__snapshots__/index.test.jsx.snap b/src/containers/MasqueradeBar/__snapshots__/index.test.jsx.snap deleted file mode 100644 index e401b0b..0000000 --- a/src/containers/MasqueradeBar/__snapshots__/index.test.jsx.snap +++ /dev/null @@ -1,220 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`MasqueradeBar snapshot can masquerade 1`] = ` -
-
- - - - View as: - - - - - - -
-
-`; - -exports[`MasqueradeBar snapshot can masquerade with input 1`] = ` -
-
- - - - View as: - - - - - - -
-
-`; - -exports[`MasqueradeBar snapshot cannot masquerade 1`] = `null`; - -exports[`MasqueradeBar snapshot is masquerading failed with error 1`] = ` -
-
- - - - View as: - - - - - - - -
-
-`; - -exports[`MasqueradeBar snapshot is masquerading pending 1`] = ` -
-
- - - - View as: - - - - - - -
-
-`; - -exports[`MasqueradeBar snapshot is masquerading with input 1`] = ` -
-
- - - - Viewing as: - - - test - - -
-
-`; diff --git a/src/containers/MasqueradeBar/index.test.jsx b/src/containers/MasqueradeBar/index.test.jsx index f2643cc..db89056 100644 --- a/src/containers/MasqueradeBar/index.test.jsx +++ b/src/containers/MasqueradeBar/index.test.jsx @@ -1,14 +1,18 @@ -import React from 'react'; -import { shallow } from '@edx/react-unit-test-utils'; +import { render, screen } from '@testing-library/react'; import { formatMessage } from 'testUtils'; import MasqueradeBar from '.'; import hooks from './hooks'; +import messages from './messages'; jest.mock('./hooks', () => ({ useMasqueradeBarData: jest.fn(), })); +jest.unmock('@openedx/paragon'); +jest.unmock('@edx/frontend-platform/i18n'); +jest.unmock('react'); + describe('MasqueradeBar', () => { const masqueradeMockData = { canMasquerade: true, @@ -23,47 +27,67 @@ describe('MasqueradeBar', () => { formatMessage, }; - describe('snapshot', () => { - test('can masquerade', () => { + describe('render', () => { + it('can masquerade', () => { hooks.useMasqueradeBarData.mockReturnValueOnce(masqueradeMockData); - expect(shallow().snapshot).toMatchSnapshot(); + render(); + const labelStudentName = screen.getByText(messages.StudentNameInput.defaultMessage); + expect(labelStudentName).toBeInTheDocument(); + const submitButton = screen.getByRole('button', { name: messages.SubmitButton.defaultMessage }); + expect(submitButton).toBeInTheDocument(); }); - test('can masquerade with input', () => { + it('can masquerade with input', () => { + const masqueradeInput = 'test'; hooks.useMasqueradeBarData.mockReturnValueOnce({ ...masqueradeMockData, - masqueradeInput: 'test', + masqueradeInput, }); - expect(shallow().snapshot).toMatchSnapshot(); + render(); + const valueMasqueradeInput = screen.getByRole('textbox', { value: masqueradeInput }); + expect(valueMasqueradeInput).toBeInTheDocument(); }); - test('cannot masquerade', () => { + it('cannot masquerade', () => { hooks.useMasqueradeBarData.mockReturnValueOnce({ ...masqueradeMockData, canMasquerade: false, }); - expect(shallow().snapshot).toMatchSnapshot(); + render(); + const labelStudentName = screen.queryByText(messages.StudentNameInput.defaultMessage); + expect(labelStudentName).toBeNull(); }); - test('is masquerading with input', () => { + it('is masquerading with input', () => { + const masqueradeInput = 'test'; hooks.useMasqueradeBarData.mockReturnValueOnce({ ...masqueradeMockData, isMasquerading: true, - masqueradeInput: 'test', + masqueradeInput, }); - expect(shallow().snapshot).toMatchSnapshot(); + render(); + const chipMasqueradeInput = screen.getByText(masqueradeInput); + expect(chipMasqueradeInput).toBeInTheDocument(); + expect(chipMasqueradeInput.parentElement).toHaveClass('masquerade-chip'); }); - test('is masquerading failed with error', () => { + it('is masquerading failed with error', () => { + const masqueradeErrorMessage = 'test-error'; + const masqueradeInput = 'test'; hooks.useMasqueradeBarData.mockReturnValueOnce({ ...masqueradeMockData, isMasqueradingFailed: true, - masqueradeErrorMessage: 'test-error', + masqueradeErrorMessage, }); - expect(shallow().snapshot).toMatchSnapshot(); + render(); + const valueMasqueradeInput = screen.getByRole('textbox', { value: masqueradeInput }); + expect(valueMasqueradeInput).toHaveClass('is-invalid'); }); - test('is masquerading pending', () => { + it('is masquerading pending', () => { hooks.useMasqueradeBarData.mockReturnValueOnce({ ...masqueradeMockData, isMasqueradingPending: true, }); - expect(shallow().snapshot).toMatchSnapshot(); + render(); + const pendingButton = screen.getByRole('button', { name: messages.SubmitButton.defaultMessage }); + expect(pendingButton).toBeInTheDocument(); + expect(pendingButton).toHaveAttribute('aria-disabled', 'true'); }); }); }); diff --git a/src/containers/RelatedProgramsModal/__snapshots__/index.test.jsx.snap b/src/containers/RelatedProgramsModal/__snapshots__/index.test.jsx.snap deleted file mode 100644 index e2d06ea..0000000 --- a/src/containers/RelatedProgramsModal/__snapshots__/index.test.jsx.snap +++ /dev/null @@ -1,169 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`RelatedProgramsModal snapshot: closed 1`] = ` - - - Related Programs - - - -

- Are you looking to expand your knowledge? Enrolling in a Program lets you take a series of courses in the subject that you're interested in -

- - - - - - - - - - - - - -
-
-`; - -exports[`RelatedProgramsModal snapshot: open 1`] = ` - - - Related Programs - - - -

- Are you looking to expand your knowledge? Enrolling in a Program lets you take a series of courses in the subject that you're interested in -

- - - - - - - - - - - - - -
-
-`; diff --git a/src/containers/RelatedProgramsModal/components/ProgramCard.test.jsx b/src/containers/RelatedProgramsModal/components/ProgramCard.test.jsx index 638c7f4..57de5d9 100644 --- a/src/containers/RelatedProgramsModal/components/ProgramCard.test.jsx +++ b/src/containers/RelatedProgramsModal/components/ProgramCard.test.jsx @@ -1,23 +1,47 @@ -import React from 'react'; -import { shallow } from '@edx/react-unit-test-utils'; +import { render, screen } from '@testing-library/react'; +import { IntlProvider } from '@edx/frontend-platform/i18n'; import ProgramCard from './ProgramCard'; const props = { data: { numberOfCourses: 2, - bannerImgSrc: 'props.data.bannerImgSrc', - logoImgSrc: 'props.data.logoImgSrc', - title: 'props.data.title', - provider: 'props.data.provider', - programType: 'props.data.programType', - programUrl: 'props.data.programUrl', - programTypeUrl: 'props.data.programTypeUrl', + bannerImgSrc: 'test bannerImgSrc', + logoImgSrc: 'test logoImgSrc', + title: 'test title', + provider: 'test provider', + programType: 'test programType', + programUrl: 'test programUrl', + programTypeUrl: 'test programTypeUrl', }, }; +jest.unmock('@openedx/paragon'); +jest.unmock('@edx/frontend-platform/i18n'); +jest.unmock('react'); + describe('RelatedProgramsModal ProgramCard', () => { - test('snapshot', () => { - expect(shallow().snapshot).toMatchSnapshot(); + describe('renders', () => { + beforeEach(() => render()); + it('bannerImg and logo', () => { + const logo = screen.getByRole('img', { name: `${props.data.provider} logo` }); + const bannerImg = screen.getByRole('img', { name: /bannerAlt/i }); + expect(logo).toBeInTheDocument(); + expect(bannerImg).toBeInTheDocument(); + }); + it('title and subtitle', () => { + const title = screen.getByText(props.data.title); + const subtitle = screen.getByText(props.data.provider); + expect(title).toBeInTheDocument(); + expect(subtitle).toBeInTheDocument(); + }); + it('badge', () => { + const badge = screen.getByText(props.data.programType); + expect(badge).toBeInTheDocument(); + }); + it('courses number', () => { + const coursesNumber = screen.getByText(`${props.data.numberOfCourses} Courses`); + expect(coursesNumber).toBeInTheDocument(); + }); }); }); diff --git a/src/containers/RelatedProgramsModal/components/__snapshots__/ProgramCard.test.jsx.snap b/src/containers/RelatedProgramsModal/components/__snapshots__/ProgramCard.test.jsx.snap deleted file mode 100644 index 5c44d9a..0000000 --- a/src/containers/RelatedProgramsModal/components/__snapshots__/ProgramCard.test.jsx.snap +++ /dev/null @@ -1,60 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`RelatedProgramsModal ProgramCard snapshot 1`] = ` - - - - props.data.provider - - } - title={ - - props.data.title - - } - /> -
- - - - props.data.programType - -
- 2 Courses -
-
-
-`; diff --git a/src/containers/RelatedProgramsModal/index.test.jsx b/src/containers/RelatedProgramsModal/index.test.jsx index 0d43db2..07406c3 100644 --- a/src/containers/RelatedProgramsModal/index.test.jsx +++ b/src/containers/RelatedProgramsModal/index.test.jsx @@ -1,10 +1,11 @@ -import React from 'react'; -import { shallow } from '@edx/react-unit-test-utils'; +import { render, screen } from '@testing-library/react'; +import { IntlProvider } from '@edx/frontend-platform/i18n'; import { reduxHooks } from 'hooks'; import RelatedProgramsModal from '.'; +import messages from './messages'; -jest.mock('./components/ProgramCard', () => 'ProgramCard'); +jest.mock('./components/ProgramCard', () => jest.fn(() =>
ProgramCard
)); jest.mock('hooks', () => ({ reduxHooks: { useCardCourseData: jest.fn(), @@ -12,9 +13,13 @@ jest.mock('hooks', () => ({ }, })); -const cardId = 'test-course-number'; +jest.unmock('@openedx/paragon'); +jest.unmock('@edx/frontend-platform/i18n'); +jest.unmock('react'); + +const cardId = 'test-card-id'; const courseData = { - courseTitle: 'hookProps.courseTitle', + courseName: 'test course', }; const programData = { list: [ @@ -45,16 +50,27 @@ describe('RelatedProgramsModal', () => { reduxHooks.useCardRelatedProgramsData.mockReturnValueOnce(programData); }); it('initializes hooks with cardId', () => { - shallow(); + render(); expect(reduxHooks.useCardCourseData).toHaveBeenCalledWith(cardId); expect(reduxHooks.useCardRelatedProgramsData).toHaveBeenCalledWith(cardId); }); - test('snapshot: open', () => { - expect(shallow().snapshot).toMatchSnapshot(); - }); - test('snapshot: closed', () => { - expect( - shallow().snapshot, - ).toMatchSnapshot(); + describe('renders', () => { + beforeEach(() => render()); + it('display header', () => { + const header = screen.getByRole('heading', { name: messages.header.defaultMessage }); + expect(header).toBeInTheDocument(); + }); + it('displays course name', () => { + const courseName = screen.getByText(courseData.courseName); + expect(courseName).toBeInTheDocument(); + }); + it('displays description', () => { + const description = screen.getByText((text) => text.includes('Are you looking to expand your knowledge?')); + expect(description).toBeInTheDocument(); + }); + it('displays program cards', () => { + const programCards = screen.getAllByText('ProgramCard'); + expect(programCards.length).toEqual(programData.list.length); + }); }); });