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