Skip to content

Commit b0a603c

Browse files
authored
fix(emitter): off() ignoring handler check when one listener remains (#1099)
1 parent b736c6d commit b0a603c

File tree

2 files changed

+90
-79
lines changed

2 files changed

+90
-79
lines changed

packages/emitter/src/emitter.spec.ts

+86-75
Original file line numberDiff line numberDiff line change
@@ -5,87 +5,98 @@ const times = (n: number, fn: () => void): number => {
55
return n;
66
};
77

8-
describe('Emitter function', () => {
9-
let handler: () => void;
10-
let emitter: Emitter;
8+
let handler: () => void;
9+
let emitter: Emitter;
1110

12-
beforeEach(() => {
13-
handler = jest.fn();
14-
emitter = new Emitter();
11+
beforeEach(() => {
12+
handler = jest.fn();
13+
emitter = new Emitter();
14+
});
15+
16+
describe('`on` method', () => {
17+
it('should call `test` handler 5 times - with only one listener', () => {
18+
emitter.on('test', handler);
19+
times(5, () => emitter.emit('test'));
20+
expect(handler).toHaveBeenCalledTimes(5);
21+
});
22+
23+
it('should call `test2` handler 0 times - with multiple listeners', () => {
24+
emitter.on('test', () => null);
25+
emitter.on('test2', handler);
26+
times(5, () => emitter.emit('test'));
27+
expect(handler).toHaveBeenCalledTimes(0);
28+
});
29+
});
30+
31+
describe('`once` method', () => {
32+
it('should call `test` handler only once', () => {
33+
emitter.once('test', handler);
34+
times(5, () => emitter.emit('test'));
35+
expect(handler).toHaveBeenCalledTimes(1);
36+
});
37+
38+
it('should call `test` handler only once - with multiple events and same handler', () => {
39+
emitter.once('test', handler);
40+
emitter.once('test2', handler);
41+
times(5, () => emitter.emit('test'));
42+
expect(handler).toHaveBeenCalledTimes(1);
43+
});
44+
45+
it('should call `test` handler 5 times afert `once + remove + on` same event', () => {
46+
emitter.once('test', handler);
47+
emitter.off('test', handler);
48+
emitter.on('test', handler);
49+
times(5, () => emitter.emit('test'));
50+
expect(handler).toHaveBeenCalledTimes(5);
1551
});
1652

17-
describe('`on` method', () => {
18-
it('It should call `test` handler 5 times - with only one listener', () => {
19-
emitter.on('test', handler);
20-
times(5, () => emitter.emit('test'));
21-
expect(handler).toHaveBeenCalledTimes(5);
22-
});
23-
24-
it('It should call `test2` handler 0 times - with multiple listeners', () => {
25-
emitter.on('test', () => null);
26-
emitter.on('test2', handler);
27-
times(5, () => emitter.emit('test'));
28-
expect(handler).toHaveBeenCalledTimes(0);
29-
});
53+
it('should call `test` handler once after add multiple `once` and remove n-1', () => {
54+
emitter.once('test', handler);
55+
emitter.once('test', handler)();
56+
emitter.once('test', handler)();
57+
emitter.once('test', handler)();
58+
emitter.once('test', handler)();
59+
emitter.once('test', handler)();
60+
times(5, () => emitter.emit('test'));
61+
expect(handler).toHaveBeenCalledTimes(1);
3062
});
3163

32-
describe('`once` method', () => {
33-
it('It should call `test` handler only once', () => {
34-
emitter.once('test', handler);
35-
times(5, () => emitter.emit('test'));
36-
expect(handler).toHaveBeenCalledTimes(1);
37-
});
38-
39-
it('It should call `test` handler only once - with multiple events and same handler', () => {
40-
emitter.once('test', handler);
41-
emitter.once('test2', handler);
42-
times(5, () => emitter.emit('test'));
43-
expect(handler).toHaveBeenCalledTimes(1);
44-
});
45-
46-
it('It should call `test` handler 5 times afert `once + remove + on` same event', () => {
47-
emitter.once('test', handler);
48-
emitter.off('test', handler);
49-
emitter.on('test', handler);
50-
times(5, () => emitter.emit('test'));
51-
expect(handler).toHaveBeenCalledTimes(5);
52-
});
53-
54-
it('It should call `test` handler once after add multiple `once` and remove n-1', () => {
55-
emitter.once('test', handler);
56-
emitter.once('test', handler)();
57-
emitter.once('test', handler)();
58-
emitter.once('test', handler)();
59-
emitter.once('test', handler)();
60-
emitter.once('test', handler)();
61-
times(5, () => emitter.emit('test'));
62-
expect(handler).toHaveBeenCalledTimes(1);
63-
});
64-
65-
it('It should call `test` handler once after add same handler with different `once` events and remove n-1', () => {
66-
emitter.once('test', handler);
67-
emitter.once('test2', handler)();
68-
times(5, () => emitter.emit('test'));
69-
expect(handler).toHaveBeenCalledTimes(1);
70-
});
64+
it('should call `test` handler once after add same handler with different `once` events and remove n-1', () => {
65+
emitter.once('test', handler);
66+
emitter.once('test2', handler)();
67+
times(5, () => emitter.emit('test'));
68+
expect(handler).toHaveBeenCalledTimes(1);
7169
});
70+
});
71+
72+
describe('`off` method', () => {
73+
it('should have no `test` handler after removal', () => {
74+
emitter.on('test', handler);
75+
emitter.off('test', handler);
76+
expect(emitter.has('test')).toBe(false);
77+
});
78+
79+
it('should have no `test` handler after use stop callback', () => {
80+
emitter.on('test', handler)();
81+
expect(emitter.has('test')).toBe(false);
82+
});
83+
84+
it('should have no `test` handler after emit once', () => {
85+
emitter.once('test', handler);
86+
emitter.emit('test');
87+
expect(emitter.has('test')).toBe(false);
88+
});
89+
90+
it('should remove only the specified handler', () => {
91+
const handler = jest.fn();
92+
const unusedHandler = jest.fn();
93+
94+
emitter.on('test', handler);
95+
emitter.off('test', unusedHandler);
96+
97+
emitter.emit('test');
7298

73-
describe('`off` method', () => {
74-
it('It should have no `test` handler after removal', () => {
75-
emitter.on('test', handler);
76-
emitter.off('test', handler);
77-
expect(emitter.has('test')).toBe(false);
78-
});
79-
80-
it('It should have no `test` handler after use stop callback', () => {
81-
emitter.on('test', handler)();
82-
expect(emitter.has('test')).toBe(false);
83-
});
84-
85-
it('It should have no `test` handler after emit once', () => {
86-
emitter.once('test', handler);
87-
emitter.emit('test');
88-
expect(emitter.has('test')).toBe(false);
89-
});
99+
expect(handler).toHaveBeenCalledTimes(1);
100+
expect(unusedHandler).toHaveBeenCalledTimes(0);
90101
});
91102
});

packages/emitter/src/index.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -167,14 +167,14 @@ export class Emitter<EventMap extends DefaultEventMap = DefaultEventMap>
167167
this[once].delete(handler);
168168
}
169169

170-
if (handlers.length === 1) {
171-
this[evts].delete(type);
172-
return;
173-
}
174170
handlers.splice(
175171
handlers.findIndex((callback) => callback === handler) >>> 0,
176172
1
177173
);
174+
175+
if (handlers.length === 0) {
176+
this[evts].delete(type);
177+
}
178178
}
179179

180180
/**

0 commit comments

Comments
 (0)