@piwitests/reporter 0.11.0 → 0.13.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.
Files changed (77) hide show
  1. package/dist/global-setup-module.d.ts +2 -1
  2. package/dist/global-setup-module.js +432 -3
  3. package/dist/index.d.ts +204 -8
  4. package/dist/index.js +4724 -23
  5. package/dist/internal/capture/attachments.d.ts +9 -3
  6. package/dist/internal/capture/attachments.js +46 -20
  7. package/dist/internal/capture/capture-fixtures.d.ts +110 -7
  8. package/dist/internal/capture/capture-fixtures.js +2227 -639
  9. package/dist/internal/capture/inspect-on-failure.d.ts +50 -0
  10. package/dist/internal/capture/inspect-on-failure.js +66 -0
  11. package/dist/internal/capture/locator-healing.d.ts +33 -131
  12. package/dist/internal/capture/locator-healing.js +602 -711
  13. package/dist/internal/capture/pick-on-failure.d.ts +198 -0
  14. package/dist/internal/capture/pick-on-failure.js +1203 -0
  15. package/package.json +9 -4
  16. package/dist/internal/collect/error-text.d.ts +0 -18
  17. package/dist/internal/collect/error-text.js +0 -79
  18. package/dist/internal/collect/metadata-collector.d.ts +0 -32
  19. package/dist/internal/collect/metadata-collector.js +0 -246
  20. package/dist/internal/collect/skip-classify.d.ts +0 -27
  21. package/dist/internal/collect/skip-classify.js +0 -40
  22. package/dist/internal/collect/step-analyzer.d.ts +0 -103
  23. package/dist/internal/collect/step-analyzer.js +0 -221
  24. package/dist/internal/config/env.d.ts +0 -45
  25. package/dist/internal/config/env.js +0 -153
  26. package/dist/internal/files/compression.d.ts +0 -5
  27. package/dist/internal/files/compression.js +0 -69
  28. package/dist/internal/files/file-handler.d.ts +0 -38
  29. package/dist/internal/files/file-handler.js +0 -198
  30. package/dist/internal/streaming/crash-recovery.d.ts +0 -23
  31. package/dist/internal/streaming/crash-recovery.js +0 -106
  32. package/dist/internal/streaming/stream-buffer.d.ts +0 -17
  33. package/dist/internal/streaming/stream-buffer.js +0 -102
  34. package/dist/internal/streaming/stream-manager.d.ts +0 -88
  35. package/dist/internal/streaming/stream-manager.js +0 -395
  36. package/dist/internal/submit/run-submitter.d.ts +0 -67
  37. package/dist/internal/submit/run-submitter.js +0 -190
  38. package/dist/internal/submit/serializer.d.ts +0 -45
  39. package/dist/internal/submit/serializer.js +0 -107
  40. package/dist/internal/submit/uploader.d.ts +0 -89
  41. package/dist/internal/submit/uploader.js +0 -226
  42. package/dist/internal/support/ci.d.ts +0 -2
  43. package/dist/internal/support/ci.js +0 -32
  44. package/dist/internal/support/cli-filters.d.ts +0 -1
  45. package/dist/internal/support/cli-filters.js +0 -51
  46. package/dist/internal/support/errors.d.ts +0 -8
  47. package/dist/internal/support/errors.js +0 -15
  48. package/dist/internal/support/instance-id.d.ts +0 -4
  49. package/dist/internal/support/instance-id.js +0 -48
  50. package/dist/internal/support/limiter.d.ts +0 -2
  51. package/dist/internal/support/limiter.js +0 -27
  52. package/dist/internal/support/logger.d.ts +0 -26
  53. package/dist/internal/support/logger.js +0 -43
  54. package/dist/internal/support/reporter-version.d.ts +0 -2
  55. package/dist/internal/support/reporter-version.js +0 -54
  56. package/dist/internal/support/setup-file.d.ts +0 -13
  57. package/dist/internal/support/setup-file.js +0 -61
  58. package/dist/internal/support/source-snippet.d.ts +0 -12
  59. package/dist/internal/support/source-snippet.js +0 -97
  60. package/dist/internal/support/worker-index.d.ts +0 -7
  61. package/dist/internal/support/worker-index.js +0 -14
  62. package/dist/internal/transport/http-client.d.ts +0 -52
  63. package/dist/internal/transport/http-client.js +0 -201
  64. package/dist/public/config-wrapper.d.ts +0 -21
  65. package/dist/public/config-wrapper.js +0 -64
  66. package/dist/public/global-setup.d.ts +0 -13
  67. package/dist/public/global-setup.js +0 -146
  68. package/dist/public/options.d.ts +0 -78
  69. package/dist/public/options.js +0 -2
  70. package/dist/public/reporter.d.ts +0 -68
  71. package/dist/public/reporter.js +0 -376
  72. package/dist/types/collected.d.ts +0 -96
  73. package/dist/types/collected.js +0 -10
  74. package/dist/types/wire.d.ts +0 -174
  75. package/dist/types/wire.js +0 -14
  76. package/dist/types.d.ts +0 -11
  77. package/dist/types.js +0 -27
