From 82ea66e3747a572fbd4bf5d7a34ace5802216373 Mon Sep 17 00:00:00 2001 From: Nikita Skovoroda Date: Tue, 10 Sep 2024 19:29:48 +0400 Subject: [PATCH] feat: don't expose snapshots, timer, module mocks in in-band tests --- src/jest.js | 20 ++++++++++++++++---- src/jest.snapshot.js | 20 +++++++++++--------- 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/src/jest.js b/src/jest.js index 6d3f935..c85733b 100644 --- a/src/jest.js +++ b/src/jest.js @@ -2,9 +2,6 @@ import { assert, utilFormat, isPromise, mock } from './engine.js' import * as node from './engine.js' import { jestConfig } from './jest.config.js' import { jestFunctionMocks } from './jest.fn.js' -import { jestModuleMocks } from './jest.mock.js' -import * as jestTimers from './jest.timers.js' -import './jest.snapshot.js' import { fetchReplay, fetchRecord, websocketRecord, websocketReplay } from './replay.js' import { createCallerLocationHook, insideEsbuild } from './dark.cjs' import { haveValidTimers } from './version.js' @@ -14,7 +11,22 @@ import { format as prettyFormat } from 'pretty-format' const { getCallerLocation, installLocationInNextTest } = createCallerLocationHook() +async function loadModules() { + if (process.env.EXODUS_TEST_ENVIRONMENT !== 'bundle') { + // We can't provide snapshots in inband tests yet, and mocks/timers are unsafe there + if (process.argv.length === 2 && process.argv[1].endsWith('/inband.js')) return {} + } + + return { + jestTimers: await import('./jest.timers.js'), + ...(await import('./jest.mock.js')), + ...(await import('./jest.snapshot.js')), + } +} + +const { jestModuleMocks, jestTimers, setupSnapshots } = await loadModules() expect.extend(matchers) +setupSnapshots?.(expect) let defaultTimeout = jestConfig().testTimeout // overridable via jest.setTimeout() const defaultConcurrency = jestConfig().maxConcurrency @@ -186,7 +198,7 @@ node.afterEach(() => { if (globalThis.process) { node.after(() => { - jestTimers.useRealTimers() + jestTimers?.useRealTimers?.() const prefix = `Tests completed, but still have asynchronous activity after` // give everything additional (configurable) defaultTimeout time to finish, otherwide fail diff --git a/src/jest.snapshot.js b/src/jest.snapshot.js index fabb9bb..69b34bd 100644 --- a/src/jest.snapshot.js +++ b/src/jest.snapshot.js @@ -6,7 +6,6 @@ import { readSnapshot, relativeRequire, } from './engine.js' -import { expect } from 'expect' import { format, plugins as builtinPlugins } from 'pretty-format' import { jestConfig } from './jest.config.js' import { getTestNamePath } from './dark.cjs' @@ -111,7 +110,7 @@ const deepMerge = (obj, matcher) => { return res } -const snapOnDisk = (orig, matcher) => { +const snapOnDisk = (expect, orig, matcher) => { if (matcher) { expect(orig).toMatchObject(matcher) // If we passed, make appear that the above call never happened @@ -143,11 +142,14 @@ const snapOnDisk = (orig, matcher) => { } } -expect.extend({ - toMatchInlineSnapshot: (obj, i) => wrap(() => snapInline(obj, i)), - toMatchSnapshot: (obj, matcher) => wrap(() => snapOnDisk(obj, matcher)), - toThrowErrorMatchingInlineSnapshot: (...a) => wrap(() => throws(a, (m) => snapInline(m, a[1]))), - toThrowErrorMatchingSnapshot: (...a) => wrap(() => throws(a, (m) => snapOnDisk(m))), -}) +export function setupSnapshots(expect) { + expect.extend({ + toMatchInlineSnapshot: (obj, i) => wrap(() => snapInline(obj, i)), + toMatchSnapshot: (obj, matcher) => wrap(() => snapOnDisk(expect, obj, matcher)), + toThrowErrorMatchingInlineSnapshot: (...a) => wrap(() => throws(a, (m) => snapInline(m, a[1]))), + toThrowErrorMatchingSnapshot: (...a) => wrap(() => throws(a, (m) => snapOnDisk(expect, m))), + }) -expect.addSnapshotSerializer = (plugin) => plugins.push(plugin) + // eslint-disable-next-line @exodus/mutable/no-param-reassign-prop-only + expect.addSnapshotSerializer = (plugin) => plugins.push(plugin) +}