token-wizard/test/utils/executeSequentially.spec.js

276 lines
7.2 KiB
JavaScript

import executeSequentially from '../../src/utils/executeSequentially'
describe('executeSequentially', () => {
it('should resolve if the list is empty', () => {
// given
const list = []
// when
return executeSequentially(list).then(() => {
// then
// it should resolve
})
})
it('should execute all the functions in the list', () => {
// given
const list = [jest.fn().mockReturnValue(Promise.resolve())]
// when
return executeSequentially(list).then(() => {
// then
expect(list[0]).toHaveBeenCalledTimes(1)
})
})
it('should wait for function to finish', () => {
// given
let finished = 0
const list = [
buildMockFunction({ timeout: 100, before: () => finished++ }),
buildMockFunction({ timeout: 50, before: () => finished++ })
]
// when
return executeSequentially(list).then(() => {
// then
expect(list[0]).toHaveBeenCalledTimes(1)
expect(list[1]).toHaveBeenCalledTimes(1)
expect(finished).toBe(2)
})
})
it('should return index of the function that failed (last function fails)', () => {
// given
const list = [buildMockFunction(), buildMockFunction(), buildMockFunction({ shouldFail: true })]
// when
return executeSequentially(list).then(
() => {
throw new Error('should not resolve')
},
([err, index]) => {
expect(index).toBe(2)
}
)
})
it('should return index of the function that failed (first function rejects)', () => {
// given
const list = [buildMockFunction({ shouldFail: true }), buildMockFunction(), buildMockFunction()]
// when
return executeSequentially(list).then(
() => {
throw new Error('should not resolve')
},
([err, index]) => {
expect(index).toBe(0)
}
)
})
it('should return index of the function that failed (first function throws)', () => {
// given
const list = [buildMockFunction({ shouldFail: true }), buildMockFunction(), buildMockFunction()]
// when
return executeSequentially(list).then(
() => {
throw new Error('should not resolve')
},
([err, index]) => {
expect(index).toBe(0)
}
)
})
it('should not execute the functions after the function that failed', () => {
// given
let finished = 0
const list = [
buildMockFunction({ shouldFail: true, before: () => finished++ }),
buildMockFunction(),
buildMockFunction()
]
// when
return executeSequentially(list).then(
() => {
throw new Error('should not resolve')
},
([err, index]) => {
expect(index).toBe(0)
expect(finished).toBe(1)
expect(list[0]).toHaveBeenCalledTimes(1)
expect(list[1]).toHaveBeenCalledTimes(0)
expect(list[2]).toHaveBeenCalledTimes(0)
}
)
})
it('should reject with the error of the failed function', () => {
// given
let finished = 0
const ERR = 'FN FAILED'
const list = [
buildMockFunction({
shouldFail: true,
rejectWith: ERR,
before: () => {
finished++
}
}),
buildMockFunction(),
buildMockFunction()
]
// when
return executeSequentially(list).then(
() => {
throw new Error('should not resolve')
},
([err, index]) => {
expect(err).toBe(ERR)
expect(index).toBe(0)
expect(finished).toBe(1)
expect(list[0]).toHaveBeenCalledTimes(1)
expect(list[1]).toHaveBeenCalledTimes(0)
expect(list[2]).toHaveBeenCalledTimes(0)
}
)
})
it('should accept an index to set the start of the execution', () => {
// given
const list = [buildMockFunction(), buildMockFunction(), buildMockFunction()]
// when
return executeSequentially(list, 1).then(() => {
expect(list[0]).toHaveBeenCalledTimes(0)
expect(list[1]).toHaveBeenCalledTimes(1)
expect(list[2]).toHaveBeenCalledTimes(1)
})
})
it('should fail with the absolute index of the failed function', () => {
// given
const list = [
buildMockFunction(),
buildMockFunction(),
buildMockFunction(),
buildMockFunction({ shouldFail: true }),
buildMockFunction()
]
// when
return executeSequentially(list, 2).then(
() => {
throw new Error('should not resolve')
},
([err, index]) => {
expect(index).toBe(3)
expect(list[0]).toHaveBeenCalledTimes(0)
expect(list[1]).toHaveBeenCalledTimes(0)
expect(list[2]).toHaveBeenCalledTimes(1)
expect(list[3]).toHaveBeenCalledTimes(1)
expect(list[4]).toHaveBeenCalledTimes(0)
}
)
})
it('should accept a callback to execute after each successful execution', () => {
// given
const list = [buildMockFunction(), buildMockFunction(), buildMockFunction()]
// when
const before = jest.fn()
return executeSequentially(list, 0, before).then(() => {
// then
expect(list[0]).toHaveBeenCalledTimes(1)
expect(list[1]).toHaveBeenCalledTimes(1)
expect(list[2]).toHaveBeenCalledTimes(1)
expect(before).toHaveBeenCalledTimes(3)
expect(before).toHaveBeenCalledWith(0)
expect(before).toHaveBeenCalledWith(1)
expect(before).toHaveBeenCalledWith(2)
})
})
it(`should not execute 'before' callback after a failed function`, () => {
// given
const list = [buildMockFunction(), buildMockFunction({ shouldFail: true }), buildMockFunction()]
// when
const before = jest.fn()
return executeSequentially(list, 0, before).then(
() => {
throw new Error('should not resolve')
},
() => {
// then
expect(list[0]).toHaveBeenCalledTimes(1)
expect(list[1]).toHaveBeenCalledTimes(1)
expect(list[2]).toHaveBeenCalledTimes(0)
expect(before).toHaveBeenCalledTimes(2)
expect(before).toHaveBeenCalledWith(0)
expect(before).toHaveBeenCalledWith(1)
expect(before).not.toHaveBeenCalledWith(2)
}
)
})
it(`should call 'after' callback right before the failing function`, () => {
// Given
const list = [buildMockFunction(), buildMockFunction({ shouldFail: true }), buildMockFunction()]
// When
const before = jest.fn()
const after = jest.fn()
return executeSequentially(list, 0, before, after).then(
() => {
throw new Error('should not resolve')
},
() => {
// Then
expect(list[0]).toHaveBeenCalledTimes(1)
expect(list[1]).toHaveBeenCalledTimes(1)
expect(list[2]).toHaveBeenCalledTimes(0)
expect(after).toHaveBeenCalledTimes(1)
expect(after).toHaveBeenCalledWith(0)
expect(after).not.toHaveBeenCalledWith(1)
expect(after).not.toHaveBeenCalledWith(2)
}
)
})
})
function buildMockFunction({
timeout = 0,
shouldFail = false,
rejectWith = null,
before = () => {},
after = () => {}
} = {}) {
return jest.fn(
() =>
new Promise((resolve, reject) => {
setTimeout(() => {
before()
if (shouldFail) {
reject(rejectWith)
} else {
after()
resolve()
}
}, timeout)
})
)
}