@tangle-network/browser-agent-driver 0.6.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.
- package/LICENSE +196 -0
- package/README.md +149 -0
- package/dist/artifacts/composite-sink.d.ts +15 -0
- package/dist/artifacts/composite-sink.d.ts.map +1 -0
- package/dist/artifacts/composite-sink.js +27 -0
- package/dist/artifacts/composite-sink.js.map +1 -0
- package/dist/artifacts/filesystem-sink.d.ts +26 -0
- package/dist/artifacts/filesystem-sink.d.ts.map +1 -0
- package/dist/artifacts/filesystem-sink.js +81 -0
- package/dist/artifacts/filesystem-sink.js.map +1 -0
- package/dist/artifacts/types.d.ts +97 -0
- package/dist/artifacts/types.d.ts.map +1 -0
- package/dist/artifacts/types.js +9 -0
- package/dist/artifacts/types.js.map +1 -0
- package/dist/artifacts/webhook-sink.d.ts +71 -0
- package/dist/artifacts/webhook-sink.d.ts.map +1 -0
- package/dist/artifacts/webhook-sink.js +117 -0
- package/dist/artifacts/webhook-sink.js.map +1 -0
- package/dist/brain/index.d.ts +149 -0
- package/dist/brain/index.d.ts.map +1 -0
- package/dist/brain/index.js +1030 -0
- package/dist/brain/index.js.map +1 -0
- package/dist/browser-launch.d.ts +27 -0
- package/dist/browser-launch.d.ts.map +1 -0
- package/dist/browser-launch.js +92 -0
- package/dist/browser-launch.js.map +1 -0
- package/dist/cli.d.ts +14 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +1035 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +143 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +205 -0
- package/dist/config.js.map +1 -0
- package/dist/context-budget.d.ts +14 -0
- package/dist/context-budget.d.ts.map +1 -0
- package/dist/context-budget.js +39 -0
- package/dist/context-budget.js.map +1 -0
- package/dist/design-audit.d.ts +48 -0
- package/dist/design-audit.d.ts.map +1 -0
- package/dist/design-audit.js +172 -0
- package/dist/design-audit.js.map +1 -0
- package/dist/domain-policy.d.ts +4 -0
- package/dist/domain-policy.d.ts.map +1 -0
- package/dist/domain-policy.js +69 -0
- package/dist/domain-policy.js.map +1 -0
- package/dist/drivers/block-patterns.d.ts +11 -0
- package/dist/drivers/block-patterns.d.ts.map +1 -0
- package/dist/drivers/block-patterns.js +123 -0
- package/dist/drivers/block-patterns.js.map +1 -0
- package/dist/drivers/cdp-page-state.d.ts +22 -0
- package/dist/drivers/cdp-page-state.d.ts.map +1 -0
- package/dist/drivers/cdp-page-state.js +38 -0
- package/dist/drivers/cdp-page-state.js.map +1 -0
- package/dist/drivers/cdp-snapshot.d.ts +32 -0
- package/dist/drivers/cdp-snapshot.d.ts.map +1 -0
- package/dist/drivers/cdp-snapshot.js +120 -0
- package/dist/drivers/cdp-snapshot.js.map +1 -0
- package/dist/drivers/playwright.d.ts +84 -0
- package/dist/drivers/playwright.d.ts.map +1 -0
- package/dist/drivers/playwright.js +385 -0
- package/dist/drivers/playwright.js.map +1 -0
- package/dist/drivers/snapshot.d.ts +134 -0
- package/dist/drivers/snapshot.d.ts.map +1 -0
- package/dist/drivers/snapshot.js +354 -0
- package/dist/drivers/snapshot.js.map +1 -0
- package/dist/drivers/types.d.ts +37 -0
- package/dist/drivers/types.d.ts.map +1 -0
- package/dist/drivers/types.js +5 -0
- package/dist/drivers/types.js.map +1 -0
- package/dist/env-loader.d.ts +2 -0
- package/dist/env-loader.d.ts.map +1 -0
- package/dist/env-loader.js +35 -0
- package/dist/env-loader.js.map +1 -0
- package/dist/formatters/slack.d.ts +37 -0
- package/dist/formatters/slack.d.ts.map +1 -0
- package/dist/formatters/slack.js +97 -0
- package/dist/formatters/slack.js.map +1 -0
- package/dist/index.d.ts +60 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +53 -0
- package/dist/index.js.map +1 -0
- package/dist/memory/analyzer.d.ts +67 -0
- package/dist/memory/analyzer.d.ts.map +1 -0
- package/dist/memory/analyzer.js +265 -0
- package/dist/memory/analyzer.js.map +1 -0
- package/dist/memory/knowledge.d.ts +55 -0
- package/dist/memory/knowledge.d.ts.map +1 -0
- package/dist/memory/knowledge.js +115 -0
- package/dist/memory/knowledge.js.map +1 -0
- package/dist/memory/project-store.d.ts +43 -0
- package/dist/memory/project-store.d.ts.map +1 -0
- package/dist/memory/project-store.js +119 -0
- package/dist/memory/project-store.js.map +1 -0
- package/dist/memory/selectors.d.ts +46 -0
- package/dist/memory/selectors.d.ts.map +1 -0
- package/dist/memory/selectors.js +89 -0
- package/dist/memory/selectors.js.map +1 -0
- package/dist/memory/store.d.ts +39 -0
- package/dist/memory/store.d.ts.map +1 -0
- package/dist/memory/store.js +193 -0
- package/dist/memory/store.js.map +1 -0
- package/dist/model-pricing.d.ts +41 -0
- package/dist/model-pricing.d.ts.map +1 -0
- package/dist/model-pricing.js +197 -0
- package/dist/model-pricing.js.map +1 -0
- package/dist/multi-actor.d.ts +108 -0
- package/dist/multi-actor.d.ts.map +1 -0
- package/dist/multi-actor.js +192 -0
- package/dist/multi-actor.js.map +1 -0
- package/dist/override-pipeline.d.ts +57 -0
- package/dist/override-pipeline.d.ts.map +1 -0
- package/dist/override-pipeline.js +26 -0
- package/dist/override-pipeline.js.map +1 -0
- package/dist/personas.d.ts +19 -0
- package/dist/personas.d.ts.map +1 -0
- package/dist/personas.js +86 -0
- package/dist/personas.js.map +1 -0
- package/dist/preview.d.ts +32 -0
- package/dist/preview.d.ts.map +1 -0
- package/dist/preview.js +138 -0
- package/dist/preview.js.map +1 -0
- package/dist/provider-defaults.d.ts +6 -0
- package/dist/provider-defaults.d.ts.map +1 -0
- package/dist/provider-defaults.js +40 -0
- package/dist/provider-defaults.js.map +1 -0
- package/dist/providers/sandbox-backend.d.ts +22 -0
- package/dist/providers/sandbox-backend.d.ts.map +1 -0
- package/dist/providers/sandbox-backend.js +259 -0
- package/dist/providers/sandbox-backend.js.map +1 -0
- package/dist/recovery.d.ts +91 -0
- package/dist/recovery.d.ts.map +1 -0
- package/dist/recovery.js +500 -0
- package/dist/recovery.js.map +1 -0
- package/dist/reporters/junit.d.ts +8 -0
- package/dist/reporters/junit.d.ts.map +1 -0
- package/dist/reporters/junit.js +99 -0
- package/dist/reporters/junit.js.map +1 -0
- package/dist/run-metrics.d.ts +4 -0
- package/dist/run-metrics.d.ts.map +1 -0
- package/dist/run-metrics.js +48 -0
- package/dist/run-metrics.js.map +1 -0
- package/dist/run-state.d.ts +22 -0
- package/dist/run-state.d.ts.map +1 -0
- package/dist/run-state.js +33 -0
- package/dist/run-state.js.map +1 -0
- package/dist/runner/goal-verification.d.ts +13 -0
- package/dist/runner/goal-verification.d.ts.map +1 -0
- package/dist/runner/goal-verification.js +152 -0
- package/dist/runner/goal-verification.js.map +1 -0
- package/dist/runner/index.d.ts +12 -0
- package/dist/runner/index.d.ts.map +1 -0
- package/dist/runner/index.js +18 -0
- package/dist/runner/index.js.map +1 -0
- package/dist/runner/overrides.d.ts +75 -0
- package/dist/runner/overrides.d.ts.map +1 -0
- package/dist/runner/overrides.js +385 -0
- package/dist/runner/overrides.js.map +1 -0
- package/dist/runner/page-analysis.d.ts +23 -0
- package/dist/runner/page-analysis.d.ts.map +1 -0
- package/dist/runner/page-analysis.js +91 -0
- package/dist/runner/page-analysis.js.map +1 -0
- package/dist/runner/runner.d.ts +66 -0
- package/dist/runner/runner.d.ts.map +1 -0
- package/dist/runner/runner.js +1314 -0
- package/dist/runner/runner.js.map +1 -0
- package/dist/runner/scout.d.ts +29 -0
- package/dist/runner/scout.d.ts.map +1 -0
- package/dist/runner/scout.js +81 -0
- package/dist/runner/scout.js.map +1 -0
- package/dist/runner/search-guidance.d.ts +31 -0
- package/dist/runner/search-guidance.d.ts.map +1 -0
- package/dist/runner/search-guidance.js +210 -0
- package/dist/runner/search-guidance.js.map +1 -0
- package/dist/runner/utils.d.ts +28 -0
- package/dist/runner/utils.d.ts.map +1 -0
- package/dist/runner/utils.js +119 -0
- package/dist/runner/utils.js.map +1 -0
- package/dist/runner.d.ts +8 -0
- package/dist/runner.d.ts.map +1 -0
- package/dist/runner.js +21 -0
- package/dist/runner.js.map +1 -0
- package/dist/supervisor/critic.d.ts +29 -0
- package/dist/supervisor/critic.d.ts.map +1 -0
- package/dist/supervisor/critic.js +320 -0
- package/dist/supervisor/critic.js.map +1 -0
- package/dist/supervisor/policy.d.ts +11 -0
- package/dist/supervisor/policy.d.ts.map +1 -0
- package/dist/supervisor/policy.js +118 -0
- package/dist/supervisor/policy.js.map +1 -0
- package/dist/test-report.d.ts +15 -0
- package/dist/test-report.d.ts.map +1 -0
- package/dist/test-report.js +241 -0
- package/dist/test-report.js.map +1 -0
- package/dist/test-runner.d.ts +99 -0
- package/dist/test-runner.d.ts.map +1 -0
- package/dist/test-runner.js +1075 -0
- package/dist/test-runner.js.map +1 -0
- package/dist/types.d.ts +493 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/dist/wallet/automation.d.ts +52 -0
- package/dist/wallet/automation.d.ts.map +1 -0
- package/dist/wallet/automation.js +507 -0
- package/dist/wallet/automation.js.map +1 -0
- package/package.json +101 -0
- package/scripts/postinstall-provider-patches.mjs +52 -0
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared accessibility tree snapshot helper.
|
|
3
|
+
*
|
|
4
|
+
* Uses Playwright's `locator.ariaSnapshot()` to produce a YAML-like tree,
|
|
5
|
+
* assigns STABLE ref IDs to interactive elements (deterministic hash of
|
|
6
|
+
* role+name), and resolves @ref selectors back to Playwright locators via
|
|
7
|
+
* getByRole().
|
|
8
|
+
*
|
|
9
|
+
* Stable refs mean the same element (e.g. button "Send") gets the SAME ref ID
|
|
10
|
+
* across observations. Only elements that truly disappear produce invalid refs.
|
|
11
|
+
* Duplicates (multiple elements with same role+name) get index suffixes.
|
|
12
|
+
*
|
|
13
|
+
* Used by PlaywrightDriver.
|
|
14
|
+
*/
|
|
15
|
+
function diffSnapshots(prev, curr) {
|
|
16
|
+
const added = [];
|
|
17
|
+
const removed = [];
|
|
18
|
+
const changed = [];
|
|
19
|
+
for (const [ref, el] of curr) {
|
|
20
|
+
const prevEl = prev.get(ref);
|
|
21
|
+
if (!prevEl) {
|
|
22
|
+
added.push(`+ ${el.role} "${el.name}" [ref=${ref}]`);
|
|
23
|
+
}
|
|
24
|
+
else if (prevEl.value !== el.value) {
|
|
25
|
+
changed.push(`~ ${el.role} "${el.name}" [ref=${ref}] value: "${prevEl.value ?? ''}" → "${el.value ?? ''}"`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
for (const [ref, el] of prev) {
|
|
29
|
+
if (!curr.has(ref)) {
|
|
30
|
+
removed.push(`- ${el.role} "${el.name}" [ref=${ref}]`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return { added, removed, changed, unchangedCount: curr.size - added.length - changed.length };
|
|
34
|
+
}
|
|
35
|
+
/** Format a SnapshotDiff as compact text for brain injection */
|
|
36
|
+
function formatDiff(diff) {
|
|
37
|
+
const lines = [];
|
|
38
|
+
if (diff.added.length)
|
|
39
|
+
lines.push('ADDED:', ...diff.added);
|
|
40
|
+
if (diff.removed.length)
|
|
41
|
+
lines.push('REMOVED:', ...diff.removed);
|
|
42
|
+
if (diff.changed.length)
|
|
43
|
+
lines.push('CHANGED:', ...diff.changed);
|
|
44
|
+
lines.push(`(${diff.unchangedCount} elements unchanged)`);
|
|
45
|
+
return lines.join('\n');
|
|
46
|
+
}
|
|
47
|
+
export const INTERACTIVE_ROLES = new Set([
|
|
48
|
+
'button', 'link', 'textbox', 'checkbox', 'radio',
|
|
49
|
+
'combobox', 'listbox', 'menuitem', 'menuitemcheckbox',
|
|
50
|
+
'menuitemradio', 'option', 'searchbox', 'slider',
|
|
51
|
+
'spinbutton', 'switch', 'tab', 'treeitem',
|
|
52
|
+
]);
|
|
53
|
+
/**
|
|
54
|
+
* Generate a short deterministic hash from role+name.
|
|
55
|
+
* Produces a 3-4 char hex string (e.g. "b3f", "1a2c").
|
|
56
|
+
*/
|
|
57
|
+
export function stableHash(role, name) {
|
|
58
|
+
const str = `${role}:${name}`;
|
|
59
|
+
let h = 0x811c9dc5; // FNV-1a offset basis
|
|
60
|
+
for (let i = 0; i < str.length; i++) {
|
|
61
|
+
h ^= str.charCodeAt(i);
|
|
62
|
+
h = Math.imul(h, 0x01000193); // FNV prime
|
|
63
|
+
}
|
|
64
|
+
// Take lower 14 bits -> 0-16383 -> 1-4 hex chars, prefix with role initial
|
|
65
|
+
const hex = ((h >>> 0) & 0x3fff).toString(16);
|
|
66
|
+
return `${role[0]}${hex}`;
|
|
67
|
+
}
|
|
68
|
+
export class AriaSnapshotHelper {
|
|
69
|
+
refMap = new Map();
|
|
70
|
+
/** Track how many times each base hash has been seen (for duplicate disambiguation) */
|
|
71
|
+
hashCounts = new Map();
|
|
72
|
+
/** Previous snapshot's parsed elements for diffing */
|
|
73
|
+
prevElements = new Map();
|
|
74
|
+
/** Current snapshot's parsed elements (populated during parseAriaSnapshot) */
|
|
75
|
+
currElements = new Map();
|
|
76
|
+
/** Last computed diff (undefined on first observe) */
|
|
77
|
+
lastDiff;
|
|
78
|
+
/** Clear refs -- call at the start of each observe() cycle */
|
|
79
|
+
reset() {
|
|
80
|
+
this.refMap.clear();
|
|
81
|
+
this.hashCounts.clear();
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Import refs and elements from an external source (e.g., CDP snapshot).
|
|
85
|
+
*
|
|
86
|
+
* Populates the internal refMap and currElements so that resolveLocator()
|
|
87
|
+
* and getDiff() work identically to the Playwright ariaSnapshot path.
|
|
88
|
+
*/
|
|
89
|
+
importCdpRefs(refMap, elements) {
|
|
90
|
+
// Save previous elements for diffing
|
|
91
|
+
this.prevElements = this.currElements;
|
|
92
|
+
this.currElements = new Map(elements);
|
|
93
|
+
// Import refs into our refMap
|
|
94
|
+
for (const [refId, entry] of refMap) {
|
|
95
|
+
this.refMap.set(refId, { role: entry.role, name: entry.name });
|
|
96
|
+
}
|
|
97
|
+
// Compute diff
|
|
98
|
+
if (this.prevElements.size > 0) {
|
|
99
|
+
this.lastDiff = diffSnapshots(this.prevElements, this.currElements);
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
this.lastDiff = undefined;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Build an accessibility tree snapshot with stable ref IDs.
|
|
107
|
+
*
|
|
108
|
+
* Calls `page.locator('body').ariaSnapshot()` and parses the YAML output,
|
|
109
|
+
* assigning deterministic `[ref=XX]` to interactive/named elements.
|
|
110
|
+
*/
|
|
111
|
+
async buildSnapshot(page) {
|
|
112
|
+
const rawSnapshot = await page.locator('body').ariaSnapshot({ timeout: 10_000 })
|
|
113
|
+
.catch(() => '');
|
|
114
|
+
if (!rawSnapshot.trim())
|
|
115
|
+
return '(empty page)';
|
|
116
|
+
// Save previous elements before parsing new snapshot
|
|
117
|
+
this.prevElements = this.currElements;
|
|
118
|
+
this.currElements = new Map();
|
|
119
|
+
let snapshot = this.parseAriaSnapshot(rawSnapshot);
|
|
120
|
+
// Compute diff after parsing (currElements is now populated)
|
|
121
|
+
if (this.prevElements.size > 0) {
|
|
122
|
+
this.lastDiff = diffSnapshots(this.prevElements, this.currElements);
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
this.lastDiff = undefined;
|
|
126
|
+
}
|
|
127
|
+
// Augment with data-testid elements -- helps LLMs identify elements
|
|
128
|
+
// that have no accessible name (e.g., icon-only buttons)
|
|
129
|
+
const testIds = await page.evaluate(() => {
|
|
130
|
+
const INTERACTIVE = new Set(['button', 'input', 'textarea', 'select', 'a']);
|
|
131
|
+
const elements = document.querySelectorAll('[data-testid]');
|
|
132
|
+
return Array.from(elements)
|
|
133
|
+
.filter(el => INTERACTIVE.has(el.tagName.toLowerCase()) || el.getAttribute('role'))
|
|
134
|
+
.slice(0, 30) // Limit to avoid token bloat
|
|
135
|
+
.map(el => ({
|
|
136
|
+
testId: el.getAttribute('data-testid') || '',
|
|
137
|
+
tag: el.tagName.toLowerCase(),
|
|
138
|
+
text: (el.textContent || '').trim().slice(0, 40),
|
|
139
|
+
disabled: el.disabled || false,
|
|
140
|
+
}));
|
|
141
|
+
}).catch(() => []);
|
|
142
|
+
if (testIds.length > 0) {
|
|
143
|
+
snapshot += '\n\nDATA-TESTID SELECTORS (use [data-testid="..."] as selector):';
|
|
144
|
+
for (const el of testIds) {
|
|
145
|
+
const disabled = el.disabled ? ' [disabled]' : '';
|
|
146
|
+
const text = el.text ? ` "${el.text}"` : '';
|
|
147
|
+
snapshot += `\n [data-testid="${el.testId}"] ${el.tag}${text}${disabled}`;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return snapshot;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Resolve a selector to a Playwright Locator.
|
|
154
|
+
*
|
|
155
|
+
* - `@b3f` -> resolved from ref map via getByRole()
|
|
156
|
+
* - Standard selectors (CSS, text=, role=, [data-testid=...]) -> page.locator()
|
|
157
|
+
*/
|
|
158
|
+
resolveLocator(page, selector) {
|
|
159
|
+
if (selector.startsWith('@')) {
|
|
160
|
+
const refId = selector.slice(1);
|
|
161
|
+
const entry = this.refMap.get(refId);
|
|
162
|
+
if (entry) {
|
|
163
|
+
const roleLocator = page.getByRole(entry.role, {
|
|
164
|
+
name: entry.name,
|
|
165
|
+
exact: entry.name.length > 0,
|
|
166
|
+
});
|
|
167
|
+
// Suffixed refs (e.g., t31b3_2) represent the Nth duplicate of a role+name combo.
|
|
168
|
+
// Use nth() to target the correct instance instead of always picking first().
|
|
169
|
+
const suffixMatch = refId.match(/_(\d+)$/);
|
|
170
|
+
if (suffixMatch) {
|
|
171
|
+
const index = parseInt(suffixMatch[1], 10);
|
|
172
|
+
return roleLocator.nth(index);
|
|
173
|
+
}
|
|
174
|
+
return roleLocator.first();
|
|
175
|
+
}
|
|
176
|
+
// Ref not found in current snapshot -- throw with available refs for
|
|
177
|
+
// auto-retry or Brain feedback
|
|
178
|
+
throw new StaleRefError(refId, [...this.refMap.keys()]);
|
|
179
|
+
}
|
|
180
|
+
return page.locator(selector).first();
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Parse Playwright's ARIA snapshot YAML and assign stable ref IDs.
|
|
184
|
+
*
|
|
185
|
+
* Ref IDs are deterministic hashes of role+name, so the same element gets
|
|
186
|
+
* the same ref across observations. Duplicates get index suffixes (_1, _2).
|
|
187
|
+
*
|
|
188
|
+
* Input:
|
|
189
|
+
* - button "Sign in"
|
|
190
|
+
* - textbox "Email" [value=""]
|
|
191
|
+
* - list "Nav":
|
|
192
|
+
* - link "Home"
|
|
193
|
+
*
|
|
194
|
+
* Output:
|
|
195
|
+
* - button "Sign in" [ref=b2a1]
|
|
196
|
+
* - textbox "Email" [ref=t3f0] [value=""]
|
|
197
|
+
* - list "Nav" [ref=l1b2]:
|
|
198
|
+
* - link "Home" [ref=la3c]
|
|
199
|
+
*/
|
|
200
|
+
parseAriaSnapshot(raw) {
|
|
201
|
+
const lines = raw.split('\n');
|
|
202
|
+
const result = [];
|
|
203
|
+
for (const line of lines) {
|
|
204
|
+
const match = line.match(/^(\s*-\s+)(\w+)(?:\s+"([^"]*)")?(.*)$/);
|
|
205
|
+
if (!match) {
|
|
206
|
+
result.push(line);
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
const [, indent, role, name, rest] = match;
|
|
210
|
+
if (INTERACTIVE_ROLES.has(role) || (name && role !== 'text')) {
|
|
211
|
+
const baseHash = stableHash(role, name || '');
|
|
212
|
+
// Track duplicates: first occurrence gets bare hash, subsequent get _N suffix
|
|
213
|
+
const count = this.hashCounts.get(baseHash) || 0;
|
|
214
|
+
this.hashCounts.set(baseHash, count + 1);
|
|
215
|
+
const refId = count === 0 ? baseHash : `${baseHash}_${count}`;
|
|
216
|
+
this.refMap.set(refId, { role, name: name || '' });
|
|
217
|
+
// Extract value for diff tracking
|
|
218
|
+
const valueMatch = rest.match(/\[value="([^"]*)"\]/);
|
|
219
|
+
this.currElements.set(refId, {
|
|
220
|
+
ref: refId,
|
|
221
|
+
role,
|
|
222
|
+
name: name || '',
|
|
223
|
+
value: valueMatch ? valueMatch[1] : undefined,
|
|
224
|
+
});
|
|
225
|
+
const cleanRest = rest.replace(/:$/, '').trim();
|
|
226
|
+
const colon = rest.trimEnd().endsWith(':') ? ':' : '';
|
|
227
|
+
const nameStr = name ? ` "${name}"` : '';
|
|
228
|
+
const refStr = ` [ref=${refId}]`;
|
|
229
|
+
const propsStr = cleanRest ? ` ${cleanRest}` : '';
|
|
230
|
+
result.push(`${indent}${role}${nameStr}${refStr}${propsStr}${colon}`);
|
|
231
|
+
}
|
|
232
|
+
else {
|
|
233
|
+
result.push(line);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
return result.join('\n');
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Get the diff from the last buildSnapshot() call.
|
|
240
|
+
* Returns undefined on the first call (no previous snapshot to diff against).
|
|
241
|
+
*/
|
|
242
|
+
getDiff() {
|
|
243
|
+
if (!this.lastDiff)
|
|
244
|
+
return undefined;
|
|
245
|
+
return formatDiff(this.lastDiff);
|
|
246
|
+
}
|
|
247
|
+
/** Get the raw structured diff (for programmatic use) */
|
|
248
|
+
getRawDiff() {
|
|
249
|
+
return this.lastDiff;
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Format a snapshot in compact form: one line per element, ref-first,
|
|
253
|
+
* flat (no nesting), ~50-60% fewer tokens.
|
|
254
|
+
*
|
|
255
|
+
* Full format:
|
|
256
|
+
* - button "Sign in" [ref=b2a1]
|
|
257
|
+
* - textbox "Email" [ref=t3f0] [value=""]
|
|
258
|
+
* - list "Nav" [ref=l1b2]:
|
|
259
|
+
* - link "Home" [ref=la3c]
|
|
260
|
+
*
|
|
261
|
+
* Compact format:
|
|
262
|
+
* @b2a1 button "Sign in"
|
|
263
|
+
* @t3f0 textbox "Email" val=""
|
|
264
|
+
* @l1b2 list "Nav"
|
|
265
|
+
* @la3c link "Home"
|
|
266
|
+
*/
|
|
267
|
+
static formatCompact(snapshot) {
|
|
268
|
+
const lines = snapshot.split('\n');
|
|
269
|
+
const compact = [];
|
|
270
|
+
for (const line of lines) {
|
|
271
|
+
const match = line.match(/\s*-\s+(\w+)\s+"([^"]*)"?\s*\[ref=(\w+)\](.*)?$/);
|
|
272
|
+
if (!match)
|
|
273
|
+
continue;
|
|
274
|
+
const [, role, name, ref, rest] = match;
|
|
275
|
+
const valueMatch = rest?.match(/\[value="([^"]*)"\]/);
|
|
276
|
+
const value = valueMatch ? ` val="${valueMatch[1]}"` : '';
|
|
277
|
+
compact.push(`@${ref} ${role} "${name}"${value}`);
|
|
278
|
+
}
|
|
279
|
+
return compact.join('\n');
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Typed error for stale ref detection -- allows runner to catch specifically
|
|
284
|
+
* and auto-retry with a fresh observation.
|
|
285
|
+
*/
|
|
286
|
+
export class StaleRefError extends Error {
|
|
287
|
+
staleRef;
|
|
288
|
+
availableRefs;
|
|
289
|
+
constructor(staleRef, availableRefs) {
|
|
290
|
+
super(`Ref "@${staleRef}" not found in current snapshot ` +
|
|
291
|
+
`(available: ${availableRefs.join(', ') || 'none'}). ` +
|
|
292
|
+
`Use a ref from the CURRENT observation.`);
|
|
293
|
+
this.name = 'StaleRefError';
|
|
294
|
+
this.staleRef = staleRef;
|
|
295
|
+
this.availableRefs = availableRefs;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Dismiss blocking overlays (dialogs, modals, Vite errors).
|
|
300
|
+
* Shared between drivers that operate on a Playwright page.
|
|
301
|
+
*
|
|
302
|
+
* Returns 'clicked' if a close button was found and clicked,
|
|
303
|
+
* 'found' if an overlay exists but no close button was found (Escape pressed),
|
|
304
|
+
* or false if no overlay was detected.
|
|
305
|
+
*/
|
|
306
|
+
export async function dismissOverlays(page) {
|
|
307
|
+
const result = await page.evaluate(() => {
|
|
308
|
+
const dialog = document.querySelector('[role="dialog"]');
|
|
309
|
+
if (dialog) {
|
|
310
|
+
const closeByLabel = dialog.querySelector('button[aria-label="Close"]');
|
|
311
|
+
if (closeByLabel) {
|
|
312
|
+
closeByLabel.click();
|
|
313
|
+
return 'clicked';
|
|
314
|
+
}
|
|
315
|
+
const btns = dialog.querySelectorAll('button');
|
|
316
|
+
for (const btn of btns) {
|
|
317
|
+
const text = (btn.textContent || '').toLowerCase().trim();
|
|
318
|
+
if (text === 'close' || text.includes('cancel') || text.includes('maybe later') || text.includes('dismiss') || text.includes('skip')) {
|
|
319
|
+
btn.click();
|
|
320
|
+
return 'clicked';
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
return 'found'; // Dialog found but no close button -- needs Escape
|
|
324
|
+
}
|
|
325
|
+
const overlay = document.querySelector('div.fixed.inset-0[class*="z-"]');
|
|
326
|
+
if (overlay) {
|
|
327
|
+
const closeBtn = overlay.querySelector('button[aria-label="Close"]');
|
|
328
|
+
if (closeBtn) {
|
|
329
|
+
closeBtn.click();
|
|
330
|
+
return 'clicked';
|
|
331
|
+
}
|
|
332
|
+
return 'found';
|
|
333
|
+
}
|
|
334
|
+
const viteOverlay = document.querySelector('vite-error-overlay');
|
|
335
|
+
if (viteOverlay) {
|
|
336
|
+
viteOverlay.remove();
|
|
337
|
+
return 'clicked';
|
|
338
|
+
}
|
|
339
|
+
return false;
|
|
340
|
+
});
|
|
341
|
+
if (result === 'clicked') {
|
|
342
|
+
// Close button handled it -- just wait for animation, no Escape needed
|
|
343
|
+
await page.waitForTimeout(300);
|
|
344
|
+
}
|
|
345
|
+
else if (result === 'found') {
|
|
346
|
+
// Overlay detected but no close button -- try Escape as fallback
|
|
347
|
+
await page.waitForTimeout(300);
|
|
348
|
+
await page.keyboard.press('Escape');
|
|
349
|
+
await page.waitForTimeout(200);
|
|
350
|
+
}
|
|
351
|
+
// result === false: no overlay, no action needed
|
|
352
|
+
return result;
|
|
353
|
+
}
|
|
354
|
+
//# sourceMappingURL=snapshot.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"snapshot.js","sourceRoot":"","sources":["../../src/drivers/snapshot.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Driver interface - abstraction over browser automation
|
|
3
|
+
*/
|
|
4
|
+
import type { Action, PageState } from '../types.js';
|
|
5
|
+
export interface ActionResult {
|
|
6
|
+
success: boolean;
|
|
7
|
+
error?: string;
|
|
8
|
+
/** Data returned by the action (e.g., runScript result) */
|
|
9
|
+
data?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface ResourceBlockingOptions {
|
|
12
|
+
/** Block image loading (png, jpg, gif, svg, webp, ico, etc.) */
|
|
13
|
+
blockImages?: boolean;
|
|
14
|
+
/** Block media loading (video, audio) */
|
|
15
|
+
blockMedia?: boolean;
|
|
16
|
+
/** Block analytics/tracking scripts */
|
|
17
|
+
blockAnalytics?: boolean;
|
|
18
|
+
/** Custom URL patterns to block (matched via url.includes()) */
|
|
19
|
+
blockPatterns?: string[];
|
|
20
|
+
}
|
|
21
|
+
export interface Driver {
|
|
22
|
+
/** Get current page state (DOM snapshot, optionally screenshot) */
|
|
23
|
+
observe(): Promise<PageState>;
|
|
24
|
+
/** Execute an action */
|
|
25
|
+
execute(action: Action): Promise<ActionResult>;
|
|
26
|
+
/** Get the underlying Playwright page (if available) */
|
|
27
|
+
getPage?(): import('playwright').Page | undefined;
|
|
28
|
+
/** Take a screenshot on demand */
|
|
29
|
+
screenshot?(): Promise<Buffer>;
|
|
30
|
+
/** Best-effort href inspection for a selector before executing a click */
|
|
31
|
+
inspectSelectorHref?(selector: string): Promise<string | undefined>;
|
|
32
|
+
/** Optional run-time diagnostics for startup and browser/session setup */
|
|
33
|
+
getDiagnostics?(): Record<string, unknown>;
|
|
34
|
+
/** Close/cleanup the driver */
|
|
35
|
+
close?(): Promise<void>;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/drivers/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAErD,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2DAA2D;IAC3D,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,uBAAuB;IACtC,gEAAgE;IAChE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,yCAAyC;IACzC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,uCAAuC;IACvC,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,gEAAgE;IAChE,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,MAAM;IACrB,mEAAmE;IACnE,OAAO,IAAI,OAAO,CAAC,SAAS,CAAC,CAAC;IAE9B,wBAAwB;IACxB,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IAE/C,wDAAwD;IACxD,OAAO,CAAC,IAAI,OAAO,YAAY,EAAE,IAAI,GAAG,SAAS,CAAC;IAElD,kCAAkC;IAClC,UAAU,CAAC,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAE/B,0EAA0E;IAC1E,mBAAmB,CAAC,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAEpE,0EAA0E;IAC1E,cAAc,CAAC,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAE3C,+BAA+B;IAC/B,KAAK,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACzB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/drivers/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env-loader.d.ts","sourceRoot":"","sources":["../src/env-loader.ts"],"names":[],"mappings":"AAGA,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,WAAyB,GAAG,IAAI,CAWxF"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
import * as path from 'node:path';
|
|
3
|
+
export function loadLocalEnvFiles(startDir, files = ['.env.local', '.env']) {
|
|
4
|
+
for (const file of files) {
|
|
5
|
+
const filePath = path.join(startDir, file);
|
|
6
|
+
if (!fs.existsSync(filePath))
|
|
7
|
+
continue;
|
|
8
|
+
const parsed = parseEnvFile(fs.readFileSync(filePath, 'utf-8'));
|
|
9
|
+
for (const [key, value] of Object.entries(parsed)) {
|
|
10
|
+
if (!(key in process.env)) {
|
|
11
|
+
process.env[key] = value;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function parseEnvFile(contents) {
|
|
17
|
+
const out = {};
|
|
18
|
+
for (const rawLine of contents.split(/\r?\n/)) {
|
|
19
|
+
const line = rawLine.trim();
|
|
20
|
+
if (!line || line.startsWith('#'))
|
|
21
|
+
continue;
|
|
22
|
+
const match = line.match(/^([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)$/);
|
|
23
|
+
if (!match)
|
|
24
|
+
continue;
|
|
25
|
+
const key = match[1];
|
|
26
|
+
let value = match[2] ?? '';
|
|
27
|
+
if ((value.startsWith('"') && value.endsWith('"')) ||
|
|
28
|
+
(value.startsWith("'") && value.endsWith("'"))) {
|
|
29
|
+
value = value.slice(1, -1);
|
|
30
|
+
}
|
|
31
|
+
out[key] = value;
|
|
32
|
+
}
|
|
33
|
+
return out;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=env-loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env-loader.js","sourceRoot":"","sources":["../src/env-loader.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,MAAM,UAAU,iBAAiB,CAAC,QAAgB,EAAE,KAAK,GAAG,CAAC,YAAY,EAAE,MAAM,CAAC;IAChF,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QAC3C,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC;YAAE,SAAS;QACvC,MAAM,MAAM,GAAG,YAAY,CAAC,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC;QAChE,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YAClD,IAAI,CAAC,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC1B,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;YAC3B,CAAC;QACH,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAS,YAAY,CAAC,QAAgB;IACpC,MAAM,GAAG,GAA2B,EAAE,CAAC;IACvC,KAAK,MAAM,OAAO,IAAI,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;QAC9C,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;QAC5B,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,SAAS;QAC5C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,uCAAuC,CAAC,CAAC;QAClE,IAAI,CAAC,KAAK;YAAE,SAAS;QACrB,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACrB,IAAI,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC3B,IACE,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;YAC9C,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,EAC9C,CAAC;YACD,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAC7B,CAAC;QACD,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IACnB,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Slack payload formatter for WebhookSink.
|
|
3
|
+
*
|
|
4
|
+
* Transforms WebhookPayload into Slack Block Kit format for incoming webhooks.
|
|
5
|
+
* Use with: new WebhookSink({ url: SLACK_WEBHOOK_URL, formatPayload: slackFormatter })
|
|
6
|
+
*/
|
|
7
|
+
import type { WebhookPayload } from '../artifacts/webhook-sink.js';
|
|
8
|
+
interface SlackBlock {
|
|
9
|
+
type: string;
|
|
10
|
+
text?: {
|
|
11
|
+
type: string;
|
|
12
|
+
text: string;
|
|
13
|
+
emoji?: boolean;
|
|
14
|
+
};
|
|
15
|
+
elements?: Array<{
|
|
16
|
+
type: string;
|
|
17
|
+
text: string;
|
|
18
|
+
emoji?: boolean;
|
|
19
|
+
}>;
|
|
20
|
+
fields?: Array<{
|
|
21
|
+
type: string;
|
|
22
|
+
text: string;
|
|
23
|
+
}>;
|
|
24
|
+
}
|
|
25
|
+
interface SlackMessage {
|
|
26
|
+
text: string;
|
|
27
|
+
blocks?: SlackBlock[];
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Format a WebhookPayload as a Slack Block Kit message.
|
|
31
|
+
*
|
|
32
|
+
* - `artifact` events: compact one-liner with test ID and artifact type
|
|
33
|
+
* - `suite:complete` events: rich summary with pass/fail counts and test list
|
|
34
|
+
*/
|
|
35
|
+
export declare function slackFormatter(payload: WebhookPayload): SlackMessage;
|
|
36
|
+
export {};
|
|
37
|
+
//# sourceMappingURL=slack.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slack.d.ts","sourceRoot":"","sources":["../../src/formatters/slack.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAEnE,UAAU,UAAU;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IACvD,QAAQ,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAClE,MAAM,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAChD;AAED,UAAU,YAAY;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,UAAU,EAAE,CAAC;CACvB;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,cAAc,GAAG,YAAY,CAMpE"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Slack payload formatter for WebhookSink.
|
|
3
|
+
*
|
|
4
|
+
* Transforms WebhookPayload into Slack Block Kit format for incoming webhooks.
|
|
5
|
+
* Use with: new WebhookSink({ url: SLACK_WEBHOOK_URL, formatPayload: slackFormatter })
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Format a WebhookPayload as a Slack Block Kit message.
|
|
9
|
+
*
|
|
10
|
+
* - `artifact` events: compact one-liner with test ID and artifact type
|
|
11
|
+
* - `suite:complete` events: rich summary with pass/fail counts and test list
|
|
12
|
+
*/
|
|
13
|
+
export function slackFormatter(payload) {
|
|
14
|
+
if (payload.event === 'suite:complete') {
|
|
15
|
+
return formatSuiteComplete(payload);
|
|
16
|
+
}
|
|
17
|
+
return formatArtifact(payload);
|
|
18
|
+
}
|
|
19
|
+
function formatSuiteComplete(payload) {
|
|
20
|
+
const { manifest, summary } = payload;
|
|
21
|
+
const testIds = [...new Set(manifest.map((e) => e.testId).filter((id) => id !== 'suite'))];
|
|
22
|
+
const hasSummary = summary && summary.total > 0;
|
|
23
|
+
const passed = summary?.passed ?? 0;
|
|
24
|
+
const failed = summary?.failed ?? 0;
|
|
25
|
+
const total = summary?.total ?? testIds.length;
|
|
26
|
+
const allPassed = failed === 0 && passed > 0;
|
|
27
|
+
const icon = allPassed ? ':white_check_mark:' : ':x:';
|
|
28
|
+
const headline = allPassed
|
|
29
|
+
? `${icon} All ${total} tests passed`
|
|
30
|
+
: `${icon} ${passed}/${total} passed, ${failed} failed`;
|
|
31
|
+
const blocks = [
|
|
32
|
+
{
|
|
33
|
+
type: 'header',
|
|
34
|
+
text: { type: 'plain_text', text: 'browser-agent-driver', emoji: true },
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
type: 'section',
|
|
38
|
+
text: { type: 'mrkdwn', text: headline },
|
|
39
|
+
},
|
|
40
|
+
];
|
|
41
|
+
if (hasSummary) {
|
|
42
|
+
blocks.push({
|
|
43
|
+
type: 'section',
|
|
44
|
+
fields: [
|
|
45
|
+
{ type: 'mrkdwn', text: `*Passed:* ${passed}` },
|
|
46
|
+
{ type: 'mrkdwn', text: `*Failed:* ${failed}` },
|
|
47
|
+
{ type: 'mrkdwn', text: `*Total:* ${total}` },
|
|
48
|
+
],
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
// List test IDs
|
|
52
|
+
if (testIds.length > 0 && testIds.length <= 20) {
|
|
53
|
+
const testList = testIds.map((id) => `\`${id}\``).join(', ');
|
|
54
|
+
blocks.push({
|
|
55
|
+
type: 'section',
|
|
56
|
+
text: { type: 'mrkdwn', text: `*Tests:* ${testList}` },
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
// Artifacts count
|
|
60
|
+
const screenshotCount = manifest.filter((e) => e.type === 'screenshot').length;
|
|
61
|
+
const reportCount = manifest.filter((e) => e.type.startsWith('report-')).length;
|
|
62
|
+
if (screenshotCount > 0 || reportCount > 0) {
|
|
63
|
+
const parts = [];
|
|
64
|
+
if (reportCount > 0)
|
|
65
|
+
parts.push(`${reportCount} reports`);
|
|
66
|
+
if (screenshotCount > 0)
|
|
67
|
+
parts.push(`${screenshotCount} screenshots`);
|
|
68
|
+
blocks.push({
|
|
69
|
+
type: 'context',
|
|
70
|
+
elements: [{ type: 'mrkdwn', text: `Artifacts: ${parts.join(', ')}` }],
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
text: headline.replace(/:[a-z_]+:/g, '').trim(), // fallback text without emoji
|
|
75
|
+
blocks,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
function formatArtifact(payload) {
|
|
79
|
+
const text = `*${payload.type}* \`${payload.name}\` for test \`${payload.testId}\` (${formatBytes(payload.sizeBytes)})`;
|
|
80
|
+
return {
|
|
81
|
+
text: `${payload.type}: ${payload.name} for ${payload.testId}`,
|
|
82
|
+
blocks: [
|
|
83
|
+
{
|
|
84
|
+
type: 'section',
|
|
85
|
+
text: { type: 'mrkdwn', text },
|
|
86
|
+
},
|
|
87
|
+
],
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
function formatBytes(bytes) {
|
|
91
|
+
if (bytes < 1024)
|
|
92
|
+
return `${bytes}B`;
|
|
93
|
+
if (bytes < 1024 * 1024)
|
|
94
|
+
return `${(bytes / 1024).toFixed(1)}KB`;
|
|
95
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=slack.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slack.js","sourceRoot":"","sources":["../../src/formatters/slack.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAgBH;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,OAAuB;IACpD,IAAI,OAAO,CAAC,KAAK,KAAK,gBAAgB,EAAE,CAAC;QACvC,OAAO,mBAAmB,CAAC,OAAO,CAAC,CAAC;IACtC,CAAC;IAED,OAAO,cAAc,CAAC,OAAO,CAAC,CAAC;AACjC,CAAC;AAED,SAAS,mBAAmB,CAAC,OAA6D;IACxF,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;IACtC,MAAM,OAAO,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;IAE3F,MAAM,UAAU,GAAG,OAAO,IAAI,OAAO,CAAC,KAAK,GAAG,CAAC,CAAC;IAChD,MAAM,MAAM,GAAG,OAAO,EAAE,MAAM,IAAI,CAAC,CAAC;IACpC,MAAM,MAAM,GAAG,OAAO,EAAE,MAAM,IAAI,CAAC,CAAC;IACpC,MAAM,KAAK,GAAG,OAAO,EAAE,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC;IAE/C,MAAM,SAAS,GAAG,MAAM,KAAK,CAAC,IAAI,MAAM,GAAG,CAAC,CAAC;IAC7C,MAAM,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,KAAK,CAAC;IACtD,MAAM,QAAQ,GAAG,SAAS;QACxB,CAAC,CAAC,GAAG,IAAI,QAAQ,KAAK,eAAe;QACrC,CAAC,CAAC,GAAG,IAAI,IAAI,MAAM,IAAI,KAAK,YAAY,MAAM,SAAS,CAAC;IAE1D,MAAM,MAAM,GAAiB;QAC3B;YACE,IAAI,EAAE,QAAQ;YACd,IAAI,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,sBAAsB,EAAE,KAAK,EAAE,IAAI,EAAE;SACxE;QACD;YACE,IAAI,EAAE,SAAS;YACf,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE;SACzC;KACF,CAAC;IAEF,IAAI,UAAU,EAAE,CAAC;QACf,MAAM,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,SAAS;YACf,MAAM,EAAE;gBACN,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,aAAa,MAAM,EAAE,EAAE;gBAC/C,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,aAAa,MAAM,EAAE,EAAE;gBAC/C,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,KAAK,EAAE,EAAE;aAC9C;SACF,CAAC,CAAC;IACL,CAAC;IAED,gBAAgB;IAChB,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC;QAC/C,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC7D,MAAM,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,SAAS;YACf,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,QAAQ,EAAE,EAAE;SACvD,CAAC,CAAC;IACL,CAAC;IAED,kBAAkB;IAClB,MAAM,eAAe,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,YAAY,CAAC,CAAC,MAAM,CAAC;IAC/E,MAAM,WAAW,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC;IAChF,IAAI,eAAe,GAAG,CAAC,IAAI,WAAW,GAAG,CAAC,EAAE,CAAC;QAC3C,MAAM,KAAK,GAAa,EAAE,CAAC;QAC3B,IAAI,WAAW,GAAG,CAAC;YAAE,KAAK,CAAC,IAAI,CAAC,GAAG,WAAW,UAAU,CAAC,CAAC;QAC1D,IAAI,eAAe,GAAG,CAAC;YAAE,KAAK,CAAC,IAAI,CAAC,GAAG,eAAe,cAAc,CAAC,CAAC;QACtE,MAAM,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,SAAS;YACf,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,cAAc,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;SACvE,CAAC,CAAC;IACL,CAAC;IAED,OAAO;QACL,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,8BAA8B;QAC/E,MAAM;KACP,CAAC;AACJ,CAAC;AAED,SAAS,cAAc,CAAC,OAAuD;IAC7E,MAAM,IAAI,GAAG,IAAI,OAAO,CAAC,IAAI,OAAO,OAAO,CAAC,IAAI,iBAAiB,OAAO,CAAC,MAAM,OAAO,WAAW,CAAC,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC;IACxH,OAAO;QACL,IAAI,EAAE,GAAG,OAAO,CAAC,IAAI,KAAK,OAAO,CAAC,IAAI,QAAQ,OAAO,CAAC,MAAM,EAAE;QAC9D,MAAM,EAAE;YACN;gBACE,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE;aAC/B;SACF;KACF,CAAC;AACJ,CAAC;AAED,SAAS,WAAW,CAAC,KAAa;IAChC,IAAI,KAAK,GAAG,IAAI;QAAE,OAAO,GAAG,KAAK,GAAG,CAAC;IACrC,IAAI,KAAK,GAAG,IAAI,GAAG,IAAI;QAAE,OAAO,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;IACjE,OAAO,GAAG,CAAC,KAAK,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;AACnD,CAAC"}
|