playwright-logbook 0.2.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 (130) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +134 -0
  3. package/dist/artifacts.d.ts +7 -0
  4. package/dist/artifacts.js +35 -0
  5. package/dist/artifacts.js.map +1 -0
  6. package/dist/caseids.d.ts +12 -0
  7. package/dist/caseids.js +24 -0
  8. package/dist/caseids.js.map +1 -0
  9. package/dist/cli/bin.d.ts +3 -0
  10. package/dist/cli/bin.js +6 -0
  11. package/dist/cli/bin.js.map +1 -0
  12. package/dist/cli/commands/debug.d.ts +7 -0
  13. package/dist/cli/commands/debug.js +14 -0
  14. package/dist/cli/commands/debug.js.map +1 -0
  15. package/dist/cli/commands/flaky.d.ts +8 -0
  16. package/dist/cli/commands/flaky.js +27 -0
  17. package/dist/cli/commands/flaky.js.map +1 -0
  18. package/dist/cli/commands/history.d.ts +8 -0
  19. package/dist/cli/commands/history.js +24 -0
  20. package/dist/cli/commands/history.js.map +1 -0
  21. package/dist/cli/commands/merge.d.ts +12 -0
  22. package/dist/cli/commands/merge.js +102 -0
  23. package/dist/cli/commands/merge.js.map +1 -0
  24. package/dist/cli/commands/report.d.ts +9 -0
  25. package/dist/cli/commands/report.js +13 -0
  26. package/dist/cli/commands/report.js.map +1 -0
  27. package/dist/cli/commands/summary.d.ts +7 -0
  28. package/dist/cli/commands/summary.js +14 -0
  29. package/dist/cli/commands/summary.js.map +1 -0
  30. package/dist/cli/format.d.ts +18 -0
  31. package/dist/cli/format.js +41 -0
  32. package/dist/cli/format.js.map +1 -0
  33. package/dist/cli/program.d.ts +12 -0
  34. package/dist/cli/program.js +74 -0
  35. package/dist/cli/program.js.map +1 -0
  36. package/dist/clientlib.d.ts +48 -0
  37. package/dist/clientlib.js +136 -0
  38. package/dist/clientlib.js.map +1 -0
  39. package/dist/collect.d.ts +101 -0
  40. package/dist/collect.js +50 -0
  41. package/dist/collect.js.map +1 -0
  42. package/dist/debugpacket.d.ts +31 -0
  43. package/dist/debugpacket.js +105 -0
  44. package/dist/debugpacket.js.map +1 -0
  45. package/dist/env.d.ts +41 -0
  46. package/dist/env.js +49 -0
  47. package/dist/env.js.map +1 -0
  48. package/dist/errors.d.ts +6 -0
  49. package/dist/errors.js +10 -0
  50. package/dist/errors.js.map +1 -0
  51. package/dist/history.d.ts +32 -0
  52. package/dist/history.js +72 -0
  53. package/dist/history.js.map +1 -0
  54. package/dist/index.cjs +1562 -0
  55. package/dist/index.d.ts +12 -0
  56. package/dist/index.js +9 -0
  57. package/dist/index.js.map +1 -0
  58. package/dist/merge.d.ts +9 -0
  59. package/dist/merge.js +64 -0
  60. package/dist/merge.js.map +1 -0
  61. package/dist/model.d.ts +98 -0
  62. package/dist/model.js +129 -0
  63. package/dist/model.js.map +1 -0
  64. package/dist/options.d.ts +23 -0
  65. package/dist/options.js +5 -0
  66. package/dist/options.js.map +1 -0
  67. package/dist/paths.d.ts +6 -0
  68. package/dist/paths.js +17 -0
  69. package/dist/paths.js.map +1 -0
  70. package/dist/publish.d.ts +14 -0
  71. package/dist/publish.js +2 -0
  72. package/dist/publish.js.map +1 -0
  73. package/dist/render.d.ts +6 -0
  74. package/dist/render.js +50 -0
  75. package/dist/render.js.map +1 -0
  76. package/dist/reporter.d.ts +53 -0
  77. package/dist/reporter.js +161 -0
  78. package/dist/reporter.js.map +1 -0
  79. package/dist/sanitize.d.ts +11 -0
  80. package/dist/sanitize.js +33 -0
  81. package/dist/sanitize.js.map +1 -0
  82. package/dist/schema.d.ts +581 -0
  83. package/dist/schema.js +31 -0
  84. package/dist/schema.js.map +1 -0
  85. package/dist/signals.d.ts +9 -0
  86. package/dist/signals.js +37 -0
  87. package/dist/signals.js.map +1 -0
  88. package/dist/store.d.ts +41 -0
  89. package/dist/store.js +142 -0
  90. package/dist/store.js.map +1 -0
  91. package/dist/template/css.d.ts +1 -0
  92. package/dist/template/css.js +17 -0
  93. package/dist/template/css.js.map +1 -0
  94. package/dist/template/icons.d.ts +1 -0
  95. package/dist/template/icons.js +9 -0
  96. package/dist/template/icons.js.map +1 -0
  97. package/dist/template/js/core.d.ts +1 -0
  98. package/dist/template/js/core.js +90 -0
  99. package/dist/template/js/core.js.map +1 -0
  100. package/dist/template/js/failures.d.ts +1 -0
  101. package/dist/template/js/failures.js +33 -0
  102. package/dist/template/js/failures.js.map +1 -0
  103. package/dist/template/js/help.d.ts +1 -0
  104. package/dist/template/js/help.js +4 -0
  105. package/dist/template/js/help.js.map +1 -0
  106. package/dist/template/js/panel.d.ts +1 -0
  107. package/dist/template/js/panel.js +84 -0
  108. package/dist/template/js/panel.js.map +1 -0
  109. package/dist/template/js/project.d.ts +1 -0
  110. package/dist/template/js/project.js +40 -0
  111. package/dist/template/js/project.js.map +1 -0
  112. package/dist/template/js/run.d.ts +1 -0
  113. package/dist/template/js/run.js +38 -0
  114. package/dist/template/js/run.js.map +1 -0
  115. package/dist/template/js/tests.d.ts +1 -0
  116. package/dist/template/js/tests.js +23 -0
  117. package/dist/template/js/tests.js.map +1 -0
  118. package/dist/template/js/trends.d.ts +1 -0
  119. package/dist/template/js/trends.js +57 -0
  120. package/dist/template/js/trends.js.map +1 -0
  121. package/dist/template/tokens.d.ts +45 -0
  122. package/dist/template/tokens.js +12 -0
  123. package/dist/template/tokens.js.map +1 -0
  124. package/dist/template.d.ts +2 -0
  125. package/dist/template.js +19 -0
  126. package/dist/template.js.map +1 -0
  127. package/dist/version.d.ts +1 -0
  128. package/dist/version.js +2 -0
  129. package/dist/version.js.map +1 -0
  130. package/package.json +63 -0
