Skip to content

Commit 33fa7c8

Browse files
fix: resolve lint errors and test cases
1 parent fa9194c commit 33fa7c8

File tree

6 files changed

+339
-88
lines changed

6 files changed

+339
-88
lines changed

src/optimizer-page/CourseOptimizerPage.test.js

Lines changed: 107 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,14 @@ import generalMessages from '../messages';
1515
import scanResultsMessages from './scan-results/messages';
1616
import CourseOptimizerPage, { pollLinkCheckDuringScan } from './CourseOptimizerPage';
1717
import { postLinkCheckCourseApiUrl, getLinkCheckStatusApiUrl } from './data/api';
18-
import { mockApiResponse, mockApiResponseForNoResultFound } from './mocks/mockApiResponse';
18+
import {
19+
mockApiResponse,
20+
mockApiResponseForNoResultFound,
21+
mockApiResponseWithPreviousRunLinks,
22+
mockApiResponseEmpty,
23+
} from './mocks/mockApiResponse';
1924
import * as thunks from './data/thunks';
25+
import { useWaffleFlags } from '../data/apiHooks';
2026

2127
let store;
2228
let axiosMock;
@@ -29,6 +35,19 @@ jest.mock('../generic/model-store', () => ({
2935
}),
3036
}));
3137

38+
// Mock the waffle flags hook
39+
jest.mock('../data/apiHooks', () => ({
40+
useWaffleFlags: jest.fn(() => ({
41+
enableCourseOptimizerCheckPrevRunLinks: false,
42+
})),
43+
}));
44+
45+
jest.mock('../generic/model-store', () => ({
46+
useModel: jest.fn().mockReturnValue({
47+
name: 'About Node JS',
48+
}),
49+
}));
50+
3251
const OptimizerPage = () => (
3352
<AppProvider store={store}>
3453
<IntlProvider locale="en" messages={{}}>
@@ -155,7 +174,7 @@ describe('CourseOptimizerPage', () => {
155174
expect(getByText(messages.headingTitle.defaultMessage)).toBeInTheDocument();
156175
fireEvent.click(getByText(messages.buttonTitle.defaultMessage));
157176
await waitFor(() => {
158-
expect(getByText(scanResultsMessages.noBrokenLinksCard.defaultMessage)).toBeInTheDocument();
177+
expect(getByText(scanResultsMessages.noResultsFound.defaultMessage)).toBeInTheDocument();
159178
});
160179
});
161180

@@ -180,7 +199,7 @@ describe('CourseOptimizerPage', () => {
180199
} = await setupOptimizerPage();
181200
// Check if the modal is opened
182201
expect(getByText('Locked')).toBeInTheDocument();
183-
// Select the broken links checkbox
202+
// Select the locked links checkbox
184203
fireEvent.click(getByLabelText(scanResultsMessages.lockedLabel.defaultMessage));
185204

186205
const collapsibleTrigger = container.querySelector('.collapsible-trigger');
@@ -205,7 +224,6 @@ describe('CourseOptimizerPage', () => {
205224
expect(getByText('Broken')).toBeInTheDocument();
206225
// Select the broken links checkbox
207226
fireEvent.click(getByLabelText(scanResultsMessages.brokenLabel.defaultMessage));
208-
209227
const collapsibleTrigger = container.querySelector('.collapsible-trigger');
210228
expect(collapsibleTrigger).toBeInTheDocument();
211229
fireEvent.click(collapsibleTrigger);
@@ -317,14 +335,14 @@ describe('CourseOptimizerPage', () => {
317335
expect(collapsibleTrigger).toBeInTheDocument();
318336
fireEvent.click(collapsibleTrigger);
319337

320-
// Assert that all links are displayed
338+
// Assert that both links are displayed
321339
await waitFor(() => {
322340
expect(getByText('Test Broken Links')).toBeInTheDocument();
323341
expect(getByText('Test Manual Links')).toBeInTheDocument();
324342
expect(queryByText('Test Locked Links')).not.toBeInTheDocument();
325343
});
326344

327-
// Click on the "Broken" chip to filter the results
345+
// Click on the "Broken" chip to remove the broken filter (should leave only manual)
328346
const brokenChip = getByTestId('chip-brokenLinks');
329347
fireEvent.click(brokenChip);
330348

@@ -361,5 +379,88 @@ describe('CourseOptimizerPage', () => {
361379
expect(getByText(scanResultsMessages.noResultsFound.defaultMessage)).toBeInTheDocument();
362380
});
363381
});
382+
383+
it('should always show broken links section header even when no data', async () => {
384+
axiosMock.onGet(getLinkCheckStatusApiUrl(courseId)).reply(200, mockApiResponseEmpty);
385+
const { getByText } = render(<OptimizerPage />);
386+
387+
fireEvent.click(getByText(messages.buttonTitle.defaultMessage));
388+
389+
await waitFor(() => {
390+
expect(getByText(scanResultsMessages.brokenLinksHeader.defaultMessage)).toBeInTheDocument();
391+
expect(getByText(scanResultsMessages.noResultsFound.defaultMessage)).toBeInTheDocument();
392+
});
393+
});
394+
395+
describe('Previous Run Links Feature', () => {
396+
beforeEach(() => {
397+
// Enable the waffle flag for previous run links
398+
useWaffleFlags.mockReturnValue({
399+
enableCourseOptimizerCheckPrevRunLinks: true,
400+
});
401+
});
402+
403+
afterEach(() => {
404+
// Reset to default (disabled)
405+
useWaffleFlags.mockReturnValue({
406+
enableCourseOptimizerCheckPrevRunLinks: false,
407+
});
408+
});
409+
410+
it('should show previous run links section when waffle flag is enabled and links exist', async () => {
411+
axiosMock.onGet(getLinkCheckStatusApiUrl(courseId)).reply(200, mockApiResponseWithPreviousRunLinks);
412+
const { getByText } = render(<OptimizerPage />);
413+
414+
fireEvent.click(getByText(messages.buttonTitle.defaultMessage));
415+
416+
await waitFor(() => {
417+
expect(getByText(scanResultsMessages.linkToPrevCourseRun.defaultMessage)).toBeInTheDocument();
418+
});
419+
});
420+
421+
it('should show no results found for previous run links when flag is enabled but no links exist', async () => {
422+
axiosMock.onGet(getLinkCheckStatusApiUrl(courseId)).reply(200, mockApiResponseForNoResultFound);
423+
const { getByText, getAllByText } = render(<OptimizerPage />);
424+
425+
fireEvent.click(getByText(messages.buttonTitle.defaultMessage));
426+
427+
await waitFor(() => {
428+
expect(getByText(scanResultsMessages.linkToPrevCourseRun.defaultMessage)).toBeInTheDocument();
429+
// Should show "No results found" for previous run section
430+
const noResultsElements = getAllByText(scanResultsMessages.noResultsFound.defaultMessage);
431+
expect(noResultsElements.length).toBeGreaterThan(0);
432+
});
433+
});
434+
435+
it('should not show previous run links section when waffle flag is disabled', async () => {
436+
// Disable the flag
437+
useWaffleFlags.mockReturnValue({
438+
enableCourseOptimizerCheckPrevRunLinks: false,
439+
});
440+
441+
axiosMock.onGet(getLinkCheckStatusApiUrl(courseId)).reply(200, mockApiResponseWithPreviousRunLinks);
442+
const { getByText, queryByText } = render(<OptimizerPage />);
443+
444+
fireEvent.click(getByText(messages.buttonTitle.defaultMessage));
445+
446+
await waitFor(() => {
447+
expect(queryByText(scanResultsMessages.linkToPrevCourseRun.defaultMessage)).not.toBeInTheDocument();
448+
});
449+
});
450+
451+
it('should handle previous run links in course updates and custom pages', async () => {
452+
axiosMock.onGet(getLinkCheckStatusApiUrl(courseId)).reply(200, mockApiResponseWithPreviousRunLinks);
453+
const { getByText, container } = render(<OptimizerPage />);
454+
455+
fireEvent.click(getByText(messages.buttonTitle.defaultMessage));
456+
457+
await waitFor(() => {
458+
expect(getByText(scanResultsMessages.linkToPrevCourseRun.defaultMessage)).toBeInTheDocument();
459+
460+
const prevRunSections = container.querySelectorAll('.scan-results');
461+
expect(prevRunSections.length).toBeGreaterThan(1);
462+
});
463+
});
464+
});
364465
});
365466
});

