Friday, 19 August 2022

Jest: Standard way to stub named exports of ESM modules

This question is not specific to Jest as it applies to all testing libraries with stubbing capabilities.

ESM modules have immutable named and default exports, which means this is no longer valid:

// @filename foo.mjs
export function foo() { ... }

// @filename foo.test.mjs
import * as foo from './foo.mjs'
// Causes runtime error because named export "foo" is immutable
jest.spyOn(foo, 'foo')

What is the current "standard" way to spy/mock named exports with ESM modules?

Potential solutions

Delegate to mutable object

// @filename foo.mjs
export function foo() {
  return _private.foo()
}
export const _private = {
  foo: () => { ... }
}

// @filename foo.test.mjs
import { _private } from './foo.mjs'
jest.spyOn(_private, 'foo')

Wrap function in proxy

// @filename proxy.mjs
export function proxy(fn) {
  const functionProxy = function (...args) {
    return functionProxy._original(...args)
  }
  functionProxy._original = fn
  return functionProxy
}

// @filename foo.mjs
import { proxy } from './proxy.mjs'
export const foo = proxy(() => { ... })

// @filename foo.test.mjs
import { foo } from './foo.mjs'
jest.spyOn(foo, '_original')


from Jest: Standard way to stub named exports of ESM modules

No comments:

Post a Comment