@futdevpro/dynamo-e2e 1.18.14 → 1.18.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/README.md +47 -1
  3. package/bin/dye2e.js +13 -0
  4. package/build/_modules/generators/_collections/cli-runner.util.d.ts.map +1 -1
  5. package/build/_modules/generators/_collections/cli-runner.util.js +17 -0
  6. package/build/_modules/generators/_collections/cli-runner.util.js.map +1 -1
  7. package/build/_modules/runtime/_collections/notification-detector-page-script.const.d.ts +30 -0
  8. package/build/_modules/runtime/_collections/notification-detector-page-script.const.d.ts.map +1 -0
  9. package/build/_modules/runtime/_collections/notification-detector-page-script.const.js +169 -0
  10. package/build/_modules/runtime/_collections/notification-detector-page-script.const.js.map +1 -0
  11. package/build/_modules/runtime/_collections/notification-detector.util.d.ts +47 -0
  12. package/build/_modules/runtime/_collections/notification-detector.util.d.ts.map +1 -0
  13. package/build/_modules/runtime/_collections/notification-detector.util.js +165 -0
  14. package/build/_modules/runtime/_collections/notification-detector.util.js.map +1 -0
  15. package/build/_modules/runtime/_collections/notification-sweep.util.d.ts +65 -0
  16. package/build/_modules/runtime/_collections/notification-sweep.util.d.ts.map +1 -0
  17. package/build/_modules/runtime/_collections/notification-sweep.util.js +326 -0
  18. package/build/_modules/runtime/_collections/notification-sweep.util.js.map +1 -0
  19. package/build/_modules/runtime/_models/notification-report.interface.d.ts +54 -0
  20. package/build/_modules/runtime/_models/notification-report.interface.d.ts.map +1 -0
  21. package/build/_modules/runtime/_models/notification-report.interface.js +3 -0
  22. package/build/_modules/runtime/_models/notification-report.interface.js.map +1 -0
  23. package/build/_modules/runtime/_models/notification-sweep.interface.d.ts +67 -0
  24. package/build/_modules/runtime/_models/notification-sweep.interface.d.ts.map +1 -0
  25. package/build/_modules/runtime/_models/notification-sweep.interface.js +3 -0
  26. package/build/_modules/runtime/_models/notification-sweep.interface.js.map +1 -0
  27. package/build/_modules/runtime/index.d.ts +5 -0
  28. package/build/_modules/runtime/index.d.ts.map +1 -1
  29. package/build/_modules/runtime/index.js +5 -0
  30. package/build/_modules/runtime/index.js.map +1 -1
  31. package/build/index.js +1 -1
  32. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -3,6 +3,34 @@
3
3
  Minden release a `dynamo-e2e-foundation` HYPERPLAN MP-N ütemezést követi.
4
4
  Verzióformátum: `MM.mm.p` (két-számjegyes major-minor, Dynamo-konvenció).
5
5
 
6
+ ## [01.18.16] — 2026-09-24 — Login-flow notification sweep
7
+
8
+ - Added `DyE2E_NotificationSweep_Util` to `/runtime` and the `dye2e notification-sweep` command (BFR-QA-002): on top of
9
+ the notification detector it opens the login page of every target, submits it with a WRONG password (the error
10
+ branch, no test account needed) and returns one matrix row per project — notifications · error/warning · banners ·
11
+ modal dialogs · raw-technical leaks · console errors. Targets: the QA workspace's `TEST-TARGETS.md` (only
12
+ `https://test.` rows) or JSON.
13
+ - Guards in code: the probe address must be on a reserved or a declared own domain (else it throws before any page is
14
+ opened); the form is submitted only on a test host (else loaded, not submitted, and the row says so).
15
+ - Modal dialogs are recorded (text + leak flag) before they are closed: on 3 of 7 TEST sites a "not the production
16
+ system" notice blocked the login, and on one the dialog was itself a JS error shown to the user.
17
+ - Detector fixes found by the live sweep: a banner's inner elements are no longer counted as more banners (one login
18
+ error was counted 3×), and `HTTP 401`-style status codes and user-visible JS errors (`… is not a function`,
19
+ `TypeError`, `this.x.`) now count as raw technical leaks.
20
+
21
+ ## [01.18.15] — 2026-09-24 — Live notification detector
22
+
23
+ - Added `DyE2E_NotificationDetector_Util` to `/runtime` (BFR-QA-001): `attach(context)` puts a `MutationObserver` into
24
+ every document BEFORE its scripts run and records each DyNX notification card / notifications area / mat-snackbar /
25
+ `[role=alert]` the moment it appears, classified error / warning / success / info — so an auto-dismissed toast is
26
+ not lost. `collect(page)` returns those plus the visible error banners (with a raw-technical-leak flag) and the
27
+ page's console errors/warnings and page errors; `summarize()` prints them.
28
+ - Captures go to Node through a Playwright binding, so they survive a full-page navigation (the redirect after
29
+ login). A capture is re-read 50 / 300 ms later to pick up content Angular renders after inserting the host element.
30
+ - The page-side code is plain JavaScript (`DYE2E_NOTIFICATION_DETECTOR_PAGE_SCRIPT`), so no `__name` shim is needed.
31
+ - 12 specs, 9 of them in a real Chromium (fixture pages served by `route`); the browser specs are reported as pending
32
+ with the reason when no Chromium can be started.
33
+
6
34
  ## [01.18.14] — 2026-09-23 — The form-level empty-submit case honours `fieldErrorSelector`
