test(core): use fake timers in Queue unit tests to stop CI flakes (#6134)
The Queue tests measured real setTimeout wall-clock time and asserted elapsed < 2 * threshold. On busy CI runners a 2400ms timer can take longer than 4800ms to fire, failing the assertion intermittently (seen in downstream validation runs). Switch to jest's modern fake timers so elapsed is exactly the timeout delay: the tests are deterministic and no longer spend ~5 seconds of real time waiting.
This commit is contained in:
parent
75105ced04
commit
9329dd5b55
@ -17,7 +17,21 @@ function timeout(delay) {
|
|||||||
|
|
||||||
const threshold = 2400;
|
const threshold = 2400;
|
||||||
|
|
||||||
|
// Fake timers make these tests deterministic: with real timers the elapsed
|
||||||
|
// assertions depend on wall-clock scheduling and flake on busy CI runners
|
||||||
|
// (a 2400ms setTimeout can take more than 4800ms to fire under load).
|
||||||
|
// jest's modern fake timers also mock Date.now, so advanceTimersByTime moves
|
||||||
|
// the timers and the clock together and elapsed is exactly the timeout delay.
|
||||||
|
|
||||||
describe('Queue', () => {
|
describe('Queue', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.useFakeTimers();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
jest.useRealTimers();
|
||||||
|
});
|
||||||
|
|
||||||
// Todo: comment due to wrong implementation
|
// Todo: comment due to wrong implementation
|
||||||
// it('should bind functions to the queue', async () => {
|
// it('should bind functions to the queue', async () => {
|
||||||
// const queue = new Queue(2);
|
// const queue = new Queue(2);
|
||||||
@ -38,14 +52,14 @@ describe('Queue', () => {
|
|||||||
const timer = queue.bind(mockedTimeout);
|
const timer = queue.bind(mockedTimeout);
|
||||||
const start = Date.now();
|
const start = Date.now();
|
||||||
const promise = timer(threshold).then(time => time - start);
|
const promise = timer(threshold).then(time => time - start);
|
||||||
try {
|
// The queue is full, so the second call rejects without waiting. Awaiting
|
||||||
await timer(threshold);
|
// the rejection also flushes the microtasks that register the first
|
||||||
} catch (e) {
|
// task's setTimeout, so it can be advanced below.
|
||||||
expect(Date.now() - start < threshold).toBe(true);
|
await expect(timer(threshold)).rejects.toThrow('Queue limit reached');
|
||||||
expect(e.message).toBe('Queue limit reached');
|
expect(Date.now() - start < threshold).toBe(true);
|
||||||
}
|
jest.advanceTimersByTime(threshold);
|
||||||
const elapsed = await promise;
|
const elapsed = await promise;
|
||||||
expect(elapsed >= threshold && elapsed < 2 * threshold).toBe(true);
|
expect(elapsed).toBe(threshold);
|
||||||
expect(mockedTimeout).toHaveBeenCalledTimes(1);
|
expect(mockedTimeout).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
it('should safely bind tasks to the queue', async () => {
|
it('should safely bind tasks to the queue', async () => {
|
||||||
@ -62,8 +76,9 @@ describe('Queue', () => {
|
|||||||
1,
|
1,
|
||||||
expect.objectContaining({ message: 'Queue limit reached' })
|
expect.objectContaining({ message: 'Queue limit reached' })
|
||||||
);
|
);
|
||||||
|
jest.advanceTimersByTime(threshold);
|
||||||
const elapsed = await promise;
|
const elapsed = await promise;
|
||||||
expect(elapsed >= threshold && elapsed < 2 * threshold).toBe(true);
|
expect(elapsed).toBe(threshold);
|
||||||
expect(mockedTimeout).toHaveBeenCalledTimes(1);
|
expect(mockedTimeout).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user