@futdevpro/dynamo-e2e 1.18.38 → 1.18.39

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 (44) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/README.md +23 -0
  3. package/build/_modules/visual-gate/_collections/blocking-overlays.util.d.ts +63 -0
  4. package/build/_modules/visual-gate/_collections/blocking-overlays.util.d.ts.map +1 -0
  5. package/build/_modules/visual-gate/_collections/blocking-overlays.util.js +104 -0
  6. package/build/_modules/visual-gate/_collections/blocking-overlays.util.js.map +1 -0
  7. package/build/_modules/visual-gate/_collections/visual-gate-defaults.const.d.ts +13 -0
  8. package/build/_modules/visual-gate/_collections/visual-gate-defaults.const.d.ts.map +1 -0
  9. package/build/_modules/visual-gate/_collections/visual-gate-defaults.const.js +28 -0
  10. package/build/_modules/visual-gate/_collections/visual-gate-defaults.const.js.map +1 -0
  11. package/build/_modules/visual-gate/_collections/visual-gate.util.d.ts +76 -0
  12. package/build/_modules/visual-gate/_collections/visual-gate.util.d.ts.map +1 -0
  13. package/build/_modules/visual-gate/_collections/visual-gate.util.js +153 -0
  14. package/build/_modules/visual-gate/_collections/visual-gate.util.js.map +1 -0
  15. package/build/_modules/visual-gate/_models/visual-gate-case.interface.d.ts +14 -0
  16. package/build/_modules/visual-gate/_models/visual-gate-case.interface.d.ts.map +1 -0
  17. package/build/_modules/visual-gate/_models/visual-gate-case.interface.js +3 -0
  18. package/build/_modules/visual-gate/_models/visual-gate-case.interface.js.map +1 -0
  19. package/build/_modules/visual-gate/_models/visual-gate-finding.interface.d.ts +11 -0
  20. package/build/_modules/visual-gate/_models/visual-gate-finding.interface.d.ts.map +1 -0
  21. package/build/_modules/visual-gate/_models/visual-gate-finding.interface.js +3 -0
  22. package/build/_modules/visual-gate/_models/visual-gate-finding.interface.js.map +1 -0
  23. package/build/_modules/visual-gate/_models/visual-gate-language.interface.d.ts +8 -0
  24. package/build/_modules/visual-gate/_models/visual-gate-language.interface.d.ts.map +1 -0
  25. package/build/_modules/visual-gate/_models/visual-gate-language.interface.js +3 -0
  26. package/build/_modules/visual-gate/_models/visual-gate-language.interface.js.map +1 -0
  27. package/build/_modules/visual-gate/_models/visual-gate-layout.interface.d.ts +14 -0
  28. package/build/_modules/visual-gate/_models/visual-gate-layout.interface.d.ts.map +1 -0
  29. package/build/_modules/visual-gate/_models/visual-gate-layout.interface.js +3 -0
  30. package/build/_modules/visual-gate/_models/visual-gate-layout.interface.js.map +1 -0
  31. package/build/_modules/visual-gate/_models/visual-gate-page.interface.d.ts +10 -0
  32. package/build/_modules/visual-gate/_models/visual-gate-page.interface.d.ts.map +1 -0
  33. package/build/_modules/visual-gate/_models/visual-gate-page.interface.js +3 -0
  34. package/build/_modules/visual-gate/_models/visual-gate-page.interface.js.map +1 -0
  35. package/build/_modules/visual-gate/_models/visual-gate-viewport.interface.d.ts +8 -0
  36. package/build/_modules/visual-gate/_models/visual-gate-viewport.interface.d.ts.map +1 -0
  37. package/build/_modules/visual-gate/_models/visual-gate-viewport.interface.js +3 -0
  38. package/build/_modules/visual-gate/_models/visual-gate-viewport.interface.js.map +1 -0
  39. package/build/_modules/visual-gate/index.d.ts +15 -0
  40. package/build/_modules/visual-gate/index.d.ts.map +1 -0
  41. package/build/_modules/visual-gate/index.js +31 -0
  42. package/build/_modules/visual-gate/index.js.map +1 -0
  43. package/build/index.js +1 -1
  44. package/package.json +10 -1
package/CHANGELOG.md CHANGED
@@ -3,6 +3,28 @@
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.39] — 2026-11-02 — `/visual-gate`: the visual regression gate, first slice (R1-72 d)
7
+
8
+ - **Why** (owner, 2026-11-02 21:39: the credit service's login "badly out of shape", "a review tool is needed";
9
+ `IN-2026-11-02-R1-72` (d)): the key pages, HU + EN, 1440 + 390, red in the CI when a page falls apart, disappears
10
+ or changes. The products wire it in.
11
+ - **`DyE2E_BlockingOverlays_Util`**: closes the two overlays of a TEST deployment through the app's own buttons
12
+ (the ngx-dynamo storage service writes a control record and may encrypt, so a hand-made `localStorage` value is
13
+ not reliably valid): the TEST warning by its panel class (`.dynx-test-ribbon-warning-dialog`; every "do not show
14
+ again" box ticked, so the ribbon is not in the screenshot either), the cookie bar by its test id (necessary
15
+ only). Language-neutral hooks. `prepareStorageState({ browser, baseUrl, locale })` returns the state to start
16
+ every case from, once per language; it fails loudly when an overlay is still visible after closing it.
17
+ Nothing to close (production) is not an error.
18
+ - **`DyE2E_VisualGate_Util`**: `cases({ pages })` (page × language × viewport, ids `<page>-<lang>-<viewport>`,
19
+ duplicate names refused); `inspect(page)` — an overlay still covering the page, `page-empty` (fewer than 20
20
+ visible characters or 5 visible elements), `horizontal-overflow` (the widest element named); `assertPage(page,
21
+ case)` — those first, with their reason, then `toHaveScreenshot(<id>.png)` (full page, animations off, masks,
22
+ 2 % tolerance).
23
+ - **Measured live** on the credit TEST `/login` (the real ngx-dynamo dialog + cookie bar): 4 / 4 cases closed both
24
+ overlays (the ribbon hidden too), HU and EN by the locale, no finding. ⚠️ A layout like the credit login before
25
+ ngx-fdp-templates 20.20.292 (a form across the whole page) is caught only by the baseline comparison, not by
26
+ the cheap checks.
27
+ - 7 specs (4 on a real Chromium, fixture pages), 4 mutants killed; 620 / 0.
6
28
  ## [01.18.38] — 2026-11-01 — `/ui-check`: `error-destination`, a press that lands on an error (BFR-FLEET-012 ②)
7
29
 
