Bug 35201: (bug 30708 follow-up) Fix Preservation tests
[koha.git] / t / cypress / integration / Preservation / Trains.ts
1 import { mount } from "@cypress/vue";
2
3 function get_attributes() {
4     return [
5         {
6             processing_attribute_id: 1,
7             processing_id: 1,
8             name: "Country",
9             type: "authorised_value",
10             option_source: "COUNTRY",
11         },
12         {
13             processing_attribute_id: 2,
14             processing_id: 1,
15             name: "DB",
16             type: "db_column",
17             option_source: "biblio.title",
18         },
19         {
20             processing_attribute_id: 3,
21             processing_id: 1,
22             name: "Height",
23             type: "free_text",
24             option_source: null,
25         },
26     ];
27 }
28 function get_other_attributes() {
29     return [
30         {
31             processing_attribute_id: 4,
32             processing_id: 2,
33             name: "Country",
34             type: "authorised_value",
35             option_source: "COUNTRY",
36         },
37         {
38             processing_attribute_id: 5,
39             processing_id: 2,
40             name: "Width",
41             type: "free_text",
42             option_source: null,
43         },
44     ];
45 }
46
47 function get_processings() {
48     return [
49         {
50             name: "new processing",
51             processing_id: 1,
52             attributes: get_attributes(),
53             letter_code: null,
54         },
55         {
56             name: "an other processing",
57             processing_id: 2,
58             attributes: get_other_attributes(),
59             letter_code: null,
60         },
61     ];
62 }
63
64 function get_items() {
65     // This is not a full item but it contains the info we are using
66     return [
67         {
68             biblio: {
69                 biblio_id: 1,
70                 title: "a biblio title",
71             },
72             external_id: "bc_1",
73             item_id: 1,
74         },
75         {
76             biblio: {
77                 biblio_id: 2,
78                 title: "an other biblio title",
79             },
80             external_id: "bc_2",
81             item_id: 2,
82         },
83         {
84             biblio: {
85                 biblio_id: 3,
86                 title: "yet an other biblio title",
87             },
88             external_id: "bc_3",
89             item_id: 3,
90         },
91     ];
92 }
93
94 function get_train_items() {
95     let train_item_1 = get_items()[0];
96     let processing_attributes = get_attributes();
97     train_item_1.attributes = [
98         {
99             processing_attribute: processing_attributes[0],
100             processing_attribute_id:
101                 processing_attributes[0].processing_attribute_id,
102             value: "Argentina",
103             _strings: { value: { str: "Argentina" } },
104         },
105         {
106             processing_attribute: processing_attributes[0],
107             processing_attribute_id:
108                 processing_attributes[0].processing_attribute_id,
109             value: "Not a country",
110             _strings: { value: { str: "Not a country" } },
111         },
112         {
113             processing_attribute: processing_attributes[1],
114             processing_attribute_id:
115                 processing_attributes[1].processing_attribute_id,
116             value: "a biblio title modified",
117             _strings: { value: { str: "a biblio title modified" } },
118         },
119         {
120             processing_attribute: processing_attributes[2],
121             processing_attribute_id:
122                 processing_attributes[2].processing_attribute_id,
123             value: "12cm",
124             _strings: { value: { str: "12cm" } },
125         },
126     ];
127     train_item_1.added_on = "2023-03-31T12:23:34+00:00";
128     train_item_1.processing_id = 1;
129     train_item_1.processing = get_processings()[0];
130     train_item_1.item_id = 1;
131
132     let train_item_2 = get_items()[1];
133     let processing_attributes = get_attributes();
134     train_item_2.attributes = [
135         {
136             processing_attribute: processing_attributes[0],
137             processing_attribute_id:
138                 processing_attributes[0].processing_attribute_id,
139             value: "Uruguay",
140             _strings: { value: { str: "Uruguay" } },
141         },
142         {
143             processing_attribute: processing_attributes[1],
144             processing_attribute_id:
145                 processing_attributes[1].processing_attribute_id,
146             value: "an other modified title",
147             _strings: { value: { str: "an other modified title" } },
148         },
149         {
150             processing_attribute: processing_attributes[2],
151             processing_attribute_id:
152                 processing_attributes[2].processing_attribute_id,
153             value: "34cm",
154             _strings: { value: { str: "34cm" } },
155         },
156     ];
157     train_item_2.added_on = "2023-04-01T12:34:56+00:00";
158     train_item_2.processing_id = 1;
159     train_item_2.processing = get_processings()[0];
160     train_item_2.item_id = 2;
161
162     let train_item_3 = get_items()[0];
163     let processing_attributes = get_other_attributes();
164     train_item_3.attributes = [
165         {
166             processing_attribute: processing_attributes[0],
167             processing_attribute_id:
168                 processing_attributes[0].processing_attribute_id,
169             value: "Bolivia",
170             _strings: { value: { str: "Bolivia" } },
171         },
172         {
173             processing_attribute: processing_attributes[1],
174             processing_attribute_id:
175                 processing_attributes[1].processing_attribute_id,
176             value: "W 123cm",
177             _strings: { value: { str: "W 123cm" } },
178         },
179     ];
180     train_item_3.added_on = "2023-04-02T12:34:56+00:00";
181     train_item_3.processing_id = 2;
182     train_item_3.processing = get_processings()[1];
183     train_item_3.item_id = 3;
184
185     return [train_item_1, train_item_2, train_item_3];
186 }
187
188 function get_train() {
189     let processings = get_processings();
190     return {
191         train_id: 1,
192         name: "My train",
193         description: "Just a train",
194         default_processing_id: processings[0].processing_id,
195         not_for_loan: "42",
196         created_on: "2023-04-05T10:16:27+00:00",
197         closed_on: null,
198         sent_on: null,
199         received_on: null,
200         items: [],
201         default_processing: processings[0],
202     };
203 }
204
205 describe("Trains", () => {
206     beforeEach(() => {
207         cy.login();
208         cy.title().should("eq", "Koha staff interface");
209         cy.intercept(
210             "GET",
211             "/api/v1/preservation/config",
212             '{"permissions":{"manage_sysprefs":"1"},"settings":{"enabled":"1","not_for_loan_default_train_in":"42","not_for_loan_waiting_list_in": "24"}}'
213         );
214
215         cy.intercept(
216             "GET",
217             "/api/v1/authorised_value_categories/NOT_LOAN/authorised_values",
218             [
219                 {
220                     category_name: "NOT_LOAN",
221                     description: "Ordered",
222                     value: "-1",
223                 },
224                 {
225                     category_name: "NOT_LOAN",
226                     description: "Not for loan",
227                     value: "1",
228                 },
229                 {
230                     category_name: "NOT_LOAN",
231                     description: "Staff collection",
232                     value: "2",
233                 },
234                 {
235                     category_name: "NOT_LOAN",
236                     description: "Added to bundle",
237                     value: "3",
238                 },
239                 {
240                     category_name: "NOT_LOAN",
241                     description: "In preservation",
242                     value: "24",
243                 },
244                 {
245                     category_name: "NOT_LOAN",
246                     description: "In preservation external",
247                     value: "42",
248                 },
249                 {
250                     category_name: "NOT_LOAN",
251                     description: "In preservation other",
252                     value: "43",
253                 },
254             ]
255         );
256     });
257
258     it("List trains", () => {
259         // GET trains returns 500
260         cy.intercept("GET", "/api/v1/preservation/trains*", {
261             statusCode: 500,
262             error: "Something went wrong",
263         });
264         cy.visit("/cgi-bin/koha/preservation/home.pl");
265         cy.get("#navmenulist").contains("Trains").click();
266         cy.get("main div[class='dialog alert']").contains(
267             /Something went wrong/
268         );
269
270         // GET trains returns empty list
271         cy.intercept("GET", "/api/v1/preservation/trains*", []);
272         cy.visit("/cgi-bin/koha/preservation/trains");
273         cy.get("#trains_list").contains("There are no trains defined");
274
275         // GET trains returns something
276         let train = get_train();
277         let trains = [train];
278
279         cy.intercept("GET", "/api/v1/preservation/trains*", {
280             statusCode: 200,
281             body: trains,
282             headers: {
283                 "X-Base-Total-Count": "1",
284                 "X-Total-Count": "1",
285             },
286         });
287         cy.intercept("GET", "/api/v1/preservation/trains/*", train);
288         cy.visit("/cgi-bin/koha/preservation/trains");
289         cy.get("#trains_list").contains("Showing 1 to 1 of 1 entries");
290     });
291
292     it("Add train", () => {
293         cy.intercept("GET", "/api/v1/preservation/trains*", []);
294         cy.intercept(
295             "GET",
296             "/api/v1/preservation/processings*",
297             get_processings()
298         );
299         cy.visit("/cgi-bin/koha/preservation/trains");
300         let train = get_train();
301         cy.contains("New train").click();
302         cy.get("#train_name").type(train.name);
303         cy.get("#train_description").type(train.description);
304         // Confirm that the default not_for_loan is selected
305         cy.get("#not_for_loan .vs__selected").contains(
306             "In preservation external"
307         );
308         // Change it
309         cy.get("#not_for_loan .vs__search").type(
310             "In preservation other{enter}"
311         );
312         cy.get("#train_default_processing .vs__search").type(
313             "new processing{enter}"
314         );
315
316         // Submit the form, get 500
317         cy.intercept("POST", "/api/v1/preservation/trains", {
318             statusCode: 500,
319             error: "Something went wrong",
320         });
321         cy.get("#trains_add").contains("Submit").click();
322         cy.get("main div[class='dialog alert']").contains(
323             "Something went wrong: Error: Internal Server Error"
324         );
325
326         // Submit the form, success!
327         cy.intercept("POST", "/api/v1/preservation/trains", {
328             statusCode: 201,
329             body: train,
330         });
331         cy.get("#trains_add").contains("Submit").click();
332         cy.get("main div[class='dialog message']").contains("Train created");
333     });
334
335     it("Edit train", () => {
336         let train = get_train();
337         let processings = get_processings();
338         cy.intercept("GET", "/api/v1/preservation/trains/*", train);
339         cy.intercept("GET", "/api/v1/preservation/trains*", {
340             statusCode: 200,
341             body: [train],
342             headers: {
343                 "X-Base-Total-Count": "1",
344                 "X-Total-Count": "1",
345             },
346         });
347
348         cy.intercept("GET", "/api/v1/preservation/processings*", processings);
349         cy.visit("/cgi-bin/koha/preservation/trains");
350         cy.get("#trains_list table tbody tr:first").contains("Edit").click();
351         cy.get("#train_name").should("have.value", train.name);
352         cy.get("#train_description").should("have.value", train.description);
353         cy.get("#not_for_loan .vs__selected").contains(
354             "In preservation external"
355         );
356         cy.get("#train_default_processing .vs__selected").contains(
357             train.default_processing.name
358         );
359
360         // Submit the form, get 500
361         cy.intercept("PUT", "/api/v1/preservation/trains/*", {
362             statusCode: 500,
363         });
364         cy.get("#trains_add").contains("Submit").click();
365         cy.get("main div[class='dialog alert']").contains(
366             "Something went wrong: Error: Internal Server Error"
367         );
368
369         // Submit the form, success!
370         cy.intercept("PUT", "/api/v1/preservation/trains/*", {
371             statusCode: 200,
372             body: train,
373         });
374         cy.intercept("GET", "/api/v1/preservation/trains", {
375             statusCode: 200,
376             body: [train],
377         });
378         cy.get("#trains_add").contains("Submit").click();
379         cy.get("main div[class='dialog message']").contains("Train updated");
380     });
381
382     it("Simple show train", () => {
383         let train = get_train();
384         let trains = [train];
385
386         cy.intercept("GET", "/api/v1/preservation/trains*", {
387             statusCode: 200,
388             body: trains,
389             headers: {
390                 "X-Base-Total-Count": "1",
391                 "X-Total-Count": "1",
392             },
393         });
394         cy.intercept("GET", "/api/v1/preservation/trains/*", train);
395         cy.visit("/cgi-bin/koha/preservation/trains");
396         let name_link = cy.get("#trains_list table tbody tr:first td:first a");
397         name_link.should(
398             "have.text",
399             train.name + " (#" + train.train_id + ")"
400         );
401         name_link.click();
402         cy.get("#trains_show h2").contains("Train #" + train.train_id);
403
404         cy.contains("Name:" + train.name);
405         cy.contains("Description:" + train.description);
406         cy.contains(
407             "Status for item added to this train:" + "In preservation external"
408         );
409         cy.contains("Default processing:" + train.default_processing.name);
410     });
411
412     it("Show train close, send, receive", () => {
413         let train = get_train();
414         cy.intercept("GET", "/api/v1/preservation/trains/" + train.train_id, {
415             statusCode: 200,
416             body: train,
417         }).as("get-train");
418         cy.visit("/cgi-bin/koha/preservation/trains/" + train.train_id);
419         cy.wait("@get-train");
420         cy.contains("Closed on:").should("not.exist");
421         cy.contains("Sent on:").should("not.exist");
422         cy.contains("Received on:").should("not.exist");
423
424         let closed_train = Object.assign({}, train);
425         closed_train.closed_on = "2022-10-27 12:34:56";
426         cy.intercept("PUT", "/api/v1/preservation/trains/" + train.train_id, {
427             statusCode: 201,
428             body: closed_train,
429         }).as("set-train");
430         cy.intercept("GET", "/api/v1/preservation/trains/" + train.train_id, {
431             statusCode: 200,
432             body: closed_train,
433         }).as("get-train");
434         cy.get("#toolbar").contains("Close").click();
435         cy.wait("@get-train");
436         cy.contains("Closed on:").should("exist");
437         cy.contains("Sent on:").should("not.exist");
438         cy.contains("Received on:").should("not.exist");
439
440         let sent_train = Object.assign({}, closed_train);
441         sent_train.sent_on = "2022-10-28 12:34:56";
442         cy.intercept("PUT", "/api/v1/preservation/trains/" + train.train_id, {
443             statusCode: 201,
444             body: sent_train,
445         }).as("set-train");
446         cy.intercept("GET", "/api/v1/preservation/trains/" + train.train_id, {
447             statusCode: 200,
448             body: sent_train,
449         }).as("get-train");
450         cy.get("#toolbar").contains("Send").click();
451         cy.wait("@get-train");
452         cy.contains("Closed on:").should("exist");
453         cy.contains("Sent on:").should("exist");
454         cy.contains("Received on:").should("not.exist");
455
456         let received_train = Object.assign({}, sent_train);
457         received_train.received_on = "2022-10-29 12:34:56";
458         cy.intercept("PUT", "/api/v1/preservation/trains/" + train.train_id, {
459             statusCode: 201,
460             body: received_train,
461         }).as("set-train");
462         cy.intercept("GET", "/api/v1/preservation/trains/" + train.train_id, {
463             statusCode: 200,
464             body: received_train,
465         }).as("get-train");
466         cy.get("#toolbar").contains("Receive").click();
467         cy.wait("@get-train");
468         cy.contains("Closed on:").should("exist");
469         cy.contains("Sent on:").should("exist");
470         cy.contains("Received on:").should("exist");
471     });
472
473     it("Delete train", () => {
474         let train = get_train();
475         cy.intercept("GET", "/api/v1/preservation/trains*", {
476             statusCode: 200,
477             body: [train],
478             headers: {
479                 "X-Base-Total-Count": "1",
480                 "X-Total-Count": "1",
481             },
482         });
483         cy.visit("/cgi-bin/koha/preservation/trains");
484
485         // Submit the form, get 500
486         cy.intercept(
487             "DELETE",
488             "/api/v1/preservation/trains/" + train.train_id,
489             {
490                 statusCode: 500,
491                 error: "Something went wrong",
492             }
493         );
494         cy.get("#trains_list table tbody tr:first").contains("Delete").click();
495         cy.contains("Yes, delete").click();
496         cy.get("main div[class='dialog alert']").contains(
497             "Something went wrong: Error: Internal Server Error"
498         );
499
500         // Submit the form, success!
501         cy.intercept(
502             "DELETE",
503             "/api/v1/preservation/trains/" + train.train_id,
504             {
505                 statusCode: 201,
506                 body: null,
507             }
508         );
509         cy.get("#trains_list table tbody tr:first").contains("Delete").click();
510         cy.contains("Yes, delete").click();
511         cy.get("main div[class='dialog message']").contains(
512             `Train ${train.name} deleted`
513         );
514     });
515
516     it("Add new item to a train", () => {
517         let train = get_train();
518         cy.intercept(
519             "GET",
520             "/api/v1/preservation/trains/" + train.train_id,
521             train
522         );
523         let processings = get_processings();
524         cy.intercept("GET", "/api/v1/preservation/processings*", processings);
525         cy.intercept(
526             "GET",
527             "/api/v1/preservation/processings/" + processings[0].processing_id,
528             processings[0]
529         );
530         cy.visit("/cgi-bin/koha/preservation/trains/" + train.train_id);
531         cy.contains("Add items").click();
532         cy.get("#barcode").type("bc_1");
533         cy.intercept("GET", "/api/v1/preservation/waiting-list/items*", []);
534         cy.contains("Submit").click();
535         cy.get("div[class='dialog alert modal']").contains(
536             "Cannot find item with this barcode. It must be in the waiting list."
537         );
538         cy.get("#close_modal").click();
539
540         let item = get_items()[0];
541         cy.intercept("GET", "/api/v1/preservation/waiting-list/items*", [item]);
542         cy.contains("Submit").click();
543         cy.intercept(
544             "POST",
545             `/api/v1/preservation/trains/${train.train_id}/items`,
546             {
547                 statusCode: 201,
548                 body: item, // Not correct but not important
549             }
550         );
551         cy.contains("Itemnumber:" + item.item_id);
552         cy.get("#processing .vs__selected").contains(
553             train.default_processing.name
554         );
555         cy.contains("Country:");
556         cy.get("#attribute_0 .vs__search").type("Argentin{enter}");
557         cy.contains("DB:");
558         cy.get("#attribute_1").should("have.value", item.biblio.title);
559         cy.get("#attribute_1").type(" modified");
560         cy.contains("Height:");
561         cy.get("#attribute_2").type("42cm");
562
563         let train_items = get_train_items();
564         let train_with_one_item = Object.assign({}, train);
565         train_with_one_item.items = [train_items[0]];
566
567         cy.intercept(
568             "GET",
569             "/api/v1/preservation/trains/" + train.train_id,
570             train_with_one_item
571         );
572         cy.contains("Submit").click();
573         cy.get("#trains_show").contains("Showing 1 to 1 of 1 entries");
574
575         let train_with_2_items = Object.assign({}, train);
576         train_with_2_items.items = [train_items[0], train_items[1]];
577         cy.intercept(
578             "GET",
579             "/api/v1/preservation/trains/" + train.train_id,
580             train_with_2_items
581         );
582         cy.visit("/cgi-bin/koha/preservation/trains/" + train.train_id);
583         cy.get("#trains_show table").should("exist");
584         cy.get("#trains_show").contains("Showing 1 to 2 of 2 entries");
585         train_with_2_items.items.forEach(train_item => {
586             train_item.attributes.forEach(attribute => {
587                 cy.get("td").contains(attribute.value);
588             });
589         });
590
591         let train_with_3_items = Object.assign({}, train);
592         train_with_3_items.items = [
593             train_items[0],
594             train_items[1],
595             train_items[2],
596         ];
597         cy.intercept(
598             "GET",
599             "/api/v1/preservation/trains/" + train.train_id,
600             train_with_3_items
601         );
602         cy.visit("/cgi-bin/koha/preservation/trains/" + train.train_id);
603         cy.get("#trains_show table").should("not.exist");
604         train_with_3_items.items.forEach((train_item, i) => {
605             train_item.attributes.forEach(attribute => {
606                 let re = new RegExp(attribute.value);
607                 cy.get(`#item_${i}`).contains(re);
608             });
609         });
610     });
611
612     it("Add to waiting list then add to a train", () => {
613         let train = get_train();
614         let processing = get_processings()[0];
615         cy.intercept("GET", "/api/v1/preservation/trains*", [train]);
616         cy.intercept("GET", "/api/v1/preservation/trains/1", train);
617         cy.intercept("GET", "/api/v1/preservation/processings/1", processing);
618         cy.visit("/cgi-bin/koha/preservation/waiting-list");
619
620         cy.intercept("GET", "/api/v1/preservation/waiting-list/items*", {
621             statusCode: 200,
622             body: get_items(),
623             headers: {
624                 "X-Base-Total-Count": "2",
625                 "X-Total-Count": "2",
626             },
627         }).as("get-items");
628         cy.intercept("POST", "/api/v1/preservation/waiting-list/items", [
629             { item_id: 1 },
630             { item_id: 2 },
631         ]);
632         cy.get("#waiting-list").contains("Add to waiting list").click();
633         cy.get("#barcode_list").type("bc_1\nbc_2\nbc_3");
634         cy.contains("Submit").click();
635         cy.wait("@get-items");
636         cy.get("main div[class='dialog message']").contains(
637             "2 new items added."
638         );
639         cy.contains("Add last 2 items to a train").click();
640         cy.get("#train_id .vs__search").type(train.name + "{enter}");
641         cy.intercept("GET", "/api/v1/items*", {
642             statusCode: 200,
643             body: get_items().filter(
644                 item => item.item_id == 1 || item.item_id == 2
645             ),
646             headers: {
647                 "X-Base-Total-Count": "2",
648                 "X-Total-Count": "2",
649             },
650         });
651         cy.intercept(
652             "POST",
653             "/api/v1/preservation/trains/" + train.train_id + "/items/batch",
654             req => {
655                 req.reply({
656                     statusCode: 201,
657                     body: req.body,
658                 });
659             }
660         );
661         cy.contains("Submit").click(); // Select train
662         train.items = get_train_items().filter(
663             train_item => train_item.item_id == 1 || train_item.item_id == 2
664         );
665         cy.intercept("GET", "/api/v1/preservation/trains/1", train);
666         cy.contains("Submit").click(); // Submit add items form
667         cy.get("main div[class='dialog message']").contains(
668             `2 items have been added to train ${train.train_id}.`
669         );
670     });
671 });