Bug 32030: Fix Cypress tests - flatpickr date format
[koha.git] / 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         agreement_relationships: [],
39         agreement_packages: [],
40         documents: [],
41     };
42 }
43
44 describe("Agreement CRUD operations", () => {
45     beforeEach(() => {
46         cy.login("koha", "koha");
47         cy.title().should("eq", "Koha staff interface");
48     });
49
50     it("List agreements", () => {
51         // GET agreements returns 500
52         cy.intercept("GET", "/api/v1/erm/agreements", {
53             statusCode: 500,
54             error: "Something went wrong",
55         });
56         cy.visit("/cgi-bin/koha/erm/erm.pl");
57         cy.get("#navmenulist").contains("Agreements").click();
58         cy.get("main div[class='dialog alert']").contains(
59             /Something went wrong/
60         );
61
62         // GET agreements returns empty list
63         cy.intercept("GET", "/api/v1/erm/agreements*", []);
64         cy.visit("/cgi-bin/koha/erm/agreements");
65         cy.get("#agreements_list").contains("There are no agreements defined");
66
67         // GET agreements returns something
68         let agreement = get_agreement();
69         let agreements = [agreement];
70
71         cy.intercept("GET", "/api/v1/erm/agreements*", {
72             statusCode: 200,
73             body: agreements,
74             headers: {
75                 "X-Base-Total-Count": "1",
76                 "X-Total-Count": "1",
77             },
78         });
79         cy.intercept("GET", "/api/v1/erm/agreements/*", agreement);
80         cy.visit("/cgi-bin/koha/erm/agreements");
81         cy.get("#agreements_list").contains("Showing 1 to 1 of 1 entries");
82     });
83
84     it("Add agreement", () => {
85         // No agreement, no license yet
86         cy.intercept("GET", "/api/v1/erm/agreements", {
87             statusCode: 200,
88             body: [],
89         });
90         cy.intercept("GET", "/api/v1/erm/licenses", {
91             statusCode: 200,
92             body: [],
93         });
94
95         // Click the button in the toolbar
96         cy.visit("/cgi-bin/koha/erm/agreements");
97         cy.contains("New agreement").click();
98         cy.get("#agreements_add h2").contains("New agreement");
99
100         // Fill in the form for normal attributes
101         let agreement = get_agreement();
102
103         cy.get("#agreements_add").contains("Submit").click();
104         cy.get("input:invalid,textarea:invalid,select:invalid").should(
105             "have.length",
106             3
107         );
108         cy.get("#agreement_name").type(agreement.name);
109         cy.get("#agreement_description").type(agreement.description);
110         cy.get("#agreements_add").contains("Submit").click();
111         cy.get("input:invalid,textarea:invalid,select:invalid").should(
112             "have.length",
113             1
114         ); // name, description, status
115         cy.get("#agreement_status .vs__search").type(
116             agreement.status + "{enter}",
117             { force: true }
118         );
119
120         cy.contains("Add new period").click();
121         cy.get("#agreements_add").contains("Submit").click();
122         cy.get("input:invalid,textarea:invalid,select:invalid").should(
123             "have.length",
124             1
125         ); // Start date
126
127         // Add new periods
128         cy.contains("Add new period").click();
129         cy.contains("Add new period").click();
130         cy.get("#agreement_periods > fieldset").should("have.length", 3);
131
132         cy.get("#agreement_period_1").contains("Remove this period").click();
133
134         cy.get("#agreement_periods > fieldset").should("have.length", 2);
135         cy.get("#agreement_period_0");
136         cy.get("#agreement_period_1");
137
138         // Selecting the flatpickr values is a bit tedious here...
139         // We have 3 date inputs per period
140         cy.get("#ended_on_0+input").click();
141         // Second flatpickr => ended_on for the first period
142         cy.get(".flatpickr-calendar")
143             .eq(1)
144             .find("span.today")
145             .click({ force: true }); // select today. No idea why we should force, but there is a random failure otherwise
146
147         cy.get("#started_on_0+input").click();
148         cy.get(".flatpickr-calendar")
149             .eq(0)
150             .find("span.today")
151             .next("span")
152             .click(); // select tomorrow
153
154         cy.get("#ended_on_0").should("have.value", ""); // Has been reset correctly
155
156         cy.get("#started_on_0+input").click();
157         cy.get(".flatpickr-calendar").eq(0).find("span.today").click(); // select today
158         cy.get("#ended_on_0+input").click({ force: true }); // No idea why we should force, but there is a random failure otherwise
159         cy.get(".flatpickr-calendar")
160             .eq(1)
161             .find("span.today")
162             .next("span")
163             .click(); // select tomorrow
164
165         // Second period
166         cy.get("#started_on_1+input").click({ force: true });
167         cy.get(".flatpickr-calendar").eq(3).find("span.today").click(); // select today
168         cy.get("#cancellation_deadline_1+input").click();
169         cy.get(".flatpickr-calendar")
170             .eq(5)
171             .find("span.today")
172             .next("span")
173             .click(); // select tomorrow
174         cy.get("#notes_1").type("this is a note");
175
176         // TODO Add a new user
177         // How to test a new window with cypresS?
178         //cy.contains("Add new user").click();
179         //cy.contains("Select user").click();
180
181         cy.get("#agreement_licenses").contains(
182             "There are no licenses created yet"
183         );
184         cy.get("#agreement_relationships").contains(
185             "There are no other agreements created yet"
186         );
187
188         cy.get("#agreement_documents").contains("Add new document");
189         // TODO Test document upload
190
191         // Submit the form, get 500
192         cy.intercept("POST", "/api/v1/erm/agreements", {
193             statusCode: 500,
194             error: "Something went wrong",
195         });
196         cy.get("#agreements_add").contains("Submit").click();
197         cy.get("main div[class='dialog alert']").contains(
198             "Something went wrong: Internal Server Error"
199         );
200
201         // Submit the form, success!
202         cy.intercept("POST", "/api/v1/erm/agreements", {
203             statusCode: 201,
204             body: agreement,
205         });
206         cy.get("#agreements_add").contains("Submit").click();
207         cy.get("main div[class='dialog message']").contains(
208             "Agreement created"
209         );
210
211         cy.intercept("GET", "/api/v1/erm/agreements", {
212             statusCode: 200,
213             body: [{ agreement_id: 1, description: "an existing agreement" }],
214         });
215         cy.intercept("GET", "/api/v1/erm/licenses", {
216             statusCode: 200,
217             body: [{ license_id: 1, description: "a license" }],
218         });
219         cy.visit("/cgi-bin/koha/erm/agreements/add");
220         cy.get("#agreement_licenses").contains(
221             "Add new license"
222         );
223         cy.get("#agreement_relationships").contains(
224             "Add new related agreement"
225         );
226
227     });
228
229     it("Edit agreement", () => {
230         let agreement = get_agreement();
231         let agreements = [agreement];
232         // Click the 'Edit' button from the list
233         cy.intercept("GET", "/api/v1/erm/agreements*", {
234             statusCode: 200,
235             body: agreements,
236             headers: {
237                 "X-Base-Total-Count": "1",
238                 "X-Total-Count": "1",
239             },
240         });
241         cy.intercept("GET", "/api/v1/erm/agreements/*", agreement).as(
242             "get-agreement"
243         );
244         cy.visit("/cgi-bin/koha/erm/agreements");
245         cy.get("#agreements_list table tbody tr:first")
246             .contains("Edit")
247             .click();
248         cy.wait("@get-agreement");
249         cy.wait(500); // Cypress is too fast! Vue hasn't populated the form yet!
250         cy.get("#agreements_add h2").contains("Edit agreement");
251
252         // Form has been correctly filled in
253         cy.get("#agreement_name").should("have.value", agreements[0].name);
254         cy.get("#agreement_description").should(
255             "have.value",
256             agreements[0].description
257         );
258         cy.get("#agreement_status .vs__selected").contains("Active");
259         cy.get("#agreement_is_perpetual_no").should("be.checked");
260         cy.get("#started_on_0").invoke("val").should("eq", dates["today_iso"]);
261         cy.get("#ended_on_0").invoke("val").should("eq", dates["tomorrow_iso"]);
262         cy.get("#cancellation_deadline_0").invoke("val").should("eq", "");
263         cy.get("#notes_0").should("have.value", "");
264         cy.get("#started_on_1").invoke("val").should("eq", dates["today_iso"]);
265         cy.get("#ended_on_1").invoke("val").should("eq", "");
266         cy.get("#cancellation_deadline_1")
267             .invoke("val")
268             .should("eq", dates["tomorrow_iso"]);
269         cy.get("#notes_1").should("have.value", "this is a note");
270
271         // Submit the form, get 500
272         cy.intercept("PUT", "/api/v1/erm/agreements/*", {
273             statusCode: 500,
274             error: "Something went wrong",
275         });
276         cy.get("#agreements_add").contains("Submit").click();
277         cy.get("main div[class='dialog alert']").contains(
278             "Something went wrong: Internal Server Error"
279         );
280
281         // Submit the form, success!
282         cy.intercept("PUT", "/api/v1/erm/agreements/*", {
283             statusCode: 200,
284             body: agreement,
285         });
286         cy.get("#agreements_add").contains("Submit").click();
287         cy.get("main div[class='dialog message']").contains(
288             "Agreement updated"
289         );
290     });
291
292     it("Show agreement", () => {
293         let agreement = get_agreement();
294         let agreements = [agreement];
295         // Click the "name" link from the list
296         cy.intercept("GET", "/api/v1/erm/agreements*", {
297             statusCode: 200,
298             body: agreements,
299             headers: {
300                 "X-Base-Total-Count": "1",
301                 "X-Total-Count": "1",
302             },
303         });
304         cy.intercept("GET", "/api/v1/erm/agreements/*", agreement).as(
305             "get-agreement"
306         );
307         cy.visit("/cgi-bin/koha/erm/agreements");
308         let name_link = cy.get(
309             "#agreements_list table tbody tr:first td:first a"
310         );
311         name_link.should(
312             "have.text",
313             agreement.name + " (#" + agreement.agreement_id + ")"
314         );
315         name_link.click();
316         cy.wait("@get-agreement");
317         cy.wait(500); // Cypress is too fast! Vue hasn't populated the form yet!
318         cy.get("#agreements_show h2").contains(
319             "Agreement #" + agreement.agreement_id
320         );
321
322         // TODO There are more to test here:
323         // Dates correctly formatted
324         // Vendors displayed
325         // AV's libs displayed
326         // Tables for periods and users
327     });
328     it("Delete agreement", () => {
329         let agreement = get_agreement();
330         let agreements = [agreement];
331
332         // Click the 'Delete' button from the list
333         cy.intercept("GET", "/api/v1/erm/agreements*", {
334             statusCode: 200,
335             body: agreements,
336             headers: {
337                 "X-Base-Total-Count": "1",
338                 "X-Total-Count": "1",
339             },
340         });
341         cy.intercept("GET", "/api/v1/erm/agreements/*", agreement);
342         cy.visit("/cgi-bin/koha/erm/agreements");
343
344         cy.get("#agreements_list table tbody tr:first")
345             .contains("Delete")
346             .click();
347         cy.get("#agreements_confirm_delete h2").contains("Delete agreement");
348         cy.contains("Agreement name: " + agreement.name);
349
350         // Submit the form, get 500
351         cy.intercept("DELETE", "/api/v1/erm/agreements/*", {
352             statusCode: 500,
353             error: "Something went wrong",
354         });
355         cy.contains("Yes, delete").click();
356         cy.get("main div[class='dialog alert']").contains(
357             "Something went wrong: Internal Server Error"
358         );
359
360         // Submit the form, success!
361         cy.intercept("DELETE", "/api/v1/erm/agreements/*", {
362             statusCode: 204,
363             body: null,
364         });
365         cy.contains("Yes, delete").click();
366         cy.get("main div[class='dialog message']").contains(
367             "Agreement deleted"
368         );
369     });
370 });