@muuktest/amikoo-playwright 2.0.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 (70) hide show
  1. package/README.md +26 -0
  2. package/dist/capture.cjs +57 -0
  3. package/dist/capture.cjs.map +1 -0
  4. package/dist/capture.d.cts +6 -0
  5. package/dist/capture.d.ts +6 -0
  6. package/dist/capture.js +23 -0
  7. package/dist/capture.js.map +1 -0
  8. package/dist/cli/agent-setup.cjs +68 -0
  9. package/dist/cli/agent-setup.cjs.map +1 -0
  10. package/dist/cli/agent-setup.d.cts +11 -0
  11. package/dist/cli/agent-setup.d.ts +11 -0
  12. package/dist/cli/agent-setup.js +31 -0
  13. package/dist/cli/agent-setup.js.map +1 -0
  14. package/dist/cli/amikoo-playwright-agent.md +82 -0
  15. package/dist/cli/fixture-creator.cjs +163 -0
  16. package/dist/cli/fixture-creator.cjs.map +1 -0
  17. package/dist/cli/fixture-creator.d.cts +12 -0
  18. package/dist/cli/fixture-creator.d.ts +12 -0
  19. package/dist/cli/fixture-creator.js +128 -0
  20. package/dist/cli/fixture-creator.js.map +1 -0
  21. package/dist/cli/index.cjs +134 -0
  22. package/dist/cli/index.cjs.map +1 -0
  23. package/dist/cli/index.d.cts +1 -0
  24. package/dist/cli/index.d.ts +1 -0
  25. package/dist/cli/index.js +111 -0
  26. package/dist/cli/index.js.map +1 -0
  27. package/dist/cli/mcp-setup.cjs +116 -0
  28. package/dist/cli/mcp-setup.cjs.map +1 -0
  29. package/dist/cli/mcp-setup.d.cts +12 -0
  30. package/dist/cli/mcp-setup.d.ts +12 -0
  31. package/dist/cli/mcp-setup.js +81 -0
  32. package/dist/cli/mcp-setup.js.map +1 -0
  33. package/dist/cli/scanner.cjs +137 -0
  34. package/dist/cli/scanner.cjs.map +1 -0
  35. package/dist/cli/scanner.d.cts +16 -0
  36. package/dist/cli/scanner.d.ts +16 -0
  37. package/dist/cli/scanner.js +100 -0
  38. package/dist/cli/scanner.js.map +1 -0
  39. package/dist/cli/test-updater.cjs +131 -0
  40. package/dist/cli/test-updater.cjs.map +1 -0
  41. package/dist/cli/test-updater.d.cts +12 -0
  42. package/dist/cli/test-updater.d.ts +12 -0
  43. package/dist/cli/test-updater.js +96 -0
  44. package/dist/cli/test-updater.js.map +1 -0
  45. package/dist/dom/buildDomTree.js +1760 -0
  46. package/dist/helpers/dom-extractor.cjs +344 -0
  47. package/dist/helpers/dom-extractor.cjs.map +1 -0
  48. package/dist/helpers/dom-extractor.d.cts +9 -0
  49. package/dist/helpers/dom-extractor.d.ts +9 -0
  50. package/dist/helpers/dom-extractor.js +318 -0
  51. package/dist/helpers/dom-extractor.js.map +1 -0
  52. package/dist/helpers/dom-service.cjs +365 -0
  53. package/dist/helpers/dom-service.cjs.map +1 -0
  54. package/dist/helpers/dom-service.d.cts +82 -0
  55. package/dist/helpers/dom-service.d.ts +82 -0
  56. package/dist/helpers/dom-service.js +338 -0
  57. package/dist/helpers/dom-service.js.map +1 -0
  58. package/dist/helpers/failure-analyzer.cjs +276 -0
  59. package/dist/helpers/failure-analyzer.cjs.map +1 -0
  60. package/dist/helpers/failure-analyzer.d.cts +100 -0
  61. package/dist/helpers/failure-analyzer.d.ts +100 -0
  62. package/dist/helpers/failure-analyzer.js +241 -0
  63. package/dist/helpers/failure-analyzer.js.map +1 -0
  64. package/dist/index.cjs +32 -0
  65. package/dist/index.cjs.map +1 -0
  66. package/dist/index.d.cts +3 -0
  67. package/dist/index.d.ts +3 -0
  68. package/dist/index.js +7 -0
  69. package/dist/index.js.map +1 -0
  70. package/package.json +51 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/helpers/failure-analyzer.ts"],"sourcesContent":["import fs from 'fs';\nimport path from 'path';\nimport type { Page, TestInfo } from '@playwright/test';\n\n// ─── Exported Interfaces ───────────────────────────────────────────────────\n\nexport interface ConsoleEntry {\n type: string;\n text: string;\n timestamp: string;\n location?: { url?: string; lineNumber?: number; columnNumber?: number };\n}\n\nexport interface NetworkFailure {\n url: string;\n method: string;\n status: number;\n statusText: string;\n resourceType: string;\n timestamp: string;\n}\n\nexport interface FailureSelector {\n raw: string;\n method: string;\n value: string;\n}\n\nexport interface ErrorCause {\n message: string;\n stack: string;\n}\n\nexport interface ErrorEntry {\n message: string;\n stack: string;\n pw_console: string | null;\n isTimeout: boolean;\n timeoutMs: number | null;\n causes: ErrorCause[];\n}\n\nexport interface FailureAnalysis {\n // Backward-compatible original 5 fields\n selector: string;\n action: string;\n error: string;\n location: string;\n context: string;\n\n // Enriched fields (v2+)\n test: {\n title: string;\n titlePath: string[];\n file: string;\n line: number | null;\n project: string;\n retries: number;\n retry: number;\n duration: number;\n status: string | undefined;\n expectedStatus: string;\n tags: string[];\n };\n page: {\n url: string;\n title: string | null;\n viewport: { width: number; height: number } | null;\n };\n selectorDetails: FailureSelector | null;\n consoleLogs: ConsoleEntry[];\n consoleErrors: ConsoleEntry[];\n networkFailures: NetworkFailure[];\n errorDetails: {\n message: string;\n stack: string;\n pw_console: string | null;\n isTimeout: boolean;\n timeoutMs: number | null;\n causes: ErrorCause[];\n };\n errors: ErrorEntry[];\n timing: {\n testStart: string;\n failureCapture: string;\n duration: number;\n };\n artifacts: {\n domJsonPath: string;\n screenshotPath: string;\n failureInfoPath: string;\n };\n _version: 3;\n}\n\n// ─── Page Listener Setup ───────────────────────────────────────────────────\n\nexport function setupPageListeners(page: Page): {\n consoleLogs: ConsoleEntry[];\n networkFailures: NetworkFailure[];\n} {\n const consoleLogs: ConsoleEntry[] = [];\n const networkFailures: NetworkFailure[] = [];\n const MAX_CONSOLE_ENTRIES = 500;\n\n page.on('console', (msg) => {\n if (consoleLogs.length >= MAX_CONSOLE_ENTRIES) return;\n const loc = msg.location();\n consoleLogs.push({\n type: msg.type(),\n text: msg.text(),\n timestamp: new Date().toISOString(),\n location: {\n url: loc.url,\n lineNumber: loc.lineNumber,\n columnNumber: loc.columnNumber,\n },\n });\n });\n\n page.on('pageerror', (err) => {\n if (consoleLogs.length >= MAX_CONSOLE_ENTRIES) return;\n consoleLogs.push({\n type: 'pageerror',\n text: err.message,\n timestamp: new Date().toISOString(),\n });\n });\n\n page.on('response', (response) => {\n if (response.status() >= 400) {\n networkFailures.push({\n url: response.url(),\n method: response.request().method(),\n status: response.status(),\n statusText: response.statusText(),\n resourceType: response.request().resourceType(),\n timestamp: new Date().toISOString(),\n });\n }\n });\n\n page.on('requestfailed', (request) => {\n networkFailures.push({\n url: request.url(),\n method: request.method(),\n status: 0,\n statusText: request.failure()?.errorText ?? 'Request failed',\n resourceType: request.resourceType(),\n timestamp: new Date().toISOString(),\n });\n });\n\n return { consoleLogs, networkFailures };\n}\n\n// ─── Failure Analysis ──────────────────────────────────────────────────────\n\nexport async function analyzeFailure(\n page: Page,\n testInfo: TestInfo,\n consoleLogs: ConsoleEntry[],\n networkFailures: NetworkFailure[],\n artifacts: { jsonPath: string; screenshotPath: string; failureInfoPath: string }\n): Promise<FailureAnalysis> {\n const error = (testInfo.error ?? testInfo.errors?.[0] ?? {}) as { message?: string; stack?: string };\n const errorMessage = error.message ?? '';\n const errorStack = error.stack ?? '';\n\n const now = new Date();\n const duration = testInfo.duration ?? 0;\n const testStart = new Date(now.getTime() - duration).toISOString();\n const failureCapture = now.toISOString();\n\n // Original 5 fields (backward compat)\n const selector = extractSelector(errorMessage);\n const action = extractAction(errorMessage);\n const errorFirstLine = errorMessage.split('\\n')[0];\n const location = extractLocation(errorStack, testInfo);\n const context = errorMessage;\n\n // Page state\n let pageTitle: string | null = null;\n try {\n pageTitle = await page.title();\n } catch {\n // page may be closed\n }\n\n // Timeout detection\n const isTimeout = /timeout/i.test(errorMessage);\n const timeoutMs = extractTimeoutMs(errorMessage);\n\n // Snippet & cause chain for primary error\n const snippet = generateSnippet(errorStack, testInfo);\n const causes = extractCauseChain(error);\n\n // Build errors array from all test errors\n const rawErrors = testInfo.errors ?? [];\n const errors: ErrorEntry[] = rawErrors.map((err) => {\n const msg = (err as { message?: string }).message ?? '';\n const stk = (err as { stack?: string }).stack ?? '';\n return {\n message: msg,\n stack: stk,\n pw_console: generateSnippet(stk, testInfo),\n isTimeout: /timeout/i.test(msg),\n timeoutMs: extractTimeoutMs(msg),\n causes: extractCauseChain(err),\n };\n });\n\n const analysis: FailureAnalysis = {\n // Backward-compatible\n selector,\n action,\n error: errorFirstLine,\n location,\n context,\n\n // v3 enriched\n test: {\n title: testInfo.title,\n titlePath: testInfo.titlePath,\n file: testInfo.file,\n line: (testInfo as unknown as { line?: number }).line ?? null,\n project: testInfo.project.name,\n retries: testInfo.project.retries,\n retry: testInfo.retry,\n duration,\n status: testInfo.status,\n expectedStatus: testInfo.expectedStatus,\n tags: (testInfo as unknown as { tags?: string[] }).tags ?? [],\n },\n page: {\n url: page.url(),\n title: pageTitle,\n viewport: page.viewportSize(),\n },\n selectorDetails: extractSelectorDetails(errorMessage),\n consoleLogs,\n consoleErrors: consoleLogs.filter(\n (e) => e.type === 'error' || e.type === 'pageerror'\n ),\n networkFailures,\n errorDetails: {\n message: errorMessage,\n stack: errorStack,\n pw_console: snippet,\n isTimeout,\n timeoutMs,\n causes,\n },\n errors,\n timing: {\n testStart,\n failureCapture,\n duration,\n },\n artifacts: {\n domJsonPath: artifacts.jsonPath,\n screenshotPath: artifacts.screenshotPath,\n failureInfoPath: artifacts.failureInfoPath,\n },\n _version: 3,\n };\n\n fs.writeFileSync(artifacts.failureInfoPath, JSON.stringify(analysis, null, 2));\n\n return analysis;\n}\n\n// ─── Snippet / Cause / Timeout Helpers ────────────────────────────────────\n\nfunction generateSnippet(stack: string, testInfo: TestInfo): string | null {\n const escaped = testInfo.file.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n const match = stack.match(new RegExp(`${escaped}:(\\\\d+):(\\\\d+)`));\n if (!match) return null;\n\n const lineNumber = parseInt(match[1], 10);\n let lines: string[];\n try {\n lines = fs.readFileSync(testInfo.file, 'utf-8').split('\\n');\n } catch {\n return null;\n }\n\n const start = Math.max(0, lineNumber - 5); // 4 lines before (0-indexed: lineNumber-1 is the error line)\n const end = Math.min(lines.length, lineNumber + 3); // 3 lines after\n const slice = lines.slice(start, end);\n\n const maxLineNum = end;\n const gutterWidth = String(maxLineNum).length;\n\n return slice\n .map((text, i) => {\n const num = start + i + 1;\n const marker = num === lineNumber ? '>' : ' ';\n const padded = String(num).padStart(gutterWidth);\n return `${marker} ${padded} | ${text}`;\n })\n .join('\\n');\n}\n\nfunction extractCauseChain(error: unknown): ErrorCause[] {\n const causes: ErrorCause[] = [];\n const seen = new WeakSet<object>();\n let current = error;\n\n for (let depth = 0; depth < 10; depth++) {\n if (current == null || typeof current !== 'object') break;\n const cause = (current as { cause?: unknown }).cause;\n if (cause == null || typeof cause !== 'object') break;\n if (seen.has(cause as object)) break;\n seen.add(cause as object);\n\n const causeErr = cause as { message?: string; stack?: string };\n causes.push({\n message: causeErr.message ?? String(cause),\n stack: causeErr.stack ?? '',\n });\n current = cause;\n }\n\n return causes;\n}\n\nfunction extractTimeoutMs(msg: string): number | null {\n if (!/timeout/i.test(msg)) return null;\n const match = msg.match(/(\\d+)\\s*ms/);\n return match ? parseInt(match[1], 10) : null;\n}\n\n// ─── Private Helpers ───────────────────────────────────────────────────────\n\nfunction extractSelector(msg: string): string {\n const match =\n msg.match(/locator\\(['\"](.+?)['\"]\\)/) ||\n msg.match(/getByRole\\(['\"](.+?)['\"]\\)/) ||\n msg.match(/getByText\\(['\"](.+?)['\"]\\)/);\n return match ? match[1] : '';\n}\n\nfunction extractAction(msg: string): string {\n if (msg.includes('.click')) return 'click';\n if (msg.includes('.fill')) return 'fill';\n if (msg.includes('.type')) return 'type';\n if (msg.includes('.hover')) return 'hover';\n if (msg.includes('.check')) return 'check';\n if (msg.includes('.uncheck')) return 'uncheck';\n if (msg.includes('.select')) return 'select';\n if (msg.includes('.press')) return 'press';\n if (msg.includes('.scroll')) return 'scroll';\n if (msg.includes('.drag')) return 'drag';\n if (/timeout/i.test(msg)) return 'wait';\n return '';\n}\n\nfunction extractLocation(stack: string, testInfo: TestInfo): string {\n const escaped = testInfo.file.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n const match = stack.match(new RegExp(`${escaped}:(\\\\d+):(\\\\d+)`));\n if (match) {\n return `${path.basename(testInfo.file)}:${match[1]}`;\n }\n return '';\n}\n\nfunction extractSelectorDetails(msg: string): FailureSelector | null {\n const patterns: Array<{ method: string; regex: RegExp }> = [\n { method: 'locator', regex: /locator\\(['\"](.+?)['\"]\\)/ },\n { method: 'getByRole', regex: /getByRole\\(['\"](.+?)['\"]\\)/ },\n { method: 'getByText', regex: /getByText\\(['\"](.+?)['\"]\\)/ },\n { method: 'getByTestId', regex: /getByTestId\\(['\"](.+?)['\"]\\)/ },\n { method: 'getByLabel', regex: /getByLabel\\(['\"](.+?)['\"]\\)/ },\n { method: 'getByPlaceholder', regex: /getByPlaceholder\\(['\"](.+?)['\"]\\)/ },\n { method: 'getByAltText', regex: /getByAltText\\(['\"](.+?)['\"]\\)/ },\n { method: 'getByTitle', regex: /getByTitle\\(['\"](.+?)['\"]\\)/ },\n { method: 'frameLocator', regex: /frameLocator\\(['\"](.+?)['\"]\\)/ },\n ];\n\n for (const { method, regex } of patterns) {\n const match = msg.match(regex);\n if (match) {\n return { raw: match[0], method, value: match[1] };\n }\n }\n return null;\n}\n"],"mappings":"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","names":["fs","path"]}
