Skip to content

Commit

Permalink
perf: lazy-load expect when needed
Browse files Browse the repository at this point in the history
  • Loading branch information
ChALkeR committed Sep 10, 2024
1 parent eec3fa5 commit b28d780
Show file tree
Hide file tree
Showing 4 changed files with 131 additions and 4 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
},
"exports": {
"./node-test-reporter": "./bin/reporter.js",
"./expect": "./src/expect.cjs",
"./jest": "./src/jest.js",
"./node": "./src/node.js",
"./tape": {
Expand Down Expand Up @@ -67,6 +68,7 @@
"src/engine.pure.cjs",
"src/engine.pure.snapshot.cjs",
"src/engine.select.cjs",
"src/expect.cjs",
"src/jest.js",
"src/jest.config.js",
"src/jest.config.fs.js",
Expand Down
125 changes: 125 additions & 0 deletions src/expect.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
let expect
let assertionsDelta = 0
const extend = []
const set = []

function fixupAssertions() {
if (assertionsDelta === 0) return
const state = expect.getState()
state.assertionCalls += assertionsDelta
state.numPassingAsserts += assertionsDelta
assertionsDelta = 0
}

function loadExpect() {
if (expect) return expect
expect = require('expect').expect
const matchers = require('jest-extended')
expect.extend(matchers)
for (const x of extend) expect.extend(...x)
for (const [key, value] of set) expect[key] = value
fixupAssertions()
return expect
}

const areNumeric = (...args) => args.every((a) => typeof a === 'number' || typeof a === 'bigint')

const matchers = {
__proto__: null,
toBe: (x, y) => x === y,
toBeNull: (x) => x === null,
toBeTruthy: (x) => x,
toBeFalsy: (x) => !x,
toBeTrue: (x) => x === true,
toBeFalse: (x) => x === false,
toBeDefined: (x) => x !== undefined,
toBeUndefined: (x) => x === undefined,
toBeInstanceOf: (x, y) => y && x instanceof y,
toBeString: (x) => typeof x === 'string' || x instanceof String,
toBeNumber: (x) => typeof x === 'number', // yes, mismatches toBeString logic. yes, no bigints
toBeArray: (x) => Array.isArray(x),
toBeArrayOfSize: (x, l) => Array.isArray(x) && x.length === l,
toHaveLength: (x, l) => x && x.length === l,
toBeGreaterThan: (x, c) => areNumeric(x, c) && x > c,
toBeGreaterThanOrEqual: (x, c) => areNumeric(x, c) && x >= c,
toBeLessThan: (x, c) => areNumeric(x, c) && x < c,
toBeLessThanOrEqual: (x, c) => areNumeric(x, c) && x <= c,
toHaveBeenCalled: (x) => x?._isMockFunction && x?.mock?.calls?.length > 0,
toHaveBeenCalledTimes: (x, c) => x?._isMockFunction && x?.mock?.calls?.length === c,
toBeCalled: (...a) => matchers.toHaveBeenCalled(...a),
toBeCalledTimes: (...a) => matchers.toHaveBeenCalledTimes(...a),
toHaveBeenCalledOnce: (x) => matchers.toHaveBeenCalledTimes(x, 1),
}

const matchersFalseNegative = {
__proto__: null,
toEqual: (x, y) => x === y,
toStrictEqual: (x, y) => x === y,
toContain: (x, c) => Array.isArray(x) && [...x].includes(c),
toBeEven: (x) => Number.isSafeInteger(x) && x % 2 === 0,
toBeOdd: (x) => Number.isSafeInteger(x) && x % 2 === 1,
}

function createExpect() {
return new Proxy(() => {}, {
apply: (target, that, [x, ...rest]) => {
if (rest.length > 0) return loadExpect()(x, ...rest)
return new Proxy(Object.create(null), {
get: (_, name) => {
const matcher = matchers[name] || matchersFalseNegative[name]
if (matcher)
return (...args) => {
if (!matcher(x, ...args)) return loadExpect()(x)[name](...args)
assertionsDelta++
}

if (name === 'not')
return new Proxy(Object.create(null), {
get: (_, not) => {
if (matchers[not])
return (...args) => {
if (matchers[not](x, ...args)) return loadExpect()(x).not[not](...args)
assertionsDelta++
}

// console.log ({ loadReason: 'not', name: not })
return loadExpect()(x).not[not]
},
})

// console.log ({ loadReason: 'expect', name })
return loadExpect()(x)[name]
},
})
},
get: (_, name) => {
if (name === 'extend' && !expect) return (...args) => extend.push(args)
if (name === 'extractExpectedAssertionsErrors') {
return expect
? (...args) => {
fixupAssertions()
return expect[name](...args)
}
: () => {
assertionsDelta = 0
return [] // no .assertions call were made, those cause loading
}
}

// console.log({ loadReason: 'get', name })
return loadExpect()[name]
},
set: (_, name, value) => {
if (expect) {
expect[name] = value
} else {
set.push([name, value])
}

return true
},
})
}

exports.expect = createExpect()
exports.loadExpect = loadExpect
6 changes: 2 additions & 4 deletions src/jest.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ import { setupSnapshots } from './jest.snapshot.js'
import { fetchReplay, fetchRecord, websocketRecord, websocketReplay } from './replay.js'
import { createCallerLocationHook, insideEsbuild } from './dark.cjs'
import { haveValidTimers } from './version.js'
import { expect } from 'expect'
import matchers from 'jest-extended'
import { expect } from './expect.cjs'
import { format as prettyFormat } from 'pretty-format'

const { getCallerLocation, installLocationInNextTest } = createCallerLocationHook()
Expand All @@ -21,7 +20,6 @@ if (process.env.EXODUS_TEST_ENVIRONMENT !== 'bundle') {
if (files.length === 1 && files[0].endsWith('/inband.js')) addStatefulApis = false
}

expect.extend(matchers)
if (addStatefulApis) setupSnapshots(expect)

let defaultTimeout = jestConfig().testTimeout // overridable via jest.setTimeout()
Expand Down Expand Up @@ -262,4 +260,4 @@ export const beforeAll = (fn) => node.before(wrapCallback(fn))
export const afterAll = (fn) => node.after(wrapCallback(fn))

export { describe, test, test as it }
export { expect } from 'expect'
export { expect } from './expect.cjs'
2 changes: 2 additions & 0 deletions src/jest.mock.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
syncBuiltinESMExports,
} from './engine.js'
import { jestfn } from './jest.fn.js'
import { loadExpect } from './expect.cjs'
import { makeEsbuildMockable, insideEsbuild } from './dark.cjs'

const mapMocks = new Map()
Expand Down Expand Up @@ -212,6 +213,7 @@ function jestmock(name, mocker, { override = false } = {}) {
const value = mocker ? expand(mocker()) : mockClone(mapActual.get(resolved))
mapMocks.set(resolved, value)

loadExpect() // we need to do this as we don't want mocks affecting expect
const topLevelESM = isTopLevelESM()
let likelyESM = topLevelESM && !insideEsbuild && ![null, resolved].includes(resolveImport(name))
let okFromESM = false
Expand Down

0 comments on commit b28d780

Please sign in to comment.