@lvce-editor/test-with-playwright-worker 0.1.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 (59) hide show
  1. package/index.js +6 -0
  2. package/package.json +25 -0
  3. package/src/parts/Assert/Assert.js +59 -0
  4. package/src/parts/AssertionError/AssertionError.js +6 -0
  5. package/src/parts/Callback/Callback.js +39 -0
  6. package/src/parts/Character/Character.js +11 -0
  7. package/src/parts/CleanStack/CleanStack.js +93 -0
  8. package/src/parts/Cli/Cli.js +8 -0
  9. package/src/parts/CliCommandType/CliCommandType.js +2 -0
  10. package/src/parts/Command/Command.js +9 -0
  11. package/src/parts/CommandMap/CommandMap.js +6 -0
  12. package/src/parts/CommandNotFoundError/CommandNotFoundError.js +9 -0
  13. package/src/parts/CommandState/CommandState.js +17 -0
  14. package/src/parts/EncodingType/EncodingType.js +1 -0
  15. package/src/parts/ErrorCodes/ErrorCodes.js +19 -0
  16. package/src/parts/GetErrorResponse/GetErrorResponse.js +56 -0
  17. package/src/parts/GetPort/GetPort.js +5 -0
  18. package/src/parts/GetResponse/GetResponse.js +12 -0
  19. package/src/parts/GetServerPath/GetServerPath.js +4 -0
  20. package/src/parts/GetSuccessResponse/GetSuccessResponse.js +12 -0
  21. package/src/parts/GetTestState/GetTestState.js +24 -0
  22. package/src/parts/GetTests/GetTests.js +22 -0
  23. package/src/parts/HandleCliArgs/HandleCliArgs.js +19 -0
  24. package/src/parts/HandleIpc/HandleIpc.js +13 -0
  25. package/src/parts/Id/Id.js +7 -0
  26. package/src/parts/IpcChild/IpcChild.js +9 -0
  27. package/src/parts/IpcChildModule/IpcChildModule.js +12 -0
  28. package/src/parts/IpcChildType/IpcChildType.js +13 -0
  29. package/src/parts/IpcChildWithNodeForkedProcess/IpcChildWithNodeForkedProcess.js +41 -0
  30. package/src/parts/IpcChildWithNodeWorker/IpcChildWithNodeWorker.js +27 -0
  31. package/src/parts/IpcError/IpcError.js +6 -0
  32. package/src/parts/IsTestFile/IsTestFile.js +6 -0
  33. package/src/parts/JoinLines/JoinLines.js +5 -0
  34. package/src/parts/Json/Json.js +17 -0
  35. package/src/parts/JsonError/JsonError.js +64 -0
  36. package/src/parts/JsonParsingError/JsonParsingError.js +17 -0
  37. package/src/parts/JsonRpc/JsonRpc.js +35 -0
  38. package/src/parts/JsonRpcErrorCode/JsonRpcErrorCode.js +2 -0
  39. package/src/parts/JsonRpcVersion/JsonRpcVersion.js +1 -0
  40. package/src/parts/Logger/Logger.js +43 -0
  41. package/src/parts/Main/Main.js +36 -0
  42. package/src/parts/NoTestFilesFoundError/NoTestFilesFoundError.js +8 -0
  43. package/src/parts/PrettyError/PrettyError.js +139 -0
  44. package/src/parts/PrintPrettyError/PrintPrettyError.js +5 -0
  45. package/src/parts/Process/Process.js +20 -0
  46. package/src/parts/ProcessListeners/ProcessListeners.js +3 -0
  47. package/src/parts/RunAllTests/RunAllTests.js +45 -0
  48. package/src/parts/RunTest/RunTest.js +37 -0
  49. package/src/parts/RunTests/RunTests.js +44 -0
  50. package/src/parts/SetupTests/SetupTests.js +25 -0
  51. package/src/parts/Signal/Signal.js +1 -0
  52. package/src/parts/SplitLines/SplitLines.js +5 -0
  53. package/src/parts/StartBrowser/StartBrowser.js +21 -0
  54. package/src/parts/StartServer/StartServer.js +29 -0
  55. package/src/parts/TearDownTests/TearDownTests.js +6 -0
  56. package/src/parts/TestOverlayState/TestOverlayState.js +3 -0
  57. package/src/parts/TestState/TestState.js +3 -0
  58. package/src/parts/TestWorkerCommandType/TestWorkerCommandType.js +1 -0
  59. package/src/workerMain.js +3 -0
