@@ -19,3 +19,234 @@ describe("For each CourseSummaries' loading status", () => {
1919 expect ( spinner ) . toBeInTheDocument ( ) ;
2020 } ) ;
2121} ) ;
22+
23+ describe ( "CourseSummaryTable show/hide inactive students" , ( ) => {
24+ it ( "toggles the checkbox UI state when clicked" , async ( ) => {
25+ render ( < CourseSummaryTable /> ) ;
26+
27+ const checkbox = screen . getByLabelText ( / d i s p l a y i n a c t i v e s t u d e n t s / i) ;
28+
29+ expect ( checkbox ) . not . toBeChecked ( ) ; // Initial state: not checked
30+
31+ await userEvent . click ( checkbox ) ; // Toggle to showHidden = true
32+ expect ( checkbox ) . toBeChecked ( ) ;
33+
34+ await userEvent . click ( checkbox ) ; // Toggle to showHidden = false
35+ expect ( checkbox ) . not . toBeChecked ( ) ;
36+ } ) ;
37+
38+ it ( "updateShowHidden correctly updates state and columnFilters" , ( ) => {
39+ const table = new CourseSummaryTable ( { } ) ;
40+
41+ // Spy on setState
42+ const setStateSpy = jest . spyOn ( table , "setState" ) ;
43+
44+ // Initial state
45+ expect ( table . state . showHidden ) . toBe ( false ) ;
46+ expect ( table . state . columnFilters ) . toEqual ( [ { id : "inactive" , value : false } ] ) ;
47+
48+ // Check the checkbox (show hidden = true)
49+ const event1 = { target : { checked : true } } ;
50+ table . updateShowHidden ( event1 ) ;
51+
52+ // Check setState called with correct values
53+ expect ( setStateSpy ) . toHaveBeenCalledWith ( {
54+ showHidden : true ,
55+ columnFilters : [ ] ,
56+ } ) ;
57+
58+ table . state . showHidden = true ;
59+ table . state . columnFilters = [ ] ;
60+
61+ // Uncheck the checkbox (show hidden = false)
62+ const event2 = { target : { checked : false } } ;
63+ table . updateShowHidden ( event2 ) ;
64+
65+ expect ( setStateSpy ) . toHaveBeenCalledWith ( {
66+ showHidden : false ,
67+ columnFilters : [ { id : "inactive" , value : false } ] , // Hidden filter added back
68+ } ) ;
69+ } ) ;
70+
71+ it ( "updateShowHidden preserves other column filters" , ( ) => {
72+ const table = new CourseSummaryTable ( { } ) ;
73+ const setStateSpy = jest . spyOn ( table , "setState" ) ;
74+
75+ // Set up state with multiple filters
76+ table . state . columnFilters = [
77+ { id : "inactive" , value : false } ,
78+ { id : "user_name" , value : "test" } ,
79+ ] ;
80+
81+ // Toggle show hidden to true
82+ const event = { target : { checked : true } } ;
83+ table . updateShowHidden ( event ) ;
84+
85+ // Should preserve user_name filter & remove hidden filter
86+ expect ( setStateSpy ) . toHaveBeenCalledWith ( {
87+ showHidden : true ,
88+ columnFilters : [ { id : "user_name" , value : "test" } ] ,
89+ } ) ;
90+
91+ // Manually update state
92+ table . state . showHidden = true ;
93+ table . state . columnFilters = [ { id : "user_name" , value : "test" } ] ;
94+
95+ // Toggle back to false
96+ const event2 = { target : { checked : false } } ;
97+ table . updateShowHidden ( event2 ) ;
98+
99+ // Should have both filters again
100+ expect ( setStateSpy ) . toHaveBeenCalledWith ( {
101+ showHidden : false ,
102+ columnFilters : [
103+ { id : "user_name" , value : "test" } ,
104+ { id : "inactive" , value : false } ,
105+ ] ,
106+ } ) ;
107+ } ) ;
108+ } ) ;
109+
110+ describe ( "For CourseSummaryTable nameColumns," , ( ) => {
111+ it ( "filterFn correctly hides rows when hidden=true" , ( ) => {
112+ const table = new CourseSummaryTable ( { } ) ;
113+ const [ hiddenColumn ] = table . nameColumns ( ) ;
114+
115+ const filterFn = hiddenColumn . filterFn ;
116+
117+ const visibleRow = { original : { hidden : false } } ;
118+ expect ( filterFn ( visibleRow , "hidden" , false ) ) . toBe ( true ) ;
119+
120+ const hiddenRow = { original : { hidden : true } } ;
121+ expect ( filterFn ( hiddenRow , "hidden" , false ) ) . toBe ( false ) ;
122+
123+ expect ( filterFn ( hiddenRow , "hidden" , true ) ) . toBe ( true ) ; // filterValue = true, show all rows
124+ } ) ;
125+
126+ it ( "filterFn shows all rows when filterValue is true" , ( ) => {
127+ const table = new CourseSummaryTable ( { } ) ;
128+ const [ hiddenColumn ] = table . nameColumns ( ) ;
129+ const filterFn = hiddenColumn . filterFn ;
130+
131+ const hiddenRow = { original : { hidden : true } } ;
132+ const visibleRow = { original : { hidden : false } } ;
133+
134+ // When filterValue is true (show hidden checkbox is checked), show all rows
135+ expect ( filterFn ( hiddenRow , "hidden" , true ) ) . toBe ( true ) ;
136+ expect ( filterFn ( visibleRow , "hidden" , true ) ) . toBe ( true ) ;
137+
138+ // When filterValue is false (show hidden checkbox is unchecked), filter out hidden rows
139+ expect ( filterFn ( hiddenRow , "hidden" , false ) ) . toBe ( false ) ;
140+ expect ( filterFn ( visibleRow , "hidden" , false ) ) . toBe ( true ) ;
141+ } ) ;
142+
143+ it ( "does not render the hidden column in the table" , async ( ) => {
144+ render ( < CourseSummaryTable /> ) ;
145+
146+ expect ( screen . queryByText ( "hidden" ) ) . not . toBeInTheDocument ( ) ;
147+ } ) ;
148+
149+ it ( "does not render the hidden column in the table" , async ( ) => {
150+ render ( < CourseSummaryTable /> ) ;
151+
152+ expect ( screen . queryByText ( "hidden" ) ) . not . toBeInTheDocument ( ) ;
153+ } ) ;
154+ } ) ;
155+
156+ describe ( "CourseSummaryTable dataColumns" , ( ) => {
157+ it ( "creates columns for assessments and marking schemes" , ( ) => {
158+ const assessments = [ { id : 1 , name : "A1" } ] ;
159+ const marking_schemes = [ { id : 2 , name : "Scheme1" } ] ;
160+
161+ const table = new CourseSummaryTable ( { assessments, marking_schemes} ) ;
162+ const columns = table . dataColumns ( ) ;
163+
164+ expect ( columns . length ) . toBe ( 2 ) ;
165+ } ) ;
166+ } ) ;
167+
168+ describe ( "CourseSummaryTable student view" , ( ) => {
169+ it ( "does not include name columns when student=true" , ( ) => {
170+ const assessments = [ { id : 1 , name : "A1" } ] ;
171+ render ( < CourseSummaryTable student = { true } assessments = { assessments } /> ) ;
172+
173+ // Name columns should not appear
174+ expect ( screen . queryByText ( I18n . t ( "activerecord.attributes.user.user_name" ) ) ) . toBeNull ( ) ;
175+
176+ // Data column should appear
177+ expect ( screen . getByText ( "A1" ) ) . toBeInTheDocument ( ) ;
178+ } ) ;
179+ } ) ;
180+
181+ describe ( "CourseSummaryTable manual filtering" , ( ) => {
182+ it ( "filterFn correctly filters marks" , ( ) => {
183+ const assessments = [ { id : 1 , name : "A1" } ] ;
184+ const marking_schemes = [ ] ;
185+ const table = new CourseSummaryTable ( { assessments, marking_schemes} ) ;
186+ const columns = table . dataColumns ( ) ;
187+
188+ const assessmentColumn = columns [ 0 ] ;
189+ const filterFn = assessmentColumn . filterFn ;
190+
191+ // Mock row with getValue returning a number
192+ const mockRow = {
193+ getValue : ( ) => 15 ,
194+ } ;
195+
196+ // Should only match when filter value equals mark
197+ expect ( filterFn ( mockRow , "assessment_marks.1.mark" , "15" ) ) . toBe ( true ) ;
198+
199+ expect ( filterFn ( mockRow , "assessment_marks.1.mark" , "1" ) ) . toBe ( false ) ;
200+ expect ( filterFn ( mockRow , "assessment_marks.1.mark" , "5" ) ) . toBe ( false ) ;
201+ expect ( filterFn ( mockRow , "assessment_marks.1.mark" , "7" ) ) . toBe ( false ) ;
202+ expect ( filterFn ( mockRow , "assessment_marks.1.mark" , "20" ) ) . toBe ( false ) ;
203+ } ) ;
204+
205+ it ( "filterFn works for marking schemes columns" , ( ) => {
206+ const assessments = [ ] ;
207+ const marking_schemes = [ { id : 1 , name : "Scheme1" } ] ;
208+ const table = new CourseSummaryTable ( { assessments, marking_schemes} ) ;
209+ const columns = table . dataColumns ( ) ;
210+
211+ const schemeColumn = columns [ 0 ] ;
212+ const filterFn = schemeColumn . filterFn ;
213+
214+ const mockRow = {
215+ getValue : ( ) => 85 ,
216+ } ;
217+
218+ // Should only match when filter value equals mark
219+ expect ( filterFn ( mockRow , "weighted_marks.1.mark" , "85" ) ) . toBe ( true ) ;
220+
221+ expect ( filterFn ( mockRow , "weighted_marks.1.mark" , "8" ) ) . toBe ( false ) ;
222+ expect ( filterFn ( mockRow , "weighted_marks.1.mark" , "5" ) ) . toBe ( false ) ;
223+ expect ( filterFn ( mockRow , "weighted_marks.1.mark" , "7" ) ) . toBe ( false ) ;
224+
225+ // Null handling
226+ const mockRowWithNull = {
227+ getValue : ( ) => null ,
228+ } ;
229+ expect ( filterFn ( mockRowWithNull , "weighted_marks.1.mark" , "5" ) ) . toBe ( false ) ;
230+ } ) ;
231+
232+ it ( "filterFn returns false for null marks" , ( ) => {
233+ const assessments = [ { id : 1 , name : "A1" } ] ;
234+ const marking_schemes = [ ] ;
235+ const table = new CourseSummaryTable ( { assessments, marking_schemes} ) ;
236+ const columns = table . dataColumns ( ) ;
237+
238+ const assessmentColumn = columns [ 0 ] ;
239+ const filterFn = assessmentColumn . filterFn ;
240+
241+ const mockRowWithNull = {
242+ getValue : ( ) => null ,
243+ } ;
244+
245+ // Should return false & not show rows with null
246+ expect ( ( ) => filterFn ( mockRowWithNull , "assessment_marks.1.mark" , "5" ) ) . not . toThrow ( ) ;
247+ expect ( filterFn ( mockRowWithNull , "assessment_marks.1.mark" , "5" ) ) . toBe ( false ) ;
248+
249+ // Also check empty string filter returns false
250+ expect ( filterFn ( mockRowWithNull , "assessment_marks.1.mark" , "" ) ) . toBe ( false ) ;
251+ } ) ;
252+ } ) ;
0 commit comments