mtcute/.config/vite-utils/fixup-bun-test.ts
2024-03-18 01:58:36 +03:00

128 lines
3.9 KiB
TypeScript

const bunTest = require('bun:test')
const console = require('console') // https://github.com/oven-sh/bun/issues/6044
const chaiExpect = require('chai').expect
const bunExpect = bunTest.expect
class BunTestUnsupportedError extends Error {
constructor(readonly feature) {
super()
}
}
function _wrapBunExpect(args, bun, invert = false) {
let chai = chaiExpect(...args)
if (invert) chai = chai.not
return new Proxy(bun, {
get: (target, prop, receiver) => {
if (prop === 'eq') return (...args) => chai.eq(...args)
if (prop === 'eql') return (...args) => chai.eql(...args)
if (prop === 'throws') return (...args) => chai.throws(...args)
if (prop === 'is') return chai.is
if (prop === 'to') return chai.to
if (prop === 'false') return chai.false
if (prop === 'true') return chai.true
if (prop === 'deep') return chai.deep
if (prop === 'toMatchInlineSnapshot') {
return (expected, options) => {
let snapshot
if (typeof args[0] === 'string') {
const snapshot = '"' + args[0] + '"'
return chaiExpect(snapshot).eql(expected.trim())
} else {
const obj = eval('(' + expected + ')') // idc lol
return chaiExpect(args[0]).eql(obj)
}
}
}
if (prop === 'not') {
const not = bun.not
return _wrapBunExpect(args, not, !invert)
}
if (prop === 'rejects') {
if (typeof args[0] === 'function') {
const newArgs = [args[0](), ...args.slice(1)]
return _wrapBunExpect(newArgs, bunExpect(...newArgs), invert).rejects
}
return bun.rejects
}
if (prop === 'resolves') {
return bun.resolves
}
if (prop === 'toHaveBeenCalledOnce' || prop === 'toHaveBeenCalledTimes' || prop === 'toMatchSnapshot') {
throw new BunTestUnsupportedError(prop)
}
return Reflect.get(target, prop, receiver).bind(bun)
},
})
}
export function expect(...args) {
return _wrapBunExpect(args, bunExpect(...args))
}
expect.any = bunExpect.any
const stubbedGlobal = new Map()
function stubGlobal(name, value) {
stubbedGlobal.set(name, globalThis[name])
globalThis[name] = value
}
function unstubAllGlobals() {
for (const [name, value] of stubbedGlobal) {
globalThis[name] = value
}
stubbedGlobal.clear()
}
const _wrapRunner = (name, fn) => {
const handleError = (err) => {
if (err instanceof BunTestUnsupportedError) {
console.warn(`skipping "${name}" - ${err.feature} is currently not supported in bun:test`)
return
}
throw err
}
return (...args) => {
try {
const res = fn(...args)
if (res instanceof Promise) {
return res.catch(handleError)
}
return res
} catch (e) {
return handleError(e)
}
}
}
const it = (name, fn) => bunTest.it(name, _wrapRunner(name, fn))
it.only = (name, fn) => bunTest.it.only(name, _wrapRunner(name, fn))
it.skip = (name, fn) => bunTest.it.skip(name, _wrapRunner(name, fn))
it.each = (table) => (name, fn) => bunTest.it.each(table)(name, _wrapRunner(name, fn))
export { it }
export const vi = {
...bunTest.jest,
...bunTest.vi,
mocked: (fn) => fn,
stubGlobal,
unstubAllGlobals,
...['setSystemTime', 'advanceTimersByTimeAsync', 'advanceTimersByTime', 'waitFor', 'doMock'].reduce(
(acc, name) => ({
...acc,
[name]: () => {
throw new BunTestUnsupportedError(name)
},
}),
{},
),
}