@@ -0,0 +1,64 @@
1
+ import { codeFrameColumns } from '@babel/code-frame'
2
+ import { LinesAndColumns } from 'lines-and-columns'
3
+
4
+ // parsing error handling based on https://github.com/sindresorhus/parse-json/blob/main/index.js
5
+
6
+ const emptyError = {
7
+ message: '',
8
+ stack: '',
9
+ codeFrame: '',
10
+ }
11
+
12
+ export const getErrorPropsFromError = (error, string, filePath) => {
13
+ const indexMatch = error.message.match(/in JSON at position (\d+)/)
14
+ if (indexMatch && indexMatch.length > 0) {
15
+ const lines = new LinesAndColumns(string)
16
+ const index = Number(indexMatch[1])
17
+ const location = lines.locationForIndex(index)
18
+ if (location) {
19
+ const line = location.line + 1
20
+ const column = location.column + 1
21
+ const codeFrame = codeFrameColumns(string, { start: { line, column } }, { highlightCode: false })
22
+ return {
23
+ codeFrame,
24
+ message: 'Json Parsing Error',
25
+ stack: ` at ${filePath}:${line}:${column}`,
26
+ }
27
+ }
28
+ }
29
+ if (string.length === 0) {
30
+ return {
31
+ codeFrame: ``,
32
+ message: 'Json Parsing Error: Cannot parse empty string',
33
+ stack: ` at ${filePath}`,
34
+ }
35
+ }
36
+
37
+ if (error.message === 'Unexpected end of JSON input') {
38
+ const lines = new LinesAndColumns(string)
39
+ const index = string.length - 1
40
+ const location = lines.locationForIndex(index)
41
+ if (location) {
42
+ const codeFrame = codeFrameColumns(string, { start: { line: location.line + 1, column: location.column + 1 } }, { highlightCode: false })
43
+ return {
44
+ codeFrame,
45
+ message: 'Json Parsing Error',
46
+ stack: ` at ${filePath}`,
47
+ }
48
+ }
49
+ }
50
+ return {
51
+ codeFrame: ``,
52
+ message: 'Json Parsing Error',
53
+ stack: ` at ${filePath}`,
54
+ }
55
+ }
56
+
57
+ export const getErrorProps = (string, filePath) => {
58
+ try {
59
+ JSON.parse(string)
60
+ return emptyError
61
+ } catch (error) {
62
+ return getErrorPropsFromError(error, string, filePath)
63
+ }
64
+ }
@@ -0,0 +1,17 @@
1
+ import * as JoinLines from '../JoinLines/JoinLines.js'
2
+ import * as SplitLines from '../SplitLines/SplitLines.js'
3
+
4
+ export class JsonParsingError extends Error {
5
+ constructor(message, codeFrame, stack) {
6
+ super(message)
7
+ this.name = 'JsonParsingError'
8
+ if (codeFrame) {
9
+ this.codeFrame = codeFrame
10
+ }
11
+
12
+ if (stack) {
13
+ const parentStack = JoinLines.joinLines(SplitLines.splitLines(this.stack).slice(1))
14
+ this.stack = this.name + ': ' + this.message + '\n' + stack + '\n' + parentStack
15
+ }
16
+ }
17
+ }
@@ -0,0 +1,35 @@
1
+ import * as Callback from '../Callback/Callback.js'
2
+ import * as JsonRpcVersion from '../JsonRpcVersion/JsonRpcVersion.js'
3
+
4
+ export const send = (transport, method, ...params) => {
5
+ transport.send({
6
+ jsonrpc: JsonRpcVersion.Two,
7
+ method,
8
+ params,
9
+ })
10
+ }
11
+
12
+ export const invoke = (ipc, method, ...params) => {
13
+ const { id, promise } = Callback.registerPromise()
14
+ ipc.send({
15
+ jsonrpc: JsonRpcVersion.Two,
16
+ method,
17
+ params,
18
+ id,
19
+ })
20
+ return promise
21
+ }
22
+
23
+ export const invokeAndTransfer = (ipc, handle, method, ...params) => {
24
+ const { id, promise } = Callback.registerPromise()
25
+ ipc.sendAndTransfer(
26
+ {
27
+ jsonrpc: JsonRpcVersion.Two,
28
+ method,
29
+ params,
30
+ id,
31
+ },
32
+ handle
33
+ )
34
+ return promise
35
+ }
@@ -0,0 +1,2 @@
1
+ export const MethodNotFound = -32601
2
+ export const Custom = -32001
@@ -0,0 +1 @@
1
+ export const Two = '2.0'
@@ -0,0 +1,43 @@
1
+ // TODO mock this module when used in unit tests
2
+
3
+ const state = {
4
+ /**
5
+ * @type {Console|undefined}
6
+ */
7
+ console: undefined,
8
+ }
9
+
10
+ const createConsole = () => {
11
+ return console
12
+ }
13
+
14
+ const getOrCreateLogger = () => {
15
+ if (!state.console) {
16
+ state.console = createConsole()
17
+ }
18
+ return state.console
19
+ }
20
+
21
+ export const log = (...args) => {
22
+ const logger = getOrCreateLogger()
23
+ logger.log(...args)
24
+ console.log(...args)
25
+ }
26
+
27
+ export const info = (...args) => {
28
+ const logger = getOrCreateLogger()
29
+ logger.info(...args)
30
+ console.info(...args)
31
+ }
32
+
33
+ export const warn = (...args) => {
34
+ const logger = getOrCreateLogger()
35
+ logger.warn(...args)
36
+ console.warn(...args)
37
+ }
38
+
39
+ export const error = (...args) => {
40
+ const logger = getOrCreateLogger()
41
+ logger.error(...args)
42
+ console.error(...args)
43
+ }
@@ -0,0 +1,36 @@
1
+ import * as CommandMap from '../CommandMap/CommandMap.js'
2
+ import * as CommandState from '../CommandState/CommandState.js'
3
+ import * as HandleIpc from '../HandleIpc/HandleIpc.js'
4
+ import * as IpcChild from '../IpcChild/IpcChild.js'
5
+ import * as IpcChildType from '../IpcChildType/IpcChildType.js'
6
+ import * as Process from '../Process/Process.js'
7
+ import * as ProcessListeners from '../ProcessListeners/ProcessListeners.js'
8
+
9
+ const handleDisconnect = () => {
10
+ console.log('[test-worker] disconnected')
11
+ }
12
+
13
+ const handleExit = () => {
14
+ console.log('[test-worker] exiting')
15
+ }
16
+
17
+ const handleSigint = () => {
18
+ console.log('[test-worker] sigint')
19
+ }
20
+
21
+ const handleSigTerm = () => {
22
+ console.log('[test-worker] sigterm')
23
+ }
24
+
25
+ export const main = async () => {
26
+ Process.on('disconnect', handleDisconnect)
27
+ Process.on('exit', handleExit)
28
+ Process.on('SIGINT', handleSigint)
29
+ Process.on('SIGTERM', handleSigTerm)
30
+ Process.on('uncaughtExceptionMonitor', ProcessListeners.handleUncaughtExceptionMonitor)
31
+ CommandState.registerCommands(CommandMap.commandMap)
32
+ const ipc = await IpcChild.listen({
33
+ method: IpcChildType.Auto(),
34
+ })
35
+ HandleIpc.handleIpc(ipc)
36
+ }
@@ -0,0 +1,8 @@
1
+ import * as ErrorCodes from '../ErrorCodes/ErrorCodes.js'
2
+
3
+ export class NoTestFilesFoundError extends Error {
4
+ constructor(root) {
5
+ super(`No test files found at ${root}`)
6
+ this.code = ErrorCodes.E_NO_TEST_FILES
7
+ }
8
+ }
@@ -0,0 +1,139 @@
1
+ import { codeFrameColumns } from '@babel/code-frame'
2
+ import { LinesAndColumns } from 'lines-and-columns'
3
+ import { readFileSync } from 'node:fs'
4
+ import { fileURLToPath } from 'node:url'
5
+ import { AssertionError } from '../AssertionError/AssertionError.js'
6
+ import * as CleanStack from '../CleanStack/CleanStack.js'
7
+ import * as EncodingType from '../EncodingType/EncodingType.js'
8
+ import * as ErrorCodes from '../ErrorCodes/ErrorCodes.js'
9
+ import * as JoinLines from '../JoinLines/JoinLines.js'
10
+ import * as Json from '../Json/Json.js'
11
+ import * as SplitLines from '../SplitLines/SplitLines.js'
12
+
13
+ const getActualPath = (fileUri) => {
14
+ if (fileUri.startsWith('file://')) {
15
+ return fileURLToPath(fileUri)
16
+ }
17
+ return fileUri
18
+ }
19
+
20
+ const RE_MODULE_NOT_FOUND_STACK = /Cannot find package '([^']+)' imported from (.+)$/
21
+
22
+ const prepareModuleNotFoundError = (error) => {
23
+ const { message } = error
24
+ const match = message.match(RE_MODULE_NOT_FOUND_STACK)
25
+ if (!match) {
26
+ return {
27
+ message,
28
+ stack: error.stack,
29
+ codeFrame: '',
30
+ }
31
+ }
32
+ const notFoundModule = match[1]
33
+ const importedFrom = match[2]
34
+ const rawLines = readFileSync(importedFrom, EncodingType.Utf8)
35
+ let line = 0
36
+ let column = 0
37
+ const splittedLines = SplitLines.splitLines(rawLines)
38
+ for (let i = 0; i < splittedLines.length; i++) {
39
+ const splittedLine = splittedLines[i]
40
+ const index = splittedLine.indexOf(notFoundModule)
41
+ if (index !== -1) {
42
+ line = i + 1
43
+ column = index
44
+ break
45
+ }
46
+ }
47
+ const location = {
48
+ start: {
49
+ line,
50
+ column,
51
+ },
52
+ }
53
+ const codeFrame = codeFrameColumns(rawLines, location)
54
+ const stackLines = SplitLines.splitLines(error.stack)
55
+ const newStackLines = [stackLines[0], ` at ${importedFrom}:${line}:${column}`, ...stackLines.slice(1)]
56
+ const newStack = JoinLines.joinLines(newStackLines)
57
+ return {
58
+ message,
59
+ stack: newStack,
60
+ codeFrame,
61
+ }
62
+ }
63
+
64
+ const getStackLinesToCut = (error) => {
65
+ if (error instanceof AssertionError) {
66
+ return 1
67
+ }
68
+ return 0
69
+ }
70
+
71
+ export const prepare = (error) => {
72
+ if (error && error.code === ErrorCodes.ERR_MODULE_NOT_FOUND) {
73
+ return prepareModuleNotFoundError(error)
74
+ }
75
+ const { message } = error
76
+ if (error && error.cause) {
77
+ const cause = error.cause()
78
+ if (cause) {
79
+ error = cause
80
+ }
81
+ }
82
+ const linesToCut = getStackLinesToCut(error)
83
+ const lines = CleanStack.cleanStack(error.stack).slice(linesToCut)
84
+ const file = lines[0]
85
+ let codeFrame = ''
86
+ if (error.codeFrame) {
87
+ codeFrame = error.codeFrame
88
+ } else if (file) {
89
+ let match = file.match(/\((.*):(\d+):(\d+)\)$/)
90
+ if (!match) {
91
+ match = file.match(/at (.*):(\d+):(\d+)$/)
92
+ }
93
+ if (match) {
94
+ const [_, path, line, column] = match
95
+ const actualPath = getActualPath(path)
96
+ const rawLines = readFileSync(actualPath, EncodingType.Utf8)
97
+ const location = {
98
+ start: {
99
+ line: Number.parseInt(line),
100
+ column: Number.parseInt(column),
101
+ },
102
+ }
103
+ codeFrame = codeFrameColumns(rawLines, location)
104
+ }
105
+ }
106
+ const relevantStack = JoinLines.joinLines(lines)
107
+ return {
108
+ message,
109
+ stack: relevantStack,
110
+ codeFrame,
111
+ type: error.constructor.name,
112
+ code: error.code,
113
+ }
114
+ }
115
+
116
+ const fixBackslashes = (string) => {
117
+ return string.replaceAll('\\\\', '\\')
118
+ }
119
+
120
+ export const prepareJsonError = (json, property, message) => {
121
+ const string = fixBackslashes(Json.stringify(json))
122
+ const stringifiedPropertyName = `"${property}"`
123
+ const index = string.indexOf(stringifiedPropertyName) // TODO this could be wrong in some cases, find a better way
124
+ console.log({ string, index })
125
+ const jsonError = {
126
+ stack: '',
127
+ }
128
+ if (index !== -1) {
129
+ const lines = new LinesAndColumns(string)
130
+ const location = lines.locationForIndex(index + stringifiedPropertyName.length + 1)
131
+ const codeFrame = codeFrameColumns(string, {
132
+ // @ts-ignore
133
+ start: { line: location.line + 1, column: location.column + 1 },
134
+ })
135
+ jsonError.codeFrame = codeFrame
136
+ }
137
+ // jsonError.stack = `${bottomMessage}\n at ${filePath}`
138
+ return jsonError
139
+ }
@@ -0,0 +1,5 @@
1
+ import * as Logger from '../Logger/Logger.js'
2
+
3
+ export const printPrettyError = (prettyError, prefix = '') => {
4
+ Logger.error(`${prefix}${prettyError.type}: ${prettyError.message}\n\n${prettyError.codeFrame}\n\n${prettyError.stack}\n`)
5
+ }
@@ -0,0 +1,20 @@
1
+ export const argv = process.argv
2
+
3
+ export const env = process.env
4
+
5
+ /**
6
+ *
7
+ * @param {number} code
8
+ */
9
+ export const exit = (code) => {
10
+ process.exit(code)
11
+ }
12
+
13
+ /**
14
+ *
15
+ * @param {string} event
16
+ * @param {any} listener
17
+ */
18
+ export const on = (event, listener) => {
19
+ process.on(event, listener)
20
+ }
@@ -0,0 +1,3 @@
1
+ export const handleUncaughtExceptionMonitor = (error) => {
2
+ console.log(`[test-worker] uncaught exception ${error}`)
3
+ }
@@ -0,0 +1,45 @@
1
+ import { join } from 'path'
2
+ import * as Assert from '../Assert/Assert.js'
3
+ import * as GetTests from '../GetTests/GetTests.js'
4
+ import * as RunTests from '../RunTests/RunTests.js'
5
+ import * as SetupTests from '../SetupTests/SetupTests.js'
6
+ import * as TearDownTests from '../TearDownTests/TearDownTests.js'
7
+ import * as JsonRpc from '../JsonRpc/JsonRpc.js'
8
+ import * as CliCommandType from '../CliCommandType/CliCommandType.js'
9
+
10
+ /**
11
+ * @param {any} ipc
12
+ * @param {string} extensionPath
13
+ * @param {string} testPath
14
+ * @param {string} cwd
15
+ * @param {boolean} headless
16
+ * @param {number} headless
17
+ */
18
+ export const runAllTests = async (ipc, extensionPath, testPath, cwd, headless, timeout) => {
19
+ Assert.string(extensionPath)
20
+ Assert.string(testPath)
21
+ Assert.string(cwd)
22
+ Assert.boolean(headless)
23
+ Assert.number(timeout)
24
+ const controller = new AbortController()
25
+ const signal = controller.signal
26
+ const { browser, page, child, port } = await SetupTests.setupTests({
27
+ signal,
28
+ headless,
29
+ onlyExtension: extensionPath,
30
+ testPath,
31
+ })
32
+ const testSrc = join(testPath, 'src')
33
+ const tests = await GetTests.getTests(testSrc)
34
+ const onResult = (result) => {
35
+ JsonRpc.send(ipc, CliCommandType.HandleResult, result)
36
+ }
37
+ const onFinalResult = (finalResult) => {
38
+ JsonRpc.send(ipc, CliCommandType.HandleFinalResult, finalResult)
39
+ }
40
+ await RunTests.runTests({ testSrc, tests, headless, port, page, timeout, onResult, onFinalResult })
41
+ await TearDownTests.tearDownTests({
42
+ controller,
43
+ child,
44
+ })
45
+ }
@@ -0,0 +1,37 @@
1
+ import { expect } from '@playwright/test'
2
+ import { basename } from 'node:path'
3
+ import { join } from 'path'
4
+ import * as GetTestState from '../GetTestState/GetTestState.js'
5
+
6
+ /**
7
+ * @param {string} absolutePath
8
+ * @param {number} port
9
+ */
10
+ const getUrlFromTestFile = (absolutePath, port) => {
11
+ const baseName = basename(absolutePath)
12
+ const htmlFileName = baseName.slice(0, -'.js'.length) + '.html'
13
+ return `http://localhost:${port}/tests/${htmlFileName}`
14
+ }
15
+
16
+ export const runTest = async ({ test, page, testSrc, port, timeout }) => {
17
+ const start = performance.now()
18
+ const url = getUrlFromTestFile(test, port)
19
+ await page.goto(url, {
20
+ waitUntil: 'networkidle',
21
+ })
22
+ const testOverlay = page.locator('#TestOverlay')
23
+ await expect(testOverlay).toBeVisible({
24
+ timeout,
25
+ })
26
+ const text = await testOverlay.textContent()
27
+ const testOverlayState = await testOverlay.getAttribute('data-state')
28
+ const testState = GetTestState.getTestState(testOverlayState)
29
+ const end = performance.now()
30
+ return {
31
+ ...testState,
32
+ name: test,
33
+ start,
34
+ end,
35
+ error: text,
36
+ }
37
+ }
@@ -0,0 +1,44 @@
1
+ import * as RunTest from '../RunTest/RunTest.js'
2
+ import * as TestState from '../TestState/TestState.js'
3
+
4
+ /**
5
+ *
6
+ * @param {{testSrc:string, tests:string[], headless:boolean, page: import('@playwright/test').Page, port:number, timeout:number, onResult:any, onFinalResult:any}} param0
7
+ */
8
+ export const runTests = async ({ testSrc, tests, headless, page, port, timeout, onResult, onFinalResult }) => {
9
+ let failed = 0
10
+ let skipped = 0
11
+ let passed = 0
12
+ const start = performance.now()
13
+ for (const test of tests) {
14
+ const result = await RunTest.runTest({
15
+ test,
16
+ page,
17
+ testSrc,
18
+ port,
19
+ timeout,
20
+ })
21
+ onResult(result)
22
+ switch (result.status) {
23
+ case TestState.Fail:
24
+ failed++
25
+ break
26
+ case TestState.Skip:
27
+ skipped++
28
+ break
29
+ case TestState.Pass:
30
+ passed++
31
+ break
32
+ default:
33
+ break
34
+ }
35
+ }
36
+ const end = performance.now()
37
+ onFinalResult({
38
+ passed,
39
+ failed,
40
+ skipped,
41
+ start,
42
+ end,
43
+ })
44
+ }
@@ -0,0 +1,25 @@
1
+ import * as StartBrowser from '../StartBrowser/StartBrowser.js'
2
+ import * as StartServer from '../StartServer/StartServer.js'
3
+ import * as GetPort from '../GetPort/GetPort.js'
4
+ import * as GetServerPath from '../GetServerPath/GetServerPath.js'
5
+
6
+ /**
7
+ *
8
+ * @param {{signal:AbortSignal, headless: boolean, onlyExtension:string, testPath:string}} options
9
+ * @returns
10
+ */
11
+ export const setupTests = async ({ signal, headless, onlyExtension, testPath }) => {
12
+ const port = await GetPort.getPort()
13
+ const { browser, page } = await StartBrowser.startBrowser({
14
+ signal,
15
+ headless,
16
+ })
17
+ const serverPath = await GetServerPath.getServerPath()
18
+ const child = await StartServer.startServer({ signal, port, serverPath, onlyExtension, testPath })
19
+ return {
20
+ port,
21
+ browser,
22
+ page,
23
+ child,
24
+ }
25
+ }
@@ -0,0 +1 @@
1
+ export const SIGINT = 'SIGINT'
@@ -0,0 +1,5 @@
1
+ import * as Character from '../Character/Character.js'
2
+
3
+ export const splitLines = (lines) => {
4
+ return lines.split(Character.NewLine)
5
+ }
@@ -0,0 +1,21 @@
1
+ import { chromium } from '@playwright/test'
2
+
3
+ /**
4
+ *
5
+ * @param {{signal:AbortSignal, headless:boolean}} options
6
+ * @returns
7
+ */
8
+ export const startBrowser = async ({ signal, headless }) => {
9
+ const browser = await chromium.launch({
10
+ headless,
11
+ })
12
+ const page = await browser.newPage()
13
+ signal.addEventListener('abort', async () => {
14
+ await page.close()
15
+ await browser.close()
16
+ })
17
+ return {
18
+ browser,
19
+ page,
20
+ }
21
+ }
@@ -0,0 +1,29 @@
1
+ import { fork } from 'child_process'
2
+
3
+ /**
4
+ *
5
+ * @param {{signal:AbortSignal, port:number, serverPath:string, onlyExtension:string, testPath:string}} param0
6
+ * @returns
7
+ */
8
+ export const startServer = async ({ signal, port, serverPath, onlyExtension, testPath }) => {
9
+ const child = fork(serverPath, {
10
+ stdio: 'inherit',
11
+ // signal,
12
+ env: {
13
+ ...process.env,
14
+ PORT: String(port),
15
+ ONLY_EXTENSION: onlyExtension,
16
+ TEST_PATH: testPath,
17
+ },
18
+ })
19
+ child.on('error', (x) => {
20
+ if (x.name === 'AbortError') {
21
+ return
22
+ }
23
+ console.log('child error', x)
24
+ })
25
+ await new Promise((resolve) => {
26
+ child.on('message', resolve)
27
+ })
28
+ return child
29
+ }
@@ -0,0 +1,6 @@
1
+ import * as Signal from '../Signal/Signal.js'
2
+
3
+ export const tearDownTests = ({ controller, child }) => {
4
+ controller.abort()
5
+ child.kill(Signal.SIGINT)
6
+ }
@@ -0,0 +1,3 @@
1
+ export const Pass = 'pass'
2
+ export const Skip = 'skip'
3
+ export const Fail = 'fail'
@@ -0,0 +1,3 @@
1
+ export const Pass = 1
2
+ export const Skip = 2
3
+ export const Fail = 3
@@ -0,0 +1 @@
1
+ export const RunAllTests = 'RunAllTests'
@@ -0,0 +1,3 @@
1
+ import * as Main from './parts/Main/Main.js'
2
+
3
+ Main.main()