@lvce-editor/test-with-playwright 22.5.0 → 22.7.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 (3) hide show
  1. package/README.md +4 -3
  2. package/dist/main.js +159 -53
  3. package/package.json +3 -3
package/README.md CHANGED
@@ -13,7 +13,7 @@
13
13
  ```json
14
14
  {
15
15
  "scripts": {
16
- "e2e:electron": "node ./node_modules/@lvce-editor/test-with-playwright/bin/test-with-playwright.js --runtime=electron --electron-version=v0.84.0 --test-path=./e2e"
16
+ "e2e:electron": "node ./node_modules/@lvce-editor/test-with-playwright/bin/test-with-playwright.js --electron --test-path=./e2e"
17
17
  }
18
18
  }
19
19
  ```
@@ -28,6 +28,7 @@ test('sample.hello-world', async () => {
28
28
  ## CLI Flags
29
29
 
30
30
  - `--runtime`: `browser` (default) or `electron`
31
+ - `--electron`: shorthand for `--runtime=electron`; infers the Lvce release from the installed `@lvce-editor/server`
31
32
  - `--only-extension`: path to the extension under test
32
33
  - `--test-path`: path to the test root
33
34
  - `--server-path`: explicit server entry point
@@ -38,7 +39,7 @@ test('sample.hello-world', async () => {
38
39
  - `--browser`: browser engine to launch: `chromium`, `firefox`, or `webkit`
39
40
  - `--trace-focus`: add `traceFocus=true` to test URLs
40
41
  - `--electron-path`: path to an existing Electron app executable
41
- - `--electron-version`: Lvce release version to download, required for `--runtime=electron` when `--electron-path` is not provided
42
+ - `--electron-version`: Lvce release version override; by default Electron uses the installed `@lvce-editor/server` version
42
43
  - `--electron-cache-dir`: directory for downloaded Electron apps, defaults to `.test-with-playwright/electron`
43
44
  - `--electron-arg`: extra Electron app argument, can be provided multiple times
44
45
  - `--electron-env`: Electron environment variable in `NAME=value` form, can be provided multiple times
@@ -47,7 +48,7 @@ test('sample.hello-world', async () => {
47
48
 
48
49
  - `browser` keeps the server-backed HTML test execution flow.
49
50
  - `--reuse-page` is browser-only. It loads `/tests/_all.html` once and reads JSON results from a hidden `.TestResults` element.
50
- - `electron` downloads or reuses a Lvce Electron app, launches it with Playwright, and runs each test module against the first window.
51
+ - `electron` downloads or reuses the matching Lvce Electron app, launches it with Playwright and a temporary user data directory, and runs each test module against the first window.
51
52
  - `--electron-path` skips downloading and is useful for custom local builds.
52
53
 
53
54
  ## Reuse Page Results
package/dist/main.js CHANGED
@@ -1,6 +1,7 @@
1
- import { dirname, join, resolve as resolve$1, basename } from 'node:path';
1
+ import { resolve as resolve$1, join, dirname, parse, basename } from 'node:path';
2
+ import { readFile, mkdir, readdir, stat, chmod, writeFile, rm, mkdtemp } from 'node:fs/promises';
3
+ import { createRequire } from 'node:module';
2
4
  import { createWriteStream, existsSync } from 'node:fs';
3
- import { mkdir, readdir, stat, readFile, chmod, writeFile, rm, mkdtemp } from 'node:fs/promises';
4
5
  import { tmpdir } from 'node:os';
5
6
  import { pipeline } from 'node:stream/promises';
6
7
  import { execFile as execFile$1 } from 'node:child_process';
@@ -122,6 +123,7 @@ const getHelpMessage = () => {
122
123
  Options:
123
124
  --browser=<browser> Browser to run tests in: chromium, firefox, or webkit
124
125
  --runtime=<runtime> Runtime to run tests in: browser or electron
126
+ --electron Run tests in Electron and infer the matching Lvce version
125
127
  --filter=<pattern> Only run tests matching the filter
126
128
  --headless Run the browser in headless mode
127
129
  --reuse-page Run browser tests through /tests/_all.html on one page
@@ -131,7 +133,7 @@ Options:
131
133
  --timeout=<ms> Test timeout in milliseconds
132
134
  --trace-focus Log focus changes while tests run
133
135
  --electron-path=<path> Path to an existing Electron app executable
134
- --electron-version=<ver> Lvce release version to download, for example v0.84.0
136
+ --electron-version=<ver> Override the inferred Lvce release version
135
137
  --electron-cache-dir=<p> Directory for downloaded Electron apps
136
138
  --electron-arg=<arg> Extra Electron app argument, repeatable
137
139
  --electron-env=<env> Electron environment variable as NAME=value, repeatable
@@ -409,14 +411,24 @@ const setOptionalPositiveNumber = (result, key, value, name) => {
409
411
  result[key] = toPositiveNumber(value, name);
410
412
  }
411
413
  };
414
+ const getRuntime = parsed => {
415
+ if (parsed.electron) {
416
+ return 'electron';
417
+ }
418
+ if (parsed.runtime) {
419
+ return toCliString(parsed.runtime);
420
+ }
421
+ return undefined;
422
+ };
412
423
  const parseCliArgs = argv => {
413
424
  const parsed = parseArgv(argv);
414
425
  const result = Object.create(null);
415
426
  if (parsed.browser) {
416
427
  result.browser = String(parsed.browser);
417
428
  }
418
- if (parsed.runtime) {
419
- result.runtime = String(parsed.runtime);
429
+ const runtime = getRuntime(parsed);
430
+ if (runtime) {
431
+ result.runtime = runtime;
420
432
  }
421
433
  if (parsed.filter) {
422
434
  result.filter = String(parsed.filter);
@@ -523,6 +535,64 @@ const getOptions = ({
523
535
  };
524
536
  };
525
537
 
538
+ const serverPackageName = '@lvce-editor/server';
539
+ const normalizeVersion = version => {
540
+ return version.startsWith('v') ? version : `v${version}`;
541
+ };
542
+ const readServerVersion = async path => {
543
+ try {
544
+ const content = await readFile(path, 'utf8');
545
+ const packageJson = JSON.parse(content);
546
+ if (packageJson.name === serverPackageName && typeof packageJson.version === 'string') {
547
+ return normalizeVersion(packageJson.version);
548
+ }
549
+ } catch {
550
+ // Try the next possible package location.
551
+ }
552
+ return undefined;
553
+ };
554
+ const findServerVersionFromPath = async path => {
555
+ let current = resolve$1(path);
556
+ if (!current.endsWith('package.json')) {
557
+ current = dirname(current);
558
+ }
559
+ const {
560
+ root
561
+ } = parse(current);
562
+ while (current !== root) {
563
+ const version = await readServerVersion(join(current, 'package.json'));
564
+ if (version) {
565
+ return version;
566
+ }
567
+ current = dirname(current);
568
+ }
569
+ return undefined;
570
+ };
571
+ const resolveServerEntryPoint = cwd => {
572
+ try {
573
+ const require = createRequire(join(cwd, 'package.json'));
574
+ return require.resolve(serverPackageName);
575
+ } catch {
576
+ return undefined;
577
+ }
578
+ };
579
+ const getPossibleServerPaths = (cwd, serverPath) => {
580
+ const resolvedServerEntryPoint = resolveServerEntryPoint(cwd);
581
+ return [...(serverPath ? [resolve$1(cwd, serverPath)] : []), ...(resolvedServerEntryPoint ? [resolvedServerEntryPoint] : []), join(cwd, 'node_modules', '@lvce-editor', 'server', 'package.json'), join(cwd, '..', 'server', 'node_modules', '@lvce-editor', 'server', 'package.json'), join(cwd, '..', 'build', 'node_modules', '@lvce-editor', 'server', 'package.json')];
582
+ };
583
+ const getElectronVersion = async ({
584
+ cwd,
585
+ serverPath
586
+ }) => {
587
+ for (const possiblePath of getPossibleServerPaths(cwd, serverPath)) {
588
+ const version = possiblePath.endsWith('package.json') ? await readServerVersion(possiblePath) : await findServerVersionFromPath(possiblePath);
589
+ if (version) {
590
+ return version;
591
+ }
592
+ }
593
+ throw new Error('[test-with-playwright] Electron version could not be inferred from @lvce-editor/server; use --electron-version or --electron-path');
594
+ };
595
+
526
596
  const downloadFile = async ({
527
597
  to,
528
598
  url
@@ -870,13 +940,19 @@ const getRuntimeOptions = async ({
870
940
  return getBrowserRuntimeOptions(serverPath);
871
941
  }
872
942
  const cacheDir = resolve$1(cwd, electronCacheDir || '.test-with-playwright/electron');
943
+ const version = electronVersion || electronPath ? electronVersion : await getElectronVersion({
944
+ cwd,
945
+ ...(serverPath && {
946
+ serverPath
947
+ })
948
+ });
873
949
  const executablePath = await prepareElectronApp({
874
950
  cacheDir,
875
951
  ...(electronPath && {
876
952
  electronPath: resolve$1(cwd, electronPath)
877
953
  }),
878
- ...(electronVersion && {
879
- version: electronVersion
954
+ ...(version && {
955
+ version
880
956
  })
881
957
  });
882
958
  return {
@@ -1035,7 +1111,6 @@ const walkValue = (value, transferrables, isTransferrable) => {
1035
1111
  for (const property of Object.values(value)) {
1036
1112
  walkValue(property, transferrables, isTransferrable);
1037
1113
  }
1038
- return;
1039
1114
  }
1040
1115
  };
1041
1116
  const getTransferrables = value => {
@@ -1189,7 +1264,14 @@ class IpcError extends VError {
1189
1264
  const cause = new Error(message);
1190
1265
  // @ts-ignore
1191
1266
  cause.code = code;
1192
- cause.stack = stack;
1267
+ if (stack) {
1268
+ Object.defineProperty(cause, 'stack', {
1269
+ configurable: true,
1270
+ enumerable: false,
1271
+ value: stack,
1272
+ writable: true
1273
+ });
1274
+ }
1193
1275
  super(cause, betterMessage);
1194
1276
  } else {
1195
1277
  super(betterMessage);
@@ -1426,8 +1508,10 @@ const getCurrentStack = () => {
1426
1508
  const currentStack = joinLines(splitLines(new Error().stack || '').slice(stackLinesToSkip));
1427
1509
  return currentStack;
1428
1510
  };
1429
- const getNewLineIndex = (string, startIndex = undefined) => {
1430
- return string.indexOf(NewLine, startIndex);
1511
+ const getNewLineIndex = (string, startIndex) => {
1512
+ {
1513
+ return string.indexOf(NewLine);
1514
+ }
1431
1515
  };
1432
1516
  const getParentStack = error => {
1433
1517
  let parentStack = error.stack || error.data || error.message || '';
@@ -1438,55 +1522,77 @@ const getParentStack = error => {
1438
1522
  };
1439
1523
  const MethodNotFound = -32601;
1440
1524
  const Custom = -32001;
1525
+ const restoreExistingError = (error, currentStack) => {
1526
+ if (typeof error.stack === 'string') {
1527
+ error.stack = error.stack + NewLine + currentStack;
1528
+ }
1529
+ return error;
1530
+ };
1531
+ const restoreMethodNotFoundError = (error, currentStack) => {
1532
+ const restoredError = new JsonRpcError(error.message);
1533
+ const parentStack = getParentStack(error);
1534
+ restoredError.stack = parentStack + NewLine + currentStack;
1535
+ return restoredError;
1536
+ };
1537
+ const restoreStackFromData = (restoredError, error, currentStack) => {
1538
+ if (error.data.stack && error.data.type && error.message) {
1539
+ restoredError.stack = error.data.type + ': ' + error.message + NewLine + error.data.stack + NewLine + currentStack;
1540
+ return;
1541
+ }
1542
+ if (error.data.stack) {
1543
+ restoredError.stack = error.data.stack;
1544
+ }
1545
+ };
1546
+ const applyDataProperties = (restoredError, error) => {
1547
+ if (!error.data) {
1548
+ return;
1549
+ }
1550
+ restoreStackFromData(restoredError, error, getCurrentStack());
1551
+ if (error.data.codeFrame) {
1552
+ // @ts-ignore
1553
+ restoredError.codeFrame = error.data.codeFrame;
1554
+ }
1555
+ if (error.data.code) {
1556
+ // @ts-ignore
1557
+ restoredError.code = error.data.code;
1558
+ }
1559
+ if (error.data.type) {
1560
+ // @ts-ignore
1561
+ restoredError.name = error.data.type;
1562
+ }
1563
+ };
1564
+ const applyDirectProperties = (restoredError, error) => {
1565
+ if (error.stack) {
1566
+ const lowerStack = restoredError.stack || '';
1567
+ const indexNewLine = getNewLineIndex(lowerStack);
1568
+ const parentStack = getParentStack(error);
1569
+ // @ts-ignore
1570
+ restoredError.stack = parentStack + lowerStack.slice(indexNewLine);
1571
+ }
1572
+ if (error.codeFrame) {
1573
+ // @ts-ignore
1574
+ restoredError.codeFrame = error.codeFrame;
1575
+ }
1576
+ };
1577
+ const restoreMessageError = (error, _currentStack) => {
1578
+ const restoredError = constructError(error.message, error.type, error.name);
1579
+ if (error.data) {
1580
+ applyDataProperties(restoredError, error);
1581
+ } else {
1582
+ applyDirectProperties(restoredError, error);
1583
+ }
1584
+ return restoredError;
1585
+ };
1441
1586
  const restoreJsonRpcError = error => {
1442
1587
  const currentStack = getCurrentStack();
1443
1588
  if (error && error instanceof Error) {
1444
- if (typeof error.stack === 'string') {
1445
- error.stack = error.stack + NewLine + currentStack;
1446
- }
1447
- return error;
1589
+ return restoreExistingError(error, currentStack);
1448
1590
  }
1449
1591
  if (error && error.code && error.code === MethodNotFound) {
1450
- const restoredError = new JsonRpcError(error.message);
1451
- const parentStack = getParentStack(error);
1452
- restoredError.stack = parentStack + NewLine + currentStack;
1453
- return restoredError;
1592
+ return restoreMethodNotFoundError(error, currentStack);
1454
1593
  }
1455
1594
  if (error && error.message) {
1456
- const restoredError = constructError(error.message, error.type, error.name);
1457
- if (error.data) {
1458
- if (error.data.stack && error.data.type && error.message) {
1459
- restoredError.stack = error.data.type + ': ' + error.message + NewLine + error.data.stack + NewLine + currentStack;
1460
- } else if (error.data.stack) {
1461
- restoredError.stack = error.data.stack;
1462
- }
1463
- if (error.data.codeFrame) {
1464
- // @ts-ignore
1465
- restoredError.codeFrame = error.data.codeFrame;
1466
- }
1467
- if (error.data.code) {
1468
- // @ts-ignore
1469
- restoredError.code = error.data.code;
1470
- }
1471
- if (error.data.type) {
1472
- // @ts-ignore
1473
- restoredError.name = error.data.type;
1474
- }
1475
- } else {
1476
- if (error.stack) {
1477
- const lowerStack = restoredError.stack || '';
1478
- // @ts-ignore
1479
- const indexNewLine = getNewLineIndex(lowerStack);
1480
- const parentStack = getParentStack(error);
1481
- // @ts-ignore
1482
- restoredError.stack = parentStack + lowerStack.slice(indexNewLine);
1483
- }
1484
- if (error.codeFrame) {
1485
- // @ts-ignore
1486
- restoredError.codeFrame = error.codeFrame;
1487
- }
1488
- }
1489
- return restoredError;
1595
+ return restoreMessageError(error);
1490
1596
  }
1491
1597
  if (typeof error === 'string') {
1492
1598
  return new Error(`JsonRpc Error: ${error}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/test-with-playwright",
3
- "version": "22.5.0",
3
+ "version": "22.7.0",
4
4
  "description": "CLI tool for running Playwright tests",
5
5
  "repository": {
6
6
  "type": "git",
@@ -12,8 +12,8 @@
12
12
  "main": "dist/main.js",
13
13
  "bin": "bin/test-with-playwright.js",
14
14
  "dependencies": {
15
- "@lvce-editor/test-with-playwright-worker": "22.5.0",
16
- "@lvce-editor/test-worker": "^17.0.2"
15
+ "@lvce-editor/test-with-playwright-worker": "22.7.0",
16
+ "@lvce-editor/test-worker": "^17.2.0"
17
17
  },
18
18
  "engines": {
19
19
  "node": ">=24"