@piwitests/reporter 0.62.0 → 0.64.0
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/README.md +1 -1
- package/dist/cli/index.js +76 -40
- package/dist/global-setup-module.js +88 -14
- package/dist/index.d.ts +27 -8
- package/dist/index.js +17501 -13740
- package/dist/internal/capture/attachments.d.ts +1 -1
- package/dist/internal/capture/capture-fixtures.d.ts +142 -7
- package/dist/internal/capture/capture-fixtures.js +4394 -1039
- package/dist/internal/capture/locator-healing.d.ts +222 -4
- package/dist/internal/capture/locator-healing.js +22 -10
- package/dist/internal/capture/pick-on-failure.d.ts +184 -6
- package/dist/internal/capture/pick-on-failure.js +29 -5
- package/dist/types-CGr9jJZ_.d.ts +87 -0
- package/dist/wire-7zsqlBoY.d.ts +48 -0
- package/package.json +2 -2
- package/templates/skills/write-the-missing-test/SKILL.md +6 -4
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/** Arguments for `probeElementAttrs` — the role maps mirror the single source of truth in `@piwitests/core`. */
|
|
2
|
+
interface ProbeArg {
|
|
3
|
+
/** Attribute whitelist to read off the element (the shared `CAPTURED_ATTRIBUTES`). */
|
|
4
|
+
keep: string[];
|
|
5
|
+
/** Required when `includeStructural` is true — role resolution needs the tag/input-type role maps. */
|
|
6
|
+
tagRoles?: Record<string, string>;
|
|
7
|
+
inputRoles?: Record<string, string>;
|
|
8
|
+
/** CSS selector matching every element role resolution can reach (also structural-only). */
|
|
9
|
+
roleSources?: string;
|
|
10
|
+
/** Compute `rolePosition` and ancestor-anchor candidates. The live picker always wants these; the snapshot picker never does (no anchors step there). */
|
|
11
|
+
includeStructural: boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Count how many elements each candidate matches: `selectorCounts`,
|
|
14
|
+
* `rolePosition` and every anchor's counts, each a walk of the document or
|
|
15
|
+
* of an ancestor's subtree. True unless set: a caller that counts with an
|
|
16
|
+
* index of its own turns it off, and the anchors then carry what identifies
|
|
17
|
+
* them and no count, whatever the size of the page.
|
|
18
|
+
*/
|
|
19
|
+
countMatches?: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* The attribute `getByTestId` reads in the project (Playwright's
|
|
22
|
+
* `testIdAttribute`); `data-testid` when null or absent. It is read with
|
|
23
|
+
* `keep`, counted for `selectorCounts.testId`, read off each ancestor for its
|
|
24
|
+
* `testId` and `testIdCount`, and never taken as an ancestor's `dataAttr`;
|
|
25
|
+
* any other `data-*`, `data-testid` included, is an ordinary one.
|
|
26
|
+
*/
|
|
27
|
+
testIdAttribute?: string | null;
|
|
28
|
+
}
|
|
29
|
+
/** Element shape the in-page probe returns — structural view of what the picker overlays need. */
|
|
30
|
+
interface ProbedAttrs {
|
|
31
|
+
tagName: string;
|
|
32
|
+
attributes: Record<string, string | null>;
|
|
33
|
+
textContent: string;
|
|
34
|
+
center: {
|
|
35
|
+
x: number;
|
|
36
|
+
y: number;
|
|
37
|
+
};
|
|
38
|
+
hasLabel: boolean;
|
|
39
|
+
/** Text of the elements `aria-labelledby` points at, else of the first associated `<label>`. */
|
|
40
|
+
labelText: string | null;
|
|
41
|
+
selectorCounts: {
|
|
42
|
+
testId?: number;
|
|
43
|
+
id?: number;
|
|
44
|
+
name?: number;
|
|
45
|
+
classes?: Record<string, number>;
|
|
46
|
+
/** How many elements share this element's role *and* exact accessible name (`getByRole(role, { name })` without `exact` also matches names that contain it). */
|
|
47
|
+
roleName?: number;
|
|
48
|
+
/** Of the `roleName` matches, how many are laid out (a box, or an `offsetParent`) — what `getByRole(role, { name }).visible()` would match. */
|
|
49
|
+
visibleRoleName?: number;
|
|
50
|
+
/** How many elements `getByText` would match on this element's text, counted no further than 2 — every consumer only asks whether that is exactly one. Undefined when the element has no text, or the subtree was too large to scan. */
|
|
51
|
+
text?: number;
|
|
52
|
+
/** How many elements share this element's `placeholder` — what `getByPlaceholder` would really match. */
|
|
53
|
+
placeholder?: number;
|
|
54
|
+
/** How many elements share this element's `alt` — what `getByAltText` would really match. */
|
|
55
|
+
alt?: number;
|
|
56
|
+
/** How many elements share this element's `title` — what `getByTitle` would really match. */
|
|
57
|
+
title?: number;
|
|
58
|
+
};
|
|
59
|
+
rolePosition?: {
|
|
60
|
+
role: string;
|
|
61
|
+
count: number;
|
|
62
|
+
index: number;
|
|
63
|
+
levelCount?: number;
|
|
64
|
+
} | null;
|
|
65
|
+
ancestors?: Array<{
|
|
66
|
+
tag: string;
|
|
67
|
+
depth: number;
|
|
68
|
+
testId: string | null;
|
|
69
|
+
id: string | null;
|
|
70
|
+
role: string | null;
|
|
71
|
+
ariaLabel: string | null;
|
|
72
|
+
scopedRoleCount?: number;
|
|
73
|
+
scopedTextCount?: number;
|
|
74
|
+
testIdCount?: number;
|
|
75
|
+
idCount?: number;
|
|
76
|
+
roleCount?: number;
|
|
77
|
+
dataAttr?: {
|
|
78
|
+
name: string;
|
|
79
|
+
value: string;
|
|
80
|
+
};
|
|
81
|
+
dataAttrCount?: number;
|
|
82
|
+
filterText?: string;
|
|
83
|
+
filterRoleCount?: number;
|
|
84
|
+
}>;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export type { ProbeArg as P, ProbedAttrs as a };
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wire leaf shapes — the small, identical building blocks of the JSON contract
|
|
3
|
+
* exchanged between the reporter and the server. The single source of truth
|
|
4
|
+
* shared by the app (`#shared/types`) and the reporter (`types/wire.ts`).
|
|
5
|
+
*
|
|
6
|
+
* The per-case *payloads* are intentionally NOT here: the reporter produces a
|
|
7
|
+
* loose `WireTestCase` superset while the server receives the stricter
|
|
8
|
+
* `TestCasePayload` / `StreamEventPayload`. Those live on each side and are kept
|
|
9
|
+
* field-compatible by `apps/application/tests/unit/wire-shared-drift.test.ts`.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* One locator call and the page it ran on, as the capture fixtures record it
|
|
14
|
+
* in the `piwi-locator-pages` attachment: a test's calls, deduped by call
|
|
15
|
+
* site, chain and page. The dashboard joins it to the locator index, so a use
|
|
16
|
+
* of a chain knows the pages it was made on.
|
|
17
|
+
*/
|
|
18
|
+
interface LocatorPageUse {
|
|
19
|
+
/** `file:line:col` of the call, as a step location reports it (absolute; the server makes it project-relative). */
|
|
20
|
+
location: string;
|
|
21
|
+
/** The chain as Playwright prints it (`Locator.toString()`). */
|
|
22
|
+
locator: string;
|
|
23
|
+
/** The page's origin (`https://shop.test`), to tell the application's pages from third-party ones. */
|
|
24
|
+
origin: string;
|
|
25
|
+
/** The page key: the path with ids and tokens collapsed, no query, no hash (`/orders/:id`). */
|
|
26
|
+
page: string;
|
|
27
|
+
/** No locator interaction happened on the page since it was navigated to: the element was there as it loaded. */
|
|
28
|
+
arrival: boolean;
|
|
29
|
+
}
|
|
30
|
+
/** What a process is for the run, from its command line. */
|
|
31
|
+
type ProcessRole = 'runner' | 'worker' | 'browser' | 'renderer' | 'gpu' | 'utility' | 'ffmpeg' | 'webServer' | 'other';
|
|
32
|
+
/**
|
|
33
|
+
* Name of the PNG the capture fixtures attach to a failed test: the page the
|
|
34
|
+
* test last acted on. The reporter uploads it with the execution's files, and
|
|
35
|
+
* the dashboard shows it as the page at the failure.
|
|
36
|
+
*/
|
|
37
|
+
declare const FAILURE_SCREENSHOT_ATTACHMENT = "piwi-failure-screenshot";
|
|
38
|
+
/** What the processes of one role used during a test. */
|
|
39
|
+
interface RoleCost {
|
|
40
|
+
cpuMs: number;
|
|
41
|
+
/** Time runnable but waiting for a CPU. */
|
|
42
|
+
runWaitMs: number | null;
|
|
43
|
+
/** The largest process of the role during the test (its peak RSS). */
|
|
44
|
+
peakRssMb: number | null;
|
|
45
|
+
processes: number;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export { FAILURE_SCREENSHOT_ATTACHMENT as F, type LocatorPageUse as L, type ProcessRole as P, type RoleCost as R };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@piwitests/reporter",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.64.0",
|
|
4
4
|
"description": "Playwright reporter that streams results, traces and HTML reports to a Piwi Dashboard instance",
|
|
5
5
|
"url": "https://github.com/PiwiTests/piwi",
|
|
6
6
|
"homepage": "https://piwitests.dev",
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
"node": ">=20"
|
|
67
67
|
},
|
|
68
68
|
"peerDependencies": {
|
|
69
|
-
"@playwright/test": "
|
|
69
|
+
"@playwright/test": ">=1.59.0 <2"
|
|
70
70
|
},
|
|
71
71
|
"dependencies": {
|
|
72
72
|
"form-data": "^4.0.0"
|
|
@@ -87,10 +87,12 @@ view, and work from what it shows plus the repo.
|
|
|
87
87
|
|
|
88
88
|
8. **Report back to Piwi.** Tell Piwi what you decided about the gap with
|
|
89
89
|
`triage_gap` (Maintainer role or above on the project): `verb: "accept"` for the gap you
|
|
90
|
-
wrote the test for, `covered-by` with the
|
|
91
|
-
|
|
92
|
-
`
|
|
93
|
-
|
|
90
|
+
wrote the test for, `covered-by` with the test's id once a test written for the gap
|
|
91
|
+
has run, or `dismiss` when the gap needed no new test: `covered-elsewhere` with the id
|
|
92
|
+
of a test that already covered it, `not-worth-testing`, or `wrong` when the evidence did
|
|
93
|
+
not hold. Each verdict counts toward the precision of the detector that raised the gap
|
|
94
|
+
(`accept` and `covered-by` for it, `wrong` and `covered-elsewhere` against it), so a
|
|
95
|
+
detector that keeps being wrong is muted.
|
|
94
96
|
|
|
95
97
|
## Guardrails
|
|
96
98
|
|