From 1c5727850ac951b14eac4474b28a3a2ef43ae69a Mon Sep 17 00:00:00 2001 From: Hardik Date: Wed, 27 May 2026 00:00:51 +0530 Subject: [PATCH] fix(gst): 0% GST rate no longer falls back to 18% parseFloat('0') is falsy in JS so `|| 0.18` silently discarded the user's explicit 0% selection. Replaced with an explicit empty-string guard. Adds e2e spec gst-rate.spec.ts covering all five GST rates (0/5/12/18/28%). Co-Authored-By: Claude Sonnet 4.6 --- .../devops-env-manager/project_services.md | 68 ++++++++------ .claude/agents/pelagia-playwright-tester.md | 29 +++--- .claude/settings.local.json | 18 +++- App/components/po/po-line-items-editor.tsx | 2 +- App/tests/e2e/gst-rate.spec.ts | 92 +++++++++++++++++++ 5 files changed, 169 insertions(+), 40 deletions(-) create mode 100644 App/tests/e2e/gst-rate.spec.ts diff --git a/.claude/agent-memory/devops-env-manager/project_services.md b/.claude/agent-memory/devops-env-manager/project_services.md index 7588a65..6659f82 100644 --- a/.claude/agent-memory/devops-env-manager/project_services.md +++ b/.claude/agent-memory/devops-env-manager/project_services.md @@ -9,20 +9,28 @@ metadata: | Service | Port | Startup Command | Directory | |---|---|---|---| -| pelagia-portal (Next.js) | 3000 | `node node_modules/next/dist/bin/next dev --turbopack` | `App/` | +| pelagia-portal (Next.js) | 3000 | `node node_modules\next\dist\bin\next dev --turbopack` | `App/` | | GstService (Express + Playwright) | 3003 | `npm run dev` (runs `tsx watch src/index.ts`) | `GstService/` | | PostgreSQL 18 | 5432 | Windows service / already running | — | +## Directory Structure (verified 2026-05-26) + +- Portal source: `App/` (contains package.json, next.config.ts, prisma/, app/, etc.) +- GstService source: `GstService/` (contains src/index.ts) +- `App/pelagia-portal/` — built artifact / deployed copy, NOT the source; has node_modules + .env.local but no package.json at root +- Project root (`C:\Users\shad0w\Documents\src\Peliagia_Portal`) has no package.json — the portal source is in `App/` + ## Startup Order 1. Verify PostgreSQL is up on port 5432 (`pg_isready -U postgres`) -2. Create DB if missing: `createdb -U postgres pelagia_portal` (PGPASSWORD=postgres) -3. Run `prisma migrate deploy` from `App/` (non-interactive, applies all pending migrations) -4. Run `prisma generate` from `App/` (generates Prisma client into node_modules) -5. Start GstService: `cd GstService && npm run dev` -6. Start pelagia-portal: `node node_modules/next/dist/bin/next dev --turbopack` from `App/` - - DO NOT use `pnpm dev` — pnpm pre-flight runs `pnpm install` which hits ERR_PNPM_IGNORED_BUILDS and aborts - - Call next directly via node to bypass pnpm dependency check +2. Install App/ deps if missing: `cd App && pnpm install --frozen-lockfile` (pnpm v10 — allowBuilds in pnpm-workspace.yaml handles build scripts cleanly) +3. Ensure `App/.env` exists with `DATABASE_URL` (Prisma reads `.env`, not `.env.local`) +4. Run `prisma migrate deploy` from `App/` using `.\node_modules\.bin\prisma.cmd migrate deploy` +5. Run `prisma generate` from `App/` using `.\node_modules\.bin\prisma.cmd generate` +6. Start GstService: `cd GstService && npm run dev > logfile 2>&1` (background) +7. Start pelagia-portal: `cd App && node node_modules\next\dist\bin\next dev --turbopack > logfile 2>&1` (background) + - DO NOT use `pnpm dev` — pnpm 10 still runs pre-install hooks that may interfere; calling next directly is safer and consistent +8. Health check both services ## Health Checks @@ -32,35 +40,43 @@ metadata: ## Environment -- App is in `K:\src\pelagia-portal\App\` (NOT `App/pelagia-portal/` — that path is stale git history) -- `.env.local` in `App/` holds actual dev secrets (NEXTAUTH_SECRET, DATABASE_URL) +- Portal `.env.local` location: `App/.env.local` (copy from `App/pelagia-portal/.env.local` if App/ is a fresh checkout) +- Portal `.env` location: `App/.env` — must contain `DATABASE_URL` for Prisma CLI (Prisma only reads `.env`, not `.env.local`) - Required dev vars: `NEXTAUTH_SECRET`, `NEXTAUTH_URL`, `DATABASE_URL` - R2 and Resend vars not needed in dev (files go to `.dev-uploads/`, emails log to console) - DATABASE_URL: `postgresql://postgres:postgres@localhost:5432/pelagia_portal` -- NEXTAUTH_SECRET: in .env.local - NEXTAUTH_URL: `http://localhost:3000` ## Node / Package Manager Setup -- Node.js: `C:\Program Files\nodejs` (NOT on system PATH by default — must prepend) -- pnpm: installed globally at `C:\Users\shad0w\AppData\Roaming\npm\node_modules\pnpm` - - $env:PATH must include `$env:APPDATA\npm` to find pnpm +- Node.js: `C:\Program Files\nodejs` (must prepend to PATH) +- pnpm: v10.33.2, installed at `C:\Users\shad0w\AppData\Roaming\npm\node_modules\pnpm` + - `$env:PATH` must include `$env:APPDATA\npm` to find pnpm - PostgreSQL 18 bin: `C:\Program Files\PostgreSQL\18\bin` -- Set PATH at start of each session: `$env:PATH = "C:\Program Files\nodejs;C:\Program Files\PostgreSQL\18\bin;$env:APPDATA\npm;$env:PATH"` +- Set PATH at start of each session: + `$env:PATH = "C:\Program Files\nodejs;C:\Program Files\PostgreSQL\18\bin;$env:APPDATA\npm;$env:PATH"` - PGPASSWORD=postgres for psql/createdb commands -## pnpm ERR_PNPM_IGNORED_BUILDS Issue +## Prisma Notes -- pnpm 11.1.2 blocks build scripts for: @prisma/client, @prisma/engines, esbuild, prisma, sharp, unrs-resolver -- The `pnpm.onlyBuiltDependencies` field in package.json does NOT fix this (field not recognized by pnpm 11) -- Workaround: use `node node_modules/next/dist/bin/next dev --turbopack` instead of `pnpm dev` -- Run `prisma generate` manually after install: `.\node_modules\.bin\prisma generate` -- The pnpm install itself completes (all 885 packages are installed) — only postinstall scripts are blocked +- Use `.\node_modules\.bin\prisma.cmd` (not `node node_modules\.bin\prisma`) — the `.bin\prisma` shim is a bash script and fails on Windows/PowerShell +- Prisma reads `App/.env` for DATABASE_URL; `.env.local` is NOT read by Prisma CLI +- `prisma generate` EPERM on Windows = DLL locked by running Node process — normal +- 14 migrations as of 2026-05-26 (latest: `20260521000000_remove_vessel_imo_number`) + +## Log Files (when started as background processes) + +- GstService: `C:\Users\shad0w\AppData\Local\Temp\gstservice.log` +- pelagia-portal: `C:\Users\shad0w\AppData\Local\Temp\portal.log` + +## pnpm workspace + +- `App/pnpm-workspace.yaml` uses `allowBuilds:` field (pnpm v10 syntax) to allow build scripts for @prisma/client, @prisma/engines, esbuild, prisma, sharp, unrs-resolver +- This resolves the ERR_PNPM_IGNORED_BUILDS issue from pnpm v11 era ## Notes -- `prisma generate` EPERM on Windows = the DLL is locked by a running Node process (Next.js) — this is normal -- pelagia-portal 307 response = auth redirect to /login — this is healthy, not an error -- Prisma migration scripts: `pnpm db:migrate` (dev), `pnpm db:migrate:deploy` (CI/prod) -- `node_modules` was missing on first setup (fresh checkout) — both App and GstService need install -- 13 Prisma migrations as of 2026-05-18 \ No newline at end of file +- pelagia-portal 307 response = auth redirect to /login — healthy, not an error +- GstService `browserConnected: false` at startup is normal — Playwright browser connects on first session +- Prisma migration scripts: `pnpm db:migrate` (dev), `pnpm db:migrate:deploy` (CI/prod) — run from App/ +- `App/pelagia-portal/` is a deployed artifact directory (has .next/, node_modules, .env.local) — do not confuse with source diff --git a/.claude/agents/pelagia-playwright-tester.md b/.claude/agents/pelagia-playwright-tester.md index f5591f4..7d2ae80 100644 --- a/.claude/agents/pelagia-playwright-tester.md +++ b/.claude/agents/pelagia-playwright-tester.md @@ -31,20 +31,27 @@ You create, execute, and persist Playwright browser tests that validate the Pela - Parameterize tests for data-driven scenarios where the user story covers multiple input variations. ### 3. Test Execution -- Run tests using the Playwright CLI or the project's configured test runner. -- Execute tests in headed mode first if debugging is needed, then confirm they pass in headless mode. -- If a test fails: - - Analyze the failure output and screenshots/traces carefully. - - Distinguish between a bug in the implementation vs. a mistake in the test. - - If it is a test authoring issue, fix and re-run. - - If it appears to be a real application bug, document it clearly and report it before saving the test. - - Do not save a test that does not pass. -- Confirm all assertions are meaningful — avoid tests that pass vacuously. + +**ALWAYS use a saved script — never run ad-hoc Playwright code.** For every verification task: + +1. **Check for an existing script first.** Before writing anything, glob `App/tests/e2e/**/*.spec.ts` for a test that already covers the area (e.g., `gst-rate.spec.ts` for GST, `auth.spec.ts` for login). If one exists, run it directly with `pnpm test:e2e -- ` rather than writing a new one. +2. **If no script exists, write and save one** (see Saving Tests below) before running it. Do not execute test logic that lives only in memory or a temp file. +3. **Run using the project test runner:** `pnpm test:e2e -- App/tests/e2e/.spec.ts` from the `App/` directory. +4. Execute tests in headless mode by default; use headed mode only when debugging a selector failure. +5. If a test fails: + - Analyze the failure output and screenshots/traces carefully. + - Distinguish between a bug in the implementation vs. a mistake in the test. + - If it is a test authoring issue, fix the saved script and re-run. + - If it appears to be a real application bug, document it clearly and report it before saving the test. + - Do not mark a verification as passed unless the saved script exits 0. +6. Confirm all assertions are meaningful — avoid tests that pass vacuously. ### 4. Saving Tests -- Once a test passes reliably, save it to the `Tests/` directory following the structure and naming conventions defined in `PLAYRIGHT_TEST_DESGN.md`. -- Include a file-level comment block documenting: the user story ID(s) covered, a brief description, the date created, and any known limitations. +- Save every test to `App/tests/e2e/` (or a subdirectory) **immediately after writing it** — before the first run. This ensures the canonical script exists on disk from the start. +- Follow the naming conventions and structure in `PLAYRIGHT_TEST_DESGN.md` and mirror the style of existing specs (file-level JSDoc comment, `test.describe` block where applicable, `beforeEach` login helper). +- Include a file-level comment block documenting: the user story ID(s) or bug ID covered, a brief description, the date created, and any known limitations. - Ensure the saved file is self-contained and runnable without modification. +- When verifying a bug fix, reuse the same script for both the "repro" run (before fix) and the "green" run (after fix) — just run it twice. Do not write separate scripts for repro vs. verification. ## Test Quality Standards diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 20e5dd9..c05b41c 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -18,7 +18,21 @@ "Bash(sed 's/ D //')", "Bash(sed 's/?? //')", "WebFetch(domain:web.archive.org)", - "WebFetch(domain:www.pexels.com)" + "WebFetch(domain:www.pexels.com)", + "Bash(npm run *)", + "Bash(npm install *)", + "Bash(node *)", + "Bash(taskkill *)", + "Bash(pg_isready *)", + "PowerShell(netstat *)", + "PowerShell(Get-Process *)", + "PowerShell(Stop-Process *)", + "PowerShell(Get-ChildItem *)", + "PowerShell(Test-NetConnection *)", + "PowerShell(Invoke-WebRequest *)", + "PowerShell(npm *)", + "PowerShell(pnpm *)", + "PowerShell(node *)" ] } -} +} \ No newline at end of file diff --git a/App/components/po/po-line-items-editor.tsx b/App/components/po/po-line-items-editor.tsx index f37cccf..1caeead 100644 --- a/App/components/po/po-line-items-editor.tsx +++ b/App/components/po/po-line-items-editor.tsx @@ -83,7 +83,7 @@ function toLineItem(row: EditRow): LineItemInput { unit: row.unit, size: row.size || undefined, unitPrice: parseFloat(row.unitPrice) || 0, - gstRate: parseFloat(row.gstRate) || 0.18, + gstRate: row.gstRate !== "" && row.gstRate != null ? parseFloat(row.gstRate) : 0.18, productId: row.productId || undefined, accountId: row.accountId || undefined, }; diff --git a/App/tests/e2e/gst-rate.spec.ts b/App/tests/e2e/gst-rate.spec.ts new file mode 100644 index 0000000..8caf901 --- /dev/null +++ b/App/tests/e2e/gst-rate.spec.ts @@ -0,0 +1,92 @@ +/** + * E2E — GST rate selection correctness on the PO line-items editor. + * + * Bug covered: GST-0PCT-FALLBACK (fixed 2026-05-26) + * `parseFloat('0') || 0.18` is falsy, so selecting 0% GST silently fell back + * to 18%. Fixed by changing the expression to an explicit null/empty-string + * guard: `row.gstRate !== "" && row.gstRate != null ? parseFloat(row.gstRate) : 0.18` + * + * User story: S-01 (create PO, line items with correct GST calculation) + * Acceptance criterion: selecting any GST rate (0 / 5 / 12 / 18 / 28 %) on a + * line item must produce the mathematically correct Grand Total in the footer. + * + * Preconditions: + * - Dev server running at http://localhost:3000 + * - Seed data present (at least one vessel and account selectable) + * - tech@pelagia.local / tech1234 credentials valid + */ + +import { test, expect, type Page } from "@playwright/test"; +import { login, fillPoHeader, USERS } from "./helpers/login"; + +// ── Helpers ────────────────────────────────────────────────────────────────── + +/** Selects a GST rate in the first line-item row's GST dropdown. */ +async function selectGstRate(page: Page, value: string): Promise { + const lineItemsSection = page.locator("section").filter({ + has: page.getByRole("heading", { name: /line items/i }), + }); + const firstRow = lineItemsSection.locator("tbody tr").first(); + // The GST select is the second