@tyndall/test-playwright 0.0.1
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 +30 -0
- package/dist/app/AppInstance.d.ts +24 -0
- package/dist/app/AppInstance.d.ts.map +1 -0
- package/dist/app/AppInstance.js +30 -0
- package/dist/app/AppLauncher.d.ts +32 -0
- package/dist/app/AppLauncher.d.ts.map +1 -0
- package/dist/app/AppLauncher.js +147 -0
- package/dist/dynamic/ManifestObserver.d.ts +24 -0
- package/dist/dynamic/ManifestObserver.d.ts.map +1 -0
- package/dist/dynamic/ManifestObserver.js +71 -0
- package/dist/errors.d.ts +17 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +19 -0
- package/dist/extensibility/EnvironmentScriptProvider.d.ts +21 -0
- package/dist/extensibility/EnvironmentScriptProvider.d.ts.map +1 -0
- package/dist/extensibility/EnvironmentScriptProvider.js +20 -0
- package/dist/extensibility/ExpectRegistry.d.ts +11 -0
- package/dist/extensibility/ExpectRegistry.d.ts.map +1 -0
- package/dist/extensibility/ExpectRegistry.js +18 -0
- package/dist/extensibility/StepRegistry.d.ts +14 -0
- package/dist/extensibility/StepRegistry.d.ts.map +1 -0
- package/dist/extensibility/StepRegistry.js +29 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/dist/reporter/ConsoleReporter.d.ts +6 -0
- package/dist/reporter/ConsoleReporter.d.ts.map +1 -0
- package/dist/reporter/ConsoleReporter.js +13 -0
- package/dist/reporter/HtmlReporter.d.ts +11 -0
- package/dist/reporter/HtmlReporter.d.ts.map +1 -0
- package/dist/reporter/HtmlReporter.js +36 -0
- package/dist/reporter/JsonReporter.d.ts +11 -0
- package/dist/reporter/JsonReporter.d.ts.map +1 -0
- package/dist/reporter/JsonReporter.js +12 -0
- package/dist/reporter/Reporter.d.ts +5 -0
- package/dist/reporter/Reporter.d.ts.map +1 -0
- package/dist/reporter/Reporter.js +1 -0
- package/dist/reporter/ResultCollector.d.ts +7 -0
- package/dist/reporter/ResultCollector.d.ts.map +1 -0
- package/dist/reporter/ResultCollector.js +26 -0
- package/dist/runner/PlaywrightRunner.d.ts +38 -0
- package/dist/runner/PlaywrightRunner.d.ts.map +1 -0
- package/dist/runner/PlaywrightRunner.js +77 -0
- package/dist/runner/StepExecutor.d.ts +16 -0
- package/dist/runner/StepExecutor.d.ts.map +1 -0
- package/dist/runner/StepExecutor.js +53 -0
- package/dist/scenario/ScenarioLoader.d.ts +4 -0
- package/dist/scenario/ScenarioLoader.d.ts.map +1 -0
- package/dist/scenario/ScenarioLoader.js +23 -0
- package/dist/scenario/ScenarioValidator.d.ts +15 -0
- package/dist/scenario/ScenarioValidator.d.ts.map +1 -0
- package/dist/scenario/ScenarioValidator.js +207 -0
- package/dist/scenario/types.d.ts +2 -0
- package/dist/scenario/types.d.ts.map +1 -0
- package/dist/scenario/types.js +1 -0
- package/dist/steps/click.d.ts +6 -0
- package/dist/steps/click.d.ts.map +1 -0
- package/dist/steps/click.js +3 -0
- package/dist/steps/expect.d.ts +7 -0
- package/dist/steps/expect.d.ts.map +1 -0
- package/dist/steps/expect.js +71 -0
- package/dist/steps/goto.d.ts +6 -0
- package/dist/steps/goto.d.ts.map +1 -0
- package/dist/steps/goto.js +6 -0
- package/dist/steps/index.d.ts +16 -0
- package/dist/steps/index.d.ts.map +1 -0
- package/dist/steps/index.js +8 -0
- package/dist/steps/types.d.ts +17 -0
- package/dist/steps/types.d.ts.map +1 -0
- package/dist/steps/types.js +1 -0
- package/dist/types/result.d.ts +25 -0
- package/dist/types/result.d.ts.map +1 -0
- package/dist/types/result.js +1 -0
- package/dist/types/scenario.d.ts +44 -0
- package/dist/types/scenario.d.ts.map +1 -0
- package/dist/types/scenario.js +1 -0
- package/package.json +28 -0
package/README.md
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# @tyndall/test-playwright
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
Scenario-driven Playwright testing package for end-to-end validation and report generation.
|
|
5
|
+
|
|
6
|
+
## Responsibilities
|
|
7
|
+
- Load and validate scenario definitions
|
|
8
|
+
- Execute scenario steps against running apps
|
|
9
|
+
- Produce console, json, and html reports with extension hooks
|
|
10
|
+
- Guard app launch ports to avoid attaching scenarios to stale pre-existing servers
|
|
11
|
+
- Stabilize async UI assertions through polling-based selector expectation checks
|
|
12
|
+
|
|
13
|
+
## Public API Highlights
|
|
14
|
+
- ScenarioLoader and ScenarioValidator
|
|
15
|
+
- PlaywrightRunner and StepExecutor
|
|
16
|
+
- Reporter interfaces
|
|
17
|
+
|
|
18
|
+
## Development
|
|
19
|
+
- Build: bun run --filter @tyndall/test-playwright build
|
|
20
|
+
- Test (from workspace root): bun test
|
|
21
|
+
|
|
22
|
+
## Documentation
|
|
23
|
+
- Package specification: [spec.md](./spec.md)
|
|
24
|
+
- Package architecture: [architecture.md](./architecture.md)
|
|
25
|
+
- Package changes: [CHANGELOG.md](./CHANGELOG.md)
|
|
26
|
+
|
|
27
|
+
## Maintenance Rules
|
|
28
|
+
- Keep this document aligned with implemented package behavior.
|
|
29
|
+
- Update spec.md and architecture.md whenever package contracts or design boundaries change.
|
|
30
|
+
- Record user-visible package changes in CHANGELOG.md.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { ChildProcess } from "node:child_process";
|
|
2
|
+
import type { ScenarioMode } from "../types/scenario.js";
|
|
3
|
+
export interface AppOutput {
|
|
4
|
+
stdout: string[];
|
|
5
|
+
stderr: string[];
|
|
6
|
+
}
|
|
7
|
+
export interface AppInstanceOptions {
|
|
8
|
+
mode: ScenarioMode;
|
|
9
|
+
baseUrl: string;
|
|
10
|
+
process: ChildProcess;
|
|
11
|
+
output: AppOutput;
|
|
12
|
+
ready: Promise<void>;
|
|
13
|
+
}
|
|
14
|
+
export declare class AppInstance {
|
|
15
|
+
readonly mode: ScenarioMode;
|
|
16
|
+
readonly baseUrl: string;
|
|
17
|
+
readonly process: ChildProcess;
|
|
18
|
+
readonly output: AppOutput;
|
|
19
|
+
private readonly readyPromise;
|
|
20
|
+
constructor(options: AppInstanceOptions);
|
|
21
|
+
waitReady(): Promise<void>;
|
|
22
|
+
dispose(gracefulTimeoutMs?: number): Promise<void>;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=AppInstance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AppInstance.d.ts","sourceRoot":"","sources":["../../src/app/AppInstance.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEzD,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,YAAY,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,YAAY,CAAC;IACtB,MAAM,EAAE,SAAS,CAAC;IAClB,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;CACtB;AAED,qBAAa,WAAW;IACtB,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC;IAC/B,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAgB;gBAEjC,OAAO,EAAE,kBAAkB;IAQjC,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAI1B,OAAO,CAAC,iBAAiB,SAAO,GAAG,OAAO,CAAC,IAAI,CAAC;CAqBvD"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export class AppInstance {
|
|
2
|
+
constructor(options) {
|
|
3
|
+
this.mode = options.mode;
|
|
4
|
+
this.baseUrl = options.baseUrl;
|
|
5
|
+
this.process = options.process;
|
|
6
|
+
this.output = options.output;
|
|
7
|
+
this.readyPromise = options.ready;
|
|
8
|
+
}
|
|
9
|
+
async waitReady() {
|
|
10
|
+
await this.readyPromise;
|
|
11
|
+
}
|
|
12
|
+
async dispose(gracefulTimeoutMs = 5000) {
|
|
13
|
+
if (this.process.killed) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
this.process.kill("SIGTERM");
|
|
17
|
+
await new Promise((resolve) => {
|
|
18
|
+
const timeout = setTimeout(() => {
|
|
19
|
+
if (!this.process.killed) {
|
|
20
|
+
this.process.kill("SIGKILL");
|
|
21
|
+
}
|
|
22
|
+
resolve();
|
|
23
|
+
}, gracefulTimeoutMs);
|
|
24
|
+
this.process.once("exit", () => {
|
|
25
|
+
clearTimeout(timeout);
|
|
26
|
+
resolve();
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { AppInstance } from "./AppInstance.js";
|
|
2
|
+
import type { ScenarioMode } from "../types/scenario.js";
|
|
3
|
+
import { LaunchError } from "../errors.js";
|
|
4
|
+
export interface AppLaunchOptions {
|
|
5
|
+
mode: ScenarioMode;
|
|
6
|
+
cwd: string;
|
|
7
|
+
host?: string;
|
|
8
|
+
port?: number;
|
|
9
|
+
outDir?: string;
|
|
10
|
+
env?: Record<string, string>;
|
|
11
|
+
command?: string[];
|
|
12
|
+
readyPath?: string;
|
|
13
|
+
timeoutMs?: number;
|
|
14
|
+
}
|
|
15
|
+
export interface AppLaunchCommand {
|
|
16
|
+
command: string;
|
|
17
|
+
args: string[];
|
|
18
|
+
}
|
|
19
|
+
export declare class AppLaunchError extends LaunchError {
|
|
20
|
+
constructor(message: string);
|
|
21
|
+
}
|
|
22
|
+
export declare class AppLauncher {
|
|
23
|
+
launch(options: AppLaunchOptions): Promise<AppInstance>;
|
|
24
|
+
buildCommand(options: AppLaunchOptions, host: string, port: number): AppLaunchCommand;
|
|
25
|
+
private runBuild;
|
|
26
|
+
private spawnProcess;
|
|
27
|
+
private waitForReady;
|
|
28
|
+
private formatOutput;
|
|
29
|
+
private ensurePortAvailable;
|
|
30
|
+
private isTcpPortOpen;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=AppLauncher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AppLauncher.d.ts","sourceRoot":"","sources":["../../src/app/AppLauncher.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,WAAW,EAAkB,MAAM,kBAAkB,CAAC;AAC/D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,YAAY,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,qBAAa,cAAe,SAAQ,WAAW;gBACjC,OAAO,EAAE,MAAM;CAI5B;AAMD,qBAAa,WAAW;IAChB,MAAM,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,WAAW,CAAC;IA0B7D,YAAY,CAAC,OAAO,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,gBAAgB;YAyBvE,QAAQ;IAoBtB,OAAO,CAAC,YAAY;YAsBN,YAAY;IAsB1B,OAAO,CAAC,YAAY;YAQN,mBAAmB;YASnB,aAAa;CA8B5B"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { setTimeout as delay } from "node:timers/promises";
|
|
3
|
+
import { Socket } from "node:net";
|
|
4
|
+
import { AppInstance } from "./AppInstance.js";
|
|
5
|
+
import { LaunchError } from "../errors.js";
|
|
6
|
+
export class AppLaunchError extends LaunchError {
|
|
7
|
+
constructor(message) {
|
|
8
|
+
super(message);
|
|
9
|
+
this.name = "AppLaunchError";
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
const DEFAULT_HOST = "localhost";
|
|
13
|
+
const DEFAULT_PORT = 3000;
|
|
14
|
+
const DEFAULT_TIMEOUT_MS = 15000;
|
|
15
|
+
export class AppLauncher {
|
|
16
|
+
async launch(options) {
|
|
17
|
+
const host = options.host ?? DEFAULT_HOST;
|
|
18
|
+
const port = options.port ?? DEFAULT_PORT;
|
|
19
|
+
const baseUrl = `http://${host}:${port}`;
|
|
20
|
+
const readyPath = options.readyPath ?? "/";
|
|
21
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
22
|
+
if (options.mode === "ssg") {
|
|
23
|
+
await this.runBuild(options);
|
|
24
|
+
}
|
|
25
|
+
await this.ensurePortAvailable(host, port);
|
|
26
|
+
const command = this.buildCommand(options, host, port);
|
|
27
|
+
const output = { stdout: [], stderr: [] };
|
|
28
|
+
const child = this.spawnProcess(command, options.cwd, options.env, output);
|
|
29
|
+
const ready = this.waitForReady(`${baseUrl}${readyPath}`, timeoutMs);
|
|
30
|
+
return new AppInstance({
|
|
31
|
+
mode: options.mode,
|
|
32
|
+
baseUrl,
|
|
33
|
+
process: child,
|
|
34
|
+
output,
|
|
35
|
+
ready,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
buildCommand(options, host, port) {
|
|
39
|
+
const base = options.command ?? ["cloud-front"];
|
|
40
|
+
const [command, ...baseArgs] = base;
|
|
41
|
+
if (options.mode === "dev") {
|
|
42
|
+
return {
|
|
43
|
+
command,
|
|
44
|
+
args: [...baseArgs, "dev", "--host", host, "--port", String(port)],
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
if (options.mode === "ssg") {
|
|
48
|
+
const outDir = options.outDir ?? "dist";
|
|
49
|
+
return {
|
|
50
|
+
command,
|
|
51
|
+
args: [...baseArgs, "preview", "--host", host, "--port", String(port), "--outDir", outDir],
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
return {
|
|
55
|
+
command,
|
|
56
|
+
args: [...baseArgs, "start", "--host", host, "--port", String(port)],
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
async runBuild(options) {
|
|
60
|
+
const base = options.command ?? ["cloud-front"];
|
|
61
|
+
const [command, ...baseArgs] = base;
|
|
62
|
+
const outDir = options.outDir ?? "dist";
|
|
63
|
+
const buildArgs = [...baseArgs, "build", "--mode", "ssg", "--outDir", outDir];
|
|
64
|
+
const output = { stdout: [], stderr: [] };
|
|
65
|
+
const child = this.spawnProcess({ command, args: buildArgs }, options.cwd, options.env, output);
|
|
66
|
+
const exitCode = await new Promise((resolve) => {
|
|
67
|
+
child.once("exit", (code) => resolve(code));
|
|
68
|
+
});
|
|
69
|
+
if (exitCode !== 0) {
|
|
70
|
+
throw new AppLaunchError(`cloud-front build failed with exit code ${exitCode}. ${this.formatOutput(output)}`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
spawnProcess(command, cwd, env, output) {
|
|
74
|
+
const child = spawn(command.command, command.args, {
|
|
75
|
+
cwd,
|
|
76
|
+
env: { ...process.env, ...env },
|
|
77
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
78
|
+
});
|
|
79
|
+
child.stdout?.on("data", (chunk) => {
|
|
80
|
+
output.stdout.push(chunk.toString());
|
|
81
|
+
});
|
|
82
|
+
child.stderr?.on("data", (chunk) => {
|
|
83
|
+
output.stderr.push(chunk.toString());
|
|
84
|
+
});
|
|
85
|
+
return child;
|
|
86
|
+
}
|
|
87
|
+
async waitForReady(url, timeoutMs) {
|
|
88
|
+
const started = Date.now();
|
|
89
|
+
while (Date.now() - started < timeoutMs) {
|
|
90
|
+
try {
|
|
91
|
+
const controller = new AbortController();
|
|
92
|
+
const timeout = setTimeout(() => controller.abort(), 1000);
|
|
93
|
+
const response = await fetch(url, { signal: controller.signal });
|
|
94
|
+
clearTimeout(timeout);
|
|
95
|
+
if (response.ok) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
// keep retrying until timeout
|
|
101
|
+
}
|
|
102
|
+
await delay(200);
|
|
103
|
+
}
|
|
104
|
+
throw new AppLaunchError(`App did not become ready within ${timeoutMs}ms: ${url}`);
|
|
105
|
+
}
|
|
106
|
+
formatOutput(output) {
|
|
107
|
+
const stdout = output.stdout.join("").trim();
|
|
108
|
+
const stderr = output.stderr.join("").trim();
|
|
109
|
+
return [stdout && `stdout: ${stdout}`, stderr && `stderr: ${stderr}`]
|
|
110
|
+
.filter(Boolean)
|
|
111
|
+
.join(" | ");
|
|
112
|
+
}
|
|
113
|
+
async ensurePortAvailable(host, port) {
|
|
114
|
+
const isOpen = await this.isTcpPortOpen(host, port);
|
|
115
|
+
if (isOpen) {
|
|
116
|
+
throw new AppLaunchError(`Port ${port} on host "${host}" is already in use. Stop the existing server or provide a different port.`);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
async isTcpPortOpen(host, port) {
|
|
120
|
+
return new Promise((resolve) => {
|
|
121
|
+
const socket = new Socket();
|
|
122
|
+
let settled = false;
|
|
123
|
+
const finalize = (value) => {
|
|
124
|
+
if (settled) {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
settled = true;
|
|
128
|
+
socket.destroy();
|
|
129
|
+
resolve(value);
|
|
130
|
+
};
|
|
131
|
+
socket.setTimeout(400);
|
|
132
|
+
socket.once("connect", () => finalize(true));
|
|
133
|
+
socket.once("timeout", () => finalize(false));
|
|
134
|
+
socket.once("error", (error) => {
|
|
135
|
+
if (error.code === "ECONNREFUSED" ||
|
|
136
|
+
error.code === "EHOSTUNREACH" ||
|
|
137
|
+
error.code === "ENOTFOUND" ||
|
|
138
|
+
error.code === "EAI_AGAIN") {
|
|
139
|
+
finalize(false);
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
finalize(true);
|
|
143
|
+
});
|
|
144
|
+
socket.connect(port, host);
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Page } from "playwright";
|
|
2
|
+
import type { DynamicManifestExpectation } from "../types/scenario.js";
|
|
3
|
+
export interface ManifestObservation {
|
|
4
|
+
url: string;
|
|
5
|
+
status: number;
|
|
6
|
+
mode?: "meta" | "program";
|
|
7
|
+
pageId?: string;
|
|
8
|
+
version?: string;
|
|
9
|
+
}
|
|
10
|
+
export interface ManifestObserverOptions {
|
|
11
|
+
endpoints?: RegExp[];
|
|
12
|
+
}
|
|
13
|
+
export declare class ManifestObserver {
|
|
14
|
+
private readonly endpoints;
|
|
15
|
+
private readonly observations;
|
|
16
|
+
constructor(options?: ManifestObserverOptions);
|
|
17
|
+
attach(page: Page): void;
|
|
18
|
+
getObservations(): ManifestObservation[];
|
|
19
|
+
reset(): void;
|
|
20
|
+
assert(expectation: DynamicManifestExpectation): void;
|
|
21
|
+
private matches;
|
|
22
|
+
private handleResponse;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=ManifestObserver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ManifestObserver.d.ts","sourceRoot":"","sources":["../../src/dynamic/ManifestObserver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAY,IAAI,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,sBAAsB,CAAC;AAEvE,MAAM,WAAW,mBAAmB;IAClC,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,uBAAuB;IACtC,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;CACtB;AAID,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAW;IACrC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA6B;gBAE9C,OAAO,GAAE,uBAA4B;IAIjD,MAAM,CAAC,IAAI,EAAE,IAAI;IAMjB,eAAe;IAIf,KAAK;IAIL,MAAM,CAAC,WAAW,EAAE,0BAA0B;IAW9C,OAAO,CAAC,OAAO;YAaD,cAAc;CAqC7B"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
const DEFAULT_ENDPOINTS = [/\/api\/pages\/resolve/, /\/api\/pages\//];
|
|
2
|
+
export class ManifestObserver {
|
|
3
|
+
constructor(options = {}) {
|
|
4
|
+
this.observations = [];
|
|
5
|
+
this.endpoints = options.endpoints ?? DEFAULT_ENDPOINTS;
|
|
6
|
+
}
|
|
7
|
+
attach(page) {
|
|
8
|
+
page.on("response", (response) => {
|
|
9
|
+
void this.handleResponse(response);
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
getObservations() {
|
|
13
|
+
return [...this.observations];
|
|
14
|
+
}
|
|
15
|
+
reset() {
|
|
16
|
+
this.observations.length = 0;
|
|
17
|
+
}
|
|
18
|
+
assert(expectation) {
|
|
19
|
+
const match = this.observations.find((entry) => this.matches(entry, expectation));
|
|
20
|
+
if (!match) {
|
|
21
|
+
throw new Error(`Dynamic manifest expectation not met (mode=${expectation.mode ?? "any"}, pageId=${expectation.pageId ?? "any"})`);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
matches(entry, expectation) {
|
|
25
|
+
if (expectation.mode && entry.mode !== expectation.mode) {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
if (expectation.pageId && entry.pageId !== expectation.pageId) {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
if (expectation.version && entry.version !== expectation.version) {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
async handleResponse(response) {
|
|
37
|
+
const url = response.url();
|
|
38
|
+
if (!this.endpoints.some((pattern) => pattern.test(url))) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
const observation = {
|
|
42
|
+
url,
|
|
43
|
+
status: response.status(),
|
|
44
|
+
};
|
|
45
|
+
try {
|
|
46
|
+
const payload = await response.json();
|
|
47
|
+
if (payload && typeof payload === "object") {
|
|
48
|
+
const data = payload;
|
|
49
|
+
if (typeof data.mode === "string") {
|
|
50
|
+
observation.mode = data.mode;
|
|
51
|
+
}
|
|
52
|
+
if (!observation.mode && data.definition && typeof data.definition === "object") {
|
|
53
|
+
const def = data.definition;
|
|
54
|
+
if (typeof def.kind === "string") {
|
|
55
|
+
observation.mode = def.kind;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (typeof data.pageId === "string") {
|
|
59
|
+
observation.pageId = data.pageId;
|
|
60
|
+
}
|
|
61
|
+
if (typeof data.version === "string") {
|
|
62
|
+
observation.version = data.version;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
// ignore json parsing failures; we still capture url/status
|
|
68
|
+
}
|
|
69
|
+
this.observations.push(observation);
|
|
70
|
+
}
|
|
71
|
+
}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface HyperTestErrorOptions {
|
|
2
|
+
cause?: unknown;
|
|
3
|
+
}
|
|
4
|
+
export declare class HyperTestError extends Error {
|
|
5
|
+
constructor(message: string, options?: HyperTestErrorOptions);
|
|
6
|
+
}
|
|
7
|
+
export declare class SchemaError extends HyperTestError {
|
|
8
|
+
}
|
|
9
|
+
export declare class LaunchError extends HyperTestError {
|
|
10
|
+
}
|
|
11
|
+
export declare class BrowserError extends HyperTestError {
|
|
12
|
+
}
|
|
13
|
+
export declare class AssertionError extends HyperTestError {
|
|
14
|
+
}
|
|
15
|
+
export declare class TimeoutError extends HyperTestError {
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,qBAAqB;IACpC,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,qBAAa,cAAe,SAAQ,KAAK;gBAC3B,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,qBAA0B;CAOjE;AAED,qBAAa,WAAY,SAAQ,cAAc;CAAG;AAClD,qBAAa,WAAY,SAAQ,cAAc;CAAG;AAClD,qBAAa,YAAa,SAAQ,cAAc;CAAG;AACnD,qBAAa,cAAe,SAAQ,cAAc;CAAG;AACrD,qBAAa,YAAa,SAAQ,cAAc;CAAG"}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export class HyperTestError extends Error {
|
|
2
|
+
constructor(message, options = {}) {
|
|
3
|
+
super(message);
|
|
4
|
+
this.name = new.target.name;
|
|
5
|
+
if (options.cause !== undefined) {
|
|
6
|
+
this.cause = options.cause;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
export class SchemaError extends HyperTestError {
|
|
11
|
+
}
|
|
12
|
+
export class LaunchError extends HyperTestError {
|
|
13
|
+
}
|
|
14
|
+
export class BrowserError extends HyperTestError {
|
|
15
|
+
}
|
|
16
|
+
export class AssertionError extends HyperTestError {
|
|
17
|
+
}
|
|
18
|
+
export class TimeoutError extends HyperTestError {
|
|
19
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export interface EnvironmentScriptDefinition {
|
|
2
|
+
path: string;
|
|
3
|
+
}
|
|
4
|
+
export interface EnvironmentScriptProvider {
|
|
5
|
+
getEnvironmentScript(): Promise<EnvironmentScriptDefinition | null>;
|
|
6
|
+
}
|
|
7
|
+
export interface EnvironmentScriptConfig {
|
|
8
|
+
testing?: {
|
|
9
|
+
e2e?: {
|
|
10
|
+
environmentScript?: string;
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
export declare class ConfigEnvironmentScriptProvider implements EnvironmentScriptProvider {
|
|
15
|
+
private readonly config;
|
|
16
|
+
private readonly projectRoot;
|
|
17
|
+
constructor(config: EnvironmentScriptConfig, projectRoot: string);
|
|
18
|
+
static fromProjectRoot(projectRoot: string): Promise<ConfigEnvironmentScriptProvider>;
|
|
19
|
+
getEnvironmentScript(): Promise<EnvironmentScriptDefinition | null>;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=EnvironmentScriptProvider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EnvironmentScriptProvider.d.ts","sourceRoot":"","sources":["../../src/extensibility/EnvironmentScriptProvider.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,2BAA2B;IAC1C,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,yBAAyB;IACxC,oBAAoB,IAAI,OAAO,CAAC,2BAA2B,GAAG,IAAI,CAAC,CAAC;CACrE;AAED,MAAM,WAAW,uBAAuB;IACtC,OAAO,CAAC,EAAE;QACR,GAAG,CAAC,EAAE;YACJ,iBAAiB,CAAC,EAAE,MAAM,CAAC;SAC5B,CAAC;KACH,CAAC;CACH;AAED,qBAAa,+BAAgC,YAAW,yBAAyB;IAC/E,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA0B;IACjD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;gBAEzB,MAAM,EAAE,uBAAuB,EAAE,WAAW,EAAE,MAAM;WAKnD,eAAe,CAAC,WAAW,EAAE,MAAM;IAK1C,oBAAoB,IAAI,OAAO,CAAC,2BAA2B,GAAG,IAAI,CAAC;CAQ1E"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { resolve } from "node:path";
|
|
2
|
+
import { loadConfig } from "@tyndall/core";
|
|
3
|
+
export class ConfigEnvironmentScriptProvider {
|
|
4
|
+
constructor(config, projectRoot) {
|
|
5
|
+
this.config = config;
|
|
6
|
+
this.projectRoot = projectRoot;
|
|
7
|
+
}
|
|
8
|
+
static async fromProjectRoot(projectRoot) {
|
|
9
|
+
const config = await loadConfig(projectRoot);
|
|
10
|
+
return new ConfigEnvironmentScriptProvider(config, projectRoot);
|
|
11
|
+
}
|
|
12
|
+
async getEnvironmentScript() {
|
|
13
|
+
const script = this.config.testing?.e2e?.environmentScript;
|
|
14
|
+
if (!script) {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
// Resolve relative paths from the project root to keep tests deterministic.
|
|
18
|
+
return { path: resolve(this.projectRoot, script) };
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { StepContext } from "../steps/types.js";
|
|
2
|
+
export type ExpectHandler = (value: unknown, context: StepContext) => Promise<void>;
|
|
3
|
+
export declare class ExpectRegistry {
|
|
4
|
+
private readonly handlers;
|
|
5
|
+
register(name: string, handler: ExpectHandler): void;
|
|
6
|
+
get(name: string): ExpectHandler | undefined;
|
|
7
|
+
list(): Map<string, ExpectHandler>;
|
|
8
|
+
}
|
|
9
|
+
export declare const defaultExpectRegistry: ExpectRegistry;
|
|
10
|
+
export declare const registerExpectation: (name: string, handler: ExpectHandler) => void;
|
|
11
|
+
//# sourceMappingURL=ExpectRegistry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExpectRegistry.d.ts","sourceRoot":"","sources":["../../src/extensibility/ExpectRegistry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,MAAM,MAAM,aAAa,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAEpF,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAoC;IAE7D,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa;IAI7C,GAAG,CAAC,IAAI,EAAE,MAAM;IAIhB,IAAI;CAGL;AAED,eAAO,MAAM,qBAAqB,gBAAuB,CAAC;AAE1D,eAAO,MAAM,mBAAmB,GAAI,MAAM,MAAM,EAAE,SAAS,aAAa,SAEvE,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export class ExpectRegistry {
|
|
2
|
+
constructor() {
|
|
3
|
+
this.handlers = new Map();
|
|
4
|
+
}
|
|
5
|
+
register(name, handler) {
|
|
6
|
+
this.handlers.set(name, handler);
|
|
7
|
+
}
|
|
8
|
+
get(name) {
|
|
9
|
+
return this.handlers.get(name);
|
|
10
|
+
}
|
|
11
|
+
list() {
|
|
12
|
+
return new Map(this.handlers);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export const defaultExpectRegistry = new ExpectRegistry();
|
|
16
|
+
export const registerExpectation = (name, handler) => {
|
|
17
|
+
defaultExpectRegistry.register(name, handler);
|
|
18
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Step } from "../types/scenario.js";
|
|
2
|
+
import type { StepContext } from "../steps/types.js";
|
|
3
|
+
export type StepHandler = (step: Step, context: StepContext) => Promise<void>;
|
|
4
|
+
export declare class StepRegistry {
|
|
5
|
+
private readonly handlers;
|
|
6
|
+
constructor(initial?: Record<string, StepHandler>);
|
|
7
|
+
register(name: string, handler: StepHandler): void;
|
|
8
|
+
get(name: string): StepHandler | undefined;
|
|
9
|
+
list(): Map<string, StepHandler>;
|
|
10
|
+
}
|
|
11
|
+
export declare const createStepRegistry: () => StepRegistry;
|
|
12
|
+
export declare const defaultStepRegistry: StepRegistry;
|
|
13
|
+
export declare const registerStep: (name: string, handler: StepHandler) => void;
|
|
14
|
+
//# sourceMappingURL=StepRegistry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StepRegistry.d.ts","sourceRoot":"","sources":["../../src/extensibility/StepRegistry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGrD,MAAM,MAAM,WAAW,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAE9E,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAkC;gBAE/C,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAM;IAMrD,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW;IAI3C,GAAG,CAAC,IAAI,EAAE,MAAM;IAIhB,IAAI;CAGL;AAED,eAAO,MAAM,kBAAkB,oBAM9B,CAAC;AAEF,eAAO,MAAM,mBAAmB,cAAuB,CAAC;AAExD,eAAO,MAAM,YAAY,GAAI,MAAM,MAAM,EAAE,SAAS,WAAW,SAE9D,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { defaultStepHandlers } from "../steps/index.js";
|
|
2
|
+
export class StepRegistry {
|
|
3
|
+
constructor(initial = {}) {
|
|
4
|
+
this.handlers = new Map();
|
|
5
|
+
for (const [name, handler] of Object.entries(initial)) {
|
|
6
|
+
this.handlers.set(name, handler);
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
register(name, handler) {
|
|
10
|
+
this.handlers.set(name, handler);
|
|
11
|
+
}
|
|
12
|
+
get(name) {
|
|
13
|
+
return this.handlers.get(name);
|
|
14
|
+
}
|
|
15
|
+
list() {
|
|
16
|
+
return new Map(this.handlers);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export const createStepRegistry = () => {
|
|
20
|
+
const registry = new StepRegistry();
|
|
21
|
+
for (const [name, handler] of Object.entries(defaultStepHandlers)) {
|
|
22
|
+
registry.register(name, handler);
|
|
23
|
+
}
|
|
24
|
+
return registry;
|
|
25
|
+
};
|
|
26
|
+
export const defaultStepRegistry = createStepRegistry();
|
|
27
|
+
export const registerStep = (name, handler) => {
|
|
28
|
+
defaultStepRegistry.register(name, handler);
|
|
29
|
+
};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export { ScenarioLoader } from "./scenario/ScenarioLoader.js";
|
|
2
|
+
export { ScenarioValidator, ScenarioValidationError } from "./scenario/ScenarioValidator.js";
|
|
3
|
+
export { AppLauncher, AppLaunchError } from "./app/AppLauncher.js";
|
|
4
|
+
export { AppInstance } from "./app/AppInstance.js";
|
|
5
|
+
export { PlaywrightRunner } from "./runner/PlaywrightRunner.js";
|
|
6
|
+
export { StepExecutor } from "./runner/StepExecutor.js";
|
|
7
|
+
export { ManifestObserver } from "./dynamic/ManifestObserver.js";
|
|
8
|
+
export { ConfigEnvironmentScriptProvider, } from "./extensibility/EnvironmentScriptProvider.js";
|
|
9
|
+
export { defaultStepRegistry, StepRegistry, registerStep, } from "./extensibility/StepRegistry.js";
|
|
10
|
+
export { defaultExpectRegistry, ExpectRegistry, registerExpectation, } from "./extensibility/ExpectRegistry.js";
|
|
11
|
+
export { ResultCollector } from "./reporter/ResultCollector.js";
|
|
12
|
+
export { ConsoleReporter } from "./reporter/ConsoleReporter.js";
|
|
13
|
+
export { JsonReporter } from "./reporter/JsonReporter.js";
|
|
14
|
+
export { HtmlReporter } from "./reporter/HtmlReporter.js";
|
|
15
|
+
export type { Reporter } from "./reporter/Reporter.js";
|
|
16
|
+
export type { EnvironmentScriptDefinition, EnvironmentScriptConfig, EnvironmentScriptProvider, } from "./extensibility/EnvironmentScriptProvider.js";
|
|
17
|
+
export type { ScenarioMode, ScenarioSetup, ScenarioCase, ScenarioDocument, Step, ExpectSpec, DynamicManifestExpectation, NetworkExpectation, } from "./types/scenario.js";
|
|
18
|
+
export type { StepResult, ScenarioResult, AggregatedResult } from "./types/result.js";
|
|
19
|
+
export type { StepContext } from "./steps/index.js";
|
|
20
|
+
export { HyperTestError, SchemaError, LaunchError, BrowserError, AssertionError, TimeoutError, } from "./errors.js";
|
|
21
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAC7F,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACnE,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EACL,+BAA+B,GAChC,MAAM,8CAA8C,CAAC;AACtD,OAAO,EACL,mBAAmB,EACnB,YAAY,EACZ,YAAY,GACb,MAAM,iCAAiC,CAAC;AACzC,OAAO,EACL,qBAAqB,EACrB,cAAc,EACd,mBAAmB,GACpB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,YAAY,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AACvD,YAAY,EACV,2BAA2B,EAC3B,uBAAuB,EACvB,yBAAyB,GAC1B,MAAM,8CAA8C,CAAC;AACtD,YAAY,EACV,YAAY,EACZ,aAAa,EACb,YAAY,EACZ,gBAAgB,EAChB,IAAI,EACJ,UAAU,EACV,0BAA0B,EAC1B,kBAAkB,GACnB,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EAAE,UAAU,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACtF,YAAY,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EACL,cAAc,EACd,WAAW,EACX,WAAW,EACX,YAAY,EACZ,cAAc,EACd,YAAY,GACb,MAAM,aAAa,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export { ScenarioLoader } from "./scenario/ScenarioLoader.js";
|
|
2
|
+
export { ScenarioValidator, ScenarioValidationError } from "./scenario/ScenarioValidator.js";
|
|
3
|
+
export { AppLauncher, AppLaunchError } from "./app/AppLauncher.js";
|
|
4
|
+
export { AppInstance } from "./app/AppInstance.js";
|
|
5
|
+
export { PlaywrightRunner } from "./runner/PlaywrightRunner.js";
|
|
6
|
+
export { StepExecutor } from "./runner/StepExecutor.js";
|
|
7
|
+
export { ManifestObserver } from "./dynamic/ManifestObserver.js";
|
|
8
|
+
export { ConfigEnvironmentScriptProvider, } from "./extensibility/EnvironmentScriptProvider.js";
|
|
9
|
+
export { defaultStepRegistry, StepRegistry, registerStep, } from "./extensibility/StepRegistry.js";
|
|
10
|
+
export { defaultExpectRegistry, ExpectRegistry, registerExpectation, } from "./extensibility/ExpectRegistry.js";
|
|
11
|
+
export { ResultCollector } from "./reporter/ResultCollector.js";
|
|
12
|
+
export { ConsoleReporter } from "./reporter/ConsoleReporter.js";
|
|
13
|
+
export { JsonReporter } from "./reporter/JsonReporter.js";
|
|
14
|
+
export { HtmlReporter } from "./reporter/HtmlReporter.js";
|
|
15
|
+
export { HyperTestError, SchemaError, LaunchError, BrowserError, AssertionError, TimeoutError, } from "./errors.js";
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { AggregatedResult } from "../types/result.js";
|
|
2
|
+
import type { Reporter } from "./Reporter.js";
|
|
3
|
+
export declare class ConsoleReporter implements Reporter {
|
|
4
|
+
report(result: AggregatedResult): Promise<void>;
|
|
5
|
+
}
|
|
6
|
+
//# sourceMappingURL=ConsoleReporter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ConsoleReporter.d.ts","sourceRoot":"","sources":["../../src/reporter/ConsoleReporter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9C,qBAAa,eAAgB,YAAW,QAAQ;IACxC,MAAM,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;CAatD"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export class ConsoleReporter {
|
|
2
|
+
async report(result) {
|
|
3
|
+
const lines = [
|
|
4
|
+
`E2E Report: ${result.name}`,
|
|
5
|
+
`Status: ${result.status}`,
|
|
6
|
+
`Scenarios: ${result.scenarios.length}`,
|
|
7
|
+
];
|
|
8
|
+
for (const scenario of result.scenarios) {
|
|
9
|
+
lines.push(`- ${scenario.scenario.id}: ${scenario.status}`);
|
|
10
|
+
}
|
|
11
|
+
console.log(lines.join("\n"));
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { AggregatedResult } from "../types/result.js";
|
|
2
|
+
import type { Reporter } from "./Reporter.js";
|
|
3
|
+
export interface HtmlReporterOptions {
|
|
4
|
+
outputPath?: string;
|
|
5
|
+
}
|
|
6
|
+
export declare class HtmlReporter implements Reporter {
|
|
7
|
+
private readonly outputPath;
|
|
8
|
+
constructor(options?: HtmlReporterOptions);
|
|
9
|
+
report(result: AggregatedResult): Promise<void>;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=HtmlReporter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HtmlReporter.d.ts","sourceRoot":"","sources":["../../src/reporter/HtmlReporter.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9C,MAAM,WAAW,mBAAmB;IAClC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,qBAAa,YAAa,YAAW,QAAQ;IAC3C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;gBAExB,OAAO,GAAE,mBAAwB;IAIvC,MAAM,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;CAgCtD"}
|