@veolab/discoverylab 1.2.1 → 1.3.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 (160) hide show
  1. package/.mcp.json +2 -2
  2. package/README.md +182 -0
  3. package/dist/{chunk-TAODYZ52.js → chunk-3QRQEDWR.js} +510 -213
  4. package/dist/{chunk-L4SA5F5W.js → chunk-4L76GPRC.js} +1162 -58
  5. package/dist/chunk-6EGBXRDK.js +30 -0
  6. package/dist/{chunk-I6YD3QFM.js → chunk-FIL7IWEL.js} +5 -3
  7. package/dist/{chunk-4KLG6DDE.js → chunk-FNUN7EPB.js} +6 -6
  8. package/dist/chunk-GAKEFJ5T.js +481 -0
  9. package/dist/chunk-LB3RNE3O.js +109 -0
  10. package/dist/chunk-N6JJ2RGV.js +2680 -0
  11. package/dist/{chunk-XUKWS2CE.js → chunk-VRM42PML.js} +3546 -926
  12. package/dist/{chunk-TJ3H23LL.js → chunk-VVIOB362.js} +3 -1
  13. package/dist/{chunk-W3WJGYR6.js → chunk-XFVDP332.js} +8 -2
  14. package/dist/{chunk-QJXXHOV7.js → chunk-XKX6NBHF.js} +5 -1
  15. package/dist/cli.js +405 -11
  16. package/dist/{db-ADBEBNH6.js → db-6WLEVKUV.js} +3 -1
  17. package/dist/esvp-GSISVXLC.js +52 -0
  18. package/dist/esvp-mobile-GC7MAGMI.js +20 -0
  19. package/dist/index.d.ts +123 -1
  20. package/dist/index.html +11689 -8690
  21. package/dist/index.js +67 -11
  22. package/dist/{ocr-UTWC7537.js → ocr-QDYNCSPE.js} +1 -1
  23. package/dist/{playwright-R7Y5HREH.js → playwright-VZ7PXDC5.js} +2 -2
  24. package/dist/runtime/esvp-host-runtime/darwin-arm64/esvp-host-runtime +0 -0
  25. package/dist/runtime/esvp-host-runtime/manifest.json +10 -0
  26. package/dist/{server-3FBHBA7L.js → server-6N3KIEGP.js} +2 -1
  27. package/dist/server-FO3UVUZU.js +22 -0
  28. package/dist/{setup-27CQAX6K.js → setup-2SQC5UHJ.js} +4 -3
  29. package/dist/{tools-L6PKKQPY.js → tools-OCRMOQ4U.js} +63 -8
  30. package/package.json +36 -5
  31. package/dist/chunk-22OCFYHG.js +0 -6283
  32. package/dist/chunk-24VARQVO.js +0 -7818
  33. package/dist/chunk-2OGZX6C4.js +0 -588
  34. package/dist/chunk-2WCNIFRO.js +0 -6191
  35. package/dist/chunk-43U6UYV7.js +0 -590
  36. package/dist/chunk-4H2E3K2G.js +0 -7638
  37. package/dist/chunk-4MS6YW2B.js +0 -6490
  38. package/dist/chunk-4NNTRJOI.js +0 -7791
  39. package/dist/chunk-5F76VWME.js +0 -6397
  40. package/dist/chunk-5NEFN42O.js +0 -7791
  41. package/dist/chunk-63MEQ6UH.js +0 -7673
  42. package/dist/chunk-6H3NXFX3.js +0 -6861
  43. package/dist/chunk-7IDQLLBW.js +0 -311
  44. package/dist/chunk-7NP64TGJ.js +0 -6822
  45. package/dist/chunk-AATLY4KT.js +0 -6505
  46. package/dist/chunk-C7QUR7XX.js +0 -6397
  47. package/dist/chunk-CGKCE6MC.js +0 -6279
  48. package/dist/chunk-D25V6IWE.js +0 -6487
  49. package/dist/chunk-EQOZSXAT.js +0 -6822
  50. package/dist/chunk-FPHD7HSQ.js +0 -6812
  51. package/dist/chunk-GGJJUCFK.js +0 -7160
  52. package/dist/chunk-GLHOY3NN.js +0 -7805
  53. package/dist/chunk-GML5MKQA.js +0 -6398
  54. package/dist/chunk-GOL6FUJL.js +0 -6045
  55. package/dist/chunk-GSWHWEYC.js +0 -1346
  56. package/dist/chunk-HDKEQOF5.js +0 -7788
  57. package/dist/chunk-HZGSWVVS.js +0 -7111
  58. package/dist/chunk-IGZ5TICZ.js +0 -334
  59. package/dist/chunk-IRKQG33A.js +0 -7054
  60. package/dist/chunk-JFTBF4JR.js +0 -6040
  61. package/dist/chunk-JVLVBPUJ.js +0 -6180
  62. package/dist/chunk-JY3KC67R.js +0 -6504
  63. package/dist/chunk-KUFBCBNJ.js +0 -6815
  64. package/dist/chunk-KV7KDJ43.js +0 -7639
  65. package/dist/chunk-L5IJZV5F.js +0 -6822
  66. package/dist/chunk-MFFPQLU4.js +0 -7102
  67. package/dist/chunk-MJS2YKNR.js +0 -6397
  68. package/dist/chunk-MN6LCZHZ.js +0 -1320
  69. package/dist/chunk-NBAUZ7X2.js +0 -1336
  70. package/dist/chunk-NDBW6ELQ.js +0 -7638
  71. package/dist/chunk-O2HBSDI2.js +0 -6175
  72. package/dist/chunk-OFFIUYMG.js +0 -6341
  73. package/dist/chunk-OVCQGF2J.js +0 -1321
  74. package/dist/chunk-P4S7ZY6G.js +0 -7638
  75. package/dist/chunk-PBHUHSC3.js +0 -6002
  76. package/dist/chunk-PC4LR4ZI.js +0 -6359
  77. package/dist/chunk-PMTGGZ7R.js +0 -6397
  78. package/dist/chunk-PTXSB3UV.js +0 -497
  79. package/dist/chunk-PYUCY3U6.js +0 -1340
  80. package/dist/chunk-RDZDSOAL.js +0 -7750
  81. package/dist/chunk-RLW2OI2L.js +0 -6383
  82. package/dist/chunk-RUGHHO4K.js +0 -6395
  83. package/dist/chunk-SIOQVM2E.js +0 -6819
  84. package/dist/chunk-SR67SRIT.js +0 -1336
  85. package/dist/chunk-SSRXIO2V.js +0 -6822
  86. package/dist/chunk-SWSEKFON.js +0 -6487
  87. package/dist/chunk-TBG76CYG.js +0 -6395
  88. package/dist/chunk-V3CBINLD.js +0 -6812
  89. package/dist/chunk-VPYSLEGM.js +0 -6710
  90. package/dist/chunk-VY3BLXBW.js +0 -329
  91. package/dist/chunk-WTFOGVJQ.js +0 -6365
  92. package/dist/chunk-X64SFUT5.js +0 -6099
  93. package/dist/chunk-XIBF5LBD.js +0 -6395
  94. package/dist/chunk-Y5VDMSYC.js +0 -6701
  95. package/dist/chunk-YUBL36H4.js +0 -6605
  96. package/dist/chunk-YWVXFVSW.js +0 -6456
  97. package/dist/chunk-ZXZACOLD.js +0 -6822
  98. package/dist/db-IWIL65EX.js +0 -33
  99. package/dist/gridCompositor-ENKLFPWR.js +0 -409
  100. package/dist/playwright-A3OGSDRG.js +0 -38
  101. package/dist/playwright-ATDC4NYW.js +0 -38
  102. package/dist/playwright-E6EUFIJG.js +0 -38
  103. package/dist/server-2DXLKLFM.js +0 -13
  104. package/dist/server-2ICEWJVK.js +0 -13
  105. package/dist/server-2MQV3FNY.js +0 -13
  106. package/dist/server-2NGD7GE3.js +0 -13
  107. package/dist/server-2VKO76UK.js +0 -14
  108. package/dist/server-3BK2VFU7.js +0 -13
  109. package/dist/server-4LDOB3NX.js +0 -13
  110. package/dist/server-4YI44KDR.js +0 -13
  111. package/dist/server-64XMXA5P.js +0 -13
  112. package/dist/server-6IPHVUYT.js +0 -14
  113. package/dist/server-73ORHMJN.js +0 -13
  114. package/dist/server-73P7M3QB.js +0 -14
  115. package/dist/server-BPVRW5LJ.js +0 -14
  116. package/dist/server-BW4RKZIX.js +0 -13
  117. package/dist/server-CFS5SM5K.js +0 -13
  118. package/dist/server-DX7VYHHM.js +0 -13
  119. package/dist/server-F3YPX6ET.js +0 -13
  120. package/dist/server-FUXTR33I.js +0 -13
  121. package/dist/server-G2SY3DOS.js +0 -13
  122. package/dist/server-G32U7VOQ.js +0 -13
  123. package/dist/server-IOOZK4NP.js +0 -14
  124. package/dist/server-J52LMTBT.js +0 -13
  125. package/dist/server-JG7UKFGK.js +0 -14
  126. package/dist/server-JSCHEBOD.js +0 -13
  127. package/dist/server-K6KC4ZOM.js +0 -13
  128. package/dist/server-KJVRGWFE.js +0 -13
  129. package/dist/server-LCPB2L4U.js +0 -13
  130. package/dist/server-M7LDYKAJ.js +0 -13
  131. package/dist/server-MKVK6ZQQ.js +0 -13
  132. package/dist/server-MU52LCXT.js +0 -13
  133. package/dist/server-NM5CKDUU.js +0 -13
  134. package/dist/server-NPZN3FWO.js +0 -14
  135. package/dist/server-O5FIAHSY.js +0 -14
  136. package/dist/server-OESJUEYC.js +0 -13
  137. package/dist/server-ONSKQO4W.js +0 -13
  138. package/dist/server-P27BZXBL.js +0 -14
  139. package/dist/server-Q4FBWQUA.js +0 -13
  140. package/dist/server-RNQ7VUAL.js +0 -13
  141. package/dist/server-S6B5WUBT.js +0 -14
  142. package/dist/server-SRYNSGSP.js +0 -14
  143. package/dist/server-SUN3W2YK.js +0 -13
  144. package/dist/server-UA62LHZB.js +0 -13
  145. package/dist/server-UJB44EW5.js +0 -13
  146. package/dist/server-X3TLP6DX.js +0 -14
  147. package/dist/server-YT2UGEZK.js +0 -13
  148. package/dist/server-ZBPQ33V6.js +0 -14
  149. package/dist/setup-AQX4JQVR.js +0 -17
  150. package/dist/setup-EQTU7FI6.js +0 -17
  151. package/dist/tools-2KPB37GK.js +0 -178
  152. package/dist/tools-3H6IOWXV.js +0 -178
  153. package/dist/tools-3KYHPDCJ.js +0 -178
  154. package/dist/tools-75BAPCUM.js +0 -177
  155. package/dist/tools-BUVCUCRL.js +0 -178
  156. package/dist/tools-HDNODRS6.js +0 -178
  157. package/dist/tools-HP5MNY3D.js +0 -177
  158. package/dist/tools-N5N2IO7V.js +0 -178
  159. package/dist/tools-NFJEZ2FF.js +0 -177
  160. package/dist/tools-TLCKABUW.js +0 -178
