@lvce-editor/test-with-playwright-worker 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 (2) hide show
  1. package/dist/workerMain.js +140 -61
  2. package/package.json +1 -1
@@ -1,8 +1,8 @@
1
1
  import { join, dirname, basename } from 'node:path';
2
- import { readFile, writeFile, readdir } from 'node:fs/promises';
2
+ import { readFile, writeFile, readdir, mkdtemp, rm } from 'node:fs/promises';
3
3
  import { pathToFileURL } from 'node:url';
4
4
  import net from 'node:net';
5
- import os from 'node:os';
5
+ import os, { tmpdir } from 'node:os';
6
6
  import { fork, spawn } from 'node:child_process';
7
7
  import { createInterface } from 'node:readline';
8
8
  import { createRequire } from 'node:module';
@@ -213,7 +213,6 @@ const walkValue = (value, transferrables, isTransferrable) => {
213
213
  for (const property of Object.values(value)) {
214
214
  walkValue(property, transferrables, isTransferrable);
215
215
  }
216
- return;
217
216
  }
218
217
  };
219
218
  const getTransferrables = value => {
@@ -367,7 +366,14 @@ class IpcError extends VError {
367
366
  const cause = new Error(message);
368
367
  // @ts-ignore
369
368
  cause.code = code;
370
- cause.stack = stack;
369
+ if (stack) {
370
+ Object.defineProperty(cause, 'stack', {
371
+ configurable: true,
372
+ enumerable: false,
373
+ value: stack,
374
+ writable: true
375
+ });
376
+ }
371
377
  super(cause, betterMessage);
372
378
  } else {
373
379
  super(betterMessage);
@@ -522,8 +528,10 @@ const getCurrentStack = () => {
522
528
  const currentStack = joinLines(splitLines(new Error().stack || '').slice(stackLinesToSkip));
523
529
  return currentStack;
524
530
  };
525
- const getNewLineIndex = (string, startIndex = undefined) => {
526
- return string.indexOf(NewLine, startIndex);
531
+ const getNewLineIndex = (string, startIndex) => {
532
+ {
533
+ return string.indexOf(NewLine);
534
+ }
527
535
  };
528
536
  const getParentStack = error => {
529
537
  let parentStack = error.stack || error.data || error.message || '';
@@ -534,55 +542,77 @@ const getParentStack = error => {
534
542
  };
535
543
  const MethodNotFound = -32601;
536
544
  const Custom = -32001;
545
+ const restoreExistingError = (error, currentStack) => {
546
+ if (typeof error.stack === 'string') {
547
+ error.stack = error.stack + NewLine + currentStack;
548
+ }
549
+ return error;
550
+ };
551
+ const restoreMethodNotFoundError = (error, currentStack) => {
552
+ const restoredError = new JsonRpcError(error.message);
553
+ const parentStack = getParentStack(error);
554
+ restoredError.stack = parentStack + NewLine + currentStack;
555
+ return restoredError;
556
+ };
557
+ const restoreStackFromData = (restoredError, error, currentStack) => {
558
+ if (error.data.stack && error.data.type && error.message) {
559
+ restoredError.stack = error.data.type + ': ' + error.message + NewLine + error.data.stack + NewLine + currentStack;
560
+ return;
561
+ }
562
+ if (error.data.stack) {
563
+ restoredError.stack = error.data.stack;
564
+ }
565
+ };
566
+ const applyDataProperties = (restoredError, error) => {
567
+ if (!error.data) {
568
+ return;
569
+ }
570
+ restoreStackFromData(restoredError, error, getCurrentStack());
571
+ if (error.data.codeFrame) {
572
+ // @ts-ignore
573
+ restoredError.codeFrame = error.data.codeFrame;
574
+ }
575
+ if (error.data.code) {
576
+ // @ts-ignore
577
+ restoredError.code = error.data.code;
578
+ }
579
+ if (error.data.type) {
580
+ // @ts-ignore
581
+ restoredError.name = error.data.type;
582
+ }
583
+ };
584
+ const applyDirectProperties = (restoredError, error) => {
585
+ if (error.stack) {
586
+ const lowerStack = restoredError.stack || '';
587
+ const indexNewLine = getNewLineIndex(lowerStack);
588
+ const parentStack = getParentStack(error);
589
+ // @ts-ignore
590
+ restoredError.stack = parentStack + lowerStack.slice(indexNewLine);
591
+ }
592
+ if (error.codeFrame) {
593
+ // @ts-ignore
594
+ restoredError.codeFrame = error.codeFrame;
595
+ }
596
+ };
597
+ const restoreMessageError = (error, _currentStack) => {
598
+ const restoredError = constructError(error.message, error.type, error.name);
599
+ if (error.data) {
600
+ applyDataProperties(restoredError, error);
601
+ } else {
602
+ applyDirectProperties(restoredError, error);
603
+ }
604
+ return restoredError;
605
+ };
537
606
  const restoreJsonRpcError = error => {
538
607
  const currentStack = getCurrentStack();
539
608
  if (error && error instanceof Error) {
540
- if (typeof error.stack === 'string') {
541
- error.stack = error.stack + NewLine + currentStack;
542
- }
543
- return error;
609
+ return restoreExistingError(error, currentStack);
544
610
  }
545
611
  if (error && error.code && error.code === MethodNotFound) {
546
- const restoredError = new JsonRpcError(error.message);
547
- const parentStack = getParentStack(error);
548
- restoredError.stack = parentStack + NewLine + currentStack;
549
- return restoredError;
612
+ return restoreMethodNotFoundError(error, currentStack);
550
613
  }
551
614
  if (error && error.message) {
552
- const restoredError = constructError(error.message, error.type, error.name);
553
- if (error.data) {
554
- if (error.data.stack && error.data.type && error.message) {
555
- restoredError.stack = error.data.type + ': ' + error.message + NewLine + error.data.stack + NewLine + currentStack;
556
- } else if (error.data.stack) {
557
- restoredError.stack = error.data.stack;
558
- }
559
- if (error.data.codeFrame) {
560
- // @ts-ignore
561
- restoredError.codeFrame = error.data.codeFrame;
562
- }
563
- if (error.data.code) {
564
- // @ts-ignore
565
- restoredError.code = error.data.code;
566
- }
567
- if (error.data.type) {
568
- // @ts-ignore
569
- restoredError.name = error.data.type;
570
- }
571
- } else {
572
- if (error.stack) {
573
- const lowerStack = restoredError.stack || '';
574
- // @ts-ignore
575
- const indexNewLine = getNewLineIndex(lowerStack);
576
- const parentStack = getParentStack(error);
577
- // @ts-ignore
578
- restoredError.stack = parentStack + lowerStack.slice(indexNewLine);
579
- }
580
- if (error.codeFrame) {
581
- // @ts-ignore
582
- restoredError.codeFrame = error.codeFrame;
583
- }
584
- }
585
- return restoredError;
615
+ return restoreMessageError(error);
586
616
  }
587
617
  if (typeof error === 'string') {
588
618
  return new Error(`JsonRpc Error: ${error}`);
@@ -1725,8 +1755,17 @@ const getElectronLaunchOptions = ({
1725
1755
  };
1726
1756
  };
1727
1757
 
1758
+ const getElectronProcessArgs = ({
1759
+ args,
1760
+ platform = process.platform,
1761
+ userDataDir
1762
+ }) => {
1763
+ return ['--remote-debugging-port=0', ...(platform === 'linux' ? ['--no-sandbox'] : []), ...args, `--user-data-dir=${userDataDir}`];
1764
+ };
1765
+
1728
1766
  const SIGINT = 'SIGINT';
1729
1767
 
1768
+ const electronConnectionTimeout = 120_000;
1730
1769
  const devtoolsRegex = /^DevTools listening on (ws:\/\/.*)$/;
1731
1770
  const waitForDevtoolsEndpoint = async child => {
1732
1771
  const {
@@ -1743,10 +1782,13 @@ const waitForDevtoolsEndpoint = async child => {
1743
1782
  reject,
1744
1783
  resolve
1745
1784
  } = Promise.withResolvers();
1785
+ const stderrLines = [];
1746
1786
  const onExit = () => {
1747
- reject(new Error('Electron exited before DevTools endpoint was available'));
1787
+ const details = stderrLines.length > 0 ? `: ${stderrLines.join('\n')}` : '';
1788
+ reject(new Error(`Electron exited before DevTools endpoint was available${details}`));
1748
1789
  };
1749
1790
  const onLine = line => {
1791
+ stderrLines.push(line);
1750
1792
  const match = line.match(devtoolsRegex);
1751
1793
  if (match) {
1752
1794
  resolve(match[1]);
@@ -1772,24 +1814,50 @@ const getFirstPage = async browser => {
1772
1814
  timeout: 15_000
1773
1815
  });
1774
1816
  };
1817
+ const waitForChildExit = async child => {
1818
+ if (child.exitCode !== null || child.signalCode !== null) {
1819
+ return;
1820
+ }
1821
+ await new Promise(resolve => {
1822
+ const timeout = setTimeout(resolve, 5000);
1823
+ child.once('exit', () => {
1824
+ clearTimeout(timeout);
1825
+ resolve();
1826
+ });
1827
+ });
1828
+ };
1829
+ const stopElectronProcess = async child => {
1830
+ if (child.exitCode === null && child.signalCode === null) {
1831
+ child.kill(SIGINT);
1832
+ await waitForChildExit(child);
1833
+ }
1834
+ if (child.exitCode === null && child.signalCode === null) {
1835
+ child.kill('SIGKILL');
1836
+ await waitForChildExit(child);
1837
+ }
1838
+ };
1775
1839
  const closeElectron = async ({
1776
1840
  browser,
1777
- child
1841
+ child,
1842
+ userDataDir
1778
1843
  }) => {
1779
1844
  try {
1780
1845
  await browser.close();
1781
1846
  } catch {
1782
1847
  // ignore close errors during cleanup
1783
1848
  }
1784
- if (!child.killed) {
1785
- child.kill(SIGINT);
1786
- }
1849
+ await stopElectronProcess(child);
1850
+ await rm(userDataDir, {
1851
+ force: true,
1852
+ recursive: true
1853
+ });
1787
1854
  };
1788
1855
  const createElectronLaunch = ({
1789
1856
  browser,
1790
1857
  child,
1791
1858
  page,
1792
- signal
1859
+ signal,
1860
+ userDataDir
1793
1861
  }) => {
1794
1862
  let disposed = false;
1795
1863
  const dispose = async () => {
@@ -1802,7 +1870,8 @@ const createElectronLaunch = ({
1802
1870
  process.off('SIGTERM', handleSigterm);
1803
1871
  await closeElectron({
1804
1872
  browser,
1805
- child
1873
+ child,
1874
+ userDataDir
1806
1875
  });
1807
1876
  };
1808
1877
  const handleAbort = () => {
@@ -1844,7 +1913,12 @@ const startElectron = async ({
1844
1913
  signal
1845
1914
  }) => {
1846
1915
  const launchOptions = getElectronLaunchOptions(runtimeOptions);
1847
- const child = spawn(launchOptions.executablePath, ['--remote-debugging-port=0', ...launchOptions.args], {
1916
+ const userDataDir = await mkdtemp(join(tmpdir(), 'test-with-playwright-electron-'));
1917
+ const args = getElectronProcessArgs({
1918
+ args: launchOptions.args,
1919
+ userDataDir
1920
+ });
1921
+ const child = spawn(launchOptions.executablePath, args, {
1848
1922
  env: launchOptions.env,
1849
1923
  stdio: ['ignore', 'ignore', 'pipe']
1850
1924
  });
@@ -1854,13 +1928,16 @@ const startElectron = async ({
1854
1928
  const {
1855
1929
  chromium
1856
1930
  } = await import('@playwright/test');
1857
- browser = await chromium.connectOverCDP(endpoint);
1931
+ browser = await chromium.connectOverCDP(endpoint, {
1932
+ timeout: electronConnectionTimeout
1933
+ });
1858
1934
  const page = await getFirstPage(browser);
1859
1935
  return createElectronLaunch({
1860
1936
  browser,
1861
1937
  child,
1862
1938
  page,
1863
- signal
1939
+ signal,
1940
+ userDataDir
1864
1941
  });
1865
1942
  } catch (error) {
1866
1943
  if (browser) {
@@ -1870,9 +1947,11 @@ const startElectron = async ({
1870
1947
  // ignore close errors during cleanup
1871
1948
  }
1872
1949
  }
1873
- if (!child.killed) {
1874
- child.kill(SIGINT);
1875
- }
1950
+ await stopElectronProcess(child);
1951
+ await rm(userDataDir, {
1952
+ force: true,
1953
+ recursive: true
1954
+ });
1876
1955
  throw error;
1877
1956
  }
1878
1957
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/test-with-playwright-worker",
3
- "version": "22.5.0",
3
+ "version": "22.7.0",
4
4
  "description": "Worker package for test-with-playwright",
5
5
  "repository": {
6
6
  "type": "git",