donobu 5.41.0 → 5.41.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.
@@ -106,6 +106,9 @@ class DonobuSlackReporter {
106
106
  this.resultsByTest = new Map();
107
107
  this.options = options;
108
108
  }
109
+ onBegin(config, _suite) {
110
+ this.rootDir = config.rootDir;
111
+ }
109
112
  onTestEnd(test, result) {
110
113
  const existing = this.resultsByTest.get(test);
111
114
  if (existing) {
@@ -121,7 +124,7 @@ class DonobuSlackReporter {
121
124
  const autoHealActive = envVars_1.env.data.DONOBU_AUTO_HEAL_ACTIVE === '1';
122
125
  const autoHealOrchestrated = envVars_1.env.data.DONOBU_AUTO_HEAL_ORCHESTRATED === '1';
123
126
  const reportUrl = envVars_1.env.data.DONOBU_REPORT_URL;
124
- const report = (0, buildReport_1.buildDonobuReport)(this.resultsByTest);
127
+ const report = (0, buildReport_1.buildDonobuReport)(this.resultsByTest, this.rootDir);
125
128
  (0, stateFile_1.mergeStateFileEntry)(envVars_1.env.data.PLAYWRIGHT_JSON_OUTPUT_DIR, report, {
126
129
  slack: { outputFile },
127
130
  });
package/dist/main.d.ts CHANGED
@@ -6,7 +6,6 @@ export { GptClient } from './clients/GptClient';
6
6
  export { type GptClientPlugin, GptClientPluginRegistry, } from './clients/GptClientPlugin';
7
7
  export { OpenAiGptClient } from './clients/OpenAiGptClient';
8
8
  export { VercelAiGptClient } from './clients/VercelAiGptClient';
9
- export { runGenerateSiteTests } from './codegen/runGenerateSiteTests';
10
9
  export { env } from './envVars';
11
10
  export * from './exceptions/DonobuException';
12
11
  export * from './exceptions/FlowIdCollisionException';
package/dist/main.js CHANGED
@@ -14,7 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.TargetRuntimePluginRegistry = exports.PersistencePluginRegistry = exports.shutdownFileUploadWorkers = exports.getFileUploadAggregateStatus = exports.createDefaultToolRegistry = exports.ToolManager = exports.PluginLoader = exports.InteractionVisualizer = exports.setupDonobuStack = exports.prepareToolCallsForRerun = exports.DonobuFlowsManager = exports.distillAllowedEnvVariableNames = exports.DonobuFlow = exports.AdminApiController = exports.env = exports.runGenerateSiteTests = exports.VercelAiGptClient = exports.OpenAiGptClient = exports.GptClientPluginRegistry = exports.GptClient = exports.GoogleGenerativeAiGptClient = exports.fixAssertFields = exports.DonobuGptClient = exports.AnthropicGptClient = void 0;
17
+ exports.TargetRuntimePluginRegistry = exports.PersistencePluginRegistry = exports.shutdownFileUploadWorkers = exports.getFileUploadAggregateStatus = exports.createDefaultToolRegistry = exports.ToolManager = exports.PluginLoader = exports.InteractionVisualizer = exports.setupDonobuStack = exports.prepareToolCallsForRerun = exports.DonobuFlowsManager = exports.distillAllowedEnvVariableNames = exports.DonobuFlow = exports.AdminApiController = exports.env = exports.VercelAiGptClient = exports.OpenAiGptClient = exports.GptClientPluginRegistry = exports.GptClient = exports.GoogleGenerativeAiGptClient = exports.fixAssertFields = exports.DonobuGptClient = exports.AnthropicGptClient = void 0;
18
18
  exports.startDonobuServer = startDonobuServer;
19
19
  const commander_1 = require("commander");
20
20
  const v4_1 = require("zod/v4");
@@ -39,8 +39,6 @@ var OpenAiGptClient_1 = require("./clients/OpenAiGptClient");
39
39
  Object.defineProperty(exports, "OpenAiGptClient", { enumerable: true, get: function () { return OpenAiGptClient_1.OpenAiGptClient; } });
40
40
  var VercelAiGptClient_1 = require("./clients/VercelAiGptClient");
41
41
  Object.defineProperty(exports, "VercelAiGptClient", { enumerable: true, get: function () { return VercelAiGptClient_1.VercelAiGptClient; } });
42
- var runGenerateSiteTests_1 = require("./codegen/runGenerateSiteTests");
43
- Object.defineProperty(exports, "runGenerateSiteTests", { enumerable: true, get: function () { return runGenerateSiteTests_1.runGenerateSiteTests; } });
44
42
  var envVars_2 = require("./envVars");
45
43
  Object.defineProperty(exports, "env", { enumerable: true, get: function () { return envVars_2.env; } });
46
44
  __exportStar(require("./exceptions/DonobuException"), exports);
@@ -18,5 +18,5 @@ import type { DonobuReport } from './model';
18
18
  * entry for their format) before persisting the result — this helper owns the
19
19
  * structure walk, not the output-path accounting.
20
20
  */
21
- export declare function buildDonobuReport(resultsByTest: Map<TestCase, TestResult[]>): DonobuReport;
21
+ export declare function buildDonobuReport(resultsByTest: Map<TestCase, TestResult[]>, rootDir?: string): DonobuReport;
22
22
  //# sourceMappingURL=buildReport.d.ts.map
@@ -11,6 +11,7 @@
11
11
  */
12
12
  Object.defineProperty(exports, "__esModule", { value: true });
13
13
  exports.buildDonobuReport = buildDonobuReport;
14
+ const path_1 = require("path");
14
15
  /**
15
16
  * Build a canonical `DonobuReport` from the per-test result accumulators that
16
17
  * each Donobu reporter maintains during a run.
@@ -19,13 +20,18 @@ exports.buildDonobuReport = buildDonobuReport;
19
20
  * entry for their format) before persisting the result — this helper owns the
20
21
  * structure walk, not the output-path accounting.
21
22
  */
22
- function buildDonobuReport(resultsByTest) {
23
+ function buildDonobuReport(resultsByTest, rootDir) {
23
24
  // Group tests by file path, then by test title.
24
25
  // Multiple TestCase objects with the same (file, title) represent the same
25
26
  // spec running under different Playwright projects.
27
+ // Paths are normalized to be relative to the Playwright rootDir (mirroring
28
+ // the native JSON reporter) so GitHub Actions summaries and other consumers
29
+ // don't show absolute CI runner paths.
26
30
  const byFile = new Map();
27
31
  for (const test of resultsByTest.keys()) {
28
- const file = test.location.file;
32
+ const file = rootDir
33
+ ? (0, path_1.relative)(rootDir, test.location.file)
34
+ : test.location.file;
29
35
  if (!byFile.has(file)) {
30
36
  byFile.set(file, new Map());
31
37
  }
@@ -30,7 +30,7 @@
30
30
  * the Playwright JSON output directory so the orchestrator can pick it up,
31
31
  * merge it with the initial run's state, and re-render the HTML once.
32
32
  */
33
- import type { FullResult, Reporter, TestCase, TestResult } from '@playwright/test/reporter';
33
+ import type { FullConfig, FullResult, Reporter, Suite, TestCase, TestResult } from '@playwright/test/reporter';
34
34
  export interface DonobuHtmlReporterOptions {
35
35
  /** Path to write the HTML report. Defaults to `test-results/index.html`. */
36
36
  outputFile?: string;
@@ -45,7 +45,9 @@ export default class DonobuHtmlReporter implements Reporter {
45
45
  private readonly options;
46
46
  /** Accumulates all TestResult objects per TestCase (one per retry attempt). */
47
47
  private readonly resultsByTest;
48
+ private rootDir;
48
49
  constructor(options?: DonobuHtmlReporterOptions);
50
+ onBegin(config: FullConfig, _suite: Suite): void;
49
51
  onTestEnd(test: TestCase, result: TestResult): void;
50
52
  onEnd(_result: FullResult): Promise<void>;
51
53
  printsToStdio(): boolean;
@@ -45,6 +45,9 @@ class DonobuHtmlReporter {
45
45
  this.resultsByTest = new Map();
46
46
  this.options = options;
47
47
  }
48
+ onBegin(config, _suite) {
49
+ this.rootDir = config.rootDir;
50
+ }
48
51
  onTestEnd(test, result) {
49
52
  const existing = this.resultsByTest.get(test);
50
53
  if (existing) {
@@ -58,7 +61,7 @@ class DonobuHtmlReporter {
58
61
  const outputFile = (0, path_1.resolve)(this.options.outputFile ?? 'test-results/index.html');
59
62
  const outputDir = (0, path_1.dirname)(outputFile);
60
63
  const autoHealActive = envVars_1.env.data.DONOBU_AUTO_HEAL_ACTIVE === '1';
61
- const report = (0, buildReport_1.buildDonobuReport)(this.resultsByTest);
64
+ const report = (0, buildReport_1.buildDonobuReport)(this.resultsByTest, this.rootDir);
62
65
  // Persist the full report + this reporter's output entry to the shared
63
66
  // state file so other reporters and the auto-heal orchestrator can find
64
67
  // it. When multiple reporters run in the same process this merges each
@@ -20,7 +20,7 @@
20
20
  * file writes. It always merges its output entry into the shared state file
21
21
  * so the orchestrator knows to regenerate the markdown from the merged report.
22
22
  */
23
- import type { FullResult, Reporter, TestCase, TestResult } from '@playwright/test/reporter';
23
+ import type { FullConfig, FullResult, Reporter, Suite, TestCase, TestResult } from '@playwright/test/reporter';
24
24
  export interface DonobuMarkdownReporterOptions {
25
25
  /** Path to write the Markdown report. Defaults to `test-results/report.md`. */
26
26
  outputFile?: string;
@@ -28,7 +28,9 @@ export interface DonobuMarkdownReporterOptions {
28
28
  export default class DonobuMarkdownReporter implements Reporter {
29
29
  private readonly options;
30
30
  private readonly resultsByTest;
31
+ private rootDir;
31
32
  constructor(options?: DonobuMarkdownReporterOptions);
33
+ onBegin(config: FullConfig, _suite: Suite): void;
32
34
  onTestEnd(test: TestCase, result: TestResult): void;
33
35
  onEnd(_result: FullResult): Promise<void>;
34
36
  printsToStdio(): boolean;
@@ -34,6 +34,9 @@ class DonobuMarkdownReporter {
34
34
  this.resultsByTest = new Map();
35
35
  this.options = options;
36
36
  }
37
+ onBegin(config, _suite) {
38
+ this.rootDir = config.rootDir;
39
+ }
37
40
  onTestEnd(test, result) {
38
41
  const existing = this.resultsByTest.get(test);
39
42
  if (existing) {
@@ -47,7 +50,7 @@ class DonobuMarkdownReporter {
47
50
  const outputFile = (0, path_1.resolve)(this.options.outputFile ?? 'test-results/report.md');
48
51
  const outputDir = (0, path_1.dirname)(outputFile);
49
52
  const autoHealActive = envVars_1.env.data.DONOBU_AUTO_HEAL_ACTIVE === '1';
50
- const report = (0, buildReport_1.buildDonobuReport)(this.resultsByTest);
53
+ const report = (0, buildReport_1.buildDonobuReport)(this.resultsByTest, this.rootDir);
51
54
  (0, stateFile_1.mergeStateFileEntry)(envVars_1.env.data.PLAYWRIGHT_JSON_OUTPUT_DIR, report, {
52
55
  markdown: { outputFile },
53
56
  });
@@ -71,7 +71,7 @@
71
71
  * both the initial run and the heal rerun; the orchestrator posts the
72
72
  * merged payload after re-rendering.
73
73
  */
74
- import type { FullResult, Reporter, TestCase, TestResult } from '@playwright/test/reporter';
74
+ import type { FullConfig, FullResult, Reporter, Suite, TestCase, TestResult } from '@playwright/test/reporter';
75
75
  import { type SlackBlockPayload } from './renderSlack';
76
76
  export interface DonobuSlackReporterOptions {
77
77
  /** Path to write the Slack payload. Defaults to `test-results/slack-payload.json`. */
@@ -85,7 +85,9 @@ export declare function postSlackPayload(webhookUrl: string, payload: SlackBlock
85
85
  export default class DonobuSlackReporter implements Reporter {
86
86
  private readonly options;
87
87
  private readonly resultsByTest;
88
+ private rootDir;
88
89
  constructor(options?: DonobuSlackReporterOptions);
90
+ onBegin(config: FullConfig, _suite: Suite): void;
89
91
  onTestEnd(test: TestCase, result: TestResult): void;
90
92
  onEnd(_result: FullResult): Promise<void>;
91
93
  printsToStdio(): boolean;
@@ -106,6 +106,9 @@ class DonobuSlackReporter {
106
106
  this.resultsByTest = new Map();
107
107
  this.options = options;
108
108
  }
109
+ onBegin(config, _suite) {
110
+ this.rootDir = config.rootDir;
111
+ }
109
112
  onTestEnd(test, result) {
110
113
  const existing = this.resultsByTest.get(test);
111
114
  if (existing) {
@@ -121,7 +124,7 @@ class DonobuSlackReporter {
121
124
  const autoHealActive = envVars_1.env.data.DONOBU_AUTO_HEAL_ACTIVE === '1';
122
125
  const autoHealOrchestrated = envVars_1.env.data.DONOBU_AUTO_HEAL_ORCHESTRATED === '1';
123
126
  const reportUrl = envVars_1.env.data.DONOBU_REPORT_URL;
124
- const report = (0, buildReport_1.buildDonobuReport)(this.resultsByTest);
127
+ const report = (0, buildReport_1.buildDonobuReport)(this.resultsByTest, this.rootDir);
125
128
  (0, stateFile_1.mergeStateFileEntry)(envVars_1.env.data.PLAYWRIGHT_JSON_OUTPUT_DIR, report, {
126
129
  slack: { outputFile },
127
130
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "donobu",
3
- "version": "5.41.0",
3
+ "version": "5.41.2",
4
4
  "description": "Create browser automations with an LLM agent and replay them as Playwright scripts.",
5
5
  "main": "dist/main.js",
6
6
  "module": "dist/esm/main.js",
@@ -29,8 +29,7 @@
29
29
  },
30
30
  "bin": {
31
31
  "donobu": "./dist/cli/donobu-cli.js",
32
- "install-donobu-plugin": "./dist/cli/install-donobu-plugin.js",
33
- "generate-site-tests": "./dist/cli/generate-site-tests.js"
32
+ "install-donobu-plugin": "./dist/cli/install-donobu-plugin.js"
34
33
  },
35
34
  "keywords": [
36
35
  "playwright",
@@ -50,19 +49,15 @@
50
49
  "@playwright/test": "^1.57.0",
51
50
  "@types/better-sqlite3": "^7.6.13",
52
51
  "@types/express": "^5.0.6",
53
- "@types/glob": "^8.1.0",
54
- "@types/js-yaml": "^4.0.9",
55
52
  "@types/node": "^22.10.5",
56
53
  "@types/proper-lockfile": "^4.1.4",
57
54
  "@typescript-eslint/eslint-plugin": "^8.56.1",
58
55
  "@typescript-eslint/parser": "^8.56.1",
59
56
  "@vitest/coverage-v8": "^4.0.17",
60
57
  "axe-core": "^4.11.2",
61
- "csv-stringify": "^6.6.0",
62
58
  "eslint": "^10.0.2",
63
59
  "eslint-plugin-simple-import-sort": "^12.1.1",
64
60
  "globals": "^16.0.0",
65
- "js-yaml": "^4.1.0",
66
61
  "playwright": "^1.57.0",
67
62
  "playwright-core": "^1.57.0",
68
63
  "typescript-eslint": "^8.47.0",
@@ -84,7 +79,6 @@
84
79
  "fast-json-stable-stringify": "^2.1.0",
85
80
  "prettier": "^3.8.0",
86
81
  "proper-lockfile": "^4.1.2",
87
- "slugify": "^1.6.6",
88
82
  "typescript": "^5.8.3",
89
83
  "winston": "^3.19.0",
90
84
  "winston-daily-rotate-file": "^5.0.0",
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=generate-site-tests.d.ts.map
@@ -1,43 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- /**
4
- * Thin CLI wrapper for Donobu Site Test Generator.
5
- */
6
- const commander_1 = require("commander");
7
- const runGenerateSiteTests_1 = require("../codegen/runGenerateSiteTests");
8
- async function main() {
9
- const program = new commander_1.Command();
10
- program
11
- .requiredOption('--url <url>', 'Target website URL')
12
- .option('--storage-state <path>', 'Path to Playwright storageState JSON')
13
- .option('--out <dir>', 'Output directory for the generated project', undefined)
14
- .option('--max-tests <n>', 'Maximum number of tests to generate', String(12))
15
- .option('--max-discovery-steps <n>', 'Max Donobu tool calls when profiling the site', String(32))
16
- .option('--max-test-steps <n>', 'Max Donobu tool calls when executing each test flow', String(28))
17
- .option('--gpt-config-name <name>', 'Name of the GPT config to use')
18
- .option('--playwright-variant <variant>', 'Use "ai" (page.ai) or "classic" scripts in the generated project', 'ai')
19
- .option('--headed', 'Generate headed Playwright config (xvfb-friendly)', false)
20
- .option('--slowmo <ms>', 'Slow motion delay in ms for headed runs', (value) => Number(value))
21
- .option('--disable-self-heal', 'Disable Donobu self-healing in generated AI-mode tests', false);
22
- const cli = program.parse(process.argv).opts();
23
- await (0, runGenerateSiteTests_1.runGenerateSiteTests)({
24
- url: cli.url,
25
- outDir: cli.outDir,
26
- storageStatePath: cli.storageStatePath,
27
- maxTests: cli.maxTests ? Number(cli.maxTests) : undefined,
28
- maxDiscoverySteps: cli.maxDiscoverySteps
29
- ? Number(cli.maxDiscoverySteps)
30
- : undefined,
31
- maxTestSteps: cli.maxTestSteps ? Number(cli.maxTestSteps) : undefined,
32
- gptConfigName: cli.gptConfigName,
33
- playwrightVariant: cli.playwrightVariant,
34
- headed: cli.headed,
35
- slowMo: cli.slowMo,
36
- disableSelfHeal: cli.disableSelfHeal,
37
- });
38
- }
39
- void main().catch((error) => {
40
- console.error(error.message);
41
- process.exit(1);
42
- });
43
- //# sourceMappingURL=generate-site-tests.js.map
@@ -1,69 +0,0 @@
1
- /**
2
- * Library entrypoint for Donobu Site Test Generator (coverage-aware).
3
- *
4
- * Use `runGenerateSiteTests(options, onProgress?, shouldCancel?)` to invoke programmatically.
5
- */
6
- type DiscoveryTestCase = {
7
- title: string;
8
- objective: string;
9
- assertions: string[];
10
- category?: string;
11
- startUrl?: string;
12
- dependsOnAuth?: boolean;
13
- dataNeeds?: string[];
14
- priority?: 'P0' | 'P1' | 'P2';
15
- };
16
- type DiscoveryResult = {
17
- siteProfile: {
18
- siteType: string;
19
- primaryAudiences: string[];
20
- requiresAuth: boolean;
21
- authNotes?: string;
22
- keyJourneys: string[];
23
- riskAreas: string[];
24
- };
25
- testCases: DiscoveryTestCase[];
26
- };
27
- export type GenerateSiteTestsOptions = {
28
- url: string;
29
- outDir?: string;
30
- storageStatePath?: string;
31
- maxTests?: number;
32
- maxDiscoverySteps?: number;
33
- maxTestSteps?: number;
34
- gptConfigName?: string;
35
- playwrightVariant?: 'ai' | 'classic';
36
- headed?: boolean;
37
- slowMo?: number;
38
- disableSelfHeal?: boolean;
39
- /** Explicit tool allowlist for discovery and test flows. If provided, only these tools are enabled. */
40
- toolAllowlist?: string[];
41
- /** Tool denylist to disable specific tools. Applied after allowlist. */
42
- toolDenylist?: string[];
43
- };
44
- export type ProgressEvent = {
45
- type: 'log';
46
- level?: 'info' | 'warn' | 'error';
47
- message: string;
48
- } | {
49
- type: 'flow';
50
- stage: 'start' | 'end';
51
- flowId: string;
52
- name?: string;
53
- } | {
54
- type: 'stdout';
55
- data: string;
56
- } | {
57
- type: 'summary';
58
- data: {
59
- projectDir: string;
60
- newlyGeneratedTests: number;
61
- totalPlannedTests: number;
62
- requiresAuth: boolean;
63
- usedStorageState: boolean;
64
- siteProfile?: DiscoveryResult['siteProfile'];
65
- };
66
- };
67
- export declare function runGenerateSiteTests(opts: GenerateSiteTestsOptions, onProgress?: (event: ProgressEvent) => void, shouldCancel?: () => boolean): Promise<void>;
68
- export {};
69
- //# sourceMappingURL=runGenerateSiteTests.d.ts.map