Skip to content

Commit 2d1d51a

Browse files
authored
fix(test-utils): Duplicated subscribers re insertion (medusajs#13798)
* fix * Create pink-boats-type.md
1 parent a34fcfa commit 2d1d51a

File tree

3 files changed

+131
-3
lines changed

3 files changed

+131
-3
lines changed

.changeset/pink-boats-type.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@medusajs/test-utils": patch
3+
---
4+
5+
fix(test-utils): Event subscribers duplicated durin tests

packages/medusa-test-utils/src/__tests__/events.spec.ts

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,4 +307,120 @@ describe("waitSubscribersExecution", () => {
307307
clearTimeoutSpy.mockRestore()
308308
})
309309
})
310+
311+
describe("nested wrapper handling", () => {
312+
it("should handle multiple consecutive waitSubscribersExecution calls on the same event", async () => {
313+
const originalListener = jest.fn().mockResolvedValue("result")
314+
eventBus.eventEmitter_.on(TEST_EVENT, originalListener)
315+
316+
// First wait
317+
const wait1 = waitSubscribersExecution(TEST_EVENT, eventBus as any)
318+
eventBus.emit(TEST_EVENT, "data1")
319+
await wait1
320+
321+
expect(originalListener).toHaveBeenCalledWith("data1")
322+
expect(originalListener).toHaveBeenCalledTimes(1)
323+
324+
// Second wait on the same event - should still restore properly
325+
const wait2 = waitSubscribersExecution(TEST_EVENT, eventBus as any)
326+
eventBus.emit(TEST_EVENT, "data2")
327+
await wait2
328+
329+
expect(originalListener).toHaveBeenCalledWith("data2")
330+
expect(originalListener).toHaveBeenCalledTimes(2)
331+
332+
// Original listener should still be intact and work normally
333+
eventBus.emit(TEST_EVENT, "data3")
334+
expect(originalListener).toHaveBeenCalledWith("data3")
335+
expect(originalListener).toHaveBeenCalledTimes(3)
336+
337+
// Verify we still have the correct number of listeners
338+
const listeners = eventBus.eventEmitter_.listeners(TEST_EVENT)
339+
expect(listeners).toHaveLength(1)
340+
expect(listeners[0]).toBe(originalListener)
341+
})
342+
343+
it("should handle three consecutive waitSubscribersExecution calls", async () => {
344+
const originalListener = jest.fn().mockResolvedValue("result")
345+
eventBus.eventEmitter_.on(TEST_EVENT, originalListener)
346+
347+
// First wait
348+
const wait1 = waitSubscribersExecution(TEST_EVENT, eventBus as any)
349+
eventBus.emit(TEST_EVENT, "data1")
350+
await wait1
351+
352+
// Second wait
353+
const wait2 = waitSubscribersExecution(TEST_EVENT, eventBus as any)
354+
eventBus.emit(TEST_EVENT, "data2")
355+
await wait2
356+
357+
// Third wait
358+
const wait3 = waitSubscribersExecution(TEST_EVENT, eventBus as any)
359+
eventBus.emit(TEST_EVENT, "data3")
360+
await wait3
361+
362+
// Verify the original listener is still properly attached
363+
const listeners = eventBus.eventEmitter_.listeners(TEST_EVENT)
364+
expect(listeners).toHaveLength(1)
365+
expect(listeners[0]).toBe(originalListener)
366+
367+
// Verify it still works
368+
eventBus.emit(TEST_EVENT, "data4")
369+
expect(originalListener).toHaveBeenCalledWith("data4")
370+
expect(originalListener).toHaveBeenCalledTimes(4)
371+
})
372+
373+
it("should handle multiple listeners with consecutive waits", async () => {
374+
const listener1 = jest.fn().mockResolvedValue("result1")
375+
const listener2 = jest.fn().mockResolvedValue("result2")
376+
377+
eventBus.eventEmitter_.on(TEST_EVENT, listener1)
378+
eventBus.eventEmitter_.on(TEST_EVENT, listener2)
379+
380+
// First wait
381+
const wait1 = waitSubscribersExecution(TEST_EVENT, eventBus as any)
382+
eventBus.emit(TEST_EVENT, "data1")
383+
await wait1
384+
385+
expect(listener1).toHaveBeenCalledWith("data1")
386+
expect(listener2).toHaveBeenCalledWith("data1")
387+
388+
// Second wait
389+
const wait2 = waitSubscribersExecution(TEST_EVENT, eventBus as any)
390+
eventBus.emit(TEST_EVENT, "data2")
391+
await wait2
392+
393+
expect(listener1).toHaveBeenCalledWith("data2")
394+
expect(listener2).toHaveBeenCalledWith("data2")
395+
396+
// Verify both original listeners are still properly attached
397+
const listeners = eventBus.eventEmitter_.listeners(TEST_EVENT)
398+
expect(listeners).toHaveLength(2)
399+
expect(listeners[0]).toBe(listener1)
400+
expect(listeners[1]).toBe(listener2)
401+
402+
// Verify they still work normally
403+
eventBus.emit(TEST_EVENT, "data3")
404+
expect(listener1).toHaveBeenCalledWith("data3")
405+
expect(listener2).toHaveBeenCalledWith("data3")
406+
})
407+
408+
it("should not add undefined listener when originalListener chain ends", async () => {
409+
// This tests the edge case where listener.originalListener might be undefined
410+
const originalListener = jest.fn().mockResolvedValue("result")
411+
eventBus.eventEmitter_.on(TEST_EVENT, originalListener)
412+
413+
const wait1 = waitSubscribersExecution(TEST_EVENT, eventBus as any)
414+
eventBus.emit(TEST_EVENT, "data1")
415+
await wait1
416+
417+
// Verify we have exactly one listener (the original)
418+
const listeners = eventBus.eventEmitter_.listeners(TEST_EVENT)
419+
expect(listeners).toHaveLength(1)
420+
421+
// Verify it's not undefined
422+
expect(listeners[0]).toBeDefined()
423+
expect(listeners[0]).toBe(originalListener)
424+
})
425+
})
310426
})

packages/medusa-test-utils/src/events.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ const doWaitSubscribersExecution = (
9999
})
100100
subscriberPromises.push(promise)
101101
let res: any[] = []
102+
let cleanupDone = false
102103

103104
const newListener = async (...args2: any[]) => {
104105
try {
@@ -121,14 +122,20 @@ const doWaitSubscribersExecution = (
121122
nok(error)
122123
}
123124

124-
if (currentCount >= triggerCount) {
125+
if (currentCount >= triggerCount && !cleanupDone) {
125126
// As soon as the subscriber is executed the required number of times, we restore the original listener
127+
cleanupDone = true
126128
eventEmitter.removeListener(eventName, newListener)
129+
130+
// Unwrap to find the true original listener
127131
let listenerToAdd = listener
128-
while (listenerToAdd.originalListener) {
132+
while (listenerToAdd?.originalListener) {
129133
listenerToAdd = listenerToAdd.originalListener
130134
}
131-
eventEmitter.on(eventName, listenerToAdd)
135+
136+
if (listenerToAdd) {
137+
eventEmitter.on(eventName, listenerToAdd)
138+
}
132139
}
133140
}
134141

0 commit comments

Comments
 (0)