@skyramp/mcp 0.1.8 → 0.2.0-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/build/playwright/registerPlaywrightTools.js +12 -0
  2. package/build/playwright/traceRecordingPrompt.js +15 -0
  3. package/build/prompts/test-recommendation/diffExecutionPlan.js +31 -0
  4. package/build/prompts/test-recommendation/recommendationSections.js +1 -2
  5. package/build/prompts/test-recommendation/test-recommendation-prompt.test.js +94 -0
  6. package/build/prompts/testbot/testbot-prompts.js +115 -11
  7. package/build/prompts/testbot/testbot-prompts.test.js +79 -0
  8. package/build/resources/testbotResource.js +1 -1
  9. package/build/services/ScenarioGenerationService.integration.test.js +158 -0
  10. package/build/services/ScenarioGenerationService.js +36 -3
  11. package/build/services/ScenarioGenerationService.test.js +158 -22
  12. package/build/tools/generate-tests/generateBatchScenarioRestTool.js +16 -4
  13. package/build/tools/generate-tests/generateIntegrationRestTool.js +2 -0
  14. package/build/tools/generate-tests/generateUIRestTool.js +2 -0
  15. package/build/tools/test-management/analyzeChangesTool.js +7 -1
  16. package/build/utils/routeParsers.js +12 -0
  17. package/node_modules/playwright/ThirdPartyNotices.txt +6 -6
  18. package/node_modules/playwright/lib/dom-analyzer/analyze.js +111 -0
  19. package/node_modules/playwright/lib/dom-analyzer/blueprint.js +1161 -0
  20. package/node_modules/playwright/lib/dom-analyzer/blueprint.test.js +396 -0
  21. package/node_modules/playwright/lib/dom-analyzer/blueprintCache.js +57 -0
  22. package/node_modules/playwright/lib/dom-analyzer/blueprintCache.test.js +57 -0
  23. package/node_modules/playwright/lib/dom-analyzer/blueprintDiff.js +250 -0
  24. package/node_modules/playwright/lib/dom-analyzer/blueprintDiff.test.js +298 -0
  25. package/node_modules/playwright/lib/dom-analyzer/crawler.js +384 -0
  26. package/node_modules/playwright/lib/dom-analyzer/curatedWidgets.js +73 -0
  27. package/node_modules/playwright/lib/dom-analyzer/dynamicId.js +43 -0
  28. package/node_modules/playwright/lib/dom-analyzer/dynamicId.test.js +85 -0
  29. package/node_modules/playwright/lib/dom-analyzer/fingerprint.js +90 -0
  30. package/node_modules/playwright/lib/dom-analyzer/fingerprint.test.js +231 -0
  31. package/node_modules/playwright/lib/dom-analyzer/fingerprintAblation.fixtures.js +145 -0
  32. package/node_modules/playwright/lib/dom-analyzer/fingerprintAblation.test.js +41 -0
  33. package/node_modules/playwright/lib/dom-analyzer/graph.js +36 -0
  34. package/node_modules/playwright/lib/dom-analyzer/liveFingerprints.js +43 -0
  35. package/node_modules/playwright/lib/dom-analyzer/logicalNameResolver.js +72 -0
  36. package/node_modules/playwright/lib/dom-analyzer/logicalNameResolver.test.js +182 -0
  37. package/node_modules/playwright/lib/dom-analyzer/sectionGrouper.js +169 -0
  38. package/node_modules/playwright/lib/dom-analyzer/sectionGrouper.test.js +269 -0
  39. package/node_modules/playwright/lib/dom-analyzer/serialization.js +75 -0
  40. package/node_modules/playwright/lib/dom-analyzer/slug.js +30 -0
  41. package/node_modules/playwright/lib/dom-analyzer/slug.test.js +84 -0
  42. package/node_modules/playwright/lib/dom-analyzer/widgetContract.js +127 -0
  43. package/node_modules/playwright/lib/dom-analyzer/widgetContract.test.js +212 -0
  44. package/node_modules/playwright/lib/mcp/browser/browserContextFactory.js +3 -1
  45. package/node_modules/playwright/lib/mcp/browser/config.js +1 -1
  46. package/node_modules/playwright/lib/mcp/browser/context.js +17 -1
  47. package/node_modules/playwright/lib/mcp/browser/tab.js +38 -0
  48. package/node_modules/playwright/lib/mcp/browser/tools/domAnalyzer.js +261 -0
  49. package/node_modules/playwright/lib/mcp/browser/tools/keyboard.js +3 -3
  50. package/node_modules/playwright/lib/mcp/browser/tools/pageBlueprint.js +129 -0
  51. package/node_modules/playwright/lib/mcp/browser/tools/pageBlueprint.test.js +137 -0
  52. package/node_modules/playwright/lib/mcp/browser/tools/sitemap.js +226 -0
  53. package/node_modules/playwright/lib/mcp/browser/tools/snapshot.js +2 -2
  54. package/node_modules/playwright/lib/mcp/browser/tools/widgetContract.js +168 -0
  55. package/node_modules/playwright/lib/mcp/browser/tools.js +6 -0
  56. package/node_modules/playwright/lib/mcp/skyramp/traceRecordingBackend.js +52 -12
  57. package/node_modules/playwright/lib/mcp/test/skyRampExport.js +64 -13
  58. package/node_modules/playwright/package.json +1 -1
  59. package/node_modules/playwright/skyramp-playwright-1.58.2-skyramp.8.9.3.tgz +0 -0
  60. package/package.json +2 -2
