Easier testing with chained functions + jest 🧪Also allows snapshot testing with chained functions!
Easier testing with chained functions + jest 🧪
⭐️ Also allows snapshot testing with chained functions! ⭐️
someItem.setPrice(2).setQuantity(5)
Related concepts: Builder Design Pattern, Fluent Interface
// yargsExample.ts
// as per example usage on: https://yargs.js.org/
export const yargsExample = (yargs: any) => {
const result = yargs
.scriptName('pirate-parser')
.usage('$0 <cmd> [args]')
.command(
'hello [name]',
'welcome ter yargs!',
(yargs: any) => {
yargs.positional('name', {
type: 'string',
default: 'Cambi',
describe: 'the name to say hello to',
})
},
function (argv: any) {
console.log('hello', argv.name, 'welcome to yargs!')
}
)
.help().argv
return result
}
Scenario:
yargsExample()
yargsExample()
is called,yargs
has been called with:scriptName()
with args ['pirate-parser']
usage()
with args ['$0 <cmd> [args]']
.argv
// 1. import makeMockChainFn()
import { makeMockChainFn } from 'jest-mock-chain-fn'
// 2. import function under test
import { yargsExample } from './yargsExample'
test('asserts chained fn is called correctly', () => {
// 3. set .argv to return mock object
const mockPropertyReturns = { argv: { value: { some: 'object' } } }
// 4. create mock chain fn
const { mockChainFn: yargs, calls } = makeMockChainFn({
mockPropertyReturns,
})
// 5. trigger usage of top-level function
const result = yargsExample(yargs)
// 7. assert chain fn calls against snapshot
expect(calls).toMatchSnapshot()
// 8. assert return value
expect(result).toEqual({ some: 'object' })
})
Key point: With minimal setup, we are able to:
yargs
No more tedious handwiring of mocks to test method chaining. 🙃
javascript
[
{ key: 'scriptName', type: 'function', args: [ 'pirate-parser' ] },
{ key: 'usage', type: 'function', args: [ '$0 <cmd> [args]' ] },
{
key: 'command',
type: 'function',
args: [ 'hello [name]', 'welcome ter yargs!', [Function], [Function] ]
},
{ key: 'help', type: 'function', args: [] },
{ key: 'argv', type: 'value', value: { some: 'object' } }
]
See more: yargsExample.test.ts, chalkExample.test.ts
const options = {
// optional: sets overrides for specific property keys
mockPropertyReturns: { somePropName: {} },
}
const result = makeMockChainFn(options)
const {
// mock that accepts method/property calls against it
mockChainFn,
// map of mock fns (automatically created upon call against mockChainFn)
mocks,
// list of calls made against mockChainFn
calls,
// clears mocks mapping
clearExistingMocks,
// clears list of calls
clearExistingCalls,
} = result
See more: makeMockChainFn.ts
mockPropertyReturns
Used to define non-standard mock function behaviors upon property call
For: Chained function (Default scenario)
mockChainFn
supports method chaining. (ie. no mockPropertyReturns
setup required)mockChainFn.myCall()
), library creates a mapping for myCall
in mocks
, myCall
key is a jest.fn()
that captures all calls and returns mockChainFn()
(to support method chaining).For: Chained value (non-function)
mockChainFn.compute.save
),mockPropertyReturns = { compute: {}, save: {} }
For: Property with fixed value (function)
mockChainFn.myCall()
)mockPropertyReturns = { myCall: { value: jest.fn() } }
(where jest.fn()
is your own mock)myCall
will still be captured into calls
For: Property with fixed value (non-function)
mockChainFn.someProperty
)mockPropertyReturns = { someProperty: { value: 'own value' } }
jest.resetAllMocks()
will clear jest.fn()
mock functions that are used internally within mockChainFn
(ie. in mocks
mapping)mockChainFn