1- import { getConfig , setConfig } from '@edx/frontend-platform' ;
1+ import { getConfig } from '@edx/frontend-platform' ;
22import { cloneDeep } from 'lodash' ;
33import { closestCorners } from '@dnd-kit/core' ;
44import { logError } from '@edx/frontend-platform/logging' ;
@@ -9,8 +9,7 @@ import { executeThunk } from '@src/utils';
99import configureModalMessages from '@src/generic/configure-modal/messages' ;
1010import pasteButtonMessages from '@src/generic/clipboard/paste-component/messages' ;
1111import { getApiBaseUrl , getClipboardUrl } from '@src/generic/data/api' ;
12- import { postXBlockBaseApiUrl } from '@src/course-unit/data/api' ;
13- import { COMPONENT_TYPES } from '@src/generic/block-type-utils/constants' ;
12+ import { ContainerType } from '@src/generic/key-utils' ;
1413import { getDownstreamApiUrl } from '@src/generic/unlink-modal/data/api' ;
1514import { CourseAuthoringProvider } from '@src/CourseAuthoringContext' ;
1615import {
@@ -31,7 +30,8 @@ import {
3130 getCourseBestPracticesApiUrl ,
3231 getCourseLaunchApiUrl ,
3332 getCourseOutlineIndexApiUrl ,
34- getCourseReindexApiUrl ,
33+ // FIXME: reindex is not used
34+ // getCourseReindexApiUrl,
3535 getXBlockApiUrl ,
3636 getCourseBlockApiUrl ,
3737 getCourseItemApiUrl ,
@@ -53,14 +53,13 @@ import {
5353 courseSectionMock ,
5454 courseSubsectionMock ,
5555} from './__mocks__' ;
56- import { COURSE_BLOCK_NAMES , VIDEO_SHARING_OPTIONS } from './constants' ;
56+ import { COURSE_BLOCK_NAMES } from './constants' ;
5757import CourseOutline from './CourseOutline' ;
5858
5959import messages from './messages' ;
6060import headerMessages from './header-navigations/messages' ;
6161import cardHeaderMessages from './card-header/messages' ;
6262import enableHighlightsModalMessages from './enable-highlights-modal/messages' ;
63- import statusBarMessages from './status-bar/messages' ;
6463import subsectionMessages from './subsection-card/messages' ;
6564import pageAlertMessages from './page-alerts/messages' ;
6665import {
@@ -74,9 +73,8 @@ let axiosMock: import('axios-mock-adapter/types');
7473let store ;
7574const mockPathname = '/foo-bar' ;
7675const courseId = '123' ;
77- const getContainerKey = jest . fn ( ) . mockReturnValue ( 'lct:org:lib:unit:1' ) ;
78- const getContainerType = jest . fn ( ) . mockReturnValue ( 'unit' ) ;
7976const clearSelection = jest . fn ( ) ;
77+ const startCurrentFlow = jest . fn ( ) ;
8078let selectedContainerId : string | undefined ;
8179let courseOutlineIndexMock = cloneDeep ( originalCourseOutlineIndexMock ) ;
8280
@@ -85,6 +83,7 @@ jest.mock('@src/course-outline/outline-sidebar/OutlineSidebarContext', () => ({
8583 ...jest . requireActual ( '@src/course-outline/outline-sidebar/OutlineSidebarContext' ) ,
8684 useOutlineSidebarContext : ( ) => ( {
8785 ...jest . requireActual ( '@src/course-outline/outline-sidebar/OutlineSidebarContext' ) . useOutlineSidebarContext ( ) ,
86+ startCurrentFlow,
8887 clearSelection,
8988 selectedContainerState : ( ( ) => ( selectedContainerId ? { currentId : selectedContainerId } : undefined ) ) ( ) ,
9089 } ) ,
@@ -109,24 +108,6 @@ jest.mock('./data/api', () => ({
109108 getTagsCount : ( ) => jest . fn ( ) . mockResolvedValue ( { } ) ,
110109} ) ) ;
111110
112- // Mock LibraryAndComponentPicker to call onComponentSelected on click
113- jest . mock ( '@src/library-authoring/component-picker' , ( ) => ( {
114- LibraryAndComponentPicker : ( props ) => {
115- const onClick = ( ) => {
116- // eslint-disable-next-line react/prop-types
117- props . onComponentSelected ( {
118- usageKey : getContainerKey ( ) ,
119- blockType : getContainerType ( ) ,
120- } ) ;
121- } ;
122- return (
123- < button type = "submit" onClick = { onClick } >
124- Dummy button
125- </ button >
126- ) ;
127- } ,
128- } ) ) ;
129-
130111jest . mock ( '@edx/frontend-platform/logging' , ( ) => ( {
131112 logError : jest . fn ( ) ,
132113} ) ) ;
@@ -250,6 +231,7 @@ describe('<CourseOutline />', () => {
250231 expect ( queryByRole ( 'button' , { name : 'Dismiss' } ) ) . not . toBeInTheDocument ( ) ;
251232 } ) ;
252233
234+ /* FIXME: reindex is missing/was moved
253235 it('check reindex and render success alert is correctly', async () => {
254236 const { findByText, findByTestId } = renderComponent();
255237
@@ -262,59 +244,6 @@ describe('<CourseOutline />', () => {
262244 expect(await findByText(messages.alertSuccessDescription.defaultMessage)).toBeInTheDocument();
263245 });
264246
265- it ( 'check video sharing option udpates correctly' , async ( ) => {
266- const { findByLabelText } = renderComponent ( ) ;
267-
268- axiosMock
269- . onPost ( getCourseBlockApiUrl ( courseId ) , {
270- metadata : {
271- video_sharing_options : VIDEO_SHARING_OPTIONS . allOff ,
272- } ,
273- } )
274- . reply ( 200 ) ;
275- const optionDropdown = await findByLabelText ( statusBarMessages . videoSharingTitle . defaultMessage ) ;
276- await act (
277- async ( ) => fireEvent . change ( optionDropdown , { target : { value : VIDEO_SHARING_OPTIONS . allOff } } ) ,
278- ) ;
279-
280- expect ( axiosMock . history . post . length ) . toBe ( 3 ) ;
281- expect ( axiosMock . history . post [ 2 ] . data ) . toBe ( JSON . stringify ( {
282- metadata : {
283- video_sharing_options : VIDEO_SHARING_OPTIONS . allOff ,
284- } ,
285- } ) ) ;
286- } ) ;
287-
288- it ( 'check video sharing option shows error on failure' , async ( ) => {
289- renderComponent ( ) ;
290-
291- axiosMock
292- . onPost ( getCourseBlockApiUrl ( courseId ) , {
293- metadata : {
294- video_sharing_options : VIDEO_SHARING_OPTIONS . allOff ,
295- } ,
296- } )
297- . reply ( 500 ) ;
298- const optionDropdown = await screen . findByLabelText ( statusBarMessages . videoSharingTitle . defaultMessage ) ;
299- await act (
300- async ( ) => fireEvent . change ( optionDropdown , { target : { value : VIDEO_SHARING_OPTIONS . allOff } } ) ,
301- ) ;
302-
303- expect ( axiosMock . history . post . length ) . toBe ( 3 ) ;
304- expect ( axiosMock . history . post [ 2 ] . data ) . toBe ( JSON . stringify ( {
305- metadata : {
306- video_sharing_options : VIDEO_SHARING_OPTIONS . allOff ,
307- } ,
308- } ) ) ;
309-
310- const alertElements = screen . queryAllByRole ( 'alert' ) ;
311- expect ( alertElements . find (
312- ( el ) => el . classList . contains ( 'alert-content' ) ,
313- ) ) . toHaveTextContent (
314- 'Unable to save changes. Please try again.' ,
315- ) ;
316- } ) ;
317-
318247 it('render error alert after failed reindex correctly', async () => {
319248 const { findByText, findByTestId } = renderComponent();
320249
@@ -326,6 +255,7 @@ describe('<CourseOutline />', () => {
326255
327256 expect(await findByText('Request failed with status code 500')).toBeInTheDocument();
328257 });
258+ */
329259
330260 it ( 'check that new section list is saved when dragged' , async ( ) => {
331261 const { findAllByRole, findByTestId } = renderComponent ( ) ;
@@ -480,118 +410,66 @@ describe('<CourseOutline />', () => {
480410 } ) ;
481411
482412 it ( 'adds a unit from library correctly' , async ( ) => {
483- getContainerKey . mockReturnValue ( 'lct:org:lib:unit:1' ) ;
484- getContainerKey . mockReturnValue ( 'unit' ) ;
413+ const user = userEvent . setup ( ) ;
485414 renderComponent ( ) ;
486415 const [ sectionElement ] = await screen . findAllByTestId ( 'section-card' ) ;
487416 const [ subsectionElement ] = await within ( sectionElement ) . findAllByTestId ( 'subsection-card' ) ;
488417 const units = await within ( subsectionElement ) . findAllByTestId ( 'unit-card' ) ;
489418 expect ( units . length ) . toBe ( 1 ) ;
490419
491- axiosMock
492- . onPost ( postXBlockBaseApiUrl ( ) )
493- . reply ( 200 , {
494- locator : 'block-v1:UNIX+UX1+2025_T3+type@vertical+block@vertical1e842129' ,
495- parent_locator : 'parent' ,
496- } ) ;
497-
498420 const addUnitFromLibraryButton = within ( subsectionElement ) . getByRole ( 'button' , {
499421 name : / u s e u n i t f r o m l i b r a r y / i,
500422 } ) ;
501- fireEvent . click ( addUnitFromLibraryButton ) ;
502-
503- // click dummy button to execute onComponentSelected prop.
504- const dummyBtn = await screen . findByRole ( 'button' , { name : 'Dummy button' } ) ;
505- fireEvent . click ( dummyBtn ) ;
506-
507- await waitFor ( ( ) => expect ( axiosMock . history . post . length ) . toBe ( 3 ) ) ;
423+ await user . click ( addUnitFromLibraryButton ) ;
508424
425+ // Start the add existing unit flow
509426 const [ section ] = courseOutlineIndexMock . courseStructure . childInfo . children ;
510427 const [ subsection ] = section . childInfo . children ;
511- await waitFor ( ( ) => {
512- expect ( axiosMock . history . post [ 2 ] . data ) . toBe ( JSON . stringify ( {
513- type : COMPONENT_TYPES . libraryV2 ,
514- category : 'vertical' ,
515- parent_locator : subsection . id ,
516- library_content_key : getContainerKey ( ) ,
517- } ) ) ;
428+ expect ( startCurrentFlow ) . toHaveBeenCalledWith ( {
429+ flowType : ContainerType . Unit ,
430+ parentLocator : subsection . id ,
431+ grandParentLocator : section . id ,
518432 } ) ;
519433 } ) ;
520434
521435 it ( 'adds a subsection from library correctly' , async ( ) => {
522- getContainerKey . mockReturnValue ( 'lct:org:lib:subsection:1' ) ;
523- getContainerKey . mockReturnValue ( 'subsection' ) ;
436+ const user = userEvent . setup ( ) ;
524437 renderComponent ( ) ;
525438 const [ sectionElement ] = await screen . findAllByTestId ( 'section-card' ) ;
526439 const subsections = await within ( sectionElement ) . findAllByTestId ( 'subsection-card' ) ;
527440 expect ( subsections . length ) . toBe ( 2 ) ;
528441
529- axiosMock
530- . onPost ( postXBlockBaseApiUrl ( ) )
531- . reply ( 200 , {
532- locator : 'block-v1:UNIX+UX1+2025_T3+type@sequential+block@sequential45d4d95a' ,
533- parent_locator : 'block-v1:UNIX+UX1+2025_T3+type@chapter+block@chaptersda1' ,
534- } ) ;
535-
536442 const addSubsectionFromLibraryButton = within ( sectionElement ) . getByRole ( 'button' , {
537443 name : / u s e s u b s e c t i o n f r o m l i b r a r y / i,
538444 } ) ;
539- fireEvent . click ( addSubsectionFromLibraryButton ) ;
540-
541- // click dummy button to execute onComponentSelected prop.
542- const dummyBtn = await screen . findByRole ( 'button' , { name : 'Dummy button' } ) ;
543- fireEvent . click ( dummyBtn ) ;
544-
545- await waitFor ( ( ) => expect ( axiosMock . history . post . length ) . toBe ( 3 ) ) ;
445+ await user . click ( addSubsectionFromLibraryButton ) ;
546446
447+ // Start the add existing subsection flow
547448 const [ section ] = courseOutlineIndexMock . courseStructure . childInfo . children ;
548- await waitFor ( ( ) => {
549- expect ( axiosMock . history . post [ 2 ] . data ) . toBe ( JSON . stringify ( {
550- type : COMPONENT_TYPES . libraryV2 ,
551- category : 'sequential' ,
552- parent_locator : section . id ,
553- library_content_key : getContainerKey ( ) ,
554- } ) ) ;
449+ expect ( startCurrentFlow ) . toHaveBeenCalledWith ( {
450+ flowType : ContainerType . Subsection ,
451+ parentLocator : section . id ,
452+ grandParentLocator : undefined ,
555453 } ) ;
556454 } ) ;
557455
558456 it ( 'adds a section from library correctly' , async ( ) => {
559457 const user = userEvent . setup ( ) ;
560- getContainerKey . mockReturnValue ( 'lct:org:lib:section:1' ) ;
561- getContainerKey . mockReturnValue ( 'section' ) ;
562458 renderComponent ( ) ;
563459 const sections = await screen . findAllByTestId ( 'section-card' ) ;
564460 expect ( sections . length ) . toBe ( 4 ) ;
565461
566- axiosMock
567- . onPost ( postXBlockBaseApiUrl ( ) )
568- . reply ( 200 , {
569- locator : 'block-v1:UNIX+UX1+2025_T3+type@chapter+block@chaptersdafdd' ,
570- courseKey : 'course-v1:UNIX+UX1+2025_T3' ,
571- } ) ;
572- axiosMock
573- . onGet ( getXBlockApiUrl ( 'block-v1:UNIX+UX1+2025_T3+type@chapter+block@chaptersdafdd' ) )
574- . reply ( 200 , courseSectionMock ) ;
575-
576462 const addSectionFromLibraryButton = await screen . findByRole ( 'button' , {
577463 name : / u s e s e c t i o n f r o m l i b r a r y / i,
578464 } ) ;
579465 await user . click ( addSectionFromLibraryButton ) ;
580466
581- // click dummy button to execute onComponentSelected prop.
582- const dummyBtn = await screen . findByRole ( 'button' , { name : 'Dummy button' } ) ;
583- fireEvent . click ( dummyBtn ) ;
584-
585- await waitFor ( ( ) => expect ( axiosMock . history . post . length ) . toBe ( 3 ) ) ;
586-
587- const courseUsageKey = courseOutlineIndexMock . courseStructure . id ;
588- await waitFor ( ( ) => {
589- expect ( axiosMock . history . post [ 2 ] . data ) . toBe ( JSON . stringify ( {
590- type : COMPONENT_TYPES . libraryV2 ,
591- category : 'chapter' ,
592- parent_locator : courseUsageKey ,
593- library_content_key : getContainerKey ( ) ,
594- } ) ) ;
467+ // Start the add existring section flow
468+ const courseBlockId = courseOutlineIndexMock . courseStructure . id ;
469+ expect ( startCurrentFlow ) . toHaveBeenCalledWith ( {
470+ flowType : ContainerType . Section ,
471+ parentLocator : courseBlockId ,
472+ grandParentLocator : undefined ,
595473 } ) ;
596474 } ) ;
597475
@@ -820,6 +698,7 @@ describe('<CourseOutline />', () => {
820698 } ) ;
821699
822700 it ( 'check whether section, subsection and unit is deleted when corresponding delete button is clicked' , async ( ) => {
701+ const user = userEvent . setup ( ) ;
823702 renderComponent ( ) ;
824703 // get section, subsection and unit
825704 const [ section ] = courseOutlineIndexMock . courseStructure . childInfo . children ;
@@ -831,22 +710,18 @@ describe('<CourseOutline />', () => {
831710 selectedContainerId = section . id ;
832711
833712 const checkDeleteBtn = async ( item , element , elementName ) => {
834- await waitFor ( ( ) => {
835- expect ( screen . queryByText ( item . displayName ) ) . toBeInTheDocument ( ) ;
836- } ) ;
713+ expect ( within ( element ) . getByText ( item . displayName ) ) . toBeInTheDocument ( ) ;
837714
838715 axiosMock . onDelete ( getCourseItemApiUrl ( item . id ) ) . reply ( 200 ) ;
839716
840717 const menu = await within ( element ) . findByTestId ( `${ elementName } -card-header__menu-button` ) ;
841- fireEvent . click ( menu ) ;
718+ await user . click ( menu ) ;
842719 const deleteButton = await within ( element ) . findByTestId ( `${ elementName } -card-header__menu-delete-button` ) ;
843- fireEvent . click ( deleteButton ) ;
720+ await user . click ( deleteButton ) ;
844721 const confirmButton = await screen . findByRole ( 'button' , { name : 'Delete' } ) ;
845- fireEvent . click ( confirmButton ) ;
722+ await user . click ( confirmButton ) ;
846723
847- await waitFor ( ( ) => {
848- expect ( screen . queryByText ( item . displayName ) ) . not . toBeInTheDocument ( ) ;
849- } ) ;
724+ expect ( element ) . not . toBeInTheDocument ( ) ;
850725 } ;
851726
852727 // delete unit, subsection and then section in order.
@@ -2614,10 +2489,6 @@ describe('<CourseOutline />', () => {
26142489 } ) ;
26152490
26162491 it ( 'check that the new status bar and expand bar is shown when flag is set' , async ( ) => {
2617- setConfig ( {
2618- ...getConfig ( ) ,
2619- ENABLE_COURSE_OUTLINE_NEW_DESIGN : 'true' ,
2620- } ) ;
26212492 renderComponent ( ) ;
26222493 const btn = await screen . findByRole ( 'button' , { name : 'Collapse all' } ) ;
26232494 expect ( btn ) . toBeInTheDocument ( ) ;
0 commit comments