@@ -0,0 +1,50 @@
1
+ import { TestInfo } from '@playwright/test';
2
+
3
+ /**
4
+ * Shared gate for Piwi's failure-time overlay. Both `inspectOnFailure`
5
+ * (`PIWI_INSPECT_ON_FAIL`) and `pickLocatorOnFailure` (`PIWI_PICK_LOCATOR_ON_FAIL`)
6
+ * open Piwi's own in-page overlay (see `pick-on-failure.ts`) — never
7
+ * Playwright's native inspector — so the experience is fully ours and a
8
+ * confirmed pick flows back into the dashboard.
9
+ *
10
+ * Local-only by design: the overlay needs a human and a visible browser, so the
11
+ * gate requires a headed browser and refuses to run under CI regardless of the
12
+ * flag. It also waits for the final attempt when retries are configured — an
13
+ * attempt that is about to be retried closes without opening the overlay.
14
+ */
15
+ /** Everything the gate reads, as plain values so it stays unit-testable. */
16
+ interface InspectionGate {
17
+ /** Raw `PIWI_INSPECT_ON_FAIL` env value — only the string `'true'` enables. */
18
+ enabled: string | undefined;
19
+ /** Raw `CI` env value. Anything except unset/empty/`'false'` counts as CI. */
20
+ ci: string | undefined;
21
+ /** `testInfo.status` at teardown. */
22
+ status: string | undefined;
23
+ /** `testInfo.expectedStatus` — an expected failure (test.fail()) never pauses. */
24
+ expectedStatus: string | undefined;
25
+ /** `testInfo.project.use.headless` — must be explicitly `false` (headed). */
26
+ headless: unknown;
27
+ /** Zero-based attempt index (`testInfo.retry`). */
28
+ retry: number;
29
+ /** Configured retry count for the project (`testInfo.project.retries`). */
30
+ retries: number;
31
+ }
32
+ /** Decide whether the failing page should be handed to the Inspector. */
33
+ declare function shouldInspectOnFailure(gate: InspectionGate): boolean;
34
+ /**
35
+ * When a failure-time feature is *enabled* on a *real* failure but the gate
36
+ * still refused for an environmental reason (headless / CI), return a
37
+ * one-line human explanation so "nothing happened" is never a silent mystery.
38
+ * Returns null when the feature is off, the test didn't really fail, or the
39
+ * gate would actually pass (the feature ran, so there is nothing to explain).
40
+ */
41
+ declare function environmentalSkipReason(gate: InspectionGate): string | null;
42
+ /**
43
+ * Project the live TestInfo + process env into the plain gate shape. The gate
44
+ * conditions are shared by every failure-time affordance that needs a live
45
+ * headed page; `enabled` selects which opt-in flag arms this one (defaults to
46
+ * the Inspector's `PIWI_INSPECT_ON_FAIL`).
47
+ */
48
+ declare function inspectionGateFromTestInfo(testInfo: TestInfo, enabled?: string | undefined): InspectionGate;
49
+
50
+ export { type InspectionGate, environmentalSkipReason, inspectionGateFromTestInfo, shouldInspectOnFailure };
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/internal/capture/inspect-on-failure.ts
21
+ var inspect_on_failure_exports = {};
22
+ __export(inspect_on_failure_exports, {
23
+ environmentalSkipReason: () => environmentalSkipReason,
24
+ inspectionGateFromTestInfo: () => inspectionGateFromTestInfo,
25
+ shouldInspectOnFailure: () => shouldInspectOnFailure
26
+ });
27
+ module.exports = __toCommonJS(inspect_on_failure_exports);
28
+ function isCi(ci) {
29
+ return ci !== void 0 && ci !== "" && ci !== "false";
30
+ }
31
+ function shouldInspectOnFailure(gate) {
32
+ if (gate.enabled !== "true") return false;
33
+ if (isCi(gate.ci)) return false;
34
+ if (gate.headless !== false) return false;
35
+ if (gate.status !== "failed" && gate.status !== "timedOut") return false;
36
+ if (gate.status === gate.expectedStatus) return false;
37
+ return gate.retry >= gate.retries;
38
+ }
39
+ function environmentalSkipReason(gate) {
40
+ if (gate.enabled !== "true") return null;
41
+ if (gate.status !== "failed" && gate.status !== "timedOut") return null;
42
+ if (gate.status === gate.expectedStatus) return null;
43
+ if (isCi(gate.ci)) return "running under CI \u2014 this is a headed, local-only feature";
44
+ if (gate.headless !== false) {
45
+ return "the browser is headless \u2014 re-run with --headed (or set use: { headless: false })";
46
+ }
47
+ return null;
48
+ }
49
+ function inspectionGateFromTestInfo(testInfo, enabled = process.env.PIWI_INSPECT_ON_FAIL) {
50
+ const use = testInfo.project?.use ?? {};
51
+ return {
52
+ enabled,
53
+ ci: process.env.CI,
54
+ status: testInfo.status,
55
+ expectedStatus: testInfo.expectedStatus,
56
+ headless: use.headless,
57
+ retry: testInfo.retry,
58
+ retries: testInfo.project?.retries ?? 0
59
+ };
60
+ }
61
+ // Annotate the CommonJS export names for ESM import in node:
62
+ 0 && (module.exports = {
63
+ environmentalSkipReason,
64
+ inspectionGateFromTestInfo,
65
+ shouldInspectOnFailure
66
+ });
@@ -1,66 +1,22 @@
1
+ export { CAPTURED_ATTRIBUTES, INPUT_TYPE_TO_ROLE, TAG_TO_ROLE, approximateAccessibleName, classifyCssStability, generateAlternatives, headingLevel, isAutoGenerated, resolveAriaRole } from '@piwitests/core/locator-generation';
2
+ import { LocatorSnapshot } from '@piwitests/core/locator-healing-types';
3
+ export { AncestorAnchor, ElementAttributes, LocatorSnapshot, RankedLocator, RolePosition, SelectorCounts } from '@piwitests/core/locator-healing-types';
4
+
1
5
  /**
2
- * Reporter-local locator healing — pure functions for alternative generation,
3
- * stability scoring, and the Playwright method-surface constants shared with
4
- * the fixture proxy. No Playwright dependency takes raw element attributes,
5
- * returns ranked locator suggestions.
6
- */
7
- export interface RankedLocator {
8
- locator: string;
9
- method: string;
10
- args: Record<string, unknown>;
11
- /** 0-100 stability score. data-testid=100, semantic CSS=35-40, hash-suffixed=10. */
12
- score: number;
13
- }
14
- /**
15
- * Match counts for candidate selectors, probed with `querySelectorAll` against
16
- * the live page at capture time. A count > 1 means the selector is ambiguous
17
- * (would be a strict-mode violation) and the alternative is suppressed; a
18
- * missing count means the probe didn't run and the alternative is kept.
6
+ * Reporter-local locator healing.
7
+ *
8
+ * The pure surfacealternative generation, stability scoring, ARIA-role
9
+ * resolution, the role maps and the captured-attribute whitelist — lives in
10
+ * `@piwitests/core` (bundled into `dist/` at build time, so nothing
11
+ * monorepo-relative leaks into the published package). It is re-exported from
12
+ * here so existing importers (`capture-fixtures.ts`, `pick-on-failure.ts`, the
13
+ * unit tests) keep importing it from this module.
14
+ *
15
+ * This module keeps only the reporter-only runtime: call-site capture (needs the
16
+ * Node stack), snapshot dedupe, the fixture-proxy method surface, and the
17
+ * failure-time locator suggestion + rendering.
19
18
  */
