diff --git a/src/containers/CourseFilterControls/ActiveCourseFilters.test.jsx b/src/containers/CourseFilterControls/ActiveCourseFilters.test.jsx index faf74d449..14a0d7bdd 100644 --- a/src/containers/CourseFilterControls/ActiveCourseFilters.test.jsx +++ b/src/containers/CourseFilterControls/ActiveCourseFilters.test.jsx @@ -1,17 +1,32 @@ -import { shallow } from '@edx/react-unit-test-utils'; +import { render, screen } from '@testing-library/react'; +import { IntlProvider } from '@edx/frontend-platform/i18n'; +import { formatMessage } from 'testUtils'; import { FilterKeys } from 'data/constants/app'; import ActiveCourseFilters from './ActiveCourseFilters'; +import messages from './messages'; + +jest.unmock('@edx/frontend-platform/i18n'); +jest.unmock('@openedx/paragon'); +jest.unmock('react'); + +const filters = Object.values(FilterKeys); describe('ActiveCourseFilters', () => { const props = { - filters: Object.values(FilterKeys), + filters, handleRemoveFilter: jest.fn().mockName('handleRemoveFilter'), }; - describe('snapshot', () => { - test('renders', () => { - const wrapper = shallow(); - expect(wrapper.snapshot).toMatchSnapshot(); + it('renders chips correctly', () => { + render(); + filters.map((key) => { + const chip = screen.getByText(formatMessage(messages[key])); + return expect(chip).toBeInTheDocument(); }); }); + it('renders button correctly', () => { + render(); + const button = screen.getByRole('button', { name: formatMessage(messages.clearAll) }); + expect(button).toBeInTheDocument(); + }); }); diff --git a/src/containers/CourseFilterControls/CourseFilterControls.test.jsx b/src/containers/CourseFilterControls/CourseFilterControls.test.jsx index 7daee4e53..c1caf71f0 100644 --- a/src/containers/CourseFilterControls/CourseFilterControls.test.jsx +++ b/src/containers/CourseFilterControls/CourseFilterControls.test.jsx @@ -1,9 +1,11 @@ -import { shallow } from '@edx/react-unit-test-utils'; - +import { render, screen } from '@testing-library/react'; +import { formatMessage } from 'testUtils'; import { breakpoints, useWindowSize } from '@openedx/paragon'; - import { reduxHooks } from 'hooks'; +import { IntlProvider } from '@edx/frontend-platform/i18n'; +import { FilterKeys, SortKeys } from 'data/constants/app'; +import messages from './messages'; import CourseFilterControls from './CourseFilterControls'; import useCourseFilterControlsData from './hooks'; @@ -11,50 +13,67 @@ jest.mock('hooks', () => ({ reduxHooks: { useHasCourses: jest.fn() }, })); -jest.mock('./hooks', () => jest.fn().mockName('useCourseFilterControlsData')); +jest.mock('./hooks', () => jest.fn()); -jest.mock('./components/FilterForm', () => 'FilterForm'); -jest.mock('./components/SortForm', () => 'SortForm'); +jest.unmock('@edx/frontend-platform/i18n'); +jest.unmock('@openedx/paragon'); +jest.unmock('react'); + +jest.mock('@openedx/paragon', () => ({ + ...jest.requireActual('@openedx/paragon'), + useWindowSize: jest.fn(), +})); -reduxHooks.useHasCourses.mockReturnValue(true); +const filters = Object.values(FilterKeys); + +const mockControlsData = { + isOpen: false, + open: jest.fn().mockName('open'), + close: jest.fn().mockName('close'), + target: 'target-test', + setTarget: jest.fn(), + handleFilterChange: jest.fn().mockName('handleFilterChange'), + handleSortChange: jest.fn().mockName('handleSortChange'), +}; describe('CourseFilterControls', () => { const props = { - sortBy: 'test-sort-by', + sortBy: SortKeys.enrolled, setSortBy: jest.fn().mockName('setSortBy'), - filters: ['test-filter'], + filters, }; - useCourseFilterControlsData.mockReturnValue({ - isOpen: false, - open: jest.fn().mockName('open'), - close: jest.fn().mockName('close'), - target: 'test-target', - setTarget: jest.fn().mockName('setTarget'), - handleFilterChange: jest.fn().mockName('handleFilterChange'), - handleSortChange: jest.fn().mockName('handleSortChange'), - }); - - describe('no courses', () => { - test('snapshot', () => { - reduxHooks.useHasCourses.mockReturnValueOnce(false); - useWindowSize.mockReturnValueOnce({ width: breakpoints.small.minWidth }); - const wrapper = shallow(); - expect(wrapper.snapshot).toMatchSnapshot(); - }); - }); - describe('mobile', () => { - test('snapshot', () => { + describe('mobile and open', () => { + it('should render sheet', () => { + reduxHooks.useHasCourses.mockReturnValue(true); + useCourseFilterControlsData.mockReturnValue({ ...mockControlsData, isOpen: true }); useWindowSize.mockReturnValueOnce({ width: breakpoints.small.minWidth - 1 }); - const wrapper = shallow(); - expect(wrapper.snapshot).toMatchSnapshot(); + render(); + const sheet = screen.getByRole('presentation', { hidden: true }); + expect(sheet).toBeInTheDocument(); + expect(sheet.parentElement).toHaveClass('sheet-container'); }); }); describe('is not mobile', () => { - test('snapshot', () => { + it('should have button disabled', () => { + reduxHooks.useHasCourses.mockReturnValue(true); + useCourseFilterControlsData.mockReturnValue({ ...mockControlsData, isOpen: true }); useWindowSize.mockReturnValueOnce({ width: breakpoints.small.minWidth }); - const wrapper = shallow(); - expect(wrapper.snapshot).toMatchSnapshot(); + render(); + const filterForm = screen.getByText(messages.courseStatus.defaultMessage); + const modal = filterForm.closest('div.pgn__modal-popup__tooltip'); + expect(modal).toBeInTheDocument(); + }); + }); + describe('no courses', () => { + it('should have button disabled', () => { + reduxHooks.useHasCourses.mockReturnValue(false); + useCourseFilterControlsData.mockReturnValue(mockControlsData); + useWindowSize.mockReturnValue({ width: breakpoints.small.minWidth }); + render(); + const button = screen.getByRole('button', { name: formatMessage(messages.refine) }); + expect(button).toBeInTheDocument(); + expect(button).toBeDisabled(); }); }); }); diff --git a/src/containers/CourseFilterControls/__snapshots__/ActiveCourseFilters.test.jsx.snap b/src/containers/CourseFilterControls/__snapshots__/ActiveCourseFilters.test.jsx.snap deleted file mode 100644 index 9a9cf832e..000000000 --- a/src/containers/CourseFilterControls/__snapshots__/ActiveCourseFilters.test.jsx.snap +++ /dev/null @@ -1,39 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`ActiveCourseFilters snapshot renders 1`] = ` -
- - In-Progress - - - Not Started - - - Done - - - Not Enrolled - - - Upgraded - - -
-`; diff --git a/src/containers/CourseFilterControls/__snapshots__/CourseFilterControls.test.jsx.snap b/src/containers/CourseFilterControls/__snapshots__/CourseFilterControls.test.jsx.snap deleted file mode 100644 index 834f4e010..000000000 --- a/src/containers/CourseFilterControls/__snapshots__/CourseFilterControls.test.jsx.snap +++ /dev/null @@ -1,169 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`CourseFilterControls is not mobile snapshot 1`] = ` -
- -
- -
-
- -
-
-
- -
-
-
-
-
-`; - -exports[`CourseFilterControls mobile snapshot 1`] = ` -
- -
- -
- - Refine - -
-
-
- -
-
- -
-
- - - -
-
-
-
-`; - -exports[`CourseFilterControls no courses snapshot 1`] = ` -
- -
- -
-
- -
-
-
- -
-
-
-
-
-`; diff --git a/src/containers/CourseFilterControls/components/SortForm.test.jsx b/src/containers/CourseFilterControls/components/SortForm.test.jsx index 598181f5d..269322599 100644 --- a/src/containers/CourseFilterControls/components/SortForm.test.jsx +++ b/src/containers/CourseFilterControls/components/SortForm.test.jsx @@ -1,19 +1,33 @@ -import { shallow } from '@edx/react-unit-test-utils'; +import { render, screen } from '@testing-library/react'; +import { IntlProvider } from '@edx/frontend-platform/i18n'; +import { formatMessage } from 'testUtils'; import { SortKeys } from 'data/constants/app'; import SortForm from './SortForm'; +import messages from '../messages'; -jest.mock('./Checkbox', () => 'Checkbox'); +jest.unmock('@edx/frontend-platform/i18n'); +jest.unmock('@openedx/paragon'); +jest.unmock('react'); describe('SortForm', () => { const props = { handleSortChange: jest.fn().mockName('handleSortChange'), sortBy: SortKeys.enrolled, }; - describe('snapshot', () => { - test('renders', () => { - const wrapper = shallow(); - expect(wrapper.snapshot).toMatchSnapshot(); - }); + it('renders heading', () => { + render(); + const heading = screen.getByText(formatMessage(messages.sort)); + expect(heading).toBeInTheDocument(); + }); + it('renders radio enrolled', () => { + render(); + const enrolled = screen.getByRole('radio', { name: formatMessage(messages.sortLastEnrolled) }); + expect(enrolled).toBeInTheDocument(); + }); + it('renders radio title', () => { + render(); + const title = screen.getByRole('radio', { name: formatMessage(messages.sortTitle) }); + expect(title).toBeInTheDocument(); }); }); diff --git a/src/containers/CourseFilterControls/components/__snapshots__/SortForm.test.jsx.snap b/src/containers/CourseFilterControls/components/__snapshots__/SortForm.test.jsx.snap deleted file mode 100644 index 05c1b195a..000000000 --- a/src/containers/CourseFilterControls/components/__snapshots__/SortForm.test.jsx.snap +++ /dev/null @@ -1,29 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`SortForm snapshot renders 1`] = ` - -
- Sort -
- - - Last enrolled - - - Title (A-Z) - - -
-`; diff --git a/src/containers/CoursesPanel/CourseList/__snapshots__/index.test.jsx.snap b/src/containers/CoursesPanel/CourseList/__snapshots__/index.test.jsx.snap deleted file mode 100644 index 89889324b..000000000 --- a/src/containers/CoursesPanel/CourseList/__snapshots__/index.test.jsx.snap +++ /dev/null @@ -1,70 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`CourseList collapsed with multiple courses and pages snapshot 1`] = ` - -
- -
-
- - - - -
-
-`; - -exports[`CourseList no courses or filters snapshot 1`] = ` - -
- -`; - -exports[`CourseList with filters snapshot 1`] = `undefined`; - -exports[`CourseList with multiple courses and pages snapshot 1`] = ` - -
- - - - -
-
-`; diff --git a/src/containers/CoursesPanel/CourseList/index.test.jsx b/src/containers/CoursesPanel/CourseList/index.test.jsx index 0584eda5f..b964e3d5a 100644 --- a/src/containers/CoursesPanel/CourseList/index.test.jsx +++ b/src/containers/CoursesPanel/CourseList/index.test.jsx @@ -1,4 +1,4 @@ -import { shallow } from '@edx/react-unit-test-utils'; +import { render, screen } from '@testing-library/react'; import { useIsCollapsed } from './hooks'; import CourseList from '.'; @@ -7,11 +7,15 @@ jest.mock('./hooks', () => ({ useIsCollapsed: jest.fn(), })); -jest.mock('containers/CourseCard', () => 'CourseCard'); +jest.mock('containers/CourseCard', () => jest.fn(() =>
CourseCard
)); jest.mock('containers/CourseFilterControls', () => ({ - ActiveCourseFilters: 'ActiveCourseFilters', + ActiveCourseFilters: jest.fn(() =>
ActiveCourseFilters
), })); +jest.unmock('@edx/frontend-platform/i18n'); +jest.unmock('@openedx/paragon'); +jest.unmock('react'); + describe('CourseList', () => { const defaultCourseListData = { filterOptions: {}, @@ -22,43 +26,60 @@ describe('CourseList', () => { }; useIsCollapsed.mockReturnValue(false); - const createWrapper = (courseListData = defaultCourseListData) => ( - shallow() + const renderList = (courseListData = defaultCourseListData) => ( + render() ); describe('no courses or filters', () => { - test('snapshot', () => { - const wrapper = createWrapper(); - expect(wrapper.snapshot).toMatchSnapshot(); + it('should not render related components', () => { + renderList(); + const filterControls = screen.queryByText('ActiveCourseFilters'); + const courseCard = screen.queryByText('CourseCard'); + const prevButton = screen.queryByRole('button', { name: 'Previous' }); + expect(filterControls).toBeNull(); + expect(courseCard).toBeNull(); + expect(prevButton).toBeNull(); }); }); describe('with filters', () => { - test('snapshot', () => { - const wrapper = createWrapper({ - filterOptions: { abitary: 'filter' }, + it('should render filter component', () => { + renderList({ + ...defaultCourseListData, showFilters: true, }); - expect(wrapper.snapshot).toMatchSnapshot(); + const filterControls = screen.getByText('ActiveCourseFilters'); + expect(filterControls).toBeInTheDocument(); }); }); describe('with multiple courses and pages', () => { - test('snapshot', () => { - const wrapper = createWrapper({ - visibleList: [{ cardId: 'foo' }, { cardId: 'bar' }, { cardId: 'baz' }], - numPages: 3, + it('render Course Cards and pagination', () => { + const visibleList = [{ cardId: 'foo' }, { cardId: 'bar' }, { cardId: 'baz' }]; + const numPages = 3; + renderList({ + ...defaultCourseListData, + visibleList, + numPages, }); - expect(wrapper.snapshot).toMatchSnapshot(); + const courseCards = screen.getAllByText('CourseCard'); + expect(courseCards.length).toEqual(visibleList.length); + const pageButtons = screen.getAllByRole('button', { name: /^Page/i }); + expect(pageButtons.length).toBe(numPages); }); }); describe('collapsed with multiple courses and pages', () => { - test('snapshot', () => { + it('should render correct components', () => { + const visibleList = [{ cardId: 'foo' }, { cardId: 'bar' }, { cardId: 'baz' }]; useIsCollapsed.mockReturnValueOnce(true); - const wrapper = createWrapper({ - visibleList: [{ cardId: 'foo' }, { cardId: 'bar' }, { cardId: 'baz' }], + renderList({ + ...defaultCourseListData, + visibleList, numPages: 3, showFilters: true, }); - expect(wrapper.snapshot).toMatchSnapshot(); + const courseCards = screen.getAllByText('CourseCard'); + expect(courseCards.length).toEqual(visibleList.length); + const reducedPagination = screen.getByRole('button', { name: '1 of 3' }); + expect(reducedPagination).toBeInTheDocument(); }); }); }); diff --git a/src/containers/CoursesPanel/NoCoursesView/__snapshots__/index.test.jsx.snap b/src/containers/CoursesPanel/NoCoursesView/__snapshots__/index.test.jsx.snap deleted file mode 100644 index fc408e146..000000000 --- a/src/containers/CoursesPanel/NoCoursesView/__snapshots__/index.test.jsx.snap +++ /dev/null @@ -1,29 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`NoCoursesView snapshot 1`] = ` -
- No Courses view banner -

- Looking for a new challenge? -

-

- Explore our courses to add them to your dashboard. -

- -
-`; diff --git a/src/containers/CoursesPanel/NoCoursesView/index.test.jsx b/src/containers/CoursesPanel/NoCoursesView/index.test.jsx index 923fde28d..9831a768e 100644 --- a/src/containers/CoursesPanel/NoCoursesView/index.test.jsx +++ b/src/containers/CoursesPanel/NoCoursesView/index.test.jsx @@ -1,18 +1,42 @@ -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 { formatMessage } from 'testUtils'; +import { baseAppUrl } from 'data/services/lms/urls'; import EmptyCourse from '.'; +import messages from './messages'; + +const courseSearchUrl = '/course-search-url'; jest.mock('hooks', () => ({ reduxHooks: { usePlatformSettingsData: jest.fn(() => ({ - courseSearchUrl: '/course-search-url', + courseSearchUrl, })), }, })); +jest.unmock('@edx/frontend-platform/i18n'); +jest.unmock('@openedx/paragon'); +jest.unmock('react'); + describe('NoCoursesView', () => { - test('snapshot', () => { - expect(shallow().snapshot).toMatchSnapshot(); + it('should display image, heading and button', () => { + render(); + const image = screen.getByRole('img', { alt: formatMessage(messages.bannerAlt) }); + expect(image).toBeInTheDocument(); + }); + it('should display heading and prompt', () => { + render(); + const heading = screen.getByText(formatMessage(messages.lookingForChallengePrompt)); + const prompt = screen.getByText(formatMessage(messages.exploreCoursesPrompt)); + expect(heading).toBeInTheDocument(); + expect(prompt).toBeInTheDocument(); + }); + it('should display button', () => { + render(); + const button = screen.getByRole('link', { name: formatMessage(messages.exploreCoursesButton) }); + expect(button).toBeInTheDocument(); + expect(button.href).toBe(baseAppUrl(courseSearchUrl)); }); });