Bug 42705: Fix SCO spec WebBasedSelfCheck setup

cy.login() in beforeEach broke the test in two ways: the intranet staff session cookie bled into the OPAC request (HTTP cookies have no port scope in
browsers), and navigating from intranet→OPAC mid-test hit a cross-origin block in Cypress. The afterEach suffered the same race condition - the syspref POST fired before the login redirect completed.

Replace with cy.request(), which makes HTTP calls at the runner level without touching the browser's current origin. cy.visitOpac() is then the first
browser navigation, so no cross-origin issue arises. A three-step flow satisfies Koha's CSRF middleware:
1) GET the login page to obtain a session and its token
2) POST credentials to authenticate
3) POST to the svc endpoint.

This fixes the #barcode and #patronlogin not found issues

The CSRF token also requires encodeURIComponent() — base64 uses +, which a
URL-encoded form body decodes as a space, silently corrupting the token and causing the login to fail.

This resolves the 403 Forbidden issue

Everything must pass:
$ cypress run --spec t/cypress/integration/OPAC/SCO_spec.ts

as well as npm run cypress open (cypress ui)

ktd selenium:
$ perl /kohadevbox/misc4dev/run_tests.pl --run-only t/cypress/integration/OPAC/SCO_spec.ts

squash

Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
This commit is contained in:
Pedro Amorim 2026-06-01 15:03:02 +00:00 committed by Lucas Gass
parent 5baf1ce6e0
commit 64e4501129
No known key found for this signature in database
GPG Key ID: 60B447398B0D36CA
1 changed files with 50 additions and 4 deletions

View File

@ -1,4 +1,50 @@
describe("SCO", () => {
// Sets a system preference via the intranet svc endpoint using only
// cy.request() — no browser navigation, so no cross-origin issues.
function setSyspref(variable: string, value: string) {
// Step 1: GET the login page to get an anonymous session + its CSRF token
cy.request("/cgi-bin/koha/mainpage.pl?logout.x=1").then(loginPage => {
const csrfForLogin = (loginPage.body as string).match(
/<meta name="csrf-token" content="([^"]+)"/
)?.[1];
if (!csrfForLogin)
throw new Error("CSRF token not found on login page");
// Step 2: POST credentials — Koha authenticates and redirects to the
// logged-in mainpage whose body contains the new session's CSRF token
cy.request({
method: "POST",
url: "/cgi-bin/koha/mainpage.pl",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
body: [
`login_userid=${encodeURIComponent(Cypress.env("apiUsername"))}`,
`login_password=${encodeURIComponent(Cypress.env("apiPassword"))}`,
`csrf_token=${encodeURIComponent(csrfForLogin)}`,
`login_op=cud-login`,
].join("&"),
}).then(mainPage => {
const csrfForSvc = (mainPage.body as string).match(
/<meta name="csrf-token" content="([^"]+)"/
)?.[1];
if (!csrfForSvc)
throw new Error("CSRF token not found on main page");
// Step 3: POST to svc endpoint — session cookie sent automatically
cy.request({
method: "POST",
url: "/cgi-bin/koha/svc/config/systempreferences",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
"CSRF-TOKEN": csrfForSvc,
},
body: `pref_${encodeURIComponent(variable)}=${encodeURIComponent(value)}`,
});
});
});
}
beforeEach(() => {
cy.task("insertSampleBiblio", { item_count: 1 }).then(objects => {
cy.wrap(objects).as("objects");
@ -9,15 +55,15 @@ describe("SCO", () => {
});
cy.task("query", {
sql: "SELECT value FROM systempreferences WHERE variable='WebBasedSelfCheck'",
}).then(value => {
cy.wrap(value).as("syspref_WebBasedSelfCheck");
}).then(rows => {
cy.wrap(rows[0].value).as("syspref_WebBasedSelfCheck");
});
setSyspref("WebBasedSelfCheck", "1");
});
afterEach(function () {
cy.task("deleteSampleObjects", this.objects);
cy.login();
cy.set_syspref("WebBasedSelfCheck", this.syspref_WebBasedSelfCheck);
setSyspref("WebBasedSelfCheck", this.syspref_WebBasedSelfCheck);
});
it("Should not crash if barcode contains '+'", function () {