From ed404304009fe1efeacc3f6dde20ad03a1a8c1f0 Mon Sep 17 00:00:00 2001 From: Jonathan Druart Date: Wed, 12 Mar 2025 10:11:23 +0100 Subject: [PATCH] Bug 39315: Move holdings Cypress tests to a separate file Signed-off-by: David Nind --- .../integration/KohaTable/Holdings_spec.ts | 292 ++++++++++++++ .../integration/KohaTable/KohaTable_spec.ts | 367 +----------------- t/cypress/support/e2e.js | 36 ++ 3 files changed, 335 insertions(+), 360 deletions(-) create mode 100644 t/cypress/integration/KohaTable/Holdings_spec.ts diff --git a/t/cypress/integration/KohaTable/Holdings_spec.ts b/t/cypress/integration/KohaTable/Holdings_spec.ts new file mode 100644 index 0000000000..0248ba773e --- /dev/null +++ b/t/cypress/integration/KohaTable/Holdings_spec.ts @@ -0,0 +1,292 @@ +const RESTdefaultPageSize = "20"; // FIXME Mock this +const baseTotalCount = "42"; + +describe("catalogue/detail/holdings_table", () => { + const table_id = "holdings_table"; + beforeEach(() => { + cy.login(); + cy.title().should("eq", "Koha staff interface"); + cy.window().then(win => { + win.localStorage.clear(); + }); + + // FIXME All the following code should not be reused as it + // It must be moved to a Cypress command or task "buildSampleBiblio" or even "insertSampleBiblio" + let generated_objects = {}; + const objects = [{ object: "library" }, { object: "item_type" }]; + cy.wrap(Promise.resolve()) + .then(() => { + return objects.reduce((chain, { object }) => { + return chain.then(() => { + return cy + .task("buildSampleObject", { object }) + .then(attributes => { + generated_objects[object] = attributes; + }); + }); + }, Promise.resolve()); + }) + .then(() => { + const library = generated_objects["library"]; + const item_type = generated_objects["item_type"]; + const queries = [ + { + query: "INSERT INTO branches(branchcode, branchname) VALUES (?, ?)", + values: [library.library_id, library.name], + }, + { + query: "INSERT INTO itemtypes(itemtype, description) VALUES (?, ?)", + values: [item_type.item_type_id, item_type.description], + }, + ]; + cy.wrap(Promise.resolve()) + .then(() => { + return queries.reduce((chain, { query, values }) => { + return chain.then(() => cy.query(query, values)); + }, Promise.resolve()); + }) + .then(() => { + let biblio = { + leader: " nam a22 7a 4500", + fields: [ + { "005": "20250120101920.0" }, + { + "245": { + ind1: "", + ind2: "", + subfields: [{ a: "Some boring read" }], + }, + }, + { + "100": { + ind1: "", + ind2: "", + subfields: [ + { c: "Some boring author" }, + ], + }, + }, + { + "942": { + ind1: "", + ind2: "", + subfields: [ + { c: item_type.item_type_id }, + ], + }, + }, + ], + }; + cy.request({ + method: "POST", + url: "/api/v1/biblios", + headers: { + "Content-Type": "application/marc-in-json", + "x-confirm-not-duplicate": 1, + }, + body: biblio, + }).then(response => { + const biblio_id = response.body.id; + cy.wrap(biblio_id).as("biblio_id"); + cy.request({ + method: "POST", + url: `/api/v1/biblios/${biblio_id}/items`, + headers: { + "Content-Type": "application/json", + }, + body: { + home_library_id: library.library_id, + holding_library_id: library.library_id, + }, + }); + }); + }); + }); + cy.query( + "SELECT value FROM systempreferences WHERE variable='AlwaysShowHoldingsTableFilters'" + ).then(value => { + cy.wrap(value).as("syspref_AlwaysShowHoldingsTableFilters"); + }); + }); + + afterEach( + () => + function () { + cleanup(); + cy.set_syspref( + "AlwaysShowHoldingsTableFilters", + this.syspref_AlwaysShowHoldingsTableFilters + ); + } + ); + + it("Correctly init the table", function () { + // Do not use `() => {` or this.biblio_id won't be retrieved + const biblio_id = this.biblio_id; + cy.task("buildSampleObjects", { + object: "item", + count: RESTdefaultPageSize, + values: { + biblio_id, + checkout: null, + transfer: null, + lost_status: 0, + withdrawn: 0, + damaged_status: 0, + not_for_loan_status: 0, + course_item: null, + cover_image_ids: [], + }, + }).then(items => { + cy.intercept("get", `/api/v1/biblios/${biblio_id}/items*`, { + statuscode: 200, + body: items, + headers: { + "X-Base-Total-Count": baseTotalCount, + "X-Total-Count": baseTotalCount, + }, + }); + + cy.visit( + "/cgi-bin/koha/catalogue/detail.pl?biblionumber=" + biblio_id + ); + + cy.window().then(win => { + win.libraries_map = items.reduce((map, i) => { + map[i.library_id] = i.library_id; + return map; + }, {}); + }); + + cy.get(`#${table_id}_wrapper tbody tr`).should( + "have.length", + RESTdefaultPageSize + ); + + cy.get(`#${table_id}_wrapper .dt-info`).contains( + `Showing 1 to ${RESTdefaultPageSize} of ${baseTotalCount} entries` + ); + }); + }); + + it("Show filters", function () { + // Do not use `() => {` or this.biblio_id won't be retrieved + const biblio_id = this.biblio_id; + cy.task("buildSampleObjects", { + object: "item", + count: RESTdefaultPageSize, + values: { + biblio_id, + checkout: null, + transfer: null, + lost_status: 0, + withdrawn: 0, + damaged_status: 0, + not_for_loan_status: 0, + course_item: null, + cover_image_ids: [], + }, + }).then(items => { + cy.intercept("get", `/api/v1/biblios/${biblio_id}/items*`, { + statuscode: 200, + body: items, + headers: { + "X-Base-Total-Count": baseTotalCount, + "X-Total-Count": baseTotalCount, + }, + }); + + cy.set_syspref("AlwaysShowHoldingsTableFilters", 0).then(() => { + cy.visit( + "/cgi-bin/koha/catalogue/detail.pl?biblionumber=" + + biblio_id + ); + + // Hide the 'URL' column + cy.mock_table_settings( + { + columns: { uri: { is_hidden: 1 } }, + }, + "items_table_settings.holdings" + ); + + cy.window().then(win => { + win.libraries_map = items.reduce((map, i) => { + map[i.library_id] = i.library_id; + return map; + }, {}); + }); + + cy.get("@columns").then(columns => { + cy.get(`#${table_id}_wrapper tbody tr`).should( + "have.length", + RESTdefaultPageSize + ); + + // Filters are not displayed + cy.get(`#${table_id} thead tr`).should("have.length", 1); + + cy.get(`#${table_id} th`).contains("Status"); + cy.get(`#${table_id} th`) + .contains("URL") + .should("not.exist"); + cy.get(`#${table_id} th`) + .contains("Course reserves") + .should("not.exist"); + + cy.get(".show_filters").click(); + cy.get(`#${table_id}_wrapper .dt-info`).contains( + `Showing 1 to ${RESTdefaultPageSize} of ${baseTotalCount} entries` + ); + // Filters are displayed + cy.get(`#${table_id} thead tr`).should("have.length", 2); + + cy.get(`#${table_id} th`).contains("Status"); + cy.get(`#${table_id} th`) + .contains("URL") + .should("not.exist"); + cy.get(`#${table_id} th`) + .contains("Course reserves") + .should("not.exist"); + }); + }); + + cy.set_syspref("AlwaysShowHoldingsTableFilters", 1).then(() => { + cy.visit( + "/cgi-bin/koha/catalogue/detail.pl?biblionumber=" + + biblio_id + ); + + // Hide the 'URL' column + cy.mock_table_settings( + { + columns: { uri: { is_hidden: 1 } }, + }, + "items_table_settings.holdings" + ); + + cy.window().then(win => { + win.libraries_map = items.reduce((map, i) => { + map[i.library_id] = i.library_id; + return map; + }, {}); + }); + + cy.get("@columns").then(columns => { + cy.get(`#${table_id}_wrapper tbody tr`).should( + "have.length", + RESTdefaultPageSize + ); + + // Filters are displayed + cy.get(`#${table_id} thead tr`).should("have.length", 2); + + cy.get(".hide_filters").click(); + + // Filters are not displayed + cy.get(`#${table_id} thead tr`).should("have.length", 1); + }); + }); + }); + }); +}); diff --git a/t/cypress/integration/KohaTable/KohaTable_spec.ts b/t/cypress/integration/KohaTable/KohaTable_spec.ts index efced8e4b6..6e9194967e 100644 --- a/t/cypress/integration/KohaTable/KohaTable_spec.ts +++ b/t/cypress/integration/KohaTable/KohaTable_spec.ts @@ -22,42 +22,6 @@ function build_libraries() { }); } -function mock_table_settings(settings, table_settings_var) { - cy.window().then(win => { - let table_settings = - typeof table_settings_var === "undefined" - ? win.table_settings - : table_settings_var - .split(".") - .reduce((acc, key) => acc[key], win); - - table_settings.columns = table_settings.columns.map(c => ({ - ...c, - is_hidden: 0, - cannot_be_toggled: 0, - })); - if (settings && settings.hasOwnProperty("default_save_state")) { - table_settings.default_save_state = settings.default_save_state; - } - if (settings && settings.hasOwnProperty("default_save_state_search")) { - table_settings.default_save_state_search = - settings.default_save_state_search; - } - - if (settings && settings.columns) { - Object.entries(settings.columns).forEach(([name, values]) => { - let column = table_settings.columns.find( - cc => cc.columnname == name - ); - Object.entries(values).forEach(([prop, value]) => { - column[prop] = value; - }); - }); - } - cy.wrap(table_settings.columns).as("columns"); - }); -} - describe("kohaTable (using REST API)", () => { beforeEach(() => { cy.login(); @@ -114,7 +78,7 @@ describe("kohaTable (using REST API)", () => { build_libraries().then(() => { cy.visit("/cgi-bin/koha/admin/branches.pl"); - mock_table_settings(); + cy.mock_table_settings(); cy.get("@columns").then(columns => { cy.get(`#${table_id} th`).should( "have.length", @@ -128,7 +92,7 @@ describe("kohaTable (using REST API)", () => { build_libraries().then(() => { cy.visit("/cgi-bin/koha/admin/branches.pl"); - mock_table_settings({ + cy.mock_table_settings({ columns: { library_code: { is_hidden: 1 } }, }); @@ -148,7 +112,7 @@ describe("kohaTable (using REST API)", () => { build_libraries().then(() => { cy.visit("/cgi-bin/koha/admin/branches.pl"); - mock_table_settings({ + cy.mock_table_settings({ default_save_state: 0, columns: { library_code: { is_hidden: 1 } }, }); @@ -176,7 +140,7 @@ describe("kohaTable (using REST API)", () => { cy.visit("/cgi-bin/koha/admin/branches.pl"); - mock_table_settings({ + cy.mock_table_settings({ default_save_state: 0, columns: { library_code: { is_hidden: 1 } }, }); @@ -198,7 +162,7 @@ describe("kohaTable (using REST API)", () => { build_libraries().then(() => { cy.visit("/cgi-bin/koha/admin/branches.pl"); - mock_table_settings({ + cy.mock_table_settings({ default_save_state: 1, columns: { library_code: { is_hidden: 1 } }, }); @@ -226,7 +190,7 @@ describe("kohaTable (using REST API)", () => { cy.visit("/cgi-bin/koha/admin/branches.pl"); - mock_table_settings({ + cy.mock_table_settings({ default_save_state: 1, columns: { library_code: { is_hidden: 1 } }, }); @@ -246,7 +210,7 @@ describe("kohaTable (using REST API)", () => { build_libraries().then(() => { cy.visit("/cgi-bin/koha/admin/branches.pl"); - mock_table_settings({ + cy.mock_table_settings({ default_save_state: 1, columns: { library_code: { is_hidden: 1 } }, }); @@ -476,320 +440,3 @@ describe("ERM ", () => { }); }); }); - -describe("Hit all tables", () => { - beforeEach(() => { - cy.login(); - cy.title().should("eq", "Koha staff interface"); - cy.window().then(win => { - win.localStorage.clear(); - }); - }); - - describe("catalogue/detail/holdings_table", () => { - const table_id = "holdings_table"; - beforeEach(() => { - // FIXME All the following code should not be reused as it - // It must be moved to a Cypress command or task "buildSampleBiblio" or even "insertSampleBiblio" - let generated_objects = {}; - const objects = [{ object: "library" }, { object: "item_type" }]; - cy.wrap(Promise.resolve()) - .then(() => { - return objects.reduce((chain, { object }) => { - return chain.then(() => { - return cy - .task("buildSampleObject", { object }) - .then(attributes => { - generated_objects[object] = attributes; - }); - }); - }, Promise.resolve()); - }) - .then(() => { - const library = generated_objects["library"]; - const item_type = generated_objects["item_type"]; - const queries = [ - { - query: "INSERT INTO branches(branchcode, branchname) VALUES (?, ?)", - values: [library.library_id, library.name], - }, - { - query: "INSERT INTO itemtypes(itemtype, description) VALUES (?, ?)", - values: [ - item_type.item_type_id, - item_type.description, - ], - }, - ]; - cy.wrap(Promise.resolve()) - .then(() => { - return queries.reduce( - (chain, { query, values }) => { - return chain.then(() => - cy.query(query, values) - ); - }, - Promise.resolve() - ); - }) - .then(() => { - let biblio = { - leader: " nam a22 7a 4500", - fields: [ - { "005": "20250120101920.0" }, - { - "245": { - ind1: "", - ind2: "", - subfields: [ - { a: "Some boring read" }, - ], - }, - }, - { - "100": { - ind1: "", - ind2: "", - subfields: [ - { c: "Some boring author" }, - ], - }, - }, - { - "942": { - ind1: "", - ind2: "", - subfields: [ - { c: item_type.item_type_id }, - ], - }, - }, - ], - }; - cy.request({ - method: "POST", - url: "/api/v1/biblios", - headers: { - "Content-Type": "application/marc-in-json", - "x-confirm-not-duplicate": 1, - }, - body: biblio, - }).then(response => { - const biblio_id = response.body.id; - cy.wrap(biblio_id).as("biblio_id"); - cy.request({ - method: "POST", - url: `/api/v1/biblios/${biblio_id}/items`, - headers: { - "Content-Type": "application/json", - }, - body: { - home_library_id: library.library_id, - holding_library_id: library.library_id, - }, - }); - }); - }); - }); - cy.query( - "SELECT value FROM systempreferences WHERE variable='AlwaysShowHoldingsTableFilters'" - ).then(value => { - cy.wrap(value).as("syspref_AlwaysShowHoldingsTableFilters"); - }); - }); - - afterEach( - () => - function () { - cleanup(); - cy.set_syspref( - "AlwaysShowHoldingsTableFilters", - this.syspref_AlwaysShowHoldingsTableFilters - ); - } - ); - - it("Correctly init the table", function () { - // Do not use `() => {` or this.biblio_id won't be retrieved - const biblio_id = this.biblio_id; - cy.task("buildSampleObjects", { - object: "item", - count: RESTdefaultPageSize, - values: { - biblio_id, - checkout: null, - transfer: null, - lost_status: 0, - withdrawn: 0, - damaged_status: 0, - not_for_loan_status: 0, - course_item: null, - cover_image_ids: [], - }, - }).then(items => { - cy.intercept("get", `/api/v1/biblios/${biblio_id}/items*`, { - statuscode: 200, - body: items, - headers: { - "X-Base-Total-Count": baseTotalCount, - "X-Total-Count": baseTotalCount, - }, - }); - - cy.visit( - "/cgi-bin/koha/catalogue/detail.pl?biblionumber=" + - biblio_id - ); - - cy.window().then(win => { - win.libraries_map = items.reduce((map, i) => { - map[i.library_id] = i.library_id; - return map; - }, {}); - }); - - cy.get(`#${table_id}_wrapper tbody tr`).should( - "have.length", - RESTdefaultPageSize - ); - - cy.get(`#${table_id}_wrapper .dt-info`).contains( - `Showing 1 to ${RESTdefaultPageSize} of ${baseTotalCount} entries` - ); - }); - }); - - it("Show filters", function () { - // Do not use `() => {` or this.biblio_id won't be retrieved - const biblio_id = this.biblio_id; - cy.task("buildSampleObjects", { - object: "item", - count: RESTdefaultPageSize, - values: { - biblio_id, - checkout: null, - transfer: null, - lost_status: 0, - withdrawn: 0, - damaged_status: 0, - not_for_loan_status: 0, - course_item: null, - cover_image_ids: [], - }, - }).then(items => { - cy.intercept("get", `/api/v1/biblios/${biblio_id}/items*`, { - statuscode: 200, - body: items, - headers: { - "X-Base-Total-Count": baseTotalCount, - "X-Total-Count": baseTotalCount, - }, - }); - - cy.set_syspref("AlwaysShowHoldingsTableFilters", 0).then(() => { - cy.visit( - "/cgi-bin/koha/catalogue/detail.pl?biblionumber=" + - biblio_id - ); - - // Hide the 'URL' column - mock_table_settings( - { - columns: { uri: { is_hidden: 1 } }, - }, - "items_table_settings.holdings" - ); - - cy.window().then(win => { - win.libraries_map = items.reduce((map, i) => { - map[i.library_id] = i.library_id; - return map; - }, {}); - }); - - cy.get("@columns").then(columns => { - cy.get(`#${table_id}_wrapper tbody tr`).should( - "have.length", - RESTdefaultPageSize - ); - - // Filters are not displayed - cy.get(`#${table_id} thead tr`).should( - "have.length", - 1 - ); - - cy.get(`#${table_id} th`).contains("Status"); - cy.get(`#${table_id} th`) - .contains("URL") - .should("not.exist"); - cy.get(`#${table_id} th`) - .contains("Course reserves") - .should("not.exist"); - - cy.get(".show_filters").click(); - cy.get(`#${table_id}_wrapper .dt-info`).contains( - `Showing 1 to ${RESTdefaultPageSize} of ${baseTotalCount} entries` - ); - // Filters are displayed - cy.get(`#${table_id} thead tr`).should( - "have.length", - 2 - ); - - cy.get(`#${table_id} th`).contains("Status"); - cy.get(`#${table_id} th`) - .contains("URL") - .should("not.exist"); - cy.get(`#${table_id} th`) - .contains("Course reserves") - .should("not.exist"); - }); - }); - - cy.set_syspref("AlwaysShowHoldingsTableFilters", 1).then(() => { - cy.visit( - "/cgi-bin/koha/catalogue/detail.pl?biblionumber=" + - biblio_id - ); - - // Hide the 'URL' column - mock_table_settings( - { - columns: { uri: { is_hidden: 1 } }, - }, - "items_table_settings.holdings" - ); - - cy.window().then(win => { - win.libraries_map = items.reduce((map, i) => { - map[i.library_id] = i.library_id; - return map; - }, {}); - }); - - cy.get("@columns").then(columns => { - cy.get(`#${table_id}_wrapper tbody tr`).should( - "have.length", - RESTdefaultPageSize - ); - - // Filters are displayed - cy.get(`#${table_id} thead tr`).should( - "have.length", - 2 - ); - - cy.get(".hide_filters").click(); - - // Filters are not displayed - cy.get(`#${table_id} thead tr`).should( - "have.length", - 1 - ); - }); - }); - }); - }); - }); -}); diff --git a/t/cypress/support/e2e.js b/t/cypress/support/e2e.js index 37dc1c750f..3f3bdbd85d 100644 --- a/t/cypress/support/e2e.js +++ b/t/cypress/support/e2e.js @@ -1822,3 +1822,39 @@ Cypress.Commands.add("set_syspref", (variable, value) => { return client.sysprefs.update(variable, value); }); }); + +Cypress.Commands.add("mock_table_settings", (settings, table_settings_var) => { + cy.window().then(win => { + let table_settings = + typeof table_settings_var === "undefined" + ? win.table_settings + : table_settings_var + .split(".") + .reduce((acc, key) => acc[key], win); + + table_settings.columns = table_settings.columns.map(c => ({ + ...c, + is_hidden: 0, + cannot_be_toggled: 0, + })); + if (settings && settings.hasOwnProperty("default_save_state")) { + table_settings.default_save_state = settings.default_save_state; + } + if (settings && settings.hasOwnProperty("default_save_state_search")) { + table_settings.default_save_state_search = + settings.default_save_state_search; + } + + if (settings && settings.columns) { + Object.entries(settings.columns).forEach(([name, values]) => { + let column = table_settings.columns.find( + cc => cc.columnname == name + ); + Object.entries(values).forEach(([prop, value]) => { + column[prop] = value; + }); + }); + } + cy.wrap(table_settings.columns).as("columns"); + }); +}); -- 2.39.5