@exodus/test 1.0.0-rc.76 → 1.0.0-rc.78
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 +2 -2
- package/bin/browsers.js +14 -1
- package/bin/inband.js +3 -1
- package/bin/index.js +6 -1
- package/package.json +1 -1
- package/src/jest.js +13 -5
- package/src/jest.timers.js +7 -1
package/README.md
CHANGED
|
@@ -18,8 +18,8 @@ It can run your existing tests on [all runtimes and also browsers](#engines), wi
|
|
|
18
18
|
- Actual `expect` module, also `jest-extended` and `jest-when` just work on top
|
|
19
19
|
- Snapshots, including snapshot matchers
|
|
20
20
|
- Function and timer mocks
|
|
21
|
-
- [test.concurrent]()
|
|
22
|
-
- Module mocks (
|
|
21
|
+
- [test.concurrent](https://jestjs.io/docs/api#testconcurrentname-fn-timeout)
|
|
22
|
+
- Module mocks, including for ESM modules (already loaded ESM modules can be mocked only on `node:test`)
|
|
23
23
|
- Loads Jest configuration
|
|
24
24
|
- It works on Hermes too!
|
|
25
25
|
- Built-in network record/replay for offline tests, mocking `fetch` and `WebSocket` sessions
|
package/bin/browsers.js
CHANGED
|
@@ -43,7 +43,20 @@ async function newPage(runner, browser, { binary, dropNetwork }) {
|
|
|
43
43
|
return newPage(runner, browser, { binary, dropNetwork })
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
// Need to load a secure origin for e.g. crypto.subtle to be available
|
|
47
|
+
if (runner === 'playwright' && binary === 'webkit') {
|
|
48
|
+
// Can attempt to download /dev/null, so we apply a work-around
|
|
49
|
+
await page.route('https://www.secure-context-top-level-domain-for-tests/*', (route) =>
|
|
50
|
+
route.fulfill({
|
|
51
|
+
status: 200,
|
|
52
|
+
contentType: 'text/html; charset=utf-8',
|
|
53
|
+
body: '<!doctype html><html><body></body></html>',
|
|
54
|
+
})
|
|
55
|
+
)
|
|
56
|
+
await page.goto('https://www.secure-context-top-level-domain-for-tests/')
|
|
57
|
+
} else {
|
|
58
|
+
await page.goto('file:///dev/null')
|
|
59
|
+
}
|
|
47
60
|
|
|
48
61
|
if (dropNetwork && context.setOffline) await context.setOffline(true)
|
|
49
62
|
if (dropNetwork && page.setOfflineMode) await page.setOfflineMode(true)
|
package/bin/inband.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { resolve } from 'node:path'
|
|
2
|
-
import { describe } from '../src/engine.js'
|
|
2
|
+
import { describe, after } from '../src/engine.js'
|
|
3
3
|
|
|
4
4
|
const files = JSON.parse(process.env.EXODUS_TEST_INBAND)
|
|
5
5
|
if (!Array.isArray(files)) throw new Error('Unexpected')
|
|
@@ -9,3 +9,5 @@ for (const file of files.sort()) {
|
|
|
9
9
|
await import(resolve(file))
|
|
10
10
|
})
|
|
11
11
|
}
|
|
12
|
+
|
|
13
|
+
if (globalThis.EXODUS_TEST_AFTER_INBAND) after(globalThis.EXODUS_TEST_AFTER_INBAND)
|
package/bin/index.js
CHANGED
|
@@ -572,7 +572,7 @@ if (options.pure) {
|
|
|
572
572
|
const missUnhandled = ['jsc'].includes(options.platform) || options.browsers
|
|
573
573
|
if (missUnhandled) warnHuman(`Warning: ${engineName} does not have unhandled rejections tracking`)
|
|
574
574
|
|
|
575
|
-
const runOne = async (inputFile) => {
|
|
575
|
+
const runOne = async (inputFile, attempt = 0) => {
|
|
576
576
|
const bundled = buildFile ? await buildFile(inputFile) : undefined
|
|
577
577
|
if (buildFile) assert(bundled.file)
|
|
578
578
|
const file = buildFile ? bundled.file : inputFile
|
|
@@ -589,6 +589,11 @@ if (options.pure) {
|
|
|
589
589
|
const ms = Number(process.hrtime.bigint() - start) / 1e6
|
|
590
590
|
return { ok: code === 0, output: [stdout, stderr], ms }
|
|
591
591
|
} catch (err) {
|
|
592
|
+
if (options.engine === 'xs:bundle' && err.signal === 'SIGSEGV' && attempt < 2) {
|
|
593
|
+
// xs sometimes randomly crashes with SIGSEGV on CI. Allow 3 attempts (allow 0 - 1 to fail)
|
|
594
|
+
return runOne(inputFile, attempt + 1)
|
|
595
|
+
}
|
|
596
|
+
|
|
592
597
|
const ms = Number(process.hrtime.bigint() - start) / 1e6
|
|
593
598
|
const { code, stdout = '', stderr = '', signal, killed } = err
|
|
594
599
|
if (code === null) {
|
package/package.json
CHANGED
package/src/jest.js
CHANGED
|
@@ -12,13 +12,14 @@ import { format as prettyFormat } from 'pretty-format'
|
|
|
12
12
|
|
|
13
13
|
const { getCallerLocation, installLocationInNextTest } = createCallerLocationHook()
|
|
14
14
|
|
|
15
|
-
let
|
|
15
|
+
let inband = false
|
|
16
16
|
if (process.env.EXODUS_TEST_ENVIRONMENT !== 'bundle') {
|
|
17
|
-
// We can't provide snapshots in inband tests yet, and mocks/timers are unsafe there
|
|
18
17
|
const files = process.argv.slice(1)
|
|
19
|
-
if (files.length === 1 && files[0].endsWith('/inband.js'))
|
|
18
|
+
if (files.length === 1 && files[0].endsWith('/inband.js')) inband = true
|
|
20
19
|
}
|
|
21
20
|
|
|
21
|
+
// We can't provide snapshots in inband tests yet, and mocks/timers are unsafe there
|
|
22
|
+
const addStatefulApis = !inband
|
|
22
23
|
if (addStatefulApis) setupSnapshots(expect)
|
|
23
24
|
|
|
24
25
|
let defaultTimeout = Number(process.env.EXODUS_TEST_TIMEOUT) || jestConfig().testTimeout // overridable via jest.setTimeout()
|
|
@@ -199,7 +200,8 @@ node.afterEach(() => {
|
|
|
199
200
|
|
|
200
201
|
if (process.env.EXODUS_TEST_PLATFORM !== 'deno' && globalThis.process) {
|
|
201
202
|
// TODO: deno, other engines
|
|
202
|
-
|
|
203
|
+
// This doesn't work with async imported tests, so for inband, we delay
|
|
204
|
+
const after = () => {
|
|
203
205
|
jestTimers.useRealTimers()
|
|
204
206
|
const prefix = `Tests completed, but still have asynchronous activity after`
|
|
205
207
|
|
|
@@ -217,7 +219,13 @@ if (process.env.EXODUS_TEST_PLATFORM !== 'deno' && globalThis.process) {
|
|
|
217
219
|
console.warn(`${prefix} ${warnTimeout}ms. Waiting for ${timeout}ms to pass to finish...`)
|
|
218
220
|
}, warnTimeout).unref()
|
|
219
221
|
}
|
|
220
|
-
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
if (inband) {
|
|
225
|
+
globalThis.EXODUS_TEST_AFTER_INBAND = after
|
|
226
|
+
} else {
|
|
227
|
+
node.after(after)
|
|
228
|
+
}
|
|
221
229
|
}
|
|
222
230
|
|
|
223
231
|
export const jest = {
|
package/src/jest.timers.js
CHANGED
|
@@ -66,8 +66,14 @@ export function runOnlyPendingTimers() {
|
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
export function advanceTimersByTime(time) {
|
|
69
|
-
assert(Number.isSafeInteger(time) && time
|
|
69
|
+
assert(Number.isSafeInteger(time) && time >= 0)
|
|
70
70
|
assertEnabledTimers()
|
|
71
|
+
|
|
72
|
+
if (time === 0) {
|
|
73
|
+
mock.timers.tick(0)
|
|
74
|
+
return this
|
|
75
|
+
}
|
|
76
|
+
|
|
71
77
|
// We split this into multiple steps to run timers scheduled during the time we are running
|
|
72
78
|
const minSteps = Math.min(1000, time) // usually just split e.g. 5 seconds into 1000 * 5ms
|
|
73
79
|
const step = Number(Math.floor(time / minSteps).toPrecision(1))
|