const capture = (actions, name, fn) => async (...args) => { const count = actions.reduce((count, curr) => { if (curr.name === name) return count + 1 return count }, 1) try { const result = await fn(...args, { count }) actions.push({ name, args, result }) return result } catch (error) { actions.push({ name, args, result: error }) throw error } } const mock = async (mocks, fn) => { const olds = {} const actions = [] for (const mock of mocks) { if (mock.package in olds === false) olds[mock.package] = {} const old = olds[mock.package] for (const name in mock.funcs) { //Save old[name] = mock.package[name] //Capture mock.package[name] = capture(actions, name, mock.funcs[name]) } } //Restore even when an error occurs //Like with a failed assert try { await fn() } catch (error) { throw error } finally { for (const mock of mocks) { const old = olds[mock.package] for (const name in mock.funcs) { //Restore mock.package[name] = old[name] } } } return actions } export { mock }