@@ -1,588 +0,0 @@
1
- import {
2
- PROJECTS_DIR
3
- } from "./chunk-TJ3H23LL.js";
4
-
5
- // src/core/testing/playwright.ts
6
- import { exec, spawn } from "child_process";
7
- import { promisify } from "util";
8
- import * as fs from "fs";
9
- import * as path from "path";
10
- import { createRequire } from "module";
11
-
12
- // src/core/security/sensitiveInput.ts
13
- function normalizeHint(value) {
14
- return typeof value === "string" ? value.trim().toLowerCase() : "";
15
- }
16
- function buildHintText(context) {
17
- if (!context) return "";
18
- return [
19
- normalizeHint(context.actionType),
20
- normalizeHint(context.selector),
21
- normalizeHint(context.description),
22
- normalizeHint(context.fieldHint)
23
- ].filter(Boolean).join(" ");
24
- }
25
- function looksLikeEmail(value) {
26
- return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
27
- }
28
- function looksLikeCpf(value) {
29
- const digits = value.replace(/\D/g, "");
30
- return digits.length === 11 && /^(\d{3}\.?\d{3}\.?\d{3}-?\d{2})$/.test(value);
31
- }
32
- function looksLikeCnpj(value) {
33
- const digits = value.replace(/\D/g, "");
34
- return digits.length === 14 && /^(\d{2}\.?\d{3}\.?\d{3}\/?\d{4}-?\d{2})$/.test(value);
35
- }
36
- function looksLikePhone(value) {
37
- const digits = value.replace(/\D/g, "");
38
- if (digits.length < 10 || digits.length > 13) return false;
39
- return /^\+?[\d\s().-]+$/.test(value);
40
- }
41
- function looksLikeMaskedPassword(value) {
42
- return /^[*•●·]+$/.test(value);
43
- }
44
- function looksLikeNumericCode(value) {
45
- const digits = value.replace(/\D/g, "");
46
- return digits.length >= 4 && digits.length <= 8 && digits === value.trim();
47
- }
48
- function hasAny(hint, patterns) {
49
- return patterns.some((pattern) => pattern.test(hint));
50
- }
51
- function redactSensitiveTestInput(rawValue, context) {
52
- if (typeof rawValue !== "string") return rawValue;
53
- const value = rawValue.trim();
54
- if (!value) return rawValue;
55
- const hint = buildHintText(context);
56
- const digits = value.replace(/\D/g, "");
57
- const passwordHint = hasAny(hint, [/\bpassword\b/, /\bsenha\b/, /\bpasscode\b/, /\bsecret\b/]);
58
- if (passwordHint || looksLikeMaskedPassword(value)) {
59
- return "${PASSWORD}";
60
- }
61
- const tokenHint = hasAny(hint, [/\btoken\b/, /\bapi[-_ ]?key\b/, /\bbearer\b/]);
62
- if (tokenHint && value.length >= 6) {
63
- return "${SECRET}";
64
- }
65
- const emailHint = hasAny(hint, [/\bemail\b/, /\be-mail\b/]);
66
- if (emailHint || looksLikeEmail(value)) {
67
- return "${EMAIL}";
68
- }
69
- const cpfHint = hasAny(hint, [/\bcpf\b/, /\bdocumento\b/]);
70
- if (cpfHint && digits.length === 11 || looksLikeCpf(value)) {
71
- return "${CPF}";
72
- }
73
- const cnpjHint = hasAny(hint, [/\bcnpj\b/]);
74
- if (cnpjHint && digits.length === 14 || looksLikeCnpj(value)) {
75
- return "${CNPJ}";
76
- }
77
- const otpHint = hasAny(hint, [/\botp\b/, /\b2fa\b/, /\bpin\b/, /\bverification\b/, /\bcodigo\b/, /\bcódigo\b/, /\bcode\b/]);
78
- if (otpHint && looksLikeNumericCode(value)) {
79
- return hint.includes("pin") ? "${PIN}" : "${OTP_CODE}";
80
- }
81
- const phoneHint = hasAny(hint, [/\bphone\b/, /\btelefone\b/, /\bcelular\b/, /\bwhats(app)?\b/, /\btel\b/]);
82
- if (phoneHint && digits.length >= 8 && digits.length <= 13 || looksLikePhone(value)) {
83
- return "${PHONE}";
84
- }
85
- const usernameHint = hasAny(hint, [/\busername\b/, /\buser\b/, /\blogin\b/]);
86
- if (usernameHint) {
87
- return "${USERNAME}";
88
- }
89
- return rawValue;
90
- }
91
- function redactQuotedStringsInText(rawText, context) {
92
- if (typeof rawText !== "string" || !rawText) return rawText;
93
- return rawText.replace(/"([^"]*)"/g, (_match, quoted) => {
94
- const redacted = redactSensitiveTestInput(String(quoted), context);
95
- return `"${redacted}"`;
96
- });
97
- }
98
-
99
- // src/core/testing/playwright.ts
100
- var execAsync = promisify(exec);
101
- var requireFromHere = createRequire(import.meta.url);
102
- function resolveInstalledPlaywrightVersion() {
103
- try {
104
- const pkgPath = requireFromHere.resolve("playwright/package.json");
105
- const raw = fs.readFileSync(pkgPath, "utf-8");
106
- const pkg = JSON.parse(raw);
107
- return typeof pkg.version === "string" && pkg.version.trim() ? pkg.version.trim() : "installed";
108
- } catch {
109
- return null;
110
- }
111
- }
112
- async function isPlaywrightInstalled() {
113
- return !!resolveInstalledPlaywrightVersion();
114
- }
115
- async function getPlaywrightVersion() {
116
- return resolveInstalledPlaywrightVersion();
117
- }
118
- async function installPlaywrightBrowsers() {
119
- try {
120
- await execAsync("npx playwright install");
121
- return { success: true };
122
- } catch (error) {
123
- return {
124
- success: false,
125
- error: error instanceof Error ? error.message : String(error)
126
- };
127
- }
128
- }
129
- var BrowserDevices = {
130
- "Desktop Chrome": {
131
- name: "Desktop Chrome",
132
- viewport: { width: 1280, height: 720 },
133
- userAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
134
- deviceScaleFactor: 1,
135
- isMobile: false,
136
- hasTouch: false
137
- },
138
- "Desktop Safari": {
139
- name: "Desktop Safari",
140
- viewport: { width: 1280, height: 720 },
141
- userAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Safari/605.1.15",
142
- deviceScaleFactor: 1,
143
- isMobile: false,
144
- hasTouch: false
145
- },
146
- "iPhone 15 Pro": {
147
- name: "iPhone 15 Pro",
148
- viewport: { width: 393, height: 852 },
149
- userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1",
150
- deviceScaleFactor: 3,
151
- isMobile: true,
152
- hasTouch: true
153
- },
154
- "iPhone 14": {
155
- name: "iPhone 14",
156
- viewport: { width: 390, height: 844 },
157
- userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Mobile/15E148 Safari/604.1",
158
- deviceScaleFactor: 3,
159
- isMobile: true,
160
- hasTouch: true
161
- },
162
- "Pixel 8": {
163
- name: "Pixel 8",
164
- viewport: { width: 412, height: 915 },
165
- userAgent: "Mozilla/5.0 (Linux; Android 14; Pixel 8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36",
166
- deviceScaleFactor: 2.625,
167
- isMobile: true,
168
- hasTouch: true
169
- },
170
- "iPad Pro 12.9": {
171
- name: "iPad Pro 12.9",
172
- viewport: { width: 1024, height: 1366 },
173
- userAgent: "Mozilla/5.0 (iPad; CPU OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1",
174
- deviceScaleFactor: 2,
175
- isMobile: true,
176
- hasTouch: true
177
- }
178
- };
179
- function listBrowserDevices() {
180
- return Object.values(BrowserDevices);
181
- }
182
- function getBrowserDevice(name) {
183
- return BrowserDevices[name] || null;
184
- }
185
- function generatePlaywrightScript(script) {
186
- const { name, baseURL, viewport, actions } = script;
187
- const lines = [
188
- "import { test, expect } from '@playwright/test';",
189
- ""
190
- ];
191
- lines.push(`test('${name || "Generated Test"}', async ({ page }) => {`);
192
- if (viewport) {
193
- lines.push(` await page.setViewportSize({ width: ${viewport.width}, height: ${viewport.height} });`);
194
- }
195
- if (baseURL) {
196
- lines.push(` await page.goto('${baseURL}');`);
197
- }
198
- for (const action of actions) {
199
- const code = generateActionCode(action);
200
- if (code) {
201
- lines.push(` ${code}`);
202
- }
203
- }
204
- lines.push("});");
205
- lines.push("");
206
- return lines.join("\n");
207
- }
208
- function generateActionCode(action) {
209
- const { type, selector, value, url, key, options } = action;
210
- switch (type) {
211
- case "goto":
212
- return `await page.goto('${url || ""}');`;
213
- case "click":
214
- if (!selector) return null;
215
- return `await page.click('${selector}');`;
216
- case "fill":
217
- if (!selector) return null;
218
- return `await page.fill('${selector}', '${redactSensitiveTestInput(String(value || ""), { actionType: "fill", selector })}');`;
219
- case "type":
220
- if (!selector) return null;
221
- return `await page.type('${selector}', '${redactSensitiveTestInput(String(value || ""), { actionType: "type", selector })}');`;
222
- case "press":
223
- if (!selector) return null;
224
- return `await page.press('${selector}', '${key || "Enter"}');`;
225
- case "check":
226
- if (!selector) return null;
227
- return `await page.check('${selector}');`;
228
- case "uncheck":
229
- if (!selector) return null;
230
- return `await page.uncheck('${selector}');`;
231
- case "selectOption":
232
- if (!selector) return null;
233
- return `await page.selectOption('${selector}', '${value || ""}');`;
234
- case "hover":
235
- if (!selector) return null;
236
- return `await page.hover('${selector}');`;
237
- case "focus":
238
- if (!selector) return null;
239
- return `await page.focus('${selector}');`;
240
- case "screenshot":
241
- return `await page.screenshot({ path: '${value || "screenshot.png"}' });`;
242
- case "wait":
243
- return `await page.waitForTimeout(${value || 1e3});`;
244
- case "waitForSelector":
245
- if (!selector) return null;
246
- return `await page.waitForSelector('${selector}');`;
247
- case "waitForURL":
248
- return `await page.waitForURL('${url || ""}');`;
249
- case "expectVisible":
250
- if (!selector) return null;
251
- return `await expect(page.locator('${selector}')).toBeVisible();`;
252
- case "expectHidden":
253
- if (!selector) return null;
254
- return `await expect(page.locator('${selector}')).toBeHidden();`;
255
- case "expectText":
256
- if (!selector) return null;
257
- return `await expect(page.locator('${selector}')).toHaveText('${value || ""}');`;
258
- case "expectURL":
259
- return `await expect(page).toHaveURL('${url || ""}');`;
260
- case "expectTitle":
261
- return `await expect(page).toHaveTitle('${value || ""}');`;
262
- case "scroll":
263
- if (selector) {
264
- return `await page.locator('${selector}').scrollIntoViewIfNeeded();`;
265
- }
266
- return `await page.evaluate(() => window.scrollBy(0, ${value || 500}));`;
267
- case "evaluate":
268
- return `await page.evaluate(() => { ${value || ""} });`;
269
- default:
270
- return null;
271
- }
272
- }
273
- var PlaywrightActions = {
274
- // Navigation
275
- goto: (url) => ({ type: "goto", url }),
276
- goBack: () => ({ type: "evaluate", value: "history.back()" }),
277
- goForward: () => ({ type: "evaluate", value: "history.forward()" }),
278
- reload: () => ({ type: "evaluate", value: "location.reload()" }),
279
- // Interactions
280
- click: (selector) => ({ type: "click", selector }),
281
- fill: (selector, value) => ({ type: "fill", selector, value }),
282
- type: (selector, value) => ({ type: "type", selector, value }),
283
- press: (selector, key) => ({ type: "press", selector, key }),
284
- check: (selector) => ({ type: "check", selector }),
285
- uncheck: (selector) => ({ type: "uncheck", selector }),
286
- selectOption: (selector, value) => ({ type: "selectOption", selector, value }),
287
- hover: (selector) => ({ type: "hover", selector }),
288
- focus: (selector) => ({ type: "focus", selector }),
289
- // Waiting
290
- wait: (ms) => ({ type: "wait", value: String(ms) }),
291
- waitForSelector: (selector) => ({ type: "waitForSelector", selector }),
292
- waitForURL: (url) => ({ type: "waitForURL", url }),
293
- // Screenshots
294
- screenshot: (path2) => ({ type: "screenshot", value: path2 }),
295
- // Scrolling
296
- scroll: (pixels) => ({ type: "scroll", value: String(pixels || 500) }),
297
- scrollToElement: (selector) => ({ type: "scroll", selector }),
298
- // Assertions
299
- expectVisible: (selector) => ({ type: "expectVisible", selector }),
300
- expectHidden: (selector) => ({ type: "expectHidden", selector }),
301
- expectText: (selector, text) => ({ type: "expectText", selector, value: text }),
302
- expectURL: (url) => ({ type: "expectURL", url }),
303
- expectTitle: (title) => ({ type: "expectTitle", value: title }),
304
- // Custom
305
- evaluate: (code) => ({ type: "evaluate", value: code })
306
- };
307
- async function runPlaywrightTest(options) {
308
- const installed = await isPlaywrightInstalled();
309
- if (!installed) {
310
- return {
311
- success: false,
312
- error: "Playwright is not installed. Install with: npm install -D @playwright/test && npx playwright install"
313
- };
314
- }
315
- const {
316
- testPath,
317
- testPattern,
318
- config = {},
319
- outputDir = path.join(PROJECTS_DIR, "playwright-output", Date.now().toString()),
320
- project,
321
- workers = 1,
322
- retries = 0,
323
- reporter = "json"
324
- } = options;
325
- await fs.promises.mkdir(outputDir, { recursive: true });
326
- const startTime = Date.now();
327
- const args = ["playwright", "test"];
328
- if (testPath) {
329
- args.push(testPath);
330
- }
331
- if (testPattern) {
332
- args.push("-g", testPattern);
333
- }
334
- if (project) {
335
- args.push("--project", project);
336
- }
337
- args.push("--workers", workers.toString());
338
- if (retries > 0) {
339
- args.push("--retries", retries.toString());
340
- }
341
- args.push("--reporter", reporter);
342
- args.push("--output", outputDir);
343
- if (config.browser) {
344
- args.push("--browser", config.browser);
345
- }
346
- if (config.headless === false) {
347
- args.push("--headed");
348
- }
349
- try {
350
- const { stdout, stderr } = await execAsync(`npx ${args.join(" ")}`, {
351
- timeout: config.timeout || 3e5,
352
- cwd: process.cwd()
353
- });
354
- const duration = Date.now() - startTime;
355
- let passed = 0;
356
- let failed = 0;
357
- let skipped = 0;
358
- const passedMatch = stdout.match(/(\d+) passed/);
359
- const failedMatch = stdout.match(/(\d+) failed/);
360
- const skippedMatch = stdout.match(/(\d+) skipped/);
361
- if (passedMatch) passed = parseInt(passedMatch[1], 10);
362
- if (failedMatch) failed = parseInt(failedMatch[1], 10);
363
- if (skippedMatch) skipped = parseInt(skippedMatch[1], 10);
364
- const videos = [];
365
- const screenshots = [];
366
- const traces = [];
367
- if (fs.existsSync(outputDir)) {
368
- const collectArtifacts = async (dir) => {
369
- const files = await fs.promises.readdir(dir, { withFileTypes: true });
370
- for (const file of files) {
371
- const filePath = path.join(dir, file.name);
372
- if (file.isDirectory()) {
373
- await collectArtifacts(filePath);
374
- } else if (file.name.endsWith(".webm") || file.name.endsWith(".mp4")) {
375
- videos.push(filePath);
376
- } else if (file.name.endsWith(".png")) {
377
- screenshots.push(filePath);
378
- } else if (file.name.endsWith(".zip") && file.name.includes("trace")) {
379
- traces.push(filePath);
380
- }
381
- }
382
- };
383
- await collectArtifacts(outputDir);
384
- }
385
- return {
386
- success: failed === 0,
387
- duration,
388
- passed,
389
- failed,
390
- skipped,
391
- output: stdout + stderr,
392
- reportPath: path.join(outputDir, "report.json"),
393
- videos,
394
- screenshots,
395
- traces
396
- };
397
- } catch (error) {
398
- const duration = Date.now() - startTime;
399
- const message = error instanceof Error ? error.message : String(error);
400
- let passed = 0;
401
- let failed = 0;
402
- let skipped = 0;
403
- const passedMatch = message.match(/(\d+) passed/);
404
- const failedMatch = message.match(/(\d+) failed/);
405
- const skippedMatch = message.match(/(\d+) skipped/);
406
- if (passedMatch) passed = parseInt(passedMatch[1], 10);
407
- if (failedMatch) failed = parseInt(failedMatch[1], 10);
408
- if (skippedMatch) skipped = parseInt(skippedMatch[1], 10);
409
- return {
410
- success: false,
411
- error: message,
412
- duration,
413
- passed,
414
- failed,
415
- skipped,
416
- output: message
417
- };
418
- }
419
- }
420
- async function runPlaywrightScript(script, options = {}) {
421
- const outputDir = options.outputDir || path.join(PROJECTS_DIR, "playwright-output", Date.now().toString());
422
- await fs.promises.mkdir(outputDir, { recursive: true });
423
- const scriptContent = generatePlaywrightScript(script);
424
- const scriptPath = path.join(outputDir, "test.spec.ts");
425
- await fs.promises.writeFile(scriptPath, scriptContent);
426
- const configContent = `
427
- import { defineConfig } from '@playwright/test';
428
-
429
- export default defineConfig({
430
- testDir: '.',
431
- timeout: ${options.config?.timeout || 3e4},
432
- use: {
433
- headless: ${options.config?.headless !== false},
434
- video: '${options.config?.video || "off"}',
435
- screenshot: '${options.config?.screenshot || "off"}',
436
- trace: '${options.config?.trace || "off"}',
437
- ${script.baseURL ? `baseURL: '${script.baseURL}',` : ""}
438
- ${script.viewport ? `viewport: { width: ${script.viewport.width}, height: ${script.viewport.height} },` : ""}
439
- },
440
- reporter: [['json', { outputFile: 'report.json' }]],
441
- outputDir: './results',
442
- });
443
- `;
444
- const configPath = path.join(outputDir, "playwright.config.ts");
445
- await fs.promises.writeFile(configPath, configContent);
446
- return runPlaywrightTest({
447
- ...options,
448
- testPath: scriptPath,
449
- outputDir
450
- });
451
- }
452
- async function savePlaywrightScript(script, outputPath) {
453
- const content = generatePlaywrightScript(script);
454
- const filePath = outputPath || path.join(
455
- PROJECTS_DIR,
456
- "scripts",
457
- `${script.name?.replace(/\s+/g, "_") || "test"}_${Date.now()}.spec.ts`
458
- );
459
- await fs.promises.mkdir(path.dirname(filePath), { recursive: true });
460
- await fs.promises.writeFile(filePath, content);
461
- return filePath;
462
- }
463
- async function startPlaywrightCodegen(url, options = {}) {
464
- const installed = await isPlaywrightInstalled();
465
- if (!installed) {
466
- return {
467
- success: false,
468
- error: "Playwright is not installed"
469
- };
470
- }
471
- try {
472
- const args = ["playwright", "codegen"];
473
- if (options.browser) {
474
- args.push("--browser", options.browser);
475
- }
476
- if (options.device) {
477
- args.push("--device", `"${options.device}"`);
478
- }
479
- if (options.outputPath) {
480
- args.push("-o", options.outputPath);
481
- }
482
- if (url) {
483
- args.push(url);
484
- }
485
- spawn("npx", args, {
486
- detached: true,
487
- stdio: "ignore",
488
- shell: true
489
- }).unref();
490
- return { success: true };
491
- } catch (error) {
492
- return {
493
- success: false,
494
- error: error instanceof Error ? error.message : String(error)
495
- };
496
- }
497
- }
498
- async function showPlaywrightReport(reportDir) {
499
- const installed = await isPlaywrightInstalled();
500
- if (!installed) {
501
- return {
502
- success: false,
503
- error: "Playwright is not installed"
504
- };
505
- }
506
- try {
507
- const args = ["playwright", "show-report"];
508
- if (reportDir) {
509
- args.push(reportDir);
510
- }
511
- spawn("npx", args, {
512
- detached: true,
513
- stdio: "ignore",
514
- shell: true
515
- }).unref();
516
- return { success: true };
517
- } catch (error) {
518
- return {
519
- success: false,
520
- error: error instanceof Error ? error.message : String(error)
521
- };
522
- }
523
- }
524
- function createLoginScript(baseURL, usernameSelector, passwordSelector, submitSelector, successURL) {
525
- return {
526
- name: "Login Test",
527
- baseURL,
528
- actions: [
529
- PlaywrightActions.goto(baseURL),
530
- PlaywrightActions.fill(usernameSelector, "${USERNAME}"),
531
- PlaywrightActions.fill(passwordSelector, "${PASSWORD}"),
532
- PlaywrightActions.click(submitSelector),
533
- PlaywrightActions.waitForURL(successURL),
534
- PlaywrightActions.expectURL(successURL),
535
- PlaywrightActions.screenshot("login-success.png")
536
- ]
537
- };
538
- }
539
- function createNavigationScript(baseURL, links) {
540
- const actions = [PlaywrightActions.goto(baseURL)];
541
- for (const link of links) {
542
- actions.push(PlaywrightActions.click(link.selector));
543
- actions.push(PlaywrightActions.waitForURL(link.expectedURL));
544
- actions.push(PlaywrightActions.screenshot(`${link.name}.png`));
545
- actions.push(PlaywrightActions.goBack());
546
- }
547
- return {
548
- name: "Navigation Test",
549
- baseURL,
550
- actions
551
- };
552
- }
553
- function createFormSubmissionScript(baseURL, formFields, submitSelector, successIndicator) {
554
- const actions = [PlaywrightActions.goto(baseURL)];
555
- for (const field of formFields) {
556
- actions.push(PlaywrightActions.fill(field.selector, field.value));
557
- }
558
- actions.push(PlaywrightActions.click(submitSelector));
559
- actions.push(PlaywrightActions.waitForSelector(successIndicator));
560
- actions.push(PlaywrightActions.expectVisible(successIndicator));
561
- actions.push(PlaywrightActions.screenshot("form-success.png"));
562
- return {
563
- name: "Form Submission Test",
564
- baseURL,
565
- actions
566
- };
567
- }
568
-
569
- export {
570
- redactSensitiveTestInput,
571
- redactQuotedStringsInText,
572
- isPlaywrightInstalled,
573
- getPlaywrightVersion,
574
- installPlaywrightBrowsers,
575
- BrowserDevices,
576
- listBrowserDevices,
577
- getBrowserDevice,
578
- generatePlaywrightScript,
579
- PlaywrightActions,
580
- runPlaywrightTest,
581
- runPlaywrightScript,
582
- savePlaywrightScript,
583
- startPlaywrightCodegen,
584
- showPlaywrightReport,
585
- createLoginScript,
586
- createNavigationScript,
587
- createFormSubmissionScript
588
- };