1
1
import React from 'react' ;
2
2
import { Factory } from 'rosie' ;
3
+ import { getConfig } from '@edx/frontend-platform' ;
4
+ import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth' ;
5
+ import MockAdapter from 'axios-mock-adapter' ;
3
6
import { breakpoints } from '@edx/paragon' ;
4
7
import {
5
- fireEvent , getByRole , initializeTestStore , loadUnit , render , screen , waitFor ,
8
+ act , fireEvent , getByRole , initializeTestStore , loadUnit , render , screen , waitFor ,
6
9
} from '../../setupTest' ;
10
+ import { buildTopicsFromUnits } from '../data/__factories__/discussionTopics.factory' ;
7
11
import { handleNextSectionCelebration } from './celebration' ;
8
12
import * as celebrationUtils from './celebration/utils' ;
9
13
import Course from './Course' ;
14
+ import { executeThunk } from '../../utils' ;
15
+ import * as thunks from '../data/thunks' ;
10
16
11
17
jest . mock ( '@edx/frontend-platform/analytics' ) ;
12
18
@@ -43,6 +49,28 @@ describe('Course', () => {
43
49
setItemSpy . mockRestore ( ) ;
44
50
} ) ;
45
51
52
+ const setupDiscussionSidebar = async ( storageValue = false ) => {
53
+ localStorage . clear ( ) ;
54
+ const testStore = await initializeTestStore ( { provider : 'openedx' } ) ;
55
+ const state = testStore . getState ( ) ;
56
+ const { courseware : { courseId } } = state ;
57
+ const axiosMock = new MockAdapter ( getAuthenticatedHttpClient ( ) ) ;
58
+ axiosMock . onGet ( `${ getConfig ( ) . LMS_BASE_URL } /api/discussion/v1/courses/${ courseId } ` ) . reply ( 200 , { provider : 'openedx' } ) ;
59
+ const topicsResponse = buildTopicsFromUnits ( state . models . units ) ;
60
+ axiosMock . onGet ( `${ getConfig ( ) . LMS_BASE_URL } /api/discussion/v2/course_topics/${ courseId } ` )
61
+ . reply ( 200 , topicsResponse ) ;
62
+
63
+ await executeThunk ( thunks . getCourseDiscussionTopics ( courseId ) , testStore . dispatch ) ;
64
+ const [ firstUnitId ] = Object . keys ( state . models . units ) ;
65
+ mockData . unitId = firstUnitId ;
66
+ const [ firstSequenceId ] = Object . keys ( state . models . sequences ) ;
67
+ mockData . sequenceId = firstSequenceId ;
68
+ if ( storageValue !== null ) {
69
+ localStorage . setItem ( 'showDiscussionSidebar' , storageValue ) ;
70
+ }
71
+ await render ( < Course { ...mockData } /> , { store : testStore } ) ;
72
+ } ;
73
+
46
74
it ( 'loads learning sequence' , async ( ) => {
47
75
render ( < Course { ...mockData } /> ) ;
48
76
expect ( screen . getByRole ( 'navigation' , { name : 'breadcrumb' } ) ) . toBeInTheDocument ( ) ;
@@ -103,6 +131,7 @@ describe('Course', () => {
103
131
} ) ;
104
132
105
133
it ( 'displays notification trigger and toggles active class on click' , async ( ) => {
134
+ localStorage . setItem ( 'showDiscussionSidebar' , false ) ;
106
135
render ( < Course { ...mockData } /> ) ;
107
136
108
137
const notificationTrigger = screen . getByRole ( 'button' , { name : / S h o w n o t i f i c a t i o n t r a y / i } ) ;
@@ -114,6 +143,7 @@ describe('Course', () => {
114
143
115
144
it ( 'handles click to open/close notification tray' , async ( ) => {
116
145
sessionStorage . clear ( ) ;
146
+ localStorage . setItem ( 'showDiscussionSidebar' , false ) ;
117
147
render ( < Course { ...mockData } /> ) ;
118
148
expect ( sessionStorage . getItem ( `notificationTrayStatus.${ mockData . courseId } ` ) ) . toBe ( '"open"' ) ;
119
149
const notificationShowButton = await screen . findByRole ( 'button' , { name : / S h o w n o t i f i c a t i o n t r a y / i } ) ;
@@ -144,6 +174,7 @@ describe('Course', () => {
144
174
145
175
it ( 'handles sessionStorage from a different course for the notification tray' , async ( ) => {
146
176
sessionStorage . clear ( ) ;
177
+ localStorage . setItem ( 'showDiscussionSidebar' , false ) ;
147
178
const courseMetadataSecondCourse = Factory . build ( 'courseMetadata' , { id : 'second_course' } ) ;
148
179
149
180
// set sessionStorage for a different course before rendering Course
@@ -186,6 +217,34 @@ describe('Course', () => {
186
217
expect ( screen . getByText ( Object . values ( models . sequences ) [ 0 ] . title ) ) . toBeInTheDocument ( ) ;
187
218
} ) ;
188
219
220
+ [
221
+ { value : true , visible : true } ,
222
+ { value : false , visible : false } ,
223
+ { value : null , visible : true } ,
224
+ ] . forEach ( async ( { value, visible } ) => (
225
+ it ( `discussion sidebar is ${ visible ? 'shown' : 'hidden' } when localstorage value is ${ value } ` , async ( ) => {
226
+ await setupDiscussionSidebar ( value ) ;
227
+ const element = await waitFor ( ( ) => screen . findByTestId ( 'sidebar-DISCUSSIONS' ) ) ;
228
+ if ( visible ) {
229
+ expect ( element ) . not . toHaveClass ( 'd-none' ) ;
230
+ } else {
231
+ expect ( element ) . toHaveClass ( 'd-none' ) ;
232
+ }
233
+ } ) ) ) ;
234
+
235
+ [
236
+ { value : true , result : 'false' } ,
237
+ { value : false , result : 'true' } ,
238
+ ] . forEach ( async ( { value, result } ) => (
239
+ it ( `Discussion sidebar storage value is ${ ! value } when sidebar is ${ value ? 'closed' : 'open' } ` , async ( ) => {
240
+ await setupDiscussionSidebar ( value ) ;
241
+ await act ( async ( ) => {
242
+ const button = await screen . queryByRole ( 'button' , { name : / S h o w d i s c u s s i o n s t r a y / i } ) ;
243
+ button . click ( ) ;
244
+ } ) ;
245
+ expect ( localStorage . getItem ( 'showDiscussionSidebar' ) ) . toBe ( result ) ;
246
+ } ) ) ) ;
247
+
189
248
it ( 'passes handlers to the sequence' , async ( ) => {
190
249
const nextSequenceHandler = jest . fn ( ) ;
191
250
const previousSequenceHandler = jest . fn ( ) ;
0 commit comments