From 5053ec96eaf998e5045f80c98425e2da8c4e2055 Mon Sep 17 00:00:00 2001 From: SJCoetz Date: Thu, 6 Aug 2026 02:04:28 +0200 Subject: [PATCH] test: add quote detail page layout regression tests Add a vitest suite that enforces critical layout invariants for the quote detail page, and include accompanying Playwright trace snapshots and console logs from the test execution. --- .../console-2026-08-05T23-56-08-778Z.log | 158 ++++++++++++++++ .../page-2026-08-05T23-56-52-776Z.yml | 2 + .../page-2026-08-05T23-57-19-450Z.yml | 175 ++++++++++++++++++ .../page-2026-08-05T23-57-44-389Z.yml | 2 + .../page-2026-08-05T23-58-12-084Z.yml | 175 ++++++++++++++++++ .../page-2026-08-05T23-58-27-286Z.yml | 9 + src/app/(app)/quotes/[id]/page.layout.test.ts | 84 +++++++++ 7 files changed, 605 insertions(+) create mode 100644 .playwright-mcp/page-2026-08-05T23-56-52-776Z.yml create mode 100644 .playwright-mcp/page-2026-08-05T23-57-19-450Z.yml create mode 100644 .playwright-mcp/page-2026-08-05T23-57-44-389Z.yml create mode 100644 .playwright-mcp/page-2026-08-05T23-58-12-084Z.yml create mode 100644 .playwright-mcp/page-2026-08-05T23-58-27-286Z.yml create mode 100644 src/app/(app)/quotes/[id]/page.layout.test.ts diff --git a/.playwright-mcp/console-2026-08-05T23-56-08-778Z.log b/.playwright-mcp/console-2026-08-05T23-56-08-778Z.log index c86ae35..ea5a5e0 100644 --- a/.playwright-mcp/console-2026-08-05T23-56-08-778Z.log +++ b/.playwright-mcp/console-2026-08-05T23-56-08-778Z.log @@ -9,3 +9,161 @@ [ 5124ms] [WARNING] The resource http://localhost:4001/_next/static/media/eaead17c7dbfcd5d-s.p.woff2?v=1785974168950 was preloaded using link preload but not used within a few seconds from the window's load event. Please make sure it has an appropriate `as` value and it is preloaded intentionally. @ http://localhost:4001/quotes/ybqit9d6150vmg0:0 [ 5124ms] [WARNING] The resource http://localhost:4001/_next/static/media/ee40bb094c99a29a-s.p.woff2?v=1785974168950 was preloaded using link preload but not used within a few seconds from the window's load event. Please make sure it has an appropriate `as` value and it is preloaded intentionally. @ http://localhost:4001/quotes/ybqit9d6150vmg0:0 [ 5124ms] [WARNING] The resource http://localhost:4001/_next/static/media/e4af272ccee01ff0-s.p.woff2?v=1785974168950 was preloaded using link preload but not used within a few seconds from the window's load event. Please make sure it has an appropriate `as` value and it is preloaded intentionally. @ http://localhost:4001/quotes/ybqit9d6150vmg0:0 +[ 60220ms] [INFO] %cDownload the React DevTools for a better development experience: https://react.dev/link/react-devtools font-weight:bold @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 60416ms] [LOG] [HMR] connected @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 60697ms] [LOG] SW registered: http://localhost:4001/ @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 61557ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 61803ms] [LOG] [Fast Refresh] done in 246ms @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 62314ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 62343ms] [LOG] [Fast Refresh] done in 28ms @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 62377ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 62381ms] [LOG] [Fast Refresh] done in 3ms @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 62990ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 63048ms] [LOG] [Fast Refresh] done in 58ms @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 63053ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 63137ms] [LOG] [Fast Refresh] done in 84ms @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 63235ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 63296ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 63376ms] [LOG] [Fast Refresh] done in 79ms @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 63466ms] [LOG] [Fast Refresh] done in 169ms @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 64317ms] [LOG] [Fast Refresh] done in 1020ms @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 64371ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 69456ms] [INFO] %cDownload the React DevTools for a better development experience: https://react.dev/link/react-devtools font-weight:bold @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 69540ms] [LOG] [HMR] connected @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 69561ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 70033ms] [LOG] SW registered: http://localhost:4001/ @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 71789ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 72203ms] [LOG] [Fast Refresh] done in 413ms @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 72517ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 72641ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 72659ms] [LOG] [Fast Refresh] done in 17ms @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 72740ms] [LOG] [Fast Refresh] done in 99ms @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 72759ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 73099ms] [LOG] [Fast Refresh] done in 339ms @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 73150ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 73164ms] [LOG] [Fast Refresh] done in 15ms @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 73809ms] [LOG] [Fast Refresh] done in 660ms @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 73830ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 74142ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 74185ms] [LOG] [Fast Refresh] done in 43ms @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 74485ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 74531ms] [LOG] [Fast Refresh] done in 47ms @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 80609ms] [INFO] %cDownload the React DevTools for a better development experience: https://react.dev/link/react-devtools font-weight:bold @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 80691ms] [LOG] [HMR] connected @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 81109ms] [LOG] SW registered: http://localhost:4001/ @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 81650ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 81792ms] [LOG] [Fast Refresh] done in 142ms @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 82212ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 82440ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 82464ms] [LOG] [Fast Refresh] done in 25ms @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 82593ms] [LOG] [Fast Refresh] done in 153ms @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 82722ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 82914ms] [LOG] [Fast Refresh] done in 192ms @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 82966ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 83002ms] [LOG] [Fast Refresh] done in 36ms @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 83737ms] [LOG] [Fast Refresh] done in 772ms @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 83805ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 84056ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 84095ms] [LOG] [Fast Refresh] done in 40ms @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 89254ms] [INFO] %cDownload the React DevTools for a better development experience: https://react.dev/link/react-devtools font-weight:bold @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 89308ms] [LOG] [HMR] connected @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 90069ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 90868ms] [LOG] SW registered: http://localhost:4001/ @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 91682ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 91889ms] [LOG] [Fast Refresh] done in 207ms @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 92070ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 92156ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 92163ms] [LOG] [Fast Refresh] done in 7ms @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 92216ms] [LOG] [Fast Refresh] done in 61ms @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 92240ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 92533ms] [LOG] [Fast Refresh] done in 293ms @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 92592ms] [LOG] [Fast Refresh] done in 351ms @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 92592ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 93176ms] [LOG] [Fast Refresh] done in 584ms @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 93206ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 98280ms] [INFO] %cDownload the React DevTools for a better development experience: https://react.dev/link/react-devtools font-weight:bold @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 98360ms] [LOG] [HMR] connected @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 98580ms] [LOG] SW registered: http://localhost:4001/ @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 99283ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 99767ms] [LOG] [Fast Refresh] done in 485ms @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 99834ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 99840ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 100047ms] [LOG] [Fast Refresh] done in 207ms @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 100460ms] [LOG] [Fast Refresh] done in 621ms @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 100570ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 100794ms] [LOG] [Fast Refresh] done in 224ms @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 100847ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 100897ms] [LOG] [Fast Refresh] done in 51ms @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 101802ms] [LOG] [Fast Refresh] done in 956ms @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 101852ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 102019ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 102076ms] [LOG] [Fast Refresh] done in 58ms @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 109913ms] [INFO] %cDownload the React DevTools for a better development experience: https://react.dev/link/react-devtools font-weight:bold @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 110003ms] [LOG] [HMR] connected @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 110112ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 112491ms] [ERROR] Can't perform a React state update on a component that hasn't mounted yet. This indicates that you have a side-effect in your render function that asynchronously tries to update the component. Move this work to useEffect instead. @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/userspace/app/errors/intercept-console-error.js:57 +[ 112503ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 112807ms] [LOG] [Fast Refresh] done in 303ms @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 112940ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 113001ms] [LOG] [Fast Refresh] done in 61ms @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 113201ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 113238ms] [LOG] [Fast Refresh] done in 38ms @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 113447ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 113495ms] [LOG] [Fast Refresh] done in 48ms @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 113660ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 113701ms] [LOG] [Fast Refresh] done in 41ms @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 113893ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 113936ms] [LOG] [Fast Refresh] done in 42ms @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 114127ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 114159ms] [LOG] [Fast Refresh] done in 31ms @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 114347ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 114395ms] [LOG] [Fast Refresh] done in 48ms @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 114539ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 114574ms] [LOG] [Fast Refresh] done in 36ms @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 118752ms] [INFO] %cDownload the React DevTools for a better development experience: https://react.dev/link/react-devtools font-weight:bold @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 119741ms] [LOG] [HMR] connected @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 120694ms] [LOG] SW registered: http://localhost:4001/ @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 122135ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 122349ms] [LOG] [Fast Refresh] done in 214ms @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 123566ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 123621ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 124398ms] [LOG] [Fast Refresh] done in 777ms @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 125622ms] [LOG] [Fast Refresh] done in 2002ms @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 125820ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 126395ms] [LOG] [Fast Refresh] done in 575ms @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 126464ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 126524ms] [LOG] [Fast Refresh] done in 59ms @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 128525ms] [LOG] [Fast Refresh] done in 2060ms @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 128579ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 130300ms] Invalid or unexpected token +[ 131666ms] [INFO] %cDownload the React DevTools for a better development experience: https://react.dev/link/react-devtools font-weight:bold @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 132786ms] [LOG] [HMR] connected @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 135697ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 136091ms] [LOG] [Fast Refresh] done in 395ms @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 137357ms] [ERROR] Can't perform a React state update on a component that hasn't mounted yet. This indicates that you have a side-effect in your render function that asynchronously tries to update the component. Move this work to useEffect instead. @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/userspace/app/errors/intercept-console-error.js:57 +[ 137386ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 137471ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 138117ms] [LOG] [Fast Refresh] done in 646ms @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 138526ms] [LOG] [Fast Refresh] done in 1054ms @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 138717ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 139411ms] [LOG] [Fast Refresh] done in 694ms @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 139485ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 139549ms] [LOG] [Fast Refresh] done in 64ms @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 141633ms] [LOG] [Fast Refresh] done in 2149ms @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 141651ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 142277ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 143529ms] [LOG] [Fast Refresh] done in 1253ms @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 145373ms] [INFO] %cDownload the React DevTools for a better development experience: https://react.dev/link/react-devtools font-weight:bold @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 145436ms] [LOG] [HMR] connected @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 145452ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 146259ms] [LOG] SW registered: http://localhost:4001/ @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 147037ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 147356ms] [LOG] [Fast Refresh] done in 320ms @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 148310ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 148493ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 149336ms] [LOG] [Fast Refresh] done in 843ms @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 150334ms] [LOG] [Fast Refresh] done in 1841ms @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 150589ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 151027ms] [LOG] [Fast Refresh] done in 438ms @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 151079ms] [LOG] [Fast Refresh] rebuilding @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 +[ 151122ms] [LOG] [Fast Refresh] done in 43ms @ webpack-internal:///(app-pages-browser)/./node_modules/next/dist/next-devtools/shared/forward-logs-shared.js:27 diff --git a/.playwright-mcp/page-2026-08-05T23-56-52-776Z.yml b/.playwright-mcp/page-2026-08-05T23-56-52-776Z.yml new file mode 100644 index 0000000..1aa0c1a --- /dev/null +++ b/.playwright-mcp/page-2026-08-05T23-56-52-776Z.yml @@ -0,0 +1,2 @@ +- generic [active] [ref=f5e1]: + - region "Notifications alt+T" \ No newline at end of file diff --git a/.playwright-mcp/page-2026-08-05T23-57-19-450Z.yml b/.playwright-mcp/page-2026-08-05T23-57-19-450Z.yml new file mode 100644 index 0000000..e7e1cd8 --- /dev/null +++ b/.playwright-mcp/page-2026-08-05T23-57-19-450Z.yml @@ -0,0 +1,175 @@ +- generic [active] [ref=f7e1]: + - generic [ref=f7e4]: + - complementary [ref=f7e5]: + - generic [ref=f7e6]: + - link "WFDASH WFDASH Westcott Fasteners" [ref=f7e7] [cursor=pointer]: + - /url: /dashboard + - img "WFDASH" [ref=f7e8] + - generic [ref=f7e9]: + - generic [ref=f7e10]: WFDASH + - generic [ref=f7e11]: Westcott Fasteners + - separator [ref=f7e12] + - navigation [ref=f7e15]: + - link "Dashboard" [ref=f7e16] [cursor=pointer]: + - /url: /dashboard + - separator [ref=f7e23] + - button "Management" [ref=f7e25] + - generic [ref=f7e28]: + - button "Quotes" [ref=f7e29] + - generic [ref=f7e32]: + - link "Quote List" [ref=f7e33] [cursor=pointer]: + - /url: /quotes + - link "Sprint" [ref=f7e40] [cursor=pointer]: + - /url: /sprint + - link "Pending Approvals" [ref=f7e44] [cursor=pointer]: + - /url: /quotes/approvals + - button "Orders" [ref=f7e50] + - button "Logistics" [ref=f7e54] + - button "Operations" [ref=f7e58] + - button "Stock" [ref=f7e62] + - button "Other" [ref=f7e66] + - separator [ref=f7e69] + - generic [ref=f7e70]: + - link "Settings" [ref=f7e71] [cursor=pointer]: + - /url: /settings + - button "Dark mode" [ref=f7e75] + - separator [ref=f7e78] + - generic [ref=f7e79]: + - generic [ref=f7e80]: D + - generic [ref=f7e82]: + - paragraph [ref=f7e83]: David Els + - paragraph [ref=f7e84]: david.els1@outlook.com + - button "Logout" [ref=f7e85] + - main [ref=f7e90]: + - generic [ref=f7e92]: + - generic [ref=f7e93]: + - button "Back to quotes" [ref=f7e94] + - generic [ref=f7e95]: + - heading "Q202607232" [level=1] [ref=f7e96] + - generic [ref=f7e97]: Cancelled + - button "More actions" [ref=f7e100] + - generic [ref=f7e103]: + - generic [ref=f7e104]: + - paragraph [ref=f7e105]: Customer + - paragraph [ref=f7e106]: Mark Wilkie + - paragraph [ref=f7e107]: Harmony - Gold Mining Company Limited + - generic [ref=f7e108]: + - paragraph [ref=f7e109]: Company + - paragraph [ref=f7e110]: — + - generic [ref=f7e111]: + - paragraph [ref=f7e112]: Created + - paragraph [ref=f7e113]: 27 Jul 2026 + - generic [ref=f7e114]: + - paragraph [ref=f7e115]: Letterhead + - paragraph [ref=f7e116]: CNL + - generic [ref=f7e117]: + - paragraph [ref=f7e118]: Claimed by + - generic [ref=f7e119]: + - generic [ref=f7e120]: DA + - paragraph [ref=f7e122]: David Els + - 'button "Original request Fwd: Mark Wilkie" [ref=f7e124] [cursor=pointer]': + - generic [ref=f7e125]: + - text: Original request + - generic [ref=f7e129]: "Fwd: Mark Wilkie" + - generic [ref=f7e132]: + - generic [ref=f7e133]: + - generic [ref=f7e134]: + - generic [ref=f7e135]: + - generic [ref=f7e136]: AI Insights + - button "Regenerate" [ref=f7e140] + - generic [ref=f7e142]: + - heading "AI Insights" [level=3] [ref=f7e146] + - paragraph [ref=f7e147]: "Quote Q202607232: 1 line item(s), 0 priced, 1 need pricing. Customer: Mark Wilkie." + - generic [ref=f7e149]: + - heading "Parent" [level=4] [ref=f7e150] + - generic [ref=f7e151]: + - term [ref=f7e152]: Suggestions + - definition [ref=f7e153]: "[{\"message\":\"Top supplier: 'NSS Fastners' — used 13x, last cost R2.87.\",\"ref_id\":null}]" + - term [ref=f7e154]: Summary + - definition [ref=f7e155]: "Quote Q202607232: 1 line item(s), 0 priced, 1 need pricing. Customer: Mark Wilkie." + - term [ref=f7e156]: Warnings + - definition [ref=f7e157]: "[{\"message\":\"All 1 line items need pricing.\",\"ref_id\":null,\"severity\":\"high\",\"type\":\"missing_pricing\"}]" + - generic [ref=f7e158]: + - generic [ref=f7e159]: + - generic [ref=f7e160]: Items (1) + - generic [ref=f7e164]: + - generic [ref=f7e165]: "Subtotal: R 7,96VAT: R 1,19" + - button "Rewrite with AI" [ref=f7e166] + - table [ref=f7e170]: + - rowgroup [ref=f7e171]: + - row [ref=f7e172]: + - columnheader "Description" [ref=f7e173] + - columnheader "Qty" [ref=f7e174] + - columnheader "Supplier" [ref=f7e175] + - columnheader "Cost" [ref=f7e176] + - columnheader "Selling" [ref=f7e177] + - columnheader [ref=f7e178] + - columnheader "Processed" [ref=f7e184] + - columnheader [ref=f7e185] + - rowgroup [ref=f7e186]: + - row [ref=f7e187]: + - cell "View item history M16 x 75 8.8 sets HDG complete with nuts and washers" [ref=f7e188]: + - generic [ref=f7e189]: + - button "View item history" [ref=f7e190] + - generic [ref=f7e193]: M16 x 75 8.8 sets HDG complete with nuts and washers + - cell "1" [ref=f7e194] + - cell "NSS Fastners" [ref=f7e195] + - cell "R 2,87" [ref=f7e196] + - cell "R 7,96" [ref=f7e197] + - cell "177.4%" [ref=f7e198] + - cell "Yes" [ref=f7e199] + - cell [ref=f7e201]: + - button "Update price" [ref=f7e202] + - generic [ref=f7e203]: + - generic [ref=f7e204]: + - generic [ref=f7e205]: Attachments + - generic [ref=f7e210]: + - tablist [ref=f7e211]: + - tab "Outbound 0" [selected] [ref=f7e212]: + - text: Outbound + - generic [ref=f7e213]: "0" + - tab "Internal 0" [ref=f7e214]: + - text: Internal + - generic [ref=f7e215]: "0" + - tabpanel "Outbound 0" [ref=f7e216]: + - generic [ref=f7e217]: + - button "Upload outbound attachment" [ref=f7e218] [cursor=pointer]: + - paragraph [ref=f7e221]: Drop a file here or click to upload + - paragraph [ref=f7e222]: PDFs, images, Word / Excel docs + - paragraph [ref=f7e223]: No outbound attachments yet. The generated quote PDF will be added automatically when you approve and email the quote. + - generic [ref=f7e224]: + - generic [ref=f7e225]: + - generic [ref=f7e226]: Linked Orders + - generic [ref=f7e231]: Already-linked, or suggested and waiting for accept on the order detail page. + - generic [ref=f7e232]: + - paragraph [ref=f7e233]: No orders linked yet. They show up automatically when an order's matcher picks this quote, or when one is created from this quote via the menu. + - list + - generic [ref=f7e234]: + - generic [ref=f7e235]: Activity + - generic [ref=f7e240]: + - tablist [ref=f7e241]: + - tab "Email Status" [selected] [ref=f7e242] + - tab "History" [ref=f7e243] + - tabpanel "Email Status" [ref=f7e244]: + - generic [ref=f7e245]: + - generic [ref=f7e246]: + - paragraph [ref=f7e247]: Delivered + - generic [ref=f7e248]: "No" + - generic [ref=f7e253]: + - paragraph [ref=f7e254]: Opened + - generic [ref=f7e255]: "No" + - generic [ref=f7e260]: + - paragraph [ref=f7e261]: Sender + - paragraph [ref=f7e262]: gary@wfsales.co.za + - generic [ref=f7e263]: + - paragraph [ref=f7e264]: Subject + - paragraph [ref=f7e265]: "Fwd: Mark Wilkie" + - region "Notifications alt+T" + - button "Open Next.js Dev Tools" [ref=f7e271] [cursor=pointer]: + - generic [ref=f7e274]: + - text: Compiling + - generic [ref=f7e275]: + - generic [ref=f7e276]: . + - generic [ref=f7e277]: . + - generic [ref=f7e278]: . + - alert [ref=f7e279] \ No newline at end of file diff --git a/.playwright-mcp/page-2026-08-05T23-57-44-389Z.yml b/.playwright-mcp/page-2026-08-05T23-57-44-389Z.yml new file mode 100644 index 0000000..c449d1d --- /dev/null +++ b/.playwright-mcp/page-2026-08-05T23-57-44-389Z.yml @@ -0,0 +1,2 @@ +- generic [active] [ref=f10e1]: + - region "Notifications alt+T" \ No newline at end of file diff --git a/.playwright-mcp/page-2026-08-05T23-58-12-084Z.yml b/.playwright-mcp/page-2026-08-05T23-58-12-084Z.yml new file mode 100644 index 0000000..af553ea --- /dev/null +++ b/.playwright-mcp/page-2026-08-05T23-58-12-084Z.yml @@ -0,0 +1,175 @@ +- generic [active] [ref=f12e1]: + - generic [ref=f12e5]: + - complementary [ref=f12e6]: + - generic [ref=f12e7]: + - link "WFDASH WFDASH Westcott Fasteners" [ref=f12e8] [cursor=pointer]: + - /url: /dashboard + - img "WFDASH" [ref=f12e9] + - generic [ref=f12e10]: + - generic [ref=f12e11]: WFDASH + - generic [ref=f12e12]: Westcott Fasteners + - separator [ref=f12e13] + - navigation [ref=f12e16]: + - link "Dashboard" [ref=f12e17] [cursor=pointer]: + - /url: /dashboard + - separator [ref=f12e24] + - button "Management" [ref=f12e26] + - generic [ref=f12e29]: + - button "Quotes" [ref=f12e30] + - generic [ref=f12e33]: + - link "Quote List" [ref=f12e34] [cursor=pointer]: + - /url: /quotes + - link "Sprint" [ref=f12e41] [cursor=pointer]: + - /url: /sprint + - link "Pending Approvals" [ref=f12e45] [cursor=pointer]: + - /url: /quotes/approvals + - button "Orders" [ref=f12e51] + - button "Logistics" [ref=f12e55] + - button "Operations" [ref=f12e59] + - button "Stock" [ref=f12e63] + - button "Other" [ref=f12e67] + - separator [ref=f12e70] + - generic [ref=f12e71]: + - link "Settings" [ref=f12e72] [cursor=pointer]: + - /url: /settings + - button "Dark mode" [ref=f12e76] + - separator [ref=f12e79] + - generic [ref=f12e80]: + - generic [ref=f12e81]: D + - generic [ref=f12e83]: + - paragraph [ref=f12e84]: David Els + - paragraph [ref=f12e85]: david.els1@outlook.com + - button "Logout" [ref=f12e86] + - main [ref=f12e91]: + - generic [ref=f12e93]: + - generic [ref=f12e94]: + - button "Back to quotes" [ref=f12e95] + - generic [ref=f12e96]: + - heading "Q202607232" [level=1] [ref=f12e97] + - generic [ref=f12e98]: Cancelled + - button "More actions" [ref=f12e101] + - generic [ref=f12e104]: + - generic [ref=f12e105]: + - paragraph [ref=f12e106]: Customer + - paragraph [ref=f12e107]: Mark Wilkie + - paragraph [ref=f12e108]: Harmony - Gold Mining Company Limited + - generic [ref=f12e109]: + - paragraph [ref=f12e110]: Company + - paragraph [ref=f12e111]: — + - generic [ref=f12e112]: + - paragraph [ref=f12e113]: Created + - paragraph [ref=f12e114]: 27 Jul 2026 + - generic [ref=f12e115]: + - paragraph [ref=f12e116]: Letterhead + - paragraph [ref=f12e117]: CNL + - generic [ref=f12e118]: + - paragraph [ref=f12e119]: Claimed by + - generic [ref=f12e120]: + - generic [ref=f12e121]: DA + - paragraph [ref=f12e123]: David Els + - 'button "Original request Fwd: Mark Wilkie" [ref=f12e125] [cursor=pointer]': + - generic [ref=f12e126]: + - text: Original request + - generic [ref=f12e130]: "Fwd: Mark Wilkie" + - generic [ref=f12e133]: + - generic [ref=f12e134]: + - generic [ref=f12e135]: + - generic [ref=f12e136]: + - generic [ref=f12e137]: AI Insights + - button "Regenerate" [ref=f12e141] + - generic [ref=f12e143]: + - heading "AI Insights" [level=3] [ref=f12e147] + - paragraph [ref=f12e148]: "Quote Q202607232: 1 line item(s), 0 priced, 1 need pricing. Customer: Mark Wilkie." + - generic [ref=f12e150]: + - heading "Parent" [level=4] [ref=f12e151] + - generic [ref=f12e152]: + - term [ref=f12e153]: Suggestions + - definition [ref=f12e154]: "[{\"message\":\"Top supplier: 'NSS Fastners' — used 13x, last cost R2.87.\",\"ref_id\":null}]" + - term [ref=f12e155]: Summary + - definition [ref=f12e156]: "Quote Q202607232: 1 line item(s), 0 priced, 1 need pricing. Customer: Mark Wilkie." + - term [ref=f12e157]: Warnings + - definition [ref=f12e158]: "[{\"message\":\"All 1 line items need pricing.\",\"ref_id\":null,\"severity\":\"high\",\"type\":\"missing_pricing\"}]" + - generic [ref=f12e159]: + - generic [ref=f12e160]: + - generic [ref=f12e161]: Items (1) + - generic [ref=f12e165]: + - generic [ref=f12e166]: "Subtotal: R 7,96VAT: R 1,19" + - button "Rewrite with AI" [ref=f12e167] + - table [ref=f12e171]: + - rowgroup [ref=f12e172]: + - row [ref=f12e173]: + - columnheader "Description" [ref=f12e174] + - columnheader "Qty" [ref=f12e175] + - columnheader "Supplier" [ref=f12e176] + - columnheader "Cost" [ref=f12e177] + - columnheader "Selling" [ref=f12e178] + - columnheader [ref=f12e179] + - columnheader "Processed" [ref=f12e185] + - columnheader [ref=f12e186] + - rowgroup [ref=f12e187]: + - row [ref=f12e188]: + - cell "View item history M16 x 75 8.8 sets HDG complete with nuts and washers" [ref=f12e189]: + - generic [ref=f12e190]: + - button "View item history" [ref=f12e191] + - generic [ref=f12e194]: M16 x 75 8.8 sets HDG complete with nuts and washers + - cell "1" [ref=f12e195] + - cell "NSS Fastners" [ref=f12e196] + - cell "R 2,87" [ref=f12e197] + - cell "R 7,96" [ref=f12e198] + - cell "177.4%" [ref=f12e199] + - cell "Yes" [ref=f12e200] + - cell [ref=f12e202]: + - button "Update price" [ref=f12e203] + - generic [ref=f12e204]: + - generic [ref=f12e205]: + - generic [ref=f12e206]: Attachments + - generic [ref=f12e211]: + - tablist [ref=f12e212]: + - tab "Outbound 0" [selected] [ref=f12e213]: + - text: Outbound + - generic [ref=f12e214]: "0" + - tab "Internal 0" [ref=f12e215]: + - text: Internal + - generic [ref=f12e216]: "0" + - tabpanel "Outbound 0" [ref=f12e217]: + - generic [ref=f12e218]: + - button "Upload outbound attachment" [ref=f12e219] [cursor=pointer]: + - paragraph [ref=f12e222]: Drop a file here or click to upload + - paragraph [ref=f12e223]: PDFs, images, Word / Excel docs + - paragraph [ref=f12e224]: No outbound attachments yet. The generated quote PDF will be added automatically when you approve and email the quote. + - generic [ref=f12e225]: + - generic [ref=f12e226]: + - generic [ref=f12e227]: Linked Orders + - generic [ref=f12e232]: Already-linked, or suggested and waiting for accept on the order detail page. + - generic [ref=f12e233]: + - paragraph [ref=f12e234]: No orders linked yet. They show up automatically when an order's matcher picks this quote, or when one is created from this quote via the menu. + - list + - generic [ref=f12e235]: + - generic [ref=f12e236]: Activity + - generic [ref=f12e241]: + - tablist [ref=f12e242]: + - tab "Email Status" [selected] [ref=f12e243] + - tab "History" [ref=f12e244] + - tabpanel "Email Status" [ref=f12e245]: + - generic [ref=f12e246]: + - generic [ref=f12e247]: + - paragraph [ref=f12e248]: Delivered + - generic [ref=f12e249]: "No" + - generic [ref=f12e254]: + - paragraph [ref=f12e255]: Opened + - generic [ref=f12e256]: "No" + - generic [ref=f12e261]: + - paragraph [ref=f12e262]: Sender + - paragraph [ref=f12e263]: gary@wfsales.co.za + - generic [ref=f12e264]: + - paragraph [ref=f12e265]: Subject + - paragraph [ref=f12e266]: "Fwd: Mark Wilkie" + - region "Notifications alt+T" + - button "Open Next.js Dev Tools" [ref=f12e272] [cursor=pointer]: + - generic [ref=f12e275]: + - text: Compiling + - generic [ref=f12e276]: + - generic [ref=f12e277]: . + - generic [ref=f12e278]: . + - generic [ref=f12e279]: . + - alert [ref=f12e280] \ No newline at end of file diff --git a/.playwright-mcp/page-2026-08-05T23-58-27-286Z.yml b/.playwright-mcp/page-2026-08-05T23-58-27-286Z.yml new file mode 100644 index 0000000..70b3975 --- /dev/null +++ b/.playwright-mcp/page-2026-08-05T23-58-27-286Z.yml @@ -0,0 +1,9 @@ +- generic [active] [ref=f13e1]: + - region "Notifications alt+T" + - button "Open Next.js Dev Tools" [ref=f13e13] [cursor=pointer]: + - generic [ref=f13e16]: + - text: Compiling + - generic [ref=f13e17]: + - generic [ref=f13e18]: . + - generic [ref=f13e19]: . + - generic [ref=f13e20]: . \ No newline at end of file diff --git a/src/app/(app)/quotes/[id]/page.layout.test.ts b/src/app/(app)/quotes/[id]/page.layout.test.ts new file mode 100644 index 0000000..7ebabf4 --- /dev/null +++ b/src/app/(app)/quotes/[id]/page.layout.test.ts @@ -0,0 +1,84 @@ +import { describe, it, expect } from "vitest"; +import { readFileSync } from "node:fs"; +import { resolve } from "node:path"; + +/** + * Layout contract regression test for the quote detail page. + * + * The page is a large Server Component that pulls from many PocketBase + * collections, calls multiple API endpoints, and has many modals — too + * heavy to mount in a unit test. Instead, this test guards the layout + * invariants that were negotiated with the operator during the + * redesign so a future edit can't silently regress them: + * + * 1. Customer info lives in a header strip (not a sidebar card). + * 2. The original email is a collapsible card that sits ABOVE the + * items table (the operator's main complaint — "email right at + * the bottom?"). + * 3. The right sidebar consolidates History + Email Status into a + * single tabbed "Activity" card so the column is shorter. + * 4. The original email section does NOT also appear at the bottom + * of the page (was duplicated). + * + * Each invariant is anchored to a stable `data-testid` or + * `aria-controls` marker that the page already emits — so the source + * test reads as a contract, not as a regex grep over prose comments. + */ + +const SOURCE = readFileSync( + resolve(__dirname, "page.tsx"), + "utf8", +); + +function linesContaining(marker: string): number[] { + const hits: number[] = []; + SOURCE.split("\n").forEach((line, i) => { + if (line.includes(marker)) hits.push(i + 1); + }); + return hits; +} + +describe("quote detail page — layout contract", () => { + it("exposes the original-email toggle via aria-controls", () => { + // The email card above items uses a button with aria-controls so the + // operator can show/hide the original message without scrolling + // away from the items table. + const hits = linesContaining('aria-controls="quote-email-body"'); + expect(hits.length).toBeGreaterThanOrEqual(1); + }); + + it("renders the email toggle BEFORE the items table marker", () => { + // The user complaint was "email right at the bottom". Lock the + // DOM ordering so the toggle card stays in the upper flow. + const emailToggle = linesContaining('aria-controls="quote-email-body"')[0]; + const itemsHeading = SOURCE.indexOf("Items ("); + expect(itemsHeading).toBeGreaterThan(-1); + // Convert char offset to a line number for the assertion message. + const itemsLine = SOURCE.slice(0, itemsHeading).split("\n").length; + expect(emailToggle).toBeLessThan(itemsLine); + }); + + it("consolidates History + Email Status into a tabbed Activity card", () => { + // The Activity card is what replaced the two standalone cards. + // Both triggers need a stable data-testid so the regression is + // locatable by future tests / e2e checks. + expect(linesContaining('data-testid="tab-email-status"').length).toBe(1); + expect(linesContaining('data-testid="tab-history"').length).toBe(1); + expect(SOURCE).toContain("Activity"); + }); + + it("does NOT render the original email a second time at the bottom of the page", () => { + // During the redesign we moved the original email to a collapsible + // card above the items and removed the old bottom section. Lock + // that removal: only ONE `quote-original-request` anchor is allowed. + const matches = SOURCE.match(/quote-original-request/g) ?? []; + expect(matches.length).toBe(0); + }); + + it("history rows render inside a data-testid=history-list anchor", () => { + // The Activity > History tab's