From a5372789902f518c288e574ba19937a3732b8eaa Mon Sep 17 00:00:00 2001 From: Martin Renvoize Date: Thu, 23 Oct 2025 11:56:27 +0100 Subject: [PATCH] Bug 23415: Add Cypress test coverage for FineNoRenewals This commit adds end-to-end tests for the fine-based renewal blocking functionality using Cypress. Test coverage includes: 1. Blocking renewal when patron fines exceed FineNoRenewals limit 2. Displaying override button when AllowFineOverrideRenewing is enabled 3. Hiding override button when AllowFineOverrideRenewing is disabled 4. Successful override when permission is enabled 5. Allowing renewal when fines are below the limit The test creates test data including: - A patron with checkouts - Account fines that exceed the FineNoRenewals threshold - Tests both blocking and override scenarios Tests verify the UI behavior matches the business logic: - Error messages are displayed correctly - Override buttons appear based on preference setting - Override functionality works as expected - Security is maintained (no override without permission) To run these tests: npx cypress run --spec "t/cypress/integration/Circulation/FineNoRenewals_spec.ts" Signed-off-by: Martin Renvoize --- .../Circulation/FineNoRenewals_spec.ts | 180 ++++++++++++++++++ 1 file changed, 180 insertions(+) create mode 100644 t/cypress/integration/Circulation/FineNoRenewals_spec.ts diff --git a/t/cypress/integration/Circulation/FineNoRenewals_spec.ts b/t/cypress/integration/Circulation/FineNoRenewals_spec.ts new file mode 100644 index 00000000000..8f49d3979ab --- /dev/null +++ b/t/cypress/integration/Circulation/FineNoRenewals_spec.ts @@ -0,0 +1,180 @@ +describe("Circulation - FineNoRenewals and AllowFineOverrideRenewing", () => { + beforeEach(() => { + cy.login(); + cy.title().should("eq", "Koha staff interface"); + }); + + describe("Renewal with fines", () => { + let patron, checkout, fine_amount; + + beforeEach(function () { + // Set up test data: patron with checkout and fines + cy.task("insertSampleCheckout").then(objects => { + patron = objects.patron; + checkout = objects.checkout; + + // Set FineNoRenewals to 5 + cy.task("query", { + sql: "UPDATE systempreferences SET value = ? WHERE variable = ?", + values: ["5", "FineNoRenewals"], + }); + + // Add a fine of 10 to the patron (exceeds limit) + fine_amount = 10; + cy.task("query", { + sql: `INSERT INTO accountlines (borrowernumber, amountoutstanding, debit_type_code, status, interface, itemnumber) + VALUES (?, ?, 'OVERDUE', 'UNRETURNED', 'test', ?)`, + values: [ + patron.patron_id, + fine_amount, + objects.item.item_id, + ], + }); + + cy.wrap(objects).as("testObjects"); + }); + }); + + afterEach(function () { + // Clean up + cy.task("deleteSampleObjects", [this.testObjects]); + + // Reset system preferences + cy.task("query", { + sql: "UPDATE systempreferences SET value = '100' WHERE variable = 'FineNoRenewals'", + }); + cy.task("query", { + sql: "UPDATE systempreferences SET value = '0' WHERE variable = 'AllowFineOverrideRenewing'", + }); + }); + + it("should block renewal when patron has fines over FineNoRenewals limit", function () { + const barcode = this.testObjects.item.barcode; + + // Visit renewal page + cy.visit("/cgi-bin/koha/circ/renew.pl"); + + // Enter barcode + cy.get("#barcode").type(barcode); + cy.get("form").submit(); + + // Should see error message about patron debt + cy.get(".dialog.alert").should("be.visible"); + cy.get(".dialog.alert li").should( + "contain", + `The patron has a debt of` + ); + }); + + it("should show override button when AllowFineOverrideRenewing is enabled", function () { + // Enable AllowFineOverrideRenewing + cy.task("query", { + sql: "UPDATE systempreferences SET value = '1' WHERE variable = 'AllowFineOverrideRenewing'", + }); + + const barcode = this.testObjects.item.barcode; + + // Visit renewal page + cy.visit("/cgi-bin/koha/circ/renew.pl"); + + // Enter barcode + cy.get("#barcode").type(barcode); + cy.get("form").submit(); + + // Should see error message about patron debt + cy.get(".dialog.alert").should("be.visible"); + cy.get(".dialog.alert li").should( + "contain", + `The patron has a debt of` + ); + + // Should see override button + cy.get('.dialog.alert form button[type="submit"].approve').should( + "be.visible" + ); + cy.get('.dialog.alert form button[type="submit"].approve').should( + "contain", + "Renew checkout(s)" + ); + }); + + it("should NOT show override button when AllowFineOverrideRenewing is disabled", function () { + // Ensure AllowFineOverrideRenewing is disabled + cy.task("query", { + sql: "UPDATE systempreferences SET value = '0' WHERE variable = 'AllowFineOverrideRenewing'", + }); + + const barcode = this.testObjects.item.barcode; + + // Visit renewal page + cy.visit("/cgi-bin/koha/circ/renew.pl"); + + // Enter barcode + cy.get("#barcode").type(barcode); + cy.get("form").submit(); + + // Should see error message about patron debt + cy.get(".dialog.alert").should("be.visible"); + cy.get(".dialog.alert li").should( + "contain", + `The patron has a debt of` + ); + + // Should NOT see override button + cy.get('.dialog.alert form button[type="submit"].approve').should( + "not.exist" + ); + }); + + it("should allow renewal after override when AllowFineOverrideRenewing is enabled", function () { + // Enable AllowFineOverrideRenewing + cy.task("query", { + sql: "UPDATE systempreferences SET value = '1' WHERE variable = 'AllowFineOverrideRenewing'", + }); + + const barcode = this.testObjects.item.barcode; + + // Visit renewal page + cy.visit("/cgi-bin/koha/circ/renew.pl"); + + // Enter barcode + cy.get("#barcode").type(barcode); + cy.get("form").submit(); + + // Click override button + cy.get('.dialog.alert form button[type="submit"].approve').click(); + + // Should see success message + cy.get(".dialog.message").should("be.visible"); + cy.get(".dialog.message").should("contain", "Item renewed"); + }); + + it("should allow renewal when patron has fines below FineNoRenewals limit", function () { + // Delete the existing fine + cy.task("query", { + sql: "DELETE FROM accountlines WHERE borrowernumber = ?", + values: [patron.patron_id], + }); + + // Add a smaller fine (below limit) + cy.task("query", { + sql: `INSERT INTO accountlines (borrowernumber, amountoutstanding, debit_type_code, status, interface, itemnumber) + VALUES (?, 3.00, 'OVERDUE', 'UNRETURNED', 'test', ?)`, + values: [patron.patron_id, this.testObjects.item.item_id], + }); + + const barcode = this.testObjects.item.barcode; + + // Visit renewal page + cy.visit("/cgi-bin/koha/circ/renew.pl"); + + // Enter barcode + cy.get("#barcode").type(barcode); + cy.get("form").submit(); + + // Should see success message (no error about fines) + cy.get(".dialog.message").should("be.visible"); + cy.get(".dialog.message").should("contain", "Item renewed"); + }); + }); +}); -- 2.51.1