diff --git a/src/frontend/js/pages/DashboardCreditCardsManagement/DashboardEditCreditCard.spec.tsx b/src/frontend/js/pages/DashboardCreditCardsManagement/DashboardEditCreditCard.spec.tsx index 442a1ac24a..9d3a012a96 100644 --- a/src/frontend/js/pages/DashboardCreditCardsManagement/DashboardEditCreditCard.spec.tsx +++ b/src/frontend/js/pages/DashboardCreditCardsManagement/DashboardEditCreditCard.spec.tsx @@ -1,22 +1,12 @@ -import { - act, - fireEvent, - getByText, - queryByText, - render, - screen, - waitFor, -} from '@testing-library/react'; -import { QueryClientProvider } from '@tanstack/react-query'; -import { IntlProvider } from 'react-intl'; +import { getByText, queryByText, screen, waitFor } from '@testing-library/react'; import fetchMock from 'fetch-mock'; +import userEvent from '@testing-library/user-event'; +import { Outlet, generatePath } from 'react-router-dom'; import { UserFactory, RichieContextFactory as mockRichieContextFactory, } from 'utils/test/factories/richie'; import { CreditCardFactory } from 'utils/test/factories/joanie'; -import { DashboardTest } from 'widgets/Dashboard/components/DashboardTest'; -import { SessionProvider } from 'contexts/SessionContext'; import { expectFetchCall } from 'utils/test/expectFetchCall'; import { expectBreadcrumbsToEqualParts } from 'utils/test/expectBreadcrumbsToEqualParts'; import { createTestQueryClient } from 'utils/test/createTestQueryClient'; @@ -24,8 +14,15 @@ import { expectBannerError } from 'utils/test/expectBanner'; import { HttpStatusCode } from 'utils/errors/HttpError'; import { User } from 'types/User'; import { OpenEdxApiProfileFactory } from 'utils/test/factories/openEdx'; - -import { LearnerDashboardPaths } from 'widgets/Dashboard/utils/learnerRoutesPaths'; +import { render } from 'utils/test/render'; +import { DashboardLayoutRoute } from 'widgets/Dashboard/components/DashboardLayoutRoute'; +import { JoanieAppWrapper } from 'utils/test/wrappers/JoanieAppWrapper'; +import { DashboardPreferences } from 'pages/DashboardPreferences'; +import { + LEARNER_DASHBOARD_ROUTE_LABELS, + LearnerDashboardPaths, +} from 'widgets/Dashboard/utils/learnerRoutesPaths'; +import { DashboardEditCreditCardLoader } from './DashboardEditCreditCardLoader'; jest.mock('utils/context', () => ({ __esModule: true, @@ -39,6 +36,38 @@ jest.mock('utils/indirection/window', () => ({ confirm: jest.fn(() => true), })); +const routes = [ + { + path: '/', + element: , + children: [ + { + path: LearnerDashboardPaths.PREFERENCES, + element: , + handle: { + crumbLabel: LEARNER_DASHBOARD_ROUTE_LABELS[LearnerDashboardPaths.PREFERENCES], + }, + children: [ + { + index: true, + element: , + }, + { + path: LearnerDashboardPaths.PREFERENCES_CREDIT_CARD_EDITION, + handle: { + crumbLabel: + LEARNER_DASHBOARD_ROUTE_LABELS[ + LearnerDashboardPaths.PREFERENCES_CREDIT_CARD_EDITION + ], + }, + element: , + }, + ], + }, + ], + }, +]; + describe('', () => { let richieUser: User; beforeEach(() => { @@ -78,28 +107,28 @@ describe('', () => { const updateUrl = 'https://joanie.endpoint/api/v1.0/credit-cards/' + creditCard.id + '/'; fetchMock.put(updateUrl, HttpStatusCode.OK); - await act(async () => { - render( - - - - - - - , - ); - }); + render( + , + { wrapper: null }, + ); - expectBreadcrumbsToEqualParts([ - 'chevron_leftBack', - 'My preferences', - 'Edit credit card "' + creditCard.title + '"', - ]); + await waitFor(() => { + expectBreadcrumbsToEqualParts([ + 'chevron_leftBack', + 'My preferences', + 'Edit credit card "' + creditCard.title + '"', + ]); + }); // It doesn't show any errors. expect(screen.queryByText('An error occurred', { exact: false })).toBeNull(); @@ -128,11 +157,12 @@ describe('', () => { // Submit of the form calls the API edit route. expect(fetchMock.called(updateUrl, { method: 'put' })).toBe(false); - await act(async () => { - // Update the title. - fireEvent.change(titleInput, { target: { value: creditCardUpdated.title } }); - fireEvent.click(button); - }); + + const user = userEvent.setup(); + await user.clear(titleInput); + await user.type(titleInput, creditCardUpdated.title!); + await user.click(button); + expect(fetchMock.called(updateUrl, { method: 'put' })).toBe(true); // The API is called with correct body. @@ -174,22 +204,20 @@ describe('', () => { const updateUrl = 'https://joanie.endpoint/api/v1.0/credit-cards/' + creditCard.id + '/'; fetchMock.put(updateUrl, HttpStatusCode.OK); - await act(async () => { - render( - - - - - - - , - ); - }); + render( + , + { wrapper: null }, + ); // We are on the expected route. await screen.findByText('Edit credit card'); @@ -220,11 +248,9 @@ describe('', () => { // Submit of the form calls the API edit route. expect(fetchMock.called(updateUrl, { method: 'put' })).toBe(false); - await act(async () => { - // Set as main. - fireEvent.click(isMainInput); - fireEvent.click(button); - }); + const user = userEvent.setup(); + await user.click(isMainInput); + await user.click(button); expect(fetchMock.called(updateUrl, { method: 'put' })).toBe(true); // The API is called with correct body. @@ -240,10 +266,8 @@ describe('', () => { // Redirected to the list route. screen.getByText('Credit cards'); - - const creditCardsContainers = screen.getAllByTestId('dashboard-credit-card__', { - exact: false, - }); + screen.debug(); + const creditCardsContainers = await screen.findAllByTestId(/dashboard-credit-card__/); expect(creditCardsContainers.length).toEqual(6); // Assert that `creditCard` is main and the first of the list. @@ -258,7 +282,7 @@ describe('', () => { ); }); - it('deletes a credit card', async () => { + it.only('deletes a credit card', async () => { const creditCard = CreditCardFactory().one(); let creditCards = [...CreditCardFactory().many(5), creditCard]; @@ -266,25 +290,24 @@ describe('', () => { const updateUrl = 'https://joanie.endpoint/api/v1.0/credit-cards/' + creditCard.id + '/'; fetchMock.put(updateUrl, HttpStatusCode.OK); - await act(async () => { - render( - - - - - - - , - ); - }); + render( + , + { wrapper: null }, + ); // We are on the expected route. await screen.findByText('Edit credit card'); + // It doesn't show any errors. expect(screen.queryByText('An error occurred', { exact: false })).toBeNull(); @@ -300,9 +323,8 @@ describe('', () => { // Clicking on the delete button calls delete API route. expect(fetchMock.called(deleteUrl)).toBe(false); - await act(async () => { - fireEvent.click(deleteButton); - }); + const user = userEvent.setup(); + await user.click(deleteButton); expect(fetchMock.called(deleteUrl)).toBe(true); // No error is shown. @@ -311,6 +333,16 @@ describe('', () => { // Redirected to the list route. screen.getByText('Credit cards'); + await waitFor(() => { + // Assert that other credit cards appear in the list. + creditCards.forEach((c) => { + screen.getByRole('heading', { + level: 6, + name: c.title, + }); + }); + }); + // Assert that the deleted credit card does not appear anymore in the list. expect( screen.queryByRole('heading', { @@ -318,14 +350,6 @@ describe('', () => { name: creditCard.title, }), ).toBeNull(); - - // Assert that other credit cards appear in the list. - creditCards.forEach((c) => { - screen.getByRole('heading', { - level: 6, - name: c.title, - }); - }); }); it('shows an error in case of API error', async () => { @@ -333,35 +357,30 @@ describe('', () => { const creditCards = [...CreditCardFactory().many(5), creditCard]; fetchMock.get('https://joanie.endpoint/api/v1.0/credit-cards/', creditCards); - const updateUrl = 'https://joanie.endpoint/api/v1.0/credit-cards/' + creditCard.id + '/'; + const updateUrl = `https://joanie.endpoint/api/v1.0/credit-cards/${creditCard.id}/`; fetchMock.put(updateUrl, { status: HttpStatusCode.INTERNAL_SERVER_ERROR, body: 'Internal Server Error', }); - await act(async () => { - render( - - - - - - - , - ); + render(, { + queryOptions: { client: createTestQueryClient({ user: richieUser }) }, + routerOptions: { + path: LearnerDashboardPaths.PREFERENCES_CREDIT_CARD_EDITION, + initialEntries: [ + generatePath(LearnerDashboardPaths.PREFERENCES_CREDIT_CARD_EDITION, { + creditCardId: creditCard.id, + }), + ], + }, }); const button = await screen.findByRole('button', { name: 'Save updates' }); // Submit of the form calls the API edit route. expect(fetchMock.called(updateUrl, { method: 'put' })).toBe(false); - await act(async () => { - fireEvent.click(button); - }); + const user = userEvent.setup(); + await user.click(button); + expect(fetchMock.called(updateUrl, { method: 'put' })).toBe(true); await expectBannerError( diff --git a/src/frontend/js/pages/DashboardCreditCardsManagement/index.spec.tsx b/src/frontend/js/pages/DashboardCreditCardsManagement/index.spec.tsx index caf9ac557d..e04c12ffd1 100644 --- a/src/frontend/js/pages/DashboardCreditCardsManagement/index.spec.tsx +++ b/src/frontend/js/pages/DashboardCreditCardsManagement/index.spec.tsx @@ -1,4 +1,3 @@ -import { QueryClientProvider } from '@tanstack/react-query'; import fetchMock from 'fetch-mock'; import { act, @@ -7,18 +6,14 @@ import { getByText, queryByRole, queryByText, - render, screen, } from '@testing-library/react'; -import { IntlProvider } from 'react-intl'; import { faker } from '@faker-js/faker'; import { UserFactory, RichieContextFactory as mockRichieContextFactory, } from 'utils/test/factories/richie'; import { CreditCardFactory } from 'utils/test/factories/joanie'; -import { SessionProvider } from 'contexts/SessionContext'; -import { DashboardTest } from 'widgets/Dashboard/components/DashboardTest'; import { CreditCard } from 'types/Joanie'; import { confirm } from 'utils/indirection/window'; import { expectBreadcrumbsToEqualParts } from 'utils/test/expectBreadcrumbsToEqualParts'; @@ -27,8 +22,15 @@ import { expectBannerError } from 'utils/test/expectBanner'; import { HttpStatusCode } from 'utils/errors/HttpError'; import { OpenEdxApiProfileFactory } from 'utils/test/factories/openEdx'; import { User } from 'types/User'; - -import { LearnerDashboardPaths } from 'widgets/Dashboard/utils/learnerRoutesPaths'; +import { DashboardPreferences } from 'pages/DashboardPreferences'; +import { render } from 'utils/test/render'; +import { DashboardLayoutRoute } from 'widgets/Dashboard/components/DashboardLayoutRoute'; +import { JoanieAppWrapper } from 'utils/test/wrappers/JoanieAppWrapper'; +import { + LEARNER_DASHBOARD_ROUTE_LABELS, + LearnerDashboardPaths, +} from 'widgets/Dashboard/utils/learnerRoutesPaths'; +import { DashboardEditCreditCardLoader } from './DashboardEditCreditCardLoader'; jest.mock('utils/context', () => ({ __esModule: true, @@ -72,17 +74,28 @@ describe('', () => { it('renders an empty list with placeholder', async () => { fetchMock.get('https://joanie.endpoint/api/v1.0/credit-cards/', []); - await act(async () => { - render( - - - - - - - , - ); - }); + const routes = [ + { + path: '/', + element: , + children: [ + { + path: LearnerDashboardPaths.PREFERENCES, + handle: { + crumbLabel: LEARNER_DASHBOARD_ROUTE_LABELS[LearnerDashboardPaths.PREFERENCES], + }, + element: , + }, + ], + }, + ]; + render( + , + { wrapper: null }, + ); expectBreadcrumbsToEqualParts(['chevron_leftBack', 'My preferences']); // The empty placeholder is shown. await screen.findByText("You haven't created any credit cards yet."); @@ -101,16 +114,8 @@ describe('', () => { }).one(); fetchMock.get('https://joanie.endpoint/api/v1.0/credit-cards/', [creditCard]); - await act(async () => { - render( - - - - - - - , - ); + render(, { + queryOptions: { client: createTestQueryClient({ user: richieUser }) }, }); // No error is shown. expect(screen.queryByText('An error occurred', { exact: false })).toBeNull(); @@ -138,16 +143,8 @@ describe('', () => { }).one(); fetchMock.get('https://joanie.endpoint/api/v1.0/credit-cards/', [creditCard]); - await act(async () => { - render( - - - - - - - , - ); + render(, { + queryOptions: { client: createTestQueryClient({ user: richieUser }) }, }); // No error is shown. expect(screen.queryByText('An error occurred', { exact: false })).toBeNull(); @@ -174,16 +171,8 @@ describe('', () => { }).one(); fetchMock.get('https://joanie.endpoint/api/v1.0/credit-cards/', [creditCard]); - await act(async () => { - render( - - - - - - - , - ); + render(, { + queryOptions: { client: createTestQueryClient({ user: richieUser }) }, }); // No error is shown. expect(screen.queryByText('An error occurred', { exact: false })).toBeNull(); @@ -203,16 +192,8 @@ describe('', () => { it('deletes a credit card', async () => { const creditCards = CreditCardFactory().many(5); fetchMock.get('https://joanie.endpoint/api/v1.0/credit-cards/', creditCards); - await act(async () => { - render( - - - - - - - , - ); + render(, { + queryOptions: { client: createTestQueryClient({ user: richieUser }) }, }); // No error is shown. expect(screen.queryByText('An error occurred', { exact: false })).toBeNull(); @@ -252,16 +233,8 @@ describe('', () => { it('promotes a credit card', async () => { const creditCards = CreditCardFactory().many(5); fetchMock.get('https://joanie.endpoint/api/v1.0/credit-cards/', creditCards); - await act(async () => { - render( - - - - - - - , - ); + render(, { + queryOptions: { client: createTestQueryClient({ user: richieUser }) }, }); // No error is shown. expect(screen.queryByText('An error occurred', { exact: false })).toBeNull(); @@ -305,16 +278,8 @@ describe('', () => { const mainCreditCard = creditCards[3]; mainCreditCard.is_main = true; fetchMock.get('https://joanie.endpoint/api/v1.0/credit-cards/', creditCards); - await act(async () => { - render( - - - - - - - , - ); + render(, { + queryOptions: { client: createTestQueryClient({ user: richieUser }) }, }); const creditCardsContainers = await screen.findAllByTestId('dashboard-credit-card__', { @@ -337,16 +302,8 @@ describe('', () => { const mainCreditCard = creditCards[3]; mainCreditCard.is_main = true; fetchMock.get('https://joanie.endpoint/api/v1.0/credit-cards/', creditCards); - await act(async () => { - render( - - - - - - - , - ); + render(, { + queryOptions: { client: createTestQueryClient({ user: richieUser }) }, }); // The delete button is not displayed. @@ -365,16 +322,8 @@ describe('', () => { const mainCreditCard = creditCards[3]; mainCreditCard.is_main = true; fetchMock.get('https://joanie.endpoint/api/v1.0/credit-cards/', creditCards); - await act(async () => { - render( - - - - - - - , - ); + render(, { + queryOptions: { client: createTestQueryClient({ user: richieUser }) }, }); // The promote button is not displayed. @@ -392,17 +341,25 @@ describe('', () => { const creditCards = CreditCardFactory().many(5); const creditCard = creditCards[2]; fetchMock.get('https://joanie.endpoint/api/v1.0/credit-cards/', creditCards); - await act(async () => { - render( - - - - - - - , - ); - }); + + const routes = [ + { + path: LearnerDashboardPaths.PREFERENCES, + element: , + }, + { + path: LearnerDashboardPaths.PREFERENCES_CREDIT_CARD_EDITION, + + element: , + }, + ]; + render( + , + { wrapper: null }, + ); // No error is shown. expect(screen.queryByText('An error occurred', { exact: false })).toBeNull(); @@ -436,16 +393,8 @@ describe('', () => { body: 'Internal Server Error', }); - await act(async () => { - render( - - - - - - - , - ); + render(, { + queryOptions: { client: createTestQueryClient({ user: richieUser }) }, }); await expectBannerError('An error occurred while fetching credit cards. Please retry later.');