@lvce-editor/test-with-playwright-worker 22.36.1 → 22.36.3

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.
@@ -460,6 +460,9 @@ const restoreExistingError = (error, currentStack) => {
460
460
  };
461
461
  const restoreMethodNotFoundError = (error, currentStack) => {
462
462
  const restoredError = new JsonRpcError(error.message);
463
+ Object.assign(restoredError, {
464
+ code: error.code
465
+ });
463
466
  const parentStack = getParentStack(error);
464
467
  setStack(restoredError, `${parentStack}${NewLine}${currentStack}`);
465
468
  return restoredError;
@@ -479,9 +482,13 @@ const applyDataProperties = (restoredError, error) => {
479
482
  // @ts-ignore
480
483
  restoredError.codeFrame = error.data.codeFrame;
481
484
  }
482
- if (error.data.code) {
485
+ if (typeof error.data.code === 'string' || typeof error.data.code === 'number') {
483
486
  // @ts-ignore
484
- restoredError.code = error.data.code;
487
+ Object.defineProperty(restoredError, 'code', {
488
+ configurable: true,
489
+ value: error.data.code,
490
+ writable: true
491
+ });
485
492
  }
486
493
  if (error.data.type) {
487
494
  // @ts-ignore
@@ -503,6 +510,13 @@ const applyDirectProperties = (restoredError, error) => {
503
510
  };
504
511
  const restoreMessageError = (error, _currentStack) => {
505
512
  const restoredError = constructError(error.message, error.type, error.name);
513
+ if (typeof error.code === 'string' || typeof error.code === 'number') {
514
+ Object.defineProperty(restoredError, 'code', {
515
+ configurable: true,
516
+ value: error.code,
517
+ writable: true
518
+ });
519
+ }
506
520
  if (error.data) {
507
521
  applyDataProperties(restoredError, error);
508
522
  } else {
@@ -581,7 +595,7 @@ const getErrorProperty = (error, prettyError) => {
581
595
  return {
582
596
  code: Custom,
583
597
  data: {
584
- code: prettyError.code,
598
+ code: prettyError.code ?? error?.code,
585
599
  codeFrame: prettyError.codeFrame,
586
600
  name: prettyError.name,
587
601
  stack: getStack(prettyError),
@@ -618,7 +632,12 @@ const getErrorResponseSimple = (id, error) => {
618
632
  return {
619
633
  error: {
620
634
  code: Custom,
621
- data: error,
635
+ data: error instanceof Error ? {
636
+ ...error,
637
+ code: 'code' in error ? error.code : undefined,
638
+ stack: error.stack,
639
+ type: error.name
640
+ } : error,
622
641
  // @ts-ignore
623
642
  message: error.message
624
643
  },
@@ -721,6 +721,9 @@ const restoreExistingError = (error, currentStack) => {
721
721
  };
722
722
  const restoreMethodNotFoundError = (error, currentStack) => {
723
723
  const restoredError = new JsonRpcError(error.message);
724
+ Object.assign(restoredError, {
725
+ code: error.code
726
+ });
724
727
  const parentStack = getParentStack(error);
725
728
  setStack(restoredError, `${parentStack}${NewLine}${currentStack}`);
726
729
  return restoredError;
@@ -740,9 +743,13 @@ const applyDataProperties = (restoredError, error) => {
740
743
  // @ts-ignore
741
744
  restoredError.codeFrame = error.data.codeFrame;
742
745
  }
743
- if (error.data.code) {
746
+ if (typeof error.data.code === 'string' || typeof error.data.code === 'number') {
744
747
  // @ts-ignore
745
- restoredError.code = error.data.code;
748
+ Object.defineProperty(restoredError, 'code', {
749
+ configurable: true,
750
+ value: error.data.code,
751
+ writable: true
752
+ });
746
753
  }
747
754
  if (error.data.type) {
748
755
  // @ts-ignore
@@ -764,6 +771,13 @@ const applyDirectProperties = (restoredError, error) => {
764
771
  };
765
772
  const restoreMessageError = (error, _currentStack) => {
766
773
  const restoredError = constructError(error.message, error.type, error.name);
774
+ if (typeof error.code === 'string' || typeof error.code === 'number') {
775
+ Object.defineProperty(restoredError, 'code', {
776
+ configurable: true,
777
+ value: error.code,
778
+ writable: true
779
+ });
780
+ }
767
781
  if (error.data) {
768
782
  applyDataProperties(restoredError, error);
769
783
  } else {
@@ -842,7 +856,7 @@ const getErrorProperty = (error, prettyError) => {
842
856
  return {
843
857
  code: Custom,
844
858
  data: {
845
- code: prettyError.code,
859
+ code: prettyError.code ?? error?.code,
846
860
  codeFrame: prettyError.codeFrame,
847
861
  name: prettyError.name,
848
862
  stack: getStack(prettyError),
@@ -879,7 +893,12 @@ const getErrorResponseSimple = (id, error) => {
879
893
  return {
880
894
  error: {
881
895
  code: Custom,
882
- data: error,
896
+ data: error instanceof Error ? {
897
+ ...error,
898
+ code: 'code' in error ? error.code : undefined,
899
+ stack: error.stack,
900
+ type: error.name
901
+ } : error,
883
902
  // @ts-ignore
884
903
  message: error.message
885
904
  },
@@ -1179,6 +1198,162 @@ const get = id => {
1179
1198
  return rpcs[id];
1180
1199
  };
1181
1200
 
1201
+ // This function is serialized by Playwright and must not close over module bindings.
1202
+ const install = () => {
1203
+ const limit = 5000;
1204
+ const payloadLimit = 8192;
1205
+ const entries = [];
1206
+ let sequence = 0;
1207
+ const channels = new WeakMap();
1208
+ let nextChannel = 0;
1209
+ const originalAdd = Object.getOwnPropertyDescriptor(EventTarget.prototype, 'addEventListener').value;
1210
+ const record = (kind, data) => {
1211
+ const entry = {
1212
+ ...data,
1213
+ kind,
1214
+ sequence: sequence++,
1215
+ timestamp: performance.now()
1216
+ };
1217
+ entries[entry.sequence % limit] = entry;
1218
+ };
1219
+ const describe = target => {
1220
+ if (!(target instanceof Element)) {
1221
+ if (!(target instanceof Node)) return 'unknown';
1222
+ return `${target.nodeName}:${target.nodeValue || ''}`.slice(0, 200);
1223
+ }
1224
+ return `${target.tagName}#${target.id}.${target.getAttribute('class') || ''}`.slice(0, 200);
1225
+ };
1226
+ const serialize = value => {
1227
+ let truncated = false;
1228
+ const seen = new WeakSet();
1229
+ try {
1230
+ const text = JSON.stringify(value, (_key, item) => {
1231
+ if (typeof item === 'bigint') return `${item}n`;
1232
+ if (typeof item === 'string') {
1233
+ truncated ||= item.length > 2048;
1234
+ return item.slice(0, 2048);
1235
+ }
1236
+ if (typeof item !== 'object' || item === null) return item;
1237
+ if (seen.has(item)) return '[Circular]';
1238
+ seen.add(item);
1239
+ if (item instanceof MessagePort) return '[MessagePort]';
1240
+ if (item instanceof ArrayBuffer) return `[ArrayBuffer ${item.byteLength}]`;
1241
+ if (ArrayBuffer.isView(item)) return `[${item.constructor.name} ${item.byteLength}]`;
1242
+ return item;
1243
+ }) || '';
1244
+ return {
1245
+ payload: text.slice(0, payloadLimit),
1246
+ truncated: truncated || text.length > payloadLimit
1247
+ };
1248
+ } catch {
1249
+ return {
1250
+ payload: '[Unserializable]',
1251
+ truncated: true
1252
+ };
1253
+ }
1254
+ };
1255
+ const observe = target => {
1256
+ const existing = channels.get(target);
1257
+ if (existing !== undefined) return existing;
1258
+ const channel = nextChannel++;
1259
+ channels.set(target, channel);
1260
+ Reflect.apply(originalAdd, target, ['message', event => {
1261
+ record('rpc-received', {
1262
+ channel,
1263
+ ...serialize(event.data)
1264
+ });
1265
+ }]);
1266
+ return channel;
1267
+ };
1268
+ class EventHooks {
1269
+ addEventListener(...args) {
1270
+ if (args[0] === 'message' && (this instanceof MessagePort || this instanceof Worker)) observe(this);
1271
+ return Reflect.apply(originalAdd, this, args);
1272
+ }
1273
+ }
1274
+ Object.defineProperty(EventTarget.prototype, 'addEventListener', {
1275
+ ...Object.getOwnPropertyDescriptor(EventTarget.prototype, 'addEventListener'),
1276
+ value: Object.getOwnPropertyDescriptor(EventHooks.prototype, 'addEventListener').value
1277
+ });
1278
+ for (const prototype of [MessagePort.prototype, Worker.prototype]) {
1279
+ const postDescriptor = Object.getOwnPropertyDescriptor(prototype, 'postMessage');
1280
+ const descriptor = Object.getOwnPropertyDescriptor(prototype, 'onmessage');
1281
+ const originalSet = Object.getOwnPropertyDescriptor(descriptor, 'set').value;
1282
+ class PortHooks {
1283
+ postMessage(...args) {
1284
+ const channel = observe(this);
1285
+ const data = serialize(args[0]);
1286
+ const result = Reflect.apply(postDescriptor.value, this, args);
1287
+ record('rpc-sent', {
1288
+ channel,
1289
+ ...data
1290
+ });
1291
+ return result;
1292
+ }
1293
+ set onmessage(listener) {
1294
+ observe(this);
1295
+ Reflect.apply(originalSet, this, [listener]);
1296
+ }
1297
+ }
1298
+ const hookDescriptor = Object.getOwnPropertyDescriptor(PortHooks.prototype, 'onmessage');
1299
+ Object.defineProperties(prototype, {
1300
+ onmessage: {
1301
+ ...descriptor,
1302
+ set: Object.getOwnPropertyDescriptor(hookDescriptor, 'set').value
1303
+ },
1304
+ postMessage: {
1305
+ ...postDescriptor,
1306
+ value: Object.getOwnPropertyDescriptor(PortHooks.prototype, 'postMessage').value
1307
+ }
1308
+ });
1309
+ }
1310
+ for (const type of ['click', 'input', 'keydown', 'keyup', 'pointerdown', 'pointerup', 'pointerover', 'pointerout', 'focusin', 'focusout']) {
1311
+ document.addEventListener(type, event => {
1312
+ record('input', {
1313
+ event: type,
1314
+ key: event.key,
1315
+ target: describe(event.target),
1316
+ trusted: event.isTrusted
1317
+ });
1318
+ }, {
1319
+ capture: true,
1320
+ passive: true
1321
+ });
1322
+ }
1323
+ const observer = new MutationObserver(mutations => {
1324
+ record('dom-mutation', {
1325
+ changes: mutations.slice(0, 10).map(mutation => ({
1326
+ added: [...mutation.addedNodes].slice(0, 2).map(describe),
1327
+ addedCount: mutation.addedNodes.length,
1328
+ attribute: mutation.attributeName,
1329
+ removed: [...mutation.removedNodes].slice(0, 2).map(describe),
1330
+ removedCount: mutation.removedNodes.length,
1331
+ target: describe(mutation.target),
1332
+ type: mutation.type,
1333
+ value: mutation.attributeName && mutation.target instanceof Element ? mutation.target.getAttribute(mutation.attributeName)?.slice(0, 200) : undefined
1334
+ })),
1335
+ count: mutations.length
1336
+ });
1337
+ });
1338
+ observer.observe(document, {
1339
+ attributes: true,
1340
+ characterData: true,
1341
+ childList: true,
1342
+ subtree: true
1343
+ });
1344
+ Object.defineProperty(globalThis, '__lvceTraceTimeline', {
1345
+ value: () => {
1346
+ const offset = sequence > limit ? sequence % limit : 0;
1347
+ return {
1348
+ dropped: Math.max(0, sequence - limit),
1349
+ entries: [...entries.slice(offset), ...entries.slice(0, offset)],
1350
+ limit,
1351
+ version: 1
1352
+ };
1353
+ }
1354
+ });
1355
+ };
1356
+
1182
1357
  const HandleResult = 'HandleResult';
1183
1358
  const HandleFinalResult = 'HandleFinalResult';
1184
1359
 
@@ -1249,19 +1424,26 @@ const exportTrace = async ({
1249
1424
  page,
1250
1425
  test
1251
1426
  }) => {
1252
- let text;
1427
+ let capture;
1253
1428
  try {
1254
- text = await page.evaluate(traceSelector => {
1255
- return globalThis.document.querySelector(traceSelector)?.textContent || undefined;
1429
+ capture = await page.evaluate(traceSelector => {
1430
+ return {
1431
+ text: globalThis.document.querySelector(traceSelector)?.textContent || undefined,
1432
+ timeline: globalThis.__lvceTraceTimeline?.()
1433
+ };
1256
1434
  }, selector);
1257
1435
  } catch {
1258
1436
  return false;
1259
1437
  }
1260
- if (!text) {
1438
+ if (!capture.text && !capture.timeline) {
1261
1439
  return false;
1262
1440
  }
1263
- JSON.parse(text);
1264
- await writeFile(join(directory, getFileName(test)), `${text}\n`);
1441
+ const trace = capture.text ? JSON.parse(capture.text) : {
1442
+ entries: [],
1443
+ version: 1
1444
+ };
1445
+ if (capture.timeline) trace.timeline = capture.timeline;
1446
+ await writeFile(join(directory, getFileName(test)), `${JSON.stringify(trace)}\n`);
1265
1447
  return true;
1266
1448
  };
1267
1449
 
@@ -2210,10 +2392,14 @@ const getElectronLaunchOptions = ({
2210
2392
  args,
2211
2393
  env,
2212
2394
  executablePath
2213
- }) => {
2395
+ }, profileRoot) => {
2214
2396
  const launchEnv = {
2215
2397
  ...getProcessEnv(),
2216
- ...env
2398
+ ...env,
2399
+ XDG_CACHE_HOME: join(profileRoot, 'cache'),
2400
+ XDG_CONFIG_HOME: join(profileRoot, 'config'),
2401
+ XDG_DATA_HOME: join(profileRoot, 'data'),
2402
+ XDG_STATE_HOME: join(profileRoot, 'state')
2217
2403
  };
2218
2404
  delete launchEnv['ELECTRON_RUN_AS_NODE'];
2219
2405
  return {
@@ -2252,19 +2438,19 @@ const createElectronLaunch = ({
2252
2438
  signal,
2253
2439
  userDataDir
2254
2440
  }) => {
2255
- let disposed = false;
2256
- const dispose = async () => {
2257
- if (disposed) {
2258
- return;
2441
+ let disposal;
2442
+ const dispose = () => {
2443
+ if (disposal) {
2444
+ return disposal;
2259
2445
  }
2260
- disposed = true;
2261
2446
  signal.removeEventListener('abort', handleAbort);
2262
2447
  process.off('SIGINT', handleSigint);
2263
2448
  process.off('SIGTERM', handleSigterm);
2264
- await closeElectron({
2449
+ disposal = closeElectron({
2265
2450
  electronApp,
2266
2451
  userDataDir
2267
2452
  });
2453
+ return disposal;
2268
2454
  };
2269
2455
  const handleAbort = () => {
2270
2456
  void dispose();
@@ -2297,14 +2483,15 @@ const startElectron = async ({
2297
2483
  runtimeOptions,
2298
2484
  signal
2299
2485
  }) => {
2300
- const launchOptions = getElectronLaunchOptions(runtimeOptions);
2301
2486
  const userDataDir = await mkdtemp(join(tmpdir(), 'test-with-playwright-electron-'));
2302
- const args = getElectronProcessArgs({
2303
- args: launchOptions.args,
2304
- userDataDir
2305
- });
2306
2487
  let electronApp;
2307
2488
  try {
2489
+ signal.throwIfAborted();
2490
+ const launchOptions = getElectronLaunchOptions(runtimeOptions, userDataDir);
2491
+ const args = getElectronProcessArgs({
2492
+ args: launchOptions.args,
2493
+ userDataDir
2494
+ });
2308
2495
  const {
2309
2496
  _electron
2310
2497
  } = await import('@playwright/test');
@@ -2314,9 +2501,11 @@ const startElectron = async ({
2314
2501
  executablePath: launchOptions.executablePath,
2315
2502
  timeout: electronLaunchTimeout
2316
2503
  });
2504
+ signal.throwIfAborted();
2317
2505
  const page = await electronApp.firstWindow({
2318
2506
  timeout: electronLaunchTimeout
2319
2507
  });
2508
+ signal.throwIfAborted();
2320
2509
  return createElectronLaunch({
2321
2510
  electronApp,
2322
2511
  page,
@@ -2446,6 +2635,9 @@ const runAllTests = async (extensionPath, testPath, cwd, browser, headless, time
2446
2635
  testPath
2447
2636
  });
2448
2637
  try {
2638
+ if (traceRendererWorker) {
2639
+ await page.addInitScript(install);
2640
+ }
2449
2641
  if (reusePage) {
2450
2642
  await runWithJavascriptCoverage({
2451
2643
  coverage,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/test-with-playwright-worker",
3
- "version": "22.36.1",
3
+ "version": "22.36.3",
4
4
  "description": "Worker package for test-with-playwright",
5
5
  "repository": {
6
6
  "type": "git",