From 4f7d5aa0a3122b29faf3c0d64bcbd6cd9c1c0697 Mon Sep 17 00:00:00 2001 From: Matt Blenkinsop Date: Thu, 30 Nov 2023 10:51:14 +0000 Subject: [PATCH] Bug 32474: Add cypress tests Signed-off-by: Jonathan Druart --- t/cypress/integration/ERM/Agreements_spec.ts | 114 +----- .../integration/InfiniteScrollSelect_spec.ts | 328 ++++++++++++++++++ t/cypress/support/e2e.js | 101 ++++++ 3 files changed, 436 insertions(+), 107 deletions(-) create mode 100644 t/cypress/integration/InfiniteScrollSelect_spec.ts diff --git a/t/cypress/integration/ERM/Agreements_spec.ts b/t/cypress/integration/ERM/Agreements_spec.ts index f682aaee0e5..e98bc3a7266 100644 --- a/t/cypress/integration/ERM/Agreements_spec.ts +++ b/t/cypress/integration/ERM/Agreements_spec.ts @@ -8,106 +8,6 @@ const dates = { tomorrow_iso: dayjs().add(1, "day").format("YYYY-MM-DD"), tomorrow_us: dayjs().add(1, "day").format("MM/DD/YYYY"), }; -function get_agreement() { - let licenses = get_licenses_to_relate(); - return { - agreement_id: 1, - closure_reason: "", - description: "my first agreement", - is_perpetual: false, - license_info: "", - name: "agreement 1", - renewal_priority: "", - status: "active", - vendor_id: 1, - vendor: [cy.get_vendors_to_relate()[0]], - periods: [ - { - started_on: dates["today_iso"], - ended_on: dates["tomorrow_iso"], - cancellation_deadline: null, - notes: null, - }, - { - started_on: dates["today_iso"], - ended_on: null, - cancellation_deadline: dates["tomorrow_iso"], - notes: "this is a note", - }, - ], - user_roles: [], - agreement_licenses: [ - { - agreement_id: 1, - agreement_license_id: 3, - license: licenses[0], - license_id: licenses[0].license_id, - notes: "license notes", - physical_location: "cupboard", - status: "controlling", - uri: "license uri", - }, - { - agreement_id: 1, - agreement_license_id: 4, - license: licenses[1], - license_id: licenses[1].license_id, - notes: "second license notes", - physical_location: "cupboard", - status: "future", - uri: "license uri", - }, - ], - agreement_relationships: [ - { - agreement_id: 1, - notes: "related agreement notes", - related_agreement: { - agreement_id: 2, - description: "agreement description", - name: "agreement name", - }, - related_agreement_id: 2, - relationship: "supersedes", - }, - ], - agreement_packages: [], - documents: [ - { - agreement_id: 1, - file_description: "file description", - file_name: "file.json", - notes: "file notes", - physical_location: "file physical location", - uri: "file uri", - uploaded_on: "2022-10-27T11:57:02+00:00", - }, - ], - }; -} - -function get_licenses_to_relate() { - return [ - { - license_id: 1, - description: "license description", - license_id: 1, - name: "first license name", - status: "expired", - type: "alliance", - }, - { - license_id: 2, - description: "a second license", - name: "second license name", - }, - { - license_id: 3, - description: "a third license", - name: "third license name", - }, - ]; -} describe("Agreement CRUD operations", () => { beforeEach(() => { @@ -137,7 +37,7 @@ describe("Agreement CRUD operations", () => { cy.get("#agreements_list").contains("There are no agreements defined"); // GET agreements returns something - let agreement = get_agreement(); + let agreement = cy.get_agreement(); let agreements = [agreement]; cy.intercept("GET", "/api/v1/erm/agreements*", { @@ -233,7 +133,7 @@ describe("Agreement CRUD operations", () => { }); it("Add agreement", () => { - let agreement = get_agreement(); + let agreement = cy.get_agreement(); let vendors = cy.get_vendors_to_relate(); // No agreement, no license yet cy.intercept("GET", "/api/v1/erm/agreements*", { @@ -399,7 +299,7 @@ describe("Agreement CRUD operations", () => { }); // Add new license - let licenses_to_relate = get_licenses_to_relate(); + let licenses_to_relate = cy.get_licenses_to_relate(); let related_license = agreement.agreement_licenses[0]; let licenses_count = licenses_to_relate.length.toString(); cy.intercept("GET", "/api/v1/erm/licenses*", { @@ -460,8 +360,8 @@ describe("Agreement CRUD operations", () => { }); it("Edit agreement", () => { - let licenses_to_relate = get_licenses_to_relate(); - let agreement = get_agreement(); + let licenses_to_relate = cy.get_licenses_to_relate(); + let agreement = cy.get_agreement(); let agreements = [agreement]; let vendors = cy.get_vendors_to_relate(); @@ -599,7 +499,7 @@ describe("Agreement CRUD operations", () => { }); it("Show agreement", () => { - let agreement = get_agreement(); + let agreement = cy.get_agreement(); let agreements = [agreement]; // Click the "name" link from the list cy.intercept("GET", "/api/v1/erm/agreements*", { @@ -636,7 +536,7 @@ describe("Agreement CRUD operations", () => { // Tables for periods and users }); it("Delete agreement", () => { - let agreement = get_agreement(); + let agreement = cy.get_agreement(); let agreements = [agreement]; // Delete from list diff --git a/t/cypress/integration/InfiniteScrollSelect_spec.ts b/t/cypress/integration/InfiniteScrollSelect_spec.ts new file mode 100644 index 00000000000..1a5295aeeee --- /dev/null +++ b/t/cypress/integration/InfiniteScrollSelect_spec.ts @@ -0,0 +1,328 @@ +import { mount } from "@cypress/vue"; +const dayjs = require("dayjs"); /* Cannot use our calendar JS code, it's in an include file (!) + Also note that moment.js is deprecated */ + +const dates = { + today_iso: dayjs().format("YYYY-MM-DD"), + today_us: dayjs().format("MM/DD/YYYY"), + tomorrow_iso: dayjs().add(1, "day").format("YYYY-MM-DD"), + tomorrow_us: dayjs().add(1, "day").format("MM/DD/YYYY"), +}; + +const createLicenses = start => { + const licenses = []; + for (let i = start; i < start + 20; i++) { + const newLicense = { + license_id: i, + name: "License " + i, + description: "A test license", + type: "local", + status: "active", + started_on: dates["today_iso"], + ended_on: dates["tomorrow_iso"], + user_roles: [], + }; + licenses.push(newLicense); + } + return licenses; +}; + +describe("Infinite scroll", () => { + beforeEach(() => { + cy.login(); + cy.title().should("eq", "Koha staff interface"); + cy.intercept( + "GET", + "/api/v1/erm/config", + '{"settings":{"ERMModule":"1","ERMProviders":["local"]}}' + ); + }); + + it("Should load the next page on scroll", () => { + const pageOne = createLicenses(1); + const pageTwo = createLicenses(21); + const pageThree = createLicenses(41); + const agreement = cy.get_agreement(); + const vendors = cy.get_vendors_to_relate(); + + // No agreement, no license yet + cy.intercept("GET", "/api/v1/erm/agreements*", { + statusCode: 200, + body: [], + }); + cy.intercept("GET", "/api/v1/erm/licenses*", { + statusCode: 200, + body: [], + }); + //Intercept vendors request + cy.intercept("GET", "/api/v1/acquisitions/vendors*", { + statusCode: 200, + body: vendors, + }); + cy.intercept("GET", "/api/v1/erm/licenses*", { + statusCode: 200, + body: pageOne, + headers: { + "X-Base-Total-Count": "20", + "X-Total-Count": "20", + }, + }); + + // Click the button in the toolbar + cy.visit("/cgi-bin/koha/erm/agreements"); + cy.contains("New agreement").click(); + + cy.get("#agreement_licenses").contains("Add new license").click(); + cy.get("#license_id_0 .vs__open-indicator").click(); + cy.get("#license_id_0").find("li").as("options"); + cy.get("@options").should("have.length", 20); + + cy.intercept("GET", "/api/v1/erm/licenses*", { + statusCode: 200, + body: pageTwo, + headers: { + "X-Base-Total-Count": "20", + "X-Total-Count": "20", + }, + }); + // Scroll the dropdown + cy.get(".vs__dropdown-menu").scrollTo("bottom"); + cy.get("@options").should("have.length", 40); + + cy.intercept("GET", "/api/v1/erm/licenses*", { + statusCode: 200, + body: pageThree, + headers: { + "X-Base-Total-Count": "20", + "X-Total-Count": "20", + }, + }); + // Scroll the dropdown again + cy.get(".vs__dropdown-menu").scrollTo("bottom"); + cy.get("@options").should("have.length", 60); + }); + + it("Should correctly submit the form", () => { + const pageOne = createLicenses(1); + const vendors = cy.get_vendors_to_relate(); + let agreement = cy.get_agreement(); + + // No agreement, no license yet + cy.intercept("GET", "/api/v1/erm/agreements*", { + statusCode: 200, + body: [], + }); + cy.intercept("GET", "/api/v1/erm/licenses*", { + statusCode: 200, + body: [], + }); + //Intercept vendors request + cy.intercept("GET", "/api/v1/acquisitions/vendors*", { + statusCode: 200, + body: vendors, + }); + cy.intercept("GET", "/api/v1/erm/licenses*", { + statusCode: 200, + body: pageOne, + headers: { + "X-Base-Total-Count": "20", + "X-Total-Count": "20", + }, + }); + + // Click the button in the toolbar + cy.visit("/cgi-bin/koha/erm/agreements"); + cy.contains("New agreement").click(); + + cy.get("#agreement_licenses").contains("Add new license").click(); + cy.get("#license_id_0 .vs__open-indicator").click(); + + cy.get("#agreement_license_0 #license_id_0 .vs__dropdown-menu li") + .eq(0) + .click({ force: true }); //click first license suggestion + + // Fill in the other required fields + cy.get("#agreement_name").type(agreement.name); + cy.get("#agreement_status .vs__search").type( + agreement.status + "{enter}", + { force: true } + ); + cy.get("#agreement_license_0 #license_status_0 .vs__search").type( + agreement.agreement_licenses[0].status + "{enter}", + { force: true } + ); + + cy.intercept("POST", "/api/v1/erm/agreements", { + statusCode: 201, + body: agreement, + }); + // Submit the form, no error should be thrown as the select has correctly set the license id + cy.get("#agreements_add").contains("Submit").click(); + cy.get("main div[class='dialog message']").contains( + "Agreement created" + ); + }); + + it("Should correctly display labels", () => { + const pageOne = createLicenses(1); + const pageTwo = createLicenses(21); + const pageThree = createLicenses(41); + const vendors = cy.get_vendors_to_relate(); + + // No agreement, no license yet + cy.intercept("GET", "/api/v1/erm/agreements*", { + statusCode: 200, + body: [], + }); + cy.intercept("GET", "/api/v1/erm/licenses*", { + statusCode: 200, + body: [], + }); + //Intercept vendors request + cy.intercept("GET", "/api/v1/acquisitions/vendors*", { + statusCode: 200, + body: vendors, + }); + cy.intercept("GET", "/api/v1/erm/licenses*", { + statusCode: 200, + body: pageOne, + headers: { + "X-Base-Total-Count": "20", + "X-Total-Count": "20", + }, + }); + + // Click the button in the toolbar + cy.visit("/cgi-bin/koha/erm/agreements"); + cy.contains("New agreement").click(); + + cy.get("#agreement_licenses").contains("Add new license").click(); + cy.get("#license_id_0 .vs__open-indicator").click(); + cy.get("#license_id_0").find("li").as("options"); + cy.get("@options").should("have.length", 20); + + cy.intercept("GET", "/api/v1/erm/licenses*", { + statusCode: 200, + body: pageTwo, + headers: { + "X-Base-Total-Count": "20", + "X-Total-Count": "20", + }, + }); + // Scroll the dropdown + cy.get(".vs__dropdown-menu").scrollTo("bottom"); + + cy.intercept("GET", "/api/v1/erm/licenses*", { + statusCode: 200, + body: pageThree, + headers: { + "X-Base-Total-Count": "20", + "X-Total-Count": "20", + }, + }).as("finalPage"); + // Scroll the dropdown again + cy.get(".vs__dropdown-menu").scrollTo("bottom"); + cy.wait("@finalPage"); + + // Select a license that is not in the first page of results + cy.get("#agreement_license_0 #license_id_0 .vs__search").type( + "License 50{enter}", + { force: true } + ); + cy.get("#agreement_license_0").contains("License 50"); + + // Re-open the dropdown, License 50 will no longer be in the dataset but the label should still show + cy.intercept("GET", "/api/v1/erm/licenses*", { + statusCode: 200, + body: pageOne, + headers: { + "X-Base-Total-Count": "20", + "X-Total-Count": "20", + }, + }); + cy.get("#license_id_0 .vs__open-indicator").click(); + cy.get("#agreement_licenses").click(); + cy.get("#agreement_license_0").contains("License 50"); + + // Select a different license + cy.get("#license_id_0 .vs__open-indicator").click(); + cy.get("#agreement_license_0 #license_id_0 .vs__search").type( + "License 10{enter}", + { force: true } + ); + cy.get("#agreement_license_0").contains("License 10"); + }); + + it("Should correctly display the label when editing", () => { + let agreement = cy.get_agreement(); + let agreements = [agreement]; + let licenses_to_relate = cy.get_licenses_to_relate(); + let vendors = cy.get_vendors_to_relate(); + + // Intercept vendors request + cy.intercept("GET", "/api/v1/acquisitions/vendors*", { + statusCode: 200, + body: vendors, + }).as("get-vendor-options"); + + // Intercept initial /agreements request once + cy.intercept( + { + method: "GET", + url: "/api/v1/erm/agreements*", + times: 1, + }, + { + body: agreements, + } + ); + // Intercept follow-up 'search' request after entering /agreements + cy.intercept("GET", "/api/v1/erm/agreements?_page*", { + statusCode: 200, + body: agreements, + headers: { + "X-Base-Total-Count": "1", + "X-Total-Count": "1", + }, + }).as("get-single-agreement-search-result"); + cy.visit("/cgi-bin/koha/erm/agreements"); + cy.wait("@get-single-agreement-search-result"); + + // Intercept request after edit click + cy.intercept("GET", "/api/v1/erm/agreements/*", agreement).as( + "get-agreement" + ); + + // Intercept related licenses request after entering agreement edit + let licenses_count = licenses_to_relate.length.toString(); + cy.intercept("GET", "/api/v1/erm/licenses*", { + statusCode: 200, + body: licenses_to_relate, + headers: { + "X-Base-Total-Count": licenses_count, + "X-Total-Count": licenses_count, + }, + }).as("get-related-licenses"); + + // Intercept related agreements request after entering agreement edit + cy.intercept("GET", "/api/v1/erm/agreements*", { + statusCode: 200, + body: cy.get_agreements_to_relate(), + }).as("get-related-agreements"); + + // Click the 'Edit' button from the list + cy.get("#agreements_list table tbody tr:first") + .contains("Edit") + .click(); + cy.wait("@get-agreement"); + cy.wait(500); // Cypress is too fast! Vue hasn't populated the form yet! + + // Licenses should be labelled correctly + cy.get("#agreement_license_0 #license_id_0 .vs__selected").contains( + "first license name" + ); + cy.get("#agreement_license_1 #license_id_1 .vs__selected").contains( + "second license name" + ); + }); +}); diff --git a/t/cypress/support/e2e.js b/t/cypress/support/e2e.js index f6bfeb4a476..c0f4ef5cb86 100644 --- a/t/cypress/support/e2e.js +++ b/t/cypress/support/e2e.js @@ -53,6 +53,107 @@ const dates = { tomorrow_us: dayjs().add(1, "day").format("MM/DD/YYYY"), } +cy.get_agreement = () => { + let licenses = cy.get_licenses_to_relate(); + return { + agreement_id: 1, + closure_reason: "", + description: "my first agreement", + is_perpetual: false, + license_info: "", + name: "agreement 1", + renewal_priority: "", + status: "active", + vendor_id: 1, + vendor: [cy.get_vendors_to_relate()[0]], + periods: [ + { + started_on: dates["today_iso"], + ended_on: dates["tomorrow_iso"], + cancellation_deadline: null, + notes: null, + }, + { + started_on: dates["today_iso"], + ended_on: null, + cancellation_deadline: dates["tomorrow_iso"], + notes: "this is a note", + }, + ], + user_roles: [], + agreement_licenses: [ + { + agreement_id: 1, + agreement_license_id: 3, + license: licenses[0], + license_id: licenses[0].license_id, + notes: "license notes", + physical_location: "cupboard", + status: "controlling", + uri: "license uri", + }, + { + agreement_id: 1, + agreement_license_id: 4, + license: licenses[1], + license_id: licenses[1].license_id, + notes: "second license notes", + physical_location: "cupboard", + status: "future", + uri: "license uri", + }, + ], + agreement_relationships: [ + { + agreement_id: 1, + notes: "related agreement notes", + related_agreement: { + agreement_id: 2, + description: "agreement description", + name: "agreement name", + }, + related_agreement_id: 2, + relationship: "supersedes", + }, + ], + agreement_packages: [], + documents: [ + { + agreement_id: 1, + file_description: "file description", + file_name: "file.json", + notes: "file notes", + physical_location: "file physical location", + uri: "file uri", + uploaded_on: "2022-10-27T11:57:02+00:00", + }, + ], + }; +} + +cy.get_licenses_to_relate = () => { + return [ + { + license_id: 1, + description: "license description", + license_id: 1, + name: "first license name", + status: "expired", + type: "alliance", + }, + { + license_id: 2, + description: "a second license", + name: "second license name", + }, + { + license_id: 3, + description: "a third license", + name: "third license name", + }, + ]; +} + cy.get_title = () => { return { access_type: "access type", -- 2.34.1