@piwitests/reporter 0.12.0 → 0.14.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 +8 -3
  6. package/dist/internal/capture/attachments.js +46 -21
  7. package/dist/internal/capture/capture-fixtures.d.ts +16 -14
  8. package/dist/internal/capture/capture-fixtures.js +2211 -971
  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 -190
  12. package/dist/internal/capture/locator-healing.js +599 -815
  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 -46
  25. package/dist/internal/config/env.js +0 -162
  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 -207
  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 -108
  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 -86
  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 -97
  73. package/dist/types/collected.js +0 -10
  74. package/dist/types/wire.d.ts +0 -176
  75. package/dist/types/wire.js +0 -14
  76. package/dist/types.d.ts +0 -11
  77. package/dist/types.js +0 -27
@@ -1,27 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createLimiter = createLimiter;
4
- /** Create a concurrency limiter that ensures at most `maxConcurrent` async operations run simultaneously */
5
- function createLimiter(maxConcurrent) {
6
- const limitValue = Math.max(1, Math.floor(maxConcurrent));
7
- let active = 0;
8
- const queue = [];
9
- const next = () => {
10
- active--;
11
- const run = queue.shift();
12
- if (run)
13
- run();
14
- };
15
- return function limit(fn) {
16
- return new Promise((resolve, reject) => {
17
- const run = () => {
18
- active++;
19
- Promise.resolve().then(fn).then(resolve, reject).finally(next);
20
- };
21
- if (active < limitValue)
22
- run();
23
- else
24
- queue.push(run);
25
- });
26
- };
27
- }
@@ -1,26 +0,0 @@
1
- /**
2
- * Tiny prefixed logger. Owns the `[Piwi Dashboard]` prefix and the verbose
3
- * gate so the prefix isn't typed out ~46× across the package and `verbose`
4
- * doesn't need to be threaded into every constructor.
5
- *
6
- * Channel preservation:
7
- * - `info` → stdout (always),
8
- * - `warn` → stderr (always),
9
- * - `error` → stderr (always),
10
- * - `debug` → stdout (only when `verbose`),
11
- * - `debugError` → stderr (only when `verbose`).
12
- *
13
- * `debugError` exists so verbose-only diagnostics that previously used
14
- * `console.error` (e.g. HTTP response bodies on failure) keep going to stderr
15
- * after the refactor.
16
- */
17
- export declare class Logger {
18
- private readonly verbose;
19
- private readonly prefix;
20
- constructor(verbose?: boolean);
21
- info(msg: string): void;
22
- warn(msg: string): void;
23
- error(msg: string): void;
24
- debug(msg: string): void;
25
- debugError(msg: string): void;
26
- }
@@ -1,43 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Logger = void 0;
4
- /**
5
- * Tiny prefixed logger. Owns the `[Piwi Dashboard]` prefix and the verbose
6
- * gate so the prefix isn't typed out ~46× across the package and `verbose`
7
- * doesn't need to be threaded into every constructor.
8
- *
9
- * Channel preservation:
10
- * - `info` → stdout (always),
11
- * - `warn` → stderr (always),
12
- * - `error` → stderr (always),
13
- * - `debug` → stdout (only when `verbose`),
14
- * - `debugError` → stderr (only when `verbose`).
15
- *
16
- * `debugError` exists so verbose-only diagnostics that previously used
17
- * `console.error` (e.g. HTTP response bodies on failure) keep going to stderr
18
- * after the refactor.
19
- */
20
- class Logger {
21
- constructor(verbose = false) {
22
- this.verbose = verbose;
23
- this.prefix = '[Piwi Dashboard] ';
24
- }
25
- info(msg) {
26
- console.log(this.prefix + msg);
27
- }
28
- warn(msg) {
29
- console.warn(this.prefix + msg);
30
- }
31
- error(msg) {
32
- console.error(this.prefix + msg);
33
- }
34
- debug(msg) {
35
- if (this.verbose)
36
- console.log(this.prefix + msg);
37
- }
38
- debugError(msg) {
39
- if (this.verbose)
40
- console.error(this.prefix + msg);
41
- }
42
- }
43
- exports.Logger = Logger;
@@ -1,2 +0,0 @@
1
- /** Read the reporter package's own version from `package.json`, memoized. Falls back to `'unknown'` if it can't be read (e.g. an unusual install layout). */
2
- export declare function getReporterVersion(): string;
@@ -1,54 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.getReporterVersion = getReporterVersion;
37
- const fs = __importStar(require("node:fs"));
38
- const path = __importStar(require("node:path"));
39
- let cachedVersion = null;
40
- /** Read the reporter package's own version from `package.json`, memoized. Falls back to `'unknown'` if it can't be read (e.g. an unusual install layout). */
41
- function getReporterVersion() {
42
- if (cachedVersion)
43
- return cachedVersion;
44
- try {
45
- const pkgPath = path.resolve(__dirname, '../../../package.json');
46
- const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
47
- const version = pkg.version;
48
- cachedVersion = typeof version === 'string' ? version : 'unknown';
49
- }
50
- catch {
51
- cachedVersion = 'unknown';
52
- }
53
- return cachedVersion;
54
- }
@@ -1,13 +0,0 @@
1
- /** Return the temp-file path used to exchange setup info between globalSetup and the reporter instance */
2
- export declare function getSetupFilePath(projectName: string): string;
3
- /** Information saved by the global setup for the reporter instance to consume */
4
- export interface SetupInfo {
5
- /** Server-assigned run ID */
6
- runId: number;
7
- /** One-time token used to authenticate the /begin call */
8
- setupToken: string;
9
- /** Project name this run belongs to */
10
- projectName: string;
11
- }
12
- /** Read and delete the setup info file for the given project. Returns `null` when no file exists. */
13
- export declare function readSetupInfo(projectName: string): SetupInfo | null;
@@ -1,61 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.getSetupFilePath = getSetupFilePath;
37
- exports.readSetupInfo = readSetupInfo;
38
- const path = __importStar(require("node:path"));
39
- const os = __importStar(require("node:os"));
40
- const fs = __importStar(require("node:fs"));
41
- const instance_id_js_1 = require("./instance-id.js");
42
- /** Return the temp-file path used to exchange setup info between globalSetup and the reporter instance */
43
- function getSetupFilePath(projectName) {
44
- return path.join(os.tmpdir(), `piwi-dashboard-setup-${(0, instance_id_js_1.hashForProject)(projectName)}.json`);
45
- }
46
- /** Read and delete the setup info file for the given project. Returns `null` when no file exists. */
47
- function readSetupInfo(projectName) {
48
- const setupFile = getSetupFilePath(projectName);
49
- try {
50
- if (fs.existsSync(setupFile)) {
51
- const info = JSON.parse(fs.readFileSync(setupFile, 'utf8'));
52
- fs.unlinkSync(setupFile);
53
- if (info.projectName === projectName)
54
- return info;
55
- }
56
- }
57
- catch {
58
- /* ignore */
59
- }
60
- return null;
61
- }
@@ -1,12 +0,0 @@
1
- /**
2
- * Read a snippet of source code surrounding the declaration line, optionally
3
- * highlighting a separate failing line. Returns a formatted string with line
4
- * numbers and markers (`>` for the failing line, `*` for the declaration), or
5
- * `null` on error.
6
- */
7
- export declare function readSourceSnippet(file: string, declLine: number, context: number, failingLine?: number): string | null;
8
- /**
9
- * Extract the line number of the first stack frame inside `testFile` from an
10
- * error's stack trace. Falls back to `declarationLine`.
11
- */
12
- export declare function extractFailingLine(errorText: string | null | undefined, testFile: string, declarationLine: number): number;
@@ -1,97 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.readSourceSnippet = readSourceSnippet;
37
- exports.extractFailingLine = extractFailingLine;
38
- const fs = __importStar(require("node:fs"));
39
- const path = __importStar(require("node:path"));
40
- /**
41
- * Read a snippet of source code surrounding the declaration line, optionally
42
- * highlighting a separate failing line. Returns a formatted string with line
43
- * numbers and markers (`>` for the failing line, `*` for the declaration), or
44
- * `null` on error.
45
- */
46
- function readSourceSnippet(file, declLine, context, failingLine) {
47
- try {
48
- const content = fs.readFileSync(file, 'utf-8');
49
- const lines = content.split('\n');
50
- const anchor = failingLine ?? declLine;
51
- const start = Math.max(0, anchor - context - 1);
52
- const end = Math.min(lines.length, anchor + context);
53
- return lines
54
- .slice(start, end)
55
- .map((l, i) => {
56
- const lineNum = start + i + 1;
57
- const hasFailingLine = failingLine != null;
58
- const isFailing = hasFailingLine && lineNum === failingLine;
59
- const isDecl = lineNum === declLine && !isFailing;
60
- let marker = ' ';
61
- if (isFailing)
62
- marker = '> ';
63
- else if (isDecl)
64
- marker = hasFailingLine ? '* ' : '> ';
65
- return `${marker}${String(lineNum).padStart(4)} | ${l}`;
66
- })
67
- .join('\n');
68
- }
69
- catch {
70
- return null;
71
- }
72
- }
73
- /**
74
- * Extract the line number of the first stack frame inside `testFile` from an
75
- * error's stack trace. Falls back to `declarationLine`.
76
- */
77
- function extractFailingLine(errorText, testFile, declarationLine) {
78
- if (!errorText)
79
- return declarationLine;
80
- const expectedFile = path.resolve(testFile);
81
- const stackRe = /^\s+at (?:[^(]*\()?(.+?):(\d+):\d+\)?\s*$/gm;
82
- let m;
83
- while ((m = stackRe.exec(errorText)) !== null) {
84
- try {
85
- const frameFile = path.resolve(m[1]);
86
- if (frameFile === expectedFile) {
87
- const line = parseInt(m[2], 10);
88
- if (!isNaN(line))
89
- return line;
90
- }
91
- }
92
- catch {
93
- /* skip unresolvable paths */
94
- }
95
- }
96
- return declarationLine;
97
- }
@@ -1,7 +0,0 @@
1
- /**
2
- * Extract a worker index from a Playwright `TestResult`, falling back to
3
- * `parallelIndex` when `workerIndex` is absent. Returns `null` when neither is
4
- * set. Localizes the `as any` reach into Playwright's result object so the
5
- * cast lives in exactly one place.
6
- */
7
- export declare function workerIndexOf(result: any): number | null;
@@ -1,14 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.workerIndexOf = workerIndexOf;
4
- /**
5
- * Extract a worker index from a Playwright `TestResult`, falling back to
6
- * `parallelIndex` when `workerIndex` is absent. Returns `null` when neither is
7
- * set. Localizes the `as any` reach into Playwright's result object so the
8
- * cast lives in exactly one place.
9
- */
10
- function workerIndexOf(result) {
11
- if (!result)
12
- return null;
13
- return result.workerIndex ?? result.parallelIndex ?? null;
14
- }
@@ -1,52 +0,0 @@
1
- import FormData from 'form-data';
2
- import { Logger } from '../support/logger.js';
3
- export { FormData };
4
- /**
5
- * An HTTP response with a non-2xx status. Carries the numeric `status` so
6
- * callers can branch on a specific code (401, 404, 409, 422, …) via
7
- * `error instanceof HttpError && error.status === …` instead of sniffing the
8
- * message string.
9
- */
10
- export declare class HttpError extends Error {
11
- readonly status: number;
12
- constructor(status: number, message?: string);
13
- }
14
- /**
15
- * Low-level HTTP client for communicating with the Piwi Dashboard server.
16
- * Supports JSON requests, multipart form-data uploads, and session-based login.
17
- *
18
- * All three public methods (`login`, `postJSON`, `postFormData`) delegate to a
19
- * single `request()` core that owns the transport selection, header/auth
20
- * application, response accumulation, and socket timeout. The package stays on
21
- * the single `form-data` runtime dependency — no HTTP client library.
22
- */
23
- export declare class HttpClient {
24
- private readonly serverUrl;
25
- private readonly logger;
26
- private readonly timeout;
27
- /**
28
- * @param serverUrl Base URL of the Piwi Dashboard server (e.g. `http://localhost:3000`).
29
- * @param logger Prefixed logger for verbose diagnostics.
30
- * @param timeout Socket inactivity timeout in ms (default 30s). A hung
31
- * server now fails fast instead of stalling the reporter.
32
- */
33
- constructor(serverUrl: string, logger?: Logger, timeout?: number);
34
- /**
35
- * Resolve an auth credential: prefer `apiKey`, fall back to `username`/`password` login,
36
- * or return `null` when neither is configured.
37
- */
38
- resolveAuth(options: {
39
- apiKey?: string | null;
40
- username?: string | null;
41
- password?: string | null;
42
- }): Promise<string | null>;
43
- /** Authenticate with username/password and return the session cookie string */
44
- login(username: string, password: string): Promise<string>;
45
- /** Send a JSON POST request. `auth` can be an API key (prefix `pd_`) or a session cookie string. */
46
- postJSON(pathname: string, payload: unknown, auth?: string | null): Promise<any>;
47
- /** Send a multipart form-data POST request. Used for report and trace uploads. */
48
- postFormData(pathname: string, form: FormData, auth?: string | null): Promise<any>;
49
- /** Unified request core: transport, headers, auth, response accumulation, timeout. */
50
- private request;
51
- private applyAuth;
52
- }
@@ -1,201 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- var __importDefault = (this && this.__importDefault) || function (mod) {
36
- return (mod && mod.__esModule) ? mod : { "default": mod };
37
- };
38
- Object.defineProperty(exports, "__esModule", { value: true });
39
- exports.HttpClient = exports.HttpError = exports.FormData = void 0;
40
- const https = __importStar(require("node:https"));
41
- const http = __importStar(require("node:http"));
42
- const node_url_1 = require("node:url");
43
- const form_data_1 = __importDefault(require("form-data"));
44
- exports.FormData = form_data_1.default;
45
- const logger_js_1 = require("../support/logger.js");
46
- /**
47
- * An HTTP response with a non-2xx status. Carries the numeric `status` so
48
- * callers can branch on a specific code (401, 404, 409, 422, …) via
49
- * `error instanceof HttpError && error.status === …` instead of sniffing the
50
- * message string.
51
- */
52
- class HttpError extends Error {
53
- constructor(status, message = `Request failed with status ${status}`) {
54
- super(message);
55
- this.status = status;
56
- this.name = 'HttpError';
57
- }
58
- }
59
- exports.HttpError = HttpError;
60
- /**
61
- * Low-level HTTP client for communicating with the Piwi Dashboard server.
62
- * Supports JSON requests, multipart form-data uploads, and session-based login.
63
- *
64
- * All three public methods (`login`, `postJSON`, `postFormData`) delegate to a
65
- * single `request()` core that owns the transport selection, header/auth
66
- * application, response accumulation, and socket timeout. The package stays on
67
- * the single `form-data` runtime dependency — no HTTP client library.
68
- */
69
- class HttpClient {
70
- /**
71
- * @param serverUrl Base URL of the Piwi Dashboard server (e.g. `http://localhost:3000`).
72
- * @param logger Prefixed logger for verbose diagnostics.
73
- * @param timeout Socket inactivity timeout in ms (default 30s). A hung
74
- * server now fails fast instead of stalling the reporter.
75
- */
76
- constructor(serverUrl, logger = new logger_js_1.Logger(), timeout = 30000) {
77
- this.serverUrl = serverUrl;
78
- this.logger = logger;
79
- this.timeout = timeout;
80
- }
81
- /**
82
- * Resolve an auth credential: prefer `apiKey`, fall back to `username`/`password` login,
83
- * or return `null` when neither is configured.
84
- */
85
- async resolveAuth(options) {
86
- if (options.apiKey)
87
- return options.apiKey;
88
- if (options.username && options.password) {
89
- this.logger.info(`Authenticating as ${options.username}...`);
90
- return this.login(options.username, options.password);
91
- }
92
- return null;
93
- }
94
- /** Authenticate with username/password and return the session cookie string */
95
- async login(username, password) {
96
- const body = JSON.stringify({ username, password });
97
- const res = await this.request('POST', '/api/auth/login', {
98
- headers: {
99
- 'Content-Type': 'application/json',
100
- 'Content-Length': Buffer.byteLength(body),
101
- },
102
- body,
103
- });
104
- if (res.status < 200 || res.status >= 300) {
105
- this.logger.debugError(`Login response: ${res.text}`);
106
- throw new HttpError(res.status, `Login failed with status ${res.status}`);
107
- }
108
- const setCookie = res.headers['set-cookie'];
109
- if (!setCookie || setCookie.length === 0) {
110
- throw new Error('Login succeeded but no session cookie was returned');
111
- }
112
- const cookie = setCookie.map((c) => c.split(';')[0]).join('; ');
113
- this.logger.debug('Logged in successfully');
114
- return cookie;
115
- }
116
- /** Send a JSON POST request. `auth` can be an API key (prefix `pd_`) or a session cookie string. */
117
- async postJSON(pathname, payload, auth) {
118
- const body = JSON.stringify(payload);
119
- const res = await this.request('POST', pathname, {
120
- headers: {
121
- 'Content-Type': 'application/json',
122
- 'Content-Length': Buffer.byteLength(body),
123
- },
124
- body,
125
- auth,
126
- });
127
- if (res.status < 200 || res.status >= 300) {
128
- this.logger.debugError(`Response: ${res.text}`);
129
- throw new HttpError(res.status);
130
- }
131
- try {
132
- return JSON.parse(res.text);
133
- }
134
- catch {
135
- return {};
136
- }
137
- }
138
- /** Send a multipart form-data POST request. Used for report and trace uploads. */
139
- async postFormData(pathname, form, auth) {
140
- const headers = form.getHeaders();
141
- const res = await this.request('POST', pathname, { headers, form, auth });
142
- if (res.status < 200 || res.status >= 300) {
143
- throw new HttpError(res.status, `Request failed with status ${res.status}: ${res.text}`);
144
- }
145
- try {
146
- return JSON.parse(res.text);
147
- }
148
- catch {
149
- return {};
150
- }
151
- }
152
- /** Unified request core: transport, headers, auth, response accumulation, timeout. */
153
- request(method, pathname, opts) {
154
- return new Promise((resolve, reject) => {
155
- const url = new node_url_1.URL(pathname, this.serverUrl);
156
- const transport = url.protocol === 'https:' ? https : http;
157
- const headers = { ...opts.headers };
158
- this.applyAuth(headers, opts.auth);
159
- const req = transport.request({
160
- hostname: url.hostname,
161
- port: url.port || (url.protocol === 'https:' ? 443 : 80),
162
- path: url.pathname,
163
- method,
164
- headers,
165
- }, (res) => {
166
- let data = '';
167
- res.on('data', (chunk) => {
168
- data += chunk;
169
- });
170
- res.on('end', () => {
171
- resolve({ status: res.statusCode ?? 0, text: data, headers: res.headers });
172
- });
173
- });
174
- req.on('error', reject);
175
- req.setTimeout(this.timeout, () => {
176
- req.destroy(new Error(`Request to ${pathname} timed out after ${this.timeout}ms`));
177
- });
178
- if (opts.form) {
179
- opts.form.pipe(req);
180
- }
181
- else if (opts.body !== undefined) {
182
- req.write(opts.body);
183
- req.end();
184
- }
185
- else {
186
- req.end();
187
- }
188
- });
189
- }
190
- applyAuth(headers, auth) {
191
- if (!auth)
192
- return;
193
- if (auth.startsWith('pd_')) {
194
- headers['Authorization'] = `Bearer ${auth}`;
195
- }
196
- else {
197
- headers['Cookie'] = auth;
198
- }
199
- }
200
- }
201
- exports.HttpClient = HttpClient;
@@ -1,21 +0,0 @@
1
- import type { PlaywrightTestConfig } from '@playwright/test';
2
- import type { PiwiDashboardOptions } from './options.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;