From 8d0eed1c6a2fbf258173f7e99bbea25a8c1014a8 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 comprehensive 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" --- .../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.0