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 */
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"),
11 function get_agreement() {
15 description: "my first agreement",
24 started_on: dates["today_iso"],
25 ended_on: dates["tomorrow_iso"],
26 cancellation_deadline: null,
30 started_on: dates["today_iso"],
32 cancellation_deadline: dates["tomorrow_iso"],
33 notes: "this is a note",
40 agreement_license_id: 3,
42 description: "license description",
49 notes: "license notes",
50 physical_location: "cupboard",
51 status: "controlling",
56 agreement_license_id: 4,
58 description: "second license description",
60 name: "second license name",
65 notes: "second license notes",
66 physical_location: "cupboard",
71 agreement_relationships: [
74 notes: 'related agreement notes',
77 description: "agreement description",
78 name: "agreement name"
80 related_agreement_id: 2,
81 relationship: "supersedes"
84 agreement_packages: [],
88 file_description: "file description",
89 file_name: "file.json",
91 physical_location: "file physical location",
93 uploaded_on: "2022-10-27T11:57:02+00:00"
99 function get_licenses_to_relate() {
103 description: "a license",
104 name: "first license name"
108 description: "a second license",
109 name: "second license name"
113 description: "a third license",
114 name: "third license name"
119 describe("Agreement CRUD operations", () => {
122 cy.title().should("eq", "Koha staff interface");
123 cy.intercept("GET", "/cgi-bin/koha/svc/config/systempreferences/?pref=ERMModule", '{"value":"1"}');
124 cy.intercept("GET", "/cgi-bin/koha/svc/config/systempreferences/?pref=ERMProviders", '{"value":"local"}');
127 it("List agreements", () => {
128 // GET agreements returns 500
129 cy.intercept("GET", "/api/v1/erm/agreements*", {
131 error: "Something went wrong",
133 cy.visit("/cgi-bin/koha/erm/erm.pl");
134 cy.get("#navmenulist").contains("Agreements").click();
135 cy.get("main div[class='dialog alert']").contains(
136 /Something went wrong/
139 // GET agreements returns empty list
140 cy.intercept("GET", "/api/v1/erm/agreements*", []);
141 cy.visit("/cgi-bin/koha/erm/agreements");
142 cy.get("#agreements_list").contains("There are no agreements defined");
144 // GET agreements returns something
145 let agreement = get_agreement();
146 let agreements = [agreement];
148 cy.intercept("GET", "/api/v1/erm/agreements*", {
152 "X-Base-Total-Count": "1",
153 "X-Total-Count": "1",
156 cy.intercept("GET", "/api/v1/erm/agreements/*", agreement);
157 cy.visit("/cgi-bin/koha/erm/agreements");
158 cy.get("#agreements_list").contains("Showing 1 to 1 of 1 entries");
159 cy.get(".filters").find("label").should(($labels) => {
160 expect($labels).to.have.length(2)
161 expect($labels.eq(0)).to.contain('Filter by expired')
162 expect($labels.eq(1)).to.contain('Show mine only')
163 }); // Filter options appear
166 cy.intercept("GET", "/api/v1/erm/agreements?max_expiration_date=*", []).as("getActiveAgreements");
167 cy.get("#expired_filter").check();
168 cy.get("#filter_table").click();
169 cy.wait('@getActiveAgreements')
171 .should('include', 'max_expiration_date='+dates["today_iso"]); // Defaults to today
172 cy.get("#max_expiration_date_filter").should("have.value", dates["today_iso"]); // Input box reflects default
173 cy.url().should('include', "/cgi-bin/koha/erm/agreements?by_expired=true&max_expiration_date="+dates["today_iso"]); // Browser url also updated
175 // Now test that the url for this particular state works
176 cy.visit("/cgi-bin/koha/erm/agreements?by_expired=true&max_expiration_date="+dates["today_iso"]);
177 cy.wait('@getActiveAgreements').its('request.url').should('include', 'max_expiration_date='+dates["today_iso"]);
179 // Now test with a user entered date
180 cy.get("#max_expiration_date_filter+input").click({ force: true });
181 cy.get(".flatpickr-calendar")
185 .click(); // select tomorrow
186 cy.get("#filter_table").click();
187 cy.wait('@getActiveAgreements').its('request.url').should('include', 'max_expiration_date='+dates["tomorrow_iso"]);
188 cy.get("#max_expiration_date_filter").should("have.value", dates["tomorrow_iso"]);
189 // Assert that browser url changed again to reflect the user entered date
190 cy.url().should('include', "/cgi-bin/koha/erm/agreements?by_expired=true&max_expiration_date="+dates["tomorrow_iso"]);
192 // Now test that the url for the updated state works
193 cy.visit("/cgi-bin/koha/erm/agreements?by_expired=true&max_expiration_date="+dates["tomorrow_iso"]);
194 cy.wait('@getActiveAgreements').its('request.url').should('include', 'max_expiration_date='+dates["tomorrow_iso"]);
196 // Test filter button with show mine_only ticked
199 it("Add agreement", () => {
200 // No agreement, no license yet
201 cy.intercept("GET", "/api/v1/erm/agreements*", {
205 cy.intercept("GET", "/api/v1/erm/licenses*", {
210 // Click the button in the toolbar
211 cy.visit("/cgi-bin/koha/erm/agreements");
212 cy.contains("New agreement").click();
213 cy.get("#agreements_add h2").contains("New agreement");
215 // Fill in the form for normal attributes
216 let agreement = get_agreement();
218 cy.get("#agreements_add").contains("Submit").click();
219 cy.get("input:invalid,textarea:invalid,select:invalid").should(
223 cy.get("#agreement_name").type(agreement.name);
224 cy.get("#agreement_description").type(agreement.description);
225 cy.get("#agreements_add").contains("Submit").click();
226 cy.get("input:invalid,textarea:invalid,select:invalid").should(
229 ); // name, description, status
230 cy.get("#agreement_status .vs__search").type(
231 agreement.status + "{enter}",
235 cy.contains("Add new period").click();
236 cy.get("#agreements_add").contains("Submit").click();
237 cy.get("input:invalid,textarea:invalid,select:invalid").should(
243 cy.contains("Add new period").click();
244 cy.contains("Add new period").click();
245 cy.get("#agreement_periods > fieldset").should("have.length", 3);
247 cy.get("#agreement_period_1").contains("Remove this period").click();
249 cy.get("#agreement_periods > fieldset").should("have.length", 2);
250 cy.get("#agreement_period_0");
251 cy.get("#agreement_period_1");
253 // Selecting the flatpickr values is a bit tedious here...
254 // We have 3 date inputs per period
255 cy.get("#ended_on_0+input").click();
256 // Second flatpickr => ended_on for the first period
257 cy.get(".flatpickr-calendar")
260 .click({ force: true }); // select today. No idea why we should force, but there is a random failure otherwise
262 cy.get("#started_on_0+input").click();
263 cy.get(".flatpickr-calendar")
267 .click(); // select tomorrow
269 cy.get("#ended_on_0").should("have.value", ""); // Has been reset correctly
271 cy.get("#started_on_0+input").click();
272 cy.get(".flatpickr-calendar").eq(0).find("span.today").click(); // select today
273 cy.get("#ended_on_0+input").click({ force: true }); // No idea why we should force, but there is a random failure otherwise
274 cy.get(".flatpickr-calendar")
278 .click(); // select tomorrow
281 cy.get("#started_on_1+input").click({ force: true });
282 cy.get(".flatpickr-calendar").eq(3).find("span.today").click(); // select today
283 cy.get("#cancellation_deadline_1+input").click();
284 cy.get(".flatpickr-calendar")
288 .click(); // select tomorrow
289 cy.get("#notes_1").type("this is a note");
291 // TODO Add a new user
292 // How to test a new window with cypresS?
293 //cy.contains("Add new user").click();
294 //cy.contains("Select user").click();
296 cy.get("#agreement_licenses").contains(
297 "There are no licenses created yet"
299 cy.get("#agreement_relationships").contains(
300 "There are no other agreements created yet"
304 cy.get("#documents").contains("Add new document").click();
305 cy.get("#document_0 input[id=file_0]").click();
306 cy.get('#document_0 input[id=file_0]').selectFile('t/cypress/fixtures/file.json');
307 cy.get("#document_0 .file_information span").contains("file.json");
308 cy.get('#document_0 input[id=file_description_0]').type('file description');
309 cy.get('#document_0 input[id=physical_location_0]').type('file physical location');
310 cy.get('#document_0 input[id=uri_0]').type('file URI');
311 cy.get('#document_0 input[id=notes_0]').type('file notes');
313 // Submit the form, get 500
314 cy.intercept("POST", "/api/v1/erm/agreements", {
316 error: "Something went wrong",
318 cy.get("#agreements_add").contains("Submit").click();
319 cy.get("main div[class='dialog alert']").contains(
320 "Something went wrong: Error: Internal Server Error"
323 // Submit the form, success!
324 cy.intercept("POST", "/api/v1/erm/agreements", {
328 cy.get("#agreements_add").contains("Submit").click();
329 cy.get("main div[class='dialog message']").contains(
333 cy.intercept("GET", "/api/v1/erm/agreements*", {
335 body: [{ agreement_id: 1, description: "an existing agreement" }],
339 let licenses_to_relate = get_licenses_to_relate();
340 let related_license = agreement.agreement_licenses[0];
341 cy.intercept("GET", "/api/v1/erm/licenses*", {
343 body: licenses_to_relate,
345 cy.visit("/cgi-bin/koha/erm/agreements/add");
346 cy.get("#agreement_licenses").contains("Add new license").click();
347 cy.get("#agreement_license_0").contains("Agreement license 1");
348 cy.get("#agreement_license_0 #license_id_0 .vs__search").type(
349 related_license.license.name
351 cy.get("#agreement_license_0 #license_id_0 .vs__dropdown-menu li").eq(0).click( { force: true } ); //click first license suggestion
352 cy.get("#agreement_license_0 #license_status_0 .vs__search").type(
353 related_license.status + "{enter}",
356 cy.get("#agreement_license_0 #license_location_0 .vs__search").type(
357 related_license.physical_location + "{enter}",
360 cy.get("#agreement_license_0 #license_notes_0").type(related_license.notes);
361 cy.get("#agreement_license_0 #license_uri_0").type(related_license.uri);
363 // Add new related agreement
364 let related_agreement = agreement.agreement_relationships[0];
365 cy.intercept("GET", "/api/v1/erm/agreements*", {
367 body: cy.get_agreements_to_relate(),
369 cy.visit("/cgi-bin/koha/erm/agreements/add");
370 cy.get("#agreement_relationships").contains("Add new related agreement").click();
371 cy.get("#related_agreement_0").contains("Related agreement 1");
372 cy.get("#related_agreement_0 #related_agreement_id_0 .vs__search").type(
373 related_agreement.related_agreement.name
375 cy.get("#related_agreement_0 #related_agreement_id_0 .vs__dropdown-menu li").eq(0).click( { force: true } ); //click first agreement suggestion
376 cy.get("#related_agreement_0 #related_agreement_notes_0").type(related_agreement.notes);
377 cy.get("#related_agreement_0 #related_agreement_relationship_0 .vs__search").type(
378 related_agreement.relationship + "{enter}",
383 it("Edit agreement", () => {
384 let licenses_to_relate = get_licenses_to_relate();
385 let agreement = get_agreement();
386 let agreements = [agreement];
388 // Intercept initial /agreements request once
392 url: "/api/v1/erm/agreements*",
400 // Intercept follow-up 'search' request after entering /agreements
401 cy.intercept("GET", "/api/v1/erm/agreements?_page*", {
405 "X-Base-Total-Count": "1",
406 "X-Total-Count": "1",
408 }).as("get-single-agreement-search-result");
409 cy.visit("/cgi-bin/koha/erm/agreements");
410 cy.wait("@get-single-agreement-search-result");
412 // Intercept request after edit click
413 cy.intercept("GET", "/api/v1/erm/agreements/*", agreement).as(
416 // Intercept related licenses request after entering agreement edit
417 cy.intercept("GET", "/api/v1/erm/licenses*", {
419 body: licenses_to_relate,
420 }).as("get-related-licenses");
421 // Intercept related agreements request after entering agreement edit
422 cy.intercept("GET", "/api/v1/erm/agreements*", {
424 body: cy.get_agreements_to_relate(),
425 }).as("get-related-agreements");
427 // Click the 'Edit' button from the list
428 cy.get("#agreements_list table tbody tr:first")
431 cy.wait("@get-agreement");
432 cy.wait(500); // Cypress is too fast! Vue hasn't populated the form yet!
433 cy.get("#agreements_add h2").contains("Edit agreement");
435 // Form has been correctly filled in
436 cy.get("#agreement_name").should("have.value", agreements[0].name);
437 cy.get("#agreement_description").should(
439 agreements[0].description
441 cy.get("#agreement_status .vs__selected").contains("Active");
442 cy.get("#agreement_is_perpetual_no").should("be.checked");
443 cy.get("#started_on_0").invoke("val").should("eq", dates["today_iso"]);
444 cy.get("#ended_on_0").invoke("val").should("eq", dates["tomorrow_iso"]);
445 cy.get("#cancellation_deadline_0").invoke("val").should("eq", "");
446 cy.get("#notes_0").should("have.value", "");
447 cy.get("#started_on_1").invoke("val").should("eq", dates["today_iso"]);
448 cy.get("#ended_on_1").invoke("val").should("eq", "");
449 cy.get("#cancellation_deadline_1")
451 .should("eq", dates["tomorrow_iso"]);
452 cy.get("#notes_1").should("have.value", "this is a note");
454 //Test related content
455 cy.get("#agreement_license_0 #license_id_0 .vs__selected").contains("first license name");
456 cy.get("#agreement_license_1 #license_id_1 .vs__selected").contains("second license name");
457 cy.get("#document_0 .file_information span").contains("file.json" );
458 cy.get("#related_agreement_0 #related_agreement_id_0 .vs__selected").contains("agreement name");
460 // Submit the form, get 500
461 cy.intercept("PUT", "/api/v1/erm/agreements/*", (req) => {
464 error: "Something went wrong",
468 cy.get("#agreements_add").contains("Submit").click();
469 cy.get("main div[class='modal_centered']").contains("Submitting...");
471 cy.get("main div[class='dialog alert']").contains(
472 "Something went wrong: Error: Internal Server Error"
475 // Submit the form, success!
476 cy.intercept("PUT", "/api/v1/erm/agreements/*", {
480 cy.get("#agreements_add").contains("Submit").click();
481 cy.get("main div[class='dialog message']").contains(
486 it("Show agreement", () => {
487 let agreement = get_agreement();
488 let agreements = [agreement];
489 // Click the "name" link from the list
490 cy.intercept("GET", "/api/v1/erm/agreements*", {
494 "X-Base-Total-Count": "1",
495 "X-Total-Count": "1",
498 cy.intercept("GET", "/api/v1/erm/agreements/*", agreement).as(
501 cy.visit("/cgi-bin/koha/erm/agreements");
502 let name_link = cy.get(
503 "#agreements_list table tbody tr:first td:first a"
507 agreement.name + " (#" + agreement.agreement_id + ")"
510 cy.wait("@get-agreement");
511 cy.wait(500); // Cypress is too fast! Vue hasn't populated the form yet!
512 cy.get("#agreements_show h2").contains(
513 "Agreement #" + agreement.agreement_id
516 // TODO There are more to test here:
517 // Dates correctly formatted
519 // AV's libs displayed
520 // Tables for periods and users
522 it("Delete agreement", () => {
523 let agreement = get_agreement();
524 let agreements = [agreement];
527 // Click the 'Delete' button from the list
528 cy.intercept("GET", "/api/v1/erm/agreements*", {
532 "X-Base-Total-Count": "1",
533 "X-Total-Count": "1",
536 cy.intercept("GET", "/api/v1/erm/agreements/*", agreement);
537 cy.visit("/cgi-bin/koha/erm/agreements");
539 cy.get("#agreements_list table tbody tr:first")
542 cy.get(".dialog.alert.confirmation h1").contains("remove this agreement");
543 cy.contains(agreement.name);
545 // Accept the confirmation dialog, get 500
546 cy.intercept("DELETE", "/api/v1/erm/agreements/*", {
548 error: "Something went wrong",
550 cy.contains("Yes, delete").click();
551 cy.get("main div[class='dialog alert']").contains(
552 "Something went wrong: Error: Internal Server Error"
555 // Accept the confirmation dialog, success!
556 cy.intercept("DELETE", "/api/v1/erm/agreements/*", {
560 cy.get("#agreements_list table tbody tr:first")
563 cy.get(".dialog.alert.confirmation h1").contains("remove this agreement");
564 cy.contains("Yes, delete").click();
565 cy.get("main div[class='dialog message']").contains("Agreement").contains("deleted");
568 // Click the "name" link from the list
569 cy.intercept("GET", "/api/v1/erm/agreements*", {
573 "X-Base-Total-Count": "1",
574 "X-Total-Count": "1",
577 cy.intercept("GET", "/api/v1/erm/agreements/*", agreement).as(
580 cy.visit("/cgi-bin/koha/erm/agreements");
581 let name_link = cy.get(
582 "#agreements_list table tbody tr:first td:first a"
586 agreement.name + " (#" + agreement.agreement_id + ")"
589 cy.wait("@get-agreement");
590 cy.wait(500); // Cypress is too fast! Vue hasn't populated the form yet!
591 cy.get("#agreements_show h2").contains(
592 "Agreement #" + agreement.agreement_id
595 cy.get('#agreements_show .action_links .fa-trash').click();
596 cy.get(".dialog.alert.confirmation h1").contains("remove this agreement");
597 cy.contains("Yes, delete").click();
599 //Make sure we return to list after deleting from show
600 cy.get("#agreements_list table tbody tr:first")