@@ -6,12 +6,19 @@ import {
6
6
getRandomName ,
7
7
getRandomUniversityID
8
8
} from "e2e/Utils" ;
9
+ import { dirname , join } from "path" ;
10
+ import { fileURLToPath } from "url" ;
11
+
12
+ const __filename = fileURLToPath ( import . meta. url ) ;
13
+ const __dirname = dirname ( __filename ) ;
9
14
10
15
test . describe . serial ( "Grades workflow" , ( ) => {
11
16
const teacherEmail = getRandomEmail ( ) ;
12
17
13
18
const courseName = "Test course" ;
19
+ const rubricName = "Test rubric" ;
14
20
const laboratoryName = "Test laboratory" ;
21
+ const testBlockName = "Test block name" ;
15
22
16
23
const studentFullName = getRandomName ( ) ;
17
24
const studentEmail = getRandomEmail ( ) ;
@@ -43,6 +50,20 @@ test.describe.serial("Grades workflow", () => {
43
50
await page . getByRole ( "button" , { name : "Submit" } ) . click ( ) ;
44
51
} ) ;
45
52
53
+ test ( "Create test rubric" , async ( { page } ) => {
54
+ // Login as a teacher
55
+ await page . goto ( "/login" ) ;
56
+ await page . getByLabel ( "Email" ) . fill ( teacherEmail ) ;
57
+ await page . getByLabel ( "Password" ) . fill ( getDefaultPassword ( ) ) ;
58
+ await page . getByRole ( "button" , { name : "Submit" } ) . click ( ) ;
59
+
60
+ // Create a rubric
61
+ await page . getByRole ( "link" , { name : "Rubrics" , exact : true } ) . click ( ) ;
62
+ await page . getByRole ( "button" , { name : "Create rubric" } ) . click ( ) ;
63
+ await page . getByLabel ( "Name" ) . fill ( "Test rubric" ) ;
64
+ await page . getByRole ( "button" , { name : "Create" } ) . click ( ) ;
65
+ } ) ;
66
+
46
67
test ( "Create test course" , async ( { page } ) => {
47
68
// Login as a teacher
48
69
await page . goto ( "/login" ) ;
@@ -78,6 +99,89 @@ test.describe.serial("Grades workflow", () => {
78
99
await page . getByLabel ( "Opening date" ) . fill ( "2023-12-01T00:00" ) ;
79
100
await page . getByLabel ( "Closing date" ) . fill ( "2032-12-01T23:59" ) ;
80
101
await page . getByRole ( "button" , { name : "Create" } ) . click ( ) ;
102
+
103
+ // Select the rubric
104
+ const editLaboratoryButton = page . getByRole ( "link" , {
105
+ name : `Edit ${ laboratoryName } laboratory`
106
+ } ) ;
107
+ await expect ( editLaboratoryButton ) . toBeVisible ( ) ;
108
+ await editLaboratoryButton . click ( ) ;
109
+
110
+ const rubricSelect = page . getByRole ( "combobox" , { name : "Rubric" } ) ;
111
+ await expect ( rubricSelect ) . toBeVisible ( ) ;
112
+ await rubricSelect . click ( ) ;
113
+
114
+ const rubricOption = page . getByLabel ( rubricName ) ;
115
+ await expect ( rubricOption ) . toBeVisible ( ) ;
116
+ await rubricOption . click ( ) ;
117
+
118
+ // Save the changes
119
+ const saveButton = page . getByRole ( "button" , { name : "Save changes" } ) ;
120
+ await expect ( saveButton ) . toBeVisible ( ) ;
121
+ await saveButton . click ( ) ;
122
+
123
+ // Assert a toast is shown
124
+ await expect (
125
+ page . getByText ( "Laboratory details updated successfully" )
126
+ ) . toBeVisible ( ) ;
127
+ } ) ;
128
+
129
+ test ( "Create test block" , async ( { page } ) => {
130
+ // Login as a teacher
131
+ await page . goto ( "/login" ) ;
132
+ await page . getByLabel ( "Email" ) . fill ( teacherEmail ) ;
133
+ await page . getByLabel ( "Password" ) . fill ( getDefaultPassword ( ) ) ;
134
+ await page . getByRole ( "button" , { name : "Submit" } ) . click ( ) ;
135
+
136
+ // Go to the course page
137
+ await page . getByRole ( "link" , { name : courseName } ) . click ( ) ;
138
+
139
+ // Enter to the edit page of the laboratory
140
+ const editLaboratoryButton = page . getByRole ( "link" , {
141
+ name : `Edit ${ laboratoryName } laboratory`
142
+ } ) ;
143
+ await expect ( editLaboratoryButton ) . toBeVisible ( ) ;
144
+ await editLaboratoryButton . click ( ) ;
145
+
146
+ // Add the test block
147
+ const addTestBlockButton = page . getByRole ( "button" , {
148
+ name : "Add test block"
149
+ } ) ;
150
+ await addTestBlockButton . click ( ) ;
151
+
152
+ // set the name
153
+ const addTestBlockModal = page . getByRole ( "dialog" ) ;
154
+ await addTestBlockModal . getByLabel ( "Name" ) . fill ( testBlockName ) ;
155
+
156
+ // select the language
157
+ const languageSelect = addTestBlockModal . getByRole ( "combobox" , {
158
+ name : "Language"
159
+ } ) ;
160
+ await expect ( languageSelect ) . toBeVisible ( ) ;
161
+ languageSelect . click ( ) ;
162
+
163
+ const javaOption = page . getByLabel ( "Java" ) ;
164
+ await expect ( javaOption ) . toBeVisible ( ) ;
165
+ await javaOption . click ( ) ;
166
+
167
+ // Upload tests file
168
+ const zipFile = join ( __dirname , "data" , "java-tests.zip" ) ;
169
+ const zipFileInput = addTestBlockModal . getByLabel ( "Test file" ) ;
170
+
171
+ const fileChooserPromise = page . waitForEvent ( "filechooser" ) ;
172
+ await zipFileInput . click ( ) ;
173
+ const fileChooser = await fileChooserPromise ;
174
+ await fileChooser . setFiles ( zipFile ) ;
175
+
176
+ // Submit the form
177
+ const submitButton = page . getByRole ( "button" , { name : "Add" } ) ;
178
+ await expect ( submitButton ) . toBeVisible ( ) ;
179
+ await submitButton . click ( ) ;
180
+
181
+ // Assert the test block is shown
182
+ const nameInput = page . getByLabel ( "Block name" ) ;
183
+ await expect ( nameInput ) . toBeVisible ( ) ;
184
+ await expect ( nameInput ) . toHaveValue ( testBlockName ) ;
81
185
} ) ;
82
186
83
187
test ( "Enroll student in test course" , async ( { page } ) => {
@@ -110,6 +214,81 @@ test.describe.serial("Grades workflow", () => {
110
214
await studentButton . click ( ) ;
111
215
} ) ;
112
216
217
+ test ( "Student submits a solution" , async ( { page } ) => {
218
+ // Login as a student
219
+ await page . goto ( "/login" ) ;
220
+ await page . getByLabel ( "Email" ) . fill ( studentEmail ) ;
221
+ await page . getByLabel ( "Password" ) . fill ( getDefaultPassword ( ) ) ;
222
+ await page . getByRole ( "button" , { name : "Submit" } ) . click ( ) ;
223
+
224
+ // Go to the course page
225
+ await page . getByRole ( "link" , { name : courseName } ) . click ( ) ;
226
+
227
+ // Go to the laboratory page
228
+ await page
229
+ . getByRole ( "link" , { name : `Complete ${ laboratoryName } laboratory` } )
230
+ . click ( ) ;
231
+
232
+ // Assert the test block is shown
233
+ const testBlockNameInput = page . getByLabel ( "Test name" ) ;
234
+ await expect ( testBlockNameInput ) . toBeVisible ( ) ;
235
+ await expect ( testBlockNameInput ) . toHaveValue ( testBlockName ) ;
236
+
237
+ // Upload the solution
238
+ const solutionFile = join ( __dirname , "data" , "java-tests.zip" ) ;
239
+ const solutionFileInput = page . getByLabel ( "Submission file" ) ;
240
+
241
+ const fileChooserPromise = page . waitForEvent ( "filechooser" ) ;
242
+ await solutionFileInput . click ( ) ;
243
+ const fileChooser = await fileChooserPromise ;
244
+ await fileChooser . setFiles ( solutionFile ) ;
245
+
246
+ // Submit the form
247
+ const submitButton = page . getByRole ( "button" , { name : "Submit" } ) ;
248
+ await expect ( submitButton ) . toBeVisible ( ) ;
249
+ await submitButton . click ( ) ;
250
+
251
+ // update the timeout
252
+ const ONE_MINUTE_IN_MS = 60000 ;
253
+ page . setDefaultTimeout ( ONE_MINUTE_IN_MS ) ;
254
+
255
+ // Assert the status phases are shown
256
+ // Pending phase
257
+ const pendingPhaseElm = page . getByTestId ( "pending-phase" ) ;
258
+ await expect ( pendingPhaseElm ) . toBeVisible ( ) ;
259
+ await expect ( pendingPhaseElm ) . toHaveAttribute ( "data-reached" , "true" ) ;
260
+
261
+ // Running phase
262
+ const runningPhaseElm = page . getByTestId ( "running-phase" ) ;
263
+ await expect ( runningPhaseElm ) . toBeVisible ( ) ;
264
+ await expect ( runningPhaseElm ) . toHaveAttribute ( "data-reached" , "true" ) ;
265
+
266
+ // Ready phase
267
+ const readyPhaseElm = page . getByTestId ( "ready-phase" ) ;
268
+ await expect ( readyPhaseElm ) . toBeVisible ( ) ;
269
+ await expect ( readyPhaseElm ) . toHaveAttribute ( "data-reached" , "true" ) ;
270
+
271
+ // TODO: Assert the student can download the submitted file
272
+ /*
273
+ const formTab = page.getByRole("tab", {
274
+ name: "Test block 1 submission form",
275
+ exact: true
276
+ });
277
+ await formTab.click();
278
+
279
+ const downloadButton = page.getByRole("button", {
280
+ name: "Download current submission file for block number 1"
281
+ });
282
+ await expect(downloadButton).toBeVisible();
283
+
284
+ const downloadPromise = page.waitForEvent("download");
285
+
286
+ await downloadButton.click();
287
+ const download = await downloadPromise;
288
+ await download.saveAs(join(__dirname, "data", "downloaded-java-tests.zip"));
289
+ */
290
+ } ) ;
291
+
113
292
test ( "Student appears in the grades list" , async ( { page } ) => {
114
293
// Login as a teacher
115
294
await page . goto ( "/login" ) ;
@@ -141,12 +320,177 @@ test.describe.serial("Grades workflow", () => {
141
320
await expect ( studentRow ) . toBeVisible ( ) ;
142
321
143
322
await expect (
144
- studentRow . getByRole ( "cell" , { name : studentFullName } )
323
+ studentRow . getByRole ( "cell" , { name : studentFullName , exact : true } )
145
324
) . toBeVisible ( ) ;
146
325
await expect (
147
326
studentRow . getByRole ( "cell" , {
148
- name : "N/A"
327
+ name : "N/A" ,
328
+ exact : true
329
+ } )
330
+ ) . toBeVisible ( ) ;
331
+ await expect (
332
+ studentRow . getByRole ( "link" , {
333
+ name : `Edit grade for student ${ studentFullName } ` ,
334
+ exact : true
149
335
} )
150
336
) . toBeVisible ( ) ;
151
337
} ) ;
338
+
339
+ test ( "Teacher can edit the grade" , async ( { page } ) => {
340
+ // Login as a teacher
341
+ await page . goto ( "/login" ) ;
342
+ await page . getByLabel ( "Email" ) . fill ( teacherEmail ) ;
343
+ await page . getByLabel ( "Password" ) . fill ( getDefaultPassword ( ) ) ;
344
+ await page . getByRole ( "button" , { name : "Submit" } ) . click ( ) ;
345
+
346
+ // Go to the course page
347
+ await page . getByRole ( "link" , { name : courseName } ) . click ( ) ;
348
+
349
+ // Go to the grades view of the laboratory
350
+ const laboratoryRow = page . getByRole ( "row" , {
351
+ name : new RegExp ( `^\\s*${ laboratoryName } ` ) ,
352
+ exact : true
353
+ } ) ;
354
+ await expect ( laboratoryRow ) . toBeVisible ( ) ;
355
+
356
+ const laboratoryGradesButton = laboratoryRow . getByRole ( "link" , {
357
+ name : `Go to the grades of ${ laboratoryName } ` ,
358
+ exact : true
359
+ } ) ;
360
+ await laboratoryGradesButton . click ( ) ;
361
+
362
+ // Edit the grade
363
+ const studentRow = page . getByRole ( "row" , {
364
+ name : new RegExp ( `^\\s*${ studentFullName } ` ) ,
365
+ exact : true
366
+ } ) ;
367
+ await expect ( studentRow ) . toBeVisible ( ) ;
368
+
369
+ const editGradeButton = studentRow . getByRole ( "link" , {
370
+ name : `Edit grade for student ${ studentFullName } ` ,
371
+ exact : true
372
+ } ) ;
373
+ await editGradeButton . click ( ) ;
374
+
375
+ // ## Select a criteria from the rubric
376
+ let criteriaCard = page . getByRole ( "button" , {
377
+ name : "Select criteria 1 of objective 1" ,
378
+ exact : true
379
+ } ) ;
380
+ await criteriaCard . click ( ) ;
381
+
382
+ const criteriaWeightElm = page . getByLabel (
383
+ "Criteria 1 of objective 1 weight"
384
+ ) ;
385
+ expect ( criteriaWeightElm ) . not . toBeNull ( ) ;
386
+
387
+ const criteriaWeight = await criteriaWeightElm . getAttribute ( "value" ) ;
388
+ expect ( criteriaWeight ) . not . toBeNull ( ) ;
389
+
390
+ // Assert a toast is shown
391
+ await expect ( page . getByText ( "Criteria has been selected" ) ) . toBeVisible ( ) ;
392
+
393
+ // Assert the weight was added to the student grade
394
+ const studentGradeInput = page . getByLabel ( "Grade" , { exact : true } ) ;
395
+ await expect ( studentGradeInput ) . toBeVisible ( ) ;
396
+ await expect ( studentGradeInput ) . toHaveValue ( criteriaWeight ! ) ;
397
+
398
+ // ## Deselect the criteria
399
+ criteriaCard = page . getByRole ( "button" , {
400
+ name : "De-select criteria 1 of objective 1" ,
401
+ exact : true
402
+ } ) ;
403
+ await criteriaCard . click ( ) ;
404
+
405
+ // Assert a toast is shown
406
+ await expect ( page . getByText ( "Criteria has been de-selected" ) ) . toBeVisible ( ) ;
407
+
408
+ // Assert the weight was removed from the student grade
409
+ await expect ( studentGradeInput ) . toBeVisible ( ) ;
410
+ await expect ( studentGradeInput ) . toHaveValue ( "0" ) ;
411
+
412
+ // ## Add a comment
413
+ const commentInput = page . getByLabel ( "Comment" ) ;
414
+ await expect ( commentInput ) . toBeVisible ( ) ;
415
+ await commentInput . fill ( "This is a comment left by the teacher" ) ;
416
+
417
+ const updateCommentButton = page . getByRole ( "button" , {
418
+ name : "Update comment" ,
419
+ exact : true
420
+ } ) ;
421
+ await updateCommentButton . click ( ) ;
422
+
423
+ // Assert a toast is shown
424
+ await expect (
425
+ page . getByText ( "The comment has been set successfully" )
426
+ ) . toBeVisible ( ) ;
427
+
428
+ // Select the criteria again
429
+ criteriaCard = page . getByRole ( "button" , {
430
+ name : "Select criteria 1 of objective 1" ,
431
+ exact : true
432
+ } ) ;
433
+ await criteriaCard . click ( ) ;
434
+ } ) ;
435
+
436
+ test ( "Teacher can download student submissions" , async ( { page } ) => {
437
+ // Login as a teacher
438
+ await page . goto ( "/login" ) ;
439
+ await page . getByLabel ( "Email" ) . fill ( teacherEmail ) ;
440
+ await page . getByLabel ( "Password" ) . fill ( getDefaultPassword ( ) ) ;
441
+ await page . getByRole ( "button" , { name : "Submit" } ) . click ( ) ;
442
+
443
+ // Go to the course page
444
+ await page . getByRole ( "link" , { name : courseName } ) . click ( ) ;
445
+
446
+ // Go to the grades view of the laboratory
447
+ const laboratoryRow = page . getByRole ( "row" , {
448
+ name : new RegExp ( `^\\s*${ laboratoryName } ` ) ,
449
+ exact : true
450
+ } ) ;
451
+
452
+ const laboratoryGradesButton = laboratoryRow . getByRole ( "link" , {
453
+ name : `Go to the grades of ${ laboratoryName } ` ,
454
+ exact : true
455
+ } ) ;
456
+ await laboratoryGradesButton . click ( ) ;
457
+
458
+ // Go to the grade of the student
459
+ const studentRow = page . getByRole ( "row" , {
460
+ name : new RegExp ( `^\\s*${ studentFullName } ` ) ,
461
+ exact : true
462
+ } ) ;
463
+
464
+ const editGradeButton = studentRow . getByRole ( "link" , {
465
+ name : `Edit grade for student ${ studentFullName } ` ,
466
+ exact : true
467
+ } ) ;
468
+
469
+ await editGradeButton . click ( ) ;
470
+
471
+ // Click on the Submission tab
472
+ const submissionTab = page . getByRole ( "tab" , {
473
+ name : "Submissions" ,
474
+ exact : true
475
+ } ) ;
476
+ await submissionTab . click ( ) ;
477
+
478
+ // Assert the teacher can download the submission
479
+ const downloadButton = page . getByRole ( "button" , {
480
+ name : `Download code sent by the student for the ${ testBlockName } test block` ,
481
+ exact : true
482
+ } ) ;
483
+ await expect ( downloadButton ) . toBeVisible ( ) ;
484
+
485
+ const downloadPromise = page . waitForEvent ( "download" ) ;
486
+
487
+ await downloadButton . click ( ) ;
488
+ const download = await downloadPromise ;
489
+ await download . saveAs ( join ( __dirname , "data" , "downloaded-java-tests.zip" ) ) ;
490
+
491
+ // Assert a toast is shown
492
+ await expect (
493
+ page . getByText ( "The submission archive has been downloaded successfully" )
494
+ ) . toBeVisible ( ) ;
495
+ } ) ;
152
496
} ) ;
0 commit comments