@veolab/discoverylab 1.2.2 → 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.
- package/.mcp.json +2 -2
- package/README.md +182 -0
- package/dist/{chunk-YEZ26ENO.js → chunk-3QRQEDWR.js} +313 -192
- package/dist/{chunk-E3N3P2AG.js → chunk-4L76GPRC.js} +1124 -51
- package/dist/{chunk-I6YD3QFM.js → chunk-FIL7IWEL.js} +5 -3
- package/dist/{chunk-G524UVBK.js → chunk-FNUN7EPB.js} +5 -5
- package/dist/chunk-GAKEFJ5T.js +481 -0
- package/dist/chunk-LB3RNE3O.js +109 -0
- package/dist/chunk-N6JJ2RGV.js +2680 -0
- package/dist/{chunk-7HZEDTS7.js → chunk-VRM42PML.js} +3471 -848
- package/dist/{chunk-TJ3H23LL.js → chunk-VVIOB362.js} +3 -1
- package/dist/{chunk-W3WJGYR6.js → chunk-XFVDP332.js} +8 -2
- package/dist/cli.js +397 -9
- package/dist/{db-ADBEBNH6.js → db-6WLEVKUV.js} +3 -1
- package/dist/esvp-GSISVXLC.js +52 -0
- package/dist/esvp-mobile-GC7MAGMI.js +20 -0
- package/dist/index.d.ts +123 -1
- package/dist/index.html +11689 -8690
- package/dist/index.js +67 -12
- package/dist/{ocr-UTWC7537.js → ocr-QDYNCSPE.js} +1 -1
- package/dist/{playwright-R7Y5HREH.js → playwright-VZ7PXDC5.js} +2 -2
- package/dist/runtime/esvp-host-runtime/darwin-arm64/esvp-host-runtime +0 -0
- package/dist/runtime/esvp-host-runtime/manifest.json +10 -0
- package/dist/server-FO3UVUZU.js +22 -0
- package/dist/{setup-B5YPNUE4.js → setup-2SQC5UHJ.js} +2 -2
- package/dist/{tools-YS4QHOTQ.js → tools-OCRMOQ4U.js} +61 -6
- package/package.json +36 -5
- package/dist/chunk-22OCFYHG.js +0 -6283
- package/dist/chunk-24VARQVO.js +0 -7818
- package/dist/chunk-2OGZX6C4.js +0 -588
- package/dist/chunk-2WCNIFRO.js +0 -6191
- package/dist/chunk-43U6UYV7.js +0 -590
- package/dist/chunk-4H2E3K2G.js +0 -7638
- package/dist/chunk-4KLG6DDE.js +0 -334
- package/dist/chunk-4MS6YW2B.js +0 -6490
- package/dist/chunk-4NNTRJOI.js +0 -7791
- package/dist/chunk-5F76VWME.js +0 -6397
- package/dist/chunk-5NEFN42O.js +0 -7791
- package/dist/chunk-63MEQ6UH.js +0 -7673
- package/dist/chunk-6H3NXFX3.js +0 -6861
- package/dist/chunk-7DOG2W4O.js +0 -6428
- package/dist/chunk-7IDQLLBW.js +0 -311
- package/dist/chunk-7NP64TGJ.js +0 -6822
- package/dist/chunk-AATLY4KT.js +0 -6505
- package/dist/chunk-C7QUR7XX.js +0 -6397
- package/dist/chunk-CGKCE6MC.js +0 -6279
- package/dist/chunk-D25V6IWE.js +0 -6487
- package/dist/chunk-EQOZSXAT.js +0 -6822
- package/dist/chunk-FPHD7HSQ.js +0 -6812
- package/dist/chunk-GGJJUCFK.js +0 -7160
- package/dist/chunk-GLHOY3NN.js +0 -7805
- package/dist/chunk-GML5MKQA.js +0 -6398
- package/dist/chunk-GOL6FUJL.js +0 -6045
- package/dist/chunk-GSWHWEYC.js +0 -1346
- package/dist/chunk-HDKEQOF5.js +0 -7788
- package/dist/chunk-HZGSWVVS.js +0 -7111
- package/dist/chunk-IGZ5TICZ.js +0 -334
- package/dist/chunk-IRKQG33A.js +0 -7054
- package/dist/chunk-JFTBF4JR.js +0 -6040
- package/dist/chunk-JVLVBPUJ.js +0 -6180
- package/dist/chunk-JY3KC67R.js +0 -6504
- package/dist/chunk-KUFBCBNJ.js +0 -6815
- package/dist/chunk-KV7KDJ43.js +0 -7639
- package/dist/chunk-L4SA5F5W.js +0 -6397
- package/dist/chunk-L5IJZV5F.js +0 -6822
- package/dist/chunk-MFFPQLU4.js +0 -7102
- package/dist/chunk-MJS2YKNR.js +0 -6397
- package/dist/chunk-MN6LCZHZ.js +0 -1320
- package/dist/chunk-NBAUZ7X2.js +0 -1336
- package/dist/chunk-NDBW6ELQ.js +0 -7638
- package/dist/chunk-O2HBSDI2.js +0 -6175
- package/dist/chunk-OFFIUYMG.js +0 -6341
- package/dist/chunk-OVCQGF2J.js +0 -1321
- package/dist/chunk-P4S7ZY6G.js +0 -7638
- package/dist/chunk-PBHUHSC3.js +0 -6002
- package/dist/chunk-PC4LR4ZI.js +0 -6359
- package/dist/chunk-PMTGGZ7R.js +0 -6397
- package/dist/chunk-PTXSB3UV.js +0 -497
- package/dist/chunk-PYUCY3U6.js +0 -1340
- package/dist/chunk-QJXXHOV7.js +0 -205
- package/dist/chunk-RDZDSOAL.js +0 -7750
- package/dist/chunk-RLW2OI2L.js +0 -6383
- package/dist/chunk-RUGHHO4K.js +0 -6395
- package/dist/chunk-SIOQVM2E.js +0 -6819
- package/dist/chunk-SR67SRIT.js +0 -1336
- package/dist/chunk-SSRXIO2V.js +0 -6822
- package/dist/chunk-SWSEKFON.js +0 -6487
- package/dist/chunk-TAODYZ52.js +0 -1393
- package/dist/chunk-TBG76CYG.js +0 -6395
- package/dist/chunk-V3CBINLD.js +0 -6812
- package/dist/chunk-VPYSLEGM.js +0 -6710
- package/dist/chunk-VY3BLXBW.js +0 -329
- package/dist/chunk-WTFOGVJQ.js +0 -6365
- package/dist/chunk-X64SFUT5.js +0 -6099
- package/dist/chunk-XIBF5LBD.js +0 -6395
- package/dist/chunk-XUKWS2CE.js +0 -7805
- package/dist/chunk-XZZKFF5V.js +0 -7787
- package/dist/chunk-Y5VDMSYC.js +0 -6701
- package/dist/chunk-YUBL36H4.js +0 -6605
- package/dist/chunk-YWVXFVSW.js +0 -6456
- package/dist/chunk-ZJFWMSZF.js +0 -7883
- package/dist/chunk-ZXZACOLD.js +0 -6822
- package/dist/db-IWIL65EX.js +0 -33
- package/dist/gridCompositor-ENKLFPWR.js +0 -409
- package/dist/playwright-A3OGSDRG.js +0 -38
- package/dist/playwright-ATDC4NYW.js +0 -38
- package/dist/playwright-E6EUFIJG.js +0 -38
- package/dist/server-2DXLKLFM.js +0 -13
- package/dist/server-2ICEWJVK.js +0 -13
- package/dist/server-2MQV3FNY.js +0 -13
- package/dist/server-2NGD7GE3.js +0 -13
- package/dist/server-2VKO76UK.js +0 -14
- package/dist/server-3BK2VFU7.js +0 -13
- package/dist/server-3FBHBA7L.js +0 -15
- package/dist/server-4LDOB3NX.js +0 -13
- package/dist/server-4YI44KDR.js +0 -13
- package/dist/server-64XMXA5P.js +0 -13
- package/dist/server-6IPHVUYT.js +0 -14
- package/dist/server-73ORHMJN.js +0 -13
- package/dist/server-73P7M3QB.js +0 -14
- package/dist/server-BPVRW5LJ.js +0 -14
- package/dist/server-BW4RKZIX.js +0 -13
- package/dist/server-CFS5SM5K.js +0 -13
- package/dist/server-DX7VYHHM.js +0 -13
- package/dist/server-F3YPX6ET.js +0 -13
- package/dist/server-FUXTR33I.js +0 -13
- package/dist/server-G2SY3DOS.js +0 -13
- package/dist/server-G32U7VOQ.js +0 -13
- package/dist/server-HKRIY7FP.js +0 -14
- package/dist/server-HON66OES.js +0 -15
- package/dist/server-IOOZK4NP.js +0 -14
- package/dist/server-IZEO7OJJ.js +0 -14
- package/dist/server-J52LMTBT.js +0 -13
- package/dist/server-JG7UKFGK.js +0 -14
- package/dist/server-JSCHEBOD.js +0 -13
- package/dist/server-K6KC4ZOM.js +0 -13
- package/dist/server-KJVRGWFE.js +0 -13
- package/dist/server-LCPB2L4U.js +0 -13
- package/dist/server-M7LDYKAJ.js +0 -13
- package/dist/server-MKVK6ZQQ.js +0 -13
- package/dist/server-MU52LCXT.js +0 -13
- package/dist/server-NM5CKDUU.js +0 -13
- package/dist/server-NPZN3FWO.js +0 -14
- package/dist/server-O5FIAHSY.js +0 -14
- package/dist/server-OESJUEYC.js +0 -13
- package/dist/server-ONSKQO4W.js +0 -13
- package/dist/server-P27BZXBL.js +0 -14
- package/dist/server-Q4FBWQUA.js +0 -13
- package/dist/server-RNQ7VUAL.js +0 -13
- package/dist/server-S6B5WUBT.js +0 -14
- package/dist/server-SRYNSGSP.js +0 -14
- package/dist/server-SUN3W2YK.js +0 -13
- package/dist/server-UA62LHZB.js +0 -13
- package/dist/server-UJB44EW5.js +0 -13
- package/dist/server-X3TLP6DX.js +0 -14
- package/dist/server-YT2UGEZK.js +0 -13
- package/dist/server-ZBPQ33V6.js +0 -14
- package/dist/setup-27CQAX6K.js +0 -17
- package/dist/setup-AQX4JQVR.js +0 -17
- package/dist/setup-EQTU7FI6.js +0 -17
- package/dist/tools-2KPB37GK.js +0 -178
- package/dist/tools-3H6IOWXV.js +0 -178
- package/dist/tools-3KYHPDCJ.js +0 -178
- package/dist/tools-75BAPCUM.js +0 -177
- package/dist/tools-BUVCUCRL.js +0 -178
- package/dist/tools-HDNODRS6.js +0 -178
- package/dist/tools-HP5MNY3D.js +0 -177
- package/dist/tools-L6PKKQPY.js +0 -179
- package/dist/tools-N5N2IO7V.js +0 -178
- package/dist/tools-NFJEZ2FF.js +0 -177
- package/dist/tools-OPULIER6.js +0 -178
- package/dist/tools-TLCKABUW.js +0 -178
package/dist/chunk-2OGZX6C4.js
DELETED
|
@@ -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
|
-
};
|