1+ let mockPathname = "/course/test-course/course-1" ;
2+
13jest . mock ( "next/navigation" , ( ) => ( {
2- usePathname : ( ) => "/course/test-course/course-1" ,
4+ usePathname : ( ) => mockPathname ,
5+ useRouter : ( ) => ( { push : jest . fn ( ) } ) ,
36 useSearchParams : ( ) => new URLSearchParams ( ) ,
47} ) ) ;
58
69jest . mock ( "next/link" , ( ) => {
7- return ( { children } : { children : React . ReactNode } ) => children ;
10+ function MockLink ( {
11+ children,
12+ href,
13+ ...props
14+ } : {
15+ children : React . ReactNode ;
16+ href : string ;
17+ } ) {
18+ return (
19+ < a href = { href } { ...props } >
20+ { children }
21+ </ a >
22+ ) ;
23+ }
24+
25+ return MockLink ;
826} ) ;
927
1028jest . mock ( "@components/contexts" , ( ) => {
@@ -25,6 +43,10 @@ jest.mock("@components/contexts", () => {
2543 ThemeContext : React . createContext ( {
2644 theme : { } ,
2745 } ) ,
46+ AddressContext : React . createContext ( {
47+ backend : "http://localhost:3000" ,
48+ frontend : "http://localhost:3000" ,
49+ } ) ,
2850 } ;
2951} ) ;
3052
@@ -41,7 +63,12 @@ jest.mock("@components/ui/sidebar", () => ({
4163 SidebarMenuItem : ( { children } : any ) => children ,
4264 SidebarProvider : ( { children } : any ) => children ,
4365 SidebarTrigger : ( ) => null ,
44- useSidebar : ( ) => ( { openMobile : false } ) ,
66+ useSidebar : ( ) => ( {
67+ open : false ,
68+ openMobile : false ,
69+ isMobile : false ,
70+ setOpenMobile : jest . fn ( ) ,
71+ } ) ,
4572} ) ) ;
4673
4774jest . mock ( "@components/ui/tooltip" , ( ) => ( {
@@ -63,10 +90,21 @@ jest.mock("@components/ui/button", () => ({
6390
6491jest . mock ( "@components/admin/next-theme-switcher" , ( ) => ( ) => null ) ;
6592
93+ jest . mock ( "@/components/public/product-discussions/panel" , ( ) => ( ) => null ) ;
94+
6695jest . mock ( "@courselit/components-library" , ( ) => ( {
6796 Image : ( ) => null ,
6897} ) ) ;
6998
99+ jest . mock ( "@courselit/page-blocks" , ( ) => ( {
100+ TextRenderer : ( ) => null ,
101+ } ) ) ;
102+
103+ jest . mock ( "@courselit/text-editor" , ( ) => ( {
104+ Editor : ( ) => null ,
105+ emptyDoc : { } ,
106+ } ) ) ;
107+
70108jest . mock ( "@courselit/icons" , ( ) => ( {
71109 CheckCircled : ( ) => null ,
72110 Circle : ( ) => null ,
@@ -77,7 +115,9 @@ jest.mock("lucide-react", () => ({
77115 BookOpen : ( ) => null ,
78116 ChevronRight : ( ) => null ,
79117 Clock : ( ) => null ,
118+ Folder : ( ) => null ,
80119 LogOutIcon : ( ) => null ,
120+ MessageSquare : ( ) => null ,
81121} ) ) ;
82122
83123jest . mock ( "@courselit/page-primitives" , ( ) => ( {
@@ -797,6 +837,10 @@ describe("generateSideBarItems", () => {
797837} ) ;
798838
799839describe ( "Course viewer layout" , ( ) => {
840+ beforeEach ( ( ) => {
841+ mockPathname = "/course/test-course/course-1" ;
842+ } ) ;
843+
800844 it ( "renders the preview badge in the viewer header when preview mode is active" , ( ) => {
801845 const course = {
802846 title : "Course" ,
@@ -823,4 +867,141 @@ describe("Course viewer layout", () => {
823867
824868 expect ( screen . getByText ( "Preview" ) ) . toBeInTheDocument ( ) ;
825869 } ) ;
870+
871+ it ( "shows the discussions sidebar item only when discussions are enabled" , ( ) => {
872+ const course = {
873+ title : "Course" ,
874+ description : "" ,
875+ featuredImage : undefined ,
876+ updatedAt : new Date ( ) . toISOString ( ) ,
877+ creatorId : "creator-1" ,
878+ slug : "test-course" ,
879+ cost : 0 ,
880+ courseId : "course-1" ,
881+ tags : [ ] ,
882+ paymentPlans : [ ] ,
883+ defaultPaymentPlan : "" ,
884+ firstLesson : "lesson-1" ,
885+ groups : [ ] ,
886+ discussions : false ,
887+ } as unknown as CourseFrontend ;
888+
889+ const profile = {
890+ userId : "user-1" ,
891+ purchases : [
892+ {
893+ courseId : "course-1" ,
894+ accessibleGroups : [ ] ,
895+ } ,
896+ ] ,
897+ } as unknown as Profile ;
898+
899+ expect (
900+ generateSideBarItems (
901+ course ,
902+ profile ,
903+ "/course/test-course/course-1" ,
904+ ) . some ( ( item ) => item . title === "Discussions" ) ,
905+ ) . toBe ( false ) ;
906+
907+ expect (
908+ generateSideBarItems (
909+ { ...course , discussions : true } as CourseFrontend ,
910+ profile ,
911+ "/course/test-course/course-1/discussions" ,
912+ ) . find ( ( item ) => item . title === "Discussions" ) ,
913+ ) . toMatchObject ( {
914+ href : "/course/test-course/course-1/discussions" ,
915+ isActive : true ,
916+ } ) ;
917+ } ) ;
918+
919+ it ( "does not show a discussions header action on the course overview page" , ( ) => {
920+ const course = {
921+ title : "Course" ,
922+ description : "" ,
923+ featuredImage : undefined ,
924+ updatedAt : new Date ( ) . toISOString ( ) ,
925+ creatorId : "creator-1" ,
926+ slug : "test-course" ,
927+ cost : 0 ,
928+ courseId : "course-1" ,
929+ tags : [ ] ,
930+ paymentPlans : [ ] ,
931+ defaultPaymentPlan : "" ,
932+ firstLesson : "lesson-1" ,
933+ isPreview : false ,
934+ groups : [ ] ,
935+ discussions : true ,
936+ } as unknown as CourseFrontend ;
937+
938+ render (
939+ < ProductPage product = { course } >
940+ < div > Course body</ div >
941+ </ ProductPage > ,
942+ ) ;
943+
944+ expect ( screen . queryByLabelText ( "Discussions" ) ) . not . toBeInTheDocument ( ) ;
945+ } ) ;
946+
947+ it ( "does not show a discussions header action on the discussions hub page" , ( ) => {
948+ mockPathname = "/course/test-course/course-1/discussions" ;
949+ const course = {
950+ title : "Course" ,
951+ description : "" ,
952+ featuredImage : undefined ,
953+ updatedAt : new Date ( ) . toISOString ( ) ,
954+ creatorId : "creator-1" ,
955+ slug : "test-course" ,
956+ cost : 0 ,
957+ courseId : "course-1" ,
958+ tags : [ ] ,
959+ paymentPlans : [ ] ,
960+ defaultPaymentPlan : "" ,
961+ firstLesson : "lesson-1" ,
962+ isPreview : false ,
963+ groups : [ ] ,
964+ discussions : true ,
965+ } as unknown as CourseFrontend ;
966+
967+ render (
968+ < ProductPage product = { course } >
969+ < div > Discussions body</ div >
970+ </ ProductPage > ,
971+ ) ;
972+
973+ expect ( screen . queryByLabelText ( "Discussions" ) ) . not . toBeInTheDocument ( ) ;
974+ } ) ;
975+
976+ it ( "opens the discussion panel from lesson pages" , ( ) => {
977+ mockPathname = "/course/test-course/course-1/lesson-1" ;
978+ const course = {
979+ title : "Course" ,
980+ description : "" ,
981+ featuredImage : undefined ,
982+ updatedAt : new Date ( ) . toISOString ( ) ,
983+ creatorId : "creator-1" ,
984+ slug : "test-course" ,
985+ cost : 0 ,
986+ courseId : "course-1" ,
987+ tags : [ ] ,
988+ paymentPlans : [ ] ,
989+ defaultPaymentPlan : "" ,
990+ firstLesson : "lesson-1" ,
991+ isPreview : false ,
992+ groups : [ ] ,
993+ discussions : true ,
994+ } as unknown as CourseFrontend ;
995+
996+ render (
997+ < ProductPage product = { course } >
998+ < div > Lesson body</ div >
999+ </ ProductPage > ,
1000+ ) ;
1001+
1002+ expect ( screen . getByLabelText ( "Discussions" ) ) . toHaveAttribute (
1003+ "href" ,
1004+ "/course/test-course/course-1/lesson-1?discussion=open" ,
1005+ ) ;
1006+ } ) ;
8261007} ) ;
0 commit comments