@futdevpro/dynamo-e2e 1.18.26 → 1.18.29

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 (88) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/README.md +10 -0
  3. package/build/_modules/contracts/_collections/test-case-sets/password-field-test-cases.const.d.ts +4 -0
  4. package/build/_modules/contracts/_collections/test-case-sets/password-field-test-cases.const.d.ts.map +1 -1
  5. package/build/_modules/contracts/_collections/test-case-sets/password-field-test-cases.const.js +39 -3
  6. package/build/_modules/contracts/_collections/test-case-sets/password-field-test-cases.const.js.map +1 -1
  7. package/build/_modules/contracts/_enums/field-test-case-type.enum.d.ts +5 -0
  8. package/build/_modules/contracts/_enums/field-test-case-type.enum.d.ts.map +1 -1
  9. package/build/_modules/contracts/_enums/field-test-case-type.enum.js +5 -0
  10. package/build/_modules/contracts/_enums/field-test-case-type.enum.js.map +1 -1
  11. package/build/_modules/contracts/_models/interfaces/form-test-suite-settings.interface.d.ts +9 -1
  12. package/build/_modules/contracts/_models/interfaces/form-test-suite-settings.interface.d.ts.map +1 -1
  13. package/build/_modules/generators/_collections/field-emission.util.d.ts +11 -0
  14. package/build/_modules/generators/_collections/field-emission.util.d.ts.map +1 -1
  15. package/build/_modules/generators/_collections/field-emission.util.js +43 -6
  16. package/build/_modules/generators/_collections/field-emission.util.js.map +1 -1
  17. package/build/_modules/generators/_collections/form-level-emission.util.d.ts.map +1 -1
  18. package/build/_modules/generators/_collections/form-level-emission.util.js +5 -6
  19. package/build/_modules/generators/_collections/form-level-emission.util.js.map +1 -1
  20. package/build/_modules/generators/_collections/json-schema.util.d.ts.map +1 -1
  21. package/build/_modules/generators/_collections/json-schema.util.js +2 -0
  22. package/build/_modules/generators/_collections/json-schema.util.js.map +1 -1
  23. package/build/_modules/generators/_collections/test-case-filter.util.d.ts +6 -0
  24. package/build/_modules/generators/_collections/test-case-filter.util.d.ts.map +1 -1
  25. package/build/_modules/generators/_collections/test-case-filter.util.js +36 -0
  26. package/build/_modules/generators/_collections/test-case-filter.util.js.map +1 -1
  27. package/build/_modules/generators/_models/form-settings-shape.interface.d.ts +13 -0
  28. package/build/_modules/generators/_models/form-settings-shape.interface.d.ts.map +1 -1
  29. package/build/_modules/generators/form-suite.generator.d.ts.map +1 -1
  30. package/build/_modules/generators/form-suite.generator.js +4 -1
  31. package/build/_modules/generators/form-suite.generator.js.map +1 -1
  32. package/build/_modules/ui-check/_collections/constants/ui-check-page-scripts.const.d.ts +6 -0
  33. package/build/_modules/ui-check/_collections/constants/ui-check-page-scripts.const.d.ts.map +1 -0
  34. package/build/_modules/ui-check/_collections/constants/ui-check-page-scripts.const.js +208 -0
  35. package/build/_modules/ui-check/_collections/constants/ui-check-page-scripts.const.js.map +1 -0
  36. package/build/_modules/ui-check/_collections/detectors/dead-control.detector.d.ts +29 -0
  37. package/build/_modules/ui-check/_collections/detectors/dead-control.detector.d.ts.map +1 -0
  38. package/build/_modules/ui-check/_collections/detectors/dead-control.detector.js +101 -0
  39. package/build/_modules/ui-check/_collections/detectors/dead-control.detector.js.map +1 -0
  40. package/build/_modules/ui-check/_collections/detectors/nested-scroll.detector.d.ts +25 -0
  41. package/build/_modules/ui-check/_collections/detectors/nested-scroll.detector.d.ts.map +1 -0
  42. package/build/_modules/ui-check/_collections/detectors/nested-scroll.detector.js +47 -0
  43. package/build/_modules/ui-check/_collections/detectors/nested-scroll.detector.js.map +1 -0
  44. package/build/_modules/ui-check/_collections/detectors/non-toggling-control.detector.d.ts +33 -0
  45. package/build/_modules/ui-check/_collections/detectors/non-toggling-control.detector.d.ts.map +1 -0
  46. package/build/_modules/ui-check/_collections/detectors/non-toggling-control.detector.js +119 -0
  47. package/build/_modules/ui-check/_collections/detectors/non-toggling-control.detector.js.map +1 -0
  48. package/build/_modules/ui-check/_collections/ui-check-default-detectors.const.d.ts +20 -0
  49. package/build/_modules/ui-check/_collections/ui-check-default-detectors.const.d.ts.map +1 -0
  50. package/build/_modules/ui-check/_collections/ui-check-default-detectors.const.js +30 -0
  51. package/build/_modules/ui-check/_collections/ui-check-default-detectors.const.js.map +1 -0
  52. package/build/_modules/ui-check/_collections/ui-check-guard.util.d.ts +60 -0
  53. package/build/_modules/ui-check/_collections/ui-check-guard.util.d.ts.map +1 -0
  54. package/build/_modules/ui-check/_collections/ui-check-guard.util.js +144 -0
  55. package/build/_modules/ui-check/_collections/ui-check-guard.util.js.map +1 -0
  56. package/build/_modules/ui-check/_collections/ui-check-page.util.d.ts +61 -0
  57. package/build/_modules/ui-check/_collections/ui-check-page.util.d.ts.map +1 -0
  58. package/build/_modules/ui-check/_collections/ui-check-page.util.js +152 -0
  59. package/build/_modules/ui-check/_collections/ui-check-page.util.js.map +1 -0
  60. package/build/_modules/ui-check/_collections/ui-check-runner.util.d.ts +41 -0
  61. package/build/_modules/ui-check/_collections/ui-check-runner.util.d.ts.map +1 -0
  62. package/build/_modules/ui-check/_collections/ui-check-runner.util.js +128 -0
  63. package/build/_modules/ui-check/_collections/ui-check-runner.util.js.map +1 -0
  64. package/build/_modules/ui-check/_models/ui-check-context.interface.d.ts +39 -0
  65. package/build/_modules/ui-check/_models/ui-check-context.interface.d.ts.map +1 -0
  66. package/build/_modules/ui-check/_models/ui-check-context.interface.js +3 -0
  67. package/build/_modules/ui-check/_models/ui-check-context.interface.js.map +1 -0
  68. package/build/_modules/ui-check/_models/ui-check-detector.interface.d.ts +32 -0
  69. package/build/_modules/ui-check/_models/ui-check-detector.interface.d.ts.map +1 -0
  70. package/build/_modules/ui-check/_models/ui-check-detector.interface.js +3 -0
  71. package/build/_modules/ui-check/_models/ui-check-detector.interface.js.map +1 -0
  72. package/build/_modules/ui-check/_models/ui-check-finding.interface.d.ts +30 -0
  73. package/build/_modules/ui-check/_models/ui-check-finding.interface.d.ts.map +1 -0
  74. package/build/_modules/ui-check/_models/ui-check-finding.interface.js +3 -0
  75. package/build/_modules/ui-check/_models/ui-check-finding.interface.js.map +1 -0
  76. package/build/_modules/ui-check/_models/ui-check-report.interface.d.ts +38 -0
  77. package/build/_modules/ui-check/_models/ui-check-report.interface.d.ts.map +1 -0
  78. package/build/_modules/ui-check/_models/ui-check-report.interface.js +3 -0
  79. package/build/_modules/ui-check/_models/ui-check-report.interface.js.map +1 -0
  80. package/build/_modules/ui-check/index.d.ts +27 -0
  81. package/build/_modules/ui-check/index.d.ts.map +1 -0
  82. package/build/_modules/ui-check/index.js +43 -0
  83. package/build/_modules/ui-check/index.js.map +1 -0
  84. package/build/index.d.ts +1 -0
  85. package/build/index.d.ts.map +1 -1
  86. package/build/index.js +2 -1
  87. package/build/index.js.map +1 -1
  88. package/package.json +10 -1