@@ -0,0 +1,12 @@
1
+ export { LogbookReporter as default, LogbookReporter } from './reporter.js';
2
+ export { shardFileSchema, runRecordSchema, runSummaryRecordSchema, testRecordSchema, stepRecordSchema, SCHEMA_VERSION } from './schema.js';
3
+ export type { ShardFile, RunRecord, RunSummaryRecord, TestRecord, ErrorRecord, StepRecord } from './schema.js';
4
+ export { mergeShards } from './merge.js';
5
+ export { FileHistoryStore, FileShardSink } from './store.js';
6
+ export type { HistoryStore, ShardSink } from './store.js';
7
+ export { computeFlaky, compareRuns, previousRun } from './history.js';
8
+ export { renderReport } from './render.js';
9
+ export { buildReportModel, renderTextSummary, renderMarkdownSummary, buildJsonSummary } from './model.js';
10
+ export type { ReportModel, ReportTest } from './model.js';
11
+ export { VERSION } from './version.js';
12
+ export type { Publisher, PublishContext, PublishResult } from './publish.js';
package/dist/index.js ADDED
@@ -0,0 +1,9 @@
1
+ export { LogbookReporter as default, LogbookReporter } from './reporter.js';
2
+ export { shardFileSchema, runRecordSchema, runSummaryRecordSchema, testRecordSchema, stepRecordSchema, SCHEMA_VERSION } from './schema.js';
3
+ export { mergeShards } from './merge.js';
4
+ export { FileHistoryStore, FileShardSink } from './store.js';
5
+ export { computeFlaky, compareRuns, previousRun } from './history.js';
6
+ export { renderReport } from './render.js';
7
+ export { buildReportModel, renderTextSummary, renderMarkdownSummary, buildJsonSummary } from './model.js';
8
+ export { VERSION } from './version.js';
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,IAAI,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAC5E,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE3I,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE7D,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AACtE,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAE1G,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { RunRecord, ShardFile } from './schema.js';
2
+ /** Merge shard files into a deterministic run record. */
3
+ export declare function mergeShards(shards: ShardFile[], opts?: {
4
+ force?: boolean;
5
+ outputDir?: string;
6
+ }): {
7
+ run: RunRecord;
8
+ warnings: string[];
9
+ };
package/dist/merge.js ADDED
@@ -0,0 +1,64 @@
1
+ import { LogbookError } from './errors.js';
2
+ const compare = (a, b) => a < b ? -1 : a > b ? 1 : 0;
3
+ const numberOf = (shard) => shard.shard?.current ?? 1;
4
+ const totalOf = (shard) => shard.shard?.total ?? 1;
5
+ const testOrder = (a, b) => compare(a.file, b.file) || a.line - b.line || compare(a.project, b.project) || compare(a.testId, b.testId);
6
+ function selectedShards(input, force, warnings) {
7
+ const byNumber = new Map();
8
+ for (const shard of [...input].sort((a, b) => numberOf(a) - numberOf(b) || compare(a.endedAt, b.endedAt) || compare(a.runId, b.runId))) {
9
+ const previous = byNumber.get(numberOf(shard));
10
+ if (previous && !force)
11
+ throw new LogbookError('DUPLICATE_SHARD', `duplicate shard ${numberOf(shard)}`);
12
+ if (previous)
13
+ warnings.push(`duplicate shard ${numberOf(shard)}; kept latest`);
14
+ byNumber.set(numberOf(shard), shard);
15
+ }
16
+ return [...byNumber.values()].sort((a, b) => numberOf(a) - numberOf(b));
17
+ }
18
+ function mergedTests(shards, warnings) {
19
+ const seen = new Set();
20
+ const tests = [];
21
+ for (const shard of shards)
22
+ for (const test of shard.tests) {
23
+ const key = `${test.testId}#${test.repeatEachIndex}`;
24
+ if (seen.has(key)) {
25
+ warnings.push(`duplicate test ${key}; kept first`);
26
+ continue;
27
+ }
28
+ seen.add(key);
29
+ tests.push(test);
30
+ }
31
+ return tests.sort(testOrder);
32
+ }
33
+ /** Merge shard files into a deterministic run record. */
34
+ export function mergeShards(shards, opts = {}) {
35
+ if (shards.length === 0)
36
+ throw new LogbookError('NO_DATA', 'no shards to merge');
37
+ const force = opts.force ?? false;
38
+ const warnings = [];
39
+ const total = totalOf(shards[0]);
40
+ if (shards.some((shard) => totalOf(shard) !== total))
41
+ throw new LogbookError('SHARD_MISMATCH', 'shard totals differ');
42
+ const newest = [...shards].sort((a, b) => compare(b.endedAt, a.endedAt) || compare(a.runId, b.runId))[0];
43
+ const runId = newest.runId;
44
+ if (shards.some((shard) => shard.runId !== runId)) {
45
+ if (!force)
46
+ throw new LogbookError('SHARD_MISMATCH', 'shard run IDs differ');
47
+ warnings.push(`shard run IDs differ; used ${runId}`);
48
+ }
49
+ const selected = selectedShards(shards, force, warnings);
50
+ const tests = mergedTests(selected, warnings);
51
+ const first = selected[0];
52
+ const startedAt = [...selected].map((shard) => shard.startedAt).sort(compare)[0];
53
+ const endedAt = [...selected].map((shard) => shard.endedAt).sort(compare).at(-1);
54
+ const summary = { total: tests.length, passed: tests.filter((test) => test.outcome === 'expected').length, failed: tests.filter((test) => test.outcome === 'unexpected').length, flaky: tests.filter((test) => test.outcome === 'flaky').length, skipped: tests.filter((test) => test.outcome === 'skipped').length };
55
+ const status = selected.some((shard) => shard.status === 'interrupted') ? 'interrupted' : selected.some((shard) => shard.status === 'timedout') ? 'timedout' : selected.some((shard) => shard.status === 'failed') || summary.failed > 0 ? 'failed' : 'passed';
56
+ const errors = new Map();
57
+ for (const shard of selected)
58
+ for (const error of shard.globalErrors)
59
+ if (!errors.has(error.message))
60
+ errors.set(error.message, error);
61
+ const receivedShards = selected.map(numberOf);
62
+ return { run: { schemaVersion: 1, kind: 'run', runId, title: first.title, startedAt, endedAt, durationMs: new Date(endedAt).getTime() - new Date(startedAt).getTime(), status, complete: receivedShards.length === total, expectedShards: total, receivedShards, env: first.env, project: first.project, paths: { outputDir: opts.outputDir ?? '.logbook' }, summary, tests, globalErrors: [...errors.values()] }, warnings };
63
+ }
64
+ //# sourceMappingURL=merge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merge.js","sourceRoot":"","sources":["../src/merge.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,98 @@
1
+ import type { Comparison, FlakyEntry } from './history.js';
2
+ import type { RunRecord, RunSummaryRecord, TestRecord } from './schema.js';
3
+ import type { ArtifactAvailability } from './artifacts.js';
4
+ export type ReportTest = TestRecord & {
5
+ timing: {
6
+ startedAt: string;
7
+ workerIndex: number;
8
+ } | null;
9
+ };
10
+ export interface ReportModel {
11
+ schemaVersion: 1;
12
+ generator: {
13
+ name: 'playwright-logbook';
14
+ version: string;
15
+ };
16
+ summaryMarkdown: string;
17
+ generatedAt: string | null;
18
+ attachmentAvailability?: ArtifactAvailability;
19
+ run: Omit<RunRecord, 'tests'> & {
20
+ tests: ReportTest[];
21
+ };
22
+ history: RunSummaryRecord[];
23
+ previous: RunSummaryRecord | null;
24
+ comparison: Comparison | null;
25
+ flaky: FlakyEntry[];
26
+ slowest: {
27
+ testId: string;
28
+ title: string;
29
+ file: string;
30
+ project: string;
31
+ durationMs: number;
32
+ }[];
33
+ files: {
34
+ file: string;
35
+ total: number;
36
+ failed: number;
37
+ flaky: number;
38
+ skipped: number;
39
+ durationMs: number;
40
+ }[];
41
+ tags: {
42
+ tag: string;
43
+ count: number;
44
+ }[];
45
+ delta: {
46
+ previousRunId: string;
47
+ passRatePp: number | null;
48
+ failed: number;
49
+ flaky: number;
50
+ durationPct: number | null;
51
+ } | null;
52
+ errorGroups: {
53
+ signature: string;
54
+ count: number;
55
+ projects: string[];
56
+ testIds: string[];
57
+ newCount: number;
58
+ }[];
59
+ recent: Record<string, string>;
60
+ projects: {
61
+ name: string;
62
+ total: number;
63
+ passed: number;
64
+ failed: number;
65
+ flaky: number;
66
+ skipped: number;
67
+ durationMs: number;
68
+ }[];
69
+ }
70
+ export declare function errorSignature(message: string | null): string;
71
+ /** Build compact, sorted report data from a stored run and its history. */
72
+ export declare function buildReportModel(input: {
73
+ run: RunRecord;
74
+ summaries: RunSummaryRecord[];
75
+ previous?: RunSummaryRecord | null;
76
+ flaky?: FlakyEntry[];
77
+ comparison?: Comparison | null;
78
+ generatedAt?: string | null;
79
+ historyLimit?: number;
80
+ recentRuns?: RunRecord[];
81
+ attachmentAvailability?: ArtifactAvailability;
82
+ }): ReportModel;
83
+ /** Format a duration for human-readable summaries. */
84
+ export declare function formatDuration(milliseconds: number): string;
85
+ /** Render a plain-text run summary. */
86
+ export declare function renderTextSummary(model: ReportModel): string;
87
+ /** Render a portable Markdown summary for CI systems. */
88
+ export declare function renderMarkdownSummary(model: ReportModel): string;
89
+ /** Build the concise JSON summary returned by the CLI. */
90
+ export declare function buildJsonSummary(model: ReportModel): {
91
+ runId: string;
92
+ status: RunRecord['status'];
93
+ complete: boolean;
94
+ summary: RunRecord['summary'];
95
+ durationMs: number;
96
+ comparison: Record<keyof Comparison, number>;
97
+ flaky: number;
98
+ };
package/dist/model.js ADDED
@@ -0,0 +1,129 @@
1
+ import { testResultKind } from './history.js';
2
+ import { VERSION } from './version.js';
3
+ const compare = (a, b) => a < b ? -1 : a > b ? 1 : 0;
4
+ export function errorSignature(message) {
5
+ if (!message?.trim())
6
+ return 'No error message';
7
+ const line = message.split(/\r?\n/).find((part) => part.trim()) ?? '';
8
+ return line.replace(/"[^"]*"|'[^']*'|`[^`]*`/g, '"…"')
9
+ .replace(/\b(?:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}|0x[0-9a-f]+|[0-9a-f]{8,})\b/gi, 'ID')
10
+ .replace(/\d+/g, 'N').replace(/\bNms\b/g, 'N ms').replace(/\s+/g, ' ').trim().slice(0, 140);
11
+ }
12
+ function currentSummary(run) {
13
+ return { schemaVersion: 1, runId: run.runId, title: run.title, startedAt: run.startedAt, durationMs: run.durationMs, status: run.status, complete: run.complete, summary: run.summary, branch: run.env.git.branch, commit: run.env.git.commit, ciProvider: run.env.ci?.provider ?? null, buildUrl: run.env.ci?.buildUrl ?? null };
14
+ }
15
+ function slim(test) {
16
+ return test.outcome === 'expected' && test.attemptCount === 1 && test.attempts[0]?.errors.length === 0 && test.attempts[0].attachments.length === 0 && !test.attempts[0].steps?.length && !test.attempts[0].stdout && !test.attempts[0].stderr
17
+ ? { ...test, attempts: [] } : test;
18
+ }
19
+ /** Build compact, sorted report data from a stored run and its history. */
20
+ export function buildReportModel(input) {
21
+ const { run } = input;
22
+ const all = new Map(input.summaries.map((entry) => [entry.runId, entry]));
23
+ all.set(run.runId, currentSummary(run));
24
+ const newest = [...all.values()].sort((a, b) => compare(b.startedAt, a.startedAt) || compare(a.runId, b.runId));
25
+ const historyLimit = Math.max(1, input.historyLimit ?? 30);
26
+ const selected = newest.slice(0, historyLimit);
27
+ if (!selected.some((item) => item.runId === run.runId))
28
+ selected.splice(-1, 1, currentSummary(run));
29
+ const history = selected.sort((a, b) => compare(a.startedAt, b.startedAt) || compare(a.runId, b.runId));
30
+ const files = new Map();
31
+ const tags = new Map();
32
+ const projects = new Map();
33
+ const groups = new Map();
34
+ const newIds = new Set(input.comparison?.newFailures.map((item) => item.testId) ?? []);
35
+ for (const test of run.tests) {
36
+ const item = files.get(test.file) ?? { file: test.file, total: 0, failed: 0, flaky: 0, skipped: 0, durationMs: 0 };
37
+ item.total += 1;
38
+ item.durationMs += test.durationMs;
39
+ if (test.outcome === 'unexpected')
40
+ item.failed += 1;
41
+ if (test.outcome === 'flaky')
42
+ item.flaky += 1;
43
+ if (test.outcome === 'skipped')
44
+ item.skipped += 1;
45
+ files.set(test.file, item);
46
+ for (const tag of test.tags)
47
+ tags.set(tag, (tags.get(tag) ?? 0) + 1);
48
+ const project = projects.get(test.project) ?? { name: test.project, total: 0, passed: 0, failed: 0, flaky: 0, skipped: 0, durationMs: 0 };
49
+ project.total += 1;
50
+ project.durationMs += test.durationMs;
51
+ if (test.outcome === 'expected')
52
+ project.passed += 1;
53
+ if (test.outcome === 'unexpected')
54
+ project.failed += 1;
55
+ if (test.outcome === 'flaky')
56
+ project.flaky += 1;
57
+ if (test.outcome === 'skipped')
58
+ project.skipped += 1;
59
+ projects.set(test.project, project);
60
+ if (test.outcome === 'unexpected' || test.outcome === 'flaky') {
61
+ const signature = errorSignature(test.firstError?.message ?? null);
62
+ const group = groups.get(signature) ?? { signature, count: 0, projects: new Set(), testIds: [], newCount: 0 };
63
+ group.count += 1;
64
+ group.projects.add(test.project);
65
+ group.testIds.push(test.testId);
66
+ if (newIds.has(test.testId))
67
+ group.newCount += 1;
68
+ groups.set(signature, group);
69
+ }
70
+ }
71
+ const previous = input.previous ?? null;
72
+ const passRate = (summary) => summary.total ? summary.passed / summary.total : null;
73
+ const currentRate = passRate(run.summary), previousRate = previous && passRate(previous.summary);
74
+ const delta = previous ? { previousRunId: previous.runId, passRatePp: currentRate === null || previousRate === null ? null : Math.round((currentRate - previousRate) * 1000) / 10, failed: run.summary.failed - previous.summary.failed, flaky: run.summary.flaky - previous.summary.flaky, durationPct: previous.durationMs ? Math.round((run.durationMs - previous.durationMs) / previous.durationMs * 100) : null } : null;
75
+ const older = (input.recentRuns ?? []).filter((item) => item.runId !== run.runId).slice(-10);
76
+ const olderTests = older.map((item) => new Map(item.tests.map((test) => [test.testId, test])));
77
+ const recent = {};
78
+ for (const test of [...run.tests].sort((a, b) => compare(a.testId, b.testId)))
79
+ recent[test.testId] = olderTests.map((tests) => {
80
+ const prior = tests.get(test.testId);
81
+ return prior ? ({ pass: 'p', fail: 'f', flaky: 'k', skip: 's' })[testResultKind(prior)] : '-';
82
+ }).join('');
83
+ const model = { schemaVersion: 1, generator: { name: 'playwright-logbook', version: VERSION }, summaryMarkdown: '', generatedAt: input.generatedAt ?? null, ...(input.attachmentAvailability ? { attachmentAvailability: input.attachmentAvailability } : {}), run: { ...run, tests: run.tests.map((test) => ({ ...slim(test), timing: test.attempts[0] ? { startedAt: test.attempts[0].startedAt, workerIndex: test.attempts[0].workerIndex } : null })) }, history, previous, comparison: input.comparison ?? null, flaky: (input.flaky ?? []).slice(0, 50), slowest: [...run.tests].sort((a, b) => b.durationMs - a.durationMs || compare(a.testId, b.testId)).slice(0, 10).map(({ testId, title, file, project, durationMs }) => ({ testId, title, file, project, durationMs })), files: [...files.values()].sort((a, b) => compare(a.file, b.file)), tags: [...tags].map(([tag, count]) => ({ tag, count })).sort((a, b) => b.count - a.count || compare(a.tag, b.tag)), delta, errorGroups: [...groups.values()].map((group) => ({ ...group, projects: [...group.projects].sort(compare), testIds: group.testIds.sort(compare) })).sort((a, b) => b.count - a.count || compare(a.signature, b.signature)), recent, projects: [...projects.values()].sort((a, b) => compare(a.name, b.name)) };
84
+ model.summaryMarkdown = renderMarkdownSummary(model);
85
+ return model;
86
+ }
87
+ /** Format a duration for human-readable summaries. */
88
+ export function formatDuration(milliseconds) {
89
+ if (milliseconds < 1000)
90
+ return `${Math.round(milliseconds)}ms`;
91
+ if (milliseconds < 60000)
92
+ return `${(milliseconds / 1000).toFixed(1)}s`;
93
+ return `${Math.floor(milliseconds / 60000)}m ${Math.floor((milliseconds % 60000) / 1000)}s`;
94
+ }
95
+ const status = (model) => `${model.run.status.toUpperCase()}${model.run.complete ? '' : ` (INCOMPLETE: received shards ${model.run.receivedShards.join(',')} of ${model.run.expectedShards ?? '?'})`}`;
96
+ /** Render a plain-text run summary. */
97
+ export function renderTextSummary(model) {
98
+ const { run } = model;
99
+ return `${run.runId}: ${status(model)} — ${run.summary.passed} passed, ${run.summary.failed} failed, ${run.summary.flaky} flaky, ${run.summary.skipped} skipped (${formatDuration(run.durationMs)})\n`;
100
+ }
101
+ /** Render a portable Markdown summary for CI systems. */
102
+ export function renderMarkdownSummary(model) {
103
+ const { run } = model;
104
+ const lines = [`### Playwright run ${run.runId} — ${status(model)}`, '| Total | Passed | Failed | Flaky | Skipped | Duration |', '|---|---|---|---|---|---|', `| ${run.summary.total} | ${run.summary.passed} | ${run.summary.failed} | ${run.summary.flaky} | ${run.summary.skipped} | ${formatDuration(run.durationMs)} |`];
105
+ if (model.comparison?.newFailures.length) {
106
+ lines.push('', `**New failures (${model.comparison.newFailures.length})**`);
107
+ for (const item of model.comparison.newFailures)
108
+ lines.push(`- \`${item.file}\` › ${item.title} [${item.project}]`);
109
+ }
110
+ const flaky = run.tests.filter((test) => test.outcome === 'flaky');
111
+ if (flaky.length) {
112
+ lines.push('', `**Flaky in this run (${flaky.length})**`);
113
+ for (const item of flaky)
114
+ lines.push(`- \`${item.file}\` › ${item.title} [${item.project}]`);
115
+ }
116
+ let footer = `**Run**: ${run.env.ci?.buildUrl ?? run.runId}`;
117
+ if (run.env.git.branch)
118
+ footer += ` · branch ${run.env.git.branch}`;
119
+ if (run.env.git.commit)
120
+ footer += ` · commit ${run.env.git.commit.slice(0, 7)}`;
121
+ lines.push('', footer);
122
+ return `${lines.join('\n')}\n`;
123
+ }
124
+ /** Build the concise JSON summary returned by the CLI. */
125
+ export function buildJsonSummary(model) {
126
+ const counts = model.comparison;
127
+ return { runId: model.run.runId, status: model.run.status, complete: model.run.complete, summary: model.run.summary, durationMs: model.run.durationMs, comparison: { newFailures: counts?.newFailures.length ?? 0, fixed: counts?.fixed.length ?? 0, stillFailing: counts?.stillFailing.length ?? 0, newTests: counts?.newTests.length ?? 0, removedTests: counts?.removedTests.length ?? 0 }, flaky: model.flaky.length };
128
+ }
129
+ //# sourceMappingURL=model.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model.js","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ export interface LogbookOptions {
2
+ outputDir?: string;
3
+ runId?: string;
4
+ title?: string;
5
+ redact?: (string | RegExp)[];
6
+ autoMerge?: boolean;
7
+ autoReport?: boolean;
8
+ historyLimit?: number;
9
+ maxTextLength?: number;
10
+ caseIdPatterns?: string[];
11
+ quiet?: boolean;
12
+ captureDetails?: boolean | {
13
+ steps?: boolean;
14
+ output?: boolean;
15
+ images?: boolean;
16
+ };
17
+ maxSteps?: number;
18
+ maxOutputLength?: number;
19
+ maxImageBytes?: number;
20
+ maxEmbeddedBytes?: number;
21
+ }
22
+ /** Resolve reporter options with deterministic defaults. */
23
+ export declare function resolveOptions(options?: LogbookOptions): Required<Pick<LogbookOptions, 'outputDir' | 'autoMerge' | 'autoReport' | 'quiet' | 'historyLimit' | 'maxTextLength'>> & LogbookOptions;
@@ -0,0 +1,5 @@
1
+ /** Resolve reporter options with deterministic defaults. */
2
+ export function resolveOptions(options = {}) {
3
+ return { outputDir: '.logbook', autoMerge: true, autoReport: true, historyLimit: 30, maxTextLength: 4000, quiet: false, captureDetails: false, maxSteps: 100, maxOutputLength: 2000, maxImageBytes: 250000, maxEmbeddedBytes: 5000000, ...options };
4
+ }
5
+ //# sourceMappingURL=options.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"options.js","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":"AAkBA,4DAA4D;AAC5D,MAAM,UAAU,cAAc,CAAC,UAA0B,EAAE;IACzD,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,YAAY,EAAE,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,cAAc,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,eAAe,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,gBAAgB,EAAE,OAAO,EAAE,GAAG,OAAO,EAAE,CAAC;AACtP,CAAC"}
@@ -0,0 +1,6 @@
1
+ /** Convert a platform path to a POSIX path. */
2
+ export declare function posixPath(value: string): string;
3
+ /** Return a path relative to the project root using POSIX separators. */
4
+ export declare function toRel(projectRoot: string, value: string): string;
5
+ /** Return a relative attachment path, or null when it is outside the project root. */
6
+ export declare function toRelOrNull(projectRoot: string, value: string): string | null;
package/dist/paths.js ADDED
@@ -0,0 +1,17 @@
1
+ import path from 'node:path';
2
+ /** Convert a platform path to a POSIX path. */
3
+ export function posixPath(value) { return value.split(path.sep).join('/'); }
4
+ function pathModule(...values) {
5
+ return values.some((value) => /^[A-Za-z]:[\\/]/.test(value) || value.includes('\\')) ? path.win32 : path.posix;
6
+ }
7
+ /** Return a path relative to the project root using POSIX separators. */
8
+ export function toRel(projectRoot, value) {
9
+ return pathModule(projectRoot, value).relative(projectRoot, value).replaceAll('\\', '/');
10
+ }
11
+ /** Return a relative attachment path, or null when it is outside the project root. */
12
+ export function toRelOrNull(projectRoot, value) {
13
+ const api = pathModule(projectRoot, value);
14
+ const relative = api.relative(projectRoot, value);
15
+ return relative === '' || (!relative.startsWith('..') && !api.isAbsolute(relative)) ? relative.replaceAll('\\', '/') : null;
16
+ }
17
+ //# sourceMappingURL=paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,+CAA+C;AAC/C,MAAM,UAAU,SAAS,CAAC,KAAa,IAAY,OAAO,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAE5F,SAAS,UAAU,CAAC,GAAG,MAAgB;IACrC,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,iBAAiB,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC;AACjH,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,KAAK,CAAC,WAAmB,EAAE,KAAa;IACtD,OAAO,UAAU,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,QAAQ,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;AAC3F,CAAC;AAED,sFAAsF;AACtF,MAAM,UAAU,WAAW,CAAC,WAAmB,EAAE,KAAa;IAC5D,MAAM,GAAG,GAAG,UAAU,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;IAC3C,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;IAClD,OAAO,QAAQ,KAAK,EAAE,IAAI,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAC9H,CAAC"}
@@ -0,0 +1,14 @@
1
+ import type { RunRecord } from './schema.js';
2
+ export interface PublishContext {
3
+ run: RunRecord;
4
+ dryRun: boolean;
5
+ }
6
+ export interface PublishResult {
7
+ published: number;
8
+ skipped: number;
9
+ errors: string[];
10
+ }
11
+ export interface Publisher {
12
+ name: string;
13
+ publish(ctx: PublishContext): Promise<PublishResult>;
14
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=publish.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publish.js","sourceRoot":"","sources":["../src/publish.ts"],"names":[],"mappings":""}
@@ -0,0 +1,6 @@
1
+ import type { ReportModel } from './model.js';
2
+ /** Render a self-contained, offline HTML report. */
3
+ export declare function renderReport(model: ReportModel, options?: {
4
+ title?: string;
5
+ reportDir?: string;
6
+ }): string;
package/dist/render.js ADDED
@@ -0,0 +1,50 @@
1
+ import path from 'node:path';
2
+ import { donutSegments, formatDuration, safeHref } from './clientlib.js';
3
+ import { buildClientScript, buildStyles } from './template.js';
4
+ const escapeHtml = (value) => value.replaceAll('&', '&amp;').replaceAll('<', '&lt;').replaceAll('>', '&gt;').replaceAll('"', '&quot;').replaceAll("'", '&#39;');
5
+ const safeJson = (value) => JSON.stringify(value).replaceAll('<', '\\u003c').replaceAll('>', '\\u003e').replaceAll('&', '\\u0026').replaceAll('\u2028', '\\u2028').replaceAll('\u2029', '\\u2029');
6
+ const tabs = ['tests', 'failures', 'trends', 'flaky', 'run', 'project'];
7
+ function attachmentLinks(model, reportDir) {
8
+ const links = {};
9
+ for (const test of model.run.tests)
10
+ for (const attempt of test.attempts)
11
+ for (const attachment of attempt.attachments) {
12
+ const file = attachment.path;
13
+ if (file && model.attachmentAvailability?.[file] !== 'missing' && !path.posix.isAbsolute(file) && !file.split('/').includes('..') && !file.includes('\\') && !file.includes(':'))
14
+ links[file] = path.posix.relative(reportDir, file);
15
+ }
16
+ return links;
17
+ }
18
+ function donut(model) {
19
+ const summary = model.run.summary;
20
+ const rate = summary.total ? `${Math.round(summary.passed / summary.total * 100)}%` : '—';
21
+ const arcs = donutSegments(summary, 54).map((item) => `<circle class="donut-segment ${item.kind}" cx="72" cy="72" r="54" fill="none" stroke-width="15" stroke-dasharray="${item.dasharray}" stroke-dashoffset="${item.offset}" transform="rotate(-90 72 72)"/>`).join('');
22
+ return `<svg class="donut" viewBox="0 0 144 144" role="img" aria-label="${escapeHtml(rate)} passed"><circle class="donut-track" cx="72" cy="72" r="54" fill="none" stroke-width="15"/>${arcs}<text class="donut-center" x="72" y="72" text-anchor="middle">${rate}</text><text class="donut-label" x="72" y="88" text-anchor="middle">passed</text></svg>`;
23
+ }
24
+ function comparison(model) {
25
+ const delta = model.delta;
26
+ if (!delta)
27
+ return '<section class="comparison comparison-empty" aria-label="Run comparison"><div><h2>Run comparison</h2><p>No earlier run to compare yet. Changes will appear here after the next run.</p></div></section>';
28
+ const signed = (value, suffix = '') => `${value > 0 ? '+' : ''}${value}${suffix}`;
29
+ const metric = (label, value) => `<div class="comparison-metric"><span>${label}</span><strong>${escapeHtml(value)}</strong></div>`;
30
+ const newFailures = model.comparison?.newFailures.length ?? 0;
31
+ return `<section class="comparison" aria-label="Changes since previous run"><div class="comparison-head"><div><h2>Changes since previous run</h2><p>Compared with <code>${escapeHtml(delta.previousRunId)}</code> · signed values are net changes</p></div>${newFailures ? '<button id="lb-new-failures" class="button" type="button">View new failures</button>' : ''}</div><div class="comparison-grid">${metric('Pass rate change', delta.passRatePp === null ? '—' : signed(delta.passRatePp, ' pp'))}${metric('Failed change', signed(delta.failed))}${metric('Flaky change', signed(delta.flaky))}${metric('Duration change', delta.durationPct === null ? '—' : signed(delta.durationPct, '%'))}${metric('New failures', String(newFailures))}</div></section>`;
32
+ }
33
+ /** Render a self-contained, offline HTML report. */
34
+ export function renderReport(model, options = {}) {
35
+ const run = model.run;
36
+ const title = options.title ?? run.title ?? 'Playwright Logbook';
37
+ const reportDir = options.reportDir ?? path.posix.join(run.paths.outputDir, 'report');
38
+ const cards = ['total', 'passed', 'failed', 'flaky', 'skipped'].map((kind) => `<button type="button" class="card" data-card-kind="${kind}">${kind[0].toUpperCase()}${kind.slice(1)}<strong>${run.summary[kind]}</strong></button>`).join('');
39
+ const tabButtons = tabs.map((tab) => `<button type="button" role="tab" data-tab="${tab}" aria-controls="tab-${tab}" aria-selected="false">${tab[0].toUpperCase()}${tab.slice(1)}</button>`).join('');
40
+ const panels = tabs.map((tab) => `<section class="panel" id="tab-${tab}" role="tabpanel" hidden></section>`).join('');
41
+ const missing = Array.from({ length: run.expectedShards ?? 1 }, (_, index) => index + 1).filter((number) => !run.receivedShards.includes(number));
42
+ const banner = run.complete ? '' : `<p class="banner">INCOMPLETE run · missing shards ${missing.join(', ')}</p>`;
43
+ const projectName = run.project.name || 'Unnamed project';
44
+ const meta = [run.env.git.branch && `Branch: ${run.env.git.branch}`, run.env.git.commit && `Commit: ${run.env.git.commit.slice(0, 7)}`, run.env.git.prNumber && `PR #${run.env.git.prNumber}`, `Shards: ${run.receivedShards.length}/${run.expectedShards ?? 1}`, `Playwright: ${run.env.playwrightVersion}`, `Workers: ${run.env.workers}`].filter(Boolean).map((item) => `<span>${escapeHtml(String(item))}</span>`).join('');
45
+ const buildUrl = run.env.ci?.buildUrl;
46
+ const buildLink = buildUrl && /^https?:\/\//i.test(buildUrl) && safeHref(buildUrl) ? `<a href="${escapeHtml(buildUrl)}" rel="noopener noreferrer">CI build</a>` : '';
47
+ const footer = `${model.generatedAt ? `Generated ${escapeHtml(model.generatedAt)} · ` : ''}playwright-logbook v${escapeHtml(model.generator?.version ?? '0.1.0')} · Press ? for shortcuts`;
48
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>${escapeHtml(title)}</title><style>${buildStyles()}</style></head><body><a class="skip-link" href="#tab-tests">Skip to results</a><div class="topbar"><div class="topbar-inner"><span class="wordmark">▤ logbook</span><span class="topbar-title">${escapeHtml(projectName)}</span><span class="status-chip ${run.status === 'passed' ? 'passed' : 'failed'}">${escapeHtml(run.status.toUpperCase())}</span><div class="topbar-actions"><button id="lb-theme" type="button">Dark mode</button><button id="lb-copy-summary" class="optional" type="button">Copy summary</button><button id="lb-download" class="optional" type="button">Download JSON</button><button id="lb-print" class="optional" type="button">Print</button><button id="lb-help" type="button" aria-label="Help">?</button></div></div></div><main class="container"><header id="lb-header" class="hero">${donut(model)}<div class="hero-main"><p class="eyebrow">Project <strong>${escapeHtml(projectName)}</strong></p><h1>${escapeHtml(title)}</h1><dl class="run-facts"><div><dt>Run ID</dt><dd title="${escapeHtml(run.runId)}">${escapeHtml(run.runId)}</dd></div><div><dt>Started</dt><dd><time datetime="${escapeHtml(run.startedAt)}" title="${escapeHtml(run.startedAt)}">${escapeHtml(run.startedAt)}</time></dd></div><div><dt>Duration</dt><dd>${formatDuration(run.durationMs)}</dd></div></dl><details class="env-disclosure"><summary>Environment details</summary><div class="meta">${meta}${buildLink}</div></details></div></header>${banner}<div id="lb-cards" class="cards">${cards}</div>${comparison(model)}<p id="lb-error" class="error-banner" hidden></p><nav class="tabs" role="tablist" aria-label="Report sections">${tabButtons}</nav>${panels}<footer>${footer}</footer></main><div id="lb-backdrop" class="panel-backdrop" hidden></div><aside id="lb-panel" class="detail-panel" aria-label="Test details" hidden><div class="panel-head"><h2 id="lb-panel-heading" tabindex="-1"></h2><button id="lb-panel-close" type="button" aria-label="Close details">Close</button></div><div id="lb-panel-content"></div></aside><div id="lb-toast" class="toast" role="status" aria-live="polite" hidden></div><dialog id="lb-help-dialog" class="help-dialog"></dialog><dialog id="lb-lightbox" class="lightbox"></dialog><noscript>Enable JavaScript to explore tests and report details.</noscript><script type="application/json" id="lb-data">${safeJson(model)}</script><script type="application/json" id="lb-links">${safeJson(attachmentLinks(model, reportDir))}</script><script>${buildClientScript()}</script></body></html>`;
49
+ }
50
+ //# sourceMappingURL=render.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render.js","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ import fs from 'node:fs/promises';
2
+ import type { PwConfig, PwError, PwResult, PwTest } from './collect.js';
3
+ import type { DetectEnvOptions } from './env.js';
4
+ import type { LogbookOptions } from './options.js';
5
+ import type { ShardSink } from './store.js';
6
+ import type { HistoryStore } from './store.js';
7
+ interface ReporterSuite {
8
+ allTests(): PwTest[];
9
+ }
10
+ interface FullResult {
11
+ status: 'passed' | 'failed' | 'timedout' | 'interrupted';
12
+ startTime?: Date;
13
+ duration?: number;
14
+ }
15
+ export interface ReporterDeps extends Pick<DetectEnvOptions, 'env' | 'exec' | 'clock' | 'random'> {
16
+ cwd?: () => string;
17
+ stderr?: (line: string) => void;
18
+ fs?: Pick<typeof fs, 'mkdir' | 'writeFile' | 'rename'> & Partial<Pick<typeof fs, 'readFile' | 'stat' | 'realpath'>>;
19
+ sink?: ShardSink;
20
+ historyStore?: HistoryStore;
21
+ }
22
+ /** Playwright reporter that writes a durable shard without changing the test result. */
23
+ export declare class LogbookReporter {
24
+ private readonly options;
25
+ private readonly deps;
26
+ private config;
27
+ private suite;
28
+ private startedAt;
29
+ private detected;
30
+ private root;
31
+ private globalErrors;
32
+ private warned;
33
+ private readonly stepsByResult;
34
+ constructor(options?: LogbookOptions, deps?: ReporterDeps);
35
+ printsToStdio(): boolean;
36
+ private write;
37
+ private warning;
38
+ onBegin(config: PwConfig, suite: ReporterSuite): void;
39
+ onError(error: PwError): void;
40
+ onStepEnd(_test: PwTest, result: PwResult, step: {
41
+ title: string;
42
+ category: string;
43
+ duration: number;
44
+ error?: unknown;
45
+ parent?: {
46
+ parent?: unknown;
47
+ } | null;
48
+ }): void;
49
+ private captureImages;
50
+ private saveReport;
51
+ onEnd(result: FullResult): Promise<void>;
52
+ }
53
+ export {};