@humanjs/playwright 0.9.0 → 0.10.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/README.md +20 -0
- package/dist/{chunk-3X36PFTS.cjs → chunk-665R4N7R.cjs} +157 -3
- package/dist/chunk-665R4N7R.cjs.map +1 -0
- package/dist/{chunk-3TXDODCO.js → chunk-I2PQGZU7.js} +158 -5
- package/dist/chunk-I2PQGZU7.js.map +1 -0
- package/dist/index.cjs +29 -25
- package/dist/index.d.cts +52 -1
- package/dist/index.d.ts +52 -1
- package/dist/index.js +1 -1
- package/dist/test.cjs +2 -2
- package/dist/test.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-3TXDODCO.js.map +0 -1
- package/dist/chunk-3X36PFTS.cjs.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { sleep as sleep$1, resolvePersonality, createRng, planScroll, countWords, computeReadingDwellMs, planReadingScan, planTypeKeystrokes, bezierPath, humanizePath } from '@humanjs/core';
|
|
2
2
|
export { applyMicroJitter, applyVelocityProfile, bezierPath, blend, careful, computeReadingDwellMs, countWords, createRng, distracted, fast, humanizePath, planScroll, planTypeKeystrokes, precise, resolvePersonality, sleep } from '@humanjs/core';
|
|
3
3
|
import { spawn } from 'child_process';
|
|
4
4
|
import { rmSync } from 'fs';
|
|
@@ -940,8 +940,17 @@ async function detectKindFromTag(locator) {
|
|
|
940
940
|
return void 0;
|
|
941
941
|
}
|
|
942
942
|
|
|
943
|
-
// src/recording/
|
|
943
|
+
// src/recording/targets.ts
|
|
944
944
|
var POINT_RE = /^point\((-?\d+(?:\.\d+)?),\s*(-?\d+(?:\.\d+)?)\)$/;
|
|
945
|
+
function parsePointTarget(desc) {
|
|
946
|
+
const match = String(desc ?? "").match(POINT_RE);
|
|
947
|
+
return match ? { x: Number(match[1]), y: Number(match[2]) } : null;
|
|
948
|
+
}
|
|
949
|
+
function resolveMouseTarget(desc) {
|
|
950
|
+
return parsePointTarget(desc) ?? String(desc ?? "");
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
// src/recording/codegen.ts
|
|
945
954
|
var POINT_COMMENT = " // raw coordinate \u2014 replace with a locator for a stable selector";
|
|
946
955
|
var UNCAPTURED_COMMENT = " // input not captured (masked or captureInputs disabled) \u2014 fill in (e.g. process.env.X)";
|
|
947
956
|
function q(value) {
|
|
@@ -1177,6 +1186,150 @@ ${todo}
|
|
|
1177
1186
|
});
|
|
1178
1187
|
`;
|
|
1179
1188
|
}
|
|
1189
|
+
function abortError() {
|
|
1190
|
+
const error = new Error("Replay aborted");
|
|
1191
|
+
error.name = "AbortError";
|
|
1192
|
+
return error;
|
|
1193
|
+
}
|
|
1194
|
+
async function replayTimeline(page, timeline, options = {}) {
|
|
1195
|
+
const events = Array.isArray(timeline) ? timeline : timeline.events;
|
|
1196
|
+
const { onStep, signal } = options;
|
|
1197
|
+
if (signal?.aborted) throw abortError();
|
|
1198
|
+
const human = await createHuman(page, {
|
|
1199
|
+
personality: options.personality ?? "careful",
|
|
1200
|
+
speed: options.speed ?? "human",
|
|
1201
|
+
...options.seed !== void 0 ? { seed: options.seed } : {},
|
|
1202
|
+
...options.cursor !== void 0 ? { cursor: options.cursor } : {}
|
|
1203
|
+
});
|
|
1204
|
+
const startedAt = Date.now();
|
|
1205
|
+
const steps = [];
|
|
1206
|
+
for (const [index, event] of events.entries()) {
|
|
1207
|
+
if (signal?.aborted) throw abortError();
|
|
1208
|
+
onStep?.({ index, type: event.type, status: "running" });
|
|
1209
|
+
try {
|
|
1210
|
+
await runEvent(human, page, event);
|
|
1211
|
+
} catch (cause) {
|
|
1212
|
+
const error = cause instanceof Error ? cause.message : String(cause);
|
|
1213
|
+
steps.push({ index, type: event.type, status: "fail", error });
|
|
1214
|
+
onStep?.({ index, type: event.type, status: "fail", error });
|
|
1215
|
+
return { status: "fail", steps, failedIndex: index, durationMs: Date.now() - startedAt };
|
|
1216
|
+
}
|
|
1217
|
+
steps.push({ index, type: event.type, status: "pass" });
|
|
1218
|
+
onStep?.({ index, type: event.type, status: "pass" });
|
|
1219
|
+
}
|
|
1220
|
+
return { status: "pass", steps, durationMs: Date.now() - startedAt };
|
|
1221
|
+
}
|
|
1222
|
+
function parseScrollTarget(target) {
|
|
1223
|
+
const value = String(target ?? "natural");
|
|
1224
|
+
const by = value.match(/^by:(-?\d+(?:\.\d+)?)$/);
|
|
1225
|
+
if (by) return { by: Number(by[1]) };
|
|
1226
|
+
const to = value.match(/^to:(-?\d+(?:\.\d+)?)$/);
|
|
1227
|
+
if (to) return { to: Number(to[1]) };
|
|
1228
|
+
return value;
|
|
1229
|
+
}
|
|
1230
|
+
var normalizeText = (value) => (value ?? "").replace(/\s+/g, " ").trim();
|
|
1231
|
+
async function runAssert(page, params) {
|
|
1232
|
+
const kind = String(params.kind ?? "visible");
|
|
1233
|
+
if (kind === "url") {
|
|
1234
|
+
const actual = page.url();
|
|
1235
|
+
const expected = String(params.value ?? "");
|
|
1236
|
+
if (actual !== expected) {
|
|
1237
|
+
throw new Error(`expected URL ${JSON.stringify(expected)}, got ${JSON.stringify(actual)}`);
|
|
1238
|
+
}
|
|
1239
|
+
return;
|
|
1240
|
+
}
|
|
1241
|
+
const locator = page.locator(String(params.target ?? "")).first();
|
|
1242
|
+
await locator.waitFor({ state: "visible" });
|
|
1243
|
+
if (kind === "text") {
|
|
1244
|
+
const actual = normalizeText(await locator.textContent());
|
|
1245
|
+
const expected = normalizeText(String(params.value ?? ""));
|
|
1246
|
+
if (actual !== expected) {
|
|
1247
|
+
throw new Error(`expected text ${JSON.stringify(expected)}, got ${JSON.stringify(actual)}`);
|
|
1248
|
+
}
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1251
|
+
async function runEvent(human, page, event) {
|
|
1252
|
+
const p = event.params;
|
|
1253
|
+
switch (event.type) {
|
|
1254
|
+
case "goto":
|
|
1255
|
+
await human.goto(String(p.url ?? ""));
|
|
1256
|
+
return;
|
|
1257
|
+
case "click":
|
|
1258
|
+
await human.click(resolveMouseTarget(p.target));
|
|
1259
|
+
return;
|
|
1260
|
+
case "rightClick":
|
|
1261
|
+
await human.rightClick(resolveMouseTarget(p.target));
|
|
1262
|
+
return;
|
|
1263
|
+
case "doubleClick":
|
|
1264
|
+
await human.doubleClick(resolveMouseTarget(p.target));
|
|
1265
|
+
return;
|
|
1266
|
+
case "move":
|
|
1267
|
+
await human.move(resolveMouseTarget(p.target));
|
|
1268
|
+
return;
|
|
1269
|
+
case "hover":
|
|
1270
|
+
await human.hover(String(p.target ?? ""));
|
|
1271
|
+
return;
|
|
1272
|
+
case "drag":
|
|
1273
|
+
await human.drag(resolveMouseTarget(p.from), resolveMouseTarget(p.to));
|
|
1274
|
+
return;
|
|
1275
|
+
case "type":
|
|
1276
|
+
await human.type(String(p.target ?? ""), event.inputValue ?? "");
|
|
1277
|
+
return;
|
|
1278
|
+
case "paste":
|
|
1279
|
+
await human.paste(String(p.target ?? ""), event.inputValue ?? "");
|
|
1280
|
+
return;
|
|
1281
|
+
case "clear":
|
|
1282
|
+
await human.clear(String(p.target ?? ""));
|
|
1283
|
+
return;
|
|
1284
|
+
case "check":
|
|
1285
|
+
await human.check(String(p.target ?? ""));
|
|
1286
|
+
return;
|
|
1287
|
+
case "uncheck":
|
|
1288
|
+
await human.uncheck(String(p.target ?? ""));
|
|
1289
|
+
return;
|
|
1290
|
+
case "selectText":
|
|
1291
|
+
await human.selectText(
|
|
1292
|
+
String(p.target ?? ""),
|
|
1293
|
+
typeof p.text === "string" ? { text: p.text } : void 0
|
|
1294
|
+
);
|
|
1295
|
+
return;
|
|
1296
|
+
case "selectOption":
|
|
1297
|
+
await human.selectOption(String(p.target ?? ""), p.values);
|
|
1298
|
+
return;
|
|
1299
|
+
case "upload":
|
|
1300
|
+
await human.upload(String(p.target ?? ""), p.files);
|
|
1301
|
+
return;
|
|
1302
|
+
case "press":
|
|
1303
|
+
await human.press(String(p.key ?? ""));
|
|
1304
|
+
return;
|
|
1305
|
+
case "scroll":
|
|
1306
|
+
await human.scroll(parseScrollTarget(p.target));
|
|
1307
|
+
return;
|
|
1308
|
+
case "read": {
|
|
1309
|
+
const target = String(p.target ?? "");
|
|
1310
|
+
if (/^\d+ words$/.test(target) || /^text:\d+ chars$/.test(target)) return;
|
|
1311
|
+
await human.read(target);
|
|
1312
|
+
return;
|
|
1313
|
+
}
|
|
1314
|
+
case "sleep":
|
|
1315
|
+
await sleep$1(Number(p.ms) || 0);
|
|
1316
|
+
return;
|
|
1317
|
+
case "reload":
|
|
1318
|
+
await human.reload();
|
|
1319
|
+
return;
|
|
1320
|
+
case "goBack":
|
|
1321
|
+
await human.goBack();
|
|
1322
|
+
return;
|
|
1323
|
+
case "goForward":
|
|
1324
|
+
await human.goForward();
|
|
1325
|
+
return;
|
|
1326
|
+
case "assert":
|
|
1327
|
+
await runAssert(page, p);
|
|
1328
|
+
return;
|
|
1329
|
+
default:
|
|
1330
|
+
return;
|
|
1331
|
+
}
|
|
1332
|
+
}
|
|
1180
1333
|
|
|
1181
1334
|
// src/recording/index.ts
|
|
1182
1335
|
var pendingFrameCleanups = /* @__PURE__ */ new Set();
|
|
@@ -1992,6 +2145,6 @@ function describeReadTarget(target) {
|
|
|
1992
2145
|
return target.toString?.() ?? "locator";
|
|
1993
2146
|
}
|
|
1994
2147
|
|
|
1995
|
-
export { Recording, createHuman, generateHumanJS, generatePlaywrightTest, installMouseHelper };
|
|
1996
|
-
//# sourceMappingURL=chunk-
|
|
1997
|
-
//# sourceMappingURL=chunk-
|
|
2148
|
+
export { Recording, createHuman, generateHumanJS, generatePlaywrightTest, installMouseHelper, replayTimeline };
|
|
2149
|
+
//# sourceMappingURL=chunk-I2PQGZU7.js.map
|
|
2150
|
+
//# sourceMappingURL=chunk-I2PQGZU7.js.map
|