@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.
Files changed (2) hide show
  1. package/dist/workerMain.js +267 -14
  2. package/package.json +1 -1
@@ -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$1 = status => {
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$1(result.status);
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
- const launcher = getLauncher(browser);
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
- main();
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();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/test-with-playwright-worker",
3
- "version": "20.2.0",
3
+ "version": "22.0.0",
4
4
  "description": "Worker package for test-with-playwright",
5
5
  "repository": {
6
6
  "type": "git",