@@ -0,0 +1,231 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") {
10
+ for (let key of __getOwnPropNames(from))
11
+ if (!__hasOwnProp.call(to, key) && key !== except)
12
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
13
+ }
14
+ return to;
15
+ };
16
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
17
+ // If the importer is in node compatibility mode or this is not an ESM
18
+ // file that has been converted to a CommonJS file using a Babel-
19
+ // compatible transform (i.e. "__esModule" has not been set), then set
20
+ // "default" to the CommonJS "module.exports" for node compatibility.
21
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
22
+ mod
23
+ ));
24
+ var fs = __toESM(require("fs"));
25
+ var path = __toESM(require("path"));
26
+ var import_fingerprint = require("./fingerprint");
27
+ const cases = [];
28
+ function test(name, run) {
29
+ cases.push({ name, run });
30
+ }
31
+ function assertEqual(actual, expected, msg) {
32
+ const a = JSON.stringify(actual);
33
+ const e = JSON.stringify(expected);
34
+ if (a !== e)
35
+ throw new Error(`${msg ?? "assertEqual"} \u2014 expected ${e}, got ${a}`);
36
+ }
37
+ test("normalizeClasses: keeps BEM-ish classes", () => {
38
+ assertEqual(
39
+ (0, import_fingerprint.normalizeClasses)("vue-treeselect vue-treeselect__menu vue-treeselect--single"),
40
+ "vue-treeselect vue-treeselect--single vue-treeselect__menu"
41
+ );
42
+ });
43
+ test("normalizeClasses: keeps framework-prefixed classes", () => {
44
+ assertEqual(
45
+ (0, import_fingerprint.normalizeClasses)("MuiSelect-root MuiSelect-standard"),
46
+ "MuiSelect-root MuiSelect-standard"
47
+ );
48
+ });
49
+ test("normalizeClasses: drops tailwind utilities", () => {
50
+ assertEqual(
51
+ (0, import_fingerprint.normalizeClasses)("vue-treeselect bg-red-500 p-4 hover:text-white"),
52
+ "vue-treeselect"
53
+ );
54
+ });
55
+ test("normalizeClasses: drops CSS-module hashed suffixes", () => {
56
+ assertEqual(
57
+ (0, import_fingerprint.normalizeClasses)("button_abc123 vue-treeselect"),
58
+ "vue-treeselect"
59
+ );
60
+ });
61
+ test("normalizeClasses: drops numeric-index suffixes", () => {
62
+ assertEqual(
63
+ (0, import_fingerprint.normalizeClasses)("item-1 item-2 vue-treeselect"),
64
+ "vue-treeselect"
65
+ );
66
+ });
67
+ test("normalizeClasses: drops state tokens", () => {
68
+ assertEqual(
69
+ (0, import_fingerprint.normalizeClasses)("vue-treeselect is-active is-open expanded"),
70
+ "vue-treeselect"
71
+ );
72
+ });
73
+ test("normalizeClasses: framework prefix beats numeric-suffix deny-list", () => {
74
+ assertEqual(
75
+ (0, import_fingerprint.normalizeClasses)("MuiSelect-root MuiSelect-123 ant-select-item-1"),
76
+ "MuiSelect-123 MuiSelect-root ant-select-item-1"
77
+ );
78
+ });
79
+ test("normalizeClasses: framework prefix beats tailwind-shape deny-list", () => {
80
+ assertEqual(
81
+ (0, import_fingerprint.normalizeClasses)("data-radix-border-blue"),
82
+ "data-radix-border-blue"
83
+ );
84
+ });
85
+ test("normalizeClasses: empty string returns empty string", () => {
86
+ assertEqual((0, import_fingerprint.normalizeClasses)(""), "");
87
+ });
88
+ test("normalizeClasses: sorts alphabetically", () => {
89
+ assertEqual(
90
+ (0, import_fingerprint.normalizeClasses)("vue-treeselect__menu vue-treeselect"),
91
+ "vue-treeselect vue-treeselect__menu"
92
+ );
93
+ });
94
+ test("normalizeClasses: deduplicates", () => {
95
+ assertEqual(
96
+ (0, import_fingerprint.normalizeClasses)("vue-treeselect vue-treeselect"),
97
+ "vue-treeselect"
98
+ );
99
+ });
100
+ test("computeFingerprintFromInput: identical input yields identical hash", () => {
101
+ const input = {
102
+ root: { tag: "div", role: "combobox", ariaHasPopup: "", classPattern: "vue-treeselect", dataAttrKeys: [] },
103
+ descendants: [],
104
+ portal: null
105
+ };
106
+ assertEqual((0, import_fingerprint.computeFingerprintFromInput)(input), (0, import_fingerprint.computeFingerprintFromInput)(input));
107
+ });
108
+ test("computeFingerprintFromInput: different tag yields different hash", () => {
109
+ const a = {
110
+ root: { tag: "div", role: "combobox", ariaHasPopup: "", classPattern: "", dataAttrKeys: [] },
111
+ descendants: [],
112
+ portal: null
113
+ };
114
+ const b = {
115
+ root: { tag: "button", role: "combobox", ariaHasPopup: "", classPattern: "", dataAttrKeys: [] },
116
+ descendants: [],
117
+ portal: null
118
+ };
119
+ if ((0, import_fingerprint.computeFingerprintFromInput)(a) === (0, import_fingerprint.computeFingerprintFromInput)(b))
120
+ throw new Error("expected different hashes");
121
+ });
122
+ test("computeFingerprintFromInput: same descendant order produces same hash (stability)", () => {
123
+ const d1 = { tag: "div", role: "", ariaHasPopup: "", classPattern: "a", dataAttrKeys: [] };
124
+ const d2 = { tag: "div", role: "", ariaHasPopup: "", classPattern: "b", dataAttrKeys: [] };
125
+ const a = {
126
+ root: { tag: "div", role: "combobox", ariaHasPopup: "", classPattern: "", dataAttrKeys: [] },
127
+ descendants: [d1, d2],
128
+ portal: null
129
+ };
130
+ const b = {
131
+ root: { tag: "div", role: "combobox", ariaHasPopup: "", classPattern: "", dataAttrKeys: [] },
132
+ descendants: [d1, d2],
133
+ // same order
134
+ portal: null
135
+ };
136
+ assertEqual((0, import_fingerprint.computeFingerprintFromInput)(a), (0, import_fingerprint.computeFingerprintFromInput)(b));
137
+ });
138
+ test("computeFingerprintFromInput: descendant order DOES affect hash (order is part of the fingerprint)", () => {
139
+ const d1 = { tag: "div", role: "", ariaHasPopup: "", classPattern: "a", dataAttrKeys: [] };
140
+ const d2 = { tag: "div", role: "", ariaHasPopup: "", classPattern: "b", dataAttrKeys: [] };
141
+ const a = {
142
+ root: { tag: "div", role: "combobox", ariaHasPopup: "", classPattern: "", dataAttrKeys: [] },
143
+ descendants: [d1, d2],
144
+ portal: null
145
+ };
146
+ const b = {
147
+ root: { tag: "div", role: "combobox", ariaHasPopup: "", classPattern: "", dataAttrKeys: [] },
148
+ descendants: [d2, d1],
149
+ // reversed
150
+ portal: null
151
+ };
152
+ if ((0, import_fingerprint.computeFingerprintFromInput)(a) === (0, import_fingerprint.computeFingerprintFromInput)(b))
153
+ throw new Error("expected different hashes when descendant order differs");
154
+ });
155
+ test("computeFingerprintFromInput: returns 16 hex chars", () => {
156
+ const input = {
157
+ root: { tag: "div", role: "", ariaHasPopup: "", classPattern: "", dataAttrKeys: [] },
158
+ descendants: [],
159
+ portal: null
160
+ };
161
+ const hash = (0, import_fingerprint.computeFingerprintFromInput)(input);
162
+ if (!/^[0-9a-f]{16}$/.test(hash))
163
+ throw new Error(`expected 16-hex hash, got "${hash}"`);
164
+ });
165
+ test("computeFingerprintFromInput: null portal differs from populated portal", () => {
166
+ const portalTuple = { tag: "div", role: "", ariaHasPopup: "", classPattern: "data-radix-popper-content-wrapper", dataAttrKeys: [] };
167
+ const a = {
168
+ root: { tag: "button", role: "combobox", ariaHasPopup: "", classPattern: "", dataAttrKeys: [] },
169
+ descendants: [],
170
+ portal: null
171
+ };
172
+ const b = {
173
+ root: { tag: "button", role: "combobox", ariaHasPopup: "", classPattern: "", dataAttrKeys: [] },
174
+ descendants: [],
175
+ portal: portalTuple
176
+ };
177
+ if ((0, import_fingerprint.computeFingerprintFromInput)(a) === (0, import_fingerprint.computeFingerprintFromInput)(b))
178
+ throw new Error("expected different hashes");
179
+ });
180
+ test("drift detection: blueprint.ts inline rule constants match fingerprint.ts exports", () => {
181
+ const blueprintSrcPath = path.resolve(__dirname, "..", "..", "src", "dom-analyzer", "blueprint.ts");
182
+ const src = fs.readFileSync(blueprintSrcPath, "utf-8");
183
+ const beginMarker = "// INLINE_RULES_BEGIN";
184
+ const endMarker = "// INLINE_RULES_END";
185
+ const beginIdx = src.indexOf(beginMarker);
186
+ const endIdx = src.indexOf(endMarker, beginIdx);
187
+ if (beginIdx === -1 || endIdx === -1)
188
+ throw new Error(`blueprint.ts must contain ${beginMarker} / ${endMarker} markers around the inlined fingerprint rule constants`);
189
+ const newlineAfterBegin = src.indexOf("\n", beginIdx);
190
+ const block = src.slice(newlineAfterBegin + 1, endIdx);
191
+ const inlined = new Function(
192
+ block + "\nreturn { BEM_ISH, FRAMEWORK_PREFIXES, TAILWIND_UTILITY, CSS_MODULE_HASH, NUMERIC_INDEX_SUFFIX, STATE_TOKENS };"
193
+ )();
194
+ function regexEq(a, b, name) {
195
+ if (a.source !== b.source || a.flags !== b.flags)
196
+ throw new Error(`${name} drift: fingerprint.ts has /${a.source}/${a.flags}, blueprint.ts has /${b.source}/${b.flags}`);
197
+ }
198
+ function arrayEq(a, b, name) {
199
+ if (a.length !== b.length || a.some((v, i) => v !== b[i]))
200
+ throw new Error(`${name} drift: fingerprint.ts has ${JSON.stringify(a)}, blueprint.ts has ${JSON.stringify(b)}`);
201
+ }
202
+ function setEq(a, b, name) {
203
+ const aSorted = Array.from(a).sort();
204
+ const bSorted = Array.from(b).sort();
205
+ arrayEq(aSorted, bSorted, name);
206
+ }
207
+ regexEq(import_fingerprint.BEM_ISH, inlined.BEM_ISH, "BEM_ISH");
208
+ arrayEq(import_fingerprint.FRAMEWORK_PREFIXES, inlined.FRAMEWORK_PREFIXES, "FRAMEWORK_PREFIXES");
209
+ regexEq(import_fingerprint.TAILWIND_UTILITY, inlined.TAILWIND_UTILITY, "TAILWIND_UTILITY");
210
+ regexEq(import_fingerprint.CSS_MODULE_HASH, inlined.CSS_MODULE_HASH, "CSS_MODULE_HASH");
211
+ regexEq(import_fingerprint.NUMERIC_INDEX_SUFFIX, inlined.NUMERIC_INDEX_SUFFIX, "NUMERIC_INDEX_SUFFIX");
212
+ setEq(import_fingerprint.STATE_TOKENS, inlined.STATE_TOKENS, "STATE_TOKENS");
213
+ });
214
+ let failed = 0;
215
+ for (const { name, run } of cases) {
216
+ try {
217
+ run();
218
+ console.log(" \u2713", name);
219
+ } catch (e) {
220
+ failed++;
221
+ console.log(" \u2717", name);
222
+ console.log(" ", e.message);
223
+ }
224
+ }
225
+ if (failed > 0) {
226
+ console.log(`
227
+ ${failed}/${cases.length} failed`);
228
+ process.exit(1);
229
+ }
230
+ console.log(`
231
+ ${cases.length} passed`);
@@ -0,0 +1,145 @@
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 fingerprintAblation_fixtures_exports = {};
20
+ __export(fingerprintAblation_fixtures_exports, {
21
+ ABLATION_FIXTURES: () => ABLATION_FIXTURES
22
+ });
23
+ module.exports = __toCommonJS(fingerprintAblation_fixtures_exports);
24
+ const ABLATION_FIXTURES = [
25
+ {
26
+ name: "vue-treeselect",
27
+ description: "Vue-Treeselect combobox trigger (in-DOM custom control)",
28
+ input: {
29
+ root: { tag: "div", role: "combobox", ariaHasPopup: "listbox", classPattern: "vue-treeselect vue-treeselect--single", dataAttrKeys: [] },
30
+ descendants: [
31
+ { tag: "div", role: "", ariaHasPopup: "", classPattern: "vue-treeselect__control", dataAttrKeys: [] },
32
+ { tag: "div", role: "", ariaHasPopup: "", classPattern: "vue-treeselect__menu", dataAttrKeys: [] }
33
+ ],
34
+ portal: null
35
+ },
36
+ expectedHash: "d7e908c767fa68cd"
37
+ },
38
+ {
39
+ name: "radix-select",
40
+ description: "Radix Select trigger with portal popper",
41
+ input: {
42
+ root: { tag: "button", role: "combobox", ariaHasPopup: "listbox", classPattern: "", dataAttrKeys: ["data-radix-select-trigger"] },
43
+ descendants: [
44
+ { tag: "span", role: "", ariaHasPopup: "", classPattern: "", dataAttrKeys: ["data-radix-select-value"] }
45
+ ],
46
+ portal: { tag: "div", role: "", ariaHasPopup: "", classPattern: "", dataAttrKeys: ["data-radix-popper-content-wrapper"] }
47
+ },
48
+ expectedHash: "024c3db1d8f29870"
49
+ },
50
+ {
51
+ name: "stripe-card-number",
52
+ description: "Stripe CardNumberElement iframe",
53
+ input: {
54
+ root: { tag: "iframe", role: "", ariaHasPopup: "", classPattern: "", dataAttrKeys: [] },
55
+ descendants: [],
56
+ portal: null
57
+ },
58
+ expectedHash: "27114237c0e4a14a"
59
+ },
60
+ {
61
+ name: "mui-select",
62
+ description: "MUI Select trigger (placeholder for follow-up curated add)",
63
+ input: {
64
+ root: { tag: "div", role: "combobox", ariaHasPopup: "listbox", classPattern: "MuiSelect-root MuiSelect-standard", dataAttrKeys: [] },
65
+ descendants: [
66
+ { tag: "div", role: "", ariaHasPopup: "", classPattern: "MuiSelect-select", dataAttrKeys: [] }
67
+ ],
68
+ portal: null
69
+ },
70
+ expectedHash: "bb8e91d32ffd6aa1"
71
+ },
72
+ {
73
+ name: "antd-select",
74
+ description: "Ant Design Select trigger",
75
+ input: {
76
+ root: { tag: "div", role: "combobox", ariaHasPopup: "listbox", classPattern: "ant-select-selector", dataAttrKeys: [] },
77
+ descendants: [
78
+ { tag: "span", role: "", ariaHasPopup: "", classPattern: "ant-select-selection-item", dataAttrKeys: [] }
79
+ ],
80
+ portal: null
81
+ },
82
+ expectedHash: "6787396f9da6022e"
83
+ },
84
+ {
85
+ name: "headlessui-listbox",
86
+ description: "Headless UI Listbox trigger with portal",
87
+ input: {
88
+ root: { tag: "button", role: "combobox", ariaHasPopup: "listbox", classPattern: "", dataAttrKeys: ["data-headlessui-state"] },
89
+ descendants: [],
90
+ portal: { tag: "div", role: "listbox", ariaHasPopup: "", classPattern: "", dataAttrKeys: ["data-headlessui-state"] }
91
+ },
92
+ expectedHash: "6016cd2641c63075"
93
+ },
94
+ {
95
+ name: "native-button",
96
+ description: "Plain native button (should not normally be fingerprinted; included to verify low collision surface)",
97
+ input: {
98
+ root: { tag: "button", role: "button", ariaHasPopup: "", classPattern: "", dataAttrKeys: [] },
99
+ descendants: [],
100
+ portal: null
101
+ },
102
+ expectedHash: "15d8dd75a3c6eacf"
103
+ },
104
+ {
105
+ name: "vue-treeselect-multi",
106
+ description: "Vue-Treeselect in multi-select mode (separate fingerprint from single)",
107
+ input: {
108
+ root: { tag: "div", role: "combobox", ariaHasPopup: "listbox", classPattern: "vue-treeselect vue-treeselect--multi", dataAttrKeys: [] },
109
+ descendants: [
110
+ { tag: "div", role: "", ariaHasPopup: "", classPattern: "vue-treeselect__control", dataAttrKeys: [] }
111
+ ],
112
+ portal: null
113
+ },
114
+ expectedHash: "7af3161b147762a3"
115
+ },
116
+ {
117
+ name: "date-picker-custom",
118
+ description: "Generic custom date-picker (unrecognized; LLM-inference path target)",
119
+ input: {
120
+ root: { tag: "div", role: "combobox", ariaHasPopup: "dialog", classPattern: "", dataAttrKeys: [] },
121
+ descendants: [
122
+ { tag: "input", role: "textbox", ariaHasPopup: "", classPattern: "", dataAttrKeys: [] },
123
+ { tag: "button", role: "button", ariaHasPopup: "", classPattern: "", dataAttrKeys: [] }
124
+ ],
125
+ portal: null
126
+ },
127
+ expectedHash: "3e1cd8161b90817f"
128
+ },
129
+ {
130
+ name: "toast-live-region",
131
+ description: "ARIA-compliant live region for toasts",
132
+ input: {
133
+ root: { tag: "div", role: "status", ariaHasPopup: "", classPattern: "", dataAttrKeys: [] },
134
+ descendants: [
135
+ { tag: "div", role: "alert", ariaHasPopup: "", classPattern: "", dataAttrKeys: [] }
136
+ ],
137
+ portal: null
138
+ },
139
+ expectedHash: "3f1e5b1bc0523ba6"
140
+ }
141
+ ];
142
+ // Annotate the CommonJS export names for ESM import in node:
143
+ 0 && (module.exports = {
144
+ ABLATION_FIXTURES
145
+ });
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ var import_fingerprint = require("./fingerprint");
3
+ var import_fingerprintAblation = require("./fingerprintAblation.fixtures");
4
+ const PLACEHOLDER = "__REPLACE_AFTER_FIRST_RUN__";
5
+ const actual = import_fingerprintAblation.ABLATION_FIXTURES.map((entry) => ({
6
+ name: entry.name,
7
+ hash: (0, import_fingerprint.computeFingerprintFromInput)(entry.input),
8
+ expected: entry.expectedHash
9
+ }));
10
+ const placeholders = actual.filter((a) => a.expected === PLACEHOLDER);
11
+ const locked = actual.filter((a) => a.expected !== PLACEHOLDER);
12
+ let drifted = 0;
13
+ for (const a of locked) {
14
+ if (a.hash === a.expected) {
15
+ console.log(" \u2713", a.name, a.hash);
16
+ } else {
17
+ drifted++;
18
+ console.log(" \u2717", a.name);
19
+ console.log(" expected:", a.expected);
20
+ console.log(" got :", a.hash);
21
+ }
22
+ }
23
+ const uniq = new Set(actual.map((a) => a.hash));
24
+ if (uniq.size !== actual.length) {
25
+ drifted++;
26
+ console.log(" \u2717 COLLISION \u2014 two or more fixtures share the same fingerprint hash");
27
+ }
28
+ if (placeholders.length > 0) {
29
+ console.log("\nBootstrap mode \u2014 paste these hashes into fingerprintAblation.fixtures.ts:");
30
+ for (const a of placeholders)
31
+ console.log(` ${a.name}: '${a.hash}',`);
32
+ console.log("\nThen re-run the test. (Note: locked entries above were still verified; any \u2717 are real drift and must be investigated, not re-bootstrapped.)");
33
+ process.exit(1);
34
+ }
35
+ if (drifted > 0) {
36
+ console.log(`
37
+ ${drifted} failed`);
38
+ process.exit(1);
39
+ }
40
+ console.log(`
41
+ ${actual.length} passed`);
@@ -0,0 +1,36 @@
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 graph_exports = {};
20
+ __export(graph_exports, {
21
+ urlToFilename: () => urlToFilename
22
+ });
23
+ module.exports = __toCommonJS(graph_exports);
24
+ function urlToFilename(url) {
25
+ try {
26
+ const parsed = new URL(url);
27
+ const path = (parsed.hostname + parsed.pathname).replace(/\/+$/, "").replace(/[^a-zA-Z0-9._-]/g, "__");
28
+ return path || "index";
29
+ } catch {
30
+ return url.replace(/[^a-zA-Z0-9._-]/g, "__") || "page";
31
+ }
32
+ }
33
+ // Annotate the CommonJS export names for ESM import in node:
34
+ 0 && (module.exports = {
35
+ urlToFilename
36
+ });
@@ -0,0 +1,43 @@
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 liveFingerprints_exports = {};
20
+ __export(liveFingerprints_exports, {
21
+ fp: () => fp,
22
+ liveFingerprintNames: () => liveFingerprintNames
23
+ });
24
+ module.exports = __toCommonJS(liveFingerprints_exports);
25
+ const LIVE_FINGERPRINTS = {
26
+ "vue-treeselect": "b83426fe818e01ee",
27
+ "radix-select": "738a5387548e9319",
28
+ "stripe-frame": "74e8e04695fbc142"
29
+ };
30
+ function fp(name) {
31
+ const hash = LIVE_FINGERPRINTS[name];
32
+ if (!hash)
33
+ throw new Error(`live fingerprint '${name}' not found in liveFingerprints.ts`);
34
+ return hash;
35
+ }
36
+ function liveFingerprintNames() {
37
+ return Object.keys(LIVE_FINGERPRINTS);
38
+ }
39
+ // Annotate the CommonJS export names for ESM import in node:
40
+ 0 && (module.exports = {
41
+ fp,
42
+ liveFingerprintNames
43
+ });
@@ -0,0 +1,72 @@
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 logicalNameResolver_exports = {};
20
+ __export(logicalNameResolver_exports, {
21
+ resolveCollisions: () => resolveCollisions
22
+ });
23
+ module.exports = __toCommonJS(logicalNameResolver_exports);
24
+ var import_slug = require("./slug");
25
+ function resolveCollisions(inputs) {
26
+ const groupsByKey = /* @__PURE__ */ new Map();
27
+ inputs.forEach((inp, idx) => {
28
+ const key = `${inp.sectionName}::${inp.initialName}`;
29
+ if (!groupsByKey.has(key)) groupsByKey.set(key, []);
30
+ groupsByKey.get(key).push(idx);
31
+ });
32
+ const output = new Array(inputs.length);
33
+ const slugOrNull = (s) => {
34
+ if (!s) return null;
35
+ const slugged = (0, import_slug.slug)(s);
36
+ return slugged ? slugged : null;
37
+ };
38
+ for (const [, indices] of groupsByKey.entries()) {
39
+ if (indices.length === 1) {
40
+ output[indices[0]] = inputs[indices[0]].initialName;
41
+ continue;
42
+ }
43
+ const candidateNames = indices.map((i) => {
44
+ const inp = inputs[i];
45
+ const testIdSlug = slugOrNull(inp.testId);
46
+ if (testIdSlug) return `${testIdSlug}_${inp.initialName}`;
47
+ const stableIdSlug = slugOrNull(inp.stableId);
48
+ if (stableIdSlug) return `${stableIdSlug}_${inp.initialName}`;
49
+ const ancestorSlug = slugOrNull(inp.nearestAncestorId);
50
+ if (ancestorSlug) return `${ancestorSlug}_${inp.initialName}`;
51
+ return null;
52
+ });
53
+ const nonNull = candidateNames.filter((n) => n !== null);
54
+ const hasDuplicates = new Set(nonNull).size !== nonNull.length;
55
+ const anyNull = candidateNames.some((n) => n === null);
56
+ if (anyNull || hasDuplicates) {
57
+ indices.forEach((idx, posWithinGroup) => {
58
+ const inp = inputs[idx];
59
+ output[idx] = `${inp.sectionName}_${inp.initialName}_${posWithinGroup + 1}`;
60
+ });
61
+ } else {
62
+ indices.forEach((idx, k) => {
63
+ output[idx] = candidateNames[k];
64
+ });
65
+ }
66
+ }
67
+ return output;
68
+ }
69
+ // Annotate the CommonJS export names for ESM import in node:
70
+ 0 && (module.exports = {
71
+ resolveCollisions
72
+ });