From c77c4f3c91aad6ef2d102c8e1f0e0f7e0c0a925a Mon Sep 17 00:00:00 2001 From: Muhammad Faraz Maqsood Date: Wed, 7 May 2025 14:14:59 +0500 Subject: [PATCH] feat: add unit tests for filter functionality --- .../CourseOptimizerPage.test.js | 164 +++++++++++++----- src/optimizer-page/mocks/mockApiResponse.js | 112 +++++++----- src/optimizer-page/utils.test.js | 6 +- 3 files changed, 185 insertions(+), 97 deletions(-) diff --git a/src/optimizer-page/CourseOptimizerPage.test.js b/src/optimizer-page/CourseOptimizerPage.test.js index fd49dbbb7..fdcd2396d 100644 --- a/src/optimizer-page/CourseOptimizerPage.test.js +++ b/src/optimizer-page/CourseOptimizerPage.test.js @@ -37,6 +37,24 @@ const OptimizerPage = () => ( ); +const setupOptimizerPage = async () => { + axiosMock.onGet(getLinkCheckStatusApiUrl(courseId)).reply(200, mockApiResponse); + const optimizerPage = render(); + + // Click the scan button + fireEvent.click(optimizerPage.getByText(messages.buttonTitle.defaultMessage)); + + // Wait for the scan results to load + await waitFor(() => { + expect(optimizerPage.getByText('Introduction to Programming')).toBeInTheDocument(); + }); + + // Click on filters button + fireEvent.click(optimizerPage.getByText(scanResultsMessages.filterButtonLabel.defaultMessage)); + + return optimizerPage; +}; + describe('CourseOptimizerPage', () => { describe('pollLinkCheckDuringScan', () => { let mockFetchLinkCheckStatus; @@ -71,6 +89,7 @@ describe('CourseOptimizerPage', () => { pollLinkCheckDuringScan(linkCheckInProgress, interval, dispatch, courseId); expect(interval.current).toBeTruthy(); }); + it('should not start polling if link check is not in progress', () => { const linkCheckInProgress = false; const interval = { current: null }; @@ -79,6 +98,7 @@ describe('CourseOptimizerPage', () => { pollLinkCheckDuringScan(linkCheckInProgress, interval, dispatch, courseId); expect(interval.current).toBeFalsy(); }); + it('should clear the interval if link check is finished', () => { const linkCheckInProgress = false; const interval = { current: 1 }; @@ -127,53 +147,6 @@ describe('CourseOptimizerPage', () => { }); }); - it('should list broken links results', async () => { - const { - getByText, queryAllByText, getAllByText, container, - } = render(); - expect(getByText(messages.headingTitle.defaultMessage)).toBeInTheDocument(); - fireEvent.click(getByText(messages.buttonTitle.defaultMessage)); - await waitFor(() => { - expect(getByText('5 broken links')).toBeInTheDocument(); - expect(getByText('5 locked links')).toBeInTheDocument(); - }); - const collapsibleTrigger = container.querySelector('.collapsible-trigger'); - expect(collapsibleTrigger).toBeInTheDocument(); - fireEvent.click(collapsibleTrigger); - await waitFor(() => { - expect(getAllByText(scanResultsMessages.brokenLinkStatus.defaultMessage)[0]).toBeInTheDocument(); - expect(queryAllByText(scanResultsMessages.lockedLinkStatus.defaultMessage)[0]).toBeInTheDocument(); - expect(queryAllByText(scanResultsMessages.recommendedManualCheckText.defaultMessage)[0]).toBeInTheDocument(); - const brokenLinks = getAllByText('https://example.com/broken-link-algo'); - expect(brokenLinks.length).toBeGreaterThan(0); - fireEvent.click(brokenLinks[0]); - const lockedLinks = getAllByText('https://example.com/locked-link-algo'); - expect(lockedLinks.length).toBeGreaterThan(0); - fireEvent.click(lockedLinks[0]); - fireEvent.click((getAllByText('Go to Block'))[0]); - }); - }); - - it('should not list locked links results when show locked links is unchecked', async () => { - const { - getByText, getAllByText, getByLabelText, queryAllByText, queryByText, container, - } = render(); - expect(getByText(messages.headingTitle.defaultMessage)).toBeInTheDocument(); - fireEvent.click(getByText(messages.buttonTitle.defaultMessage)); - await waitFor(() => { - expect(getByText('5 broken links')).toBeInTheDocument(); - }); - fireEvent.click(getByLabelText(scanResultsMessages.lockedCheckboxLabel.defaultMessage)); - const collapsibleTrigger = container.querySelector('.collapsible-trigger'); - expect(collapsibleTrigger).toBeInTheDocument(); - fireEvent.click(collapsibleTrigger); - await waitFor(() => { - expect(queryByText('5 locked links')).not.toBeInTheDocument(); - expect(getAllByText(scanResultsMessages.brokenLinkStatus.defaultMessage)[0]).toBeInTheDocument(); - expect(queryAllByText(scanResultsMessages.lockedLinkStatus.defaultMessage)?.[0]).toBeUndefined(); - }); - }); - it('should show no broken links found message', async () => { axiosMock .onGet(getLinkCheckStatusApiUrl(courseId)) @@ -197,5 +170,102 @@ describe('CourseOptimizerPage', () => { expect(screen.getByText(generalMessages.supportText.defaultMessage)).toBeInTheDocument(); }); }); + + it('should show only broken links when brokenLinks filter is selected', async () => { + const { + getByText, + getByLabelText, + queryByText, + container, + } = await setupOptimizerPage(); + // Check if the modal is opened + expect(getByText('Broken')).toBeInTheDocument(); + // Select the broken links checkbox + fireEvent.click(getByLabelText(scanResultsMessages.brokenLabel.defaultMessage)); + + const collapsibleTrigger = container.querySelector('.collapsible-trigger'); + expect(collapsibleTrigger).toBeInTheDocument(); + fireEvent.click(collapsibleTrigger); + + await waitFor(() => { + expect(getByText('Test Broken Links')).toBeInTheDocument(); + expect(queryByText('Test Locked Links')).not.toBeInTheDocument(); + expect(queryByText('Test Manual Links')).not.toBeInTheDocument(); + }); + }); + + it('should show only manual links when manualLinks filter is selected', async () => { + const { + getByText, + getByLabelText, + queryByText, + container, + } = await setupOptimizerPage(); + // Check if the modal is opened + expect(getByText('Manual')).toBeInTheDocument(); + // Select the manual links checkbox + fireEvent.click(getByLabelText(scanResultsMessages.manualLabel.defaultMessage)); + + const collapsibleTrigger = container.querySelector('.collapsible-trigger'); + expect(collapsibleTrigger).toBeInTheDocument(); + fireEvent.click(collapsibleTrigger); + + await waitFor(() => { + expect(getByText('Test Manual Links')).toBeInTheDocument(); + expect(queryByText('Test Broken Links')).not.toBeInTheDocument(); + expect(queryByText('Test Locked Links')).not.toBeInTheDocument(); + }); + }); + + it('should show only manual & locked links when manual & locked Links filters are selected, ignore broken links', async () => { + const { + getByText, + getByLabelText, + queryByText, + container, + } = await setupOptimizerPage(); + // Check if the modal is opened + expect(getByText('Manual')).toBeInTheDocument(); + expect(getByText('Locked')).toBeInTheDocument(); + // Select the manual & locked links checkbox + fireEvent.click(getByLabelText(scanResultsMessages.manualLabel.defaultMessage)); + fireEvent.click(getByLabelText(scanResultsMessages.lockedLabel.defaultMessage)); + + const collapsibleTrigger = container.querySelector('.collapsible-trigger'); + expect(collapsibleTrigger).toBeInTheDocument(); + fireEvent.click(collapsibleTrigger); + + await waitFor(() => { + expect(getByText('Test Manual Links')).toBeInTheDocument(); + expect(getByText('Test Locked Links')).toBeInTheDocument(); + expect(queryByText('Test Broken Links')).not.toBeInTheDocument(); + }); + }); + + it('should show all links when all filters are selected', async () => { + const { + getByText, + getByLabelText, + container, + } = await setupOptimizerPage(); + // Check if the modal is opened + expect(getByText('Broken')).toBeInTheDocument(); + expect(getByText('Manual')).toBeInTheDocument(); + expect(getByText('Locked')).toBeInTheDocument(); + // Select the all checkboxes + fireEvent.click(getByLabelText(scanResultsMessages.brokenLabel.defaultMessage)); + fireEvent.click(getByLabelText(scanResultsMessages.lockedLabel.defaultMessage)); + fireEvent.click(getByLabelText(scanResultsMessages.manualLabel.defaultMessage)); + + const collapsibleTrigger = container.querySelector('.collapsible-trigger'); + expect(collapsibleTrigger).toBeInTheDocument(); + fireEvent.click(collapsibleTrigger); + + await waitFor(() => { + expect(getByText('Test Broken Links')).toBeInTheDocument(); + expect(getByText('Test Manual Links')).toBeInTheDocument(); + expect(getByText('Test Locked Links')).toBeInTheDocument(); + }); + }); }); }); diff --git a/src/optimizer-page/mocks/mockApiResponse.js b/src/optimizer-page/mocks/mockApiResponse.js index 4d425c6e2..339d99648 100644 --- a/src/optimizer-page/mocks/mockApiResponse.js +++ b/src/optimizer-page/mocks/mockApiResponse.js @@ -13,56 +13,40 @@ const mockApiResponse = { units: [ { id: 'unit-1-1-1', - displayName: 'Welcome Video', + displayName: 'Test Broken Links', + blocks: [ + { + id: 'block-1-1-1-5', + url: 'https://example.com/welcome-video', + brokenLinks: ['https://example.com/broken-link-algo1'], + lockedLinks: [], + externalForbiddenLinks: [], + }, + ], + }, + { + id: 'unit-1-1-3', + displayName: 'Test Manual Links', blocks: [ { id: 'block-1-1-1-1', url: 'https://example.com/welcome-video', - brokenLinks: ['https://example.com/broken-link-algo'], - lockedLinks: ['https://example.com/locked-link-algo'], - }, - { - id: 'block-1-1-1-2', - url: 'https://example.com/intro-guide', - brokenLinks: ['https://example.com/broken-link-algo'], - lockedLinks: ['https://example.com/locked-link-algo'], + brokenLinks: [], + lockedLinks: [], externalForbiddenLinks: ['https://outsider.com/forbidden-link-algo'], }, ], }, { id: 'unit-1-1-2', - displayName: 'Course Overview', + displayName: 'Test Locked Links', blocks: [ { id: 'block-1-1-2-1', url: 'https://example.com/course-overview', - brokenLinks: ['https://example.com/broken-link-algo'], - lockedLinks: ['https://example.com/locked-link-algo'], - }, - ], - }, - ], - }, - { - id: 'subsection-1-2', - displayName: 'Basic Concepts', - units: [ - { - id: 'unit-1-2-1', - displayName: 'Variables and Data Types', - blocks: [ - { - id: 'block-1-2-1-1', - url: 'https://example.com/variables', - brokenLinks: ['https://example.com/broken-link-algo'], - lockedLinks: ['https://example.com/locked-link-algo'], - }, - { - id: 'block-1-2-1-2', - url: 'https://example.com/broken-link', - brokenLinks: ['https://example.com/broken-link'], + brokenLinks: [], lockedLinks: ['https://example.com/locked-link-algo'], + externalForbiddenLinks: [], }, ], }, @@ -72,26 +56,60 @@ const mockApiResponse = { }, { id: 'section-2', - displayName: 'Advanced Topics', + displayName: 'Introduction to Programming 2', subsections: [ { - id: 'subsection-2-1', - displayName: 'Algorithms and Data Structures', + id: 'subsection-1-2', + displayName: 'Getting Started 2', units: [ { - id: 'unit-2-1-1', - displayName: 'Sorting Algorithms', + id: 'unit-2-2-2', + displayName: 'unit', blocks: [ { - id: 'block-2-1-1-1', - url: 'https://example.com/sorting-algorithms', - brokenLinks: ['https://example.com/broken-link-algo'], - lockedLinks: ['https://example.com/locked-link-algo'], + id: 'block-1-1-1-6', + url: 'https://example.com/welcome-video', + brokenLinks: ['https://example.com/broken-link-algo1'], + lockedLinks: [], + externalForbiddenLinks: [], }, { - id: 'block-2-1-1-2', - url: 'https://example.com/broken-link-algo', - brokenLinks: ['https://example.com/broken-link-algo'], + id: 'block-1-1-1-6', + url: 'https://example.com/welcome-video', + brokenLinks: ['https://example.com/broken-link-algo1'], + lockedLinks: ['https://example.com/locked-link-algo'], + externalForbiddenLinks: [], + }, + { + id: 'block-1-1-1-6', + url: 'https://example.com/welcome-video', + brokenLinks: ['https://example.com/broken-link-algo1'], + lockedLinks: [], + externalForbiddenLinks: ['https://outsider.com/forbidden-link-algo'], + }, + ], + }, + { + id: 'unit-2-2-3', + displayName: 'unit', + blocks: [ + { + id: 'block-1-1-1-7', + url: 'https://example.com/welcome-video', + brokenLinks: ['https://example.com/broken-link-algo1'], + lockedLinks: [], + externalForbiddenLinks: ['https://outsider.com/forbidden-link-algo'], + }, + ], + }, + { + id: 'unit-2-2-4', + displayName: 'Test Locked Links', + blocks: [ + { + id: 'block-1-1-7-1', + url: 'https://example.com/course-overview', + brokenLinks: ['https://example.com/broken-link-algo1'], lockedLinks: ['https://example.com/locked-link-algo'], externalForbiddenLinks: ['https://outsider.com/forbidden-link-algo'], }, diff --git a/src/optimizer-page/utils.test.js b/src/optimizer-page/utils.test.js index dccd820b8..eadabc8d0 100644 --- a/src/optimizer-page/utils.test.js +++ b/src/optimizer-page/utils.test.js @@ -6,9 +6,9 @@ describe('countBrokenLinks', () => { const data = mockApiResponse.LinkCheckOutput; expect(countBrokenLinks(data)).toStrictEqual( { - brokenLinksCounts: [5, 2], - lockedLinksCounts: [5, 2], - externalForbiddenLinksCounts: [1, 1], + brokenLinksCounts: [1, 5], + lockedLinksCounts: [1, 2], + externalForbiddenLinksCounts: [1, 3], }, ); });