Skip to content

Commit 2175678

Browse files
committed
test(core): Use fake timers in promisebuffer tests to ensure deterministic behavior
1 parent 1307651 commit 2175678

File tree

1 file changed

+76
-44
lines changed

1 file changed

+76
-44
lines changed

packages/core/test/lib/utils/promisebuffer.test.ts

Lines changed: 76 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -105,61 +105,93 @@ describe('PromiseBuffer', () => {
105105

106106
describe('drain()', () => {
107107
test('drains all promises without timeout', async () => {
108-
const buffer = makePromiseBuffer();
108+
vi.useFakeTimers();
109109

110-
const p1 = vi.fn(() => new Promise(resolve => setTimeout(resolve, 1)));
111-
const p2 = vi.fn(() => new Promise(resolve => setTimeout(resolve, 1)));
112-
const p3 = vi.fn(() => new Promise(resolve => setTimeout(resolve, 1)));
113-
const p4 = vi.fn(() => new Promise(resolve => setTimeout(resolve, 1)));
114-
const p5 = vi.fn(() => new Promise(resolve => setTimeout(resolve, 1)));
110+
try {
111+
const buffer = makePromiseBuffer();
115112

116-
[p1, p2, p3, p4, p5].forEach(p => {
117-
void buffer.add(p);
118-
});
113+
const p1 = vi.fn(() => new Promise(resolve => setTimeout(resolve, 10)));
114+
const p2 = vi.fn(() => new Promise(resolve => setTimeout(resolve, 10)));
115+
const p3 = vi.fn(() => new Promise(resolve => setTimeout(resolve, 10)));
116+
const p4 = vi.fn(() => new Promise(resolve => setTimeout(resolve, 10)));
117+
const p5 = vi.fn(() => new Promise(resolve => setTimeout(resolve, 10)));
119118

120-
expect(buffer.$.length).toEqual(5);
121-
const result = await buffer.drain();
122-
expect(result).toEqual(true);
123-
expect(buffer.$.length).toEqual(0);
119+
[p1, p2, p3, p4, p5].forEach(p => {
120+
void buffer.add(p);
121+
});
124122

125-
expect(p1).toHaveBeenCalled();
126-
expect(p2).toHaveBeenCalled();
127-
expect(p3).toHaveBeenCalled();
128-
expect(p4).toHaveBeenCalled();
129-
expect(p5).toHaveBeenCalled();
123+
expect(buffer.$.length).toEqual(5);
124+
125+
const drainPromise = buffer.drain();
126+
127+
// Advance time to resolve all promises
128+
await vi.advanceTimersByTimeAsync(10);
129+
130+
const result = await drainPromise;
131+
expect(result).toEqual(true);
132+
expect(buffer.$.length).toEqual(0);
133+
134+
expect(p1).toHaveBeenCalled();
135+
expect(p2).toHaveBeenCalled();
136+
expect(p3).toHaveBeenCalled();
137+
expect(p4).toHaveBeenCalled();
138+
expect(p5).toHaveBeenCalled();
139+
} finally {
140+
vi.useRealTimers();
141+
}
130142
});
131143

132144
test('drains all promises with timeout', async () => {
133-
const buffer = makePromiseBuffer();
145+
vi.useFakeTimers();
134146

135-
const p1 = vi.fn(() => new Promise(resolve => setTimeout(resolve, 2)));
136-
const p2 = vi.fn(() => new Promise(resolve => setTimeout(resolve, 4)));
137-
const p3 = vi.fn(() => new Promise(resolve => setTimeout(resolve, 6)));
138-
const p4 = vi.fn(() => new Promise(resolve => setTimeout(resolve, 8)));
139-
const p5 = vi.fn(() => new Promise(resolve => setTimeout(resolve, 10)));
147+
try {
148+
const buffer = makePromiseBuffer();
140149

141-
[p1, p2, p3, p4, p5].forEach(p => {
142-
void buffer.add(p);
143-
});
150+
const p1 = vi.fn(() => new Promise(resolve => setTimeout(resolve, 20)));
151+
const p2 = vi.fn(() => new Promise(resolve => setTimeout(resolve, 40)));
152+
const p3 = vi.fn(() => new Promise(resolve => setTimeout(resolve, 60)));
153+
const p4 = vi.fn(() => new Promise(resolve => setTimeout(resolve, 80)));
154+
const p5 = vi.fn(() => new Promise(resolve => setTimeout(resolve, 100)));
144155

145-
expect(p1).toHaveBeenCalled();
146-
expect(p2).toHaveBeenCalled();
147-
expect(p3).toHaveBeenCalled();
148-
expect(p4).toHaveBeenCalled();
149-
expect(p5).toHaveBeenCalled();
156+
[p1, p2, p3, p4, p5].forEach(p => {
157+
void buffer.add(p);
158+
});
150159

151-
expect(buffer.$.length).toEqual(5);
152-
const result = await buffer.drain(6);
153-
expect(result).toEqual(false);
154-
// p5 & p4 are still in the buffer
155-
// Leaving some wiggle room, possibly one or two items are still in the buffer
156-
// to avoid flakiness
157-
expect(buffer.$.length).toBeGreaterThanOrEqual(1);
158-
159-
// Now drain final item
160-
const result2 = await buffer.drain();
161-
expect(result2).toEqual(true);
162-
expect(buffer.$.length).toEqual(0);
160+
expect(p1).toHaveBeenCalled();
161+
expect(p2).toHaveBeenCalled();
162+
expect(p3).toHaveBeenCalled();
163+
expect(p4).toHaveBeenCalled();
164+
expect(p5).toHaveBeenCalled();
165+
166+
expect(buffer.$.length).toEqual(5);
167+
168+
// Start draining with a 50ms timeout
169+
const drainPromise = buffer.drain(50);
170+
171+
// Advance time by 50ms - this will:
172+
// - Resolve p1 (20ms) and p2 (40ms)
173+
// - Trigger the drain timeout (50ms)
174+
// - p3, p4, p5 are still pending
175+
await vi.advanceTimersByTimeAsync(50);
176+
177+
const result = await drainPromise;
178+
expect(result).toEqual(false);
179+
180+
// p3, p4 & p5 are still in the buffer
181+
expect(buffer.$.length).toEqual(3);
182+
183+
// Now drain remaining items without timeout
184+
const drainPromise2 = buffer.drain();
185+
186+
// Advance time to resolve remaining promises
187+
await vi.advanceTimersByTimeAsync(100);
188+
189+
const result2 = await drainPromise2;
190+
expect(result2).toEqual(true);
191+
expect(buffer.$.length).toEqual(0);
192+
} finally {
193+
vi.useRealTimers();
194+
}
163195
});
164196

165197
test('on empty buffer', async () => {

0 commit comments

Comments
 (0)