src/optimizer-page/CourseOptimizerPage.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ const CourseOptimizerPage: FC<{ courseId: string }> = ({ courseId }) => {
151151
size="md"
152152
className="px-4 rounded-0 scan-course-btn"
153153
onClick={() => dispatch(startLinkCheck(courseId))}
154-
disabled={linkCheckInProgress && !errorMessage}
154+
disabled={(!!linkCheckInProgress) && !errorMessage}
155155
>
156156
{linkCheckInProgress && !errorMessage ? (
157157
<>

src/optimizer-page/mocks/mockApiResponse.js

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export const mockApiResponse = {
2121
brokenLinks: ['https://example.com/broken-link-algo1'],
2222
lockedLinks: [],
2323
externalForbiddenLinks: [],
24+
previousRunLinks: [],
2425
},
2526
],
2627
},
@@ -34,6 +35,7 @@ export const mockApiResponse = {
3435
brokenLinks: [],
3536
lockedLinks: [],
3637
externalForbiddenLinks: ['https://outsider.com/forbidden-link-algo'],
38+
previousRunLinks: [],
3739
},
3840
],
3941
},
@@ -47,6 +49,7 @@ export const mockApiResponse = {
4749
brokenLinks: [],
4850
lockedLinks: ['https://example.com/locked-link-algo'],
4951
externalForbiddenLinks: [],
52+
previousRunLinks: [],
5053
},
5154
],
5255
},
@@ -72,20 +75,23 @@ export const mockApiResponse = {
7275
brokenLinks: ['https://example.com/broken-link-algo1'],
7376
lockedLinks: [],
7477
externalForbiddenLinks: [],
78+
previousRunLinks: [],
7579
},
7680
{
7781
id: 'block-1-1-1-6',
7882
url: 'https://example.com/welcome-video',
7983
brokenLinks: ['https://example.com/broken-link-algo1'],
8084
lockedLinks: ['https://example.com/locked-link-algo'],
8185
externalForbiddenLinks: [],
86+
previousRunLinks: [],
8287
},
8388
{
8489
id: 'block-1-1-1-6',
8590
url: 'https://example.com/welcome-video',
8691
brokenLinks: ['https://example.com/broken-link-algo1'],
8792
lockedLinks: [],
8893
externalForbiddenLinks: ['https://outsider.com/forbidden-link-algo'],
94+
previousRunLinks: [],
8995
},
9096
],
9197
},
@@ -99,6 +105,7 @@ export const mockApiResponse = {
99105
brokenLinks: ['https://example.com/broken-link-algo1'],
100106
lockedLinks: [],
101107
externalForbiddenLinks: ['https://outsider.com/forbidden-link-algo'],
108+
previousRunLinks: [],
102109
},
103110
],
104111
},
@@ -112,6 +119,7 @@ export const mockApiResponse = {
112119
brokenLinks: ['https://example.com/broken-link-algo1'],
113120
lockedLinks: ['https://example.com/locked-link-algo'],
114121
externalForbiddenLinks: ['https://outsider.com/forbidden-link-algo'],
122+
previousRunLinks: [],
115123
},
116124
],
117125
},
@@ -120,6 +128,28 @@ export const mockApiResponse = {
120128
],
121129
},
122130
],
131+
course_updates: [
132+
{
133+
id: 'update-1',
134+
displayName: 'Course Update 1',
135+
url: 'https://example.com/course-update-1',
136+
brokenLinks: [],
137+
lockedLinks: [],
138+
externalForbiddenLinks: [],
139+
previousRunLinks: [],
140+
},
141+
],
142+
custom_pages: [
143+
{
144+
id: 'custom-1',
145+
displayName: 'About Page',
146+
url: 'https://example.com/about',
147+
brokenLinks: [],
148+
lockedLinks: [],
149+
externalForbiddenLinks: [],
150+
previousRunLinks: [],
151+
},
152+
],
123153
},
124154
};
125155