7
35
 
8
36
  - `DyE2E_FormLevelEmission_Util.emitSubmitEmpty` now uses the form's `fieldErrorSelector` (default unchanged:
package/README.md CHANGED
@@ -68,9 +68,55 @@ const specSource = DyE2E_FormSuite_Generator.emit({
68
68
 
69
69
  - `@futdevpro/dynamo-e2e/contracts` — POJO types
70
70
  - `@futdevpro/dynamo-e2e/generators` — Node-only emission engine
71
- - `@futdevpro/dynamo-e2e/runtime` — Playwright fixtures + page-objects (Wave-4)
71
+ - `@futdevpro/dynamo-e2e/runtime` — Playwright fixtures + page-objects (Wave-4) + the live notification detector
72
+ (`DyE2E_NotificationDetector_Util`, see below)
72
73
  - `@futdevpro/dynamo-e2e/presets` — pre-built suites + `DyE2E_getPlaywrightConfig` / `DyE2E_getGlobalSetup` playwright-config factory (fleet e2e-config SSOT)
73
74
  - `@futdevpro/dynamo-e2e/game` — capability-gated deterministic game seam, failure artifacts and bidirectional journey-catalog validation
74
75
  - `@futdevpro/dynamo-e2e/cwv` — Core Web Vitals (Wave-3)
75
76
 
77
+ ## Live notification detector (`/runtime`)
78
+
79
+ Records every user-visible notification — DyNX `dynamo-notification-card` / `dynamo-notifications-area`, mat-snackbar
80
+ (`red-` / `yellow-` / `blue-` / `green-snackbar`), `[role=alert]` — at the moment it APPEARS, so a toast that
81
+ auto-dismissed before the end of the test is still in the report. It also snapshots the visible error banners (with a
82
+ `rawTechnicalLeak` flag for texts like `Http failure response`, `/api/`, `[object Object]`) and collects the page's
83
+ `console` errors/warnings and uncaught `pageerror`s.
84
+
85
+ ```ts
86
+ import { DyE2E_NotificationDetector_Util } from '@futdevpro/dynamo-e2e/runtime';
87
+
88
+ await DyE2E_NotificationDetector_Util.attach(context); // before the first navigation
89
+ // ... the flow ...
90
+ const report = await DyE2E_NotificationDetector_Util.collect(page);
91
+ expect(report.notifications.filter((n) => n.type === 'error')).toEqual([]);
92
+ console.log(DyE2E_NotificationDetector_Util.summarize(report, 'login'));
93
+ ```
94
+
95
+ Captures survive a full-page navigation (they are reported to Node through a Playwright binding). The page-side code
96
+ is plain JavaScript, so no `__name` shim is needed under `tsx` / esbuild. `collect()` throws on a context without
97
+ `attach()` — an empty report would otherwise read as "no notifications".
98
+
99
+ ## Login-flow notification sweep (`/runtime` + CLI)
100
+
101
+ Built on the detector: opens the login page of many projects, submits it with a WRONG password (so the ERROR branch
102
+ is measured without a test account) and prints one matrix row per project — notifications · error/warning · banners ·
103
+ modal dialogs · raw-technical leaks · console errors. Framework-level defects show up only when many projects are
104
+ measured the same way.
105
+
106
+ ```bash
107
+ dye2e notification-sweep --targets TEST-TARGETS.md --json sweep.json # or a JSON [{ key, loginUrl | baseUrl }]
108
+ dye2e notification-sweep --targets targets.json --only a,b --fail-on-leak # exit 1 on a raw technical leak
109
+ ```
110
+ ```ts
111
+ const outcomes = await DyE2E_NotificationSweep_Util.sweep(browser, targets, { settleMs: 5000 });
112
+ console.log(DyE2E_NotificationSweep_Util.matrix(outcomes.map((o) => o.row)));
113
+ ```
114
+
115
+ Guards in code, not in docs: the probe address must be on a reserved domain (`example.com`, `*.test`, `*.invalid` …)
116
+ or on one you declare with `ownDomains` — anything else throws before a page is opened; the form is submitted only on
117
+ a test host (`test.*`, `*.test`, `localhost` …, or `allowSubmitHosts`) — anything else is loaded but NOT submitted,
118
+ and the row says so. `real: true` / `--real` uses `E2E_PERSISTENT_USER_EMAIL` / `_PASSWORD`; without them the row says
119
+ it fell back to the probe. Modal dialogs (a "not the production system" notice, an error dialog) are RECORDED —
120
+ text + leak flag — before they are closed; a non-modal cookie bar is left alone.
121
+
76
122
  Detailed game-preset contract: [`__documentations/game-preset.md`](__documentations/game-preset.md).
package/bin/dye2e.js CHANGED
@@ -403,6 +403,19 @@ function main() {
403
403
  process.exit(0);
404
404
  }
405
405
 
406
+ if (parsed.command === 'notification-sweep') {
407
+ // BFR-QA-002 — the logic is TypeScript (runtime module); needs @playwright/test in the consumer
408
+ const { DyE2E_NotificationSweep_Util } = require('../build/_modules/runtime/_collections/notification-sweep.util');
409
+ DyE2E_NotificationSweep_Util.runCli(parsed.flags).then(
410
+ (code) => process.exit(code),
411
+ (error) => {
412
+ process.stderr.write('[dye2e] notification-sweep failed: ' + (error && error.stack ? error.stack : error) + '\n');
413
+ process.exit(1);
414
+ },
415
+ );
416
+ return;
417
+ }
418
+
406
419
  if (parsed.command === 'bundle-summary') {
407
420
  const bundleP = parsed.flags.bundle;
408
421
  if (!bundleP) {
@@ -1 +1 @@
1
- {"version":3,"file":"cli-runner.util.d.ts","sourceRoot":"","sources":["../../../../src/_modules/generators/_collections/cli-runner.util.ts"],"names":[],"mappings":"AAOA;;;;;GAKG;AACH,qBAAa,oBAAoB;IAE/B,MAAM,CAAC,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE;IAsBpF,MAAM,CAAC,QAAQ,IAAI,MAAM;IAwFzB;;;OAGG;IACH,MAAM,CAAC,cAAc,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IA0D/C;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE;QAAE,UAAU,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC;QAAC,YAAY,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,MAAM,CAAA;KAAE,GAAG;QAC9H,YAAY,EAAE,OAAO,CAAC;QACtB,iBAAiB,EAAE,OAAO,CAAC;QAC3B,mBAAmB,EAAE,OAAO,CAAC;QAC7B,SAAS,EAAE,OAAO,CAAC;QACnB,aAAa,EAAE,OAAO,CAAC;QACvB,WAAW,EAAE,MAAM,EAAE,CAAC;KACvB;IA2CD,MAAM,CAAC,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM;IAI3C;;OAEG;IACH,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,MAAM;IAuB9D;;;OAGG;IACH,MAAM,CAAC,WAAW,CAChB,OAAO,EAAE,qBAAqB,GAAG,yBAAyB,GAAG,mBAAmB,EAChF,UAAU,EAAE,MAAM,GACjB,MAAM;CAaV"}
1
+ {"version":3,"file":"cli-runner.util.d.ts","sourceRoot":"","sources":["../../../../src/_modules/generators/_collections/cli-runner.util.ts"],"names":[],"mappings":"AAOA;;;;;GAKG;AACH,qBAAa,oBAAoB;IAE/B,MAAM,CAAC,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE;IAsBpF,MAAM,CAAC,QAAQ,IAAI,MAAM;IAyGzB;;;OAGG;IACH,MAAM,CAAC,cAAc,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IA0D/C;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE;QAAE,UAAU,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC;QAAC,YAAY,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,MAAM,CAAA;KAAE,GAAG;QAC9H,YAAY,EAAE,OAAO,CAAC;QACtB,iBAAiB,EAAE,OAAO,CAAC;QAC3B,mBAAmB,EAAE,OAAO,CAAC;QAC7B,SAAS,EAAE,OAAO,CAAC;QACnB,aAAa,EAAE,OAAO,CAAC;QACvB,WAAW,EAAE,MAAM,EAAE,CAAC;KACvB;IA2CD,MAAM,CAAC,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM;IAI3C;;OAEG;IACH,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,MAAM;IAuB9D;;;OAGG;IACH,MAAM,CAAC,WAAW,CAChB,OAAO,EAAE,qBAAqB,GAAG,yBAAyB,GAAG,mBAAmB,EAChF,UAAU,EAAE,MAAM,GACjB,MAAM;CAaV"}
@@ -61,6 +61,23 @@ Visual QA (/vqa) commands:
61
61
  generate-comparison-bundle Before/after capture sets -> comparison bundle
62
62
  bundle-summary Print an existing bundle's summary.md
63
63
 
64
+ QA commands:
65
+ notification-sweep Login pages -> wrong-password submit -> notification / banner / leak matrix
66
+
67
+ Flags (notification-sweep):
68
+ --targets <path> TEST-TARGETS.md (only https://test. rows) or JSON [{ key, loginUrl | baseUrl }] (required)
69
+ --only <a,b> Only these target keys
70
+ --login-paths <k=/p,..> Per-target login path (default /landing/login)
71
+ --no-submit Only load the login pages
72
+ --real Use E2E_PERSISTENT_USER_EMAIL / _PASSWORD (else the wrong-password probe)
73
+ --probe-email <addr> Probe address — reserved domain or one of --own-domains ONLY
74
+ --own-domains <d,..> Your own e-mail domains allowed for the probe address
75
+ --allow-hosts <h,..> Extra hosts the form may be submitted to (default: test.*, *.test, localhost)
76
+ --settle-ms / --after-submit-ms <ms> Waits (default 5000 / 9000)
77
+ --json <out> Write rows + full reports as JSON
78
+ --fail-on-leak Exit 1 if any page shows a raw technical leak
79
+ --executable-path <exe> Chromium to launch (or DYE2E_CHROMIUM_EXECUTABLE_PATH)
80
+
64
81
  Flags (preset):
65
82
  --name <preset> Print this preset as JSON (omit to list all)
66
83
 
@@ -1 +1 @@
1
- {"version":3,"file":"cli-runner.util.js","sourceRoot":"","sources":["../../../../src/_modules/generators/_collections/cli-runner.util.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli-runner.util.js","sourceRoot":"","sources":["../../../../src/_modules/generators/_collections/cli-runner.util.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Name of the Playwright binding the page script reports every capture to (BFR-QA-001). Node keeps the
3
+ * captures, so a notification survives a full-page navigation (e.g. the redirect after login) and the page close.
4
+ */
5
+ export declare const DYE2E_NOTIFICATION_BINDING_NAME: string;
6
+ /**
7
+ * Page-side notification detector — `addInitScript` input (BFR-QA-001).
8
+ *
9
+ * **PURE JavaScript** (not TypeScript), like `DYE2E_WEB_VITALS_PAGE_SCRIPT`: the browser runs it as-is, so no
10
+ * transpiler helper (`__name` of tsx/esbuild) can leak into the page — no shim is needed in any consumer setup.
11
+ *
12
+ * Observes the document from its very start (a `MutationObserver` on `document`, subtree) and records every DyNX
13
+ * notification card / notifications area / mat-snackbar / `[role=alert]` at the moment it is ADDED — so an
14
+ * auto-dismissed toast (DyNX error 14 s, others 7 s) is not lost. A capture is re-read 50 ms and 300 ms later to
15
+ * fill in what Angular renders after inserting the host element (title, message, colour class); the re-read keeps
16
+ * the capture id. Every capture (and re-read) goes to the Node binding, and to `window.__dye2e_notifications__`.
17
+ *
18
+ * Type classification (from `@futdevpro/ngx-dynamo` notifications): `bg-red-50` / `red-snackbar` / mat-icon `error`
19
+ * → error · `bg-orange-50` / `yellow-snackbar` / `warning` → warning · `bg-green-50` / `green-snackbar` /
20
+ * `check_circle` → success · `bg-blue-50` / `blue-snackbar` → info.
21
+ */
22
+ export declare const DYE2E_NOTIFICATION_DETECTOR_PAGE_SCRIPT: string;
23
+ /**
24
+ * Page-side expression: the visible error banners / inline error texts at this moment (not toasts — e.g. a login
25
+ * form showing a raw HTTP error). Only really visible elements, deduplicated by tag + text; an element INSIDE an
26
+ * already counted banner is part of it, not a new one (measured: a `role=alert` box with its `.error-text` and icon
27
+ * was counted three times). PURE JavaScript.
28
+ */
29
+ export declare const DYE2E_VISIBLE_ERRORS_PAGE_EXPRESSION: string;
30
+ //# sourceMappingURL=notification-detector-page-script.const.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notification-detector-page-script.const.d.ts","sourceRoot":"","sources":["../../../../src/_modules/runtime/_collections/notification-detector-page-script.const.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,eAAO,MAAM,+BAA+B,EAAE,MAAyC,CAAC;AAExF;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,uCAAuC,EAAE,MA6GrD,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,oCAAoC,EAAE,MA2BlD,CAAC"}
@@ -0,0 +1,169 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DYE2E_VISIBLE_ERRORS_PAGE_EXPRESSION = exports.DYE2E_NOTIFICATION_DETECTOR_PAGE_SCRIPT = exports.DYE2E_NOTIFICATION_BINDING_NAME = void 0;
4
+ /**
5
+ * Name of the Playwright binding the page script reports every capture to (BFR-QA-001). Node keeps the
6
+ * captures, so a notification survives a full-page navigation (e.g. the redirect after login) and the page close.
7
+ */
8
+ exports.DYE2E_NOTIFICATION_BINDING_NAME = '__dye2e_notification_binding__';
9
+ /**
10
+ * Page-side notification detector — `addInitScript` input (BFR-QA-001).
11
+ *
12
+ * **PURE JavaScript** (not TypeScript), like `DYE2E_WEB_VITALS_PAGE_SCRIPT`: the browser runs it as-is, so no
13
+ * transpiler helper (`__name` of tsx/esbuild) can leak into the page — no shim is needed in any consumer setup.
14
+ *
15
+ * Observes the document from its very start (a `MutationObserver` on `document`, subtree) and records every DyNX
16
+ * notification card / notifications area / mat-snackbar / `[role=alert]` at the moment it is ADDED — so an
17
+ * auto-dismissed toast (DyNX error 14 s, others 7 s) is not lost. A capture is re-read 50 ms and 300 ms later to
18
+ * fill in what Angular renders after inserting the host element (title, message, colour class); the re-read keeps
19
+ * the capture id. Every capture (and re-read) goes to the Node binding, and to `window.__dye2e_notifications__`.
20
+ *
21
+ * Type classification (from `@futdevpro/ngx-dynamo` notifications): `bg-red-50` / `red-snackbar` / mat-icon `error`
22
+ * → error · `bg-orange-50` / `yellow-snackbar` / `warning` → warning · `bg-green-50` / `green-snackbar` /
23
+ * `check_circle` → success · `bg-blue-50` / `blue-snackbar` → info.
24
+ */
25
+ exports.DYE2E_NOTIFICATION_DETECTOR_PAGE_SCRIPT = `
26
+ (function () {
27
+ var w = window;
28
+ if (w.__dye2e_notifications__) { return; }
29
+ var list = [];
30
+ w.__dye2e_notifications__ = list;
31
+ var bindingName = '${exports.DYE2E_NOTIFICATION_BINDING_NAME}';
32
+ var perf = w.performance;
33
+ var origin = String(Math.round(perf && perf.timeOrigin ? perf.timeOrigin : Date.now()));
34
+ var counter = 0;
35
+ var recentKeys = {};
36
+ var recorded = {};
37
+ var checks = [
38
+ ['dynx-card', 'dynamo-notification-card'],
39
+ ['notif-area', 'dynamo-notifications-area'],
40
+ ['snackbar', 'mat-snack-bar-container, .mat-mdc-snack-bar-container, simple-snack-bar, ' +
41
+ '.red-snackbar, .yellow-snackbar, .green-snackbar, .blue-snackbar'],
42
+ ['role-alert', '[role="alert"], [role="alertdialog"]']
43
+ ];
44
+
45
+ function nowMs() { return perf ? perf.now() : 0; }
46
+ function squash(text) { return (text || '').replace(/\\s+/g, ' ').trim(); }
47
+ function textOf(el, selector) {
48
+ try {
49
+ var node = el.querySelector(selector);
50
+ return node ? squash(node.textContent) : '';
51
+ } catch (e) { return ''; }
52
+ }
53
+ function classify(el) {
54
+ var html = el.outerHTML || '';
55
+ if (/bg-red-50|red-snackbar|>\\s*error\\s*</.test(html)) { return 'error'; }
56
+ if (/bg-orange-50|yellow-snackbar|>\\s*warning\\s*</.test(html)) { return 'warning'; }
57
+ if (/bg-green-50|green-snackbar|>\\s*check_circle\\s*</.test(html)) { return 'success'; }
58
+ if (/bg-blue-50|blue-snackbar/.test(html)) { return 'info'; }
59
+ return 'unknown';
60
+ }
61
+ function read(el) {
62
+ var structured = textOf(el, '.text-slate-700') || textOf(el, '.mat-mdc-snack-bar-label') ||
63
+ textOf(el, '[matsnackbarlabel]');
64
+ return {
65
+ type: classify(el),
66
+ structured: !!structured,
67
+ title: (structured || squash(el.textContent)).slice(0, 400),
68
+ message: textOf(el, '.text-slate-500').slice(0, 400),
69
+ html: squash(el.outerHTML).slice(0, 500)
70
+ };
71
+ }
72
+ function emit(entry) {
73
+ try {
74
+ if (typeof w[bindingName] === 'function') { w[bindingName](entry); }
75
+ } catch (e) { /* the page must never break because of the detector */ }
76
+ }
77
+ function enrich(entry, state, el) {
78
+ if (!el.isConnected) { return; }
79
+ var fresh = read(el);
80
+ var changed = false;
81
+ if (entry.type === 'unknown' && fresh.type !== 'unknown') { entry.type = fresh.type; changed = true; }
82
+ if (fresh.title && fresh.title !== entry.title && (!entry.title || !state.structured)) {
83
+ entry.title = fresh.title; state.structured = fresh.structured; changed = true;
84
+ }
85
+ if (!entry.message && fresh.message) { entry.message = fresh.message; changed = true; }
86
+ if (changed) { entry.html = fresh.html; emit(entry); }
87
+ }
88
+ function record(kind, el) {
89
+ var seen = recorded[kind] || (recorded[kind] = new WeakSet());
90
+ if (seen.has(el)) { return; }
91
+ seen.add(el);
92
+ var data = read(el);
93
+ var t = nowMs();
94
+ var key = kind + '|' + data.type + '|' + data.title;
95
+ if (data.title && recentKeys[key] !== undefined && t - recentKeys[key] < 1500) { return; }
96
+ recentKeys[key] = t;
97
+ counter += 1;
98
+ var entry = {
99
+ id: origin + '-' + counter,
100
+ kind: kind,
101
+ type: data.type,
102
+ title: data.title,
103
+ message: data.message,
104
+ url: location.href,
105
+ at: Date.now(),
106
+ sinceDocumentStartMs: Math.round(t),
107
+ html: data.html
108
+ };
109
+ var state = { structured: data.structured };
110
+ list.push(entry);
111
+ emit(entry);
112
+ setTimeout(function () { enrich(entry, state, el); }, 50);
113
+ setTimeout(function () { enrich(entry, state, el); }, 300);
114
+ }
115
+ function scan(node) {
116
+ if (!node || node.nodeType !== 1) { return; }
117
+ for (var i = 0; i < checks.length; i++) {
118
+ try {
119
+ if (node.matches(checks[i][1])) { record(checks[i][0], node); }
120
+ var found = node.querySelectorAll(checks[i][1]);
121
+ for (var j = 0; j < found.length; j++) { record(checks[i][0], found[j]); }
122
+ } catch (e) { /* one bad selector must not stop the other checks */ }
123
+ }
124
+ }
125
+
126
+ new MutationObserver(function (mutations) {
127
+ for (var i = 0; i < mutations.length; i++) {
128
+ var added = mutations[i].addedNodes;
129
+ for (var j = 0; j < added.length; j++) { scan(added[j]); }
130
+ }
131
+ }).observe(document, { childList: true, subtree: true });
132
+ scan(document.documentElement);
133
+ })();
134
+ `;
135
+ /**
136
+ * Page-side expression: the visible error banners / inline error texts at this moment (not toasts — e.g. a login
137
+ * form showing a raw HTTP error). Only really visible elements, deduplicated by tag + text; an element INSIDE an
138
+ * already counted banner is part of it, not a new one (measured: a `role=alert` box with its `.error-text` and icon
139
+ * was counted three times). PURE JavaScript.
140
+ */
141
+ exports.DYE2E_VISIBLE_ERRORS_PAGE_EXPRESSION = `
142
+ (function () {
143
+ var selectors = ['.error-text', '[class*="error-text"]', 'mat-error', '.mat-mdc-form-field-error',
144
+ '.text-red-200', '.text-red-500', '.text-red-600', '.text-red-700', '[role="alert"]'];
145
+ var out = [];
146
+ var seen = {};
147
+ var picked = [];
148
+ var found = document.querySelectorAll(selectors.join(','));
149
+ for (var i = 0; i < found.length; i++) {
150
+ var el = found[i];
151
+ var text = (el.textContent || '').replace(/\\s+/g, ' ').trim();
152
+ if (!text || text.length > 300 || !(el instanceof HTMLElement)) { continue; }
153
+ var rect = el.getBoundingClientRect();
154
+ var style = getComputedStyle(el);
155
+ var visible = el.offsetParent !== null && rect.width > 0 && rect.height > 0 &&
156
+ style.visibility !== 'hidden' && style.display !== 'none';
157
+ var key = el.tagName + '|' + text;
158
+ if (!visible || seen[key]) { continue; }
159
+ var inside = false;
160
+ for (var j = 0; j < picked.length; j++) { if (picked[j].contains(el)) { inside = true; break; } }
161
+ if (inside) { continue; }
162
+ seen[key] = true;
163
+ picked.push(el);
164
+ out.push({ tag: el.tagName.toLowerCase(), cls: String(el.className || '').slice(0, 120), text: text.slice(0, 260) });
165
+ }
166
+ return out;
167
+ })()
168
+ `;
169
+ //# sourceMappingURL=notification-detector-page-script.const.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notification-detector-page-script.const.js","sourceRoot":"","sources":["../../../../src/_modules/runtime/_collections/notification-detector-page-script.const.ts"],"names":[],"mappings":";;;AAAA;;;GAGG;AACU,QAAA,+BAA+B,GAAW,gCAAgC,CAAC;AAExF;;;;;;;;;;;;;;;GAeG;AACU,QAAA,uCAAuC,GAAW;;;;;;uBAMxC,uCAA+B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuGrD,CAAC;AAEF;;;;;GAKG;AACU,QAAA,oCAAoC,GAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2B3D,CAAC"}
@@ -0,0 +1,47 @@
1
+ import { BrowserContext, Page } from '@playwright/test';
2
+ import { DyE2E_NotificationReport_Interface, DyE2E_VisibleError_Interface } from '../_models/notification-report.interface';
3
+ /**
4
+ * Live notification detector (BFR-QA-001) — records every user-visible notification / toast / snackbar /
5
+ * `[role=alert]` at the moment it APPEARS, so an auto-dismissed toast is still in the report; plus the visible
6
+ * error banners (with a raw-technical-leak flag) and the page's `console` error/warning + `pageerror`.
7
+ *
8
+ * Why: console mining does not see the framework's user notifications (they are DOM, without a console log), and
9
+ * a final screenshot loses the ones that disappeared. A QA run missed a login error toast exactly this way.
10
+ *
11
+ * ```ts
12
+ * await DyE2E_NotificationDetector_Util.attach(context); // BEFORE the first navigation
13
+ * const page: Page = await context.newPage();
14
+ * await page.goto('/login'); // ... the flow ...
15
+ * const report: DyE2E_NotificationReport_Interface = await DyE2E_NotificationDetector_Util.collect(page);
16
+ * expect(report.notifications.filter((n) => n.type === 'error')).toEqual([]);
17
+ * console.log(DyE2E_NotificationDetector_Util.summarize(report, 'login'));
18
+ * ```
19
+ */
20
+ export declare class DyE2E_NotificationDetector_Util {
21
+ /** Texts that expose internals to the user instead of a human message. */
22
+ static readonly rawTechnicalLeakPattern: RegExp;
23
+ private static readonly attachedContexts;
24
+ private static readonly pageStates;
25
+ /**
26
+ * Attaches the detector to a context: every document of every page (and frame) gets the observer BEFORE its
27
+ * own scripts run; pages that already exist are instrumented immediately (their current DOM is scanned).
28
+ * Calling it again for the same context is a no-op.
29
+ */
30
+ static attach(context: BrowserContext): Promise<void>;
31
+ /**
32
+ * The report of one page: every notification captured so far (across its navigations, in order of appearance),
33
+ * the error banners visible NOW, and the console errors/warnings + page errors.
34
+ * @throws if the page's context has no detector attached — an empty report would be a false "all clear".
35
+ */
36
+ static collect(page: Page): Promise<DyE2E_NotificationReport_Interface>;
37
+ /** The error banners / inline error texts visible on the page right now, with the raw-technical-leak flag. */
38
+ static scanVisibleErrors(page: Page): Promise<DyE2E_VisibleError_Interface[]>;
39
+ /** `true` when the text shows the user raw technical detail (HTTP error text, API path, `[object Object]` …). */
40
+ static isRawTechnicalLeak(text: string): boolean;
41
+ /** Short human-readable summary (CLI output / QA round log). */
42
+ static summarize(report: DyE2E_NotificationReport_Interface, label?: string): string;
43
+ /** Console + pageerror listeners, once per page. */
44
+ private static watchPage;
45
+ private static stateOf;
46
+ }
47
+ //# sourceMappingURL=notification-detector.util.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notification-detector.util.d.ts","sourceRoot":"","sources":["../../../../src/_modules/runtime/_collections/notification-detector.util.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAkB,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAExE,OAAO,EAGL,kCAAkC,EAGlC,4BAA4B,EAC7B,MAAM,0CAA0C,CAAC;AAqBlD;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,+BAA+B;IAE1C,0EAA0E;IAC1E,MAAM,CAAC,QAAQ,CAAC,uBAAuB,EAAE,MAAM,CAM7C;IAEF,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAA0D;IAClG,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,CAC2B;IAE7D;;;;OAIG;WACU,MAAM,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IA4B3D;;;;OAIG;WACU,OAAO,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,kCAAkC,CAAC;IAiC7E,8GAA8G;WACjG,iBAAiB,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,4BAA4B,EAAE,CAAC;IAenF,iHAAiH;IACjH,MAAM,CAAC,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAIhD,gEAAgE;IAChE,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,kCAAkC,EAAE,KAAK,GAAE,MAAW,GAAG,MAAM;IA+BxF,oDAAoD;IACpD,OAAO,CAAC,MAAM,CAAC,SAAS;IAgBxB,OAAO,CAAC,MAAM,CAAC,OAAO;CAQvB"}
@@ -0,0 +1,165 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DyE2E_NotificationDetector_Util = void 0;
4
+ const notification_detector_page_script_const_1 = require("./notification-detector-page-script.const");
5
+ /**
6
+ * Live notification detector (BFR-QA-001) — records every user-visible notification / toast / snackbar /
7
+ * `[role=alert]` at the moment it APPEARS, so an auto-dismissed toast is still in the report; plus the visible
8
+ * error banners (with a raw-technical-leak flag) and the page's `console` error/warning + `pageerror`.
9
+ *
10
+ * Why: console mining does not see the framework's user notifications (they are DOM, without a console log), and
11
+ * a final screenshot loses the ones that disappeared. A QA run missed a login error toast exactly this way.
12
+ *
13
+ * ```ts
14
+ * await DyE2E_NotificationDetector_Util.attach(context); // BEFORE the first navigation
15
+ * const page: Page = await context.newPage();
16
+ * await page.goto('/login'); // ... the flow ...
17
+ * const report: DyE2E_NotificationReport_Interface = await DyE2E_NotificationDetector_Util.collect(page);
18
+ * expect(report.notifications.filter((n) => n.type === 'error')).toEqual([]);
19
+ * console.log(DyE2E_NotificationDetector_Util.summarize(report, 'login'));
20
+ * ```
21
+ */
22
+ class DyE2E_NotificationDetector_Util {
23
+ /** Texts that expose internals to the user instead of a human message. */
24
+ static rawTechnicalLeakPattern = new RegExp('(Http failure response|Unauthorized|Internal Server|undefined|\\[object Object\\]|/api/|-api/|' +
25
+ 'status of \\d{3}|\\bHTTP \\d{3}\\b|ERR_|Cannot (GET|POST|read)|' +
26
+ // JS errors shown to the user (measured on a TEST site: "…: this.rendering_CS.noServer… is not a function")
27
+ 'is not a function|is not defined|TypeError|\\bthis\\.[A-Za-z_$][\\w$]*\\.)', 'i');
28
+ static attachedContexts = new WeakSet();
29
+ static pageStates = new WeakMap();
30
+ /**
31
+ * Attaches the detector to a context: every document of every page (and frame) gets the observer BEFORE its
32
+ * own scripts run; pages that already exist are instrumented immediately (their current DOM is scanned).
33
+ * Calling it again for the same context is a no-op.
34
+ */
35
+ static async attach(context) {
36
+ if (this.attachedContexts.has(context)) {
37
+ return;
38
+ }
39
+ this.attachedContexts.add(context);
40
+ // the page reports every capture here — the Node-side store survives navigations
41
+ await context.exposeBinding(notification_detector_page_script_const_1.DYE2E_NOTIFICATION_BINDING_NAME, (source, entry) => {
42
+ if (source.page && entry && typeof entry.id === 'string') {
43
+ this.stateOf(source.page).notifications.set(entry.id, entry);
44
+ }
45
+ });
46
+ await context.addInitScript({ content: notification_detector_page_script_const_1.DYE2E_NOTIFICATION_DETECTOR_PAGE_SCRIPT });
47
+ context.on('page', (page) => this.watchPage(page));
48
+ for (const page of context.pages()) {
49
+ this.watchPage(page);
50
+ try {
51
+ await page.evaluate(notification_detector_page_script_const_1.DYE2E_NOTIFICATION_DETECTOR_PAGE_SCRIPT);
52
+ }
53
+ catch (error) {
54
+ // the page is navigating / closed — the init script reaches its next document anyway
55
+ }
56
+ }
57
+ }
58
+ /**
59
+ * The report of one page: every notification captured so far (across its navigations, in order of appearance),
60
+ * the error banners visible NOW, and the console errors/warnings + page errors.
61
+ * @throws if the page's context has no detector attached — an empty report would be a false "all clear".
62
+ */
63
+ static async collect(page) {
64
+ if (!this.attachedContexts.has(page.context())) {
65
+ throw new Error('DyE2E_NotificationDetector_Util.collect: no detector is attached to this page\'s context — call ' +
66
+ '`await DyE2E_NotificationDetector_Util.attach(context)` before the first navigation. Without it the ' +
67
+ 'report would be empty and read as "no notifications".');
68
+ }
69
+ const state = this.stateOf(page);
70
+ // merge the page's own list too (by id): binding calls may still be in flight
71
+ let inPage = [];
72
+ try {
73
+ inPage = await page.evaluate('window.__dye2e_notifications__ || []');
74
+ }
75
+ catch (error) {
76
+ // the page closed / is navigating — the Node-side store is still complete
77
+ }
78
+ const merged = new Map(state.notifications);
79
+ for (const entry of inPage) {
80
+ merged.set(entry.id, entry);
81
+ }
82
+ return {
83
+ notifications: [...merged.values()].sort((a, b) => a.at - b.at),
84
+ visibleErrors: await this.scanVisibleErrors(page),
85
+ consoleErrors: [...state.consoleErrors],
86
+ pageErrors: [...state.pageErrors],
87
+ };
88
+ }
89
+ /** The error banners / inline error texts visible on the page right now, with the raw-technical-leak flag. */
90
+ static async scanVisibleErrors(page) {
91
+ let raw = [];
92
+ try {
93
+ raw = await page.evaluate(notification_detector_page_script_const_1.DYE2E_VISIBLE_ERRORS_PAGE_EXPRESSION);
94
+ }
95
+ catch (error) {
96
+ return [];
97
+ }
98
+ return raw.map((item) => ({
99
+ tag: item.tag,
100
+ cls: item.cls,
101
+ text: item.text,
102
+ rawTechnicalLeak: this.isRawTechnicalLeak(item.text),
103
+ }));
104
+ }
105
+ /** `true` when the text shows the user raw technical detail (HTTP error text, API path, `[object Object]` …). */
106
+ static isRawTechnicalLeak(text) {
107
+ return this.rawTechnicalLeakPattern.test(text || '');
108
+ }
109
+ /** Short human-readable summary (CLI output / QA round log). */
110
+ static summarize(report, label = '') {
111
+ const byType = { error: 0, warning: 0, success: 0, info: 0, unknown: 0 };
112
+ report.notifications.forEach((n) => {
113
+ byType[n.type] = byType[n.type] + 1;
114
+ });
115
+ const lines = [];
116
+ lines.push('=== NOTIFICATION DETECTOR' + (label ? ' — ' + label : '') + ' ===');
117
+ lines.push('Notifications: ' + report.notifications.length + ' (error=' + byType.error + ' warning=' +
118
+ byType.warning + ' success=' + byType.success + ' info=' + byType.info + ' unknown=' + byType.unknown + ')');
119
+ report.notifications.forEach((n, i) => {
120
+ lines.push(' [' + (i + 1) + '] ' + n.type.toUpperCase() + ' <' + n.kind + '> "' + n.title.slice(0, 160) + '"' +
121
+ (n.message ? ' — ' + n.message.slice(0, 120) : ''));
122
+ });
123
+ const leaks = report.visibleErrors.filter((e) => e.rawTechnicalLeak).length;
124
+ lines.push('Visible error banners: ' + report.visibleErrors.length + ' (raw-technical-leak: ' + leaks + ')');
125
+ report.visibleErrors.forEach((e, i) => {
126
+ lines.push(' [E' + (i + 1) + '] ' + (e.rawTechnicalLeak ? 'LEAK ' : '') + '<' + e.tag + '.' +
127
+ (e.cls.split(' ')[0] || '') + '> "' + e.text.slice(0, 200) + '"');
128
+ });
129
+ lines.push('Console errors/warnings: ' + report.consoleErrors.length + ' | pageerrors: ' +
130
+ report.pageErrors.length);
131
+ report.consoleErrors.slice(0, 12).forEach((c) => {
132
+ lines.push(' console.' + c.type + ': ' + c.text.slice(0, 180));
133
+ });
134
+ report.pageErrors.slice(0, 8).forEach((p) => {
135
+ lines.push(' pageerror: ' + p.text.slice(0, 180));
136
+ });
137
+ return lines.join('\n');
138
+ }
139
+ /** Console + pageerror listeners, once per page. */
140
+ static watchPage(page) {
141
+ if (this.pageStates.has(page)) {
142
+ return;
143
+ }
144
+ const state = this.stateOf(page);
145
+ page.on('console', (message) => {
146
+ const type = message.type();
147
+ if (type === 'error' || type === 'warning') {
148
+ state.consoleErrors.push({ type: type, text: (message.text() || '').slice(0, 500), url: page.url() });
149
+ }
150
+ });
151
+ page.on('pageerror', (error) => {
152
+ state.pageErrors.push({ text: String(error?.message || error).slice(0, 500), url: page.url() });
153
+ });
154
+ }
155
+ static stateOf(page) {
156
+ let state = this.pageStates.get(page);
157
+ if (!state) {
158
+ state = { notifications: new Map(), consoleErrors: [], pageErrors: [] };
159
+ this.pageStates.set(page, state);
160
+ }
161
+ return state;
162
+ }
163
+ }
164
+ exports.DyE2E_NotificationDetector_Util = DyE2E_NotificationDetector_Util;
165
+ //# sourceMappingURL=notification-detector.util.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notification-detector.util.js","sourceRoot":"","sources":["../../../../src/_modules/runtime/_collections/notification-detector.util.ts"],"names":[],"mappings":"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"}