@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.
- package/README.md +4 -3
- package/dist/main.js +159 -53
- 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 --
|
|
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
|
|
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
|
|
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 {
|
|
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
|
|
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
|
-
|
|
419
|
-
|
|
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
|
-
...(
|
|
879
|
-
version
|
|
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
|
-
|
|
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
|
|
1430
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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.
|
|
16
|
-
"@lvce-editor/test-worker": "^17.0
|
|
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"
|