@@ -0,0 +1,100 @@
1
+ import { Page, TestInfo } from '@playwright/test';
2
+
3
+ interface ConsoleEntry {
4
+ type: string;
5
+ text: string;
6
+ timestamp: string;
7
+ location?: {
8
+ url?: string;
9
+ lineNumber?: number;
10
+ columnNumber?: number;
11
+ };
12
+ }
13
+ interface NetworkFailure {
14
+ url: string;
15
+ method: string;
16
+ status: number;
17
+ statusText: string;
18
+ resourceType: string;
19
+ timestamp: string;
20
+ }
21
+ interface FailureSelector {
22
+ raw: string;
23
+ method: string;
24
+ value: string;
25
+ }
26
+ interface ErrorCause {
27
+ message: string;
28
+ stack: string;
29
+ }
30
+ interface ErrorEntry {
31
+ message: string;
32
+ stack: string;
33
+ pw_console: string | null;
34
+ isTimeout: boolean;
35
+ timeoutMs: number | null;
36
+ causes: ErrorCause[];
37
+ }
38
+ interface FailureAnalysis {
39
+ selector: string;
40
+ action: string;
41
+ error: string;
42
+ location: string;
43
+ context: string;
44
+ test: {
45
+ title: string;
46
+ titlePath: string[];
47
+ file: string;
48
+ line: number | null;
49
+ project: string;
50
+ retries: number;
51
+ retry: number;
52
+ duration: number;
53
+ status: string | undefined;
54
+ expectedStatus: string;
55
+ tags: string[];
56
+ };
57
+ page: {
58
+ url: string;
59
+ title: string | null;
60
+ viewport: {
61
+ width: number;
62
+ height: number;
63
+ } | null;
64
+ };
65
+ selectorDetails: FailureSelector | null;
66
+ consoleLogs: ConsoleEntry[];
67
+ consoleErrors: ConsoleEntry[];
68
+ networkFailures: NetworkFailure[];
69
+ errorDetails: {
70
+ message: string;
71
+ stack: string;
72
+ pw_console: string | null;
73
+ isTimeout: boolean;
74
+ timeoutMs: number | null;
75
+ causes: ErrorCause[];
76
+ };
77
+ errors: ErrorEntry[];
78
+ timing: {
79
+ testStart: string;
80
+ failureCapture: string;
81
+ duration: number;
82
+ };
83
+ artifacts: {
84
+ domJsonPath: string;
85
+ screenshotPath: string;
86
+ failureInfoPath: string;
87
+ };
88
+ _version: 3;
89
+ }
90
+ declare function setupPageListeners(page: Page): {
91
+ consoleLogs: ConsoleEntry[];
92
+ networkFailures: NetworkFailure[];
93
+ };
94
+ declare function analyzeFailure(page: Page, testInfo: TestInfo, consoleLogs: ConsoleEntry[], networkFailures: NetworkFailure[], artifacts: {
95
+ jsonPath: string;
96
+ screenshotPath: string;
97
+ failureInfoPath: string;
98
+ }): Promise<FailureAnalysis>;
99
+
100
+ export { type ConsoleEntry, type ErrorCause, type ErrorEntry, type FailureAnalysis, type FailureSelector, type NetworkFailure, analyzeFailure, setupPageListeners };
@@ -0,0 +1,100 @@
1
+ import { Page, TestInfo } from '@playwright/test';
2
+
3
+ interface ConsoleEntry {
4
+ type: string;
5
+ text: string;
6
+ timestamp: string;
7
+ location?: {
8
+ url?: string;
9
+ lineNumber?: number;
10
+ columnNumber?: number;
11
+ };
12
+ }
13
+ interface NetworkFailure {
14
+ url: string;
15
+ method: string;
16
+ status: number;
17
+ statusText: string;
18
+ resourceType: string;
19
+ timestamp: string;
20
+ }
21
+ interface FailureSelector {
22
+ raw: string;
23
+ method: string;
24
+ value: string;
25
+ }
26
+ interface ErrorCause {
27
+ message: string;
28
+ stack: string;
29
+ }
30
+ interface ErrorEntry {
31
+ message: string;
32
+ stack: string;
33
+ pw_console: string | null;
34
+ isTimeout: boolean;
35
+ timeoutMs: number | null;
36
+ causes: ErrorCause[];
37
+ }
38
+ interface FailureAnalysis {
39
+ selector: string;
40
+ action: string;
41
+ error: string;
42
+ location: string;
43
+ context: string;
44
+ test: {
45
+ title: string;
46
+ titlePath: string[];
47
+ file: string;
48
+ line: number | null;
49
+ project: string;
50
+ retries: number;
51
+ retry: number;
52
+ duration: number;
53
+ status: string | undefined;
54
+ expectedStatus: string;
55
+ tags: string[];
56
+ };
57
+ page: {
58
+ url: string;
59
+ title: string | null;
60
+ viewport: {
61
+ width: number;
62
+ height: number;
63
+ } | null;
64
+ };
65
+ selectorDetails: FailureSelector | null;
66
+ consoleLogs: ConsoleEntry[];
67
+ consoleErrors: ConsoleEntry[];
68
+ networkFailures: NetworkFailure[];
69
+ errorDetails: {
70
+ message: string;
71
+ stack: string;
72
+ pw_console: string | null;
73
+ isTimeout: boolean;
74
+ timeoutMs: number | null;
75
+ causes: ErrorCause[];
76
+ };
77
+ errors: ErrorEntry[];
78
+ timing: {
79
+ testStart: string;
80
+ failureCapture: string;
81
+ duration: number;
82
+ };
83
+ artifacts: {
84
+ domJsonPath: string;
85
+ screenshotPath: string;
86
+ failureInfoPath: string;
87
+ };
88
+ _version: 3;
89
+ }
90
+ declare function setupPageListeners(page: Page): {
91
+ consoleLogs: ConsoleEntry[];
92
+ networkFailures: NetworkFailure[];
93
+ };
94
+ declare function analyzeFailure(page: Page, testInfo: TestInfo, consoleLogs: ConsoleEntry[], networkFailures: NetworkFailure[], artifacts: {
95
+ jsonPath: string;
96
+ screenshotPath: string;
97
+ failureInfoPath: string;
98
+ }): Promise<FailureAnalysis>;
99
+
100
+ export { type ConsoleEntry, type ErrorCause, type ErrorEntry, type FailureAnalysis, type FailureSelector, type NetworkFailure, analyzeFailure, setupPageListeners };
@@ -0,0 +1,241 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ function setupPageListeners(page) {
4
+ const consoleLogs = [];
5
+ const networkFailures = [];
6
+ const MAX_CONSOLE_ENTRIES = 500;
7
+ page.on("console", (msg) => {
8
+ if (consoleLogs.length >= MAX_CONSOLE_ENTRIES) return;
9
+ const loc = msg.location();
10
+ consoleLogs.push({
11
+ type: msg.type(),
12
+ text: msg.text(),
13
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
14
+ location: {
15
+ url: loc.url,
16
+ lineNumber: loc.lineNumber,
17
+ columnNumber: loc.columnNumber
18
+ }
19
+ });
20
+ });
21
+ page.on("pageerror", (err) => {
22
+ if (consoleLogs.length >= MAX_CONSOLE_ENTRIES) return;
23
+ consoleLogs.push({
24
+ type: "pageerror",
25
+ text: err.message,
26
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
27
+ });
28
+ });
29
+ page.on("response", (response) => {
30
+ if (response.status() >= 400) {
31
+ networkFailures.push({
32
+ url: response.url(),
33
+ method: response.request().method(),
34
+ status: response.status(),
35
+ statusText: response.statusText(),
36
+ resourceType: response.request().resourceType(),
37
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
38
+ });
39
+ }
40
+ });
41
+ page.on("requestfailed", (request) => {
42
+ networkFailures.push({
43
+ url: request.url(),
44
+ method: request.method(),
45
+ status: 0,
46
+ statusText: request.failure()?.errorText ?? "Request failed",
47
+ resourceType: request.resourceType(),
48
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
49
+ });
50
+ });
51
+ return { consoleLogs, networkFailures };
52
+ }
53
+ async function analyzeFailure(page, testInfo, consoleLogs, networkFailures, artifacts) {
54
+ const error = testInfo.error ?? testInfo.errors?.[0] ?? {};
55
+ const errorMessage = error.message ?? "";
56
+ const errorStack = error.stack ?? "";
57
+ const now = /* @__PURE__ */ new Date();
58
+ const duration = testInfo.duration ?? 0;
59
+ const testStart = new Date(now.getTime() - duration).toISOString();
60
+ const failureCapture = now.toISOString();
61
+ const selector = extractSelector(errorMessage);
62
+ const action = extractAction(errorMessage);
63
+ const errorFirstLine = errorMessage.split("\n")[0];
64
+ const location = extractLocation(errorStack, testInfo);
65
+ const context = errorMessage;
66
+ let pageTitle = null;
67
+ try {
68
+ pageTitle = await page.title();
69
+ } catch {
70
+ }
71
+ const isTimeout = /timeout/i.test(errorMessage);
72
+ const timeoutMs = extractTimeoutMs(errorMessage);
73
+ const snippet = generateSnippet(errorStack, testInfo);
74
+ const causes = extractCauseChain(error);
75
+ const rawErrors = testInfo.errors ?? [];
76
+ const errors = rawErrors.map((err) => {
77
+ const msg = err.message ?? "";
78
+ const stk = err.stack ?? "";
79
+ return {
80
+ message: msg,
81
+ stack: stk,
82
+ pw_console: generateSnippet(stk, testInfo),
83
+ isTimeout: /timeout/i.test(msg),
84
+ timeoutMs: extractTimeoutMs(msg),
85
+ causes: extractCauseChain(err)
86
+ };
87
+ });
88
+ const analysis = {
89
+ // Backward-compatible
90
+ selector,
91
+ action,
92
+ error: errorFirstLine,
93
+ location,
94
+ context,
95
+ // v3 enriched
96
+ test: {
97
+ title: testInfo.title,
98
+ titlePath: testInfo.titlePath,
99
+ file: testInfo.file,
100
+ line: testInfo.line ?? null,
101
+ project: testInfo.project.name,
102
+ retries: testInfo.project.retries,
103
+ retry: testInfo.retry,
104
+ duration,
105
+ status: testInfo.status,
106
+ expectedStatus: testInfo.expectedStatus,
107
+ tags: testInfo.tags ?? []
108
+ },
109
+ page: {
110
+ url: page.url(),
111
+ title: pageTitle,
112
+ viewport: page.viewportSize()
113
+ },
114
+ selectorDetails: extractSelectorDetails(errorMessage),
115
+ consoleLogs,
116
+ consoleErrors: consoleLogs.filter(
117
+ (e) => e.type === "error" || e.type === "pageerror"
118
+ ),
119
+ networkFailures,
120
+ errorDetails: {
121
+ message: errorMessage,
122
+ stack: errorStack,
123
+ pw_console: snippet,
124
+ isTimeout,
125
+ timeoutMs,
126
+ causes
127
+ },
128
+ errors,
129
+ timing: {
130
+ testStart,
131
+ failureCapture,
132
+ duration
133
+ },
134
+ artifacts: {
135
+ domJsonPath: artifacts.jsonPath,
136
+ screenshotPath: artifacts.screenshotPath,
137
+ failureInfoPath: artifacts.failureInfoPath
138
+ },
139
+ _version: 3
140
+ };
141
+ fs.writeFileSync(artifacts.failureInfoPath, JSON.stringify(analysis, null, 2));
142
+ return analysis;
143
+ }
144
+ function generateSnippet(stack, testInfo) {
145
+ const escaped = testInfo.file.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
146
+ const match = stack.match(new RegExp(`${escaped}:(\\d+):(\\d+)`));
147
+ if (!match) return null;
148
+ const lineNumber = parseInt(match[1], 10);
149
+ let lines;
150
+ try {
151
+ lines = fs.readFileSync(testInfo.file, "utf-8").split("\n");
152
+ } catch {
153
+ return null;
154
+ }
155
+ const start = Math.max(0, lineNumber - 5);
156
+ const end = Math.min(lines.length, lineNumber + 3);
157
+ const slice = lines.slice(start, end);
158
+ const maxLineNum = end;
159
+ const gutterWidth = String(maxLineNum).length;
160
+ return slice.map((text, i) => {
161
+ const num = start + i + 1;
162
+ const marker = num === lineNumber ? ">" : " ";
163
+ const padded = String(num).padStart(gutterWidth);
164
+ return `${marker} ${padded} | ${text}`;
165
+ }).join("\n");
166
+ }
167
+ function extractCauseChain(error) {
168
+ const causes = [];
169
+ const seen = /* @__PURE__ */ new WeakSet();
170
+ let current = error;
171
+ for (let depth = 0; depth < 10; depth++) {
172
+ if (current == null || typeof current !== "object") break;
173
+ const cause = current.cause;
174
+ if (cause == null || typeof cause !== "object") break;
175
+ if (seen.has(cause)) break;
176
+ seen.add(cause);
177
+ const causeErr = cause;
178
+ causes.push({
179
+ message: causeErr.message ?? String(cause),
180
+ stack: causeErr.stack ?? ""
181
+ });
182
+ current = cause;
183
+ }
184
+ return causes;
185
+ }
186
+ function extractTimeoutMs(msg) {
187
+ if (!/timeout/i.test(msg)) return null;
188
+ const match = msg.match(/(\d+)\s*ms/);
189
+ return match ? parseInt(match[1], 10) : null;
190
+ }
191
+ function extractSelector(msg) {
192
+ const match = msg.match(/locator\(['"](.+?)['"]\)/) || msg.match(/getByRole\(['"](.+?)['"]\)/) || msg.match(/getByText\(['"](.+?)['"]\)/);
193
+ return match ? match[1] : "";
194
+ }
195
+ function extractAction(msg) {
196
+ if (msg.includes(".click")) return "click";
197
+ if (msg.includes(".fill")) return "fill";
198
+ if (msg.includes(".type")) return "type";
199
+ if (msg.includes(".hover")) return "hover";
200
+ if (msg.includes(".check")) return "check";
201
+ if (msg.includes(".uncheck")) return "uncheck";
202
+ if (msg.includes(".select")) return "select";
203
+ if (msg.includes(".press")) return "press";
204
+ if (msg.includes(".scroll")) return "scroll";
205
+ if (msg.includes(".drag")) return "drag";
206
+ if (/timeout/i.test(msg)) return "wait";
207
+ return "";
208
+ }
209
+ function extractLocation(stack, testInfo) {
210
+ const escaped = testInfo.file.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
211
+ const match = stack.match(new RegExp(`${escaped}:(\\d+):(\\d+)`));
212
+ if (match) {
213
+ return `${path.basename(testInfo.file)}:${match[1]}`;
214
+ }
215
+ return "";
216
+ }
217
+ function extractSelectorDetails(msg) {
218
+ const patterns = [
219
+ { method: "locator", regex: /locator\(['"](.+?)['"]\)/ },
220
+ { method: "getByRole", regex: /getByRole\(['"](.+?)['"]\)/ },
221
+ { method: "getByText", regex: /getByText\(['"](.+?)['"]\)/ },
222
+ { method: "getByTestId", regex: /getByTestId\(['"](.+?)['"]\)/ },
223
+ { method: "getByLabel", regex: /getByLabel\(['"](.+?)['"]\)/ },
224
+ { method: "getByPlaceholder", regex: /getByPlaceholder\(['"](.+?)['"]\)/ },
225
+ { method: "getByAltText", regex: /getByAltText\(['"](.+?)['"]\)/ },
226
+ { method: "getByTitle", regex: /getByTitle\(['"](.+?)['"]\)/ },
227
+ { method: "frameLocator", regex: /frameLocator\(['"](.+?)['"]\)/ }
228
+ ];
229
+ for (const { method, regex } of patterns) {
230
+ const match = msg.match(regex);
231
+ if (match) {
232
+ return { raw: match[0], method, value: match[1] };
233
+ }
234
+ }
235
+ return null;
236
+ }
237
+ export {
238
+ analyzeFailure,
239
+ setupPageListeners
240
+ };
241
+ //# sourceMappingURL=failure-analyzer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/helpers/failure-analyzer.ts"],"sourcesContent":["import fs from 'fs';\nimport path from 'path';\nimport type { Page, TestInfo } from '@playwright/test';\n\n// ─── Exported Interfaces ───────────────────────────────────────────────────\n\nexport interface ConsoleEntry {\n type: string;\n text: string;\n timestamp: string;\n location?: { url?: string; lineNumber?: number; columnNumber?: number };\n}\n\nexport interface NetworkFailure {\n url: string;\n method: string;\n status: number;\n statusText: string;\n resourceType: string;\n timestamp: string;\n}\n\nexport interface FailureSelector {\n raw: string;\n method: string;\n value: string;\n}\n\nexport interface ErrorCause {\n message: string;\n stack: string;\n}\n\nexport interface ErrorEntry {\n message: string;\n stack: string;\n pw_console: string | null;\n isTimeout: boolean;\n timeoutMs: number | null;\n causes: ErrorCause[];\n}\n\nexport interface FailureAnalysis {\n // Backward-compatible original 5 fields\n selector: string;\n action: string;\n error: string;\n location: string;\n context: string;\n\n // Enriched fields (v2+)\n test: {\n title: string;\n titlePath: string[];\n file: string;\n line: number | null;\n project: string;\n retries: number;\n retry: number;\n duration: number;\n status: string | undefined;\n expectedStatus: string;\n tags: string[];\n };\n page: {\n url: string;\n title: string | null;\n viewport: { width: number; height: number } | null;\n };\n selectorDetails: FailureSelector | null;\n consoleLogs: ConsoleEntry[];\n consoleErrors: ConsoleEntry[];\n networkFailures: NetworkFailure[];\n errorDetails: {\n message: string;\n stack: string;\n pw_console: string | null;\n isTimeout: boolean;\n timeoutMs: number | null;\n causes: ErrorCause[];\n };\n errors: ErrorEntry[];\n timing: {\n testStart: string;\n failureCapture: string;\n duration: number;\n };\n artifacts: {\n domJsonPath: string;\n screenshotPath: string;\n failureInfoPath: string;\n };\n _version: 3;\n}\n\n// ─── Page Listener Setup ───────────────────────────────────────────────────\n\nexport function setupPageListeners(page: Page): {\n consoleLogs: ConsoleEntry[];\n networkFailures: NetworkFailure[];\n} {\n const consoleLogs: ConsoleEntry[] = [];\n const networkFailures: NetworkFailure[] = [];\n const MAX_CONSOLE_ENTRIES = 500;\n\n page.on('console', (msg) => {\n if (consoleLogs.length >= MAX_CONSOLE_ENTRIES) return;\n const loc = msg.location();\n consoleLogs.push({\n type: msg.type(),\n text: msg.text(),\n timestamp: new Date().toISOString(),\n location: {\n url: loc.url,\n lineNumber: loc.lineNumber,\n columnNumber: loc.columnNumber,\n },\n });\n });\n\n page.on('pageerror', (err) => {\n if (consoleLogs.length >= MAX_CONSOLE_ENTRIES) return;\n consoleLogs.push({\n type: 'pageerror',\n text: err.message,\n timestamp: new Date().toISOString(),\n });\n });\n\n page.on('response', (response) => {\n if (response.status() >= 400) {\n networkFailures.push({\n url: response.url(),\n method: response.request().method(),\n status: response.status(),\n statusText: response.statusText(),\n resourceType: response.request().resourceType(),\n timestamp: new Date().toISOString(),\n });\n }\n });\n\n page.on('requestfailed', (request) => {\n networkFailures.push({\n url: request.url(),\n method: request.method(),\n status: 0,\n statusText: request.failure()?.errorText ?? 'Request failed',\n resourceType: request.resourceType(),\n timestamp: new Date().toISOString(),\n });\n });\n\n return { consoleLogs, networkFailures };\n}\n\n// ─── Failure Analysis ──────────────────────────────────────────────────────\n\nexport async function analyzeFailure(\n page: Page,\n testInfo: TestInfo,\n consoleLogs: ConsoleEntry[],\n networkFailures: NetworkFailure[],\n artifacts: { jsonPath: string; screenshotPath: string; failureInfoPath: string }\n): Promise<FailureAnalysis> {\n const error = (testInfo.error ?? testInfo.errors?.[0] ?? {}) as { message?: string; stack?: string };\n const errorMessage = error.message ?? '';\n const errorStack = error.stack ?? '';\n\n const now = new Date();\n const duration = testInfo.duration ?? 0;\n const testStart = new Date(now.getTime() - duration).toISOString();\n const failureCapture = now.toISOString();\n\n // Original 5 fields (backward compat)\n const selector = extractSelector(errorMessage);\n const action = extractAction(errorMessage);\n const errorFirstLine = errorMessage.split('\\n')[0];\n const location = extractLocation(errorStack, testInfo);\n const context = errorMessage;\n\n // Page state\n let pageTitle: string | null = null;\n try {\n pageTitle = await page.title();\n } catch {\n // page may be closed\n }\n\n // Timeout detection\n const isTimeout = /timeout/i.test(errorMessage);\n const timeoutMs = extractTimeoutMs(errorMessage);\n\n // Snippet & cause chain for primary error\n const snippet = generateSnippet(errorStack, testInfo);\n const causes = extractCauseChain(error);\n\n // Build errors array from all test errors\n const rawErrors = testInfo.errors ?? [];\n const errors: ErrorEntry[] = rawErrors.map((err) => {\n const msg = (err as { message?: string }).message ?? '';\n const stk = (err as { stack?: string }).stack ?? '';\n return {\n message: msg,\n stack: stk,\n pw_console: generateSnippet(stk, testInfo),\n isTimeout: /timeout/i.test(msg),\n timeoutMs: extractTimeoutMs(msg),\n causes: extractCauseChain(err),\n };\n });\n\n const analysis: FailureAnalysis = {\n // Backward-compatible\n selector,\n action,\n error: errorFirstLine,\n location,\n context,\n\n // v3 enriched\n test: {\n title: testInfo.title,\n titlePath: testInfo.titlePath,\n file: testInfo.file,\n line: (testInfo as unknown as { line?: number }).line ?? null,\n project: testInfo.project.name,\n retries: testInfo.project.retries,\n retry: testInfo.retry,\n duration,\n status: testInfo.status,\n expectedStatus: testInfo.expectedStatus,\n tags: (testInfo as unknown as { tags?: string[] }).tags ?? [],\n },\n page: {\n url: page.url(),\n title: pageTitle,\n viewport: page.viewportSize(),\n },\n selectorDetails: extractSelectorDetails(errorMessage),\n consoleLogs,\n consoleErrors: consoleLogs.filter(\n (e) => e.type === 'error' || e.type === 'pageerror'\n ),\n networkFailures,\n errorDetails: {\n message: errorMessage,\n stack: errorStack,\n pw_console: snippet,\n isTimeout,\n timeoutMs,\n causes,\n },\n errors,\n timing: {\n testStart,\n failureCapture,\n duration,\n },\n artifacts: {\n domJsonPath: artifacts.jsonPath,\n screenshotPath: artifacts.screenshotPath,\n failureInfoPath: artifacts.failureInfoPath,\n },\n _version: 3,\n };\n\n fs.writeFileSync(artifacts.failureInfoPath, JSON.stringify(analysis, null, 2));\n\n return analysis;\n}\n\n// ─── Snippet / Cause / Timeout Helpers ────────────────────────────────────\n\nfunction generateSnippet(stack: string, testInfo: TestInfo): string | null {\n const escaped = testInfo.file.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n const match = stack.match(new RegExp(`${escaped}:(\\\\d+):(\\\\d+)`));\n if (!match) return null;\n\n const lineNumber = parseInt(match[1], 10);\n let lines: string[];\n try {\n lines = fs.readFileSync(testInfo.file, 'utf-8').split('\\n');\n } catch {\n return null;\n }\n\n const start = Math.max(0, lineNumber - 5); // 4 lines before (0-indexed: lineNumber-1 is the error line)\n const end = Math.min(lines.length, lineNumber + 3); // 3 lines after\n const slice = lines.slice(start, end);\n\n const maxLineNum = end;\n const gutterWidth = String(maxLineNum).length;\n\n return slice\n .map((text, i) => {\n const num = start + i + 1;\n const marker = num === lineNumber ? '>' : ' ';\n const padded = String(num).padStart(gutterWidth);\n return `${marker} ${padded} | ${text}`;\n })\n .join('\\n');\n}\n\nfunction extractCauseChain(error: unknown): ErrorCause[] {\n const causes: ErrorCause[] = [];\n const seen = new WeakSet<object>();\n let current = error;\n\n for (let depth = 0; depth < 10; depth++) {\n if (current == null || typeof current !== 'object') break;\n const cause = (current as { cause?: unknown }).cause;\n if (cause == null || typeof cause !== 'object') break;\n if (seen.has(cause as object)) break;\n seen.add(cause as object);\n\n const causeErr = cause as { message?: string; stack?: string };\n causes.push({\n message: causeErr.message ?? String(cause),\n stack: causeErr.stack ?? '',\n });\n current = cause;\n }\n\n return causes;\n}\n\nfunction extractTimeoutMs(msg: string): number | null {\n if (!/timeout/i.test(msg)) return null;\n const match = msg.match(/(\\d+)\\s*ms/);\n return match ? parseInt(match[1], 10) : null;\n}\n\n// ─── Private Helpers ───────────────────────────────────────────────────────\n\nfunction extractSelector(msg: string): string {\n const match =\n msg.match(/locator\\(['\"](.+?)['\"]\\)/) ||\n msg.match(/getByRole\\(['\"](.+?)['\"]\\)/) ||\n msg.match(/getByText\\(['\"](.+?)['\"]\\)/);\n return match ? match[1] : '';\n}\n\nfunction extractAction(msg: string): string {\n if (msg.includes('.click')) return 'click';\n if (msg.includes('.fill')) return 'fill';\n if (msg.includes('.type')) return 'type';\n if (msg.includes('.hover')) return 'hover';\n if (msg.includes('.check')) return 'check';\n if (msg.includes('.uncheck')) return 'uncheck';\n if (msg.includes('.select')) return 'select';\n if (msg.includes('.press')) return 'press';\n if (msg.includes('.scroll')) return 'scroll';\n if (msg.includes('.drag')) return 'drag';\n if (/timeout/i.test(msg)) return 'wait';\n return '';\n}\n\nfunction extractLocation(stack: string, testInfo: TestInfo): string {\n const escaped = testInfo.file.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n const match = stack.match(new RegExp(`${escaped}:(\\\\d+):(\\\\d+)`));\n if (match) {\n return `${path.basename(testInfo.file)}:${match[1]}`;\n }\n return '';\n}\n\nfunction extractSelectorDetails(msg: string): FailureSelector | null {\n const patterns: Array<{ method: string; regex: RegExp }> = [\n { method: 'locator', regex: /locator\\(['\"](.+?)['\"]\\)/ },\n { method: 'getByRole', regex: /getByRole\\(['\"](.+?)['\"]\\)/ },\n { method: 'getByText', regex: /getByText\\(['\"](.+?)['\"]\\)/ },\n { method: 'getByTestId', regex: /getByTestId\\(['\"](.+?)['\"]\\)/ },\n { method: 'getByLabel', regex: /getByLabel\\(['\"](.+?)['\"]\\)/ },\n { method: 'getByPlaceholder', regex: /getByPlaceholder\\(['\"](.+?)['\"]\\)/ },\n { method: 'getByAltText', regex: /getByAltText\\(['\"](.+?)['\"]\\)/ },\n { method: 'getByTitle', regex: /getByTitle\\(['\"](.+?)['\"]\\)/ },\n { method: 'frameLocator', regex: /frameLocator\\(['\"](.+?)['\"]\\)/ },\n ];\n\n for (const { method, regex } of patterns) {\n const match = msg.match(regex);\n if (match) {\n return { raw: match[0], method, value: match[1] };\n }\n }\n return null;\n}\n"],"mappings":"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","names":[]}
package/dist/index.cjs ADDED
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var index_exports = {};
20
+ __export(index_exports, {
21
+ captureFailure: () => import_capture.captureFailure,
22
+ setupPageListeners: () => import_failure_analyzer.setupPageListeners
23
+ });
24
+ module.exports = __toCommonJS(index_exports);
25
+ var import_capture = require("./capture.cjs");
26
+ var import_failure_analyzer = require("./helpers/failure-analyzer.cjs");
27
+ // Annotate the CommonJS export names for ESM import in node:
28
+ 0 && (module.exports = {
29
+ captureFailure,
30
+ setupPageListeners
31
+ });
32
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export { captureFailure } from './capture.js';\nexport { setupPageListeners } from './helpers/failure-analyzer.js';\nexport type { ConsoleEntry, NetworkFailure, FailureSelector, ErrorCause, ErrorEntry, FailureAnalysis } from './helpers/failure-analyzer.js';\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBAA+B;AAC/B,8BAAmC;","names":[]}
@@ -0,0 +1,3 @@
1
+ export { captureFailure } from './capture.cjs';
2
+ export { ConsoleEntry, ErrorCause, ErrorEntry, FailureAnalysis, FailureSelector, NetworkFailure, setupPageListeners } from './helpers/failure-analyzer.cjs';
3
+ import '@playwright/test';
@@ -0,0 +1,3 @@
1
+ export { captureFailure } from './capture.js';
2
+ export { ConsoleEntry, ErrorCause, ErrorEntry, FailureAnalysis, FailureSelector, NetworkFailure, setupPageListeners } from './helpers/failure-analyzer.js';
3
+ import '@playwright/test';
package/dist/index.js ADDED
@@ -0,0 +1,7 @@
1
+ import { captureFailure } from "./capture.js";
2
+ import { setupPageListeners } from "./helpers/failure-analyzer.js";
3
+ export {
4
+ captureFailure,
5
+ setupPageListeners
6
+ };
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export { captureFailure } from './capture.js';\nexport { setupPageListeners } from './helpers/failure-analyzer.js';\nexport type { ConsoleEntry, NetworkFailure, FailureSelector, ErrorCause, ErrorEntry, FailureAnalysis } from './helpers/failure-analyzer.js';\n"],"mappings":"AAAA,SAAS,sBAAsB;AAC/B,SAAS,0BAA0B;","names":[]}
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@muuktest/amikoo-playwright",
3
+ "version": "2.0.0",
4
+ "description": "Playwright DOM failure capture library. Automatically captures DOM state and screenshots when tests fail.",
5
+ "type": "module",
6
+ "main": "dist/index.cjs",
7
+ "module": "dist/index.js",
8
+ "types": "dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "import": {
12
+ "types": "./dist/index.d.ts",
13
+ "default": "./dist/index.js"
14
+ },
15
+ "require": {
16
+ "types": "./dist/index.d.cts",
17
+ "default": "./dist/index.cjs"
18
+ }
19
+ }
20
+ },
21
+ "files": [
22
+ "dist"
23
+ ],
24
+ "publishConfig": {
25
+ "access": "public"
26
+ },
27
+ "bin": "dist/cli/index.js",
28
+ "scripts": {
29
+ "build": "tsup && node scripts/postbuild.mjs",
30
+ "prepublishOnly": "npm run build",
31
+ "clean": "rm -rf dist"
32
+ },
33
+ "peerDependencies": {
34
+ "@playwright/test": ">=1.40.0"
35
+ },
36
+ "devDependencies": {
37
+ "@playwright/test": "^1.40.0",
38
+ "@types/node": "^25.2.3",
39
+ "tsup": "^8.5.1",
40
+ "typescript": "^5.3.0"
41
+ },
42
+ "keywords": [
43
+ "playwright",
44
+ "testing",
45
+ "dom",
46
+ "failure",
47
+ "capture",
48
+ "screenshot"
49
+ ],
50
+ "license": "MIT"
51
+ }