20
- export interface SelectorCounts {
21
- testId?: number;
22
- id?: number;
23
- name?: number;
24
- classes?: Record<string, number>;
25
- }
26
- export interface ElementAttributes {
27
- tagName: string;
28
- attributes: Record<string, string | null>;
29
- textContent: string | null;
30
- accessibleName: string | null;
31
- center: {
32
- x: number;
33
- y: number;
34
- } | null;
35
- /**
36
- * True when the element has an associated `<label>` (`el.labels`). Gates the
37
- * `getByLabel` alternative — an accessible name approximated from
38
- * placeholder/title would produce a `getByLabel` that matches nothing.
39
- * Undefined on payloads from older capture probes (legacy behavior applies).
40
- */
41
- hasLabel?: boolean;
42
- /** Live-page uniqueness probe results for candidate selectors. */
43
- selectorCounts?: SelectorCounts;
44
- }
45
- export interface LocatorSnapshot {
46
- location: string | null;
47
- used: {
48
- method: string;
49
- args: unknown[];
50
- raw: string;
51
- };
52
- element: {
53
- tagName: string;
54
- attributes: Record<string, string | null>;
55
- textContent: string | null;
56
- accessibleName: string | null;
57
- center: {
58
- x: number;
59
- y: number;
60
- } | null;
61
- } | null;
62
- alternatives: RankedLocator[];
63
- }
19
+
64
20
  /**
65
21
  * Drop repeated captures of the same call site before attaching: a loop (or a
66
22
  * page-object method called repeatedly) produces one snapshot per action, but
@@ -69,62 +25,24 @@ export interface LocatorSnapshot {
69
25
  * when no capture resolved, so the location still counts as "seen this run"
70
26
  * for the server's stale-location purge. Entries with no location pass through.
71
27
  */
