/** * Live Tracking — Halted state editor (issue #255) * * Verifies the approver flow on the Halted section of the property detail * drawer: * 1. an approver can set a halted date + free-text reason and save them, * 2. the drawer reflects the halted state (badge + persisted values), * 3. clicking Resume clears the date but keeps the reason as the * last-set value, both in the input and after a reload. * * Mirrors `pibi-dates.cy.js`. Assumes an authenticated approver session * is reusable by the test harness; the target portfolio + a deal whose * Halted section is editable by the current user are read from Cypress * env vars so the spec stays portable. */ const PORTFOLIO_SLUG = Cypress.env("LIVE_PORTFOLIO_SLUG"); const TARGET_DEAL_NAME = Cypress.env("LIVE_HALTED_DEAL_NAME"); const HALTED_DATE = "2025-06-01"; const HALTED_REASON = "Awaiting roof access from landlord"; describe("Halted state editor — approver flow", function () { before(function () { if (!PORTFOLIO_SLUG) { cy.log( "LIVE_PORTFOLIO_SLUG env var not set — skipping live tracking specs", ); this.skip(); } }); function openDrawerForTargetDeal() { cy.visit(`/portfolio/${PORTFOLIO_SLUG}/your-projects/live`); // Switch to the Measures tab — the easiest way into the drawer. cy.contains("button, [role=tab]", "Measures").click(); if (TARGET_DEAL_NAME) { cy.contains("[data-testid=measures-row]", TARGET_DEAL_NAME).click(); } else { cy.get("[data-testid=measures-row]").first().click(); } cy.get("[data-testid=property-detail-drawer]").should("be.visible"); // Navigate to Survey & Admin tab (drawer opens on Works tab from Measures row click). cy.get("[data-testid=drawer-tab-survey-admin]").click(); cy.get("[data-testid=drawer-section-halted]").should("exist"); } it("lets an approver halt a property and resume it while preserving the reason", () => { openDrawerForTargetDeal(); // Approver sees editable inputs. cy.get("[data-testid=halted-date-input]").should("be.visible"); cy.get("[data-testid=halted-reason-input]").should("be.visible"); // Set halted date + reason. cy.get("[data-testid=halted-date-input]").clear().type(HALTED_DATE); cy.get("[data-testid=halted-reason-input]") .clear() .type(HALTED_REASON); cy.get("[data-testid=halted-save-button]") .should("not.be.disabled") .click(); // Save completes — button label flips back, no error banner. cy.get("[data-testid=halted-save-button]").should( "contain.text", "Save Halted State", ); cy.get("[data-testid=halted-error]").should("not.exist"); // Drawer reflects halted state via the status badge + persisted values. cy.get("[data-testid=halted-status-badge]").should("contain.text", "Halted"); cy.get("[data-testid=halted-date-input]").should("have.value", HALTED_DATE); cy.get("[data-testid=halted-reason-input]").should( "have.value", HALTED_REASON, ); // Now resume — date clears, reason stays. cy.get("[data-testid=halted-resume-button]") .should("be.visible") .click(); // Once resumed the badge + resume button disappear, but the reason is // still visible in the textarea. cy.get("[data-testid=halted-status-badge]").should("not.exist"); cy.get("[data-testid=halted-resume-button]").should("not.exist"); cy.get("[data-testid=halted-date-input]").should("have.value", ""); cy.get("[data-testid=halted-reason-input]").should( "have.value", HALTED_REASON, ); // Reload the page — the cleared date and preserved reason persist // server-side. cy.reload(); openDrawerForTargetDeal(); cy.get("[data-testid=halted-date-input]").should("have.value", ""); cy.get("[data-testid=halted-reason-input]").should( "have.value", HALTED_REASON, ); }); });