Bug 32131: Move set_ERM_sys_pref_value to before
[koha.git] / t / cypress / integration / Agreements_spec.ts
1 import { mount } from "@cypress/vue";
2 const dayjs = require("dayjs"); /* Cannot use our calendar JS code, it's in an include file (!)
3                                    Also note that moment.js is deprecated */
4
5 const dates = {
6     today_iso: dayjs().format("YYYY-MM-DD"),
7     today_us: dayjs().format("MM/DD/YYYY"),
8     tomorrow_iso: dayjs().add(1, "day").format("YYYY-MM-DD"),
9     tomorrow_us: dayjs().add(1, "day").format("MM/DD/YYYY"),
10 };
11 function get_agreement() {
12     return {
13         agreement_id: 1,
14         closure_reason: "",
15         description: "my first agreement",
16         is_perpetual: false,
17         license_info: "",
18         name: "agreement 1",
19         renewal_priority: "",
20         status: "active",
21         vendor_id: null,
22         periods: [
23             {
24                 started_on: dates["today_iso"],
25                 ended_on: dates["tomorrow_iso"],
26                 cancellation_deadline: null,
27                 notes: null,
28             },
29             {
30                 started_on: dates["today_iso"],
31                 ended_on: null,
32                 cancellation_deadline: dates["tomorrow_iso"],
33                 notes: "this is a note",
34             },
35         ],
36         user_roles: [],
37         agreement_licenses: [
38             {
39                 agreement_id: 1,
40                 agreement_license_id: 3,
41                 license: {
42                     description: "license description",
43                     license_id: 1,
44                     name: "license name",
45                     status: "expired",
46                     type: "alliance"
47                 },
48                 license_id:1,
49                 notes: "license notes",
50                 physical_location: "cupboard",
51                 status: "controlling",
52                 uri: "license uri"
53             },
54             {
55                 agreement_id: 1,
56                 agreement_license_id: 4,
57                 license: {
58                     description: "second license description",
59                     license_id: 2,
60                     name: "second license name",
61                     status: "expired",
62                     type: "alliance"
63                 },
64                 license_id:2,
65                 notes: "second license notes",
66                 physical_location: "cupboard",
67                 status: "future",
68                 uri: "license uri"
69             }
70         ],
71         agreement_relationships: [
72             {
73                 agreement_id: 1,
74                 notes: 'related agreement notes',
75                 related_agreement: {
76                     agreement_id: 2,
77                     description: "agreement description",
78                     name: "agreement name"
79                 },
80                 related_agreement_id: 2,
81                 relationship: "supersedes"
82             }
83         ],
84         agreement_packages: [],
85         documents: [
86             {
87                 agreement_id:1,
88                 file_description: "file description",
89                 file_name: "file.json",
90                 notes: "file notes",
91                 physical_location: "file physical location",
92                 uri: "file uri",
93                 uploaded_on: "2022-10-27T11:57:02+00:00"
94             }
95         ],
96     };
97 }
98
99 function get_licenses_to_relate() {
100     return [
101         {
102             license_id: 1,
103             description: "a license",
104             name: "first license name"
105         },
106         {
107             license_id: 2,
108             description: "a second license",
109             name: "second license name"
110         },
111         {
112             license_id: 3,
113             description: "a third license",
114             name: "third license name"
115         },
116     ]
117 }
118
119 describe("Agreement CRUD operations", () => {
120     before(() => {
121         cy.fetch_initial_ERM_sys_pref_value();
122         cy.set_ERM_sys_pref_value(true);
123     });
124
125     beforeEach(() => {
126         cy.login("koha", "koha");
127         cy.title().should("eq", "Koha staff interface");
128     });
129
130     after(() => {
131         cy.reset_initial_ERM_sys_pref_value();
132     });
133
134     it("List agreements", () => {
135         // GET agreements returns 500
136         cy.intercept("GET", "/api/v1/erm/agreements", {
137             statusCode: 500,
138             error: "Something went wrong",
139         });
140         cy.visit("/cgi-bin/koha/erm/erm.pl");
141         cy.get("#navmenulist").contains("Agreements").click();
142         cy.get("main div[class='dialog alert']").contains(
143             /Something went wrong/
144         );
145
146         // GET agreements returns empty list
147         cy.intercept("GET", "/api/v1/erm/agreements*", []);
148         cy.visit("/cgi-bin/koha/erm/agreements");
149         cy.get("#agreements_list").contains("There are no agreements defined");
150
151         // GET agreements returns something
152         let agreement = get_agreement();
153         let agreements = [agreement];
154
155         cy.intercept("GET", "/api/v1/erm/agreements*", {
156             statusCode: 200,
157             body: agreements,
158             headers: {
159                 "X-Base-Total-Count": "1",
160                 "X-Total-Count": "1",
161             },
162         });
163         cy.intercept("GET", "/api/v1/erm/agreements/*", agreement);
164         cy.visit("/cgi-bin/koha/erm/agreements");
165         cy.get("#agreements_list").contains("Showing 1 to 1 of 1 entries");
166     });
167
168     it("Add agreement", () => {
169         // No agreement, no license yet
170         cy.intercept("GET", "/api/v1/erm/agreements", {
171             statusCode: 200,
172             body: [],
173         });
174         cy.intercept("GET", "/api/v1/erm/licenses", {
175             statusCode: 200,
176             body: [],
177         });
178
179         // Click the button in the toolbar
180         cy.visit("/cgi-bin/koha/erm/agreements");
181         cy.contains("New agreement").click();
182         cy.get("#agreements_add h2").contains("New agreement");
183
184         // Fill in the form for normal attributes
185         let agreement = get_agreement();
186
187         cy.get("#agreements_add").contains("Submit").click();
188         cy.get("input:invalid,textarea:invalid,select:invalid").should(
189             "have.length",
190             3
191         );
192         cy.get("#agreement_name").type(agreement.name);
193         cy.get("#agreement_description").type(agreement.description);
194         cy.get("#agreements_add").contains("Submit").click();
195         cy.get("input:invalid,textarea:invalid,select:invalid").should(
196             "have.length",
197             1
198         ); // name, description, status
199         cy.get("#agreement_status .vs__search").type(
200             agreement.status + "{enter}",
201             { force: true }
202         );
203
204         cy.contains("Add new period").click();
205         cy.get("#agreements_add").contains("Submit").click();
206         cy.get("input:invalid,textarea:invalid,select:invalid").should(
207             "have.length",
208             1
209         ); // Start date
210
211         // Add new periods
212         cy.contains("Add new period").click();
213         cy.contains("Add new period").click();
214         cy.get("#agreement_periods > fieldset").should("have.length", 3);
215
216         cy.get("#agreement_period_1").contains("Remove this period").click();
217
218         cy.get("#agreement_periods > fieldset").should("have.length", 2);
219         cy.get("#agreement_period_0");
220         cy.get("#agreement_period_1");
221
222         // Selecting the flatpickr values is a bit tedious here...
223         // We have 3 date inputs per period
224         cy.get("#ended_on_0+input").click();
225         // Second flatpickr => ended_on for the first period
226         cy.get(".flatpickr-calendar")
227             .eq(1)
228             .find("span.today")
229             .click({ force: true }); // select today. No idea why we should force, but there is a random failure otherwise
230
231         cy.get("#started_on_0+input").click();
232         cy.get(".flatpickr-calendar")
233             .eq(0)
234             .find("span.today")
235             .next("span")
236             .click(); // select tomorrow
237
238         cy.get("#ended_on_0").should("have.value", ""); // Has been reset correctly
239
240         cy.get("#started_on_0+input").click();
241         cy.get(".flatpickr-calendar").eq(0).find("span.today").click(); // select today
242         cy.get("#ended_on_0+input").click({ force: true }); // No idea why we should force, but there is a random failure otherwise
243         cy.get(".flatpickr-calendar")
244             .eq(1)
245             .find("span.today")
246             .next("span")
247             .click(); // select tomorrow
248
249         // Second period
250         cy.get("#started_on_1+input").click({ force: true });
251         cy.get(".flatpickr-calendar").eq(3).find("span.today").click(); // select today
252         cy.get("#cancellation_deadline_1+input").click();
253         cy.get(".flatpickr-calendar")
254             .eq(5)
255             .find("span.today")
256             .next("span")
257             .click(); // select tomorrow
258         cy.get("#notes_1").type("this is a note");
259
260         // TODO Add a new user
261         // How to test a new window with cypresS?
262         //cy.contains("Add new user").click();
263         //cy.contains("Select user").click();
264
265         cy.get("#agreement_licenses").contains(
266             "There are no licenses created yet"
267         );
268         cy.get("#agreement_relationships").contains(
269             "There are no other agreements created yet"
270         );
271
272         // Add new document
273         cy.get("#documents").contains("Add new document").click();
274         cy.get("#document_0 input[id=file_0]").click();
275         cy.get('#document_0 input[id=file_0]').selectFile('t/cypress/fixtures/file.json');
276         cy.get("#document_0 .file_information span").contains("file.json");
277         cy.get('#document_0 input[id=file_description_0]').type('file description');
278         cy.get('#document_0 input[id=physical_location_0]').type('file physical location');
279         cy.get('#document_0 input[id=uri_0]').type('file URI');
280         cy.get('#document_0 input[id=notes_0]').type('file notes');
281
282         // Submit the form, get 500
283         cy.intercept("POST", "/api/v1/erm/agreements", {
284             statusCode: 500,
285             error: "Something went wrong",
286         });
287         cy.get("#agreements_add").contains("Submit").click();
288         cy.get("main div[class='dialog alert']").contains(
289             "Something went wrong: Internal Server Error"
290         );
291
292         // Submit the form, success!
293         cy.intercept("POST", "/api/v1/erm/agreements", {
294             statusCode: 201,
295             body: agreement,
296         });
297         cy.get("#agreements_add").contains("Submit").click();
298         cy.get("main div[class='dialog message']").contains(
299             "Agreement created"
300         );
301
302         cy.intercept("GET", "/api/v1/erm/agreements", {
303             statusCode: 200,
304             body: [{ agreement_id: 1, description: "an existing agreement" }],
305         });
306
307         // Add new license
308         let licenses_to_relate = get_licenses_to_relate();
309         let related_license = agreement.agreement_licenses[0];
310         cy.intercept("GET", "/api/v1/erm/licenses", {
311             statusCode: 200,
312             body: licenses_to_relate,
313         });
314         cy.visit("/cgi-bin/koha/erm/agreements/add");
315         cy.get("#agreement_licenses").contains("Add new license").click();
316         cy.get("#agreement_license_0").contains("Agreement license 1");
317         cy.get("#agreement_license_0 #license_id_0 .vs__search").type(
318             related_license.license.name
319         );
320         cy.get("#agreement_license_0 #license_id_0 .vs__dropdown-menu li").eq(0).click( { force: true } ); //click first license suggestion
321         cy.get("#agreement_license_0 #license_status_0 .vs__search").type(
322             related_license.status + "{enter}",
323             { force: true }
324         );
325         cy.get("#agreement_license_0 #license_location_0 .vs__search").type(
326             related_license.physical_location + "{enter}",
327             { force: true }
328         );
329         cy.get("#agreement_license_0 #license_notes_0").type(related_license.notes);
330         cy.get("#agreement_license_0 #license_uri_0").type(related_license.uri);
331
332         // Add new related agreement
333         let related_agreement = agreement.agreement_relationships[0];
334         cy.intercept("GET", "/api/v1/erm/agreements", {
335             statusCode: 200,
336             body: cy.get_agreements_to_relate(),
337         });
338         cy.visit("/cgi-bin/koha/erm/agreements/add");
339         cy.get("#agreement_relationships").contains("Add new related agreement").click();
340         cy.get("#related_agreement_0").contains("Related agreement 1");
341         cy.get("#related_agreement_0 #related_agreement_id_0 .vs__search").type(
342             related_agreement.related_agreement.name
343         );
344         cy.get("#related_agreement_0 #related_agreement_id_0 .vs__dropdown-menu li").eq(0).click( { force: true } ); //click first agreement suggestion
345         cy.get("#related_agreement_0 #related_agreement_notes_0").type(related_agreement.notes);
346         cy.get("#related_agreement_0 #related_agreement_relationship_0 .vs__search").type(
347             related_agreement.relationship + "{enter}",
348             { force: true }
349         );
350     });
351
352     it("Edit agreement", () => {
353         let licenses_to_relate = get_licenses_to_relate();
354         let agreement = get_agreement();
355         let agreements = [agreement];
356
357         // Intercept initial /agreements request once
358         cy.intercept(
359             {
360                 method: "GET",
361                 url: "/api/v1/erm/agreements",
362                 times: 1
363             },
364             {
365                 body: agreements
366             }
367         );
368
369         // Intercept follow-up 'search' request after entering /agreements
370         cy.intercept("GET", "/api/v1/erm/agreements?_page*", {
371             statusCode: 200,
372             body: agreements,
373             headers: {
374                 "X-Base-Total-Count": "1",
375                 "X-Total-Count": "1",
376             },
377         }).as("get-single-agreement-search-result");
378         cy.visit("/cgi-bin/koha/erm/agreements");
379
380         // Intercept request after edit click
381         cy.intercept("GET", "/api/v1/erm/agreements/*", agreement).as(
382             "get-agreement"
383         );
384         // Intercept related licenses request after entering agreement edit
385         cy.intercept("GET", "/api/v1/erm/licenses", {
386             statusCode: 200,
387             body: licenses_to_relate,
388         }).as("get-related-licenses");
389         // Intercept related agreements request after entering agreement edit
390         cy.intercept("GET", "/api/v1/erm/agreements", {
391             statusCode: 200,
392             body: cy.get_agreements_to_relate(),
393         }).as("get-related-agreements");
394
395         // Click the 'Edit' button from the list
396         cy.get("#agreements_list table tbody tr:first")
397             .contains("Edit")
398             .click();
399         cy.wait("@get-agreement");
400         cy.wait(500); // Cypress is too fast! Vue hasn't populated the form yet!
401         cy.get("#agreements_add h2").contains("Edit agreement");
402
403         // Form has been correctly filled in
404         cy.get("#agreement_name").should("have.value", agreements[0].name);
405         cy.get("#agreement_description").should(
406             "have.value",
407             agreements[0].description
408         );
409         cy.get("#agreement_status .vs__selected").contains("Active");
410         cy.get("#agreement_is_perpetual_no").should("be.checked");
411         cy.get("#started_on_0").invoke("val").should("eq", dates["today_iso"]);
412         cy.get("#ended_on_0").invoke("val").should("eq", dates["tomorrow_iso"]);
413         cy.get("#cancellation_deadline_0").invoke("val").should("eq", "");
414         cy.get("#notes_0").should("have.value", "");
415         cy.get("#started_on_1").invoke("val").should("eq", dates["today_iso"]);
416         cy.get("#ended_on_1").invoke("val").should("eq", "");
417         cy.get("#cancellation_deadline_1")
418             .invoke("val")
419             .should("eq", dates["tomorrow_iso"]);
420         cy.get("#notes_1").should("have.value", "this is a note");
421
422         //Test related content
423         cy.get("#agreement_license_0 #license_id_0 .vs__selected").contains("first license name");
424         cy.get("#agreement_license_1 #license_id_1 .vs__selected").contains("second license name");
425         cy.get("#document_0 .file_information span").contains("file.json" );
426         cy.get("#related_agreement_0 #related_agreement_id_0 .vs__selected").contains("agreement name");
427
428         // Submit the form, get 500
429         cy.intercept("PUT", "/api/v1/erm/agreements/*", {
430             statusCode: 500,
431             error: "Something went wrong",
432         });
433         cy.get("#agreements_add").contains("Submit").click();
434         cy.get("main div[class='dialog alert']").contains(
435             "Something went wrong: Internal Server Error"
436         );
437
438         // Submit the form, success!
439         cy.intercept("PUT", "/api/v1/erm/agreements/*", {
440             statusCode: 200,
441             body: agreement,
442         });
443         cy.get("#agreements_add").contains("Submit").click();
444         cy.get("main div[class='dialog message']").contains(
445             "Agreement updated"
446         );
447     });
448
449     it("Show agreement", () => {
450         let agreement = get_agreement();
451         let agreements = [agreement];
452         // Click the "name" link from the list
453         cy.intercept("GET", "/api/v1/erm/agreements*", {
454             statusCode: 200,
455             body: agreements,
456             headers: {
457                 "X-Base-Total-Count": "1",
458                 "X-Total-Count": "1",
459             },
460         });
461         cy.intercept("GET", "/api/v1/erm/agreements/*", agreement).as(
462             "get-agreement"
463         );
464         cy.visit("/cgi-bin/koha/erm/agreements");
465         let name_link = cy.get(
466             "#agreements_list table tbody tr:first td:first a"
467         );
468         name_link.should(
469             "have.text",
470             agreement.name + " (#" + agreement.agreement_id + ")"
471         );
472         name_link.click();
473         cy.wait("@get-agreement");
474         cy.wait(500); // Cypress is too fast! Vue hasn't populated the form yet!
475         cy.get("#agreements_show h2").contains(
476             "Agreement #" + agreement.agreement_id
477         );
478
479         // TODO There are more to test here:
480         // Dates correctly formatted
481         // Vendors displayed
482         // AV's libs displayed
483         // Tables for periods and users
484     });
485     it("Delete agreement", () => {
486         let agreement = get_agreement();
487         let agreements = [agreement];
488
489         // Click the 'Delete' button from the list
490         cy.intercept("GET", "/api/v1/erm/agreements*", {
491             statusCode: 200,
492             body: agreements,
493             headers: {
494                 "X-Base-Total-Count": "1",
495                 "X-Total-Count": "1",
496             },
497         });
498         cy.intercept("GET", "/api/v1/erm/agreements/*", agreement);
499         cy.visit("/cgi-bin/koha/erm/agreements");
500
501         cy.get("#agreements_list table tbody tr:first")
502             .contains("Delete")
503             .click();
504         cy.get("#agreements_confirm_delete h2").contains("Delete agreement");
505         cy.contains("Agreement name: " + agreement.name);
506
507         // Submit the form, get 500
508         cy.intercept("DELETE", "/api/v1/erm/agreements/*", {
509             statusCode: 500,
510             error: "Something went wrong",
511         });
512         cy.contains("Yes, delete").click();
513         cy.get("main div[class='dialog alert']").contains(
514             "Something went wrong: Internal Server Error"
515         );
516
517         // Submit the form, success!
518         cy.intercept("DELETE", "/api/v1/erm/agreements/*", {
519             statusCode: 204,
520             body: null,
521         });
522         cy.contains("Yes, delete").click();
523         cy.get("main div[class='dialog message']").contains(
524             "Agreement deleted"
525         );
526     });
527 });