@lvce-editor/test-with-playwright-worker 20.2.0 → 22.0.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/dist/workerMain.js +267 -14
- package/package.json +1 -1
package/dist/workerMain.js
CHANGED
|
@@ -1,11 +1,58 @@
|
|
|
1
|
-
import { join, basename } from 'node:path';
|
|
2
|
-
import { readdir } from 'node:fs/promises';
|
|
3
|
-
import { expect, webkit, firefox, chromium } from '@playwright/test';
|
|
1
|
+
import { join, dirname, basename } from 'node:path';
|
|
2
|
+
import { readFile, writeFile, readdir } from 'node:fs/promises';
|
|
4
3
|
import { pathToFileURL } from 'node:url';
|
|
5
4
|
import net from 'node:net';
|
|
6
5
|
import os from 'node:os';
|
|
7
6
|
import { fork, spawn } from 'node:child_process';
|
|
8
7
|
import { createInterface } from 'node:readline';
|
|
8
|
+
import { createRequire } from 'node:module';
|
|
9
|
+
|
|
10
|
+
const require$1 = createRequire(import.meta.url);
|
|
11
|
+
const before = ` _onWebSocketOpened(event) {
|
|
12
|
+
const request2 = this._webSocketRequests.get(event.requestId);
|
|
13
|
+
assert(request2);
|
|
14
|
+
const response2 = this._webSocketResponses.get(event.requestId);
|
|
15
|
+
assert(response2);
|
|
16
|
+
this._webSocketRequests.delete(event.requestId);
|
|
17
|
+
this._webSocketResponses.delete(event.requestId);
|
|
18
|
+
this._page.frameManager.onWebSocketRequest(webSocketId(event.frameId, event.wsid), request2.headers);
|
|
19
|
+
this._page.frameManager.onWebSocketResponse(webSocketId(event.frameId, event.wsid), response2.status, response2.statusText, response2.headers);
|
|
20
|
+
}`;
|
|
21
|
+
const after = ` _onWebSocketOpened(event) {
|
|
22
|
+
const request2 = this._webSocketRequests.get(event.requestId);
|
|
23
|
+
const response2 = this._webSocketResponses.get(event.requestId);
|
|
24
|
+
if (!request2 || !response2) {
|
|
25
|
+
this._webSocketRequests.delete(event.requestId);
|
|
26
|
+
this._webSocketResponses.delete(event.requestId);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
this._webSocketRequests.delete(event.requestId);
|
|
30
|
+
this._webSocketResponses.delete(event.requestId);
|
|
31
|
+
this._page.frameManager.onWebSocketRequest(webSocketId(event.frameId, event.wsid), request2.headers);
|
|
32
|
+
this._page.frameManager.onWebSocketResponse(webSocketId(event.frameId, event.wsid), response2.status, response2.statusText, response2.headers);
|
|
33
|
+
}`;
|
|
34
|
+
const patchCoreBundleContent = content => {
|
|
35
|
+
if (content.includes(after)) {
|
|
36
|
+
return content;
|
|
37
|
+
}
|
|
38
|
+
if (!content.includes(before)) {
|
|
39
|
+
throw new Error('Could not patch Playwright Firefox worker WebSocket handler');
|
|
40
|
+
}
|
|
41
|
+
return content.split(before).join(after);
|
|
42
|
+
};
|
|
43
|
+
const getCoreBundlePath = () => {
|
|
44
|
+
const packageJsonPath = require$1.resolve('playwright-core/package.json');
|
|
45
|
+
return join(dirname(packageJsonPath), 'lib', 'coreBundle.js');
|
|
46
|
+
};
|
|
47
|
+
const patchPlaywrightFirefoxWorkerWebSocket = async () => {
|
|
48
|
+
const file = getCoreBundlePath();
|
|
49
|
+
const content = await readFile(file, 'utf8');
|
|
50
|
+
const patched = patchCoreBundleContent(content);
|
|
51
|
+
if (patched === content) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
await writeFile(file, patched);
|
|
55
|
+
};
|
|
9
56
|
|
|
10
57
|
const normalizeLine = line => {
|
|
11
58
|
if (line.startsWith('Error: ')) {
|
|
@@ -70,7 +117,7 @@ class AssertionError extends Error {
|
|
|
70
117
|
}
|
|
71
118
|
}
|
|
72
119
|
const Object$1 = 1;
|
|
73
|
-
const Number = 2;
|
|
120
|
+
const Number$1 = 2;
|
|
74
121
|
const Array$1 = 3;
|
|
75
122
|
const String$1 = 4;
|
|
76
123
|
const Boolean = 5;
|
|
@@ -80,7 +127,7 @@ const Unknown = 8;
|
|
|
80
127
|
const getType = value => {
|
|
81
128
|
switch (typeof value) {
|
|
82
129
|
case 'number':
|
|
83
|
-
return Number;
|
|
130
|
+
return Number$1;
|
|
84
131
|
case 'function':
|
|
85
132
|
return Function;
|
|
86
133
|
case 'string':
|
|
@@ -107,7 +154,7 @@ const object = value => {
|
|
|
107
154
|
};
|
|
108
155
|
const number = value => {
|
|
109
156
|
const type = getType(value);
|
|
110
|
-
if (type !== Number) {
|
|
157
|
+
if (type !== Number$1) {
|
|
111
158
|
throw new AssertionError('expected value to be of type number');
|
|
112
159
|
}
|
|
113
160
|
};
|
|
@@ -957,6 +1004,9 @@ const runElectronTest = async ({
|
|
|
957
1004
|
status: Skip$1
|
|
958
1005
|
};
|
|
959
1006
|
}
|
|
1007
|
+
const {
|
|
1008
|
+
expect
|
|
1009
|
+
} = await import('@playwright/test');
|
|
960
1010
|
await withTimeout(testModule.test({
|
|
961
1011
|
electronApp,
|
|
962
1012
|
expect,
|
|
@@ -984,7 +1034,7 @@ const runElectronTest = async ({
|
|
|
984
1034
|
}
|
|
985
1035
|
};
|
|
986
1036
|
|
|
987
|
-
const getResultCounts$
|
|
1037
|
+
const getResultCounts$2 = status => {
|
|
988
1038
|
switch (status) {
|
|
989
1039
|
case Fail$1:
|
|
990
1040
|
return {
|
|
@@ -1036,7 +1086,7 @@ const runElectronTests = async ({
|
|
|
1036
1086
|
timeout
|
|
1037
1087
|
});
|
|
1038
1088
|
await onResult(result);
|
|
1039
|
-
const resultCounts = getResultCounts$
|
|
1089
|
+
const resultCounts = getResultCounts$2(result.status);
|
|
1040
1090
|
failed += resultCounts.failed;
|
|
1041
1091
|
passed += resultCounts.passed;
|
|
1042
1092
|
skipped += resultCounts.skipped;
|
|
@@ -1104,6 +1154,9 @@ const runTest = async ({
|
|
|
1104
1154
|
}) => {
|
|
1105
1155
|
const start = performance.now();
|
|
1106
1156
|
try {
|
|
1157
|
+
const {
|
|
1158
|
+
expect
|
|
1159
|
+
} = await import('@playwright/test');
|
|
1107
1160
|
const url = getUrlFromTestFile(test, port, traceFocus);
|
|
1108
1161
|
await page.goto(url, {
|
|
1109
1162
|
waitUntil: 'networkidle'
|
|
@@ -1138,7 +1191,7 @@ const runTest = async ({
|
|
|
1138
1191
|
}
|
|
1139
1192
|
};
|
|
1140
1193
|
|
|
1141
|
-
const getResultCounts = status => {
|
|
1194
|
+
const getResultCounts$1 = status => {
|
|
1142
1195
|
switch (status) {
|
|
1143
1196
|
case Fail$1:
|
|
1144
1197
|
return {
|
|
@@ -1200,6 +1253,167 @@ const runTests = async ({
|
|
|
1200
1253
|
});
|
|
1201
1254
|
await onResult(result);
|
|
1202
1255
|
// @ts-ignore
|
|
1256
|
+
const resultCounts = getResultCounts$1(result.status);
|
|
1257
|
+
failed += resultCounts.failed;
|
|
1258
|
+
passed += resultCounts.passed;
|
|
1259
|
+
skipped += resultCounts.skipped;
|
|
1260
|
+
}
|
|
1261
|
+
const end = performance.now();
|
|
1262
|
+
await onFinalResult({
|
|
1263
|
+
end,
|
|
1264
|
+
failed,
|
|
1265
|
+
passed,
|
|
1266
|
+
skipped,
|
|
1267
|
+
start
|
|
1268
|
+
});
|
|
1269
|
+
};
|
|
1270
|
+
|
|
1271
|
+
const testResultsSelector = '.TestResults';
|
|
1272
|
+
const getResultCounts = status => {
|
|
1273
|
+
switch (status) {
|
|
1274
|
+
case Fail$1:
|
|
1275
|
+
return {
|
|
1276
|
+
failed: 1,
|
|
1277
|
+
passed: 0,
|
|
1278
|
+
skipped: 0
|
|
1279
|
+
};
|
|
1280
|
+
case Pass$1:
|
|
1281
|
+
return {
|
|
1282
|
+
failed: 0,
|
|
1283
|
+
passed: 1,
|
|
1284
|
+
skipped: 0
|
|
1285
|
+
};
|
|
1286
|
+
case Skip$1:
|
|
1287
|
+
return {
|
|
1288
|
+
failed: 0,
|
|
1289
|
+
passed: 0,
|
|
1290
|
+
skipped: 1
|
|
1291
|
+
};
|
|
1292
|
+
default:
|
|
1293
|
+
return {
|
|
1294
|
+
failed: 0,
|
|
1295
|
+
passed: 0,
|
|
1296
|
+
skipped: 0
|
|
1297
|
+
};
|
|
1298
|
+
}
|
|
1299
|
+
};
|
|
1300
|
+
const getAllTestsUrl = (port, filter, traceFocus) => {
|
|
1301
|
+
const url = new URL(`http://localhost:${port}/tests/_all.html`);
|
|
1302
|
+
if (traceFocus) {
|
|
1303
|
+
url.searchParams.set('traceFocus', 'true');
|
|
1304
|
+
}
|
|
1305
|
+
if (filter) {
|
|
1306
|
+
url.searchParams.set('filter', filter);
|
|
1307
|
+
}
|
|
1308
|
+
return url.href;
|
|
1309
|
+
};
|
|
1310
|
+
const isObject = value => {
|
|
1311
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
1312
|
+
};
|
|
1313
|
+
const parseStatus = value => {
|
|
1314
|
+
switch (value) {
|
|
1315
|
+
case 'fail':
|
|
1316
|
+
return Fail$1;
|
|
1317
|
+
case 'pass':
|
|
1318
|
+
return Pass$1;
|
|
1319
|
+
case 'skip':
|
|
1320
|
+
return Skip$1;
|
|
1321
|
+
default:
|
|
1322
|
+
throw new Error(`expected status to be pass, skip, or fail`);
|
|
1323
|
+
}
|
|
1324
|
+
};
|
|
1325
|
+
const parseString = (value, field) => {
|
|
1326
|
+
if (typeof value !== 'string') {
|
|
1327
|
+
throw new TypeError(`expected ${field} to be a string`);
|
|
1328
|
+
}
|
|
1329
|
+
return value;
|
|
1330
|
+
};
|
|
1331
|
+
const parseOptionalString = (value, field) => {
|
|
1332
|
+
if (value === undefined) {
|
|
1333
|
+
return '';
|
|
1334
|
+
}
|
|
1335
|
+
return parseString(value, field);
|
|
1336
|
+
};
|
|
1337
|
+
const parseNumber = (value, field) => {
|
|
1338
|
+
if (typeof value !== 'number' || !Number.isFinite(value)) {
|
|
1339
|
+
throw new TypeError(`expected ${field} to be a finite number`);
|
|
1340
|
+
}
|
|
1341
|
+
return value;
|
|
1342
|
+
};
|
|
1343
|
+
const parseTestResult = value => {
|
|
1344
|
+
if (!isObject(value)) {
|
|
1345
|
+
throw new TypeError(`expected test result to be an object`);
|
|
1346
|
+
}
|
|
1347
|
+
return {
|
|
1348
|
+
end: parseNumber(value.end, 'end'),
|
|
1349
|
+
error: parseOptionalString(value.error, 'error'),
|
|
1350
|
+
name: parseString(value.name, 'name'),
|
|
1351
|
+
start: parseNumber(value.start, 'start'),
|
|
1352
|
+
status: parseStatus(value.status)
|
|
1353
|
+
};
|
|
1354
|
+
};
|
|
1355
|
+
const parseTestResults = text => {
|
|
1356
|
+
const parsed = JSON.parse(text);
|
|
1357
|
+
if (!Array.isArray(parsed)) {
|
|
1358
|
+
throw new TypeError(`expected TestResults JSON to be an array`);
|
|
1359
|
+
}
|
|
1360
|
+
return parsed.map(parseTestResult);
|
|
1361
|
+
};
|
|
1362
|
+
const getFailedAllTestsResult = (error, start) => {
|
|
1363
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1364
|
+
return {
|
|
1365
|
+
end: performance.now(),
|
|
1366
|
+
error: message,
|
|
1367
|
+
name: '_all.html',
|
|
1368
|
+
start,
|
|
1369
|
+
status: Fail$1
|
|
1370
|
+
};
|
|
1371
|
+
};
|
|
1372
|
+
const readTestResultsText = async (page, timeout) => {
|
|
1373
|
+
const testResults = page.locator(testResultsSelector);
|
|
1374
|
+
await testResults.waitFor({
|
|
1375
|
+
state: 'attached',
|
|
1376
|
+
timeout
|
|
1377
|
+
});
|
|
1378
|
+
await page.waitForFunction(selector => {
|
|
1379
|
+
const element = document.querySelector(selector);
|
|
1380
|
+
const text = element?.textContent;
|
|
1381
|
+
return typeof text === 'string' && text.trim().length > 0;
|
|
1382
|
+
}, testResultsSelector, {
|
|
1383
|
+
timeout
|
|
1384
|
+
});
|
|
1385
|
+
const text = await testResults.textContent();
|
|
1386
|
+
if (!text || text.trim().length === 0) {
|
|
1387
|
+
throw new Error(`TestResults is empty`);
|
|
1388
|
+
}
|
|
1389
|
+
return text;
|
|
1390
|
+
};
|
|
1391
|
+
const runTestsWithReusedPage = async ({
|
|
1392
|
+
filter,
|
|
1393
|
+
onFinalResult,
|
|
1394
|
+
onResult,
|
|
1395
|
+
page,
|
|
1396
|
+
port,
|
|
1397
|
+
timeout,
|
|
1398
|
+
traceFocus
|
|
1399
|
+
}) => {
|
|
1400
|
+
const start = performance.now();
|
|
1401
|
+
let results;
|
|
1402
|
+
try {
|
|
1403
|
+
const url = getAllTestsUrl(port, filter, traceFocus ?? false);
|
|
1404
|
+
await page.goto(url, {
|
|
1405
|
+
waitUntil: 'networkidle'
|
|
1406
|
+
});
|
|
1407
|
+
const text = await readTestResultsText(page, timeout);
|
|
1408
|
+
results = parseTestResults(text);
|
|
1409
|
+
} catch (error) {
|
|
1410
|
+
results = [getFailedAllTestsResult(error, start)];
|
|
1411
|
+
}
|
|
1412
|
+
let failed = 0;
|
|
1413
|
+
let passed = 0;
|
|
1414
|
+
let skipped = 0;
|
|
1415
|
+
for (const result of results) {
|
|
1416
|
+
await onResult(result);
|
|
1203
1417
|
const resultCounts = getResultCounts(result.status);
|
|
1204
1418
|
failed += resultCounts.failed;
|
|
1205
1419
|
passed += resultCounts.passed;
|
|
@@ -1370,7 +1584,12 @@ const getServerPath = async serverPath => {
|
|
|
1370
1584
|
* @param {{browser:'chromium'|'firefox'|'webkit', signal:AbortSignal, headless:boolean}} options
|
|
1371
1585
|
* @returns
|
|
1372
1586
|
*/
|
|
1373
|
-
const getLauncher = browser => {
|
|
1587
|
+
const getLauncher = async browser => {
|
|
1588
|
+
const {
|
|
1589
|
+
chromium,
|
|
1590
|
+
firefox,
|
|
1591
|
+
webkit
|
|
1592
|
+
} = await import('@playwright/test');
|
|
1374
1593
|
switch (browser) {
|
|
1375
1594
|
case 'chromium':
|
|
1376
1595
|
return chromium;
|
|
@@ -1385,7 +1604,10 @@ const startBrowser = async ({
|
|
|
1385
1604
|
headless,
|
|
1386
1605
|
signal
|
|
1387
1606
|
}) => {
|
|
1388
|
-
|
|
1607
|
+
if (browser === 'firefox') {
|
|
1608
|
+
await patchPlaywrightFirefoxWorkerWebSocket();
|
|
1609
|
+
}
|
|
1610
|
+
const launcher = await getLauncher(browser);
|
|
1389
1611
|
const browserInstance = await launcher.launch({
|
|
1390
1612
|
headless
|
|
1391
1613
|
});
|
|
@@ -1629,6 +1851,9 @@ const startElectron = async ({
|
|
|
1629
1851
|
let browser;
|
|
1630
1852
|
try {
|
|
1631
1853
|
const endpoint = await waitForDevtoolsEndpoint(child);
|
|
1854
|
+
const {
|
|
1855
|
+
chromium
|
|
1856
|
+
} = await import('@playwright/test');
|
|
1632
1857
|
browser = await chromium.connectOverCDP(endpoint);
|
|
1633
1858
|
const page = await getFirstPage(browser);
|
|
1634
1859
|
return createElectronLaunch({
|
|
@@ -1677,8 +1902,9 @@ const tearDownTests = async ({
|
|
|
1677
1902
|
* @param {string} serverPath
|
|
1678
1903
|
* @param {boolean} traceFocus
|
|
1679
1904
|
* @param {string} filter
|
|
1905
|
+
* @param {boolean} reusePage
|
|
1680
1906
|
*/
|
|
1681
|
-
const runAllTests = async (extensionPath, testPath, cwd, browser, headless, timeout, runtimeOptions, traceFocus, filter) => {
|
|
1907
|
+
const runAllTests = async (extensionPath, testPath, cwd, browser, headless, timeout, runtimeOptions, traceFocus, filter, reusePage) => {
|
|
1682
1908
|
string(extensionPath);
|
|
1683
1909
|
string(testPath);
|
|
1684
1910
|
string(cwd);
|
|
@@ -1686,13 +1912,13 @@ const runAllTests = async (extensionPath, testPath, cwd, browser, headless, time
|
|
|
1686
1912
|
boolean(headless);
|
|
1687
1913
|
number(timeout);
|
|
1688
1914
|
object(runtimeOptions);
|
|
1915
|
+
boolean(reusePage);
|
|
1689
1916
|
const rpc = get(Cli);
|
|
1690
1917
|
const controller = new AbortController();
|
|
1691
1918
|
const {
|
|
1692
1919
|
signal
|
|
1693
1920
|
} = controller;
|
|
1694
1921
|
const testSrc = join(testPath, 'src');
|
|
1695
|
-
const tests = await getTests(testSrc);
|
|
1696
1922
|
const onResult = async result => {
|
|
1697
1923
|
await rpc.invoke(HandleResult, result);
|
|
1698
1924
|
};
|
|
@@ -1703,6 +1929,7 @@ const runAllTests = async (extensionPath, testPath, cwd, browser, headless, time
|
|
|
1703
1929
|
filter
|
|
1704
1930
|
};
|
|
1705
1931
|
if (runtimeOptions.type === 'electron') {
|
|
1932
|
+
const tests = await getTests(testSrc);
|
|
1706
1933
|
await using electron = await startElectron({
|
|
1707
1934
|
runtimeOptions,
|
|
1708
1935
|
signal
|
|
@@ -1733,6 +1960,23 @@ const runAllTests = async (extensionPath, testPath, cwd, browser, headless, time
|
|
|
1733
1960
|
signal,
|
|
1734
1961
|
testPath
|
|
1735
1962
|
});
|
|
1963
|
+
if (reusePage) {
|
|
1964
|
+
await runTestsWithReusedPage({
|
|
1965
|
+
...filterOption,
|
|
1966
|
+
onFinalResult,
|
|
1967
|
+
onResult,
|
|
1968
|
+
page,
|
|
1969
|
+
port,
|
|
1970
|
+
timeout,
|
|
1971
|
+
traceFocus
|
|
1972
|
+
});
|
|
1973
|
+
await tearDownTests({
|
|
1974
|
+
child,
|
|
1975
|
+
controller
|
|
1976
|
+
});
|
|
1977
|
+
return;
|
|
1978
|
+
}
|
|
1979
|
+
const tests = await getTests(testSrc);
|
|
1736
1980
|
await runTests({
|
|
1737
1981
|
...filterOption,
|
|
1738
1982
|
headless,
|
|
@@ -1789,4 +2033,13 @@ const main = async () => {
|
|
|
1789
2033
|
set(Cli, rpc);
|
|
1790
2034
|
};
|
|
1791
2035
|
|
|
1792
|
-
|
|
2036
|
+
const Main$1 = {
|
|
2037
|
+
__proto__: null,
|
|
2038
|
+
main
|
|
2039
|
+
};
|
|
2040
|
+
|
|
2041
|
+
if (process.argv.includes('--browser=firefox')) {
|
|
2042
|
+
await patchPlaywrightFirefoxWorkerWebSocket();
|
|
2043
|
+
}
|
|
2044
|
+
const Main = await Promise.resolve().then(function () { return Main$1; });
|
|
2045
|
+
await Main.main();
|