72
- export declare function dedupeSnapshotsByLocation(snaps: LocatorSnapshot[]): LocatorSnapshot[];
28
+ declare function dedupeSnapshotsByLocation(snaps: LocatorSnapshot[]): LocatorSnapshot[];
73
29
  /**
74
30
  * Page-level locator-building methods wrapped by the capture proxy. Imported by
75
31
  * both the capture fixtures (`capture-fixtures.ts`) and the dogfooding
76
32
  * `application/tests/fixtures.ts` so the two stay in sync (a prior drift missed
77
33
  * `scrollIntoViewIfNeeded`).
78
34
  */
79
- export declare const LOCATOR_METHODS: string[];
35
+ declare const LOCATOR_METHODS: string[];
80
36
  /**
81
37
  * Methods that can be chained onto a wrapped locator. Locator-creating chains
82
38
  * (those also in `LOCATOR_METHODS`) update the origin; positional/filter chains
83
39
  * (`first`, `nth`, `filter`, …) narrow without changing locator identity.
84
40
  */
85
- export declare const CHAIN_METHODS: string[];
41
+ declare const CHAIN_METHODS: string[];
86
42
  /** Locator action methods that trigger element capture. */
87
- export declare const ACTION_METHODS: string[];
43
+ declare const ACTION_METHODS: string[];
88
44
  /** Chain methods that create a new locator scope (origin tracks the chain call). */
89
- export declare const LOCATOR_CREATING_CHAINS: ReadonlySet<string>;
90
- /**
91
- * Element attributes to capture after a successful action, passed into the
92
- * in-page `evaluate`. Shared so the reporter and dogfooding fixtures capture
93
- * the same attribute set.
94
- */
95
- export declare const CAPTURED_ATTRIBUTES: string[];
96
- /**
97
- * Resolve the ARIA role for an element. An explicit `role` attribute wins;
98
- * otherwise the implicit role is derived from the tag name (and `type` for
99
- * `<input>`). Returns null when the element has no ARIA role (e.g. `<div>`,
100
- * `<span>`, `<a>` without `href`) — `getByRole` is not a valid locator for
101
- * such elements and other alternatives take over.
102
- */
103
- export declare function resolveAriaRole(attrs: ElementAttributes): string | null;
104
- /**
105
- * Build a ranked list of alternative locators from the captured element
106
- * attributes. The list is sorted descending by stability score.
107
- *
108
- * Only generates alternatives that differ from each other — no duplicates
109
- * of the same locator expression.
110
- */
111
- export declare function generateAlternatives(attrs: ElementAttributes): RankedLocator[];
112
- /**
113
- * Score a CSS class name on a 0-40 stability scale.
114
- *
115
- * Heuristics (inherited from common CSS-naming conventions):
116
- * - Hash-like suffixes (≥4 hex chars) → 10 — auto-generated, fragile
117
- * - CSS-in-JS patterns (css-, sc-, emotion-, styled-, _) → 15
118
- * - Tailwind/utility classes → 25
119
- * - BEM-style semantic → 35
120
- * - Plain semantic → 40
121
- */
122
- export declare function classifyCssStability(className: string): number;
123
- /**
124
- * Detects GUID-like, auto-incremented, or hash-suffixed IDs that are
125
- * likely regenerated on each render and unstable for testing.
126
- */
127
- export declare function isAutoGenerated(value: string): boolean;
45
+ declare const LOCATOR_CREATING_CHAINS: ReadonlySet<string>;
128
46
  /**
129
47
  * Extract the accessible name from a YAML-like ariaSnapshot() output.
130
48
  *
@@ -136,40 +54,22 @@ export declare function isAutoGenerated(value: string): boolean;
136
54
  *
137
55
  * Returns the first quoted string after the role, or null if none found.
138
56
  */