8
30
  - **`error-destination`** (`press-leads-to-error`; owner, 2026-10-26, `IN-2026-10-26-ORC-02`: "…ha valamire
package/README.md CHANGED
@@ -84,6 +84,29 @@ const report = await DyE2E_UICheckRunner_Util.run(page, { url: page.url(), accou
84
84
  DyE2E_UICheckRunner_Util.assertClean(report); // throws with every finding's measurement
85
85
  ```
86
86
 
87
+ - `@futdevpro/dynamo-e2e/visual-gate` — the visual regression gate: closes the TEST warning and the cookie bar through
88
+ the app (`DyE2E_BlockingOverlays_Util.prepareStorageState`, once per language), then checks each key page in
89
+ HU + EN at 1440 + 390 (`DyE2E_VisualGate_Util.cases`): red when an overlay still covers it, it shows (almost)
90
+ nothing, it is wider than the screen, or it differs from the committed baseline (`toHaveScreenshot`).
91
+
92
+ ```ts
93
+ import { DyE2E_BlockingOverlays_Util, DyE2E_VisualGate_Util } from '@futdevpro/dynamo-e2e/visual-gate';
94
+
95
+ for (const gateCase of DyE2E_VisualGate_Util.cases({ pages: [ { name: 'login', path: '/login' } ] })) {
96
+ test(`| visual: ${gateCase.id}`, async ({ browser }) => {
97
+ const { storageState } = await DyE2E_BlockingOverlays_Util.prepareStorageState({
98
+ browser, baseUrl: BASE_URL, locale: gateCase.language.locale,
99
+ });
100
+ const context = await browser.newContext({ storageState, locale: gateCase.language.locale,
101
+ viewport: { width: gateCase.viewport.width, height: gateCase.viewport.height } });
102
+ const page = await context.newPage();
103
+
104
+ await page.goto(BASE_URL + gateCase.page.path);
105
+ await DyE2E_VisualGate_Util.assertPage(page, gateCase); // layout first, then the screenshot comparison
106
+ });
107
+ }
108
+ ```
109
+
87
110
  ## Playwright preset — CI timeouts and the failure budget
88
111
 
89
112
  ```ts
@@ -0,0 +1,63 @@
1
+ import { Browser, BrowserContext, Page } from '@playwright/test';
2
+ /** What `DyE2E_BlockingOverlays_Util.acknowledge` closed. */
3
+ export interface DyE2E_BlockingOverlaysResult_Interface {
4
+ /** The TEST-environment warning was there and is acknowledged (every "do not show again" box ticked). */
5
+ isTestWarningAcknowledged: boolean;
6
+ /** The cookie bar was there and is decided (necessary cookies only). */
7
+ isCookieConsentDecided: boolean;
8
+ }
9
+ /** The browser state after the overlays are closed: reuse it as `storageState` of every visual-gate context. */
10
+ export type DyE2E_BlockingOverlaysState_Type = Awaited<ReturnType<BrowserContext['storageState']>>;
11
+ /**
12
+ * Closes the two overlays that cover every page of a TEST deployment before an automated check (R1-72 d): the
13
+ * TEST-environment warning (`dynamo-test-ribbon` of ngx-dynamo) and the cookie bar (`dynamo-cookie-consent`).
14
+ *
15
+ * @description Through the app itself, by its buttons — not by writing `localStorage` by hand: the ngx-dynamo storage
16
+ * service writes its own control record (`dynamo-control`) and may encrypt, so a hand-made value is not reliably
17
+ * valid (measured in futdevpro's `test-warning.global-setup.ts`). The hooks do not depend on the language: the
18
+ * warning dialog's own panel class, the cookie bar's `data-testid` (a test id built from a button caption changed
19
+ * when the caption was localised and silently broke a harness; FAM, adventor 2026-09-21).
20
+ */
21
+ export declare class DyE2E_BlockingOverlays_Util {
22
+ /** The TEST-warning dialog (its `panelClass`). */
23
+ static readonly testWarningSelector: string;
24
+ /** The cookie bar. */
25
+ static readonly cookieConsentSelector: string;
26
+ /** The cookie bar's "necessary only" button (the summary view and the details view both carry it). */
27
+ static readonly cookieRejectSelector: string;
28
+ /** How often the page is looked at while waiting for an overlay, ms. */
29
+ static readonly lookIntervalMs: number;
30
+ /**
31
+ * Closes the TEST warning and the cookie bar on this page, in the order they cover each other (the warning first).
32
+ *
33
+ * @description Waits up to `timeoutMs` for both: either may render late (the cookie bar waits for the language
34
+ * map). On production neither exists — that is not an error, the result says so.
35
+ */
36
+ static acknowledge(page: Page, timeoutMs?: number): Promise<DyE2E_BlockingOverlaysResult_Interface>;
37
+ /**
38
+ * The overlays that still cover the page (empty when the page is free).
39
+ *
40
+ * @returns the names: `test-warning`, `cookie-consent`
41
+ */
42
+ static findVisible(page: Page): Promise<string[]>;
43
+ /**
44
+ * Opens the app once in a fresh context, closes both overlays, and returns the browser state to start every
45
+ * visual-gate context from (`browser.newContext({ storageState })`).
46
+ *
47
+ * @description Call it once per language with that language's `locale`: an app that stores the language it
48
+ * picked would otherwise carry the first language into every case. Fails loudly when an overlay is still visible
49
+ * after closing it (a silent "nothing to close" hid a broken harness before; FAM, adventor 2026-09-21).
50
+ */
51
+ static prepareStorageState(set: {
52
+ browser: Browser;
53
+ baseUrl: string;
54
+ locale?: string;
55
+ timeoutMs?: number;
56
+ }): Promise<{
57
+ storageState: DyE2E_BlockingOverlaysState_Type;
58
+ result: DyE2E_BlockingOverlaysResult_Interface;
59
+ }>;
60
+ /** Ticks every "do not show again" box of the warning (the ribbon too, so it is not in the screenshot), confirms. */
61
+ private static acknowledgeTestWarning;
62
+ }
63
+ //# sourceMappingURL=blocking-overlays.util.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blocking-overlays.util.d.ts","sourceRoot":"","sources":["../../../../src/_modules/visual-gate/_collections/blocking-overlays.util.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,cAAc,EAAW,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAI1E,6DAA6D;AAC7D,MAAM,WAAW,sCAAsC;IACrD,yGAAyG;IACzG,yBAAyB,EAAE,OAAO,CAAC;IACnC,wEAAwE;IACxE,sBAAsB,EAAE,OAAO,CAAC;CACjC;AAED,gHAAgH;AAChH,MAAM,MAAM,gCAAgC,GAAG,OAAO,CAAC,UAAU,CAAC,cAAc,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;AAEnG;;;;;;;;;GASG;AACH,qBAAa,2BAA2B;IAEtC,kDAAkD;IAClD,MAAM,CAAC,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAsC;IAEjF,sBAAsB;IACtB,MAAM,CAAC,QAAQ,CAAC,qBAAqB,EAAE,MAAM,CAAoC;IAEjF,sGAAsG;IACtG,MAAM,CAAC,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAA2C;IAEvF,wEAAwE;IACxE,MAAM,CAAC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAO;IAE7C;;;;;OAKG;WACU,WAAW,CACtB,IAAI,EAAE,IAAI,EACV,SAAS,GAAE,MAAwD,GAClE,OAAO,CAAC,sCAAsC,CAAC;IAyBlD;;;;OAIG;WACU,WAAW,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAavD;;;;;;;OAOG;WACU,mBAAmB,CAAC,GAAG,EAAE;QACpC,OAAO,EAAE,OAAO,CAAC;QACjB,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,GAAG,OAAO,CAAC;QAAE,YAAY,EAAE,gCAAgC,CAAC;QAAC,MAAM,EAAE,sCAAsC,CAAA;KAAE,CAAC;IAsB/G,qHAAqH;mBAChG,sBAAsB;CAU5C"}
@@ -0,0 +1,104 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DyE2E_BlockingOverlays_Util = void 0;
4
+ const visual_gate_defaults_const_1 = require("./visual-gate-defaults.const");
5
+ /**
6
+ * Closes the two overlays that cover every page of a TEST deployment before an automated check (R1-72 d): the
7
+ * TEST-environment warning (`dynamo-test-ribbon` of ngx-dynamo) and the cookie bar (`dynamo-cookie-consent`).
8
+ *
9
+ * @description Through the app itself, by its buttons — not by writing `localStorage` by hand: the ngx-dynamo storage
10
+ * service writes its own control record (`dynamo-control`) and may encrypt, so a hand-made value is not reliably
11
+ * valid (measured in futdevpro's `test-warning.global-setup.ts`). The hooks do not depend on the language: the
12
+ * warning dialog's own panel class, the cookie bar's `data-testid` (a test id built from a button caption changed
13
+ * when the caption was localised and silently broke a harness; FAM, adventor 2026-09-21).
14
+ */
15
+ class DyE2E_BlockingOverlays_Util {
16
+ /** The TEST-warning dialog (its `panelClass`). */
17
+ static testWarningSelector = '.dynx-test-ribbon-warning-dialog';
18
+ /** The cookie bar. */
19
+ static cookieConsentSelector = '[data-testid="cookie-consent"]';
20
+ /** The cookie bar's "necessary only" button (the summary view and the details view both carry it). */
21
+ static cookieRejectSelector = '[data-testid="cookie-consent-reject"]';
22
+ /** How often the page is looked at while waiting for an overlay, ms. */
23
+ static lookIntervalMs = 250;
24
+ /**
25
+ * Closes the TEST warning and the cookie bar on this page, in the order they cover each other (the warning first).
26
+ *
27
+ * @description Waits up to `timeoutMs` for both: either may render late (the cookie bar waits for the language
28
+ * map). On production neither exists — that is not an error, the result says so.
29
+ */
30
+ static async acknowledge(page, timeoutMs = visual_gate_defaults_const_1.DyE2E_VisualGateDefaults_Const.overlayTimeoutMs) {
31
+ const result = {
32
+ isTestWarningAcknowledged: false, isCookieConsentDecided: false,
33
+ };
34
+ const deadline = Date.now() + timeoutMs;
35
+ while (Date.now() < deadline && !(result.isTestWarningAcknowledged && result.isCookieConsentDecided)) {
36
+ const warning = page.locator(this.testWarningSelector).first();
37
+ const reject = page.locator(`${this.cookieRejectSelector}:visible`).first();
38
+ if (!result.isTestWarningAcknowledged && await warning.isVisible()) {
39
+ await this.acknowledgeTestWarning(warning);
40
+ result.isTestWarningAcknowledged = true;
41
+ }
42
+ else if (!result.isCookieConsentDecided && await reject.isVisible()) {
43
+ await reject.click();
44
+ await page.locator(this.cookieConsentSelector).first().waitFor({ state: 'hidden', timeout: 5_000 });
45
+ result.isCookieConsentDecided = true;
46
+ }
47
+ else {
48
+ await page.waitForTimeout(this.lookIntervalMs);
49
+ }
50
+ }
51
+ return result;
52
+ }
53
+ /**
54
+ * The overlays that still cover the page (empty when the page is free).
55
+ *
56
+ * @returns the names: `test-warning`, `cookie-consent`
57
+ */
58
+ static async findVisible(page) {
59
+ const visible = [];
60
+ if (await page.locator(this.testWarningSelector).first().isVisible()) {
61
+ visible.push('test-warning');
62
+ }
63
+ if (await page.locator(this.cookieConsentSelector).first().isVisible()) {
64
+ visible.push('cookie-consent');
65
+ }
66
+ return visible;
67
+ }
68
+ /**
69
+ * Opens the app once in a fresh context, closes both overlays, and returns the browser state to start every
70
+ * visual-gate context from (`browser.newContext({ storageState })`).
71
+ *
72
+ * @description Call it once per language with that language's `locale`: an app that stores the language it
73
+ * picked would otherwise carry the first language into every case. Fails loudly when an overlay is still visible
74
+ * after closing it (a silent "nothing to close" hid a broken harness before; FAM, adventor 2026-09-21).
75
+ */
76
+ static async prepareStorageState(set) {
77
+ const context = await set.browser.newContext({ locale: set.locale, ignoreHTTPSErrors: true });
78
+ try {
79
+ const page = await context.newPage();
80
+ await page.goto(set.baseUrl, { waitUntil: 'domcontentloaded' });
81
+ const result = await this.acknowledge(page, set.timeoutMs);
82
+ const stillVisible = await this.findVisible(page);
83
+ if (stillVisible.length) {
84
+ throw new Error(`[dynamo-e2e visual-gate] still covering the page after closing: ${stillVisible.join(', ')} (${set.baseUrl})`);
85
+ }
86
+ return { storageState: await context.storageState(), result: result };
87
+ }
88
+ finally {
89
+ await context.close();
90
+ }
91
+ }
92
+ /** Ticks every "do not show again" box of the warning (the ribbon too, so it is not in the screenshot), confirms. */
93
+ static async acknowledgeTestWarning(warning) {
94
+ const boxes = warning.locator('input[type="checkbox"]');
95
+ const count = await boxes.count();
96
+ for (let i = 0; i < count; i++) {
97
+ await boxes.nth(i).check();
98
+ }
99
+ await warning.locator('button').last().click();
100
+ await warning.waitFor({ state: 'hidden', timeout: 5_000 });
101
+ }
102
+ }
103
+ exports.DyE2E_BlockingOverlays_Util = DyE2E_BlockingOverlays_Util;
104
+ //# sourceMappingURL=blocking-overlays.util.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blocking-overlays.util.js","sourceRoot":"","sources":["../../../../src/_modules/visual-gate/_collections/blocking-overlays.util.ts"],"names":[],"mappings":";;;AAEA,6EAA8E;AAa9E;;;;;;;;;GASG;AACH,MAAa,2BAA2B;IAEtC,kDAAkD;IAClD,MAAM,CAAU,mBAAmB,GAAW,kCAAkC,CAAC;IAEjF,sBAAsB;IACtB,MAAM,CAAU,qBAAqB,GAAW,gCAAgC,CAAC;IAEjF,sGAAsG;IACtG,MAAM,CAAU,oBAAoB,GAAW,uCAAuC,CAAC;IAEvF,wEAAwE;IACxE,MAAM,CAAU,cAAc,GAAW,GAAG,CAAC;IAE7C;;;;;OAKG;IACH,MAAM,CAAC,KAAK,CAAC,WAAW,CACtB,IAAU,EACV,YAAoB,2DAA8B,CAAC,gBAAgB;QAEnE,MAAM,MAAM,GAA2C;YACrD,yBAAyB,EAAE,KAAK,EAAE,sBAAsB,EAAE,KAAK;SAChE,CAAC;QACF,MAAM,QAAQ,GAAW,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;QAEhD,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,IAAI,CAAC,CAAC,MAAM,CAAC,yBAAyB,IAAI,MAAM,CAAC,sBAAsB,CAAC,EAAE,CAAC;YACrG,MAAM,OAAO,GAAY,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,KAAK,EAAE,CAAC;YACxE,MAAM,MAAM,GAAY,IAAI,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,oBAAoB,UAAU,CAAC,CAAC,KAAK,EAAE,CAAC;YAErF,IAAI,CAAC,MAAM,CAAC,yBAAyB,IAAI,MAAM,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC;gBACnE,MAAM,IAAI,CAAC,sBAAsB,CAAC,OAAO,CAAC,CAAC;gBAC3C,MAAM,CAAC,yBAAyB,GAAG,IAAI,CAAC;YAC1C,CAAC;iBAAM,IAAI,CAAC,MAAM,CAAC,sBAAsB,IAAI,MAAM,MAAM,CAAC,SAAS,EAAE,EAAE,CAAC;gBACtE,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;gBACrB,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC,KAAK,EAAE,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;gBACpG,MAAM,CAAC,sBAAsB,GAAG,IAAI,CAAC;YACvC,CAAC;iBAAM,CAAC;gBACN,MAAM,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;YACjD,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAED;;;;OAIG;IACH,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,IAAU;QACjC,MAAM,OAAO,GAAa,EAAE,CAAC;QAE7B,IAAI,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,KAAK,EAAE,CAAC,SAAS,EAAE,EAAE,CAAC;YACrE,OAAO,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAC/B,CAAC;QACD,IAAI,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC,KAAK,EAAE,CAAC,SAAS,EAAE,EAAE,CAAC;YACvE,OAAO,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;QACjC,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;;;;;;OAOG;IACH,MAAM,CAAC,KAAK,CAAC,mBAAmB,CAAC,GAKhC;QACC,MAAM,OAAO,GAAmB,MAAM,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,iBAAiB,EAAE,IAAI,EAAE,CAAC,CAAC;QAE9G,IAAI,CAAC;YACH,MAAM,IAAI,GAAS,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC;YAE3C,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,kBAAkB,EAAE,CAAC,CAAC;YAChE,MAAM,MAAM,GAA2C,MAAM,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC;YACnG,MAAM,YAAY,GAAa,MAAM,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;YAE5D,IAAI,YAAY,CAAC,MAAM,EAAE,CAAC;gBACxB,MAAM,IAAI,KAAK,CACb,mEAAmE,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,OAAO,GAAG,CAC9G,CAAC;YACJ,CAAC;YAED,OAAO,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC,YAAY,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;QACxE,CAAC;gBAAS,CAAC;YACT,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;QACxB,CAAC;IACH,CAAC;IAED,qHAAqH;IAC7G,MAAM,CAAC,KAAK,CAAC,sBAAsB,CAAC,OAAgB;QAC1D,MAAM,KAAK,GAAY,OAAO,CAAC,OAAO,CAAC,wBAAwB,CAAC,CAAC;QACjE,MAAM,KAAK,GAAW,MAAM,KAAK,CAAC,KAAK,EAAE,CAAC;QAE1C,KAAK,IAAI,CAAC,GAAW,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;YACvC,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC;QAC7B,CAAC;QACD,MAAM,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,CAAC;QAC/C,MAAM,OAAO,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;IAC7D,CAAC;;AA/GH,kEAgHC"}
@@ -0,0 +1,13 @@
1
+ import { DyE2E_VisualGateLanguage_Interface } from '../_models/visual-gate-language.interface';
2
+ import { DyE2E_VisualGateViewport_Interface } from '../_models/visual-gate-viewport.interface';
3
+ /** The defaults of the visual gate (R1-72 d: "HU + EN, 1440 + 390"). */
4
+ export declare const DyE2E_VisualGateDefaults_Const: {
5
+ viewports: DyE2E_VisualGateViewport_Interface[];
6
+ languages: DyE2E_VisualGateLanguage_Interface[];
7
+ minVisibleTextLength: number;
8
+ minVisibleElementCount: number;
9
+ overflowTolerancePx: number;
10
+ maxDiffPixelRatio: number;
11
+ overlayTimeoutMs: number;
12
+ };
13
+ //# sourceMappingURL=visual-gate-defaults.const.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"visual-gate-defaults.const.d.ts","sourceRoot":"","sources":["../../../../src/_modules/visual-gate/_collections/visual-gate-defaults.const.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kCAAkC,EAAE,MAAM,2CAA2C,CAAC;AAC/F,OAAO,EAAE,kCAAkC,EAAE,MAAM,2CAA2C,CAAC;AAE/F,wEAAwE;AACxE,eAAO,MAAM,8BAA8B,EAAE;IAC3C,SAAS,EAAE,kCAAkC,EAAE,CAAC;IAChD,SAAS,EAAE,kCAAkC,EAAE,CAAC;IAChD,oBAAoB,EAAE,MAAM,CAAC;IAC7B,sBAAsB,EAAE,MAAM,CAAC;IAC/B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,gBAAgB,EAAE,MAAM,CAAC;CAuB1B,CAAC"}
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DyE2E_VisualGateDefaults_Const = void 0;
4
+ /** The defaults of the visual gate (R1-72 d: "HU + EN, 1440 + 390"). */
5
+ exports.DyE2E_VisualGateDefaults_Const = {
6
+ viewports: [
7
+ { name: 'desktop', width: 1440, height: 900 },
8
+ { name: 'mobile', width: 390, height: 844 },
9
+ ],
10
+ languages: [
11
+ { code: 'hu', locale: 'hu-HU' },
12
+ { code: 'en', locale: 'en-US' },
13
+ ],
14
+ /** Fewer visible characters than this ⇒ the page disappeared (a heading and a button already give more). */
15
+ minVisibleTextLength: 20,
16
+ /** Fewer visible elements than this ⇒ the page disappeared. */
17
+ minVisibleElementCount: 5,
18
+ /** Sub-pixel rounding: a document at most this much wider than the viewport is not a sideways scroll. */
19
+ overflowTolerancePx: 1,
20
+ /** The share of differing pixels the screenshot comparison tolerates (antialiasing, a moved caret). */
21
+ maxDiffPixelRatio: 0.02,
22
+ /**
23
+ * How long the setup waits for the TEST warning and the cookie bar. Measured (FAM, futdevpro 2026-09-21): the bar
24
+ * renders behind the app's language map or a 4 s fail-open, so a slow runner needs well over 4 s.
25
+ */
26
+ overlayTimeoutMs: 15_000,
27
+ };
28
+ //# sourceMappingURL=visual-gate-defaults.const.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"visual-gate-defaults.const.js","sourceRoot":"","sources":["../../../../src/_modules/visual-gate/_collections/visual-gate-defaults.const.ts"],"names":[],"mappings":";;;AAGA,wEAAwE;AAC3D,QAAA,8BAA8B,GAQvC;IACF,SAAS,EAAE;QACT,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE;QAC7C,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE;KAC5C;IACD,SAAS,EAAE;QACT,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE;QAC/B,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE;KAChC;IACD,4GAA4G;IAC5G,oBAAoB,EAAE,EAAE;IACxB,+DAA+D;IAC/D,sBAAsB,EAAE,CAAC;IACzB,yGAAyG;IACzG,mBAAmB,EAAE,CAAC;IACtB,uGAAuG;IACvG,iBAAiB,EAAE,IAAI;IACvB;;;OAGG;IACH,gBAAgB,EAAE,MAAM;CACzB,CAAC"}
@@ -0,0 +1,76 @@
1
+ import { Page } from '@playwright/test';
2
+ import { DyE2E_VisualGateCase_Interface } from '../_models/visual-gate-case.interface';
3
+ import { DyE2E_VisualGateFinding_Interface } from '../_models/visual-gate-finding.interface';
4
+ import { DyE2E_VisualGateLanguage_Interface } from '../_models/visual-gate-language.interface';
5
+ import { DyE2E_VisualGateLayout_Interface } from '../_models/visual-gate-layout.interface';
6
+ import { DyE2E_VisualGatePage_Interface } from '../_models/visual-gate-page.interface';
7
+ import { DyE2E_VisualGateViewport_Interface } from '../_models/visual-gate-viewport.interface';
8
+ /**
9
+ * The visual regression gate (R1-72 d; owner, 2026-11-02 21:39: the credit login "badly out of shape", "a review tool
10
+ * is needed"): the key pages, HU + EN, 1440 + 390, red in the CI when a page falls apart or disappears.
11
+ *
12
+ * @description Two checks per page, the cheap and certain one first: (1) a layout check in the browser — the TEST
13
+ * warning or the cookie bar still covers the page, the page shows (almost) nothing, or it is wider than the screen;
14
+ * (2) a screenshot comparison against the product's committed baseline (Playwright `toHaveScreenshot`; the first run,
15
+ * or `--update-snapshots`, writes it).
16
+ *
17
+ * ```ts
18
+ * import { DyE2E_BlockingOverlays_Util, DyE2E_VisualGate_Util } from '@futdevpro/dynamo-e2e/visual-gate';
19
+ *
20
+ * for (const gateCase of DyE2E_VisualGate_Util.cases({ pages: [ { name: 'home', path: '/' } ] })) {
21
+ * test(`| visual: ${gateCase.id}`, async ({ browser }) => {
22
+ * const { storageState } = await DyE2E_BlockingOverlays_Util.prepareStorageState({
23
+ * browser, baseUrl: BASE_URL, locale: gateCase.language.locale,
24
+ * });
25
+ * const context = await browser.newContext({ storageState, locale: gateCase.language.locale,
26
+ * viewport: { width: gateCase.viewport.width, height: gateCase.viewport.height } });
27
+ * const page = await context.newPage();
28
+ *
29
+ * await page.goto(BASE_URL + gateCase.page.path);
30
+ * await DyE2E_VisualGate_Util.assertPage(page, gateCase);
31
+ * });
32
+ * }
33
+ * ```
34
+ */
35
+ export declare class DyE2E_VisualGate_Util {
36
+ /** Browser-side layout measurement: a function expression, evaluated through `page.evaluate` (DOM APIs only). */
37
+ static readonly measureLayoutScript: string;
38
+ /**
39
+ * The check matrix: every page in every language at every screen size.
40
+ *
41
+ * @returns one case per page × language × viewport, ids `<page>-<language>-<viewport>`
42
+ */
43
+ static cases(set: {
44
+ pages: DyE2E_VisualGatePage_Interface[];
45
+ languages?: DyE2E_VisualGateLanguage_Interface[];
46
+ viewports?: DyE2E_VisualGateViewport_Interface[];
47
+ }): DyE2E_VisualGateCase_Interface[];
48
+ /** Measures what the page shows (after the fonts are loaded). */
49
+ static measureLayout(page: Page): Promise<DyE2E_VisualGateLayout_Interface>;
50
+ /**
51
+ * Judges a measured layout.
52
+ *
53
+ * @returns `page-empty` (it disappeared) and / or `horizontal-overflow` (it fell apart); empty when healthy
54
+ */
55
+ static checkLayout(layout: DyE2E_VisualGateLayout_Interface, limits?: {
56
+ minVisibleTextLength?: number;
57
+ minVisibleElementCount?: number;
58
+ overflowTolerancePx?: number;
59
+ }): DyE2E_VisualGateFinding_Interface[];
60
+ /** The cheap checks of one page: overlays still covering it + the layout. */
61
+ static inspect(page: Page, limits?: {
62
+ minVisibleTextLength?: number;
63
+ minVisibleElementCount?: number;
64
+ overflowTolerancePx?: number;
65
+ }): Promise<DyE2E_VisualGateFinding_Interface[]>;
66
+ /**
67
+ * The gate for one case, inside a Playwright test: the cheap checks first (a finding fails the test with its
68
+ * reason), then the screenshot comparison against the baseline `<case id>.png`.
69
+ */
70
+ static assertPage(page: Page, gateCase: DyE2E_VisualGateCase_Interface, options?: {
71
+ maxDiffPixelRatio?: number;
72
+ minVisibleTextLength?: number;
73
+ overflowTolerancePx?: number;
74
+ }): Promise<void>;
75
+ }
76
+ //# sourceMappingURL=visual-gate.util.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"visual-gate.util.d.ts","sourceRoot":"","sources":["../../../../src/_modules/visual-gate/_collections/visual-gate.util.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAEzD,OAAO,EAAE,8BAA8B,EAAE,MAAM,uCAAuC,CAAC;AACvF,OAAO,EAAE,iCAAiC,EAAE,MAAM,0CAA0C,CAAC;AAC7F,OAAO,EAAE,kCAAkC,EAAE,MAAM,2CAA2C,CAAC;AAC/F,OAAO,EAAE,gCAAgC,EAAE,MAAM,yCAAyC,CAAC;AAC3F,OAAO,EAAE,8BAA8B,EAAE,MAAM,uCAAuC,CAAC;AACvF,OAAO,EAAE,kCAAkC,EAAE,MAAM,2CAA2C,CAAC;AAI/F;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,qBAAa,qBAAqB;IAEhC,iHAAiH;IACjH,MAAM,CAAC,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAoCxC;IAEH;;;;OAIG;IACH,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE;QAChB,KAAK,EAAE,8BAA8B,EAAE,CAAC;QACxC,SAAS,CAAC,EAAE,kCAAkC,EAAE,CAAC;QACjD,SAAS,CAAC,EAAE,kCAAkC,EAAE,CAAC;KAClD,GAAG,8BAA8B,EAAE;IAoBpC,iEAAiE;WACpD,aAAa,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,gCAAgC,CAAC;IAMjF;;;;OAIG;IACH,MAAM,CAAC,WAAW,CAChB,MAAM,EAAE,gCAAgC,EACxC,MAAM,GAAE;QAAE,oBAAoB,CAAC,EAAE,MAAM,CAAC;QAAC,sBAAsB,CAAC,EAAE,MAAM,CAAC;QAAC,mBAAmB,CAAC,EAAE,MAAM,CAAA;KAAO,GAC5G,iCAAiC,EAAE;IAwBtC,6EAA6E;WAChE,OAAO,CAClB,IAAI,EAAE,IAAI,EACV,MAAM,GAAE;QAAE,oBAAoB,CAAC,EAAE,MAAM,CAAC;QAAC,sBAAsB,CAAC,EAAE,MAAM,CAAC;QAAC,mBAAmB,CAAC,EAAE,MAAM,CAAA;KAAO,GAC5G,OAAO,CAAC,iCAAiC,EAAE,CAAC;IAS/C;;;OAGG;WACU,UAAU,CACrB,IAAI,EAAE,IAAI,EACV,QAAQ,EAAE,8BAA8B,EACxC,OAAO,GAAE;QAAE,iBAAiB,CAAC,EAAE,MAAM,CAAC;QAAC,oBAAoB,CAAC,EAAE,MAAM,CAAC;QAAC,mBAAmB,CAAC,EAAE,MAAM,CAAA;KAAO,GACxG,OAAO,CAAC,IAAI,CAAC;CAgBjB"}
@@ -0,0 +1,153 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DyE2E_VisualGate_Util = void 0;
4
+ const test_1 = require("@playwright/test");
5
+ const blocking_overlays_util_1 = require("./blocking-overlays.util");
6
+ const visual_gate_defaults_const_1 = require("./visual-gate-defaults.const");
7
+ /**
8
+ * The visual regression gate (R1-72 d; owner, 2026-11-02 21:39: the credit login "badly out of shape", "a review tool
9
+ * is needed"): the key pages, HU + EN, 1440 + 390, red in the CI when a page falls apart or disappears.
10
+ *
11
+ * @description Two checks per page, the cheap and certain one first: (1) a layout check in the browser — the TEST
12
+ * warning or the cookie bar still covers the page, the page shows (almost) nothing, or it is wider than the screen;
13
+ * (2) a screenshot comparison against the product's committed baseline (Playwright `toHaveScreenshot`; the first run,
14
+ * or `--update-snapshots`, writes it).
15
+ *
16
+ * ```ts
17
+ * import { DyE2E_BlockingOverlays_Util, DyE2E_VisualGate_Util } from '@futdevpro/dynamo-e2e/visual-gate';
18
+ *
19
+ * for (const gateCase of DyE2E_VisualGate_Util.cases({ pages: [ { name: 'home', path: '/' } ] })) {
20
+ * test(`| visual: ${gateCase.id}`, async ({ browser }) => {
21
+ * const { storageState } = await DyE2E_BlockingOverlays_Util.prepareStorageState({
22
+ * browser, baseUrl: BASE_URL, locale: gateCase.language.locale,
23
+ * });
24
+ * const context = await browser.newContext({ storageState, locale: gateCase.language.locale,
25
+ * viewport: { width: gateCase.viewport.width, height: gateCase.viewport.height } });
26
+ * const page = await context.newPage();
27
+ *
28
+ * await page.goto(BASE_URL + gateCase.page.path);
29
+ * await DyE2E_VisualGate_Util.assertPage(page, gateCase);
30
+ * });
31
+ * }
32
+ * ```
33
+ */
34
+ class DyE2E_VisualGate_Util {
35
+ /** Browser-side layout measurement: a function expression, evaluated through `page.evaluate` (DOM APIs only). */
36
+ static measureLayoutScript = `() => {
37
+ const root = document.documentElement;
38
+ const viewportWidth = root.clientWidth;
39
+ let visibleTextLength = 0;
40
+ let visibleElementCount = 0;
41
+ let widestOverflow = null;
42
+ let widestRight = viewportWidth;
43
+ for (const el of Array.from(document.body ? document.body.querySelectorAll('*') : [])) {
44
+ const style = getComputedStyle(el);
45
+ if (style.display === 'none' || style.visibility === 'hidden' || Number(style.opacity) === 0) {
46
+ continue;
47
+ }
48
+ const rect = el.getBoundingClientRect();
49
+ if (rect.width < 1 || rect.height < 1) {
50
+ continue;
51
+ }
52
+ visibleElementCount++;
53
+ for (const node of Array.from(el.childNodes)) {
54
+ if (node.nodeType === 3) {
55
+ visibleTextLength += node.textContent.trim().length;
56
+ }
57
+ }
58
+ const right = rect.right + window.scrollX;
59
+ if (right > widestRight + 1 && style.position !== 'fixed') {
60
+ widestRight = right;
61
+ const cls = typeof el.className === 'string' ? el.className.trim().split(/\\s+/).slice(0, 2).join('.') : '';
62
+ widestOverflow = el.tagName.toLowerCase() + (cls ? '.' + cls : '') + ' (' + Math.round(right) + ' px)';
63
+ }
64
+ }
65
+ return {
66
+ viewportWidth: viewportWidth,
67
+ scrollWidth: root.scrollWidth,
68
+ widestOverflow: widestOverflow,
69
+ visibleTextLength: visibleTextLength,
70
+ visibleElementCount: visibleElementCount,
71
+ };
72
+ }`;
73
+ /**
74
+ * The check matrix: every page in every language at every screen size.
75
+ *
76
+ * @returns one case per page × language × viewport, ids `<page>-<language>-<viewport>`
77
+ */
78
+ static cases(set) {
79
+ const gateCases = [];
80
+ for (const page of set.pages) {
81
+ for (const language of set.languages ?? visual_gate_defaults_const_1.DyE2E_VisualGateDefaults_Const.languages) {
82
+ for (const viewport of set.viewports ?? visual_gate_defaults_const_1.DyE2E_VisualGateDefaults_Const.viewports) {
83
+ const id = `${page.name}-${language.code}-${viewport.name}`;
84
+ gateCases.push({ id: id, page: page, language: language, viewport: viewport, snapshotName: `${id}.png` });
85
+ }
86
+ }
87
+ }
88
+ if (new Set(gateCases.map((gateCase) => gateCase.id)).size
89
+ !== gateCases.length) {
90
+ throw new Error('[dynamo-e2e visual-gate] two pages, languages or viewports share a name');
91
+ }
92
+ return gateCases;
93
+ }
94
+ /** Measures what the page shows (after the fonts are loaded). */
95
+ static async measureLayout(page) {
96
+ await page.evaluate('document.fonts ? document.fonts.ready.then(() => true) : true');
97
+ return page.evaluate(`(${this.measureLayoutScript})()`);
98
+ }
99
+ /**
100
+ * Judges a measured layout.
101
+ *
102
+ * @returns `page-empty` (it disappeared) and / or `horizontal-overflow` (it fell apart); empty when healthy
103
+ */
104
+ static checkLayout(layout, limits = {}) {
105
+ const findings = [];
106
+ const minText = limits.minVisibleTextLength ?? visual_gate_defaults_const_1.DyE2E_VisualGateDefaults_Const.minVisibleTextLength;
107
+ const minElements = limits.minVisibleElementCount ?? visual_gate_defaults_const_1.DyE2E_VisualGateDefaults_Const.minVisibleElementCount;
108
+ const tolerance = limits.overflowTolerancePx ?? visual_gate_defaults_const_1.DyE2E_VisualGateDefaults_Const.overflowTolerancePx;
109
+ if (layout.visibleTextLength < minText || layout.visibleElementCount < minElements) {
110
+ findings.push({
111
+ kind: 'page-empty',
112
+ message: `the page shows almost nothing: ${layout.visibleTextLength} characters, `
113
+ + `${layout.visibleElementCount} elements (at least ${minText} / ${minElements})`,
114
+ });
115
+ }
116
+ if (layout.scrollWidth > layout.viewportWidth + tolerance) {
117
+ findings.push({
118
+ kind: 'horizontal-overflow',
119
+ message: `the page is ${layout.scrollWidth} px wide on a ${layout.viewportWidth} px screen`
120
+ + (layout.widestOverflow ? `; widest: ${layout.widestOverflow}` : ''),
121
+ });
122
+ }
123
+ return findings;
124
+ }
125
+ /** The cheap checks of one page: overlays still covering it + the layout. */
126
+ static async inspect(page, limits = {}) {
127
+ const findings = (await blocking_overlays_util_1.DyE2E_BlockingOverlays_Util.findVisible(page))
128
+ .map((name) => ({
129
+ kind: 'blocking-overlay', message: `${name} covers the page (close it first: DyE2E_BlockingOverlays_Util)`,
130
+ }));
131
+ return findings.concat(this.checkLayout(await this.measureLayout(page), limits));
132
+ }
133
+ /**
134
+ * The gate for one case, inside a Playwright test: the cheap checks first (a finding fails the test with its
135
+ * reason), then the screenshot comparison against the baseline `<case id>.png`.
136
+ */
137
+ static async assertPage(page, gateCase, options = {}) {
138
+ const findings = await this.inspect(page, options);
139
+ if (findings.length) {
140
+ throw new Error(`[dynamo-e2e visual-gate] ${gateCase.id} (${page.url()}):\n`
141
+ + findings.map((finding) => `- ${finding.kind}: ${finding.message}`).join('\n'));
142
+ }
143
+ await (0, test_1.expect)(page).toHaveScreenshot(gateCase.snapshotName, {
144
+ fullPage: true,
145
+ animations: 'disabled',
146
+ caret: 'hide',
147
+ maxDiffPixelRatio: options.maxDiffPixelRatio ?? visual_gate_defaults_const_1.DyE2E_VisualGateDefaults_Const.maxDiffPixelRatio,
148
+ mask: (gateCase.page.mask ?? []).map((selector) => page.locator(selector)),
149
+ });
150
+ }
151
+ }
152
+ exports.DyE2E_VisualGate_Util = DyE2E_VisualGate_Util;
153
+ //# sourceMappingURL=visual-gate.util.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"visual-gate.util.js","sourceRoot":"","sources":["../../../../src/_modules/visual-gate/_collections/visual-gate.util.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import { DyE2E_VisualGateLanguage_Interface } from './visual-gate-language.interface';
2
+ import { DyE2E_VisualGatePage_Interface } from './visual-gate-page.interface';
3
+ import { DyE2E_VisualGateViewport_Interface } from './visual-gate-viewport.interface';
4
+ /** One check of the visual gate: a page, in one language, at one screen size. */
5
+ export interface DyE2E_VisualGateCase_Interface {
6
+ /** `<page>-<language>-<viewport>`, unique within the matrix. */
7
+ id: string;
8
+ page: DyE2E_VisualGatePage_Interface;
9
+ language: DyE2E_VisualGateLanguage_Interface;
10
+ viewport: DyE2E_VisualGateViewport_Interface;
11
+ /** The baseline file name of the screenshot comparison (`<id>.png`). */
12
+ snapshotName: string;
13
+ }
14
+ //# sourceMappingURL=visual-gate-case.interface.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"visual-gate-case.interface.d.ts","sourceRoot":"","sources":["../../../../src/_modules/visual-gate/_models/visual-gate-case.interface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kCAAkC,EAAE,MAAM,kCAAkC,CAAC;AACtF,OAAO,EAAE,8BAA8B,EAAE,MAAM,8BAA8B,CAAC;AAC9E,OAAO,EAAE,kCAAkC,EAAE,MAAM,kCAAkC,CAAC;AAEtF,iFAAiF;AACjF,MAAM,WAAW,8BAA8B;IAC7C,gEAAgE;IAChE,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,8BAA8B,CAAC;IACrC,QAAQ,EAAE,kCAAkC,CAAC;IAC7C,QAAQ,EAAE,kCAAkC,CAAC;IAC7C,wEAAwE;IACxE,YAAY,EAAE,MAAM,CAAC;CACtB"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=visual-gate-case.interface.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"visual-gate-case.interface.js","sourceRoot":"","sources":["../../../../src/_modules/visual-gate/_models/visual-gate-case.interface.ts"],"names":[],"mappings":""}
@@ -0,0 +1,11 @@
1
+ /** A reason the visual gate fails a page before (or instead of) the screenshot comparison. */
2
+ export interface DyE2E_VisualGateFinding_Interface {
3
+ /**
4
+ * `blocking-overlay`: the TEST warning or the cookie bar covers the page (the screenshot would show them);
5
+ * `page-empty`: the page shows (almost) nothing — it disappeared; `horizontal-overflow`: the page is wider than the
6
+ * screen — it fell apart.
7
+ */
8
+ kind: 'blocking-overlay' | 'page-empty' | 'horizontal-overflow';
9
+ message: string;
10
+ }
11
+ //# sourceMappingURL=visual-gate-finding.interface.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"visual-gate-finding.interface.d.ts","sourceRoot":"","sources":["../../../../src/_modules/visual-gate/_models/visual-gate-finding.interface.ts"],"names":[],"mappings":"AAAA,8FAA8F;AAC9F,MAAM,WAAW,iCAAiC;IAChD;;;;OAIG;IACH,IAAI,EAAE,kBAAkB,GAAG,YAAY,GAAG,qBAAqB,CAAC;IAChE,OAAO,EAAE,MAAM,CAAC;CACjB"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=visual-gate-finding.interface.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"visual-gate-finding.interface.js","sourceRoot":"","sources":["../../../../src/_modules/visual-gate/_models/visual-gate-finding.interface.ts"],"names":[],"mappings":""}
@@ -0,0 +1,8 @@
1
+ /** A language of the visual gate: the page is opened in a browser of this locale. */
2
+ export interface DyE2E_VisualGateLanguage_Interface {
3
+ /** Short code (`hu`, `en`) — part of the snapshot name. */
4
+ code: string;
5
+ /** The browser locale (`hu-HU`, `en-US`): the FDP language service follows it when nothing is stored. */
6
+ locale: string;
7
+ }
8
+ //# sourceMappingURL=visual-gate-language.interface.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"visual-gate-language.interface.d.ts","sourceRoot":"","sources":["../../../../src/_modules/visual-gate/_models/visual-gate-language.interface.ts"],"names":[],"mappings":"AAAA,qFAAqF;AACrF,MAAM,WAAW,kCAAkC;IACjD,2DAA2D;IAC3D,IAAI,EAAE,MAAM,CAAC;IACb,yGAAyG;IACzG,MAAM,EAAE,MAAM,CAAC;CAChB"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=visual-gate-language.interface.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"visual-gate-language.interface.js","sourceRoot":"","sources":["../../../../src/_modules/visual-gate/_models/visual-gate-language.interface.ts"],"names":[],"mappings":""}
@@ -0,0 +1,14 @@
1
+ /** What the page shows, measured in the browser (`DyE2E_VisualGate_Util.measureLayout`). */
2
+ export interface DyE2E_VisualGateLayout_Interface {
3
+ /** The width of the viewport (the document element's client width), px. */
4
+ viewportWidth: number;
5
+ /** The width of the scrollable document, px: wider than the viewport ⇒ the page scrolls sideways. */
6
+ scrollWidth: number;
7
+ /** The widest element that sticks out of the viewport (tag + class), or `null`. */
8
+ widestOverflow: string | null;
9
+ /** The number of characters of the visible text. */
10
+ visibleTextLength: number;
11
+ /** The number of visible elements with a size. */
12
+ visibleElementCount: number;
13
+ }
14
+ //# sourceMappingURL=visual-gate-layout.interface.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"visual-gate-layout.interface.d.ts","sourceRoot":"","sources":["../../../../src/_modules/visual-gate/_models/visual-gate-layout.interface.ts"],"names":[],"mappings":"AAAA,4FAA4F;AAC5F,MAAM,WAAW,gCAAgC;IAC/C,2EAA2E;IAC3E,aAAa,EAAE,MAAM,CAAC;IACtB,qGAAqG;IACrG,WAAW,EAAE,MAAM,CAAC;IACpB,mFAAmF;IACnF,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,oDAAoD;IACpD,iBAAiB,EAAE,MAAM,CAAC;IAC1B,kDAAkD;IAClD,mBAAmB,EAAE,MAAM,CAAC;CAC7B"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=visual-gate-layout.interface.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"visual-gate-layout.interface.js","sourceRoot":"","sources":["../../../../src/_modules/visual-gate/_models/visual-gate-layout.interface.ts"],"names":[],"mappings":""}
@@ -0,0 +1,10 @@
1
+ /** A key page of the product the visual gate checks (R1-72 d). */
2
+ export interface DyE2E_VisualGatePage_Interface {
3
+ /** Short, file-name safe name (`home`, `login`) — part of the snapshot name. */
4
+ name: string;
5
+ /** The path from the base URL (`/`, `/login`). */
6
+ path: string;
7
+ /** Selectors of changing parts (a date, a version number) that the screenshot comparison masks. */
8
+ mask?: string[];
9
+ }
10
+ //# sourceMappingURL=visual-gate-page.interface.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"visual-gate-page.interface.d.ts","sourceRoot":"","sources":["../../../../src/_modules/visual-gate/_models/visual-gate-page.interface.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,MAAM,WAAW,8BAA8B;IAC7C,gFAAgF;IAChF,IAAI,EAAE,MAAM,CAAC;IACb,kDAAkD;IAClD,IAAI,EAAE,MAAM,CAAC;IACb,mGAAmG;IACnG,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=visual-gate-page.interface.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"visual-gate-page.interface.js","sourceRoot":"","sources":["../../../../src/_modules/visual-gate/_models/visual-gate-page.interface.ts"],"names":[],"mappings":""}
@@ -0,0 +1,8 @@
1
+ /** A screen size of the visual gate. */
2
+ export interface DyE2E_VisualGateViewport_Interface {
3
+ /** Short name (`desktop`, `mobile`) — part of the snapshot name. */
4
+ name: string;
5
+ width: number;
6
+ height: number;
7
+ }
8
+ //# sourceMappingURL=visual-gate-viewport.interface.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"visual-gate-viewport.interface.d.ts","sourceRoot":"","sources":["../../../../src/_modules/visual-gate/_models/visual-gate-viewport.interface.ts"],"names":[],"mappings":"AAAA,wCAAwC;AACxC,MAAM,WAAW,kCAAkC;IACjD,oEAAoE;IACpE,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=visual-gate-viewport.interface.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"visual-gate-viewport.interface.js","sourceRoot":"","sources":["../../../../src/_modules/visual-gate/_models/visual-gate-viewport.interface.ts"],"names":[],"mappings":""}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * `@futdevpro/dynamo-e2e/visual-gate` — the visual regression gate (R1-72 d): close the TEST warning and the cookie
3
+ * bar, then check the key pages (HU + EN, 1440 + 390) — red when a page falls apart, disappears or changes.
4
+ * The `/vqa` layer collects evidence for a reviewer, `/ui-check` presses controls; this layer judges the look.
5
+ */
6
+ export * from './_collections/blocking-overlays.util';
7
+ export * from './_collections/visual-gate-defaults.const';
8
+ export * from './_collections/visual-gate.util';
9
+ export * from './_models/visual-gate-case.interface';
10
+ export * from './_models/visual-gate-finding.interface';
11
+ export * from './_models/visual-gate-language.interface';
12
+ export * from './_models/visual-gate-layout.interface';
13
+ export * from './_models/visual-gate-page.interface';
14
+ export * from './_models/visual-gate-viewport.interface';
15
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/_modules/visual-gate/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,cAAc,uCAAuC,CAAC;AACtD,cAAc,2CAA2C,CAAC;AAC1D,cAAc,iCAAiC,CAAC;AAChD,cAAc,sCAAsC,CAAC;AACrD,cAAc,yCAAyC,CAAC;AACxD,cAAc,0CAA0C,CAAC;AACzD,cAAc,wCAAwC,CAAC;AACvD,cAAc,sCAAsC,CAAC;AACrD,cAAc,0CAA0C,CAAC"}
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ /**
18
+ * `@futdevpro/dynamo-e2e/visual-gate` — the visual regression gate (R1-72 d): close the TEST warning and the cookie
19
+ * bar, then check the key pages (HU + EN, 1440 + 390) — red when a page falls apart, disappears or changes.
20
+ * The `/vqa` layer collects evidence for a reviewer, `/ui-check` presses controls; this layer judges the look.
21
+ */
22
+ __exportStar(require("./_collections/blocking-overlays.util"), exports);
23
+ __exportStar(require("./_collections/visual-gate-defaults.const"), exports);
24
+ __exportStar(require("./_collections/visual-gate.util"), exports);
25
+ __exportStar(require("./_models/visual-gate-case.interface"), exports);
26
+ __exportStar(require("./_models/visual-gate-finding.interface"), exports);
27
+ __exportStar(require("./_models/visual-gate-language.interface"), exports);
28
+ __exportStar(require("./_models/visual-gate-layout.interface"), exports);
29
+ __exportStar(require("./_models/visual-gate-page.interface"), exports);
30
+ __exportStar(require("./_models/visual-gate-viewport.interface"), exports);
31
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/_modules/visual-gate/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA;;;;GAIG;AACH,wEAAsD;AACtD,4EAA0D;AAC1D,kEAAgD;AAChD,uEAAqD;AACrD,0EAAwD;AACxD,2EAAyD;AACzD,yEAAuD;AACvD,uEAAqD;AACrD,2EAAyD"}
package/build/index.js CHANGED
@@ -26,5 +26,5 @@ __exportStar(require("./_modules/game/index"), exports);
26
26
  __exportStar(require("./_modules/ui-check/index"), exports);
27
27
  __exportStar(require("./_modules/coverage/index"), exports);
28
28
  /** Package-version stamp — npm-publish-time runtime-érték. */
29
- exports.DYE2E_PACKAGE_VERSION = '01.18.38';
29
+ exports.DYE2E_PACKAGE_VERSION = '01.18.39';
30
30
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@futdevpro/dynamo-e2e",
3
- "version": "01.18.38",
3
+ "version": "01.18.39",
4
4
  "description": "End-to-end testing engine for the Dynamo + FDP ecosystem — auto-generated form-coverage tests, viewport audit matrix, CWV diagnostics. Settings-POJO-first.",
5
5
  "DyBu_settings": {
6
6
  "packageType": "core-package",
@@ -102,6 +102,12 @@
102
102
  "types": "./build/_modules/ui-check/index.d.ts",
103
103
  "typings": "./build/_modules/ui-check/index.d.ts"
104
104
  },
105
+ "./visual-gate": {
106
+ "default": "./build/_modules/visual-gate/index.js",
107
+ "module": "./build/_modules/visual-gate/index.js",
108
+ "types": "./build/_modules/visual-gate/index.d.ts",
109
+ "typings": "./build/_modules/visual-gate/index.d.ts"
110
+ },
105
111
  "./game": {
106
112
  "default": "./build/_modules/game/index.js",
107
113
  "module": "./build/_modules/game/index.js",
@@ -132,6 +138,9 @@
132
138
  "ui-check": [
133
139
  "build/_modules/ui-check/index.d.ts"
134
140
  ],
141
+ "visual-gate": [
142
+ "build/_modules/visual-gate/index.d.ts"
143
+ ],
135
144
  "game": [
136
145
  "build/_modules/game/index.d.ts"
137
146
  ]