@@ -0,0 +1,119 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DyE2E_NonTogglingControl_Detector = void 0;
4
+ const ui_check_page_scripts_const_1 = require("../constants/ui-check-page-scripts.const");
5
+ const ui_check_guard_util_1 = require("../ui-check-guard.util");
6
+ const ui_check_page_util_1 = require("../ui-check-page.util");
7
+ /**
8
+ * A checkbox / switch that does not toggle like one: on a fresh page it is pressed, a dialog it opened is closed the
9
+ * user's way (its own accept / close button, else Escape), then it is pressed AGAIN. Each press must flip the state;
10
+ * a press that fails (something covers the control) or does not flip it is a finding.
11
+ *
12
+ * Origin: owner 2026-10-20 (`IN-2026-10-20-HONNIE-10`, `-11`) — the Terms checkbox of the registration could be
13
+ * pressed only after navigating away and back; a generated e2e case had found it on 2026-09-23 and was switched off
14
+ * instead (BFR-FLEET-013).
15
+ */
16
+ class DyE2E_NonTogglingControl_Detector {
17
+ id = 'non-toggling-control';
18
+ errorClass = 'toggle-does-not-toggle';
19
+ description = 'A checkbox / switch whose press (first or second) does not flip its state.';
20
+ origin = {
21
+ code: 'BFR-FLEET-013', foundBy: 'owner (HONNIE-10 / -11)', date: '2026-10-20',
22
+ };
23
+ interactive = true;
24
+ notes = [];
25
+ /** Buttons that close a dialog the user's way. */
26
+ static closeButtonPattern = /^(accept|i accept|agree|i agree|ok|okay|close|done|got it|understood|elfogad|elfogadom|rendben|bezár|értem)/i;
27
+ async run(page, context) {
28
+ const guard = await ui_check_guard_util_1.DyE2E_UICheckGuard_Util.installNetworkGuard(page, context);
29
+ const findings = [];
30
+ this.notes = [];
31
+ try {
32
+ await ui_check_page_util_1.DyE2E_UICheckPage_Util.reload(page, context);
33
+ const listed = await ui_check_page_util_1.DyE2E_UICheckPage_Util.listControls(page, context, 'toggle');
34
+ for (const control of [...listed.controls, ...listed.denied.filter((c) => !c.destructive)]) {
35
+ await ui_check_page_util_1.DyE2E_UICheckPage_Util.reload(page, context);
36
+ const steps = [];
37
+ for (const press of [1, 2]) {
38
+ const step = await this.pressOnce(page, control.selector, press, context);
39
+ steps.push(step);
40
+ if (context.trace) {
41
+ this.notes.push(`trace "${control.text || control.ariaLabel}" press ${press}: ${step.before} → ` +
42
+ `${step.after}${step.dialog ? ` (${step.dialog})` : ''}${step.pressError ? `, error ${step.pressError}` : ''}`);
43
+ }
44
+ if (step.pressError || step.after === step.before) {
45
+ findings.push(this.finding(control, steps, context));
46
+ break;
47
+ }
48
+ }
49
+ }
50
+ }
51
+ finally {
52
+ await guard.remove();
53
+ }
54
+ return findings;
55
+ }
56
+ /** One press: state before, the press, the dialog it opened (closed), state after. */
57
+ async pressOnce(page, selector, press, context) {
58
+ const before = await ui_check_page_util_1.DyE2E_UICheckPage_Util.evaluate(page, ui_check_page_scripts_const_1.DyE2E_UICheckPageScripts_Const['toggleState'], selector);
59
+ const dialogsBefore = (await this.dialogs(page)).length;
60
+ let pressError = null;
61
+ let dialog = null;
62
+ try {
63
+ await page.locator(selector).first().click({ timeout: 3_000 });
64
+ }
65
+ catch (error) {
66
+ pressError = ui_check_page_util_1.DyE2E_UICheckPage_Util.describePressError(error);
67
+ }
68
+ await page.waitForTimeout(context.settleMs ?? ui_check_page_util_1.DyE2E_UICheckPage_Util.defaultSettleMs);
69
+ const dialogs = await this.dialogs(page);
70
+ if (!pressError && dialogs.length > dialogsBefore) {
71
+ dialog = await this.closeDialog(page, dialogs[dialogs.length - 1]);
72
+ await page.waitForTimeout(context.settleMs ?? ui_check_page_util_1.DyE2E_UICheckPage_Util.defaultSettleMs);
73
+ }
74
+ const after = await ui_check_page_util_1.DyE2E_UICheckPage_Util.evaluate(page, ui_check_page_scripts_const_1.DyE2E_UICheckPageScripts_Const['toggleState'], selector);
75
+ return { press: press, before: before, after: after, pressError: pressError, dialog: dialog };
76
+ }
77
+ /** The visible modal dialogs (their button texts). */
78
+ async dialogs(page) {
79
+ return ui_check_page_util_1.DyE2E_UICheckPage_Util.evaluate(page, ui_check_page_scripts_const_1.DyE2E_UICheckPageScripts_Const['openDialogs']);
80
+ }
81
+ /** Closes the newest dialog with its own accept / close button, else with Escape; returns how. */
82
+ async closeDialog(page, buttons) {
83
+ const label = buttons.find((text) => DyE2E_NonTogglingControl_Detector.closeButtonPattern.test(text));
84
+ if (label) {
85
+ const button = page.locator('[role="dialog"], [role="alertdialog"], mat-dialog-container, ' +
86
+ '.mat-mdc-dialog-container, dialog[open]').last().locator('button, [role="button"], a', { hasText: label })
87
+ .first();
88
+ try {
89
+ await button.click({ timeout: 3_000 });
90
+ return `opened a dialog, closed with its "${label}" button`;
91
+ }
92
+ catch (error) {
93
+ // the dialog's own button cannot be pressed (covered) ⇒ fall back to Escape
94
+ }
95
+ }
96
+ await page.keyboard.press('Escape');
97
+ return `opened a dialog (buttons: ${buttons.join(', ') || 'none'}), closed with Escape`;
98
+ }
99
+ /** The finding of a control whose last step failed. */
100
+ finding(control, steps, context) {
101
+ const last = steps[steps.length - 1];
102
+ const label = control.text || control.ariaLabel || control.testId || control.selector;
103
+ const history = steps.slice(0, -1).map((s) => `press ${s.press}: ${s.before} → ${s.after}${s.dialog ? ` (${s.dialog})` : ''}`).join('; ');
104
+ const what = last.pressError
105
+ ? `press ${last.press} failed: ${last.pressError}`
106
+ : `press ${last.press} left it "${last.after}"${last.dialog ? ` (${last.dialog})` : ''}`;
107
+ return {
108
+ detector: this.id,
109
+ errorClass: this.errorClass,
110
+ url: context.url,
111
+ target: ui_check_page_util_1.DyE2E_UICheckPage_Util.toTarget(control),
112
+ measured: `"${label}": ${history ? history + '; ' : ''}${what}.`,
113
+ expected: 'Every press flips the state (on ⇄ off), also right after a dialog it opened was closed.',
114
+ details: { steps: steps },
115
+ };
116
+ }
117
+ }
118
+ exports.DyE2E_NonTogglingControl_Detector = DyE2E_NonTogglingControl_Detector;
119
+ //# sourceMappingURL=non-toggling-control.detector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"non-toggling-control.detector.js","sourceRoot":"","sources":["../../../../../src/_modules/ui-check/_collections/detectors/non-toggling-control.detector.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import { DyE2E_UICheckDetector_Interface } from '../_models/ui-check-detector.interface';
2
+ /**
3
+ * The DEFAULT, growing UI detector list (BFR-FLEET-012) — every page, form and feature gets all of them.
4
+ *
5
+ * Each entry was written for a defect a HUMAN identified, and joined the list only after it caught that real defect AND
6
+ * stayed silent on the fixed version (the proofs: `__documentations/UI-CHECK-DETECTORS.md`). New human-found defect
7
+ * class ⇒ new detector; a project may add its own, and switch one off only with a coded, dated waiver.
8
+ */
9
+ export declare const DyE2E_UICheckDefaultDetectors_Const: readonly DyE2E_UICheckDetector_Interface[];
10
+ /**
11
+ * CANDIDATES — written, tested on minimal fixtures, but their real-defect proof is not complete yet, so they are NOT in
12
+ * the default list. Opt in:
13
+ * `detectors: [ ...DyE2E_UICheckDefaultDetectors_Const, ...DyE2E_UICheckCandidateDetectors_Const ]`.
14
+ * - `nested-scroll`: fires on the real defect (`BL-QA-FDPUI-003`, MP TEST 2026-10-20), the "silent after the fix" half
15
+ * waits for the fix;
16
+ * - `non-toggling-control`: the owner's checkbox defect could not be reproduced on 2026-10-20 (MP + Adventor TEST,
17
+ * desktop + mobile, five close paths) — the exact place is needed from the human who saw it.
18
+ */
19
+ export declare const DyE2E_UICheckCandidateDetectors_Const: readonly DyE2E_UICheckDetector_Interface[];
20
+ //# sourceMappingURL=ui-check-default-detectors.const.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui-check-default-detectors.const.d.ts","sourceRoot":"","sources":["../../../../src/_modules/ui-check/_collections/ui-check-default-detectors.const.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,+BAA+B,EAAE,MAAM,wCAAwC,CAAC;AAKzF;;;;;;GAMG;AACH,eAAO,MAAM,mCAAmC,EAAE,SAAS,+BAA+B,EAEzF,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,qCAAqC,EAAE,SAAS,+BAA+B,EAG3F,CAAC"}
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DyE2E_UICheckCandidateDetectors_Const = exports.DyE2E_UICheckDefaultDetectors_Const = void 0;
4
+ const dead_control_detector_1 = require("./detectors/dead-control.detector");
5
+ const nested_scroll_detector_1 = require("./detectors/nested-scroll.detector");
6
+ const non_toggling_control_detector_1 = require("./detectors/non-toggling-control.detector");
7
+ /**
8
+ * The DEFAULT, growing UI detector list (BFR-FLEET-012) — every page, form and feature gets all of them.
9
+ *
10
+ * Each entry was written for a defect a HUMAN identified, and joined the list only after it caught that real defect AND
11
+ * stayed silent on the fixed version (the proofs: `__documentations/UI-CHECK-DETECTORS.md`). New human-found defect
12
+ * class ⇒ new detector; a project may add its own, and switch one off only with a coded, dated waiver.
13
+ */
14
+ exports.DyE2E_UICheckDefaultDetectors_Const = [
15
+ new dead_control_detector_1.DyE2E_DeadControl_Detector(),
16
+ ];
17
+ /**
18
+ * CANDIDATES — written, tested on minimal fixtures, but their real-defect proof is not complete yet, so they are NOT in
19
+ * the default list. Opt in:
20
+ * `detectors: [ ...DyE2E_UICheckDefaultDetectors_Const, ...DyE2E_UICheckCandidateDetectors_Const ]`.
21
+ * - `nested-scroll`: fires on the real defect (`BL-QA-FDPUI-003`, MP TEST 2026-10-20), the "silent after the fix" half
22
+ * waits for the fix;
23
+ * - `non-toggling-control`: the owner's checkbox defect could not be reproduced on 2026-10-20 (MP + Adventor TEST,
24
+ * desktop + mobile, five close paths) — the exact place is needed from the human who saw it.
25
+ */
26
+ exports.DyE2E_UICheckCandidateDetectors_Const = [
27
+ new nested_scroll_detector_1.DyE2E_NestedScroll_Detector(),
28
+ new non_toggling_control_detector_1.DyE2E_NonTogglingControl_Detector(),
29
+ ];
30
+ //# sourceMappingURL=ui-check-default-detectors.const.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui-check-default-detectors.const.js","sourceRoot":"","sources":["../../../../src/_modules/ui-check/_collections/ui-check-default-detectors.const.ts"],"names":[],"mappings":";;;AACA,6EAA+E;AAC/E,+EAAiF;AACjF,6FAA8F;AAE9F;;;;;;GAMG;AACU,QAAA,mCAAmC,GAA+C;IAC7F,IAAI,kDAA0B,EAAE;CACjC,CAAC;AAEF;;;;;;;;GAQG;AACU,QAAA,qCAAqC,GAA+C;IAC/F,IAAI,oDAA2B,EAAE;IACjC,IAAI,iEAAiC,EAAE;CACxC,CAAC"}
@@ -0,0 +1,60 @@
1
+ import { Page, Request } from '@playwright/test';
2
+ import { DyE2E_UICheckContext_Interface } from '../_models/ui-check-context.interface';
3
+ /** What the network guard saw while it was installed. */
4
+ export interface DyE2E_UICheckNetworkLog_Interface {
5
+ /** Requests started (document, xhr, fetch, websocket, eventsource) — an effect of a press. */
6
+ started: number;
7
+ /** Requests the guard aborted — they never reached a server. */
8
+ aborted: string[];
9
+ }
10
+ /** A removable network guard. */
11
+ export interface DyE2E_UICheckNetworkGuard_Interface {
12
+ log: DyE2E_UICheckNetworkLog_Interface;
13
+ /** Zeroes the log (before the next press). */
14
+ reset(): void;
15
+ remove(): Promise<void>;
16
+ }
17
+ /**
18
+ * The safety layer of the interactive UI detectors (BFR-FLEET-012) — the rules are CODE, not advice:
19
+ * 1. a control is pressed only on a test host, anonymously or with a throwaway account;
20
+ * 2. a control whose text / label / test id names payment, e-mail sending, deletion, logout, publishing … is NEVER
21
+ * pressed (`defaultDenyPattern`, plus `data-e2e-destructive`);
22
+ * 3. while a control is pressed, every mutating request (non-GET) is ABORTED — unless it matches `mutationAllow`, and
23
+ * even then a payment / e-mail URL (`hardDenyUrlPattern`) or a non-reserved e-mail address in the body aborts it;
24
+ * every navigation away from the page's host is aborted too;
25
+ * 4. every WebSocket opened while the guard is on is MOCKED: its messages never reach a server (a sent message still
26
+ * counts as an effect) — a socket action (e.g. starting a paid run) cannot slip past the HTTP guard.
27
+ * So a press can never pay, never send a mail to a real address, and never change real data.
28
+ */
29
+ export declare class DyE2E_UICheckGuard_Util {
30
+ /** Controls never pressed: payment, e-mail sending, deletion, logout, publishing (EN + HU). */
31
+ static readonly defaultDenyPattern: RegExp;
32
+ /** Request URLs never let through, even when `mutationAllow` matches: payment and e-mail sending. */
33
+ static readonly hardDenyUrlPattern: RegExp;
34
+ /** Methods that do not change server state. */
35
+ static readonly safeMethods: string[];
36
+ /** Resource types that count as the effect of a press. */
37
+ static readonly effectResourceTypes: string[];
38
+ /** E-mail addresses in a text (request body). */
39
+ private static readonly emailPattern;
40
+ /**
41
+ * Throws (with the reason) unless an interactive detector may run on `context`: a test host and an anonymous or
42
+ * throwaway account. Called by the runner BEFORE the page is touched.
43
+ */
44
+ static assertInteractiveAllowed(context: DyE2E_UICheckContext_Interface, detectorId: string): void;
45
+ /** Whether a control (its text, label, title, test id) is on the deny list. */
46
+ static isDenied(label: string, context: DyE2E_UICheckContext_Interface, destructive: boolean): boolean;
47
+ /** Whether a request may reach the server during a press (see the class doc). */
48
+ static isRequestAllowed(request: Request, context: DyE2E_UICheckContext_Interface): boolean;
49
+ /** Whether every e-mail address in `body` is reserved / undeliverable or on an own domain. */
50
+ static bodyEmailsAllowed(body: string, ownDomains: string[]): boolean;
51
+ /**
52
+ * Installs the network guard on `page` (HTTP route + request counter + WebSocket mock); `remove()` takes them off.
53
+ * Playwright has no `unrouteWebSocket`: after `remove()` NEW sockets connect to the server again, sockets opened
54
+ * while the guard was on stay mocked until the next load.
55
+ */
56
+ static installNetworkGuard(page: Page, context: DyE2E_UICheckContext_Interface): Promise<DyE2E_UICheckNetworkGuard_Interface>;
57
+ /** Whether two URLs share a host. */
58
+ private static sameHost;
59
+ }
60
+ //# sourceMappingURL=ui-check-guard.util.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui-check-guard.util.d.ts","sourceRoot":"","sources":["../../../../src/_modules/ui-check/_collections/ui-check-guard.util.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,OAAO,EAAyB,MAAM,kBAAkB,CAAC;AAGxE,OAAO,EAAE,8BAA8B,EAAE,MAAM,uCAAuC,CAAC;AAEvF,yDAAyD;AACzD,MAAM,WAAW,iCAAiC;IAChD,8FAA8F;IAC9F,OAAO,EAAE,MAAM,CAAC;IAChB,gEAAgE;IAChE,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,iCAAiC;AACjC,MAAM,WAAW,mCAAmC;IAClD,GAAG,EAAE,iCAAiC,CAAC;IACvC,8CAA8C;IAC9C,KAAK,IAAI,IAAI,CAAC;IACd,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACzB;AAED;;;;;;;;;;;GAWG;AACH,qBAAa,uBAAuB;IAElC,+FAA+F;IAC/F,MAAM,CAAC,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAKxB;IAElB,qGAAqG;IACrG,MAAM,CAAC,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAGxB;IAElB,+CAA+C;IAC/C,MAAM,CAAC,QAAQ,CAAC,WAAW,EAAE,MAAM,EAAE,CAAgC;IAErE,0DAA0D;IAC1D,MAAM,CAAC,QAAQ,CAAC,mBAAmB,EAAE,MAAM,EAAE,CAA8D;IAE3G,iDAAiD;IACjD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAqD;IAEzF;;;OAGG;IACH,MAAM,CAAC,wBAAwB,CAAC,OAAO,EAAE,8BAA8B,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI;IAWlG,+EAA+E;IAC/E,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,8BAA8B,EAAE,WAAW,EAAE,OAAO,GAAG,OAAO;IAStG,iFAAiF;IACjF,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,8BAA8B,GAAG,OAAO;IAmB3F,8FAA8F;IAC9F,MAAM,CAAC,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,OAAO;IAMrE;;;;OAIG;WACU,mBAAmB,CAC9B,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,8BAA8B,GACtC,OAAO,CAAC,mCAAmC,CAAC;IAqD/C,qCAAqC;IACrC,OAAO,CAAC,MAAM,CAAC,QAAQ;CAOxB"}
@@ -0,0 +1,144 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DyE2E_UICheckGuard_Util = void 0;
4
+ const notification_sweep_util_1 = require("../../runtime/_collections/notification-sweep.util");
5
+ /**
6
+ * The safety layer of the interactive UI detectors (BFR-FLEET-012) — the rules are CODE, not advice:
7
+ * 1. a control is pressed only on a test host, anonymously or with a throwaway account;
8
+ * 2. a control whose text / label / test id names payment, e-mail sending, deletion, logout, publishing … is NEVER
9
+ * pressed (`defaultDenyPattern`, plus `data-e2e-destructive`);
10
+ * 3. while a control is pressed, every mutating request (non-GET) is ABORTED — unless it matches `mutationAllow`, and
11
+ * even then a payment / e-mail URL (`hardDenyUrlPattern`) or a non-reserved e-mail address in the body aborts it;
12
+ * every navigation away from the page's host is aborted too;
13
+ * 4. every WebSocket opened while the guard is on is MOCKED: its messages never reach a server (a sent message still
14
+ * counts as an effect) — a socket action (e.g. starting a paid run) cannot slip past the HTTP guard.
15
+ * So a press can never pay, never send a mail to a real address, and never change real data.
16
+ */
17
+ class DyE2E_UICheckGuard_Util {
18
+ /** Controls never pressed: payment, e-mail sending, deletion, logout, publishing (EN + HU). */
19
+ static defaultDenyPattern = new RegExp([
20
+ '\\blog\\s*-?\\s*out\\b', '\\bsign\\s*-?\\s*out\\b', 'kijelentkez', '\\bdelete\\b', 'törl[éő]', '\\bremove\\b',
21
+ 'eltávolít', '\\bpay', 'fizet', '\\bbuy\\b', 'vásárl', '\\bcheckout\\b', '\\bpurchase', '\\border\\b', 'megrendel',
22
+ '\\bsubscri', 'előfizet', '\\bpublish', 'közzétesz', 'közzététel', '\\bsend\\b', 'küld', '\\binvite', 'meghív',
23
+ 'e-?mail', '\\bdonat', 'adomány', '\\bdeactivat', '\\btransfer\\b', '\\bwithdraw', '\\bcredit', 'kredit',
24
+ ].join('|'), 'i');
25
+ /** Request URLs never let through, even when `mutationAllow` matches: payment and e-mail sending. */
26
+ static hardDenyUrlPattern = new RegExp([
27
+ 'pay', 'checkout', 'purchase', 'order', 'invoice', 'billing', 'simplepay', 'barion', 'stripe', 'paypal', 'credit',
28
+ 'mail', 'invite', 'newsletter', 'notify', 'send',
29
+ ].join('|'), 'i');
30
+ /** Methods that do not change server state. */
31
+ static safeMethods = ['GET', 'HEAD', 'OPTIONS'];
32
+ /** Resource types that count as the effect of a press. */
33
+ static effectResourceTypes = ['document', 'xhr', 'fetch', 'websocket', 'eventsource'];
34
+ /** E-mail addresses in a text (request body). */
35
+ static emailPattern = /[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}/gi;
36
+ /**
37
+ * Throws (with the reason) unless an interactive detector may run on `context`: a test host and an anonymous or
38
+ * throwaway account. Called by the runner BEFORE the page is touched.
39
+ */
40
+ static assertInteractiveAllowed(context, detectorId) {
41
+ if (!notification_sweep_util_1.DyE2E_NotificationSweep_Util.isSubmitAllowed(context.url, context.allowHosts ?? [])) {
42
+ throw new Error(`UI-check "${detectorId}" refused: "${context.url}" is not a test host (test.*, *.test, ` +
43
+ 'localhost, 127.0.0.1 or allowHosts) — interactive detectors press controls, so they never run elsewhere.');
44
+ }
45
+ if (context.accountKind !== 'anonymous' && context.accountKind !== 'throwaway') {
46
+ throw new Error(`UI-check "${detectorId}" refused: accountKind must be "anonymous" or "throwaway" ` +
47
+ `(got "${String(context.accountKind)}") — a persistent or real account is never used for pressing controls.`);
48
+ }
49
+ }
50
+ /** Whether a control (its text, label, title, test id) is on the deny list. */
51
+ static isDenied(label, context, destructive) {
52
+ if (destructive) {
53
+ return true;
54
+ }
55
+ const patterns = [DyE2E_UICheckGuard_Util.defaultDenyPattern, ...(context.extraDenyPatterns ?? [])];
56
+ return patterns.some((pattern) => pattern.test(label));
57
+ }
58
+ /** Whether a request may reach the server during a press (see the class doc). */
59
+ static isRequestAllowed(request, context) {
60
+ const url = request.url();
61
+ if (request.isNavigationRequest() && !DyE2E_UICheckGuard_Util.sameHost(url, context.url)) {
62
+ return false;
63
+ }
64
+ if (DyE2E_UICheckGuard_Util.safeMethods.includes(request.method().toUpperCase())) {
65
+ return !(request.isNavigationRequest() && DyE2E_UICheckGuard_Util.hardDenyUrlPattern.test(new URL(url).pathname));
66
+ }
67
+ if (!(context.mutationAllow ?? []).some((pattern) => pattern.test(url))) {
68
+ return false;
69
+ }
70
+ if (DyE2E_UICheckGuard_Util.hardDenyUrlPattern.test(url)) {
71
+ return false;
72
+ }
73
+ return DyE2E_UICheckGuard_Util.bodyEmailsAllowed(request.postData() ?? '', context.ownEmailDomains ?? []);
74
+ }
75
+ /** Whether every e-mail address in `body` is reserved / undeliverable or on an own domain. */
76
+ static bodyEmailsAllowed(body, ownDomains) {
77
+ const emails = body.match(DyE2E_UICheckGuard_Util.emailPattern) ?? [];
78
+ return emails.every((email) => notification_sweep_util_1.DyE2E_NotificationSweep_Util.isAllowedProbeEmail(email, ownDomains));
79
+ }
80
+ /**
81
+ * Installs the network guard on `page` (HTTP route + request counter + WebSocket mock); `remove()` takes them off.
82
+ * Playwright has no `unrouteWebSocket`: after `remove()` NEW sockets connect to the server again, sockets opened
83
+ * while the guard was on stay mocked until the next load.
84
+ */
85
+ static async installNetworkGuard(page, context) {
86
+ const log = { started: 0, aborted: [] };
87
+ let active = true;
88
+ const socketHandler = (socket) => {
89
+ if (!active) {
90
+ socket.connectToServer();
91
+ return;
92
+ }
93
+ socket.onMessage(() => {
94
+ log.started++;
95
+ log.aborted.push(`WS message to ${socket.url()} (mocked, never forwarded)`);
96
+ });
97
+ };
98
+ if (typeof page.routeWebSocket !== 'function') {
99
+ throw new Error('UI-check guard refused: this Playwright has no page.routeWebSocket (needs >= 1.48) — without ' +
100
+ 'it a WebSocket action of a pressed control could reach the server.');
101
+ }
102
+ await page.routeWebSocket(/.*/, socketHandler);
103
+ const onRequest = (request) => {
104
+ if (DyE2E_UICheckGuard_Util.effectResourceTypes.includes(request.resourceType())) {
105
+ log.started++;
106
+ }
107
+ };
108
+ const handler = async (route) => {
109
+ const request = route.request();
110
+ if (DyE2E_UICheckGuard_Util.isRequestAllowed(request, context)) {
111
+ await route.fallback();
112
+ }
113
+ else {
114
+ log.aborted.push(`${request.method()} ${request.url()}`);
115
+ await route.abort('blockedbyclient');
116
+ }
117
+ };
118
+ page.on('request', onRequest);
119
+ await page.route('**/*', handler);
120
+ return {
121
+ log: log,
122
+ reset: () => {
123
+ log.started = 0;
124
+ log.aborted = [];
125
+ },
126
+ remove: async () => {
127
+ active = false;
128
+ page.off('request', onRequest);
129
+ await page.unroute('**/*', handler);
130
+ },
131
+ };
132
+ }
133
+ /** Whether two URLs share a host. */
134
+ static sameHost(a, b) {
135
+ try {
136
+ return new URL(a).host === new URL(b).host;
137
+ }
138
+ catch (error) {
139
+ return false;
140
+ }
141
+ }
142
+ }
143
+ exports.DyE2E_UICheckGuard_Util = DyE2E_UICheckGuard_Util;
144
+ //# sourceMappingURL=ui-check-guard.util.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui-check-guard.util.js","sourceRoot":"","sources":["../../../../src/_modules/ui-check/_collections/ui-check-guard.util.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,61 @@
1
+ import { Page } from '@playwright/test';
2
+ import { DyE2E_UICheckContext_Interface } from '../_models/ui-check-context.interface';
3
+ import { DyE2E_UICheckTarget_Interface } from '../_models/ui-check-finding.interface';
4
+ import { DyE2E_UICheckNetworkGuard_Interface } from './ui-check-guard.util';
5
+ /** A control as listed in the page (`listControls`). */
6
+ export interface DyE2E_UICheckControl_Interface extends DyE2E_UICheckTarget_Interface {
7
+ title: string;
8
+ destructive: boolean;
9
+ }
10
+ /** Everything a press caused (or failed to cause). */
11
+ export interface DyE2E_UICheckPressEffect_Interface {
12
+ /** The press itself failed (covered, detached, timed out) — the first line of the error. */
13
+ pressError: string | null;
14
+ urlBefore: string;
15
+ urlAfter: string;
16
+ mutations: number;
17
+ mutationSamples: string[];
18
+ requests: number;
19
+ abortedRequests: string[];
20
+ popups: number;
21
+ downloads: number;
22
+ nativeDialogs: number;
23
+ consoleErrors: string[];
24
+ /** Any effect at all. */
25
+ hadEffect: boolean;
26
+ }
27
+ /** Shared page operations of the UI detectors. */
28
+ export declare class DyE2E_UICheckPage_Util {
29
+ /** Default wait after a press, ms. */
30
+ static readonly defaultSettleMs: number;
31
+ /** Default number of controls pressed per detector and page. */
32
+ static readonly defaultMaxControls: number;
33
+ /** Console errors caused by the network guard's aborts (not by the product). */
34
+ static readonly guardInducedError: RegExp;
35
+ /** Runs one of `DyE2E_UICheckPageScripts_Const` in the page. */
36
+ static evaluate<T>(page: Page, script: string, arg?: unknown): Promise<T>;
37
+ /**
38
+ * Loads the page under check fresh, waits until it settled, and runs `context.prepare`. The console errors the page
39
+ * logs WITHOUT any press are added to `background` — a press is not blamed for them.
40
+ */
41
+ static reload(page: Page, context: DyE2E_UICheckContext_Interface, background?: Set<string>): Promise<void>;
42
+ /** A console error without its volatile parts (numbers, ids), so a repeating background error matches itself. */
43
+ static errorSignature(text: string): string;
44
+ /** The identity of a control across reloads (its CSS path may shift when an earlier press changed the page). */
45
+ static signature(control: DyE2E_UICheckControl_Interface): string;
46
+ /** The first line of a press error, plus the Playwright call-log line that names the cause (e.g. what covers it). */
47
+ static describePressError(error: unknown): string;
48
+ /** The visible, enabled controls of one kind, minus the denied ones (returned separately). */
49
+ static listControls(page: Page, context: DyE2E_UICheckContext_Interface, kind: 'press' | 'toggle'): Promise<{
50
+ controls: DyE2E_UICheckControl_Interface[];
51
+ denied: DyE2E_UICheckControl_Interface[];
52
+ }>;
53
+ /**
54
+ * Presses `selector` with every effect channel watched: URL, meaningful DOM mutations, requests (started — the
55
+ * guard aborts the mutating ones), popups, downloads, native dialogs, console errors.
56
+ */
57
+ static press(page: Page, selector: string, guard: DyE2E_UICheckNetworkGuard_Interface, context: DyE2E_UICheckContext_Interface, background?: Set<string>): Promise<DyE2E_UICheckPressEffect_Interface>;
58
+ /** The target part of a finding, from a listed control. */
59
+ static toTarget(control: DyE2E_UICheckControl_Interface): DyE2E_UICheckTarget_Interface;
60
+ }
61
+ //# sourceMappingURL=ui-check-page.util.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui-check-page.util.d.ts","sourceRoot":"","sources":["../../../../src/_modules/ui-check/_collections/ui-check-page.util.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAE1D,OAAO,EAAE,8BAA8B,EAAE,MAAM,uCAAuC,CAAC;AACvF,OAAO,EAAE,6BAA6B,EAAE,MAAM,uCAAuC,CAAC;AAEtF,OAAO,EAA2B,mCAAmC,EAAE,MAAM,uBAAuB,CAAC;AAErG,wDAAwD;AACxD,MAAM,WAAW,8BAA+B,SAAQ,6BAA6B;IACnF,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,sDAAsD;AACtD,MAAM,WAAW,kCAAkC;IACjD,4FAA4F;IAC5F,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,yBAAyB;IACzB,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,kDAAkD;AAClD,qBAAa,sBAAsB;IAEjC,sCAAsC;IACtC,MAAM,CAAC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAO;IAE9C,gEAAgE;IAChE,MAAM,CAAC,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAM;IAEhD,gFAAgF;IAChF,MAAM,CAAC,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CACqE;IAE9G,gEAAgE;WACnD,QAAQ,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC;IAI/E;;;OAGG;WACU,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,8BAA8B,EAAE,UAAU,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAsBjH,iHAAiH;IACjH,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAI3C,gHAAgH;IAChH,MAAM,CAAC,SAAS,CAAC,OAAO,EAAE,8BAA8B,GAAG,MAAM;IAIjE,qHAAqH;IACrH,MAAM,CAAC,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM;IASjD,8FAA8F;WACjF,YAAY,CACvB,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,8BAA8B,EACvC,IAAI,EAAE,OAAO,GAAG,QAAQ,GACvB,OAAO,CAAC;QAAE,QAAQ,EAAE,8BAA8B,EAAE,CAAC;QAAC,MAAM,EAAE,8BAA8B,EAAE,CAAA;KAAE,CAAC;IAiBpG;;;OAGG;WACU,KAAK,CAChB,IAAI,EAAE,IAAI,EACV,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,mCAAmC,EAC1C,OAAO,EAAE,8BAA8B,EACvC,UAAU,GAAE,GAAG,CAAC,MAAM,CAAqB,GAC1C,OAAO,CAAC,kCAAkC,CAAC;IA8E9C,2DAA2D;IAC3D,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,8BAA8B,GAAG,6BAA6B;CAIxF"}
@@ -0,0 +1,152 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DyE2E_UICheckPage_Util = void 0;
4
+ const ui_check_page_scripts_const_1 = require("./constants/ui-check-page-scripts.const");
5
+ const ui_check_guard_util_1 = require("./ui-check-guard.util");
6
+ /** Shared page operations of the UI detectors. */
7
+ class DyE2E_UICheckPage_Util {
8
+ /** Default wait after a press, ms. */
9
+ static defaultSettleMs = 600;
10
+ /** Default number of controls pressed per detector and page. */
11
+ static defaultMaxControls = 60;
12
+ /** Console errors caused by the network guard's aborts (not by the product). */
13
+ static guardInducedError = /ERR_BLOCKED_BY_CLIENT|Failed to fetch|NetworkError|Unknown Error|status of 0|net::ERR_FAILED|Load failed/i;
14
+ /** Runs one of `DyE2E_UICheckPageScripts_Const` in the page. */
15
+ static async evaluate(page, script, arg) {
16
+ return page.evaluate(`(${script})(${arg === undefined ? '' : JSON.stringify(arg)})`);
17
+ }
18
+ /**
19
+ * Loads the page under check fresh, waits until it settled, and runs `context.prepare`. The console errors the page
20
+ * logs WITHOUT any press are added to `background` — a press is not blamed for them.
21
+ */
22
+ static async reload(page, context, background) {
23
+ const onConsole = (message) => {
24
+ if (message.type() === 'error') {
25
+ background?.add(DyE2E_UICheckPage_Util.errorSignature(message.text()));
26
+ }
27
+ };
28
+ page.on('console', onConsole);
29
+ try {
30
+ await page.goto(context.url, { waitUntil: 'load' });
31
+ await page.waitForLoadState('networkidle', { timeout: 5_000 }).catch(() => undefined);
32
+ await page.waitForTimeout(context.settleMs ?? DyE2E_UICheckPage_Util.defaultSettleMs);
33
+ if (context.prepare) {
34
+ await context.prepare(page);
35
+ await page.waitForTimeout(context.settleMs ?? DyE2E_UICheckPage_Util.defaultSettleMs);
36
+ }
37
+ }
38
+ finally {
39
+ page.off('console', onConsole);
40
+ }
41
+ }
42
+ /** A console error without its volatile parts (numbers, ids), so a repeating background error matches itself. */
43
+ static errorSignature(text) {
44
+ return text.replace(/[0-9a-f]{8,}/gi, '#').replace(/\d+/g, '#').trim().slice(0, 160);
45
+ }
46
+ /** The identity of a control across reloads (its CSS path may shift when an earlier press changed the page). */
47
+ static signature(control) {
48
+ return [control.tag, control.testId ?? '', control.ariaLabel ?? '', control.text].join('|');
49
+ }
50
+ /** The first line of a press error, plus the Playwright call-log line that names the cause (e.g. what covers it). */
51
+ static describePressError(error) {
52
+ const message = error instanceof Error ? error.message : String(error);
53
+ const lines = message.split('\n');
54
+ const cause = lines.find((line) => /intercepts pointer events|not visible|not enabled|not stable|detached|outside of the viewport/.test(line));
55
+ return (lines[0] + (cause ? ' — ' + cause.trim() : '')).slice(0, 400);
56
+ }
57
+ /** The visible, enabled controls of one kind, minus the denied ones (returned separately). */
58
+ static async listControls(page, context, kind) {
59
+ const all = await DyE2E_UICheckPage_Util.evaluate(page, ui_check_page_scripts_const_1.DyE2E_UICheckPageScripts_Const['listControls'], { kind: kind, max: (context.maxControls ?? DyE2E_UICheckPage_Util.defaultMaxControls) * 3 });
60
+ const controls = [];
61
+ const denied = [];
62
+ for (const control of all) {
63
+ const label = [control.text, control.ariaLabel, control.title, control.testId].filter(Boolean).join(' ');
64
+ (ui_check_guard_util_1.DyE2E_UICheckGuard_Util.isDenied(label, context, control.destructive) ? denied : controls).push(control);
65
+ }
66
+ return { controls: controls.slice(0, context.maxControls ?? DyE2E_UICheckPage_Util.defaultMaxControls),
67
+ denied: denied };
68
+ }
69
+ /**
70
+ * Presses `selector` with every effect channel watched: URL, meaningful DOM mutations, requests (started — the
71
+ * guard aborts the mutating ones), popups, downloads, native dialogs, console errors.
72
+ */
73
+ static async press(page, selector, guard, context, background = new Set()) {
74
+ const consoleErrors = [];
75
+ let popups = 0;
76
+ let downloads = 0;
77
+ let nativeDialogs = 0;
78
+ const onConsole = (message) => {
79
+ if (message.type() === 'error') {
80
+ consoleErrors.push(message.text().slice(0, 200));
81
+ }
82
+ };
83
+ const onPageError = (error) => {
84
+ consoleErrors.push(('uncaught: ' + error.message).slice(0, 200));
85
+ };
86
+ const onPopup = () => {
87
+ popups++;
88
+ };
89
+ const onDownload = (download) => {
90
+ downloads++;
91
+ download.cancel().catch(() => undefined);
92
+ };
93
+ const onDialog = (dialog) => {
94
+ nativeDialogs++;
95
+ dialog.dismiss().catch(() => undefined);
96
+ };
97
+ page.on('console', onConsole);
98
+ page.on('pageerror', onPageError);
99
+ page.on('popup', onPopup);
100
+ page.on('download', onDownload);
101
+ page.on('dialog', onDialog);
102
+ const urlBefore = page.url();
103
+ let pressError = null;
104
+ await DyE2E_UICheckPage_Util.evaluate(page, ui_check_page_scripts_const_1.DyE2E_UICheckPageScripts_Const['startMutationWatch']);
105
+ guard.reset();
106
+ try {
107
+ await page.locator(selector).first().click({ timeout: 3_000 });
108
+ }
109
+ catch (error) {
110
+ pressError = DyE2E_UICheckPage_Util.describePressError(error);
111
+ }
112
+ await page.waitForTimeout(context.settleMs ?? DyE2E_UICheckPage_Util.defaultSettleMs);
113
+ const urlAfter = page.url();
114
+ const watch = await DyE2E_UICheckPage_Util.evaluate(page, ui_check_page_scripts_const_1.DyE2E_UICheckPageScripts_Const['readMutationWatch'])
115
+ .catch(() => ({ count: -1, samples: ['the page navigated away'] }));
116
+ page.off('console', onConsole);
117
+ page.off('pageerror', onPageError);
118
+ page.off('popup', onPopup);
119
+ page.off('download', onDownload);
120
+ page.off('dialog', onDialog);
121
+ // the guard's own aborts surface as console errors too (`ERR_BLOCKED_BY_CLIENT`, a failed fetch, an HTTP status 0)
122
+ // ⇒ those are the measurement's, not the product's, and are dropped while something was aborted
123
+ // …and an error the page also logs without any press is background noise, not the press's
124
+ const productErrors = consoleErrors
125
+ .filter((text) => !guard.log.aborted.length
126
+ || !DyE2E_UICheckPage_Util.guardInducedError.test(text))
127
+ .filter((text) => !background.has(DyE2E_UICheckPage_Util.errorSignature(text)));
128
+ const hadEffect = urlAfter !== urlBefore || watch.count !== 0 || guard.log.started > 0 || popups > 0
129
+ || downloads > 0 || nativeDialogs > 0;
130
+ return {
131
+ pressError: pressError,
132
+ urlBefore: urlBefore,
133
+ urlAfter: urlAfter,
134
+ mutations: watch.count,
135
+ mutationSamples: watch.samples,
136
+ requests: guard.log.started,
137
+ abortedRequests: [...guard.log.aborted],
138
+ popups: popups,
139
+ downloads: downloads,
140
+ nativeDialogs: nativeDialogs,
141
+ consoleErrors: productErrors,
142
+ hadEffect: hadEffect,
143
+ };
144
+ }
145
+ /** The target part of a finding, from a listed control. */
146
+ static toTarget(control) {
147
+ return { selector: control.selector, tag: control.tag, text: control.text, testId: control.testId,
148
+ ariaLabel: control.ariaLabel };
149
+ }
150
+ }
151
+ exports.DyE2E_UICheckPage_Util = DyE2E_UICheckPage_Util;
152
+ //# sourceMappingURL=ui-check-page.util.js.map