@piwitests/reporter 0.4.2

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 (45) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +234 -0
  3. package/dist/compression.d.ts +5 -0
  4. package/dist/compression.js +39 -0
  5. package/dist/config-wrapper.d.ts +21 -0
  6. package/dist/config-wrapper.js +64 -0
  7. package/dist/config.d.ts +104 -0
  8. package/dist/config.js +127 -0
  9. package/dist/crash-recovery.d.ts +23 -0
  10. package/dist/crash-recovery.js +105 -0
  11. package/dist/file-handler.d.ts +38 -0
  12. package/dist/file-handler.js +166 -0
  13. package/dist/fixtures.d.ts +25 -0
  14. package/dist/fixtures.js +156 -0
  15. package/dist/global-setup-module.d.ts +2 -0
  16. package/dist/global-setup-module.js +4 -0
  17. package/dist/helpers.d.ts +44 -0
  18. package/dist/helpers.js +288 -0
  19. package/dist/http-client.d.ts +42 -0
  20. package/dist/http-client.js +154 -0
  21. package/dist/index.d.ts +8 -0
  22. package/dist/index.js +6 -0
  23. package/dist/logger.d.ts +26 -0
  24. package/dist/logger.js +43 -0
  25. package/dist/metadata-collector.d.ts +32 -0
  26. package/dist/metadata-collector.js +243 -0
  27. package/dist/reporter.d.ts +65 -0
  28. package/dist/reporter.js +341 -0
  29. package/dist/run-submitter.d.ts +66 -0
  30. package/dist/run-submitter.js +184 -0
  31. package/dist/serializer.d.ts +45 -0
  32. package/dist/serializer.js +104 -0
  33. package/dist/skip-classify.d.ts +27 -0
  34. package/dist/skip-classify.js +40 -0
  35. package/dist/step-analyzer.d.ts +97 -0
  36. package/dist/step-analyzer.js +216 -0
  37. package/dist/stream-buffer.d.ts +17 -0
  38. package/dist/stream-buffer.js +102 -0
  39. package/dist/stream-manager.d.ts +74 -0
  40. package/dist/stream-manager.js +338 -0
  41. package/dist/types.d.ts +251 -0
  42. package/dist/types.js +14 -0
  43. package/dist/uploader.d.ts +86 -0
  44. package/dist/uploader.js +191 -0
  45. package/package.json +62 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025-present Fabien Ménager
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,234 @@
1
+ # Piwi Dashboard Reporter
2
+
3
+ A custom Playwright reporter that sends test results to a [Piwi Dashboard](https://piwitests.github.io) server. It handles uploading test results, HTML reports, trace files, and performance metrics — with optional live streaming of results as tests execute.
4
+
5
+ 📖 **[Full documentation](https://piwitests.github.io/reporter)**
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install --save-dev @piwitests/reporter
11
+ ```
12
+
13
+ ## Quick start
14
+
15
+ Add the reporter to your `playwright.config.ts`:
16
+
17
+ ```typescript
18
+ import { defineConfig } from '@playwright/test'
19
+
20
+ export default defineConfig({
21
+ reporter: [
22
+ ['list'],
23
+ ['@piwitests/reporter', {
24
+ serverUrl: 'http://localhost:3000',
25
+ projectName: 'my-project',
26
+ }],
27
+ ],
28
+ use: {
29
+ trace: 'retain-on-failure',
30
+ },
31
+ })
32
+ ```
33
+
34
+ Run your tests — results are uploaded automatically:
35
+
36
+ ```bash
37
+ npx playwright test
38
+ ```
39
+
40
+ ## Configuration Options
41
+
42
+ | Option | Type | Default | Description |
43
+ |-----------------------------|----------|---------------------------|------------------------------------------------------------------------|
44
+ | `serverUrl` | string | `'http://localhost:3000'` | URL of the Piwi Dashboard server |
45
+ | `projectName` | string | `'default-project'` | Name of the project to report results under |
46
+ | `uploadTraces` | boolean | `true` | Whether to upload trace files to the dashboard |
47
+ | `uploadReport` | boolean | `true` | Whether to upload the HTML report to the dashboard |
48
+ | `reports` | array | — | Additional report types to upload (html, monocart, blob, or custom) |
49
+ | `streaming` | boolean | `true` | Enable live streaming of results as tests complete |
50
+ | `streamingBatchSize` | number | `5` | Number of test results to batch before sending |
51
+ | `streamingBatchDelay` | number | `2000` | Max delay (ms) before flushing pending events |
52
+ | `projectDescription` | string | — | Description of the project |
53
+ | `environment` | string | — | Deployment environment for the run, e.g. `production`, `staging` |
54
+ | `relatedIssue` | string | — | Related issue reference (e.g., "PROJ-123") |
55
+ | `ciInfo` | string | — | CI job information |
56
+ | `tags` | string[] | — | Tags to categorize the test run |
57
+ | `customData` | object | — | Additional custom metadata as key-value pairs |
58
+ | `collectScmInfo` | boolean | `true` | Auto-collect git commit, branch, author |
59
+ | `collectCiInfo` | boolean | `true` | Auto-collect CI environment info |
60
+ | `collectPerformanceMetrics` | boolean | `true` | Collect step timings, network requests and web vitals from the fixture |
61
+ | `apiKey` | string | — | API key for authentication (preferred for CI) |
62
+ | `username` | string | — | Username for dashboard login (use `apiKey` instead when possible) |
63
+ | `password` | string | — | Password for dashboard login (used with `username`) |
64
+ | `verbose` | boolean | `false` | Enable verbose logging for debugging |
65
+
66
+ ## Live streaming
67
+
68
+ By default, the reporter streams test results to the dashboard in real-time. This allows you to monitor progress live in the dashboard UI while CI is still running.
69
+
70
+ To disable streaming and send all results at the end:
71
+
72
+ ```typescript
73
+ ['@piwitests/reporter', {
74
+ serverUrl: 'http://localhost:3000',
75
+ projectName: 'my-project',
76
+ streaming: false,
77
+ }]
78
+ ```
79
+
80
+ If the server doesn't support streaming (older versions), the reporter automatically falls back to batch mode.
81
+
82
+ ## Multiple reports
83
+
84
+ Attach multiple report types to a single test run:
85
+
86
+ ```typescript
87
+ export default defineConfig({
88
+ reporter: [
89
+ ['list'],
90
+ ['@playwright/test/reporter-html', { outputFolder: 'playwright-report' }],
91
+ ['monocart-reporter', { name: 'My Tests', outputFile: 'monocart-report/index.html' }],
92
+ ['@piwitests/reporter', {
93
+ serverUrl: 'http://localhost:3000',
94
+ projectName: 'my-project',
95
+ reports: [
96
+ { type: 'html' },
97
+ { type: 'monocart' },
98
+ { type: 'blob', dir: 'blob-report', label: 'Blob archive' },
99
+ ],
100
+ }],
101
+ ],
102
+ })
103
+ ```
104
+
105
+ ## Performance Metrics & Web Vitals
106
+
107
+ To capture network request timing and browser Web Vitals, use the provided fixtures:
108
+
109
+ ```typescript
110
+ // tests/fixtures.ts
111
+ import { test as base, expect } from '@playwright/test'
112
+ import { dashboardFixtures } from '@piwitests/reporter/fixtures'
113
+
114
+ export const test = base.extend(dashboardFixtures)
115
+ export { expect }
116
+ ```
117
+
118
+ Or as a drop-in replacement:
119
+
120
+ ```typescript
121
+ import { test, expect } from '@piwitests/reporter/fixtures'
122
+ ```
123
+
124
+ ### What gets captured
125
+
126
+ - **Network requests** — method, URL, status, duration, resource type. Aggregated on the dashboard into a *Slow API Endpoints* table grouped by `METHOD + normalized route`.
127
+ - **Browser Web Vitals** — TTFB, DOM Interactive, DOMContentLoaded, Load Complete, First Paint, First Contentful Paint — displayed with color-coded thresholds.
128
+
129
+ Both are only collected when `collectPerformanceMetrics` is `true` (the default).
130
+
131
+ ## Authentication
132
+
133
+ When the dashboard has authentication enabled, use an API key (recommended for CI):
134
+
135
+ ```typescript
136
+ ['@piwitests/reporter', {
137
+ serverUrl: 'https://your-dashboard.example.com',
138
+ projectName: 'my-project',
139
+ apiKey: process.env.PIWI_API_KEY,
140
+ }]
141
+ ```
142
+
143
+ Generate a key in the dashboard UI: **Settings → Users → API keys**. Store it as a CI secret.
144
+
145
+ Alternatively, use `username`/`password` — the reporter will call `/api/auth/login` automatically.
146
+
147
+ ## Automatic Metadata Collection
148
+
149
+ ### SCM Information (Git)
150
+
151
+ When `collectScmInfo` is enabled (default), the reporter collects:
152
+ - Commit hash and message
153
+ - Branch name
154
+ - Author name
155
+ - Remote URL
156
+
157
+ ### CI Information
158
+
159
+ When `collectCiInfo` is enabled (default), the reporter auto-detects:
160
+ - **GitHub Actions** — run ID, workflow, actor, repository, ref, SHA
161
+ - **Jenkins** — build number, build URL, job name
162
+ - **GitLab CI** — pipeline ID/URL, job ID/URL, job name
163
+ - **CircleCI** — build number/URL, job name, workflow
164
+ - **Travis CI** — build number/URL, job number
165
+ - **Azure Pipelines** — build number, build ID/URL, job name
166
+
167
+ ## How It Works
168
+
169
+ 1. When tests start, the reporter creates a run on the server (streaming mode) or collects results locally (batch mode)
170
+ 2. As tests complete, results are streamed in batches to the server
171
+ 3. After all tests finish, HTML reports are compressed and uploaded
172
+ 4. Trace files from test attachments are uploaded
173
+ 5. Network request and web vitals data (from fixtures) are included per test case
174
+ 6. The server stores everything and makes it available in the dashboard UI
175
+
176
+ ## Requirements
177
+
178
+ - Node.js 18 or higher
179
+ - Playwright Test 1.40 or higher
180
+ - Running Piwi Dashboard server
181
+
182
+ ## Development
183
+
184
+ This package is written in TypeScript. Source files live in `src/` and compile to `dist/`.
185
+
186
+ ```bash
187
+ cd reporter
188
+ npm install
189
+ npm run reporter:build # compile TypeScript src/ → dist/
190
+ npm run reporter:dev # watch mode — auto-recompile on changes
191
+ ```
192
+
193
+ ### Source layout
194
+
195
+ | File | Responsibility |
196
+ |----------------------------|---------------------------------------------|
197
+ | `src/reporter.ts` | Orchestrator — Playwright hooks + fallback |
198
+ | `src/config.ts` | Options interface + defaults |
199
+ | `src/http-client.ts` | HTTP transport layer |
200
+ | `src/uploader.ts` | Upload strategies (JSON, multipart) |
201
+ | `src/stream-buffer.ts` | Persistent JSONL buffer |
202
+ | `src/crash-recovery.ts` | Recovery data management |
203
+ | `src/file-handler.ts` | Report/trace/attachment file operations |
204
+ | `src/metadata-collector.ts`| CI, SCM, Playwright config metadata |
205
+ | `src/step-analyzer.ts` | Step categorization + performance analysis |
206
+ | `src/helpers.ts` | Pure utility functions |
207
+ | `src/compression.ts` | Directory gzip archiver |
208
+ | `src/fixtures.ts` | Playwright fixtures |
209
+ | `src/index.ts` | Package entry point |
210
+
211
+ The `package.json` `exports` field maps the main entry and `./fixtures` to their `dist/` counterparts.
212
+
213
+ ## Troubleshooting
214
+
215
+ ### Reporter not uploading files
216
+
217
+ - Ensure an HTML reporter is configured: `['html', { outputFolder: 'playwright-report' }]`
218
+ - Ensure traces are enabled: `use: { trace: 'retain-on-failure' }`
219
+ - Check the dashboard server is running and accessible at `serverUrl`
220
+
221
+ ### Network/Web Vitals not appearing
222
+
223
+ - Import `test` from `@piwitests/reporter/fixtures` (or extend with `dashboardFixtures`)
224
+ - Verify `collectPerformanceMetrics` is not set to `false`
225
+ - Ensure tests navigate to at least one page (`await page.goto(...)`)
226
+
227
+ ### Connection errors
228
+
229
+ - Check that `serverUrl` is correct and the server is running
230
+ - Verify network connectivity and firewall settings
231
+
232
+ ## License
233
+
234
+ MIT
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Recursively read a directory and pack all files into a gzip-compressed
3
+ * archive (a concatenation of length-prefixed path+content pairs).
4
+ */
5
+ export declare function compressDirectory(sourceDir: string): Promise<Buffer>;
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.compressDirectory = compressDirectory;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const zlib_1 = __importDefault(require("zlib"));
10
+ const util_1 = require("util");
11
+ const gzipAsync = (0, util_1.promisify)(zlib_1.default.gzip);
12
+ /**
13
+ * Recursively read a directory and pack all files into a gzip-compressed
14
+ * archive (a concatenation of length-prefixed path+content pairs).
15
+ */
16
+ async function compressDirectory(sourceDir) {
17
+ const files = [];
18
+ function collect(dir, baseDir = '') {
19
+ for (const entry of fs_1.default.readdirSync(dir, { withFileTypes: true })) {
20
+ const full = path_1.default.join(dir, entry.name);
21
+ const rel = path_1.default.join(baseDir, entry.name);
22
+ if (entry.isDirectory())
23
+ collect(full, rel);
24
+ else if (entry.isFile())
25
+ files.push({ path: rel, content: fs_1.default.readFileSync(full) });
26
+ }
27
+ }
28
+ collect(sourceDir);
29
+ const parts = [];
30
+ for (const f of files) {
31
+ const pb = Buffer.from(f.path, 'utf8');
32
+ const plb = Buffer.allocUnsafe(4);
33
+ plb.writeUInt32LE(pb.length, 0);
34
+ const clb = Buffer.allocUnsafe(4);
35
+ clb.writeUInt32LE(f.content.length, 0);
36
+ parts.push(plb, pb, clb, f.content);
37
+ }
38
+ return await gzipAsync(Buffer.concat(parts), { level: 5 });
39
+ }
@@ -0,0 +1,21 @@
1
+ import type { PlaywrightTestConfig } from '@playwright/test';
2
+ import { type PiwiDashboardOptions } from './config.js';
3
+ /**
4
+ * Wrap a Playwright config to auto-inject the Piwi Dashboard reporter and
5
+ * chain its global setup module. Returns a new config object (shallow merge)
6
+ * without mutating the original.
7
+ *
8
+ * The `globalSetup` field is set to a `string` (or `string[]` if the user
9
+ * already has a global setup) referencing the Piwi global setup module,
10
+ * which registers the run on the server. The original setup path(s) are
11
+ * preserved and executed first.
12
+ *
13
+ * Playwright options required in `globalSetup` are forwarded via `PIWI_*`
14
+ * environment variables (see `applyOptionsToEnv` in `config.ts` for the
15
+ * supported set — `serverUrl`, `projectName`, `verbose`, `apiKey`,
16
+ * `username`, `password`, `environment`, `label`, `runLabel`).
17
+ *
18
+ * @param config The user's Playwright config.
19
+ * @param piwiOptions Optional Piwi Dashboard options (serverUrl, projectName, …).
20
+ */
21
+ export declare function wrapConfig<T extends PlaywrightTestConfig>(config: T, piwiOptions?: PiwiDashboardOptions): T;
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.wrapConfig = wrapConfig;
4
+ const config_js_1 = require("./config.js");
5
+ const PIWI_MODULE = '@piwitests/reporter';
6
+ function isPiwiReporterEntry(entry) {
7
+ if (typeof entry === 'string')
8
+ return entry.toLowerCase().includes('piwi');
9
+ if (Array.isArray(entry) && typeof entry[0] === 'string')
10
+ return entry[0].toLowerCase().includes('piwi');
11
+ return false;
12
+ }
13
+ function injectReporter(reporter, piwiOptions) {
14
+ const piwiEntry = piwiOptions ? [PIWI_MODULE, piwiOptions] : [PIWI_MODULE];
15
+ if (!reporter)
16
+ return [piwiEntry];
17
+ if (Array.isArray(reporter)) {
18
+ if (reporter.some(isPiwiReporterEntry))
19
+ return reporter;
20
+ return [...reporter, piwiEntry];
21
+ }
22
+ return [[reporter], piwiEntry];
23
+ }
24
+ function resolveSetupModule() {
25
+ try {
26
+ return require.resolve('./global-setup-module.js');
27
+ }
28
+ catch {
29
+ return require.resolve('./global-setup-module.ts');
30
+ }
31
+ }
32
+ /**
33
+ * Wrap a Playwright config to auto-inject the Piwi Dashboard reporter and
34
+ * chain its global setup module. Returns a new config object (shallow merge)
35
+ * without mutating the original.
36
+ *
37
+ * The `globalSetup` field is set to a `string` (or `string[]` if the user
38
+ * already has a global setup) referencing the Piwi global setup module,
39
+ * which registers the run on the server. The original setup path(s) are
40
+ * preserved and executed first.
41
+ *
42
+ * Playwright options required in `globalSetup` are forwarded via `PIWI_*`
43
+ * environment variables (see `applyOptionsToEnv` in `config.ts` for the
44
+ * supported set — `serverUrl`, `projectName`, `verbose`, `apiKey`,
45
+ * `username`, `password`, `environment`, `label`, `runLabel`).
46
+ *
47
+ * @param config The user's Playwright config.
48
+ * @param piwiOptions Optional Piwi Dashboard options (serverUrl, projectName, …).
49
+ */
50
+ function wrapConfig(config, piwiOptions) {
51
+ if (piwiOptions)
52
+ (0, config_js_1.applyOptionsToEnv)(piwiOptions);
53
+ const globalSetupModules = [];
54
+ if (config.globalSetup) {
55
+ const orig = Array.isArray(config.globalSetup) ? config.globalSetup : [config.globalSetup];
56
+ globalSetupModules.push(...orig);
57
+ }
58
+ globalSetupModules.push(resolveSetupModule());
59
+ return {
60
+ ...config,
61
+ reporter: injectReporter(config.reporter, piwiOptions),
62
+ globalSetup: globalSetupModules.length === 1 ? globalSetupModules[0] : globalSetupModules,
63
+ };
64
+ }
@@ -0,0 +1,104 @@
1
+ import type { PlaywrightTestConfig } from '@playwright/test';
2
+ /** Playwright shard info — mirrors `config.shard` shape */
3
+ export interface ShardInfo {
4
+ current: number;
5
+ total: number;
6
+ }
7
+ /** Options for configuring the Piwi Dashboard reporter */
8
+ export interface PiwiDashboardOptions extends PlaywrightTestConfig {
9
+ /** URL of the Piwi Dashboard server */
10
+ serverUrl?: string;
11
+ /** Name of the project to report results under. Defaults to `'default-project'`. */
12
+ projectName?: string;
13
+ /** Optional description of the project */
14
+ projectDescription?: string;
15
+ /** Upload trace files to the dashboard. Defaults to `true`. */
16
+ uploadTraces?: boolean;
17
+ /** Upload the Playwright HTML report. Defaults to `true`. */
18
+ uploadReport?: boolean;
19
+ /** Upload each test's trace and attachments as soon as the test finishes (streaming mode only). Defaults to `true`. */
20
+ liveFileUploads?: boolean;
21
+ /** Auto-collect git commit, branch, author. Defaults to `true`. */
22
+ collectScmInfo?: boolean;
23
+ /** Auto-collect CI environment info. Defaults to `true`. */
24
+ collectCiInfo?: boolean;
25
+ /** Collect step timings, network requests and web vitals. Defaults to `true`. */
26
+ collectPerformanceMetrics?: boolean;
27
+ /** Enable live streaming of results (falls back to batch if unsupported). Defaults to `true`. */
28
+ streaming?: boolean;
29
+ /** Number of test results to batch before sending during streaming. Defaults to `5`. */
30
+ streamingBatchSize?: number;
31
+ /** Max delay (ms) before flushing pending events during streaming. Defaults to `2000`. */
32
+ streamingBatchDelay?: number;
33
+ /** Username for dashboard login (use `apiKey` instead when possible) */
34
+ username?: string | null;
35
+ /** Password for dashboard login (used with `username`) */
36
+ password?: string | null;
37
+ /** API key for authentication (preferred over `username`/`password` for CI) */
38
+ apiKey?: string | null;
39
+ /** Additional report types to upload. Each entry can specify `type`, optional `dir`, and optional `label`. */
40
+ reports?: Array<{
41
+ type: string;
42
+ dir?: string;
43
+ label?: string;
44
+ }>;
45
+ /** Stable label that ties shards together (e.g. CI run ID). Auto-detected from CI env; override if needed. */
46
+ runLabel?: string;
47
+ /** Deployment environment for this run, e.g. `"production"`, `"staging"`, `"integration"` */
48
+ environment?: string;
49
+ /** Optional display label for the test run (e.g. "v2.3.1 release") */
50
+ label?: string;
51
+ /** Related issue reference, e.g. `"JIRA-123"` */
52
+ relatedIssue?: string;
53
+ /** CI job information */
54
+ ciInfo?: string;
55
+ /** Tags to categorize the test run */
56
+ tags?: string[];
57
+ /** Additional custom metadata as key-value pairs */
58
+ customData?: Record<string, unknown>;
59
+ /** Enable verbose logging for debugging. Defaults to `false`. */
60
+ verbose?: boolean;
61
+ }
62
+ /**
63
+ * Single source of truth for the `PIWI_*` env-var → option mapping. Both
64
+ * `resolveOptions` (env → option) and `applyOptionsToEnv` (option → env, used
65
+ * by `wrapConfig` to bridge into the global-setup process) read these names so
66
+ * the mapping lives in exactly one place.
67
+ */
68
+ export declare const PIWI_ENV_KEYS: {
69
+ readonly serverUrl: "PIWI_DASHBOARD_URL";
70
+ readonly projectName: "PIWI_PROJECT_NAME";
71
+ readonly verbose: "PIWI_VERBOSE";
72
+ readonly apiKey: "PIWI_API_KEY";
73
+ readonly username: "PIWI_USERNAME";
74
+ readonly password: "PIWI_PASSWORD";
75
+ readonly environment: "PIWI_ENVIRONMENT";
76
+ readonly label: "PIWI_LABEL";
77
+ readonly runLabel: "PIWI_RUN_LABEL";
78
+ readonly streaming: "PIWI_STREAMING";
79
+ readonly streamingBatchSize: "PIWI_STREAMING_BATCH_SIZE";
80
+ readonly streamingBatchDelay: "PIWI_STREAMING_BATCH_DELAY";
81
+ readonly liveFileUploads: "PIWI_LIVE_FILE_UPLOADS";
82
+ readonly uploadTraces: "PIWI_UPLOAD_TRACES";
83
+ readonly uploadReport: "PIWI_UPLOAD_REPORT";
84
+ };
85
+ /**
86
+ * Merge raw user options with defaults, reading from `PIWI_*` env vars when
87
+ * options are not provided.
88
+ *
89
+ * Env semantics: env vars fill in values the caller didn't provide (fallback).
90
+ * They're applied to `raw` *before* the `DEFAULTS` merge so a built-in default
91
+ * never masks an env var (the pre-Phase-4 `PIWI_PROJECT_NAME` was masked by the
92
+ * `default-project` default — that quirk is now fixed).
93
+ *
94
+ * One preserved quirk: `PIWI_VERBOSE` wins over both the default *and* an
95
+ * explicit user option, matching the pre-Phase-4 behavior.
96
+ */
97
+ export declare function resolveOptions(raw: Record<string, any>): PiwiDashboardOptions;
98
+ /**
99
+ * Write the options that the isolated `global-setup-module` process needs into
100
+ * `PIWI_*` env vars. `wrapConfig` calls this so the global setup (which runs
101
+ * `resolveOptions({})` in a separate module) picks up the same server/auth
102
+ * config the reporter instance uses. Only writes values that are actually set.
103
+ */
104
+ export declare function applyOptionsToEnv(options: PiwiDashboardOptions): void;
package/dist/config.js ADDED
@@ -0,0 +1,127 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PIWI_ENV_KEYS = void 0;
4
+ exports.resolveOptions = resolveOptions;
5
+ exports.applyOptionsToEnv = applyOptionsToEnv;
6
+ const DEFAULTS = {
7
+ projectName: 'default-project',
8
+ uploadTraces: true,
9
+ uploadReport: true,
10
+ liveFileUploads: true,
11
+ collectScmInfo: true,
12
+ collectCiInfo: true,
13
+ collectPerformanceMetrics: true,
14
+ streaming: true,
15
+ streamingBatchSize: 5,
16
+ streamingBatchDelay: 2000,
17
+ username: null,
18
+ password: null,
19
+ apiKey: null,
20
+ verbose: false,
21
+ };
22
+ /**
23
+ * Single source of truth for the `PIWI_*` env-var → option mapping. Both
24
+ * `resolveOptions` (env → option) and `applyOptionsToEnv` (option → env, used
25
+ * by `wrapConfig` to bridge into the global-setup process) read these names so
26
+ * the mapping lives in exactly one place.
27
+ */
28
+ exports.PIWI_ENV_KEYS = {
29
+ serverUrl: 'PIWI_DASHBOARD_URL',
30
+ projectName: 'PIWI_PROJECT_NAME',
31
+ verbose: 'PIWI_VERBOSE',
32
+ apiKey: 'PIWI_API_KEY',
33
+ username: 'PIWI_USERNAME',
34
+ password: 'PIWI_PASSWORD',
35
+ environment: 'PIWI_ENVIRONMENT',
36
+ label: 'PIWI_LABEL',
37
+ runLabel: 'PIWI_RUN_LABEL',
38
+ streaming: 'PIWI_STREAMING',
39
+ streamingBatchSize: 'PIWI_STREAMING_BATCH_SIZE',
40
+ streamingBatchDelay: 'PIWI_STREAMING_BATCH_DELAY',
41
+ liveFileUploads: 'PIWI_LIVE_FILE_UPLOADS',
42
+ uploadTraces: 'PIWI_UPLOAD_TRACES',
43
+ uploadReport: 'PIWI_UPLOAD_REPORT',
44
+ };
45
+ function readBool(val) {
46
+ if (val === undefined)
47
+ return undefined;
48
+ return val === 'true';
49
+ }
50
+ /**
51
+ * Merge raw user options with defaults, reading from `PIWI_*` env vars when
52
+ * options are not provided.
53
+ *
54
+ * Env semantics: env vars fill in values the caller didn't provide (fallback).
55
+ * They're applied to `raw` *before* the `DEFAULTS` merge so a built-in default
56
+ * never masks an env var (the pre-Phase-4 `PIWI_PROJECT_NAME` was masked by the
57
+ * `default-project` default — that quirk is now fixed).
58
+ *
59
+ * One preserved quirk: `PIWI_VERBOSE` wins over both the default *and* an
60
+ * explicit user option, matching the pre-Phase-4 behavior.
61
+ */
62
+ function resolveOptions(raw) {
63
+ const env = process.env;
64
+ const mergedRaw = { ...raw };
65
+ // String options: env fills in when the caller didn't provide one.
66
+ if (mergedRaw.serverUrl === undefined && env[exports.PIWI_ENV_KEYS.serverUrl])
67
+ mergedRaw.serverUrl = env[exports.PIWI_ENV_KEYS.serverUrl];
68
+ if (mergedRaw.projectName === undefined && env[exports.PIWI_ENV_KEYS.projectName])
69
+ mergedRaw.projectName = env[exports.PIWI_ENV_KEYS.projectName];
70
+ if (mergedRaw.apiKey === undefined && env[exports.PIWI_ENV_KEYS.apiKey])
71
+ mergedRaw.apiKey = env[exports.PIWI_ENV_KEYS.apiKey];
72
+ if (mergedRaw.username === undefined && env[exports.PIWI_ENV_KEYS.username])
73
+ mergedRaw.username = env[exports.PIWI_ENV_KEYS.username];
74
+ if (mergedRaw.password === undefined && env[exports.PIWI_ENV_KEYS.password])
75
+ mergedRaw.password = env[exports.PIWI_ENV_KEYS.password];
76
+ if (mergedRaw.environment === undefined && env[exports.PIWI_ENV_KEYS.environment])
77
+ mergedRaw.environment = env[exports.PIWI_ENV_KEYS.environment];
78
+ if (mergedRaw.label === undefined && env[exports.PIWI_ENV_KEYS.label])
79
+ mergedRaw.label = env[exports.PIWI_ENV_KEYS.label];
80
+ if (mergedRaw.runLabel === undefined && env[exports.PIWI_ENV_KEYS.runLabel])
81
+ mergedRaw.runLabel = env[exports.PIWI_ENV_KEYS.runLabel];
82
+ // Boolean / numeric options: env fills in when the caller didn't provide one.
83
+ if (mergedRaw.streaming === undefined && env[exports.PIWI_ENV_KEYS.streaming] !== undefined)
84
+ mergedRaw.streaming = readBool(env[exports.PIWI_ENV_KEYS.streaming]);
85
+ if (mergedRaw.streamingBatchSize === undefined && env[exports.PIWI_ENV_KEYS.streamingBatchSize])
86
+ mergedRaw.streamingBatchSize = Number(env[exports.PIWI_ENV_KEYS.streamingBatchSize]);
87
+ if (mergedRaw.streamingBatchDelay === undefined && env[exports.PIWI_ENV_KEYS.streamingBatchDelay])
88
+ mergedRaw.streamingBatchDelay = Number(env[exports.PIWI_ENV_KEYS.streamingBatchDelay]);
89
+ if (mergedRaw.liveFileUploads === undefined && env[exports.PIWI_ENV_KEYS.liveFileUploads] !== undefined)
90
+ mergedRaw.liveFileUploads = readBool(env[exports.PIWI_ENV_KEYS.liveFileUploads]);
91
+ if (mergedRaw.uploadTraces === undefined && env[exports.PIWI_ENV_KEYS.uploadTraces] !== undefined)
92
+ mergedRaw.uploadTraces = readBool(env[exports.PIWI_ENV_KEYS.uploadTraces]);
93
+ if (mergedRaw.uploadReport === undefined && env[exports.PIWI_ENV_KEYS.uploadReport] !== undefined)
94
+ mergedRaw.uploadReport = readBool(env[exports.PIWI_ENV_KEYS.uploadReport]);
95
+ const opts = { ...DEFAULTS, ...mergedRaw };
96
+ // Preserved quirk: PIWI_VERBOSE wins over both default and user option.
97
+ if (env[exports.PIWI_ENV_KEYS.verbose] !== undefined)
98
+ opts.verbose = env[exports.PIWI_ENV_KEYS.verbose] === 'true';
99
+ return opts;
100
+ }
101
+ /**
102
+ * Write the options that the isolated `global-setup-module` process needs into
103
+ * `PIWI_*` env vars. `wrapConfig` calls this so the global setup (which runs
104
+ * `resolveOptions({})` in a separate module) picks up the same server/auth
105
+ * config the reporter instance uses. Only writes values that are actually set.
106
+ */
107
+ function applyOptionsToEnv(options) {
108
+ const env = process.env;
109
+ if (options.serverUrl !== undefined)
110
+ env[exports.PIWI_ENV_KEYS.serverUrl] = options.serverUrl;
111
+ if (options.projectName !== undefined)
112
+ env[exports.PIWI_ENV_KEYS.projectName] = options.projectName;
113
+ if (options.verbose !== undefined)
114
+ env[exports.PIWI_ENV_KEYS.verbose] = String(options.verbose);
115
+ if (options.apiKey)
116
+ env[exports.PIWI_ENV_KEYS.apiKey] = options.apiKey;
117
+ if (options.username)
118
+ env[exports.PIWI_ENV_KEYS.username] = options.username;
119
+ if (options.password)
120
+ env[exports.PIWI_ENV_KEYS.password] = options.password;
121
+ if (options.environment)
122
+ env[exports.PIWI_ENV_KEYS.environment] = options.environment;
123
+ if (options.label)
124
+ env[exports.PIWI_ENV_KEYS.label] = options.label;
125
+ if (options.runLabel)
126
+ env[exports.PIWI_ENV_KEYS.runLabel] = options.runLabel;
127
+ }
@@ -0,0 +1,23 @@
1
+ import { HttpClient } from './http-client.js';
2
+ import { Logger } from './logger.js';
3
+ /**
4
+ * Persists a test-run payload to disk when all upload strategies fail, so the
5
+ * data can be retried on the next run.
6
+ */
7
+ export declare class CrashRecovery {
8
+ private filePath;
9
+ private readonly logger;
10
+ /**
11
+ * @param projectName Used to derive the temp-file name so recovery data is project-scoped.
12
+ * @param logger Prefixed logger.
13
+ */
14
+ constructor(projectName: string, logger?: Logger);
15
+ /** Serialise the payload to a temp file for later retry */
16
+ save(data: Record<string, any>): void;
17
+ /** Read the saved payload from disk, or return `null` if none exists */
18
+ load(): Record<string, any> | null;
19
+ /** Delete the recovery file from disk */
20
+ clear(): void;
21
+ /** Attempt to submit a previously saved payload. Clears the recovery file on success. */
22
+ tryUpload(httpClient: HttpClient, auth?: string | null): Promise<void>;
23
+ }