@@ -146,6 +176,42 @@ export const mockApiResponseForNoResultFound = {
146176
brokenLinks: ['https://example.com/broken-link-algo1'],
147177
lockedLinks: [],
148178
externalForbiddenLinks: [],
179+
previousRunLinks: [],
180+
},
181+
],
182+
},
183+
],
184+
},
185+
],
186+
},
187+
],
188+
},
189+
};
190+
191+
export const mockApiResponseWithPreviousRunLinks = {
192+
LinkCheckStatus: 'Succeeded',
193+
LinkCheckCreatedAt: '2024-12-14T00:26:50.838350Z',
194+
LinkCheckOutput: {
195+
sections: [
196+
{
197+
id: 'section-1',
198+
displayName: 'Introduction to Programming',
199+
subsections: [
200+
{
201+
id: 'subsection-1-1',
202+
displayName: 'Getting Started',
203+
units: [
204+
{
205+
id: 'unit-1-1-1',
206+
displayName: 'Test Previous Run Links',
207+
blocks: [
208+
{
209+
id: 'block-1-1-1-5',
210+
url: 'https://example.com/welcome-video',
211+
brokenLinks: [],
212+
lockedLinks: [],
213+
externalForbiddenLinks: [],
214+
previousRunLinks: ['https://example.com/old-course-run/content'],
149215
},
150216
],
151217
},
@@ -154,5 +220,37 @@ export const mockApiResponseForNoResultFound = {
154220
],
155221
},
156222
],
223+
course_updates: [
224+
{
225+
id: 'update-1',
226+
displayName: 'Course Update with Previous Run Link',
227+
url: 'https://example.com/course-update-1',
228+
brokenLinks: [],
229+
lockedLinks: [],
230+
externalForbiddenLinks: [],
231+
previousRunLinks: ['https://example.com/old-course-run/update'],
232+
},
233+
],
234+
custom_pages: [
235+
{
236+
id: 'custom-2',
237+
displayName: 'About Page with Previous Run',
238+
url: 'https://example.com/about',
239+
brokenLinks: [],
240+
lockedLinks: [],
241+
externalForbiddenLinks: [],
242+
previousRunLinks: ['https://example.com/old-course-run/about'],
243+
},
244+
],
245+
},
246+
};
247+
248+
export const mockApiResponseEmpty = {
249+
LinkCheckStatus: 'Succeeded',
250+
LinkCheckCreatedAt: '2024-12-14T00:26:50.838350Z',
251+
LinkCheckOutput: {
252+
sections: [],
253+
course_updates: [],
254+
custom_pages: [],
157255
},
158256
};

0 commit comments

Comments
 (0)