@futdevpro/dynamo-e2e 1.18.26 → 1.18.30
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.
- package/CHANGELOG.md +51 -0
- package/README.md +10 -0
- package/build/_modules/contracts/_collections/test-case-sets/password-field-test-cases.const.d.ts +4 -0
- package/build/_modules/contracts/_collections/test-case-sets/password-field-test-cases.const.d.ts.map +1 -1
- package/build/_modules/contracts/_collections/test-case-sets/password-field-test-cases.const.js +39 -3
- package/build/_modules/contracts/_collections/test-case-sets/password-field-test-cases.const.js.map +1 -1
- package/build/_modules/contracts/_enums/field-test-case-type.enum.d.ts +5 -0
- package/build/_modules/contracts/_enums/field-test-case-type.enum.d.ts.map +1 -1
- package/build/_modules/contracts/_enums/field-test-case-type.enum.js +5 -0
- package/build/_modules/contracts/_enums/field-test-case-type.enum.js.map +1 -1
- package/build/_modules/contracts/_models/interfaces/form-test-suite-settings.interface.d.ts +9 -1
- package/build/_modules/contracts/_models/interfaces/form-test-suite-settings.interface.d.ts.map +1 -1
- package/build/_modules/generators/_collections/field-emission.util.d.ts +11 -0
- package/build/_modules/generators/_collections/field-emission.util.d.ts.map +1 -1
- package/build/_modules/generators/_collections/field-emission.util.js +43 -6
- package/build/_modules/generators/_collections/field-emission.util.js.map +1 -1
- package/build/_modules/generators/_collections/form-level-emission.util.d.ts.map +1 -1
- package/build/_modules/generators/_collections/form-level-emission.util.js +5 -6
- package/build/_modules/generators/_collections/form-level-emission.util.js.map +1 -1
- package/build/_modules/generators/_collections/json-schema.util.d.ts.map +1 -1
- package/build/_modules/generators/_collections/json-schema.util.js +2 -0
- package/build/_modules/generators/_collections/json-schema.util.js.map +1 -1
- package/build/_modules/generators/_collections/test-case-filter.util.d.ts +6 -0
- package/build/_modules/generators/_collections/test-case-filter.util.d.ts.map +1 -1
- package/build/_modules/generators/_collections/test-case-filter.util.js +36 -0
- package/build/_modules/generators/_collections/test-case-filter.util.js.map +1 -1
- package/build/_modules/generators/_models/form-settings-shape.interface.d.ts +13 -0
- package/build/_modules/generators/_models/form-settings-shape.interface.d.ts.map +1 -1
- package/build/_modules/generators/form-suite.generator.d.ts.map +1 -1
- package/build/_modules/generators/form-suite.generator.js +4 -1
- package/build/_modules/generators/form-suite.generator.js.map +1 -1
- package/build/_modules/ui-check/_collections/constants/ui-check-page-scripts.const.d.ts +6 -0
- package/build/_modules/ui-check/_collections/constants/ui-check-page-scripts.const.d.ts.map +1 -0
- package/build/_modules/ui-check/_collections/constants/ui-check-page-scripts.const.js +255 -0
- package/build/_modules/ui-check/_collections/constants/ui-check-page-scripts.const.js.map +1 -0
- package/build/_modules/ui-check/_collections/detectors/dead-control.detector.d.ts +36 -0
- package/build/_modules/ui-check/_collections/detectors/dead-control.detector.d.ts.map +1 -0
- package/build/_modules/ui-check/_collections/detectors/dead-control.detector.js +133 -0
- package/build/_modules/ui-check/_collections/detectors/dead-control.detector.js.map +1 -0
- package/build/_modules/ui-check/_collections/detectors/nested-scroll.detector.d.ts +25 -0
- package/build/_modules/ui-check/_collections/detectors/nested-scroll.detector.d.ts.map +1 -0
- package/build/_modules/ui-check/_collections/detectors/nested-scroll.detector.js +47 -0
- package/build/_modules/ui-check/_collections/detectors/nested-scroll.detector.js.map +1 -0
- package/build/_modules/ui-check/_collections/detectors/non-toggling-control.detector.d.ts +33 -0
- package/build/_modules/ui-check/_collections/detectors/non-toggling-control.detector.d.ts.map +1 -0
- package/build/_modules/ui-check/_collections/detectors/non-toggling-control.detector.js +119 -0
- package/build/_modules/ui-check/_collections/detectors/non-toggling-control.detector.js.map +1 -0
- package/build/_modules/ui-check/_collections/ui-check-default-detectors.const.d.ts +20 -0
- package/build/_modules/ui-check/_collections/ui-check-default-detectors.const.d.ts.map +1 -0
- package/build/_modules/ui-check/_collections/ui-check-default-detectors.const.js +30 -0
- package/build/_modules/ui-check/_collections/ui-check-default-detectors.const.js.map +1 -0
- package/build/_modules/ui-check/_collections/ui-check-guard.util.d.ts +60 -0
- package/build/_modules/ui-check/_collections/ui-check-guard.util.d.ts.map +1 -0
- package/build/_modules/ui-check/_collections/ui-check-guard.util.js +144 -0
- package/build/_modules/ui-check/_collections/ui-check-guard.util.js.map +1 -0
- package/build/_modules/ui-check/_collections/ui-check-page.util.d.ts +80 -0
- package/build/_modules/ui-check/_collections/ui-check-page.util.d.ts.map +1 -0
- package/build/_modules/ui-check/_collections/ui-check-page.util.js +195 -0
- package/build/_modules/ui-check/_collections/ui-check-page.util.js.map +1 -0
- package/build/_modules/ui-check/_collections/ui-check-runner.util.d.ts +41 -0
- package/build/_modules/ui-check/_collections/ui-check-runner.util.d.ts.map +1 -0
- package/build/_modules/ui-check/_collections/ui-check-runner.util.js +146 -0
- package/build/_modules/ui-check/_collections/ui-check-runner.util.js.map +1 -0
- package/build/_modules/ui-check/_models/ui-check-context.interface.d.ts +39 -0
- package/build/_modules/ui-check/_models/ui-check-context.interface.d.ts.map +1 -0
- package/build/_modules/ui-check/_models/ui-check-context.interface.js +3 -0
- package/build/_modules/ui-check/_models/ui-check-context.interface.js.map +1 -0
- package/build/_modules/ui-check/_models/ui-check-detector.interface.d.ts +32 -0
- package/build/_modules/ui-check/_models/ui-check-detector.interface.d.ts.map +1 -0
- package/build/_modules/ui-check/_models/ui-check-detector.interface.js +3 -0
- package/build/_modules/ui-check/_models/ui-check-detector.interface.js.map +1 -0
- package/build/_modules/ui-check/_models/ui-check-finding.interface.d.ts +30 -0
- package/build/_modules/ui-check/_models/ui-check-finding.interface.d.ts.map +1 -0
- package/build/_modules/ui-check/_models/ui-check-finding.interface.js +3 -0
- package/build/_modules/ui-check/_models/ui-check-finding.interface.js.map +1 -0
- package/build/_modules/ui-check/_models/ui-check-report.interface.d.ts +38 -0
- package/build/_modules/ui-check/_models/ui-check-report.interface.d.ts.map +1 -0
- package/build/_modules/ui-check/_models/ui-check-report.interface.js +3 -0
- package/build/_modules/ui-check/_models/ui-check-report.interface.js.map +1 -0
- package/build/_modules/ui-check/index.d.ts +27 -0
- package/build/_modules/ui-check/index.d.ts.map +1 -0
- package/build/_modules/ui-check/index.js +43 -0
- package/build/_modules/ui-check/index.js.map +1 -0
- package/build/index.d.ts +1 -0
- package/build/index.d.ts.map +1 -1
- package/build/index.js +2 -1
- package/build/index.js.map +1 -1
- package/package.json +10 -1
|
@@ -0,0 +1,195 @@
|
|
|
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
|
+
/** Length a reported console error is cut to — AFTER the guard filter (cut first, the filter misses the tail). */
|
|
15
|
+
static maxErrorLength = 200;
|
|
16
|
+
/**
|
|
17
|
+
* The browser page itself crashed (renderer out of memory, killed) — the measurement's failure, not a finding.
|
|
18
|
+
* Measured (QA-1 round 128, Adventor `/preset-library`): 2 of 3 long detector runs; the 13 controls pressed one by
|
|
19
|
+
* one WITHOUT the detector did not crash it. After a renderer crash Playwright reports the page as CLOSED on the next
|
|
20
|
+
* call (measured with CDP `Page.crash`), so that text belongs here too.
|
|
21
|
+
*/
|
|
22
|
+
static pageCrashError = /Target crashed|Page crashed|Target page, context or browser has been closed/i;
|
|
23
|
+
/** Whether `error` says that the page crashed. */
|
|
24
|
+
static isPageCrash(error) {
|
|
25
|
+
return DyE2E_UICheckPage_Util.pageCrashError.test(error instanceof Error ? error.message : String(error));
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Whether a console error was caused by the guard's own abort: an abort-type text, or the text names the path of a
|
|
29
|
+
* request the guard aborted. QA-1 round 128 (Adventor "Download my data"): the product logged
|
|
30
|
+
* `DyNX_ApiService call "newPrivacyExportRequest" ERROR: Http failure response for https://…/privacy-request/new/…: 0
|
|
31
|
+
* Unknown Error` — the text was cut to 200 characters BEFORE this check, so "Unknown Error" was lost and the guard's
|
|
32
|
+
* own abort was reported as the product's console error.
|
|
33
|
+
*/
|
|
34
|
+
static isGuardInducedError(text, aborted) {
|
|
35
|
+
if (!aborted.length) {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
if (DyE2E_UICheckPage_Util.guardInducedError.test(text)) {
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
return aborted.some((entry) => {
|
|
42
|
+
const url = entry.split(' ')[1] ?? '';
|
|
43
|
+
let pathname = url;
|
|
44
|
+
try {
|
|
45
|
+
pathname = new URL(url).pathname;
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
// a non-URL entry (a mocked socket message): its whole text is matched
|
|
49
|
+
}
|
|
50
|
+
return pathname.length > 1 && text.includes(pathname);
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
/** Runs one of `DyE2E_UICheckPageScripts_Const` in the page. */
|
|
54
|
+
static async evaluate(page, script, arg) {
|
|
55
|
+
return page.evaluate(`(${script})(${arg === undefined ? '' : JSON.stringify(arg)})`);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Loads the page under check fresh, waits until it settled, and runs `context.prepare`. The console errors the page
|
|
59
|
+
* logs WITHOUT any press are added to `background` — a press is not blamed for them.
|
|
60
|
+
*/
|
|
61
|
+
static async reload(page, context, background) {
|
|
62
|
+
const onConsole = (message) => {
|
|
63
|
+
if (message.type() === 'error') {
|
|
64
|
+
background?.add(DyE2E_UICheckPage_Util.errorSignature(message.text()));
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
page.on('console', onConsole);
|
|
68
|
+
try {
|
|
69
|
+
await page.goto(context.url, { waitUntil: 'load' });
|
|
70
|
+
await page.waitForLoadState('networkidle', { timeout: 5_000 }).catch(() => undefined);
|
|
71
|
+
await page.waitForTimeout(context.settleMs ?? DyE2E_UICheckPage_Util.defaultSettleMs);
|
|
72
|
+
if (context.prepare) {
|
|
73
|
+
await context.prepare(page);
|
|
74
|
+
await page.waitForTimeout(context.settleMs ?? DyE2E_UICheckPage_Util.defaultSettleMs);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
finally {
|
|
78
|
+
page.off('console', onConsole);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/** A console error without its volatile parts (numbers, ids), so a repeating background error matches itself. */
|
|
82
|
+
static errorSignature(text) {
|
|
83
|
+
return text.replace(/[0-9a-f]{8,}/gi, '#').replace(/\d+/g, '#').trim().slice(0, 160);
|
|
84
|
+
}
|
|
85
|
+
/** The identity of a control across reloads (its CSS path may shift when an earlier press changed the page). */
|
|
86
|
+
static signature(control) {
|
|
87
|
+
return [control.tag, control.testId ?? '', control.ariaLabel ?? '', control.text].join('|');
|
|
88
|
+
}
|
|
89
|
+
/** The first line of a press error, plus the Playwright call-log line that names the cause (e.g. what covers it). */
|
|
90
|
+
static describePressError(error) {
|
|
91
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
92
|
+
const lines = message.split('\n');
|
|
93
|
+
const cause = lines.find((line) => /intercepts pointer events|not visible|not enabled|not stable|detached|outside of the viewport/.test(line));
|
|
94
|
+
return (lines[0] + (cause ? ' — ' + cause.trim() : '')).slice(0, 400);
|
|
95
|
+
}
|
|
96
|
+
/** The visible, enabled controls of one kind, minus the denied ones (returned separately). */
|
|
97
|
+
static async listControls(page, context, kind) {
|
|
98
|
+
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 });
|
|
99
|
+
const controls = [];
|
|
100
|
+
const denied = [];
|
|
101
|
+
for (const control of all) {
|
|
102
|
+
const label = [control.text, control.ariaLabel, control.title, control.testId].filter(Boolean).join(' ');
|
|
103
|
+
(ui_check_guard_util_1.DyE2E_UICheckGuard_Util.isDenied(label, context, control.destructive) ? denied : controls).push(control);
|
|
104
|
+
}
|
|
105
|
+
return { controls: controls.slice(0, context.maxControls ?? DyE2E_UICheckPage_Util.defaultMaxControls),
|
|
106
|
+
denied: denied };
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Presses `selector` with every effect channel watched: URL, meaningful DOM mutations, requests (started — the
|
|
110
|
+
* guard aborts the mutating ones), popups, downloads, native dialogs, console errors.
|
|
111
|
+
*/
|
|
112
|
+
static async press(page, selector, guard, context, background = new Set()) {
|
|
113
|
+
const consoleErrors = [];
|
|
114
|
+
let popups = 0;
|
|
115
|
+
let downloads = 0;
|
|
116
|
+
let nativeDialogs = 0;
|
|
117
|
+
const onConsole = (message) => {
|
|
118
|
+
if (message.type() === 'error') {
|
|
119
|
+
consoleErrors.push(message.text());
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
const onPageError = (error) => {
|
|
123
|
+
consoleErrors.push('uncaught: ' + error.message);
|
|
124
|
+
};
|
|
125
|
+
const onPopup = () => {
|
|
126
|
+
popups++;
|
|
127
|
+
};
|
|
128
|
+
const onDownload = (download) => {
|
|
129
|
+
downloads++;
|
|
130
|
+
download.cancel().catch(() => undefined);
|
|
131
|
+
};
|
|
132
|
+
const onDialog = (dialog) => {
|
|
133
|
+
nativeDialogs++;
|
|
134
|
+
dialog.dismiss().catch(() => undefined);
|
|
135
|
+
};
|
|
136
|
+
page.on('console', onConsole);
|
|
137
|
+
page.on('pageerror', onPageError);
|
|
138
|
+
page.on('popup', onPopup);
|
|
139
|
+
page.on('download', onDownload);
|
|
140
|
+
page.on('dialog', onDialog);
|
|
141
|
+
const urlBefore = page.url();
|
|
142
|
+
let pressError = null;
|
|
143
|
+
await DyE2E_UICheckPage_Util.evaluate(page, ui_check_page_scripts_const_1.DyE2E_UICheckPageScripts_Const['startMutationWatch']);
|
|
144
|
+
guard.reset();
|
|
145
|
+
try {
|
|
146
|
+
await page.locator(selector).first().click({ timeout: 3_000 });
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
// a crashed page is the measurement's failure: it must not become a "not pressable" finding
|
|
150
|
+
if (DyE2E_UICheckPage_Util.isPageCrash(error)) {
|
|
151
|
+
throw error;
|
|
152
|
+
}
|
|
153
|
+
pressError = DyE2E_UICheckPage_Util.describePressError(error);
|
|
154
|
+
}
|
|
155
|
+
await page.waitForTimeout(context.settleMs ?? DyE2E_UICheckPage_Util.defaultSettleMs);
|
|
156
|
+
const urlAfter = page.url();
|
|
157
|
+
const watch = await DyE2E_UICheckPage_Util.evaluate(page, ui_check_page_scripts_const_1.DyE2E_UICheckPageScripts_Const['readMutationWatch'])
|
|
158
|
+
.catch(() => ({ count: -1, samples: ['the page navigated away'] }));
|
|
159
|
+
page.off('console', onConsole);
|
|
160
|
+
page.off('pageerror', onPageError);
|
|
161
|
+
page.off('popup', onPopup);
|
|
162
|
+
page.off('download', onDownload);
|
|
163
|
+
page.off('dialog', onDialog);
|
|
164
|
+
// the guard's own aborts surface as console errors too (`ERR_BLOCKED_BY_CLIENT`, a failed fetch, an HTTP status 0)
|
|
165
|
+
// ⇒ those are the measurement's, not the product's, and are dropped while something was aborted
|
|
166
|
+
// …and an error the page also logs without any press is background noise, not the press's
|
|
167
|
+
const productErrors = consoleErrors
|
|
168
|
+
.filter((text) => !DyE2E_UICheckPage_Util.isGuardInducedError(text, guard.log.aborted))
|
|
169
|
+
.filter((text) => !background.has(DyE2E_UICheckPage_Util.errorSignature(text)))
|
|
170
|
+
.map((text) => text.slice(0, DyE2E_UICheckPage_Util.maxErrorLength));
|
|
171
|
+
const hadEffect = urlAfter !== urlBefore || watch.count !== 0 || guard.log.started > 0 || popups > 0
|
|
172
|
+
|| downloads > 0 || nativeDialogs > 0;
|
|
173
|
+
return {
|
|
174
|
+
pressError: pressError,
|
|
175
|
+
urlBefore: urlBefore,
|
|
176
|
+
urlAfter: urlAfter,
|
|
177
|
+
mutations: watch.count,
|
|
178
|
+
mutationSamples: watch.samples,
|
|
179
|
+
requests: guard.log.started,
|
|
180
|
+
abortedRequests: [...guard.log.aborted],
|
|
181
|
+
popups: popups,
|
|
182
|
+
downloads: downloads,
|
|
183
|
+
nativeDialogs: nativeDialogs,
|
|
184
|
+
consoleErrors: productErrors,
|
|
185
|
+
hadEffect: hadEffect,
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
/** The target part of a finding, from a listed control. */
|
|
189
|
+
static toTarget(control) {
|
|
190
|
+
return { selector: control.selector, tag: control.tag, text: control.text, testId: control.testId,
|
|
191
|
+
ariaLabel: control.ariaLabel };
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
exports.DyE2E_UICheckPage_Util = DyE2E_UICheckPage_Util;
|
|
195
|
+
//# sourceMappingURL=ui-check-page.util.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui-check-page.util.js","sourceRoot":"","sources":["../../../../src/_modules/ui-check/_collections/ui-check-page.util.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Page } from '@playwright/test';
|
|
2
|
+
import { DyE2E_UICheckContext_Interface } from '../_models/ui-check-context.interface';
|
|
3
|
+
import { DyE2E_UICheckDetector_Interface } from '../_models/ui-check-detector.interface';
|
|
4
|
+
import { DyE2E_UICheckFinding_Interface } from '../_models/ui-check-finding.interface';
|
|
5
|
+
import { DyE2E_UICheckReport_Interface, DyE2E_UICheckWaiver_Interface } from '../_models/ui-check-report.interface';
|
|
6
|
+
/** Options of one UI check run. */
|
|
7
|
+
export interface DyE2E_UICheckRunOptions_Interface {
|
|
8
|
+
/** The detectors to run (default: the whole default list). Extend it, do not shrink it — waive instead. */
|
|
9
|
+
detectors?: DyE2E_UICheckDetector_Interface[];
|
|
10
|
+
/** Coded, dated exceptions for known findings. */
|
|
11
|
+
waivers?: DyE2E_UICheckWaiver_Interface[];
|
|
12
|
+
/** "Today" for the waiver expiry (`YYYY-MM-DD`, default: the current UTC date). */
|
|
13
|
+
today?: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Runs the UI detectors on one page and returns VERDICTS (BFR-FLEET-012). The page is expected on `context.url`.
|
|
17
|
+
* Measuring detectors run first (on the page as loaded), interactive ones after them (each reloads the page).
|
|
18
|
+
* A crashed detector is a failed check; a finding is suppressed only by a valid, unexpired, coded waiver.
|
|
19
|
+
*
|
|
20
|
+
* ```ts
|
|
21
|
+
* const report = await DyE2E_UICheckRunner_Util.run(page, { url: page.url(), accountKind: 'anonymous' });
|
|
22
|
+
* DyE2E_UICheckRunner_Util.assertClean(report);
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export declare class DyE2E_UICheckRunner_Util {
|
|
26
|
+
/** A waiver's trace code. */
|
|
27
|
+
static readonly waiverCodePattern: RegExp;
|
|
28
|
+
/** Runs the check — see the class doc. */
|
|
29
|
+
static run(page: Page, context: DyE2E_UICheckContext_Interface, options?: DyE2E_UICheckRunOptions_Interface): Promise<DyE2E_UICheckReport_Interface>;
|
|
30
|
+
/** Throws (with the formatted report) when the report has a finding or a crashed detector. */
|
|
31
|
+
static assertClean(report: DyE2E_UICheckReport_Interface): void;
|
|
32
|
+
/** The report as readable text — findings, crashes, waived and expired waivers, each with its measurement. */
|
|
33
|
+
static format(report: DyE2E_UICheckReport_Interface): string;
|
|
34
|
+
/** Throws for a waiver without a trace code, a reason or a valid expiry date. */
|
|
35
|
+
static validateWaivers(waivers: DyE2E_UICheckWaiver_Interface[]): void;
|
|
36
|
+
/** The target of a finding in one line: selector, text, test id, label. */
|
|
37
|
+
static describeTarget(finding: DyE2E_UICheckFinding_Interface): string;
|
|
38
|
+
/** Whether `waiver` applies to `finding`. */
|
|
39
|
+
private static waiverMatches;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=ui-check-runner.util.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui-check-runner.util.d.ts","sourceRoot":"","sources":["../../../../src/_modules/ui-check/_collections/ui-check-runner.util.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAExC,OAAO,EAAE,8BAA8B,EAAE,MAAM,uCAAuC,CAAC;AACvF,OAAO,EAAE,+BAA+B,EAAE,MAAM,wCAAwC,CAAC;AACzF,OAAO,EAAE,8BAA8B,EAAE,MAAM,uCAAuC,CAAC;AACvF,OAAO,EACL,6BAA6B,EAE7B,6BAA6B,EAC9B,MAAM,sCAAsC,CAAC;AAK9C,mCAAmC;AACnC,MAAM,WAAW,iCAAiC;IAChD,2GAA2G;IAC3G,SAAS,CAAC,EAAE,+BAA+B,EAAE,CAAC;IAC9C,kDAAkD;IAClD,OAAO,CAAC,EAAE,6BAA6B,EAAE,CAAC;IAC1C,mFAAmF;IACnF,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;GASG;AACH,qBAAa,wBAAwB;IAEnC,6BAA6B;IAC7B,MAAM,CAAC,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAmC;IAE5E,0CAA0C;WAC7B,GAAG,CACd,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,8BAA8B,EACvC,OAAO,GAAE,iCAAsC,GAC9C,OAAO,CAAC,6BAA6B,CAAC;IA8DzC,8FAA8F;IAC9F,MAAM,CAAC,WAAW,CAAC,MAAM,EAAE,6BAA6B,GAAG,IAAI;IAM/D,8GAA8G;IAC9G,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,6BAA6B,GAAG,MAAM;IA0B5D,iFAAiF;IACjF,MAAM,CAAC,eAAe,CAAC,OAAO,EAAE,6BAA6B,EAAE,GAAG,IAAI;IAuBtE,2EAA2E;IAC3E,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,8BAA8B,GAAG,MAAM;IAOtE,6CAA6C;IAC7C,OAAO,CAAC,MAAM,CAAC,aAAa;CAY7B"}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DyE2E_UICheckRunner_Util = void 0;
|
|
4
|
+
const ui_check_default_detectors_const_1 = require("./ui-check-default-detectors.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
|
+
* Runs the UI detectors on one page and returns VERDICTS (BFR-FLEET-012). The page is expected on `context.url`.
|
|
9
|
+
* Measuring detectors run first (on the page as loaded), interactive ones after them (each reloads the page).
|
|
10
|
+
* A crashed detector is a failed check; a finding is suppressed only by a valid, unexpired, coded waiver.
|
|
11
|
+
*
|
|
12
|
+
* ```ts
|
|
13
|
+
* const report = await DyE2E_UICheckRunner_Util.run(page, { url: page.url(), accountKind: 'anonymous' });
|
|
14
|
+
* DyE2E_UICheckRunner_Util.assertClean(report);
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
class DyE2E_UICheckRunner_Util {
|
|
18
|
+
/** A waiver's trace code. */
|
|
19
|
+
static waiverCodePattern = /^(BL|BFR|BUG|CFR)-[A-Z0-9-]+$/;
|
|
20
|
+
/** Runs the check — see the class doc. */
|
|
21
|
+
static async run(page, context, options = {}) {
|
|
22
|
+
const detectors = options.detectors ?? [...ui_check_default_detectors_const_1.DyE2E_UICheckDefaultDetectors_Const];
|
|
23
|
+
const waivers = options.waivers ?? [];
|
|
24
|
+
const today = options.today ?? new Date().toISOString().slice(0, 10);
|
|
25
|
+
DyE2E_UICheckRunner_Util.validateWaivers(waivers);
|
|
26
|
+
// the guard fails the WHOLE run before the page is touched
|
|
27
|
+
detectors.filter((d) => d.interactive)
|
|
28
|
+
.forEach((d) => ui_check_guard_util_1.DyE2E_UICheckGuard_Util.assertInteractiveAllowed(context, d.id));
|
|
29
|
+
const ordered = [
|
|
30
|
+
...detectors.filter((d) => !d.interactive),
|
|
31
|
+
...detectors.filter((d) => d.interactive),
|
|
32
|
+
];
|
|
33
|
+
const report = {
|
|
34
|
+
url: context.url, detectorsRun: [], findings: [], waived: [], expiredWaivers: [], errors: [], notes: [],
|
|
35
|
+
};
|
|
36
|
+
const active = waivers.filter((w) => w.expires >= today);
|
|
37
|
+
report.expiredWaivers = waivers.filter((w) => w.expires < today);
|
|
38
|
+
let current = page;
|
|
39
|
+
for (const detector of ordered) {
|
|
40
|
+
report.detectorsRun.push(detector.id);
|
|
41
|
+
try {
|
|
42
|
+
let found;
|
|
43
|
+
try {
|
|
44
|
+
found = await detector.run(current, context);
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
// QA-1 round 128 (Adventor `/preset-library`): the PAGE crashed under a long detector run (2 of 3 runs), and the
|
|
48
|
+
// crash was reported like a finding. A crash is the measurement's failure: noted, and the detector runs ONCE
|
|
49
|
+
// more on a fresh page of the same context; a second crash is a crashed detector (visible, as before).
|
|
50
|
+
if (!ui_check_page_util_1.DyE2E_UICheckPage_Util.isPageCrash(error)) {
|
|
51
|
+
throw error;
|
|
52
|
+
}
|
|
53
|
+
report.notes.push(`${detector.id}: the measurement page crashed (${(error instanceof Error ? error.message
|
|
54
|
+
: String(error)).split('\n')[0].slice(0, 160)}) — not a product finding; re-run once on a fresh page`);
|
|
55
|
+
current = await current.context().newPage();
|
|
56
|
+
found = await detector.run(current, context);
|
|
57
|
+
}
|
|
58
|
+
for (const finding of found) {
|
|
59
|
+
const waiver = active.find((w) => DyE2E_UICheckRunner_Util.waiverMatches(w, finding));
|
|
60
|
+
if (waiver) {
|
|
61
|
+
report.waived.push({ finding: finding, waiver: waiver });
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
report.findings.push(finding);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
report.notes.push(...(detector.notes ?? []).map((note) => `${detector.id}: ${note}`));
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
report.errors.push({ detector: detector.id,
|
|
71
|
+
message: error instanceof Error ? (error.stack ?? error.message) : String(error) });
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return report;
|
|
75
|
+
}
|
|
76
|
+
/** Throws (with the formatted report) when the report has a finding or a crashed detector. */
|
|
77
|
+
static assertClean(report) {
|
|
78
|
+
if (report.findings.length || report.errors.length) {
|
|
79
|
+
throw new Error(DyE2E_UICheckRunner_Util.format(report));
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/** The report as readable text — findings, crashes, waived and expired waivers, each with its measurement. */
|
|
83
|
+
static format(report) {
|
|
84
|
+
const lines = [`UI check of ${report.url} — detectors: ${report.detectorsRun.join(', ')}`,
|
|
85
|
+
`${report.findings.length} finding(s), ${report.errors.length} crashed detector(s), ` +
|
|
86
|
+
`${report.waived.length} waived, ${report.expiredWaivers.length} expired waiver(s), ${report.notes.length} note(s)`];
|
|
87
|
+
report.findings.forEach((f, i) => {
|
|
88
|
+
lines.push(` ${i + 1}. [${f.detector} / ${f.errorClass}] ${DyE2E_UICheckRunner_Util.describeTarget(f)}`, ` measured: ${f.measured}`, ` expected: ${f.expected}`);
|
|
89
|
+
});
|
|
90
|
+
report.errors.forEach((e) => {
|
|
91
|
+
lines.push(` ✖ ${e.detector} crashed: ${e.message.split('\n').slice(0, 3).join(' / ')}`);
|
|
92
|
+
});
|
|
93
|
+
report.waived.forEach((w) => {
|
|
94
|
+
lines.push(` ~ waived (${w.waiver.code}, until ${w.waiver.expires}): [${w.finding.detector}] ` +
|
|
95
|
+
`${DyE2E_UICheckRunner_Util.describeTarget(w.finding)}`);
|
|
96
|
+
});
|
|
97
|
+
report.notes.forEach((note) => {
|
|
98
|
+
lines.push(` ? ${note}`);
|
|
99
|
+
});
|
|
100
|
+
report.expiredWaivers.forEach((w) => {
|
|
101
|
+
lines.push(` ! expired waiver ${w.code} (${w.detector}, expired ${w.expires}) — no longer applied`);
|
|
102
|
+
});
|
|
103
|
+
return lines.join('\n');
|
|
104
|
+
}
|
|
105
|
+
/** Throws for a waiver without a trace code, a reason or a valid expiry date. */
|
|
106
|
+
static validateWaivers(waivers) {
|
|
107
|
+
for (const waiver of waivers) {
|
|
108
|
+
const problems = [];
|
|
109
|
+
if (!DyE2E_UICheckRunner_Util.waiverCodePattern.test(waiver.code ?? '')) {
|
|
110
|
+
problems.push('code must be a BL- / BFR- / BUG- / CFR- trace code');
|
|
111
|
+
}
|
|
112
|
+
if (!(waiver.reason ?? '').trim()) {
|
|
113
|
+
problems.push('reason is empty');
|
|
114
|
+
}
|
|
115
|
+
if (!/^\d{4}-\d{2}-\d{2}$/.test(waiver.expires ?? '') || isNaN(Date.parse(waiver.expires))) {
|
|
116
|
+
problems.push('expires must be a YYYY-MM-DD date');
|
|
117
|
+
}
|
|
118
|
+
if (!(waiver.detector ?? '').trim()) {
|
|
119
|
+
problems.push('detector is empty');
|
|
120
|
+
}
|
|
121
|
+
if (problems.length) {
|
|
122
|
+
throw new Error(`Invalid UI-check waiver ${JSON.stringify(waiver)}: ${problems.join('; ')} — a detector is ` +
|
|
123
|
+
'never switched off silently (BFR-FLEET-012).');
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
/** The target of a finding in one line: selector, text, test id, label. */
|
|
128
|
+
static describeTarget(finding) {
|
|
129
|
+
const t = finding.target;
|
|
130
|
+
return [t.selector, t.text ? `"${t.text}"` : '', t.testId ? `[data-testid=${t.testId}]` : '',
|
|
131
|
+
t.ariaLabel ? `(aria-label "${t.ariaLabel}")` : ''].filter(Boolean).join(' ');
|
|
132
|
+
}
|
|
133
|
+
/** Whether `waiver` applies to `finding`. */
|
|
134
|
+
static waiverMatches(waiver, finding) {
|
|
135
|
+
if (waiver.detector !== finding.detector) {
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
if (!waiver.target) {
|
|
139
|
+
return true;
|
|
140
|
+
}
|
|
141
|
+
return [finding.target.selector, finding.target.text, finding.target.testId ?? '']
|
|
142
|
+
.some((value) => value.includes(waiver.target));
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
exports.DyE2E_UICheckRunner_Util = DyE2E_UICheckRunner_Util;
|
|
146
|
+
//# sourceMappingURL=ui-check-runner.util.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui-check-runner.util.js","sourceRoot":"","sources":["../../../../src/_modules/ui-check/_collections/ui-check-runner.util.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Page } from '@playwright/test';
|
|
2
|
+
/** Who is logged in while an interactive detector presses controls. */
|
|
3
|
+
export type DyE2E_UICheckAccount_Type = 'anonymous' | 'throwaway';
|
|
4
|
+
/**
|
|
5
|
+
* The page a UI check runs on, and the safety limits of the run.
|
|
6
|
+
*
|
|
7
|
+
* Interactive detectors (they press controls) run ONLY on a test host (`test.*`, `*.test`, `localhost`, … or
|
|
8
|
+
* `allowHosts`), and only anonymously or with a throwaway account — the runner refuses anything else.
|
|
9
|
+
*/
|
|
10
|
+
export interface DyE2E_UICheckContext_Interface {
|
|
11
|
+
/** The page under check — interactive detectors reload it before every press. */
|
|
12
|
+
url: string;
|
|
13
|
+
/** Declared by the caller: `throwaway` = an account created for this run and deleted afterwards. */
|
|
14
|
+
accountKind: DyE2E_UICheckAccount_Type;
|
|
15
|
+
/** Extra hosts treated as test hosts (exact match). */
|
|
16
|
+
allowHosts?: string[];
|
|
17
|
+
/** At most this many controls are pressed per detector and page (default 60). */
|
|
18
|
+
maxControls?: number;
|
|
19
|
+
/** Wait after a press before the effect is read, ms (default 600). */
|
|
20
|
+
settleMs?: number;
|
|
21
|
+
/** Controls whose text / label / test id matches any of these are never pressed (added to the default list). */
|
|
22
|
+
extraDenyPatterns?: RegExp[];
|
|
23
|
+
/**
|
|
24
|
+
* Mutating requests (non-GET) are ABORTED by default during a press — the press is still counted as an effect.
|
|
25
|
+
* A request whose URL matches one of these is let through, unless it hits the hard deny list (payment, e-mail) or
|
|
26
|
+
* carries a non-reserved e-mail address in its body.
|
|
27
|
+
*/
|
|
28
|
+
mutationAllow?: RegExp[];
|
|
29
|
+
/** Own e-mail domains that may appear in a let-through request body (besides the reserved ones). */
|
|
30
|
+
ownEmailDomains?: string[];
|
|
31
|
+
/**
|
|
32
|
+
* Runs after every (re)load, before anything is listed or pressed — closes the ENTRY dialogs a returning user no
|
|
33
|
+
* longer sees (an environment notice, a cookie banner). While a modal dialog stays open, only its controls count.
|
|
34
|
+
*/
|
|
35
|
+
prepare?: (page: Page) => Promise<void>;
|
|
36
|
+
/** Every press (and what it caused) is written into the report notes — for debugging a detector on a real page. */
|
|
37
|
+
trace?: boolean;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=ui-check-context.interface.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui-check-context.interface.d.ts","sourceRoot":"","sources":["../../../../src/_modules/ui-check/_models/ui-check-context.interface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAExC,uEAAuE;AACvE,MAAM,MAAM,yBAAyB,GAAG,WAAW,GAAG,WAAW,CAAC;AAElE;;;;;GAKG;AACH,MAAM,WAAW,8BAA8B;IAC7C,iFAAiF;IACjF,GAAG,EAAE,MAAM,CAAC;IACZ,oGAAoG;IACpG,WAAW,EAAE,yBAAyB,CAAC;IACvC,uDAAuD;IACvD,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,iFAAiF;IACjF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,sEAAsE;IACtE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gHAAgH;IAChH,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,oGAAoG;IACpG,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B;;;OAGG;IACH,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACxC,mHAAmH;IACnH,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui-check-context.interface.js","sourceRoot":"","sources":["../../../../src/_modules/ui-check/_models/ui-check-context.interface.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Page } from '@playwright/test';
|
|
2
|
+
import { DyE2E_UICheckContext_Interface } from './ui-check-context.interface';
|
|
3
|
+
import { DyE2E_UICheckFinding_Interface } from './ui-check-finding.interface';
|
|
4
|
+
/** The human-found defect a detector was written for — every detector starts from one (BFR-FLEET-012). */
|
|
5
|
+
export interface DyE2E_UICheckOrigin_Interface {
|
|
6
|
+
/** The defect's trace code (BL / BFR / BUG). */
|
|
7
|
+
code: string;
|
|
8
|
+
/** Who identified it (owner, QA, a tester). */
|
|
9
|
+
foundBy: string;
|
|
10
|
+
/** When (ISO date). */
|
|
11
|
+
date: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* One scripted, per-error-class UI detector. It returns VERDICTS: an empty list means the page is clean for this
|
|
15
|
+
* error class. A detector is added to the default list only after it caught the real, human-identified defect and
|
|
16
|
+
* stayed silent on the fixed version.
|
|
17
|
+
*/
|
|
18
|
+
export interface DyE2E_UICheckDetector_Interface {
|
|
19
|
+
/** Stable id, kebab-case. */
|
|
20
|
+
id: string;
|
|
21
|
+
/** The error class it detects. */
|
|
22
|
+
errorClass: string;
|
|
23
|
+
/** One sentence: what the detector measures. */
|
|
24
|
+
description: string;
|
|
25
|
+
origin: DyE2E_UICheckOrigin_Interface;
|
|
26
|
+
/** It presses controls ⇒ test host + anonymous / throwaway account only. */
|
|
27
|
+
interactive: boolean;
|
|
28
|
+
/** What the last run could not measure (a skipped control, a page that changed) — copied into the report. */
|
|
29
|
+
notes?: string[];
|
|
30
|
+
run(page: Page, context: DyE2E_UICheckContext_Interface): Promise<DyE2E_UICheckFinding_Interface[]>;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=ui-check-detector.interface.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui-check-detector.interface.d.ts","sourceRoot":"","sources":["../../../../src/_modules/ui-check/_models/ui-check-detector.interface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAExC,OAAO,EAAE,8BAA8B,EAAE,MAAM,8BAA8B,CAAC;AAC9E,OAAO,EAAE,8BAA8B,EAAE,MAAM,8BAA8B,CAAC;AAE9E,0GAA0G;AAC1G,MAAM,WAAW,6BAA6B;IAC5C,gDAAgD;IAChD,IAAI,EAAE,MAAM,CAAC;IACb,+CAA+C;IAC/C,OAAO,EAAE,MAAM,CAAC;IAChB,uBAAuB;IACvB,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;GAIG;AACH,MAAM,WAAW,+BAA+B;IAC9C,6BAA6B;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,kCAAkC;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,gDAAgD;IAChD,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,6BAA6B,CAAC;IACtC,4EAA4E;IAC5E,WAAW,EAAE,OAAO,CAAC;IACrB,6GAA6G;IAC7G,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,8BAA8B,GAAG,OAAO,CAAC,8BAA8B,EAAE,CAAC,CAAC;CACrG"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui-check-detector.interface.js","sourceRoot":"","sources":["../../../../src/_modules/ui-check/_models/ui-check-detector.interface.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/** The control or region a UI-check finding points at — enough to find it again without a screenshot. */
|
|
2
|
+
export interface DyE2E_UICheckTarget_Interface {
|
|
3
|
+
/** A unique CSS path in the page (re-resolvable after a reload). */
|
|
4
|
+
selector: string;
|
|
5
|
+
tag: string;
|
|
6
|
+
/** Whitespace-collapsed visible text, capped at 120 chars. */
|
|
7
|
+
text: string;
|
|
8
|
+
testId: string | null;
|
|
9
|
+
ariaLabel: string | null;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* One UI-check finding: a VERDICT (this is a defect of the detector's error class), not evidence for a reviewer.
|
|
13
|
+
* It carries what was measured and what the correct behaviour would have been (`core-error-debuggable`).
|
|
14
|
+
*/
|
|
15
|
+
export interface DyE2E_UICheckFinding_Interface {
|
|
16
|
+
/** The detector id (e.g. `dead-control`). */
|
|
17
|
+
detector: string;
|
|
18
|
+
/** The error class of the detector (e.g. `control-without-effect`). */
|
|
19
|
+
errorClass: string;
|
|
20
|
+
/** The page the finding was measured on. */
|
|
21
|
+
url: string;
|
|
22
|
+
target: DyE2E_UICheckTarget_Interface;
|
|
23
|
+
/** What was measured, in one sentence. */
|
|
24
|
+
measured: string;
|
|
25
|
+
/** What a working UI would have done. */
|
|
26
|
+
expected: string;
|
|
27
|
+
/** Raw measurements behind the verdict. */
|
|
28
|
+
details: Record<string, unknown>;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=ui-check-finding.interface.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui-check-finding.interface.d.ts","sourceRoot":"","sources":["../../../../src/_modules/ui-check/_models/ui-check-finding.interface.ts"],"names":[],"mappings":"AAAA,yGAAyG;AACzG,MAAM,WAAW,6BAA6B;IAC5C,oEAAoE;IACpE,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,8DAA8D;IAC9D,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED;;;GAGG;AACH,MAAM,WAAW,8BAA8B;IAC7C,6CAA6C;IAC7C,QAAQ,EAAE,MAAM,CAAC;IACjB,uEAAuE;IACvE,UAAU,EAAE,MAAM,CAAC;IACnB,4CAA4C;IAC5C,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,6BAA6B,CAAC;IACtC,0CAA0C;IAC1C,QAAQ,EAAE,MAAM,CAAC;IACjB,yCAAyC;IACzC,QAAQ,EAAE,MAAM,CAAC;IACjB,2CAA2C;IAC3C,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui-check-finding.interface.js","sourceRoot":"","sources":["../../../../src/_modules/ui-check/_models/ui-check-finding.interface.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { DyE2E_UICheckFinding_Interface } from './ui-check-finding.interface';
|
|
2
|
+
/**
|
|
3
|
+
* A coded, dated exception for one known finding — a detector is NEVER switched off silently (BFR-FLEET-012/-013).
|
|
4
|
+
* Without a trace code, a reason and an expiry date the runner rejects it; after the expiry it no longer applies.
|
|
5
|
+
*/
|
|
6
|
+
export interface DyE2E_UICheckWaiver_Interface {
|
|
7
|
+
/** The detector id the waiver applies to. */
|
|
8
|
+
detector: string;
|
|
9
|
+
/** Substring of the finding's selector, text or test id; omitted = every finding of the detector on the page. */
|
|
10
|
+
target?: string;
|
|
11
|
+
/** The open defect's trace code: `BL-…`, `BFR-…`, `BUG-…` or `CFR-…`. */
|
|
12
|
+
code: string;
|
|
13
|
+
reason: string;
|
|
14
|
+
/** ISO date (`YYYY-MM-DD`); from the next day on the waiver is expired. */
|
|
15
|
+
expires: string;
|
|
16
|
+
}
|
|
17
|
+
/** A finding the waiver suppressed — still listed in the report. */
|
|
18
|
+
export interface DyE2E_UICheckWaived_Interface {
|
|
19
|
+
finding: DyE2E_UICheckFinding_Interface;
|
|
20
|
+
waiver: DyE2E_UICheckWaiver_Interface;
|
|
21
|
+
}
|
|
22
|
+
/** A detector that crashed — a crash is a failed check, never a clean one. */
|
|
23
|
+
export interface DyE2E_UICheckError_Interface {
|
|
24
|
+
detector: string;
|
|
25
|
+
message: string;
|
|
26
|
+
}
|
|
27
|
+
/** The result of one UI check on one page. */
|
|
28
|
+
export interface DyE2E_UICheckReport_Interface {
|
|
29
|
+
url: string;
|
|
30
|
+
detectorsRun: string[];
|
|
31
|
+
findings: DyE2E_UICheckFinding_Interface[];
|
|
32
|
+
waived: DyE2E_UICheckWaived_Interface[];
|
|
33
|
+
expiredWaivers: DyE2E_UICheckWaiver_Interface[];
|
|
34
|
+
errors: DyE2E_UICheckError_Interface[];
|
|
35
|
+
/** What a detector could not measure — read them: a skipped control is not a clean one. */
|
|
36
|
+
notes: string[];
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=ui-check-report.interface.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui-check-report.interface.d.ts","sourceRoot":"","sources":["../../../../src/_modules/ui-check/_models/ui-check-report.interface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,8BAA8B,EAAE,MAAM,8BAA8B,CAAC;AAE9E;;;GAGG;AACH,MAAM,WAAW,6BAA6B;IAC5C,6CAA6C;IAC7C,QAAQ,EAAE,MAAM,CAAC;IACjB,iHAAiH;IACjH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,yEAAyE;IACzE,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,2EAA2E;IAC3E,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,oEAAoE;AACpE,MAAM,WAAW,6BAA6B;IAC5C,OAAO,EAAE,8BAA8B,CAAC;IACxC,MAAM,EAAE,6BAA6B,CAAC;CACvC;AAED,8EAA8E;AAC9E,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,8CAA8C;AAC9C,MAAM,WAAW,6BAA6B;IAC5C,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,QAAQ,EAAE,8BAA8B,EAAE,CAAC;IAC3C,MAAM,EAAE,6BAA6B,EAAE,CAAC;IACxC,cAAc,EAAE,6BAA6B,EAAE,CAAC;IAChD,MAAM,EAAE,4BAA4B,EAAE,CAAC;IACvC,2FAA2F;IAC3F,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui-check-report.interface.js","sourceRoot":"","sources":["../../../../src/_modules/ui-check/_models/ui-check-report.interface.ts"],"names":[],"mappings":""}
|