From 0745cb391ec0fd141ee3abf549cfae71dfb339cb Mon Sep 17 00:00:00 2001 From: Benjamin CHARMES Date: Fri, 4 Oct 2024 17:32:53 +0100 Subject: [PATCH 1/2] Add test for every Datatable --- .../component/CollectionTableTest.cy.jsx | 110 ++++++++++++ .../component/EquipmentTableTest.cy.jsx | 133 +++++++++++++++ .../cypress/component/SampleTableTest.cy.jsx | 157 ++++++++++++++++++ .../StartingMaterialTableTest.cy.jsx | 125 ++++++++++++++ 4 files changed, 525 insertions(+) create mode 100644 webapp/cypress/component/CollectionTableTest.cy.jsx create mode 100644 webapp/cypress/component/EquipmentTableTest.cy.jsx create mode 100644 webapp/cypress/component/SampleTableTest.cy.jsx create mode 100644 webapp/cypress/component/StartingMaterialTableTest.cy.jsx diff --git a/webapp/cypress/component/CollectionTableTest.cy.jsx b/webapp/cypress/component/CollectionTableTest.cy.jsx new file mode 100644 index 000000000..30b96e77b --- /dev/null +++ b/webapp/cypress/component/CollectionTableTest.cy.jsx @@ -0,0 +1,110 @@ +import CollectionTable from "@/components/CollectionTable.vue"; +import PrimeVue from "primevue/config"; +import { createStore } from "vuex"; + +describe("CollectionTable Component Tests", () => { + let store; + + beforeEach(() => { + store = createStore({ + state() { + return { + collection_list: [ + { + collection_id: "collection1", + type: "collections", + title: "Collection One", + creators: [{ display_name: "Creator A" }], + }, + { + collection_id: "collection2", + type: "collections", + title: "Collection Two", + creators: [{ display_name: "Creator B" }, { display_name: "Creator C" }], + }, + ], + }; + }, + }); + + cy.mount(CollectionTable, { + global: { + plugins: [store, PrimeVue], + }, + }); + }); + + it("renders the correct buttons", () => { + cy.get('[data-testid="add-item-button"]').should("not.exist"); + cy.get('[data-testid="batch-item-button"]').should("not.exist"); + cy.get('[data-testid="scan-qr-button"]').should("not.exist"); + cy.get('[data-testid="add-collection-button"]').should("exist"); + cy.get('[data-testid="add-starting-material-button"]').should("not.exist"); + cy.get('[data-testid="add-equipment-button"]').should("not.exist"); + cy.get('[data-testid="add-to-collection-button"]').should("not.exist"); + cy.get('[data-testid="delete-selected-button"]').should("not.exist"); + cy.get('[data-testid="search-input"]').should("exist"); + }); + + it("renders the correct columns in the table", () => { + const headers = [ + "", //checkbox + "ID", + "Title", + "Creators", + ]; + + cy.get(".p-datatable-column-header-content").should("have.length", headers.length); + cy.get(".p-datatable-column-header-content").each((header, index) => { + cy.wrap(header).should("contain.text", headers[index]); + }); + }); + + it("displays data from the Vuex store", () => { + cy.get(".p-datatable-tbody") + .find("tr") + .eq(0) + .within(() => { + cy.get("td").eq(0).should("contain.text", ""); + cy.get("td").eq(1).should("contain.text", "collection1"); + cy.get("td").eq(2).should("contain.text", "Collection One"); + cy.get("td").eq(3).find(".avatar").should("have.length", 1); + }); + + cy.get(".p-datatable-tbody") + .find("tr") + .eq(1) + .within(() => { + cy.get("td").eq(0).should("contain.text", ""); + cy.get("td").eq(1).should("contain.text", "collection2"); + cy.get("td").eq(2).should("contain.text", "Collection Two"); + cy.get("td").eq(3).find(".avatar").should("have.length", 2); + }); + }); + + it("renders the component FormattedCollectionName", () => { + cy.get(".p-datatable-tbody tr") + .eq(0) + .within(() => { + cy.get("td").eq(1).find(".formatted-collection-name").should("exist"); + }); + cy.get(".p-datatable-tbody tr") + .eq(1) + .within(() => { + cy.get("td").eq(1).find(".formatted-collection-name").should("exist"); + }); + }); + + it("renders the component Creators", () => { + cy.get(".p-datatable-tbody tr") + .eq(0) + .within(() => { + cy.get("td").eq(3).find(".avatar").should("exist"); + }); + cy.get(".p-datatable-tbody tr") + .eq(1) + .within(() => { + cy.get("td").eq(3).find(".avatar").should("exist"); + }); + }); +}); diff --git a/webapp/cypress/component/EquipmentTableTest.cy.jsx b/webapp/cypress/component/EquipmentTableTest.cy.jsx new file mode 100644 index 000000000..905e6a1a2 --- /dev/null +++ b/webapp/cypress/component/EquipmentTableTest.cy.jsx @@ -0,0 +1,133 @@ +import EquipmentTable from "@/components/EquipmentTable.vue"; +import PrimeVue from "primevue/config"; +import { createStore } from "vuex"; + +const IsoDatetimeToDate = (value) => { + if (!value) return ""; + const date = new Date(value); + return date.toLocaleDateString(); +}; + +describe("EquipmentTable Component Tests", () => { + let store; + + beforeEach(() => { + store = createStore({ + state() { + return { + equipment_list: [ + { + item_id: "equipment1", + type: "equipment", + name: "Equipment One", + date: "2023-09-01T12:34:56Z", + location: "Warehouse A", + creators: [{ display_name: "Maintainer A" }], + }, + { + item_id: "equipment2", + type: "equipment", + name: "Equipment Two", + date: "2023-08-15T08:45:30Z", + location: "Warehouse B", + creators: [{ display_name: "Maintainer B" }, { display_name: "Maintainer C" }], + }, + ], + }; + }, + }); + + cy.mount(EquipmentTable, { + global: { + plugins: [store, PrimeVue], + config: { + globalProperties: { + $filters: { + IsoDatetimeToDate, + }, + }, + }, + }, + }); + }); + + it("renders the correct buttons", () => { + cy.get('[data-testid="add-item-button"]').should("not.exist"); + cy.get('[data-testid="batch-item-button"]').should("not.exist"); + cy.get('[data-testid="scan-qr-button"]').should("not.exist"); + cy.get('[data-testid="add-collection-button"]').should("not.exist"); + cy.get('[data-testid="add-starting-material-button"]').should("not.exist"); + cy.get('[data-testid="add-equipment-button"]').should("exist"); + cy.get('[data-testid="add-to-collection-button"]').should("not.exist"); + cy.get('[data-testid="delete-selected-button"]').should("not.exist"); + cy.get('[data-testid="search-input"]').should("exist"); + }); + + it("renders the correct columns in the table", () => { + const headers = [ + "", // checkbox + "ID", + "Name", + "Date", + "Location", + "Maintainers", + ]; + + cy.get(".p-datatable-column-header-content").should("have.length", headers.length); + cy.get(".p-datatable-column-header-content").each((header, index) => { + cy.wrap(header).should("contain.text", headers[index]); + }); + }); + + it("displays data from the Vuex store", () => { + cy.get(".p-datatable-tbody") + .find("tr") + .eq(0) + .within(() => { + cy.get("td").eq(0).should("contain.text", ""); + cy.get("td").eq(1).should("contain.text", "equipment1"); + cy.get("td").eq(2).should("contain.text", "Equipment One"); + cy.get("td").eq(3).should("contain.text", "01/09/2023"); + cy.get("td").eq(4).should("contain.text", "Warehouse A"); + cy.get("td").eq(5).find(".avatar").should("have.length", 1); + }); + + cy.get(".p-datatable-tbody") + .find("tr") + .eq(1) + .within(() => { + cy.get("td").eq(0).should("contain.text", ""); + cy.get("td").eq(1).should("contain.text", "equipment2"); + cy.get("td").eq(2).should("contain.text", "Equipment Two"); + cy.get("td").eq(3).should("contain.text", "15/08/2023"); + cy.get("td").eq(4).should("contain.text", "Warehouse B"); + cy.get("td").eq(5).find(".avatar").should("have.length", 2); + }); + }); + + it("renders the component FormattedItemName", () => { + cy.get(".p-datatable-tbody tr") + .eq(0) + .within(() => { + cy.get("td").eq(1).find(".formatted-item-name").should("exist"); + }); + cy.get(".p-datatable-tbody tr") + .eq(1) + .within(() => { + cy.get("td").eq(1).find(".formatted-item-name").should("exist"); + }); + }); + + it("renders the component Creators", () => { + cy.get(".p-datatable-tbody tr") + .eq(0) + .within(() => { + cy.get("td").eq(5).find(".avatar").should("exist"); + }); + cy.get(".p-datatable-tbody tr") + .eq(1) + .within(() => { + cy.get("td").eq(5).find(".avatar").should("exist"); + }); + }); +}); diff --git a/webapp/cypress/component/SampleTableTest.cy.jsx b/webapp/cypress/component/SampleTableTest.cy.jsx new file mode 100644 index 000000000..175a47578 --- /dev/null +++ b/webapp/cypress/component/SampleTableTest.cy.jsx @@ -0,0 +1,157 @@ +import SampleTable from "@/components/SampleTable.vue"; +import PrimeVue from "primevue/config"; +import { createStore } from "vuex"; + +const IsoDatetimeToDate = (value) => { + if (!value) return ""; + const date = new Date(value); + return date.toLocaleDateString(); +}; + +describe("SampleTable Component Tests", () => { + let store; + + beforeEach(() => { + store = createStore({ + state() { + return { + sample_list: [ + { + item_id: "sample1", + type: "samples", + name: "Sample 1", + chemform: "H2O", + date: "2023-09-01T12:34:56Z", + collections: ["collection1"], + creators: [{ display_name: "Creator 1" }], + nblocks: 1, + }, + { + item_id: "cell2", + type: "cells", + name: "Cell 2", + chemform: "CH4", + date: "2023-08-15T08:45:30Z", + collections: ["collection1", "collection2"], + creators: [{ display_name: "Creator 1" }, { display_name: "Creator 2" }], + nblocks: 2, + }, + ], + }; + }, + }); + + cy.mount(SampleTable, { + global: { + plugins: [store, PrimeVue], + config: { + globalProperties: { + $filters: { + IsoDatetimeToDate, + }, + }, + }, + }, + }); + }); + + it("renders the correct buttons", () => { + cy.get('[data-testid="add-item-button"]').should("exist"); + cy.get('[data-testid="batch-item-button"]').should("exist"); + cy.get('[data-testid="scan-qr-button"]').should("exist"); + cy.get('[data-testid="add-collection-button"]').should("not.exist"); + cy.get('[data-testid="add-starting-material-button"]').should("not.exist"); + cy.get('[data-testid="add-equipment-button"]').should("not.exist"); + cy.get('[data-testid="add-to-collection-button"]').should("not.exist"); + cy.get('[data-testid="delete-selected-button"]').should("not.exist"); + cy.get('[data-testid="search-input"]').should("exist"); + }); + + it("renders the table with correct headers", () => { + const headers = [ + "", //checkbox + "ID", + "Type", + "Sample name", + "Formula", + "Date", + "Collections", + "Creators", + "# of blocks", + ]; + + cy.get(".p-datatable-column-header-content").should("have.length", headers.length); + cy.get(".p-datatable-column-header-content").each((header, index) => { + cy.wrap(header).should("contain.text", headers[index]); + }); + }); + + it("displays data from the Vuex store", () => { + cy.get(".p-datatable-tbody tr") + .eq(0) + .within(() => { + cy.get("td").eq(0).should("contain.text", ""); + cy.get("td").eq(1).should("contain.text", "sample1"); + cy.get("td").eq(2).should("contain.text", "samples"); + cy.get("td").eq(3).should("contain.text", "Sample 1"); + cy.get("td").eq(4).should("contain.text", "H2O"); + cy.get("td").eq(5).should("contain.text", "01/09/2023"); + cy.get("td").eq(6).find(".badge").should("have.length", 1); + cy.get("td").eq(7).find(".avatar").should("have.length", 1); + cy.get("td").eq(8).should("contain.text", "1"); + }); + + cy.get(".p-datatable-tbody tr") + .eq(1) + .within(() => { + cy.get("td").eq(0).should("contain.text", ""); + cy.get("td").eq(1).should("contain.text", "cell2"); + cy.get("td").eq(2).should("contain.text", "cells"); + cy.get("td").eq(3).should("contain.text", "Cell 2"); + cy.get("td").eq(4).should("contain.text", "CH4"); + cy.get("td").eq(5).should("contain.text", "15/08/2023"); + cy.get("td").eq(6).find(".badge").should("have.length", 2); + cy.get("td").eq(7).find(".avatar").should("have.length", 2); + cy.get("td").eq(8).should("contain.text", "2"); + }); + }); + + it("renders the component FormattedItemName", () => { + cy.get(".p-datatable-tbody tr") + .eq(0) + .within(() => { + cy.get("td").eq(1).find(".formatted-item-name").should("exist"); + }); + cy.get(".p-datatable-tbody tr") + .eq(1) + .within(() => { + cy.get("td").eq(1).find(".formatted-item-name").should("exist"); + }); + }); + + it("renders the component FormattedCollectionName", () => { + cy.get(".p-datatable-tbody tr") + .eq(0) + .within(() => { + cy.get("td").eq(6).find(".formatted-collection-name").should("exist"); + }); + cy.get(".p-datatable-tbody tr") + .eq(1) + .within(() => { + cy.get("td").eq(6).find(".formatted-collection-name").should("exist"); + }); + }); + + it("renders the component Creators", () => { + cy.get(".p-datatable-tbody tr") + .eq(0) + .within(() => { + cy.get("td").eq(7).find(".avatar").should("exist"); + }); + cy.get(".p-datatable-tbody tr") + .eq(1) + .within(() => { + cy.get("td").eq(7).find(".avatar").should("exist"); + }); + }); +}); diff --git a/webapp/cypress/component/StartingMaterialTableTest.cy.jsx b/webapp/cypress/component/StartingMaterialTableTest.cy.jsx new file mode 100644 index 000000000..424587abf --- /dev/null +++ b/webapp/cypress/component/StartingMaterialTableTest.cy.jsx @@ -0,0 +1,125 @@ +import StartingMaterialTable from "@/components/StartingMaterialTable.vue"; +import PrimeVue from "primevue/config"; +import { createStore } from "vuex"; + +const IsoDatetimeToDate = (value) => { + if (!value) return ""; + const date = new Date(value); + return date.toLocaleDateString(); +}; + +describe("StartingMaterialTable Component Tests", () => { + let store; + + beforeEach(() => { + store = createStore({ + state() { + return { + starting_material_list: [ + { + item_id: "material1", + type: "starting_materials", + name: "Material One", + chemform: "H2O", + date: "2023-09-01", + chemical_purity: "99%", + nblocks: 1, + }, + { + item_id: "material2", + type: "starting_materials", + name: "Material Two", + chemform: "CH4", + date: "2023-08-15", + chemical_purity: "95%", + nblocks: 2, + }, + ], + }; + }, + }); + + cy.mount(StartingMaterialTable, { + global: { + plugins: [store, PrimeVue], + config: { + globalProperties: { + $filters: { + IsoDatetimeToDate, + }, + }, + }, + }, + }); + }); + + it("renders the correct buttons", () => { + cy.get('[data-testid="add-item-button"]').should("not.exist"); + cy.get('[data-testid="batch-item-button"]').should("not.exist"); + cy.get('[data-testid="scan-qr-button"]').should("not.exist"); + cy.get('[data-testid="add-collection-button"]').should("not.exist"); + cy.get('[data-testid="add-starting-material-button"]').should("exist"); + cy.get('[data-testid="add-equipment-button"]').should("not.exist"); + cy.get('[data-testid="add-to-collection-button"]').should("not.exist"); + cy.get('[data-testid="delete-selected-button"]').should("not.exist"); + cy.get('[data-testid="search-input"]').should("exist"); + }); + + it("renders the correct columns in the table", () => { + const headers = [ + "", // checkbox + "ID", + "Name", + "Formula", + "Date", + "Purity", + "# of blocks", + ]; + + cy.get(".p-datatable-column-header-content").should("have.length", headers.length); + cy.get(".p-datatable-column-header-content").each((header, index) => { + cy.wrap(header).should("contain.text", headers[index]); + }); + }); + + it("displays data from the Vuex store", () => { + cy.get(".p-datatable-tbody") + .find("tr") + .eq(0) + .within(() => { + cy.get("td").eq(0).should("contain.text", ""); + cy.get("td").eq(1).should("contain.text", "material1"); + cy.get("td").eq(2).should("contain.text", "Material One"); + cy.get("td").eq(3).should("contain.text", "H2O"); + cy.get("td").eq(4).should("contain.text", "01/09/2023"); + cy.get("td").eq(5).should("contain.text", "99%"); + cy.get("td").eq(6).should("contain.text", "1"); + }); + + cy.get(".p-datatable-tbody") + .find("tr") + .eq(1) + .within(() => { + cy.get("td").eq(0).should("contain.text", ""); + cy.get("td").eq(1).should("contain.text", "material2"); + cy.get("td").eq(2).should("contain.text", "Material Two"); + cy.get("td").eq(3).should("contain.text", "CH4"); + cy.get("td").eq(4).should("contain.text", "15/08/2023"); + cy.get("td").eq(5).should("contain.text", "95%"); + cy.get("td").eq(6).should("contain.text", "2"); + }); + }); + + it("renders the component FormattedItemName", () => { + cy.get(".p-datatable-tbody tr") + .eq(0) + .within(() => { + cy.get("td").eq(1).find(".formatted-item-name").should("exist"); + }); + cy.get(".p-datatable-tbody tr") + .eq(1) + .within(() => { + cy.get("td").eq(1).find(".formatted-item-name").should("exist"); + }); + }); +}); From 22da19f5bb4e9e11227099aa5c977cd7ac4a6b27 Mon Sep 17 00:00:00 2001 From: Benjamin CHARMES Date: Fri, 4 Oct 2024 17:38:16 +0100 Subject: [PATCH 2/2] Add e2e test for startingMaterial --- webapp/cypress/e2e/startingMaterial.cy.js | 157 ++++++++++++++++++++++ 1 file changed, 157 insertions(+) create mode 100644 webapp/cypress/e2e/startingMaterial.cy.js diff --git a/webapp/cypress/e2e/startingMaterial.cy.js b/webapp/cypress/e2e/startingMaterial.cy.js new file mode 100644 index 000000000..5765ea717 --- /dev/null +++ b/webapp/cypress/e2e/startingMaterial.cy.js @@ -0,0 +1,157 @@ +const API_URL = Cypress.config("apiUrl"); +console.log(API_URL); + +let item_ids = ["test_sm1", "test_sm2", "test_sm3", "123startingMaterial", "test_sm3_copy"]; + +before(() => { + cy.visit("/starting-materials"); + cy.removeAllTestSamples(item_ids); + cy.visit("/starting-materials").then(() => { + cy.get("[data-testid='starting-material-table'] > tbody > tr").should("have.length", 0); + }); +}); + +after(() => { + cy.visit("/starting-materials"); + cy.removeAllTestSamples(item_ids); + cy.visit("/starting-materials").then(() => { + cy.get("[data-testid='starting-material-table'] > tbody > tr").should("have.length", 0); + }); +}); + +describe("Starting material table page", () => { + before(() => { + Cypress.env("VUE_APP_EDITABLE_INVENTORY", "true"); + }); + + beforeEach(() => { + cy.visit("/starting-materials"); + }); + + it("Loads the Starting material page without any errors", () => { + cy.findByText("About").should("exist"); + cy.findByText("Inventory").should("exist"); + cy.findByText("Add a starting material").should("exist"); + }); + + it("Adds some valid starting material entries", () => { + cy.createStartingMaterial("test_sm1", "a scientific starting material"); + cy.verifyStartingMaterial("test_sm1", "a scientific starting material"); + + cy.createStartingMaterial("test_sm2"); + cy.verifyStartingMaterial("test_sm2"); + + cy.createStartingMaterial("test_sm3", "my inst", "1990-01-07T00:00:00"); + cy.verifyStartingMaterial("test_sm3", "my inst", "1990-01-07T00:00:00"); + + cy.createStartingMaterial("123startingMaterial", null, "2005-04-03T00:00:00"); + cy.verifyStartingMaterial("123startingMaterial", null, "2005-04-03T00:00:00"); + }); + + it("Checks if one of the starting material is in the database", () => { + cy.request({ url: `${API_URL}/get-item-data/test_sm3`, failOnStatusCode: true }) + .its("body") + .then((body) => { + expect(body).to.have.property("item_id", "test_sm3"); + expect(body.item_data).to.have.property("item_id", "test_sm3"); + expect(body.item_data).to.have.property("name", "my inst"); + expect(body.item_data).to.have.property("date", "1990-01-07T00:00:00"); + }); + }); + + it("Attempts to Add a starting material with the same name", () => { + cy.findByText("Add a starting material").click(); + cy.get('[data-testid="create-item-form"]').within(() => { + cy.findByLabelText("ID:").type("test_sm3"); + cy.findByText("Submit").click(); + }); + + cy.contains("already in use").should("exist"); + cy.get(".form-error a").contains("test_sm3"); + + cy.get("[data-testid=create-item-form]").contains("Submit").should("be.disabled"); + }); + + it("Deletes a starting material", function () { + cy.deleteStartingMaterial(["test_sm2"]); + cy.contains("test_sm2").should("not.exist"); + + cy.request({ url: `${API_URL}/get-item-data/test_sm2`, failOnStatusCode: false }).then( + (resp) => { + expect(resp.status).to.be.gte(400).lt(500); + }, + ); + }); + + it("copies a starting material entry", () => { + cy.findByText("Add a starting material").click(); + + cy.get('[data-testid="create-item-form"]').within(() => { + cy.findByLabelText("ID:").type("test_sm3_copy"); + cy.findByLabelText("(Optional) Copy from existing starting material:").type("test_sm3"); + cy.findByLabelText("(Optional) Copy from existing starting material:") + .contains(".vs__dropdown-menu .badge", "test_sm3") + .click(); + + cy.findByLabelText("Name:"); //("COPY OF my inst") + + cy.findByText("Submit").click(); + }); + + cy.verifyStartingMaterial("test_sm3_copy", "COPY OF my inst", null); + }); +}); + +describe("Starting material edit page", () => { + beforeEach(() => { + cy.visit("/starting-materials/"); + }); + + it("Checks the equipment edit page", () => { + cy.findByText("test_sm3").click(); + cy.wait(1000); + cy.go("back"); + cy.verifyStartingMaterial("test_sm3", "my inst", "1990-01-07T00:00:00"); + }); + + it("modifies some data in a starting material", () => { + cy.findByText("test_sm3").click(); + cy.get('[id="item-description"]').type("this is a description of testB."); + cy.findByLabelText("Date acquired").type("2000-01-01"); + cy.findByLabelText("Location").type("room 404"); + + cy.findByText("Add a block").click(); + cy.findByText("Comment").click(); + + cy.get(".datablock-content div").first().type("a comment is added here."); + + cy.get(".fa-save").click(); + cy.visit("/starting-materials"); + cy.verifyStartingMaterial("test_sm3", "my inst", "2000-01-01T00:00", "room 404"); + }); +}); + +describe("Starting material table page - editable_inventory FALSE", () => { + before(() => { + Cypress.env("VUE_APP_EDITABLE_INVENTORY", "false"); + }); + + beforeEach(() => { + cy.visit("/starting-materials"); + }); + + it("Does not allow adding starting materials", () => { + cy.findByText("Add a starting material").click(); + cy.get('[data-testid="create-item-form"]').within(() => { + cy.findByLabelText("ID:").type("test_sm1"); + cy.findByText("Submit").click(); + }); + + cy.get("[data-testid=create-item-form]").contains("Submit").should("be.disabled"); + }); + + it("Does not allow modifying existing starting materials", () => { + cy.findByText("test_sm3").click(); + cy.get('[id="item-description"]').should("not.exist"); + }); +});