@@ -4,7 +4,7 @@ describe('the zim file creation page', () => {
44 describe ( 'when the user is logged in' , ( ) => {
55 beforeEach ( ( ) => {
66 cy . intercept ( 'v1/oauth/identify' , { fixture : 'identity.json' } ) . as (
7- 'identity' ,
7+ 'identity'
88 ) ;
99 } ) ;
1010
@@ -32,7 +32,7 @@ describe('the zim file creation page', () => {
3232 fixture : 'zim_status_not_requested.json' ,
3333 } ) . as ( 'status' ) ;
3434 cy . intercept ( 'POST' , 'v1/builders/1/zim' , { statusCode : 204 } ) . as (
35- 'create' ,
35+ 'create'
3636 ) ;
3737 cy . visit ( '/#/selections/1/zim' ) ;
3838 cy . wait ( '@identity' ) ;
@@ -59,7 +59,7 @@ describe('the zim file creation page', () => {
5959 cy . get ( '#zimtitle' ) . type ( longTitle ) ;
6060 cy . get ( '#zimtitle' ) . should (
6161 'have.value' ,
62- longTitle . substring ( 0 , 30 ) ,
62+ longTitle . substring ( 0 , 30 )
6363 ) ;
6464 } ) ;
6565
@@ -75,7 +75,7 @@ describe('the zim file creation page', () => {
7575 cy . get ( '#desc' ) . click ( ) ;
7676 cy . get ( '#longdesc' ) . click ( ) ;
7777 cy . get ( '#long-desc-group > .invalid-feedback' ) . should (
78- 'not.be.visible' ,
78+ 'not.be.visible'
7979 ) ;
8080 } ) ;
8181
@@ -254,6 +254,237 @@ describe('the zim file creation page', () => {
254254 cy . get ( '#request' ) . should ( 'not.have.attr' , 'disabled' ) ;
255255 } ) ;
256256 } ) ;
257+
258+ describe ( 'scheduling form UI' , ( ) => {
259+ beforeEach ( ( ) => {
260+ cy . intercept ( 'v1/builders/1/zim/status' , {
261+ fixture : 'zim_status_not_requested.json' ,
262+ } ) . as ( 'status' ) ;
263+ cy . intercept ( 'GET' , 'v1/oauth/email' , {
264+ body : { email : 'test@example.org' } ,
265+ } ) . as ( 'email' ) ;
266+ cy . visit ( '/#/selections/1/zim' ) ;
267+ cy . wait ( '@identity' ) ;
268+ cy . wait ( '@builder' ) ;
269+ cy . wait ( '@status' ) ;
270+ } ) ;
271+
272+ it ( 'shows the scheduling checkbox unchecked by default' , ( ) => {
273+ cy . get ( '#enableScheduling' ) . should ( 'be.visible' ) ;
274+ cy . get ( '#enableScheduling' ) . should ( 'not.be.checked' ) ;
275+ } ) ;
276+
277+ it ( 'does not show scheduling options when checkbox is unchecked' , ( ) => {
278+ cy . get ( '#repetitionPeriod' ) . should ( 'not.exist' ) ;
279+ cy . get ( '#numberOfRepetitions' ) . should ( 'not.exist' ) ;
280+ cy . get ( '#scheduleEmail' ) . should ( 'not.exist' ) ;
281+ } ) ;
282+
283+ it ( 'shows scheduling options when checkbox is checked' , ( ) => {
284+ cy . get ( '#enableScheduling' ) . check ( ) ;
285+ cy . get ( '#repetitionPeriod' ) . should ( 'be.visible' ) ;
286+ cy . get ( '#numberOfRepetitions' ) . should ( 'be.visible' ) ;
287+ cy . get ( '#scheduleEmail' ) . should ( 'be.visible' ) ;
288+ } ) ;
289+
290+ it ( 'shows the correct period options (1, 3, 6)' , ( ) => {
291+ cy . get ( '#enableScheduling' ) . check ( ) ;
292+ cy . get ( '#repetitionPeriod option' ) . should ( 'have.length' , 3 ) ;
293+ cy . get ( '#repetitionPeriod option' ) . eq ( 0 ) . should ( 'have.value' , '1' ) ;
294+ cy . get ( '#repetitionPeriod option' ) . eq ( 1 ) . should ( 'have.value' , '3' ) ;
295+ cy . get ( '#repetitionPeriod option' ) . eq ( 2 ) . should ( 'have.value' , '6' ) ;
296+ } ) ;
297+
298+ it ( 'shows the correct repetition options (1, 2, 3)' , ( ) => {
299+ cy . get ( '#enableScheduling' ) . check ( ) ;
300+ cy . get ( '#numberOfRepetitions option' ) . should ( 'have.length' , 3 ) ;
301+ cy . get ( '#numberOfRepetitions option' )
302+ . eq ( 0 )
303+ . should ( 'have.value' , '1' ) ;
304+ cy . get ( '#numberOfRepetitions option' )
305+ . eq ( 1 )
306+ . should ( 'have.value' , '2' ) ;
307+ cy . get ( '#numberOfRepetitions option' )
308+ . eq ( 2 )
309+ . should ( 'have.value' , '3' ) ;
310+ } ) ;
311+
312+ it ( 'pre-fills the schedule email from the user email endpoint' , ( ) => {
313+ cy . get ( '#enableScheduling' ) . check ( ) ;
314+ cy . get ( '#scheduleEmail' ) . should ( 'have.value' , 'test@example.org' ) ;
315+ } ) ;
316+ } ) ;
317+
318+ describe ( 'submitting with scheduling enabled' , ( ) => {
319+ beforeEach ( ( ) => {
320+ cy . intercept ( 'v1/builders/1/zim/status' , {
321+ fixture : 'zim_status_not_requested.json' ,
322+ } ) . as ( 'status' ) ;
323+ cy . intercept ( 'GET' , 'v1/oauth/email' , {
324+ body : { email : '' } ,
325+ } ) . as ( 'email' ) ;
326+ cy . intercept ( 'POST' , 'v1/builders/1/zim' , { statusCode : 204 } ) . as (
327+ 'create'
328+ ) ;
329+ cy . visit ( '/#/selections/1/zim' ) ;
330+ cy . wait ( '@identity' ) ;
331+ cy . wait ( '@builder' ) ;
332+ cy . wait ( '@status' ) ;
333+ } ) ;
334+
335+ it ( 'includes scheduled_repetitions in the request body' , ( ) => {
336+ cy . get ( '#zimtitle' ) . click ( ) ;
337+ cy . get ( '#zimtitle' ) . clear ( ) ;
338+ cy . get ( '#zimtitle' ) . type ( 'Scheduled Title' ) ;
339+ cy . get ( '#desc' ) . click ( ) ;
340+ cy . get ( '#desc' ) . clear ( ) ;
341+ cy . get ( '#desc' ) . type ( 'Test description' ) ;
342+ cy . get ( '#enableScheduling' ) . check ( ) ;
343+ cy . get ( '#repetitionPeriod' ) . select ( '3' ) ;
344+ cy . get ( '#numberOfRepetitions' ) . select ( '2' ) ;
345+ cy . get ( '#scheduleEmail' ) . clear ( ) ;
346+ cy . get ( '#scheduleEmail' ) . type ( 'user@example.org' ) ;
347+ cy . get ( '#request' ) . click ( ) ;
348+ cy . wait ( '@create' ) . then ( ( interception ) => {
349+ expect ( interception . request . body ) . to . have . property (
350+ 'scheduled_repetitions'
351+ ) ;
352+ expect (
353+ interception . request . body . scheduled_repetitions
354+ ) . to . deep . equal ( {
355+ repetition_period_in_months : 3 ,
356+ number_of_repetitions : 2 ,
357+ email : 'user@example.org' ,
358+ } ) ;
359+ } ) ;
360+ } ) ;
361+
362+ it ( 'submits without email when email is empty' , ( ) => {
363+ cy . get ( '#zimtitle' ) . click ( ) ;
364+ cy . get ( '#zimtitle' ) . clear ( ) ;
365+ cy . get ( '#zimtitle' ) . type ( 'Scheduled Title' ) ;
366+ cy . get ( '#desc' ) . click ( ) ;
367+ cy . get ( '#desc' ) . clear ( ) ;
368+ cy . get ( '#desc' ) . type ( 'Test description' ) ;
369+ cy . get ( '#enableScheduling' ) . check ( ) ;
370+ cy . get ( '#repetitionPeriod' ) . select ( '1' ) ;
371+ cy . get ( '#numberOfRepetitions' ) . select ( '1' ) ;
372+ cy . get ( '#scheduleEmail' ) . clear ( ) ;
373+ cy . get ( '#request' ) . click ( ) ;
374+ cy . wait ( '@create' ) . then ( ( interception ) => {
375+ expect ( interception . request . body ) . to . have . property (
376+ 'scheduled_repetitions'
377+ ) ;
378+ expect (
379+ interception . request . body . scheduled_repetitions
380+ ) . to . not . have . property ( 'email' ) ;
381+ } ) ;
382+ } ) ;
383+
384+ it ( 'does not include scheduled_repetitions when scheduling is disabled' , ( ) => {
385+ cy . get ( '#zimtitle' ) . click ( ) ;
386+ cy . get ( '#zimtitle' ) . clear ( ) ;
387+ cy . get ( '#zimtitle' ) . type ( 'No Schedule Title' ) ;
388+ cy . get ( '#desc' ) . click ( ) ;
389+ cy . get ( '#desc' ) . clear ( ) ;
390+ cy . get ( '#desc' ) . type ( 'Test description' ) ;
391+ cy . get ( '#request' ) . click ( ) ;
392+ cy . wait ( '@create' ) . then ( ( interception ) => {
393+ expect ( interception . request . body ) . to . not . have . property (
394+ 'scheduled_repetitions'
395+ ) ;
396+ } ) ;
397+ } ) ;
398+ } ) ;
399+
400+ describe ( 'when there is an active schedule' , ( ) => {
401+ beforeEach ( ( ) => {
402+ cy . intercept ( 'v1/builders/1/zim/status' , {
403+ fixture : 'zim_status_with_schedule.json' ,
404+ } ) . as ( 'status' ) ;
405+ cy . visit ( '/#/selections/1/zim' ) ;
406+ cy . wait ( '@identity' ) ;
407+ cy . wait ( '@builder' ) ;
408+ cy . wait ( '@status' ) ;
409+ } ) ;
410+
411+ it ( 'displays the active schedule warning' , ( ) => {
412+ cy . contains ( 'Active Schedule Found' ) . should ( 'be.visible' ) ;
413+ } ) ;
414+
415+ it ( 'shows the correct interval in the warning' , ( ) => {
416+ cy . contains ( '3 months' ) . should ( 'be.visible' ) ;
417+ } ) ;
418+
419+ it ( 'shows the next generation date' , ( ) => {
420+ cy . contains ( 'June 1, 2026' ) . should ( 'be.visible' ) ;
421+ } ) ;
422+
423+ it ( 'shows the Delete Schedule button' , ( ) => {
424+ cy . contains ( 'button' , 'Delete Schedule' ) . should ( 'be.visible' ) ;
425+ cy . contains ( 'button' , 'Delete Schedule' ) . should (
426+ 'not.have.attr' ,
427+ 'disabled'
428+ ) ;
429+ } ) ;
430+
431+ it ( 'does not show the request form' , ( ) => {
432+ cy . get ( '#desc' ) . should ( 'not.exist' ) ;
433+ cy . get ( '#longdesc' ) . should ( 'not.exist' ) ;
434+ cy . get ( '#request' ) . should ( 'not.exist' ) ;
435+ } ) ;
436+
437+ describe ( 'when the Delete Schedule button is clicked' , ( ) => {
438+ beforeEach ( ( ) => {
439+ cy . intercept ( 'DELETE' , 'v1/builders/1/schedule' , {
440+ statusCode : 200 ,
441+ body : { } ,
442+ } ) . as ( 'deleteSchedule' ) ;
443+ // After deletion, status returns without schedule
444+ cy . intercept ( 'v1/builders/1/zim/status' , {
445+ fixture : 'zim_status_not_requested.json' ,
446+ } ) . as ( 'statusAfterDelete' ) ;
447+ } ) ;
448+
449+ it ( 'sends the DELETE request' , ( ) => {
450+ cy . contains ( 'button' , 'Delete Schedule' ) . click ( ) ;
451+ cy . wait ( '@deleteSchedule' ) ;
452+ } ) ;
453+
454+ it ( 'shows the request form after deletion' , ( ) => {
455+ cy . contains ( 'button' , 'Delete Schedule' ) . click ( ) ;
456+ cy . wait ( '@deleteSchedule' ) ;
457+ cy . wait ( '@statusAfterDelete' ) ;
458+ cy . get ( '#desc' ) . should ( 'be.visible' ) ;
459+ cy . get ( '#longdesc' ) . should ( 'be.visible' ) ;
460+ } ) ;
461+ } ) ;
462+ } ) ;
463+
464+ describe ( 'when there is an active schedule and ZIM is REQUESTED' , ( ) => {
465+ beforeEach ( ( ) => {
466+ cy . intercept ( 'v1/builders/1/zim/status' , {
467+ fixture : 'zim_status_with_schedule_requested.json' ,
468+ } ) . as ( 'status' ) ;
469+ cy . visit ( '/#/selections/1/zim' ) ;
470+ cy . wait ( '@identity' ) ;
471+ cy . wait ( '@builder' ) ;
472+ cy . wait ( '@status' ) ;
473+ } ) ;
474+
475+ it ( 'does not show the active schedule warning' , ( ) => {
476+ cy . contains ( 'Active Schedule Found' ) . should ( 'not.exist' ) ;
477+ } ) ;
478+
479+ it ( 'shows the Download ZIM button disabled' , ( ) => {
480+ cy . get ( '#download' ) . should ( 'be.visible' ) ;
481+ cy . get ( '#download' ) . should ( 'have.attr' , 'disabled' ) ;
482+ } ) ;
483+
484+ it ( 'shows the spinner' , ( ) => {
485+ cy . get ( '#loader' ) . should ( 'be.visible' ) ;
486+ } ) ;
487+ } ) ;
257488 } ) ;
258489
259490 describe ( 'and the selection is over the article limit' , ( ) => {
0 commit comments