@actboard/playwright-reporter 1.0.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 +270 -0
- package/dist/index.d.ts +73 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +189 -0
- package/dist/index.js.map +1 -0
- package/package.json +53 -0
package/README.md
ADDED
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
# @actboard/playwright-reporter
|
|
2
|
+
|
|
3
|
+
> The official Playwright reporter for [ActBoard](https://actboard.dev) — a self-hostable dashboard that stores your Playwright test history, tracks pass rates, surfaces flaky tests, and connects to your CI pipeline.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install --save-dev @actboard/playwright-reporter
|
|
11
|
+
# or
|
|
12
|
+
yarn add -D @actboard/playwright-reporter
|
|
13
|
+
# or
|
|
14
|
+
pnpm add -D @actboard/playwright-reporter
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Quick Start
|
|
18
|
+
|
|
19
|
+
### 1. Start ActBoard
|
|
20
|
+
|
|
21
|
+
**Cloud:** Sign up at [actboard.dev](https://actboard.dev) and get an API key.
|
|
22
|
+
|
|
23
|
+
**Self-hosted (Docker):**
|
|
24
|
+
```bash
|
|
25
|
+
docker run -p 3141:3141 -v actboard_data:/app/data actboard/server:latest
|
|
26
|
+
# Then seed demo data:
|
|
27
|
+
docker exec actboard node scripts/seed.js
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
**Self-hosted (Node.js):**
|
|
31
|
+
```bash
|
|
32
|
+
npx actboard-server # starts on http://localhost:3141
|
|
33
|
+
npx actboard-server seed # seed demo data
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### 2. Configure the reporter
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
// playwright.config.ts
|
|
40
|
+
import { defineConfig } from '@playwright/test';
|
|
41
|
+
|
|
42
|
+
export default defineConfig({
|
|
43
|
+
reporter: [
|
|
44
|
+
['list'], // keep the terminal reporter
|
|
45
|
+
['@actboard/playwright-reporter', {
|
|
46
|
+
serverUrl: 'http://localhost:3141', // or https://actboard.dev
|
|
47
|
+
apiKey: process.env.ACTBOARD_API_KEY,
|
|
48
|
+
project: 'e2e-production', // must match your project slug
|
|
49
|
+
branch: process.env.GITHUB_REF_NAME || 'local',
|
|
50
|
+
commitSha: process.env.GITHUB_SHA,
|
|
51
|
+
triggeredBy: process.env.CI ? 'ci' : 'local',
|
|
52
|
+
}],
|
|
53
|
+
],
|
|
54
|
+
});
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### 3. Run your tests
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
ACTBOARD_API_KEY=act_yourkey npx playwright test
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Results appear in the ActBoard dashboard immediately after the run completes.
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## Configuration Options
|
|
68
|
+
|
|
69
|
+
| Option | Type | Required | Default | Description |
|
|
70
|
+
|--------|------|----------|---------|-------------|
|
|
71
|
+
| `apiKey` | `string` | ✓ | `ACTBOARD_API_KEY` env | Project API key from ActBoard dashboard |
|
|
72
|
+
| `serverUrl` | `string` | | `http://localhost:3141` | ActBoard server URL |
|
|
73
|
+
| `project` | `string` | | `ACTBOARD_PROJECT` env | Project slug (from Settings → Project) |
|
|
74
|
+
| `branch` | `string` | | `GITHUB_REF_NAME` or `'local'` | Git branch name |
|
|
75
|
+
| `commitSha` | `string` | | `GITHUB_SHA` | Full commit SHA |
|
|
76
|
+
| `commitMessage` | `string` | | `CI_COMMIT_MESSAGE` | Short commit message |
|
|
77
|
+
| `triggeredBy` | `string` | | `'ci'` / `'local'` | What triggered the run |
|
|
78
|
+
| `browsers` | `string[]` | | auto-detected | Override browser list |
|
|
79
|
+
| `metadata` | `object` | | `{}` | Extra key-value data attached to the run |
|
|
80
|
+
| `timeout` | `number` | | `30000` | HTTP request timeout (ms) |
|
|
81
|
+
| `verbose` | `boolean` | | `true` | Print ActBoard status to stdout |
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## Environment Variables
|
|
86
|
+
|
|
87
|
+
The reporter reads these automatically — no code changes needed in CI:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
ACTBOARD_API_KEY=act_myproject_abc123 # required
|
|
91
|
+
ACTBOARD_SERVER_URL=https://actboard.dev # optional, default: localhost:3141
|
|
92
|
+
ACTBOARD_PROJECT=e2e-production # optional, use if project not set in config
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## CI Integration Examples
|
|
98
|
+
|
|
99
|
+
### GitHub Actions
|
|
100
|
+
|
|
101
|
+
```yaml
|
|
102
|
+
# .github/workflows/playwright.yml
|
|
103
|
+
name: Playwright Tests
|
|
104
|
+
|
|
105
|
+
on: [push, pull_request]
|
|
106
|
+
|
|
107
|
+
jobs:
|
|
108
|
+
test:
|
|
109
|
+
runs-on: ubuntu-latest
|
|
110
|
+
steps:
|
|
111
|
+
- uses: actions/checkout@v4
|
|
112
|
+
|
|
113
|
+
- uses: actions/setup-node@v4
|
|
114
|
+
with:
|
|
115
|
+
node-version: 20
|
|
116
|
+
cache: npm
|
|
117
|
+
|
|
118
|
+
- run: npm ci
|
|
119
|
+
- run: npx playwright install --with-deps
|
|
120
|
+
|
|
121
|
+
- name: Run Playwright Tests
|
|
122
|
+
env:
|
|
123
|
+
ACTBOARD_API_KEY: ${{ secrets.ACTBOARD_API_KEY }}
|
|
124
|
+
ACTBOARD_SERVER_URL: ${{ secrets.ACTBOARD_SERVER_URL }}
|
|
125
|
+
run: npx playwright test
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Add `ACTBOARD_API_KEY` and `ACTBOARD_SERVER_URL` to **Settings → Secrets and variables → Actions**.
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
### GitLab CI
|
|
133
|
+
|
|
134
|
+
```yaml
|
|
135
|
+
# .gitlab-ci.yml
|
|
136
|
+
playwright:
|
|
137
|
+
image: mcr.microsoft.com/playwright:v1.44.0-jammy
|
|
138
|
+
stage: test
|
|
139
|
+
variables:
|
|
140
|
+
ACTBOARD_API_KEY: $ACTBOARD_API_KEY
|
|
141
|
+
ACTBOARD_SERVER_URL: $ACTBOARD_SERVER_URL
|
|
142
|
+
script:
|
|
143
|
+
- npm ci
|
|
144
|
+
- npx playwright test
|
|
145
|
+
artifacts:
|
|
146
|
+
when: always
|
|
147
|
+
paths:
|
|
148
|
+
- playwright-report/
|
|
149
|
+
expire_in: 1 week
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
### CircleCI
|
|
155
|
+
|
|
156
|
+
```yaml
|
|
157
|
+
# .circleci/config.yml
|
|
158
|
+
version: 2.1
|
|
159
|
+
|
|
160
|
+
jobs:
|
|
161
|
+
playwright:
|
|
162
|
+
docker:
|
|
163
|
+
- image: mcr.microsoft.com/playwright:v1.44.0-jammy
|
|
164
|
+
steps:
|
|
165
|
+
- checkout
|
|
166
|
+
- run: npm ci
|
|
167
|
+
- run:
|
|
168
|
+
name: Run Playwright Tests
|
|
169
|
+
command: npx playwright test
|
|
170
|
+
environment:
|
|
171
|
+
ACTBOARD_API_KEY: $ACTBOARD_API_KEY
|
|
172
|
+
ACTBOARD_SERVER_URL: $ACTBOARD_SERVER_URL
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
### Jenkins
|
|
178
|
+
|
|
179
|
+
```groovy
|
|
180
|
+
// Jenkinsfile
|
|
181
|
+
pipeline {
|
|
182
|
+
agent any
|
|
183
|
+
environment {
|
|
184
|
+
ACTBOARD_API_KEY = credentials('actboard-api-key')
|
|
185
|
+
ACTBOARD_SERVER_URL = 'https://actboard.yourcompany.com'
|
|
186
|
+
}
|
|
187
|
+
stages {
|
|
188
|
+
stage('Test') {
|
|
189
|
+
steps {
|
|
190
|
+
sh 'npm ci'
|
|
191
|
+
sh 'npx playwright install --with-deps chromium'
|
|
192
|
+
sh 'npx playwright test'
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
post {
|
|
197
|
+
always {
|
|
198
|
+
publishHTML(target: [reportDir: 'playwright-report', reportFiles: 'index.html', reportName: 'Playwright Report'])
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
### Azure DevOps
|
|
207
|
+
|
|
208
|
+
```yaml
|
|
209
|
+
# azure-pipelines.yml
|
|
210
|
+
trigger:
|
|
211
|
+
- main
|
|
212
|
+
|
|
213
|
+
pool:
|
|
214
|
+
vmImage: ubuntu-latest
|
|
215
|
+
|
|
216
|
+
variables:
|
|
217
|
+
ACTBOARD_API_KEY: $(ACTBOARD_API_KEY)
|
|
218
|
+
ACTBOARD_SERVER_URL: $(ACTBOARD_SERVER_URL)
|
|
219
|
+
|
|
220
|
+
steps:
|
|
221
|
+
- task: NodeTool@0
|
|
222
|
+
inputs:
|
|
223
|
+
versionSpec: '20.x'
|
|
224
|
+
|
|
225
|
+
- script: npm ci
|
|
226
|
+
displayName: Install dependencies
|
|
227
|
+
|
|
228
|
+
- script: npx playwright install --with-deps
|
|
229
|
+
displayName: Install browsers
|
|
230
|
+
|
|
231
|
+
- script: npx playwright test
|
|
232
|
+
displayName: Run Playwright tests
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
Add `ACTBOARD_API_KEY` and `ACTBOARD_SERVER_URL` as pipeline variables (mark as secret).
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
## How It Works
|
|
240
|
+
|
|
241
|
+
1. The reporter hooks into Playwright's lifecycle via `onBegin` / `onTestEnd` / `onEnd`
|
|
242
|
+
2. Results are buffered in memory during the run (zero impact on test performance)
|
|
243
|
+
3. When `onEnd` fires, results are POSTed to `POST /api/runs` on your ActBoard server
|
|
244
|
+
4. The server stores results in SQLite (self-host) or PostgreSQL (cloud) and finalizes the run record
|
|
245
|
+
5. The dashboard immediately reflects the new run
|
|
246
|
+
|
|
247
|
+
If the server is unreachable, the reporter logs a warning and exits gracefully — your test run always completes regardless.
|
|
248
|
+
|
|
249
|
+
---
|
|
250
|
+
|
|
251
|
+
## Troubleshooting
|
|
252
|
+
|
|
253
|
+
**Reporter not publishing results:**
|
|
254
|
+
- Check `ACTBOARD_API_KEY` is set in your CI environment
|
|
255
|
+
- Verify `serverUrl` is reachable from your CI runner (firewall / VPN?)
|
|
256
|
+
- Run with `verbose: true` (default) and check stdout for error messages
|
|
257
|
+
|
|
258
|
+
**`Invalid API key` error:**
|
|
259
|
+
- Copy the key exactly from Settings → API Keys in the dashboard
|
|
260
|
+
- Keys are shown only once when created — generate a new one if lost
|
|
261
|
+
|
|
262
|
+
**Connection timeout:**
|
|
263
|
+
- Increase `timeout` option (default: 30 seconds)
|
|
264
|
+
- Check that your ActBoard server is healthy: `curl http://your-server/api/health`
|
|
265
|
+
|
|
266
|
+
---
|
|
267
|
+
|
|
268
|
+
## License
|
|
269
|
+
|
|
270
|
+
MIT © [ActBoard](https://actboard.dev)
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @actboard/playwright-reporter
|
|
3
|
+
*
|
|
4
|
+
* Playwright reporter that buffers test results during a run and publishes
|
|
5
|
+
* them to an ActBoard server (self-hosted or cloud) when the run ends.
|
|
6
|
+
*
|
|
7
|
+
* Usage in playwright.config.ts:
|
|
8
|
+
*
|
|
9
|
+
* import { defineConfig } from '@playwright/test';
|
|
10
|
+
*
|
|
11
|
+
* export default defineConfig({
|
|
12
|
+
* reporter: [
|
|
13
|
+
* ['list'],
|
|
14
|
+
* ['@actboard/playwright-reporter', {
|
|
15
|
+
* serverUrl: 'http://localhost:3141', // or your cloud URL
|
|
16
|
+
* apiKey: process.env.ACTBOARD_API_KEY,
|
|
17
|
+
* project: 'e2e-production', // matches project slug
|
|
18
|
+
* branch: process.env.GITHUB_REF_NAME || 'local',
|
|
19
|
+
* commitSha: process.env.GITHUB_SHA,
|
|
20
|
+
* commitMessage: process.env.COMMIT_MESSAGE,
|
|
21
|
+
* triggeredBy: process.env.CI ? 'ci' : 'local',
|
|
22
|
+
* // Optional: browsers to tag runs with (auto-detected if omitted)
|
|
23
|
+
* browsers: ['chromium'],
|
|
24
|
+
* // Optional: extra metadata attached to the run
|
|
25
|
+
* metadata: { ci_url: process.env.CI_JOB_URL },
|
|
26
|
+
* }],
|
|
27
|
+
* ],
|
|
28
|
+
* });
|
|
29
|
+
*/
|
|
30
|
+
import type { Reporter, FullConfig, Suite, TestCase, TestResult, FullResult } from '@playwright/test/reporter';
|
|
31
|
+
export interface ActBoardOptions {
|
|
32
|
+
/**
|
|
33
|
+
* URL of your ActBoard server.
|
|
34
|
+
* Priority: this option → ACTBOARD_SERVER_URL env var → http://localhost:3141
|
|
35
|
+
*/
|
|
36
|
+
serverUrl?: string;
|
|
37
|
+
/** API key generated from the ActBoard dashboard */
|
|
38
|
+
apiKey: string;
|
|
39
|
+
/**
|
|
40
|
+
* Project slug (must match a project on the server).
|
|
41
|
+
* Priority: this option → ACTBOARD_PROJECT env var
|
|
42
|
+
*/
|
|
43
|
+
project?: string;
|
|
44
|
+
/** Git branch name */
|
|
45
|
+
branch?: string;
|
|
46
|
+
/** Full commit SHA */
|
|
47
|
+
commitSha?: string;
|
|
48
|
+
/** Short commit message */
|
|
49
|
+
commitMessage?: string;
|
|
50
|
+
/** What triggered this run (push, manual, schedule, ci, local…) */
|
|
51
|
+
triggeredBy?: string;
|
|
52
|
+
/** List of browsers used in this run (auto-detected from results if omitted) */
|
|
53
|
+
browsers?: string[];
|
|
54
|
+
/** Extra metadata attached to the run (JSON-serialisable object) */
|
|
55
|
+
metadata?: Record<string, unknown>;
|
|
56
|
+
/** Timeout for the HTTP publish request in ms (default: 30000) */
|
|
57
|
+
timeout?: number;
|
|
58
|
+
/** Set to false to suppress ActBoard output (default: true) */
|
|
59
|
+
verbose?: boolean;
|
|
60
|
+
}
|
|
61
|
+
declare class ActBoardReporter implements Reporter {
|
|
62
|
+
private readonly options;
|
|
63
|
+
private readonly suitesMap;
|
|
64
|
+
private startTime;
|
|
65
|
+
private detectedBrowsers;
|
|
66
|
+
constructor(options: ActBoardOptions);
|
|
67
|
+
onBegin(_config: FullConfig, _suite: Suite): void;
|
|
68
|
+
onTestEnd(test: TestCase, result: TestResult): void;
|
|
69
|
+
onEnd(_result: FullResult): Promise<void>;
|
|
70
|
+
printsToStdio(): boolean;
|
|
71
|
+
}
|
|
72
|
+
export default ActBoardReporter;
|
|
73
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,KAAK,EACV,QAAQ,EACR,UAAU,EACV,KAAK,EACL,QAAQ,EACR,UAAU,EACV,UAAU,EACX,MAAM,2BAA2B,CAAC;AAInC,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oDAAoD;IACpD,MAAM,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,sBAAsB;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,sBAAsB;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2BAA2B;IAC3B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,mEAAmE;IACnE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gFAAgF;IAChF,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,oEAAoE;IACpE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,kEAAkE;IAClE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,+DAA+D;IAC/D,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAkED,cAAM,gBAAiB,YAAW,QAAQ;IACxC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA4B;IACpD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAoC;IAC9D,OAAO,CAAC,SAAS,CAAc;IAC/B,OAAO,CAAC,gBAAgB,CAAqB;gBAEjC,OAAO,EAAE,eAAe;IAoBpC,OAAO,CAAC,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,GAAG,IAAI;IAOjD,SAAS,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI;IA+B7C,KAAK,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IA6D/C,aAAa,IAAI,OAAO;CAGzB;AAED,eAAe,gBAAgB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @actboard/playwright-reporter
|
|
4
|
+
*
|
|
5
|
+
* Playwright reporter that buffers test results during a run and publishes
|
|
6
|
+
* them to an ActBoard server (self-hosted or cloud) when the run ends.
|
|
7
|
+
*
|
|
8
|
+
* Usage in playwright.config.ts:
|
|
9
|
+
*
|
|
10
|
+
* import { defineConfig } from '@playwright/test';
|
|
11
|
+
*
|
|
12
|
+
* export default defineConfig({
|
|
13
|
+
* reporter: [
|
|
14
|
+
* ['list'],
|
|
15
|
+
* ['@actboard/playwright-reporter', {
|
|
16
|
+
* serverUrl: 'http://localhost:3141', // or your cloud URL
|
|
17
|
+
* apiKey: process.env.ACTBOARD_API_KEY,
|
|
18
|
+
* project: 'e2e-production', // matches project slug
|
|
19
|
+
* branch: process.env.GITHUB_REF_NAME || 'local',
|
|
20
|
+
* commitSha: process.env.GITHUB_SHA,
|
|
21
|
+
* commitMessage: process.env.COMMIT_MESSAGE,
|
|
22
|
+
* triggeredBy: process.env.CI ? 'ci' : 'local',
|
|
23
|
+
* // Optional: browsers to tag runs with (auto-detected if omitted)
|
|
24
|
+
* browsers: ['chromium'],
|
|
25
|
+
* // Optional: extra metadata attached to the run
|
|
26
|
+
* metadata: { ci_url: process.env.CI_JOB_URL },
|
|
27
|
+
* }],
|
|
28
|
+
* ],
|
|
29
|
+
* });
|
|
30
|
+
*/
|
|
31
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
32
|
+
// ── Helpers ────────────────────────────────────────────
|
|
33
|
+
function resolveStatus(result, test) {
|
|
34
|
+
if (result.status === 'skipped')
|
|
35
|
+
return 'skipped';
|
|
36
|
+
// expectedStatus lives on TestCase, not TestResult
|
|
37
|
+
if (result.status === test.expectedStatus) {
|
|
38
|
+
// Flaky = eventually passed but needed at least one retry
|
|
39
|
+
return test.results.length > 1 && test.results.some(r => r.status !== test.expectedStatus)
|
|
40
|
+
? 'flaky'
|
|
41
|
+
: 'passed';
|
|
42
|
+
}
|
|
43
|
+
return 'failed';
|
|
44
|
+
}
|
|
45
|
+
function extractBrowser(result) {
|
|
46
|
+
// Playwright attaches project name / browser info in various ways
|
|
47
|
+
const projectName = result
|
|
48
|
+
// @ts-ignore — internal field available in Playwright ≥1.38
|
|
49
|
+
?.workerIndex !== undefined ? null : null;
|
|
50
|
+
// Try to find browser from result annotations or title path
|
|
51
|
+
const titlePath = result?.titlePath?.() ?? [];
|
|
52
|
+
for (const seg of titlePath) {
|
|
53
|
+
const m = seg.match(/chromium|firefox|webkit/i);
|
|
54
|
+
if (m)
|
|
55
|
+
return m[0].toLowerCase();
|
|
56
|
+
}
|
|
57
|
+
// Environment variable fallback
|
|
58
|
+
if (process.env.BROWSER)
|
|
59
|
+
return process.env.BROWSER.toLowerCase();
|
|
60
|
+
if (process.env.PLAYWRIGHT_BROWSER)
|
|
61
|
+
return process.env.PLAYWRIGHT_BROWSER.toLowerCase();
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
function groupBySuite(collected) {
|
|
65
|
+
return Array.from(collected.entries()).map(([file, tests]) => ({
|
|
66
|
+
title: file.split('/').pop() ?? file,
|
|
67
|
+
file,
|
|
68
|
+
tests,
|
|
69
|
+
}));
|
|
70
|
+
}
|
|
71
|
+
// ── Reporter Class ─────────────────────────────────────
|
|
72
|
+
class ActBoardReporter {
|
|
73
|
+
constructor(options) {
|
|
74
|
+
this.suitesMap = new Map();
|
|
75
|
+
this.startTime = Date.now();
|
|
76
|
+
this.detectedBrowsers = new Set();
|
|
77
|
+
const apiKey = options.apiKey ?? process.env.ACTBOARD_API_KEY;
|
|
78
|
+
if (!apiKey) {
|
|
79
|
+
throw new Error('[ActBoard] apiKey is required. Set it in the reporter options or via the ACTBOARD_API_KEY environment variable.');
|
|
80
|
+
}
|
|
81
|
+
this.options = {
|
|
82
|
+
serverUrl: (options.serverUrl ?? process.env.ACTBOARD_SERVER_URL ?? 'http://localhost:3141').replace(/\/$/, ''),
|
|
83
|
+
apiKey,
|
|
84
|
+
project: options.project ?? process.env.ACTBOARD_PROJECT ?? '',
|
|
85
|
+
branch: options.branch ?? process.env.GITHUB_REF_NAME ?? process.env.CI_COMMIT_BRANCH ?? 'local',
|
|
86
|
+
commitSha: options.commitSha ?? process.env.GITHUB_SHA ?? process.env.CI_COMMIT_SHA ?? '',
|
|
87
|
+
commitMessage: options.commitMessage ?? process.env.CI_COMMIT_MESSAGE ?? '',
|
|
88
|
+
triggeredBy: options.triggeredBy ?? (process.env.CI ? 'ci' : 'local'),
|
|
89
|
+
browsers: options.browsers ?? [],
|
|
90
|
+
metadata: options.metadata ?? {},
|
|
91
|
+
timeout: options.timeout ?? 30000,
|
|
92
|
+
verbose: options.verbose ?? true,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
onBegin(_config, _suite) {
|
|
96
|
+
this.startTime = Date.now();
|
|
97
|
+
if (this.options.verbose) {
|
|
98
|
+
console.log(`\n 🎭 ActBoard reporter active → ${this.options.serverUrl}\n`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
onTestEnd(test, result) {
|
|
102
|
+
const file = test.location?.file ?? '__unknown__';
|
|
103
|
+
if (!this.suitesMap.has(file))
|
|
104
|
+
this.suitesMap.set(file, []);
|
|
105
|
+
// Track browser
|
|
106
|
+
const browser = extractBrowser(result);
|
|
107
|
+
if (browser)
|
|
108
|
+
this.detectedBrowsers.add(browser);
|
|
109
|
+
// Collapse all retries into one record: status of final attempt
|
|
110
|
+
const status = resolveStatus(result, test);
|
|
111
|
+
const retryCount = test.results.length - 1;
|
|
112
|
+
const err = result.error;
|
|
113
|
+
const testPayload = {
|
|
114
|
+
title: test.title,
|
|
115
|
+
full_title: test.titlePath().join(' > '),
|
|
116
|
+
file: file,
|
|
117
|
+
line: test.location?.line ?? null,
|
|
118
|
+
status,
|
|
119
|
+
duration_ms: result.duration,
|
|
120
|
+
retry_count: retryCount,
|
|
121
|
+
error_message: err?.message?.slice(0, 2000) ?? null,
|
|
122
|
+
error_stack: err?.stack?.slice(0, 5000) ?? null,
|
|
123
|
+
browser,
|
|
124
|
+
tags: test.tags ?? [],
|
|
125
|
+
started_at: result.startTime?.toISOString() ?? null,
|
|
126
|
+
};
|
|
127
|
+
this.suitesMap.get(file).push(testPayload);
|
|
128
|
+
}
|
|
129
|
+
async onEnd(_result) {
|
|
130
|
+
const suites = groupBySuite(this.suitesMap);
|
|
131
|
+
if (!suites.length) {
|
|
132
|
+
if (this.options.verbose)
|
|
133
|
+
console.log(' [ActBoard] No tests collected — skipping publish.');
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
const browsers = this.options.browsers.length > 0
|
|
137
|
+
? this.options.browsers
|
|
138
|
+
: Array.from(this.detectedBrowsers);
|
|
139
|
+
const payload = {
|
|
140
|
+
branch: this.options.branch || null,
|
|
141
|
+
commit_sha: this.options.commitSha || null,
|
|
142
|
+
commit_message: this.options.commitMessage || null,
|
|
143
|
+
triggered_by: this.options.triggeredBy,
|
|
144
|
+
browsers,
|
|
145
|
+
metadata: this.options.metadata,
|
|
146
|
+
suites,
|
|
147
|
+
};
|
|
148
|
+
if (this.options.verbose) {
|
|
149
|
+
process.stdout.write(` [ActBoard] Publishing ${suites.length} suite(s) to ${this.options.serverUrl}… `);
|
|
150
|
+
}
|
|
151
|
+
try {
|
|
152
|
+
const controller = new AbortController();
|
|
153
|
+
const timer = setTimeout(() => controller.abort(), this.options.timeout);
|
|
154
|
+
const res = await fetch(`${this.options.serverUrl}/api/runs`, {
|
|
155
|
+
method: 'POST',
|
|
156
|
+
headers: {
|
|
157
|
+
'Content-Type': 'application/json',
|
|
158
|
+
'Authorization': `Bearer ${this.options.apiKey}`,
|
|
159
|
+
},
|
|
160
|
+
body: JSON.stringify(payload),
|
|
161
|
+
signal: controller.signal,
|
|
162
|
+
});
|
|
163
|
+
clearTimeout(timer);
|
|
164
|
+
if (!res.ok) {
|
|
165
|
+
const body = await res.text().catch(() => '');
|
|
166
|
+
throw new Error(`HTTP ${res.status}: ${body.slice(0, 200)}`);
|
|
167
|
+
}
|
|
168
|
+
const { run } = await res.json();
|
|
169
|
+
if (this.options.verbose) {
|
|
170
|
+
console.log(`✓\n [ActBoard] Run published: ${run.id} (${run.status})`);
|
|
171
|
+
console.log(` [ActBoard] View at: ${this.options.serverUrl}/\n`);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
catch (err) {
|
|
175
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
176
|
+
if (this.options.verbose) {
|
|
177
|
+
console.error(`\n [ActBoard] ⚠ Failed to publish results: ${msg}`);
|
|
178
|
+
console.error(' [ActBoard] Results were NOT saved. Check your serverUrl and apiKey.\n');
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
printsToStdio() {
|
|
183
|
+
return false; // Don't suppress other reporters
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
exports.default = ActBoardReporter;
|
|
187
|
+
module.exports = ActBoardReporter;
|
|
188
|
+
module.exports.default = ActBoardReporter;
|
|
189
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@actboard/playwright-reporter",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Playwright reporter that streams test results to ActBoard — the self-hostable test history dashboard",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"require": "./dist/index.js",
|
|
10
|
+
"types": "./dist/index.d.ts"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsc",
|
|
15
|
+
"build:watch": "tsc --watch",
|
|
16
|
+
"prepublishOnly": "tsc"
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"dist/",
|
|
20
|
+
"README.md"
|
|
21
|
+
],
|
|
22
|
+
"keywords": [
|
|
23
|
+
"playwright",
|
|
24
|
+
"reporter",
|
|
25
|
+
"testing",
|
|
26
|
+
"dashboard",
|
|
27
|
+
"actboard",
|
|
28
|
+
"e2e",
|
|
29
|
+
"test-history",
|
|
30
|
+
"flaky-tests"
|
|
31
|
+
],
|
|
32
|
+
"license": "MIT",
|
|
33
|
+
"repository": {
|
|
34
|
+
"type": "git",
|
|
35
|
+
"url": "https://github.com/actboard/actboard.git",
|
|
36
|
+
"directory": "reporter"
|
|
37
|
+
},
|
|
38
|
+
"homepage": "https://actboard.dev",
|
|
39
|
+
"bugs": {
|
|
40
|
+
"url": "https://github.com/actboard/actboard/issues"
|
|
41
|
+
},
|
|
42
|
+
"publishConfig": {
|
|
43
|
+
"access": "public"
|
|
44
|
+
},
|
|
45
|
+
"peerDependencies": {
|
|
46
|
+
"@playwright/test": ">=1.38.0"
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@playwright/test": "^1.43.0",
|
|
50
|
+
"@types/node": "^20.0.0",
|
|
51
|
+
"typescript": "^5.4.5"
|
|
52
|
+
}
|
|
53
|
+
}
|