139
- export declare function extractAccessibleName(ariaSnapshot: string | null): string | null;
140
- /**
141
- * Approximate the accessible name from HTML attributes when ariaSnapshot()
142
- * is unavailable. Priority: aria-label > text content > title > placeholder.
143
- */
144
- export declare function approximateAccessibleName(attrs: ElementAttributes): string | null;
57
+ declare function extractAccessibleName(ariaSnapshot: string | null): string | null;
145
58
  /** A failed locator action, used to suggest a fresh locator from the live page. */
146
- export interface FailedLocatorInfo {
59
+ interface FailedLocatorInfo {
147
60
  method: string;
148
61
  args: unknown[];
62
+ /** Test call site (`file:line:col`) of the failed action, when captured. */
63
+ location?: string | null;
149
64
  }
150
- export interface LocatorSuggestion {
65
+ interface LocatorSuggestion {
151
66
  /** The failed locator rendered as source, e.g. `getByText('Go to page')`. */
152
67
  failing: string;
153
68
  /** Fresh locator suggestions for the element's current identity, best first. */
154
69
  suggestions: string[];
155
70
  }
156
- /**
157
- * Parse `ariaSnapshot()` lines into role/name pairs (mirrors the server-side
158
- * `parseAriaCandidates` in application/shared/locator-fingerprint.ts).
159
- * Exported so the dashboard's drift-guard unit test can compare the two.
160
- */
161
- export declare function parseAriaRoleName(ariaSnapshot: string): Array<{
162
- role: string;
163
- name: string | null;
164
- }>;
165
- /**
166
- * Token-set (Dice) similarity, 0-1, case- and punctuation-insensitive.
167
- * Duplicated from `textSimilarity` in application/shared/locator-fingerprint.ts —
168
- * this package publishes standalone to npm and can't import monorepo-relative
169
- * shared/ code, so keep the two implementations in sync by hand. Exported so
170
- * the dashboard's drift-guard unit test can compare the two.
171
- */
172
- export declare function nameSimilarity(a: string | null, b: string | null): number;
71
+ /** Render the failed locator back to source for annotation/picker messages. */
72
+ declare function renderFailing(failed: FailedLocatorInfo): string;
173
73
  /**
174
74
  * Best-effort runtime suggestion for a locator that matched nothing: find the
175
75
  * element on the *current* page that the failed locator most likely targeted
@@ -181,7 +81,7 @@ export declare function nameSimilarity(a: string | null, b: string | null): numb
181
81
  * for non-name-based locators (testid/CSS), when the targeted name is still
182
82
  * present (so the failure wasn't a rename), or when no candidate is confident.
183
83
  */
184
- export declare function suggestLocatorsFromAria(failed: FailedLocatorInfo, ariaSnapshot: string | null): LocatorSuggestion | null;
84
+ declare function suggestLocatorsFromAria(failed: FailedLocatorInfo, ariaSnapshot: string | null): LocatorSuggestion | null;
185
85
  /**
186
86
  * Capture the calling test's source location (`file:line:col`) from the current
187
87
  * stack, for stamping onto a locator snapshot. The path is made cwd-relative so
@@ -196,4 +96,6 @@ export declare function suggestLocatorsFromAria(failed: FailedLocatorInfo, ariaS
196
96
  * Returns null when no user frame can be identified — the snapshot keeps
197
97
  * `location: null` and the server falls back to fingerprint / ARIA lookup.
198
98
  */
199
- export declare function captureCallerLocation(): string | null;
99
+ declare function captureCallerLocation(stack?: string): string | null;
100
+
101
+ export { ACTION_METHODS, CHAIN_METHODS, type FailedLocatorInfo, LOCATOR_CREATING_CHAINS, LOCATOR_METHODS, type LocatorSuggestion, captureCallerLocation, dedupeSnapshotsByLocation, extractAccessibleName, renderFailing, suggestLocatorsFromAria };