Bug 40170: Replace cypress-mysql with mysql2 - Cypress tests
This patch suggests to replace cypress-mysql with mysql2 cypress-mysql provides a custom Cypress command (cy.query) that run within the browser context. This approach mixes test-side and server-side and is limited in flexibility and error handling. mysql2 runs inside Cypress plugins (Node process) via cy.task calls, which are executed server-side (outside the browser) This is needed for the follow-up bug reports where we need to request the DB from other plugins Test plan: Run `yarn install` to install the mysql2 All the Cypress tests modified by this patch must still pass The new test t/cypress/integration/t/db.ts must also pass Signed-off-by: David Nind <david@davidnind.com> Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk> Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
This commit is contained in:
parent
6096d986d5
commit
79060544a4
|
|
@ -15,13 +15,5 @@ export default defineConfig({
|
|||
baseUrl: "http://localhost:8081",
|
||||
specPattern: "t/cypress/integration/**/*.*",
|
||||
supportFile: "t/cypress/support/e2e.js",
|
||||
env: {
|
||||
db: {
|
||||
host: "db",
|
||||
user: "koha_kohadev",
|
||||
password: "password",
|
||||
database: "koha_kohadev",
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@
|
|||
"bootstrap": "^5.3.3",
|
||||
"css-loader": "^6.6.0",
|
||||
"cypress": "^12.17.2",
|
||||
"cypress-mysql": "^1.0.0",
|
||||
"datatables.net-buttons": "^2.3.4",
|
||||
"datatables.net-vue3": "^2.0.0",
|
||||
"gulp": "^4.0.2",
|
||||
|
|
@ -82,6 +81,7 @@
|
|||
"globals": "^16.0.0",
|
||||
"gulp-tap": "^1.0.1",
|
||||
"html-webpack-plugin": "^5.5.0",
|
||||
"mysql2": "^3.14.1",
|
||||
"node-sass-tilde-importer": "^1.0.2",
|
||||
"postcss": "^8.4.14",
|
||||
"postcss-selector-parser": "^6.0.10",
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ const branchname = "test_branchname";
|
|||
|
||||
function cleanup() {
|
||||
const sql = "DELETE FROM branches WHERE branchcode=?";
|
||||
cy.query(sql, branchcode);
|
||||
cy.task("query", { sql, values: [branchcode] });
|
||||
}
|
||||
|
||||
describe("CSRF", () => {
|
||||
|
|
@ -32,10 +32,10 @@ describe("CSRF", () => {
|
|||
.find(".alert")
|
||||
.contains(/No CSRF token passed for POST/);
|
||||
|
||||
cy.query(
|
||||
"SELECT COUNT(*) as count FROM branches WHERE branchcode=?",
|
||||
branchcode
|
||||
).then(result => {
|
||||
cy.task("query", {
|
||||
sql: "SELECT COUNT(*) as count FROM branches WHERE branchcode=?",
|
||||
values: [branchcode],
|
||||
}).then(result => {
|
||||
expect(result[0].count).to.equal(0);
|
||||
});
|
||||
});
|
||||
|
|
@ -53,10 +53,10 @@ describe("CSRF", () => {
|
|||
.find(".alert")
|
||||
.contains(/Wrong CSRF token/);
|
||||
|
||||
cy.query(
|
||||
"SELECT COUNT(*) as count FROM branches WHERE branchcode=?",
|
||||
branchcode
|
||||
).then(result => {
|
||||
cy.task("query", {
|
||||
sql: "SELECT COUNT(*) as count FROM branches WHERE branchcode=?",
|
||||
values: [branchcode],
|
||||
}).then(result => {
|
||||
expect(result[0].count).to.equal(0);
|
||||
});
|
||||
});
|
||||
|
|
@ -89,10 +89,10 @@ describe("CSRF", () => {
|
|||
// We do not want Wrong CSRF token here
|
||||
cy.get(".message").should("not.exist");
|
||||
|
||||
cy.query(
|
||||
"SELECT COUNT(*) as count FROM branches WHERE branchcode=?",
|
||||
branchcode
|
||||
).then(result => {
|
||||
cy.task("query", {
|
||||
sql: "SELECT COUNT(*) as count FROM branches WHERE branchcode=?",
|
||||
values: [branchcode],
|
||||
}).then(result => {
|
||||
expect(result[0].count).to.equal(0);
|
||||
});
|
||||
});
|
||||
|
|
@ -112,19 +112,19 @@ describe("CSRF", () => {
|
|||
cy.get("select[name='libraries_length']").select("-1");
|
||||
cy.get("td").contains(branchcode);
|
||||
|
||||
cy.query(
|
||||
"SELECT COUNT(*) as count FROM branches WHERE branchcode=?",
|
||||
branchcode
|
||||
).then(result => {
|
||||
cy.task("query", {
|
||||
sql: "SELECT COUNT(*) as count FROM branches WHERE branchcode=?",
|
||||
values: [branchcode],
|
||||
}).then(result => {
|
||||
expect(result[0].count).to.equal(1);
|
||||
});
|
||||
});
|
||||
|
||||
it("Delete without CSRF", () => {
|
||||
cy.query("INSERT INTO branches(branchcode, branchname) VALUES (?, ?)", [
|
||||
branchcode,
|
||||
branchname,
|
||||
]);
|
||||
cy.task("query", {
|
||||
sql: "INSERT INTO branches(branchcode, branchname) VALUES (?, ?)",
|
||||
values: [branchcode, branchname],
|
||||
});
|
||||
|
||||
cy.visit("/cgi-bin/koha/admin/branches.pl");
|
||||
cy.get("select[name='libraries_length']").select("-1");
|
||||
|
|
@ -141,19 +141,19 @@ describe("CSRF", () => {
|
|||
.find(".alert")
|
||||
.contains(/No CSRF token passed for POST/);
|
||||
|
||||
cy.query(
|
||||
"SELECT COUNT(*) as count FROM branches WHERE branchcode=?",
|
||||
branchcode
|
||||
).then(result => {
|
||||
cy.task("query", {
|
||||
sql: "SELECT COUNT(*) as count FROM branches WHERE branchcode=?",
|
||||
values: [branchcode],
|
||||
}).then(result => {
|
||||
expect(result[0].count).to.equal(1);
|
||||
});
|
||||
});
|
||||
|
||||
it("Delete", () => {
|
||||
cy.query("INSERT INTO branches(branchcode, branchname) VALUES (?, ?)", [
|
||||
branchcode,
|
||||
branchname,
|
||||
]);
|
||||
cy.task("query", {
|
||||
sql: "INSERT INTO branches(branchcode, branchname) VALUES (?, ?)",
|
||||
values: [branchcode, branchname],
|
||||
});
|
||||
|
||||
cy.visit("/cgi-bin/koha/admin/branches.pl");
|
||||
cy.get("select[name='libraries_length']").select("-1");
|
||||
|
|
@ -165,10 +165,10 @@ describe("CSRF", () => {
|
|||
.find(".alert")
|
||||
.contains(/Library deleted successfully/);
|
||||
|
||||
cy.query(
|
||||
"SELECT COUNT(*) as count FROM branches WHERE branchcode=?",
|
||||
branchcode
|
||||
).then(result => {
|
||||
cy.task("query", {
|
||||
sql: "SELECT COUNT(*) as count FROM branches WHERE branchcode=?",
|
||||
values: [branchcode],
|
||||
}).then(result => {
|
||||
expect(result[0].count).to.equal(0);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -23,12 +23,14 @@ describe("Acquisitions menu", () => {
|
|||
it("Should show/hide links based on permissions", () => {
|
||||
cy.get(".sidebar_menu").should("be.visible");
|
||||
|
||||
cy.query(
|
||||
"UPDATE borrowers SET flags=2052 WHERE borrowernumber=51"
|
||||
).then(() => {
|
||||
cy.task("query", {
|
||||
sql: "UPDATE borrowers SET flags=2052 WHERE borrowernumber=51",
|
||||
}).then(() => {
|
||||
cy.reload(true);
|
||||
cy.get(".sidebar_menu a").should("have.length", 8);
|
||||
cy.query("UPDATE borrowers SET flags=1 WHERE borrowernumber=51");
|
||||
cy.task("query", {
|
||||
sql: "UPDATE borrowers SET flags=1 WHERE borrowernumber=51",
|
||||
});
|
||||
});
|
||||
});
|
||||
it("Should correctly apply the 'current' class", () => {
|
||||
|
|
|
|||
|
|
@ -42,7 +42,9 @@ describe("catalogue/detail/holdings_table with items", () => {
|
|||
cy.wrap(Promise.resolve())
|
||||
.then(() => {
|
||||
return queries.reduce((chain, { query, values }) => {
|
||||
return chain.then(() => cy.query(query, values));
|
||||
return chain.then(() =>
|
||||
cy.task("query", { sql: query, values })
|
||||
);
|
||||
}, Promise.resolve());
|
||||
})
|
||||
.then(() => {
|
||||
|
|
@ -102,9 +104,9 @@ describe("catalogue/detail/holdings_table with items", () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
cy.query(
|
||||
"SELECT value FROM systempreferences WHERE variable='AlwaysShowHoldingsTableFilters'"
|
||||
).then(value => {
|
||||
cy.task("query", {
|
||||
sql: "SELECT value FROM systempreferences WHERE variable='AlwaysShowHoldingsTableFilters'",
|
||||
}).then(value => {
|
||||
cy.wrap(value).as("syspref_AlwaysShowHoldingsTableFilters");
|
||||
});
|
||||
});
|
||||
|
|
@ -435,14 +437,16 @@ describe("catalogue/detail/holdings_table without items", () => {
|
|||
const item_type = generated_objects["item_type"];
|
||||
const queries = [
|
||||
{
|
||||
query: "INSERT INTO itemtypes(itemtype, description) VALUES (?, ?)",
|
||||
sql: "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));
|
||||
return queries.reduce((chain, { sql, values }) => {
|
||||
return chain.then(() =>
|
||||
cy.task("query", { sql, values })
|
||||
);
|
||||
}, Promise.resolve());
|
||||
})
|
||||
.then(() => {
|
||||
|
|
@ -491,9 +495,9 @@ describe("catalogue/detail/holdings_table without items", () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
cy.query(
|
||||
"SELECT value FROM systempreferences WHERE variable='AlwaysShowHoldingsTableFilters'"
|
||||
).then(value => {
|
||||
cy.task("query", {
|
||||
sql: "SELECT value FROM systempreferences WHERE variable='AlwaysShowHoldingsTableFilters'",
|
||||
}).then(value => {
|
||||
cy.wrap(value).as("syspref_AlwaysShowHoldingsTableFilters");
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ const patron_attr_type = "attribute_type4TEST";
|
|||
|
||||
function cleanup() {
|
||||
const sql = "DELETE FROM borrower_attribute_types WHERE code=?";
|
||||
cy.query(sql, patron_attr_type);
|
||||
cy.task("query", { sql, values: [patron_attr_type] });
|
||||
}
|
||||
describe("ExtendedPatronAttributes", () => {
|
||||
beforeEach(() => {
|
||||
|
|
@ -19,9 +19,9 @@ describe("ExtendedPatronAttributes", () => {
|
|||
cy.window().then(win => {
|
||||
win.localStorage.clear();
|
||||
});
|
||||
cy.query(
|
||||
"SELECT value FROM systempreferences WHERE variable='ExtendedPatronAttributes'"
|
||||
).then(value => {
|
||||
cy.task("query", {
|
||||
sql: "SELECT value FROM systempreferences WHERE variable='ExtendedPatronAttributes'",
|
||||
}).then(value => {
|
||||
cy.wrap(value).as("syspref_ExtendedPatronAttributes");
|
||||
});
|
||||
});
|
||||
|
|
@ -45,9 +45,9 @@ describe("ExtendedPatronAttributes", () => {
|
|||
cy.get("#search_patron_filter").type("something");
|
||||
cy.get("form.patron_search_form input[type='submit']").click();
|
||||
|
||||
cy.query(
|
||||
"select count(*) as nb_searchable from borrower_attribute_types where staff_searchable=1"
|
||||
).then(result => {
|
||||
cy.task("query", {
|
||||
sql: "select count(*) as nb_searchable from borrower_attribute_types where staff_searchable=1",
|
||||
}).then(result => {
|
||||
const has_searchable = result[0].nb_searchable;
|
||||
cy.wait("@searchPatrons").then(interception => {
|
||||
const q = interception.request.query.q;
|
||||
|
|
@ -55,10 +55,10 @@ describe("ExtendedPatronAttributes", () => {
|
|||
});
|
||||
});
|
||||
|
||||
cy.query(
|
||||
"INSERT INTO borrower_attribute_types(code, description, staff_searchable, searched_by_default) VALUES (?, 'only for tests', 1, 1)",
|
||||
patron_attr_type
|
||||
).then(() => {
|
||||
cy.task("query", {
|
||||
sql: "INSERT INTO borrower_attribute_types(code, description, staff_searchable, searched_by_default) VALUES (?, 'only for tests', 1, 1)",
|
||||
values: [patron_attr_type],
|
||||
}).then(() => {
|
||||
cy.visit("/cgi-bin/koha/members/members-home.pl");
|
||||
|
||||
cy.get("#search_patron_filter").type("something");
|
||||
|
|
@ -80,9 +80,9 @@ describe("ExtendedPatronAttributes", () => {
|
|||
cy.get("#search_patron_filter").type("something");
|
||||
cy.get("form.patron_search_form input[type='submit']").click();
|
||||
|
||||
cy.query(
|
||||
"select count(*) as nb_searchable from borrower_attribute_types where staff_searchable=1 AND searched_by_default=1"
|
||||
).then(result => {
|
||||
cy.task("query", {
|
||||
sql: "select count(*) as nb_searchable from borrower_attribute_types where staff_searchable=1 AND searched_by_default=1",
|
||||
}).then(result => {
|
||||
const has_searchable = result[0].nb_searchable;
|
||||
cy.wait("@searchPatrons").then(interception => {
|
||||
const q = interception.request.query.q;
|
||||
|
|
@ -94,10 +94,10 @@ describe("ExtendedPatronAttributes", () => {
|
|||
});
|
||||
});
|
||||
|
||||
cy.query(
|
||||
"INSERT INTO borrower_attribute_types(code, description, staff_searchable, searched_by_default) VALUES (?, 'only for tests', 1, 1)",
|
||||
patron_attr_type
|
||||
).then(() => {
|
||||
cy.task("query", {
|
||||
sql: "INSERT INTO borrower_attribute_types(code, description, staff_searchable, searched_by_default) VALUES (?, 'only for tests', 1, 1)",
|
||||
values: [patron_attr_type],
|
||||
}).then(() => {
|
||||
cy.visit("/cgi-bin/koha/members/members-home.pl");
|
||||
|
||||
cy.get("#search_patron_filter").type("something");
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
describe("DB tests", () => {
|
||||
it("should be able to SELECT", () => {
|
||||
cy.task("query", { sql: "SELECT count(*) FROM borrowers" }).then(
|
||||
rows => {
|
||||
expect(typeof rows.length).to.be.equal("number");
|
||||
}
|
||||
);
|
||||
cy.task("query", {
|
||||
sql: "SELECT count(*) FROM borrowers WHERE `surname` = ?",
|
||||
values: ["john"],
|
||||
}).then(rows => {
|
||||
expect(typeof rows.length).to.be.equal("number");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
const mysql = require("mysql2/promise");
|
||||
|
||||
const connectionConfig = {
|
||||
host: "db",
|
||||
user: "koha_kohadev",
|
||||
password: "password",
|
||||
database: "koha_kohadev",
|
||||
};
|
||||
|
||||
async function query(sql, params = []) {
|
||||
const connection = await mysql.createConnection(connectionConfig);
|
||||
const [rows] = await connection.execute(sql, params);
|
||||
await connection.end();
|
||||
return rows;
|
||||
}
|
||||
|
||||
module.exports = { query };
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
const { startDevServer } = require("@cypress/webpack-dev-server");
|
||||
|
||||
const mysql = require("cypress-mysql");
|
||||
|
||||
const { buildSampleObject, buildSampleObjects } = require("./mockData.js");
|
||||
|
||||
const { query } = require("./db.js");
|
||||
|
||||
module.exports = (on, config) => {
|
||||
on("dev-server:start", options =>
|
||||
startDevServer({
|
||||
|
|
@ -11,11 +11,10 @@ module.exports = (on, config) => {
|
|||
})
|
||||
);
|
||||
|
||||
mysql.configurePlugin(on);
|
||||
|
||||
on("task", {
|
||||
buildSampleObject,
|
||||
buildSampleObjects,
|
||||
query,
|
||||
});
|
||||
return config;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1874,9 +1874,6 @@ cy.getVendor = () => {
|
|||
};
|
||||
};
|
||||
|
||||
const mysql = require("cypress-mysql");
|
||||
mysql.addCommands();
|
||||
|
||||
Cypress.Commands.add("set_syspref", (variable, value) => {
|
||||
cy.window().then(win => {
|
||||
const client = win.APIClient.sysprefs;
|
||||
|
|
|
|||
Loading…
Reference in New Issue