@@ -15,8 +15,14 @@ import generalMessages from '../messages';
15
15
import scanResultsMessages from './scan-results/messages' ;
16
16
import CourseOptimizerPage , { pollLinkCheckDuringScan } from './CourseOptimizerPage' ;
17
17
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' ;
19
24
import * as thunks from './data/thunks' ;
25
+ import { useWaffleFlags } from '../data/apiHooks' ;
20
26
21
27
let store ;
22
28
let axiosMock ;
@@ -29,6 +35,19 @@ jest.mock('../generic/model-store', () => ({
29
35
} ) ,
30
36
} ) ) ;
31
37
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
+
32
51
const OptimizerPage = ( ) => (
33
52
< AppProvider store = { store } >
34
53
< IntlProvider locale = "en" messages = { { } } >
@@ -155,7 +174,7 @@ describe('CourseOptimizerPage', () => {
155
174
expect ( getByText ( messages . headingTitle . defaultMessage ) ) . toBeInTheDocument ( ) ;
156
175
fireEvent . click ( getByText ( messages . buttonTitle . defaultMessage ) ) ;
157
176
await waitFor ( ( ) => {
158
- expect ( getByText ( scanResultsMessages . noBrokenLinksCard . defaultMessage ) ) . toBeInTheDocument ( ) ;
177
+ expect ( getByText ( scanResultsMessages . noDataCard . defaultMessage ) ) . toBeInTheDocument ( ) ;
159
178
} ) ;
160
179
} ) ;
161
180
@@ -180,7 +199,7 @@ describe('CourseOptimizerPage', () => {
180
199
} = await setupOptimizerPage ( ) ;
181
200
// Check if the modal is opened
182
201
expect ( getByText ( 'Locked' ) ) . toBeInTheDocument ( ) ;
183
- // Select the broken links checkbox
202
+ // Select the locked links checkbox
184
203
fireEvent . click ( getByLabelText ( scanResultsMessages . lockedLabel . defaultMessage ) ) ;
185
204
186
205
const collapsibleTrigger = container . querySelector ( '.collapsible-trigger' ) ;
@@ -205,7 +224,6 @@ describe('CourseOptimizerPage', () => {
205
224
expect ( getByText ( 'Broken' ) ) . toBeInTheDocument ( ) ;
206
225
// Select the broken links checkbox
207
226
fireEvent . click ( getByLabelText ( scanResultsMessages . brokenLabel . defaultMessage ) ) ;
208
-
209
227
const collapsibleTrigger = container . querySelector ( '.collapsible-trigger' ) ;
210
228
expect ( collapsibleTrigger ) . toBeInTheDocument ( ) ;
211
229
fireEvent . click ( collapsibleTrigger ) ;
@@ -317,14 +335,14 @@ describe('CourseOptimizerPage', () => {
317
335
expect ( collapsibleTrigger ) . toBeInTheDocument ( ) ;
318
336
fireEvent . click ( collapsibleTrigger ) ;
319
337
320
- // Assert that all links are displayed
338
+ // Assert that both links are displayed
321
339
await waitFor ( ( ) => {
322
340
expect ( getByText ( 'Test Broken Links' ) ) . toBeInTheDocument ( ) ;
323
341
expect ( getByText ( 'Test Manual Links' ) ) . toBeInTheDocument ( ) ;
324
342
expect ( queryByText ( 'Test Locked Links' ) ) . not . toBeInTheDocument ( ) ;
325
343
} ) ;
326
344
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)
328
346
const brokenChip = getByTestId ( 'chip-brokenLinks' ) ;
329
347
fireEvent . click ( brokenChip ) ;
330
348
@@ -361,5 +379,87 @@ describe('CourseOptimizerPage', () => {
361
379
expect ( getByText ( scanResultsMessages . noResultsFound . defaultMessage ) ) . toBeInTheDocument ( ) ;
362
380
} ) ;
363
381
} ) ;
382
+
383
+ it ( 'should always show no scan data message when data is empty' , 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 . noDataCard . defaultMessage ) ) . toBeInTheDocument ( ) ;
391
+ } ) ;
392
+ } ) ;
393
+
394
+ describe ( 'Previous Run Links Feature' , ( ) => {
395
+ beforeEach ( ( ) => {
396
+ // Enable the waffle flag for previous run links
397
+ useWaffleFlags . mockReturnValue ( {
398
+ enableCourseOptimizerCheckPrevRunLinks : true ,
399
+ } ) ;
400
+ } ) ;
401
+
402
+ afterEach ( ( ) => {
403
+ // Reset to default (disabled)
404
+ useWaffleFlags . mockReturnValue ( {
405
+ enableCourseOptimizerCheckPrevRunLinks : false ,
406
+ } ) ;
407
+ } ) ;
408
+
409
+ it ( 'should show previous run links section when waffle flag is enabled and links exist' , async ( ) => {
410
+ axiosMock . onGet ( getLinkCheckStatusApiUrl ( courseId ) ) . reply ( 200 , mockApiResponseWithPreviousRunLinks ) ;
411
+ const { getByText } = render ( < OptimizerPage /> ) ;
412
+
413
+ fireEvent . click ( getByText ( messages . buttonTitle . defaultMessage ) ) ;
414
+
415
+ await waitFor ( ( ) => {
416
+ expect ( getByText ( scanResultsMessages . linkToPrevCourseRun . defaultMessage ) ) . toBeInTheDocument ( ) ;
417
+ } ) ;
418
+ } ) ;
419
+
420
+ it ( 'should show no results found for previous run links when flag is enabled but no links exist' , async ( ) => {
421
+ axiosMock . onGet ( getLinkCheckStatusApiUrl ( courseId ) ) . reply ( 200 , mockApiResponseForNoResultFound ) ;
422
+ const { getByText, getAllByText } = render ( < OptimizerPage /> ) ;
423
+
424
+ fireEvent . click ( getByText ( messages . buttonTitle . defaultMessage ) ) ;
425
+
426
+ await waitFor ( ( ) => {
427
+ expect ( getByText ( scanResultsMessages . linkToPrevCourseRun . defaultMessage ) ) . toBeInTheDocument ( ) ;
428
+ // Should show "No results found" for previous run section
429
+ const noResultsElements = getAllByText ( scanResultsMessages . noResultsFound . defaultMessage ) ;
430
+ expect ( noResultsElements . length ) . toBeGreaterThan ( 0 ) ;
431
+ } ) ;
432
+ } ) ;
433
+
434
+ it ( 'should not show previous run links section when waffle flag is disabled' , async ( ) => {
435
+ // Disable the flag
436
+ useWaffleFlags . mockReturnValue ( {
437
+ enableCourseOptimizerCheckPrevRunLinks : false ,
438
+ } ) ;
439
+
440
+ axiosMock . onGet ( getLinkCheckStatusApiUrl ( courseId ) ) . reply ( 200 , mockApiResponseWithPreviousRunLinks ) ;
441
+ const { getByText, queryByText } = render ( < OptimizerPage /> ) ;
442
+
443
+ fireEvent . click ( getByText ( messages . buttonTitle . defaultMessage ) ) ;
444
+
445
+ await waitFor ( ( ) => {
446
+ expect ( queryByText ( scanResultsMessages . linkToPrevCourseRun . defaultMessage ) ) . not . toBeInTheDocument ( ) ;
447
+ } ) ;
448
+ } ) ;
449
+
450
+ it ( 'should handle previous run links in course updates and custom pages' , async ( ) => {
451
+ axiosMock . onGet ( getLinkCheckStatusApiUrl ( courseId ) ) . reply ( 200 , mockApiResponseWithPreviousRunLinks ) ;
452
+ const { getByText, container } = render ( < OptimizerPage /> ) ;
453
+
454
+ fireEvent . click ( getByText ( messages . buttonTitle . defaultMessage ) ) ;
455
+
456
+ await waitFor ( ( ) => {
457
+ expect ( getByText ( scanResultsMessages . linkToPrevCourseRun . defaultMessage ) ) . toBeInTheDocument ( ) ;
458
+
459
+ const prevRunSections = container . querySelectorAll ( '.scan-results' ) ;
460
+ expect ( prevRunSections . length ) . toBeGreaterThan ( 1 ) ;
461
+ } ) ;
462
+ } ) ;
463
+ } ) ;
364
464
} ) ;
365
465
} ) ;
0 commit comments