@sentinelqa/playwright-reporter 0.1.30 → 0.1.32
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 +67 -52
- package/dist/index.d.ts +0 -3
- package/dist/index.js +1 -4
- package/dist/reporter.d.ts +0 -4
- package/dist/reporter.js +15 -78
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,15 +1,21 @@
|
|
|
1
1
|
# Playwright Reporter
|
|
2
2
|
|
|
3
|
+
After every failed run, Sentinel prints a shareable debugging link:
|
|
4
|
+
|
|
5
|
+
👉 https://sentinelqa.com/run/abc123
|
|
6
|
+
|
|
7
|
+
Open it to inspect failures instantly or share it in Slack, PRs, or GitHub issues.
|
|
8
|
+
|
|
3
9
|
[](https://www.npmjs.com/package/@sentinelqa/playwright-reporter)
|
|
4
10
|
[](https://www.npmjs.com/package/@sentinelqa/playwright-reporter)
|
|
5
11
|
[](./LICENSE)
|
|
6
12
|
|
|
7
|
-
|
|
8
|
-
|
|
13
|
+
From failed CI run → root cause in seconds.
|
|
14
|
+
Get a shareable Playwright debugging link with traces, screenshots, and failure context — no setup required.
|
|
9
15
|
|
|
10
|
-
Works
|
|
16
|
+
Works with no account or API key required.
|
|
11
17
|
|
|
12
|
-
|
|
18
|
+
Use it to get a shareable hosted run link from CI or local development, then upgrade to Sentinel Cloud for richer history and intelligence.
|
|
13
19
|
|
|
14
20
|

|
|
15
21
|

|
|
@@ -17,24 +23,31 @@ Optionally upload runs to Sentinel Cloud for CI history and AI failure analysis.
|
|
|
17
23
|
|
|
18
24
|
## Features
|
|
19
25
|
|
|
20
|
-
-
|
|
21
|
-
-
|
|
22
|
-
-
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
-
-
|
|
26
|
+
- Free hosted debugging links by default, with no account or API key required
|
|
27
|
+
- Public run page that opens on unified failures across the run
|
|
28
|
+
- Within-run failure grouping so repeated failures collapse into one issue
|
|
29
|
+
- Public failure pages with screenshots, evidence, parsed errors and light summaries
|
|
30
|
+
- Copyable share actions for Slack, PRs, and debugging handoff
|
|
31
|
+
- Deterministic quick diagnosis in the terminal after failed runs
|
|
32
|
+
- Playwright traces, screenshots, videos and logs uploaded automatically
|
|
33
|
+
- 48-hour public share links on the free hosted flow
|
|
27
34
|
- Works with existing Playwright reporter setup
|
|
28
|
-
- Optional Sentinel Cloud
|
|
29
|
-
- CI run history and AI debugging
|
|
35
|
+
- Optional live failure capture for richer Sentinel Cloud analysis
|
|
36
|
+
- CI run history, retention, and deeper AI debugging in Sentinel Cloud
|
|
30
37
|
|
|
31
38
|
## Why this exists
|
|
32
39
|
|
|
33
|
-
Debugging Playwright
|
|
34
|
-
|
|
40
|
+
Debugging Playwright failures usually means downloading traces, screenshots, and logs separately from CI.
|
|
41
|
+
|
|
42
|
+
Reporter uploads those artifacts into a single hosted Sentinel run page so you can open one link, inspect failures fast, and share that link with the rest of the team.
|
|
35
43
|
|
|
36
|
-
|
|
37
|
-
|
|
44
|
+
## Why teams use the free version
|
|
45
|
+
|
|
46
|
+
- Drop one wrapper into `playwright.config.ts` and keep running `npx playwright test`
|
|
47
|
+
- Get a hosted Sentinel debugging link automatically on failed runs
|
|
48
|
+
- Share one public URL in Slack, PRs, or GitHub issues instead of passing around raw CI artifacts
|
|
49
|
+
- See unified failures, grouped failure patterns, screenshots, and evidence in one place
|
|
50
|
+
- Let teammates inspect the failure without needing your CI system or local machine
|
|
38
51
|
|
|
39
52
|
## Requirements
|
|
40
53
|
|
|
@@ -47,8 +60,8 @@ so you can quickly understand what failed.
|
|
|
47
60
|
|
|
48
61
|
- best for free and local users
|
|
49
62
|
- zero-friction setup
|
|
50
|
-
-
|
|
51
|
-
-
|
|
63
|
+
- hosted Sentinel report link is generated automatically
|
|
64
|
+
- no `SENTINEL_TOKEN` required
|
|
52
65
|
- AI summaries use trace and reporter evidence, but are less precise than live page capture
|
|
53
66
|
|
|
54
67
|
Install:
|
|
@@ -87,58 +100,59 @@ Run your Playwright tests:
|
|
|
87
100
|
npx playwright test
|
|
88
101
|
```
|
|
89
102
|
|
|
90
|
-
If tests fail and
|
|
103
|
+
If tests fail, Sentinel uploads a hosted debugging report and prints the shareable link in the terminal.
|
|
104
|
+
|
|
105
|
+
Open the hosted report to inspect:
|
|
91
106
|
|
|
92
|
-
-
|
|
93
|
-
-
|
|
107
|
+
- failed tests across jobs
|
|
108
|
+
- within-run grouped failures
|
|
109
|
+
- screenshots and videos
|
|
110
|
+
- trace links
|
|
111
|
+
- parsed failure details
|
|
112
|
+
- light summaries
|
|
113
|
+
- shareable public debugging page
|
|
94
114
|
|
|
95
|
-
|
|
115
|
+
The free hosted public flow is designed for distribution:
|
|
96
116
|
|
|
97
|
-
-
|
|
98
|
-
-
|
|
99
|
-
-
|
|
100
|
-
-
|
|
101
|
-
- screenshots
|
|
102
|
-
- videos
|
|
103
|
-
- trace files
|
|
104
|
-
- logs
|
|
117
|
+
- one shareable debugging link per run
|
|
118
|
+
- public read-only pages
|
|
119
|
+
- fast enough to use in CI comments and Slack threads
|
|
120
|
+
- clear upgrade path into a full Sentinel workspace when teams want history, retention, and deeper analysis
|
|
105
121
|
|
|
106
122
|
## Modes
|
|
107
123
|
|
|
108
|
-
###
|
|
124
|
+
### Free hosted mode
|
|
109
125
|
|
|
110
|
-
If `SENTINEL_TOKEN` is not set, the reporter
|
|
126
|
+
If `SENTINEL_TOKEN` is not set, the reporter uploads the run to a hosted public Sentinel report and prints the shareable URL.
|
|
111
127
|
|
|
112
|
-
|
|
128
|
+
This free public flow includes:
|
|
113
129
|
|
|
114
|
-
|
|
130
|
+
- hosted run page
|
|
131
|
+
- hosted failure pages
|
|
132
|
+
- grouped failures inside the run
|
|
133
|
+
- light summaries
|
|
134
|
+
- copy/share actions
|
|
135
|
+
- 48-hour share links
|
|
115
136
|
|
|
116
|
-
|
|
117
|
-
SENTINEL_TOKEN=your_project_ingest_token npx playwright test
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
For intentional uploads outside CI, also set `SENTINEL_UPLOAD_LOCAL=1` and provide the usual commit and run metadata expected by the uploader.
|
|
137
|
+
### Workspace mode
|
|
121
138
|
|
|
122
|
-
|
|
139
|
+
If `SENTINEL_TOKEN` is set, the reporter uploads into your Sentinel workspace instead of the free hosted public flow.
|
|
123
140
|
|
|
124
141
|
```bash
|
|
125
|
-
SENTINEL_TOKEN=your_project_ingest_token
|
|
126
|
-
SENTINEL_UPLOAD_LOCAL=1 \
|
|
127
|
-
GITHUB_SHA=abc123 \
|
|
128
|
-
GITHUB_REF_NAME=main \
|
|
129
|
-
GITHUB_RUN_ID=local-dev \
|
|
130
|
-
npx playwright test
|
|
142
|
+
SENTINEL_TOKEN=your_project_ingest_token npx playwright test
|
|
131
143
|
```
|
|
132
144
|
|
|
145
|
+
For local runs outside CI, Sentinel will use your local git metadata automatically when available.
|
|
146
|
+
|
|
133
147
|
## What `withSentinel()` does
|
|
134
148
|
|
|
135
149
|
- Preserves your existing reporter configuration
|
|
136
150
|
- Injects a Playwright JSON reporter if one is missing
|
|
137
|
-
- Reuses your existing Playwright HTML reporter path when configured
|
|
138
151
|
- Sets sensible artifact defaults:
|
|
139
152
|
- trace: `retain-on-failure`
|
|
140
153
|
- screenshot: `only-on-failure`
|
|
141
154
|
- video: `retain-on-failure`
|
|
155
|
+
- Uploads the run to hosted Sentinel at the end of the test run
|
|
142
156
|
|
|
143
157
|
## Recommended Cloud Setup
|
|
144
158
|
|
|
@@ -175,7 +189,7 @@ Use this cloud setup when you want:
|
|
|
175
189
|
- richer DOM-aware diagnosis
|
|
176
190
|
- more reliable code patches grounded in real page state
|
|
177
191
|
|
|
178
|
-
Free and local-only users do not need this. The standard `withSentinel()` setup remains the simplest path and
|
|
192
|
+
Free and local-only users do not need this. The standard `withSentinel()` setup remains the simplest path and will upload a hosted Sentinel report automatically.
|
|
179
193
|
|
|
180
194
|
## Options
|
|
181
195
|
|
|
@@ -187,9 +201,6 @@ withSentinel(config, {
|
|
|
187
201
|
testResultsDir: "test-results",
|
|
188
202
|
artifactDirs: ["tmp/extra-artifacts"],
|
|
189
203
|
verbose: true,
|
|
190
|
-
localReportDir: "sentinel-report",
|
|
191
|
-
localReportFileName: "index.html",
|
|
192
|
-
localRedirectFileName: "sentinel-debug.html",
|
|
193
204
|
});
|
|
194
205
|
```
|
|
195
206
|
|
|
@@ -202,6 +213,10 @@ Sentinel Cloud adds:
|
|
|
202
213
|
- AI-generated failure summaries
|
|
203
214
|
- flaky test detection
|
|
204
215
|
- shareable run links
|
|
216
|
+
- longer retention
|
|
217
|
+
- compare against previous runs
|
|
218
|
+
- recurring failure history
|
|
219
|
+
- richer fix suggestions and team workflows
|
|
205
220
|
|
|
206
221
|
Free for up to 100 CI runs per month.
|
|
207
222
|
Create an account at [sentinelqa.com](https://sentinelqa.com).
|
package/dist/index.d.ts
CHANGED
|
@@ -23,9 +23,6 @@ export type SentinelPlaywrightOptions = {
|
|
|
23
23
|
testResultsDir?: string;
|
|
24
24
|
artifactDirs?: string[];
|
|
25
25
|
verbose?: boolean;
|
|
26
|
-
localReportDir?: string;
|
|
27
|
-
localReportFileName?: string;
|
|
28
|
-
localRedirectFileName?: string;
|
|
29
26
|
};
|
|
30
27
|
export declare function withSentinel(config: PlaywrightConfig, options?: SentinelPlaywrightOptions): PlaywrightConfig;
|
|
31
28
|
export declare function resolveSentinelPaths(config: PlaywrightConfig, options?: SentinelPlaywrightOptions): SentinelResolvedPaths;
|
package/dist/index.js
CHANGED
|
@@ -105,10 +105,7 @@ function withSentinel(config, options = {}) {
|
|
|
105
105
|
playwrightReportDir,
|
|
106
106
|
testResultsDir,
|
|
107
107
|
artifactDirs,
|
|
108
|
-
verbose: options.verbose ?? false
|
|
109
|
-
localReportDir: options.localReportDir,
|
|
110
|
-
localReportFileName: options.localReportFileName,
|
|
111
|
-
localRedirectFileName: options.localRedirectFileName
|
|
108
|
+
verbose: options.verbose ?? false
|
|
112
109
|
};
|
|
113
110
|
const sentinelIndex = reporters.findIndex((entry) => getReporterName(entry) === sentinelReporterPath);
|
|
114
111
|
if (sentinelIndex !== -1) {
|
package/dist/reporter.d.ts
CHANGED
|
@@ -5,9 +5,6 @@ type ReporterOptions = {
|
|
|
5
5
|
testResultsDir: string;
|
|
6
6
|
artifactDirs?: string[];
|
|
7
7
|
verbose?: boolean;
|
|
8
|
-
localReportDir?: string;
|
|
9
|
-
localReportFileName?: string;
|
|
10
|
-
localRedirectFileName?: string;
|
|
11
8
|
};
|
|
12
9
|
declare class SentinelReporter {
|
|
13
10
|
private failedCount;
|
|
@@ -16,7 +13,6 @@ declare class SentinelReporter {
|
|
|
16
13
|
constructor(options: ReporterOptions);
|
|
17
14
|
onBegin(config: any, suite: any): void;
|
|
18
15
|
onTestEnd(test: any, result: any): Promise<void>;
|
|
19
|
-
private printLocalReport;
|
|
20
16
|
onEnd(): Promise<void>;
|
|
21
17
|
}
|
|
22
18
|
export = SentinelReporter;
|
package/dist/reporter.js
CHANGED
|
@@ -1,33 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
const path_1 = __importDefault(require("path"));
|
|
6
|
-
const url_1 = require("url");
|
|
7
2
|
const node_1 = require("@sentinelqa/uploader/node");
|
|
8
3
|
const env_1 = require("./env");
|
|
9
|
-
const localReport_1 = require("./localReport");
|
|
10
4
|
const quickDiagnosis_1 = require("./quickDiagnosis");
|
|
11
5
|
const { sentinelCaptureFailureContextFromReporter } = require("@sentinelqa/uploader/playwright");
|
|
12
|
-
const pluralize = (count, singular, plural) => {
|
|
13
|
-
return count === 1 ? singular : plural;
|
|
14
|
-
};
|
|
15
|
-
const formatTerminalLink = (label, target) => {
|
|
16
|
-
if (!process.stdout.isTTY)
|
|
17
|
-
return label;
|
|
18
|
-
return `\u001B]8;;${target}\u0007${label}\u001B]8;;\u0007`;
|
|
19
|
-
};
|
|
20
6
|
const colorize = (value, code) => {
|
|
21
7
|
if (!process.stdout.isTTY)
|
|
22
8
|
return value;
|
|
23
9
|
return `\u001b[${code}m${value}\u001b[0m`;
|
|
24
10
|
};
|
|
25
|
-
const bold = (value) => colorize(value, "1");
|
|
26
11
|
const green = (value) => colorize(value, "32");
|
|
27
|
-
const cyan = (value) => colorize(value, "36");
|
|
28
12
|
const yellow = (value) => colorize(value, "33");
|
|
29
13
|
const dim = (value) => colorize(value, "2");
|
|
30
|
-
const magenta = (value) => colorize(value, "35");
|
|
31
14
|
class SentinelReporter {
|
|
32
15
|
constructor(options) {
|
|
33
16
|
this.failedCount = 0;
|
|
@@ -59,75 +42,21 @@ class SentinelReporter {
|
|
|
59
42
|
this.failedCount += 1;
|
|
60
43
|
}
|
|
61
44
|
}
|
|
62
|
-
|
|
63
|
-
const localReportPath = localReport.htmlPath;
|
|
64
|
-
const relativeReportPath = path_1.default
|
|
65
|
-
.relative(process.cwd(), localReportPath)
|
|
66
|
-
.replace(/\\/g, "/");
|
|
67
|
-
const displayPath = relativeReportPath.startsWith(".")
|
|
68
|
-
? relativeReportPath
|
|
69
|
-
: `./${relativeReportPath}`;
|
|
70
|
-
const openCommand = `open ${displayPath}`;
|
|
45
|
+
async onEnd() {
|
|
71
46
|
console.log("");
|
|
72
47
|
console.log(green("✔ Artifacts collected"));
|
|
73
|
-
console.log(green("✔ Sentinel HTML debugging report created"));
|
|
74
|
-
console.log("");
|
|
75
|
-
console.log(bold("Report"));
|
|
76
|
-
console.log(` ${cyan(formatTerminalLink(displayPath, (0, url_1.pathToFileURL)(localReportPath).href))}`);
|
|
77
|
-
console.log("");
|
|
78
|
-
console.log(bold("Open"));
|
|
79
|
-
console.log(` ${cyan(openCommand)}`);
|
|
80
|
-
console.log("");
|
|
81
48
|
const quickDiagnosis = (0, quickDiagnosis_1.buildQuickDiagnosis)(this.options.playwrightJsonPath);
|
|
82
49
|
if (quickDiagnosis?.lines.length) {
|
|
50
|
+
console.log("");
|
|
83
51
|
console.log(yellow("Quick diagnosis"));
|
|
84
52
|
for (const line of quickDiagnosis.lines) {
|
|
85
53
|
console.log(` ${dim(line)}`);
|
|
86
54
|
}
|
|
87
|
-
console.log("");
|
|
88
|
-
}
|
|
89
|
-
if (localReport.runDiff) {
|
|
90
|
-
console.log(yellow("Run-to-run diff"));
|
|
91
|
-
console.log(` ${dim(`New failures: ${localReport.runDiff.newFailures.length}`)}`);
|
|
92
|
-
console.log(` ${dim(`Fixed since last run: ${localReport.runDiff.fixedTests.length}`)}`);
|
|
93
|
-
console.log(` ${dim(`Still failing: ${localReport.runDiff.stillFailing.length}`)}`);
|
|
94
|
-
console.log("");
|
|
95
|
-
}
|
|
96
|
-
console.log(yellow("Tip"));
|
|
97
|
-
console.log(` ${dim("Want full AI analysis, shareable run links, and CI history?")}`);
|
|
98
|
-
console.log(` ${dim("Try Sentinel Cloud Beta free:")} ${cyan(formatTerminalLink("https://sentinelqa.com", "https://sentinelqa.com"))}`);
|
|
99
|
-
console.log("");
|
|
100
|
-
console.log(` ${magenta("★ If this reporter helped you debug faster,")}`);
|
|
101
|
-
console.log(` ${dim("consider starring the project:")}`);
|
|
102
|
-
console.log(` ${cyan(formatTerminalLink("https://github.com/adnangradascevic/playwright-reporter", "https://github.com/adnangradascevic/playwright-reporter"))}`);
|
|
103
|
-
}
|
|
104
|
-
async onEnd() {
|
|
105
|
-
const hasSentinelToken = Boolean(process.env.SENTINEL_TOKEN);
|
|
106
|
-
const hasCiEnv = (0, node_1.hasSupportedCiEnv)(process.env);
|
|
107
|
-
const localUploadEnabled = (0, node_1.isLocalUploadEnabled)(process.env);
|
|
108
|
-
if (!hasSentinelToken || (!hasCiEnv && !localUploadEnabled)) {
|
|
109
|
-
const localReport = (0, localReport_1.generateLocalDebugReport)({
|
|
110
|
-
playwrightJsonPath: this.options.playwrightJsonPath,
|
|
111
|
-
playwrightReportDir: this.options.playwrightReportDir,
|
|
112
|
-
testResultsDir: this.options.testResultsDir,
|
|
113
|
-
artifactDirs: this.options.artifactDirs || [],
|
|
114
|
-
reportDir: this.options.localReportDir,
|
|
115
|
-
reportFileName: this.options.localReportFileName,
|
|
116
|
-
redirectFileName: this.options.localRedirectFileName
|
|
117
|
-
});
|
|
118
|
-
this.printLocalReport(localReport);
|
|
119
|
-
console.log("");
|
|
120
|
-
if (hasSentinelToken && !hasCiEnv && !localUploadEnabled) {
|
|
121
|
-
console.log("Sentinel upload skipped for this local run.");
|
|
122
|
-
console.log("To upload local runs, set SENTINEL_UPLOAD_LOCAL=1 and provide the required CI metadata.");
|
|
123
|
-
console.log("");
|
|
124
|
-
}
|
|
125
|
-
return;
|
|
126
55
|
}
|
|
127
56
|
console.log("");
|
|
128
|
-
console.log("Uploading
|
|
57
|
+
console.log("Uploading hosted debugging report to Sentinel...");
|
|
129
58
|
console.log("");
|
|
130
|
-
const
|
|
59
|
+
const upload = await (0, node_1.runSentinelUpload)({
|
|
131
60
|
playwrightJsonPath: this.options.playwrightJsonPath,
|
|
132
61
|
playwrightReportDir: this.options.playwrightReportDir,
|
|
133
62
|
testResultsDir: this.options.testResultsDir,
|
|
@@ -137,11 +66,19 @@ class SentinelReporter {
|
|
|
137
66
|
SENTINEL_REPORTER_PROJECT: this.options.project || undefined
|
|
138
67
|
}
|
|
139
68
|
});
|
|
140
|
-
if (exitCode !== 0) {
|
|
141
|
-
throw new Error(`Sentinel upload failed with exit code ${exitCode}`);
|
|
69
|
+
if (upload.exitCode !== 0) {
|
|
70
|
+
throw new Error(`Sentinel upload failed with exit code ${upload.exitCode}`);
|
|
142
71
|
}
|
|
143
72
|
console.log("");
|
|
144
|
-
console.log("✔
|
|
73
|
+
console.log("✔ Hosted report uploaded to Sentinel");
|
|
74
|
+
if (upload.shareRunUrl || upload.internalRunUrl) {
|
|
75
|
+
console.log("");
|
|
76
|
+
console.log("Sentinel report");
|
|
77
|
+
console.log(` ${upload.shareRunUrl || upload.internalRunUrl}`);
|
|
78
|
+
if (upload.shareLabel) {
|
|
79
|
+
console.log(` ${dim(upload.shareLabel)}`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
145
82
|
}
|
|
146
83
|
}
|
|
147
84
|
module.exports = SentinelReporter;
|