@dangao/bun-server 1.8.0 → 1.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/api.md +194 -81
- package/docs/extensions.md +53 -0
- package/docs/guide.md +243 -1
- package/docs/microservice-config-center.md +73 -74
- package/docs/microservice-nacos.md +89 -90
- package/docs/microservice-service-registry.md +85 -86
- package/docs/microservice.md +142 -137
- package/docs/request-lifecycle.md +45 -4
- package/docs/symbol-interface-pattern.md +106 -106
- package/docs/zh/api.md +458 -18
- package/docs/zh/extensions.md +53 -0
- package/docs/zh/guide.md +251 -4
- package/docs/zh/microservice-config-center.md +258 -0
- package/docs/zh/microservice-nacos.md +346 -0
- package/docs/zh/microservice-service-registry.md +306 -0
- package/docs/zh/microservice.md +680 -0
- package/docs/zh/request-lifecycle.md +43 -5
- package/package.json +1 -1
- package/tests/auth/auth-decorators.test.ts +241 -0
- package/tests/auth/oauth2-service.test.ts +318 -0
- package/tests/cache/cache-decorators-extended.test.ts +272 -0
- package/tests/cache/cache-interceptors.test.ts +534 -0
- package/tests/cache/cache-service-proxy.test.ts +246 -0
- package/tests/cache/memory-cache-store.test.ts +155 -0
- package/tests/cache/redis-cache-store.test.ts +199 -0
- package/tests/config/config-center-integration.test.ts +334 -0
- package/tests/config/config-module-extended.test.ts +165 -0
- package/tests/controller/param-binder.test.ts +333 -0
- package/tests/error/error-handler.test.ts +166 -57
- package/tests/error/i18n-extended.test.ts +105 -0
- package/tests/events/event-listener-scanner.test.ts +114 -0
- package/tests/events/event-module.test.ts +133 -302
- package/tests/extensions/logger-module.test.ts +158 -0
- package/tests/files/file-storage.test.ts +136 -0
- package/tests/interceptor/base-interceptor.test.ts +605 -0
- package/tests/interceptor/builtin/cache-interceptor.test.ts +233 -86
- package/tests/interceptor/builtin/log-interceptor.test.ts +469 -0
- package/tests/interceptor/builtin/permission-interceptor.test.ts +219 -120
- package/tests/interceptor/interceptor-chain.test.ts +241 -189
- package/tests/interceptor/interceptor-metadata.test.ts +221 -0
- package/tests/microservice/circuit-breaker.test.ts +221 -0
- package/tests/microservice/service-client-decorators.test.ts +86 -0
- package/tests/microservice/service-client-interceptors.test.ts +274 -0
- package/tests/microservice/service-registry-decorators.test.ts +147 -0
- package/tests/microservice/tracer.test.ts +213 -0
- package/tests/microservice/tracing-collectors.test.ts +168 -0
- package/tests/middleware/builtin/middleware-builtin-extended.test.ts +237 -0
- package/tests/middleware/builtin/rate-limit.test.ts +257 -0
- package/tests/middleware/middleware-decorators.test.ts +222 -0
- package/tests/middleware/middleware-pipeline.test.ts +160 -0
- package/tests/queue/queue-decorators.test.ts +139 -0
- package/tests/queue/queue-service.test.ts +191 -0
- package/tests/request/body-parser-extended.test.ts +291 -0
- package/tests/request/request-wrapper.test.ts +319 -0
- package/tests/router/router-decorators.test.ts +260 -0
- package/tests/router/router-extended.test.ts +298 -0
- package/tests/security/guards/reflector.test.ts +188 -0
- package/tests/security/security-filter.test.ts +182 -0
- package/tests/security/security-module-extended.test.ts +133 -0
- package/tests/session/memory-session-store.test.ts +172 -0
- package/tests/session/session-decorators.test.ts +163 -0
- package/tests/swagger/ui.test.ts +212 -0
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { describe, expect, test, beforeEach } from 'bun:test';
|
|
2
|
+
import 'reflect-metadata';
|
|
3
|
+
|
|
4
|
+
import { EventListenerScanner, EVENT_LISTENER_SCANNER_TOKEN } from '../../src/events/event-module';
|
|
5
|
+
import { EventEmitterService } from '../../src/events/service';
|
|
6
|
+
import { OnEvent } from '../../src/events/decorators';
|
|
7
|
+
import { EVENT_LISTENER_CLASS_METADATA_KEY } from '../../src/events/types';
|
|
8
|
+
import { Container } from '../../src/di/container';
|
|
9
|
+
import { Injectable } from '../../src/di/decorators';
|
|
10
|
+
|
|
11
|
+
describe('EventListenerScanner', () => {
|
|
12
|
+
let emitter: EventEmitterService;
|
|
13
|
+
let container: Container;
|
|
14
|
+
let scanner: EventListenerScanner;
|
|
15
|
+
|
|
16
|
+
beforeEach(() => {
|
|
17
|
+
emitter = new EventEmitterService();
|
|
18
|
+
container = new Container();
|
|
19
|
+
scanner = new EventListenerScanner(emitter, container);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
describe('scanAndRegister', () => {
|
|
23
|
+
test('should register listeners from class with OnEvent decorator', () => {
|
|
24
|
+
@Injectable()
|
|
25
|
+
class TestListener {
|
|
26
|
+
public receivedPayload: any = null;
|
|
27
|
+
|
|
28
|
+
@OnEvent('test-event')
|
|
29
|
+
public handleTestEvent(payload: any): void {
|
|
30
|
+
this.receivedPayload = payload;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Mark as event listener class
|
|
35
|
+
Reflect.defineMetadata(EVENT_LISTENER_CLASS_METADATA_KEY, true, TestListener);
|
|
36
|
+
|
|
37
|
+
container.register(TestListener);
|
|
38
|
+
scanner.scanAndRegister([TestListener]);
|
|
39
|
+
|
|
40
|
+
expect(emitter.listenerCount('test-event')).toBe(1);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test('should skip non-listener classes', () => {
|
|
44
|
+
class NotAListener {
|
|
45
|
+
public someMethod(): void {}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
scanner.scanAndRegister([NotAListener]);
|
|
49
|
+
|
|
50
|
+
// No listeners registered
|
|
51
|
+
expect(emitter.listenerCount('some-event')).toBe(0);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
test('should handle multiple listeners', () => {
|
|
55
|
+
@Injectable()
|
|
56
|
+
class MultiListener {
|
|
57
|
+
@OnEvent('event1')
|
|
58
|
+
public handleEvent1(): void {}
|
|
59
|
+
|
|
60
|
+
@OnEvent('event2')
|
|
61
|
+
public handleEvent2(): void {}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
Reflect.defineMetadata(EVENT_LISTENER_CLASS_METADATA_KEY, true, MultiListener);
|
|
65
|
+
|
|
66
|
+
container.register(MultiListener);
|
|
67
|
+
scanner.scanAndRegister([MultiListener]);
|
|
68
|
+
|
|
69
|
+
expect(emitter.listenerCount('event1')).toBe(1);
|
|
70
|
+
expect(emitter.listenerCount('event2')).toBe(1);
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
describe('registerListenerClass', () => {
|
|
75
|
+
test('should register single listener class', () => {
|
|
76
|
+
@Injectable()
|
|
77
|
+
class SingleListener {
|
|
78
|
+
@OnEvent('single-event')
|
|
79
|
+
public handle(): void {}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
Reflect.defineMetadata(EVENT_LISTENER_CLASS_METADATA_KEY, true, SingleListener);
|
|
83
|
+
container.register(SingleListener);
|
|
84
|
+
|
|
85
|
+
scanner.registerListenerClass(SingleListener);
|
|
86
|
+
|
|
87
|
+
expect(emitter.listenerCount('single-event')).toBe(1);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
test('should skip class without metadata', () => {
|
|
91
|
+
class NoMetadata {
|
|
92
|
+
public handle(): void {}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
scanner.registerListenerClass(NoMetadata);
|
|
96
|
+
|
|
97
|
+
expect(emitter.eventNames().length).toBe(0);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
test('should handle class not registered in container', () => {
|
|
101
|
+
@Injectable()
|
|
102
|
+
class UnregisteredListener {
|
|
103
|
+
@OnEvent('unreg-event')
|
|
104
|
+
public handle(): void {}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
Reflect.defineMetadata(EVENT_LISTENER_CLASS_METADATA_KEY, true, UnregisteredListener);
|
|
108
|
+
// Not registering in container
|
|
109
|
+
|
|
110
|
+
// Should not throw, just warn
|
|
111
|
+
expect(() => scanner.registerListenerClass(UnregisteredListener)).not.toThrow();
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
});
|
|
@@ -1,373 +1,204 @@
|
|
|
1
|
-
import { describe, expect, test, beforeEach,
|
|
1
|
+
import { describe, expect, test, beforeEach, afterEach } from 'bun:test';
|
|
2
2
|
import 'reflect-metadata';
|
|
3
|
-
|
|
3
|
+
|
|
4
|
+
import { EventModule } from '../../src/events/event-module';
|
|
4
5
|
import { EventEmitterService } from '../../src/events/service';
|
|
5
|
-
import {
|
|
6
|
-
import { Container } from '../../src/di/container';
|
|
7
|
-
import { Injectable } from '../../src/di/decorators';
|
|
6
|
+
import { EVENT_EMITTER_TOKEN, EVENT_OPTIONS_TOKEN } from '../../src/events/types';
|
|
8
7
|
import { MODULE_METADATA_KEY } from '../../src/di/module';
|
|
9
|
-
import { ModuleRegistry } from '../../src/di/module-registry';
|
|
10
|
-
import {
|
|
11
|
-
EVENT_EMITTER_TOKEN,
|
|
12
|
-
EVENT_OPTIONS_TOKEN,
|
|
13
|
-
type EventEmitter,
|
|
14
|
-
} from '../../src/events/types';
|
|
15
8
|
|
|
16
9
|
describe('EventModule', () => {
|
|
17
10
|
beforeEach(() => {
|
|
18
|
-
// 清除模块元数据
|
|
19
11
|
Reflect.deleteMetadata(MODULE_METADATA_KEY, EventModule);
|
|
20
12
|
});
|
|
21
13
|
|
|
22
|
-
describe('forRoot
|
|
23
|
-
test('should
|
|
14
|
+
describe('forRoot', () => {
|
|
15
|
+
test('should create module with default options', () => {
|
|
24
16
|
EventModule.forRoot();
|
|
25
17
|
|
|
26
18
|
const metadata = Reflect.getMetadata(MODULE_METADATA_KEY, EventModule);
|
|
27
19
|
expect(metadata.providers).toBeDefined();
|
|
28
|
-
expect(metadata.
|
|
29
|
-
|
|
30
|
-
const emitterProvider = metadata.providers.find(
|
|
31
|
-
(p: any) => p.provide === EVENT_EMITTER_TOKEN,
|
|
32
|
-
);
|
|
33
|
-
expect(emitterProvider).toBeDefined();
|
|
34
|
-
expect(emitterProvider.useValue).toBeInstanceOf(EventEmitterService);
|
|
20
|
+
expect(metadata.exports).toContain(EVENT_EMITTER_TOKEN);
|
|
35
21
|
});
|
|
36
22
|
|
|
37
|
-
test('should
|
|
38
|
-
|
|
39
|
-
|
|
23
|
+
test('should create module with custom options', () => {
|
|
24
|
+
EventModule.forRoot({
|
|
25
|
+
maxListeners: 50,
|
|
26
|
+
async: true,
|
|
27
|
+
errorHandler: (event, error) => {
|
|
28
|
+
console.error(`Event ${event} error:`, error);
|
|
29
|
+
},
|
|
30
|
+
});
|
|
40
31
|
|
|
41
32
|
const metadata = Reflect.getMetadata(MODULE_METADATA_KEY, EventModule);
|
|
33
|
+
expect(metadata.providers).toBeDefined();
|
|
34
|
+
|
|
35
|
+
// Find options provider
|
|
42
36
|
const optionsProvider = metadata.providers.find(
|
|
43
37
|
(p: any) => p.provide === EVENT_OPTIONS_TOKEN,
|
|
44
38
|
);
|
|
45
|
-
|
|
46
|
-
expect(optionsProvider).
|
|
47
|
-
expect(optionsProvider.useValue).toEqual(options);
|
|
39
|
+
expect(optionsProvider?.useValue?.maxListeners).toBe(50);
|
|
40
|
+
expect(optionsProvider?.useValue?.async).toBe(true);
|
|
48
41
|
});
|
|
49
42
|
|
|
50
|
-
test('should export
|
|
43
|
+
test('should export EventService', () => {
|
|
51
44
|
EventModule.forRoot();
|
|
52
45
|
|
|
53
46
|
const metadata = Reflect.getMetadata(MODULE_METADATA_KEY, EventModule);
|
|
54
47
|
expect(metadata.exports).toContain(EVENT_EMITTER_TOKEN);
|
|
55
48
|
});
|
|
56
|
-
|
|
57
|
-
test('should apply options to event emitter', () => {
|
|
58
|
-
EventModule.forRoot({ wildcard: true, globalPrefix: 'test' });
|
|
59
|
-
|
|
60
|
-
const metadata = Reflect.getMetadata(MODULE_METADATA_KEY, EventModule);
|
|
61
|
-
const emitterProvider = metadata.providers.find(
|
|
62
|
-
(p: any) => p.provide === EVENT_EMITTER_TOKEN,
|
|
63
|
-
);
|
|
64
|
-
|
|
65
|
-
// EventEmitterService 内部存储了选项
|
|
66
|
-
expect(emitterProvider.useValue).toBeInstanceOf(EventEmitterService);
|
|
67
|
-
});
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
describe('getEventEmitter()', () => {
|
|
71
|
-
test('should return event emitter from container', () => {
|
|
72
|
-
EventModule.forRoot();
|
|
73
|
-
|
|
74
|
-
const container = new Container();
|
|
75
|
-
const emitterService = new EventEmitterService();
|
|
76
|
-
// 使用 registerInstance 方法注册实例(对应 useValue)
|
|
77
|
-
container.registerInstance(EVENT_EMITTER_TOKEN, emitterService);
|
|
78
|
-
|
|
79
|
-
const result = EventModule.getEventEmitter(container);
|
|
80
|
-
expect(result).toBe(emitterService);
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
test('should return undefined when not registered', () => {
|
|
84
|
-
const container = new Container();
|
|
85
|
-
// getEventEmitter 现在会捕获错误并返回 undefined
|
|
86
|
-
const result = EventModule.getEventEmitter(container);
|
|
87
|
-
expect(result).toBeUndefined();
|
|
88
|
-
});
|
|
89
49
|
});
|
|
90
50
|
});
|
|
91
51
|
|
|
92
|
-
describe('
|
|
93
|
-
let
|
|
94
|
-
let eventEmitter: EventEmitterService;
|
|
95
|
-
let scanner: EventListenerScanner;
|
|
52
|
+
describe('EventEmitterService', () => {
|
|
53
|
+
let service: EventEmitterService;
|
|
96
54
|
|
|
97
55
|
beforeEach(() => {
|
|
98
|
-
|
|
99
|
-
eventEmitter = new EventEmitterService();
|
|
100
|
-
scanner = new EventListenerScanner(eventEmitter, container);
|
|
56
|
+
service = new EventEmitterService({ maxListeners: 10 });
|
|
101
57
|
});
|
|
102
58
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
@Injectable()
|
|
107
|
-
class TestService {
|
|
108
|
-
@OnEvent('test.event')
|
|
109
|
-
public handleEvent(payload: unknown): void {
|
|
110
|
-
handler(payload);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// 注册服务到容器
|
|
115
|
-
container.register(TestService, { useClass: TestService });
|
|
116
|
-
|
|
117
|
-
// 扫描并注册监听器
|
|
118
|
-
scanner.scanAndRegister([TestService]);
|
|
119
|
-
|
|
120
|
-
// 触发事件
|
|
121
|
-
eventEmitter.emit('test.event', { data: 'test' });
|
|
122
|
-
|
|
123
|
-
expect(handler).toHaveBeenCalledTimes(1);
|
|
124
|
-
expect(handler).toHaveBeenCalledWith({ data: 'test' });
|
|
59
|
+
afterEach(() => {
|
|
60
|
+
service.removeAllListeners();
|
|
125
61
|
});
|
|
126
62
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
63
|
+
describe('on', () => {
|
|
64
|
+
test('should register listener', () => {
|
|
65
|
+
const handler = () => {};
|
|
66
|
+
service.on('test-event', handler);
|
|
130
67
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
@OnEvent('event1')
|
|
134
|
-
public handleEvent1(payload: unknown): void {
|
|
135
|
-
handler1(payload);
|
|
136
|
-
}
|
|
68
|
+
expect(service.listenerCount('test-event')).toBe(1);
|
|
69
|
+
});
|
|
137
70
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
}
|
|
142
|
-
}
|
|
71
|
+
test('should return unsubscribe function', () => {
|
|
72
|
+
const handler = () => {};
|
|
73
|
+
const unsubscribe = service.on('test-event', handler);
|
|
143
74
|
|
|
144
|
-
|
|
145
|
-
|
|
75
|
+
expect(typeof unsubscribe).toBe('function');
|
|
76
|
+
unsubscribe();
|
|
77
|
+
expect(service.listenerCount('test-event')).toBe(0);
|
|
78
|
+
});
|
|
146
79
|
|
|
147
|
-
|
|
148
|
-
|
|
80
|
+
test('should support multiple listeners', () => {
|
|
81
|
+
service.on('event', () => {});
|
|
82
|
+
service.on('event', () => {});
|
|
83
|
+
service.on('event', () => {});
|
|
149
84
|
|
|
150
|
-
|
|
151
|
-
|
|
85
|
+
expect(service.listenerCount('event')).toBe(3);
|
|
86
|
+
});
|
|
152
87
|
});
|
|
153
88
|
|
|
154
|
-
|
|
155
|
-
|
|
89
|
+
describe('once', () => {
|
|
90
|
+
test('should register one-time listener', async () => {
|
|
91
|
+
let callCount = 0;
|
|
92
|
+
service.once('one-time', () => {
|
|
93
|
+
callCount++;
|
|
94
|
+
});
|
|
156
95
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
@OnEvent('test.event', { priority: 1 })
|
|
160
|
-
public lowPriority(): void {
|
|
161
|
-
order.push(1);
|
|
162
|
-
}
|
|
96
|
+
await service.emit('one-time');
|
|
97
|
+
await service.emit('one-time');
|
|
163
98
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
order.push(10);
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
container.register(TestService, { useClass: TestService });
|
|
171
|
-
scanner.scanAndRegister([TestService]);
|
|
172
|
-
|
|
173
|
-
eventEmitter.emit('test.event', null);
|
|
174
|
-
|
|
175
|
-
expect(order).toEqual([10, 1]);
|
|
99
|
+
expect(callCount).toBe(1);
|
|
100
|
+
});
|
|
176
101
|
});
|
|
177
102
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
103
|
+
describe('emit', () => {
|
|
104
|
+
test('should call listeners with payload', () => {
|
|
105
|
+
let receivedData: any;
|
|
106
|
+
service.on('data-event', (data) => {
|
|
107
|
+
receivedData = data;
|
|
108
|
+
});
|
|
183
109
|
|
|
184
|
-
|
|
110
|
+
service.emit('data-event', { value: 42 });
|
|
185
111
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
});
|
|
112
|
+
expect(receivedData).toEqual({ value: 42 });
|
|
113
|
+
});
|
|
189
114
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
public handleEvent(): void {}
|
|
195
|
-
}
|
|
115
|
+
test('should not throw when no listeners', () => {
|
|
116
|
+
// emit returns void, not boolean
|
|
117
|
+
expect(() => service.emit('no-listeners', null)).not.toThrow();
|
|
118
|
+
});
|
|
196
119
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
120
|
+
test('should call listener when registered', () => {
|
|
121
|
+
let called = false;
|
|
122
|
+
service.on('has-listeners', () => { called = true; });
|
|
123
|
+
service.emit('has-listeners', null);
|
|
124
|
+
expect(called).toBe(true);
|
|
125
|
+
});
|
|
202
126
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
127
|
+
test('should call multiple listeners in order', () => {
|
|
128
|
+
const order: number[] = [];
|
|
129
|
+
service.on('ordered', () => order.push(1));
|
|
130
|
+
service.on('ordered', () => order.push(2));
|
|
131
|
+
service.on('ordered', () => order.push(3));
|
|
207
132
|
|
|
208
|
-
|
|
209
|
-
const handler = mock(() => {});
|
|
210
|
-
|
|
211
|
-
@Injectable()
|
|
212
|
-
class NotificationService {
|
|
213
|
-
@OnEvent('user.created')
|
|
214
|
-
public sendWelcomeEmail(payload: { email: string }): void {
|
|
215
|
-
handler(payload);
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
// 配置模块
|
|
220
|
-
EventModule.forRoot();
|
|
221
|
-
|
|
222
|
-
// 模拟模块注册流程
|
|
223
|
-
const registry = ModuleRegistry.getInstance();
|
|
224
|
-
const rootContainer = new Container();
|
|
225
|
-
|
|
226
|
-
// 手动创建 EventModule 的模块引用
|
|
227
|
-
const eventModuleContainer = new Container({ parent: rootContainer });
|
|
228
|
-
const emitter = new EventEmitterService();
|
|
229
|
-
eventModuleContainer.registerInstance(EVENT_EMITTER_TOKEN, emitter);
|
|
230
|
-
|
|
231
|
-
// 注册 NotificationService 到同一个容器
|
|
232
|
-
eventModuleContainer.register(NotificationService, { implementation: NotificationService });
|
|
233
|
-
|
|
234
|
-
// 模拟 ModuleRegistry 的 getModuleRef 返回
|
|
235
|
-
const originalGetModuleRef = registry.getModuleRef.bind(registry);
|
|
236
|
-
registry.getModuleRef = (moduleClass: any) => {
|
|
237
|
-
if (moduleClass === EventModule) {
|
|
238
|
-
return {
|
|
239
|
-
moduleClass: EventModule,
|
|
240
|
-
container: eventModuleContainer,
|
|
241
|
-
metadata: { providers: [], exports: [], imports: [], controllers: [] },
|
|
242
|
-
controllersRegistered: false,
|
|
243
|
-
attachedParents: new Set(),
|
|
244
|
-
extensions: [],
|
|
245
|
-
middlewares: [],
|
|
246
|
-
isGlobal: false,
|
|
247
|
-
} as any;
|
|
248
|
-
}
|
|
249
|
-
return originalGetModuleRef(moduleClass);
|
|
250
|
-
};
|
|
251
|
-
|
|
252
|
-
// 初始化监听器
|
|
253
|
-
EventModule.initializeListeners(eventModuleContainer, [NotificationService]);
|
|
254
|
-
|
|
255
|
-
// 发布事件
|
|
256
|
-
emitter.emit('user.created', { email: 'test@example.com' });
|
|
257
|
-
|
|
258
|
-
expect(handler).toHaveBeenCalledWith({ email: 'test@example.com' });
|
|
259
|
-
|
|
260
|
-
// 恢复原始方法
|
|
261
|
-
registry.getModuleRef = originalGetModuleRef;
|
|
262
|
-
});
|
|
133
|
+
service.emit('ordered', null);
|
|
263
134
|
|
|
264
|
-
|
|
265
|
-
|
|
135
|
+
expect(order).toEqual([1, 2, 3]);
|
|
136
|
+
});
|
|
137
|
+
});
|
|
266
138
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
results.push(payload);
|
|
273
|
-
}
|
|
274
|
-
}
|
|
139
|
+
describe('off', () => {
|
|
140
|
+
test('should remove specific listener', () => {
|
|
141
|
+
const handler = () => {};
|
|
142
|
+
service.on('removable', handler);
|
|
143
|
+
service.off('removable', handler);
|
|
275
144
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
container.register(EVENT_EMITTER_TOKEN, { useValue: emitter });
|
|
279
|
-
container.register(AsyncService, { useClass: AsyncService });
|
|
145
|
+
expect(service.listenerCount('removable')).toBe(0);
|
|
146
|
+
});
|
|
280
147
|
|
|
281
|
-
|
|
282
|
-
|
|
148
|
+
test('should not affect other listeners', () => {
|
|
149
|
+
const handler1 = () => {};
|
|
150
|
+
const handler2 = () => {};
|
|
283
151
|
|
|
284
|
-
|
|
152
|
+
service.on('event', handler1);
|
|
153
|
+
service.on('event', handler2);
|
|
154
|
+
service.off('event', handler1);
|
|
285
155
|
|
|
286
|
-
|
|
156
|
+
expect(service.listenerCount('event')).toBe(1);
|
|
157
|
+
});
|
|
287
158
|
});
|
|
288
159
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
160
|
+
describe('removeAllListeners', () => {
|
|
161
|
+
test('should remove all listeners for event', () => {
|
|
162
|
+
service.on('event', () => {});
|
|
163
|
+
service.on('event', () => {});
|
|
164
|
+
service.removeAllListeners('event');
|
|
292
165
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
@OnEvent(USER_UPDATED)
|
|
296
|
-
public handleUserUpdated(payload: unknown): void {
|
|
297
|
-
handler(payload);
|
|
298
|
-
}
|
|
299
|
-
}
|
|
166
|
+
expect(service.listenerCount('event')).toBe(0);
|
|
167
|
+
});
|
|
300
168
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
169
|
+
test('should remove all listeners when no event specified', () => {
|
|
170
|
+
service.on('event1', () => {});
|
|
171
|
+
service.on('event2', () => {});
|
|
172
|
+
service.removeAllListeners();
|
|
305
173
|
|
|
306
|
-
|
|
307
|
-
|
|
174
|
+
expect(service.listenerCount('event1')).toBe(0);
|
|
175
|
+
expect(service.listenerCount('event2')).toBe(0);
|
|
176
|
+
});
|
|
177
|
+
});
|
|
308
178
|
|
|
309
|
-
|
|
179
|
+
describe('eventNames', () => {
|
|
180
|
+
test('should return all event names', () => {
|
|
181
|
+
service.on('event1', () => {});
|
|
182
|
+
service.on('event2', () => {});
|
|
183
|
+
service.on('event3', () => {});
|
|
310
184
|
|
|
311
|
-
|
|
185
|
+
const names = service.eventNames();
|
|
186
|
+
expect(names).toContain('event1');
|
|
187
|
+
expect(names).toContain('event2');
|
|
188
|
+
expect(names).toContain('event3');
|
|
189
|
+
});
|
|
312
190
|
});
|
|
313
|
-
});
|
|
314
191
|
|
|
315
|
-
describe('
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
192
|
+
describe('getListeners', () => {
|
|
193
|
+
test('should return listeners count via listenerCount', () => {
|
|
194
|
+
const handler1 = () => {};
|
|
195
|
+
const handler2 = () => {};
|
|
196
|
+
|
|
197
|
+
service.on('event', handler1);
|
|
198
|
+
service.on('event', handler2);
|
|
320
199
|
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
@Injectable()
|
|
325
|
-
class CollectedService {
|
|
326
|
-
@OnEvent('collected.event')
|
|
327
|
-
public handleEvent(payload: unknown): void {
|
|
328
|
-
handler(payload);
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
EventModule.forRoot();
|
|
333
|
-
EventModule.registerListeners([CollectedService]);
|
|
334
|
-
|
|
335
|
-
// 模拟模块注册流程
|
|
336
|
-
const registry = ModuleRegistry.getInstance();
|
|
337
|
-
const rootContainer = new Container();
|
|
338
|
-
|
|
339
|
-
// 手动创建 EventModule 的模块引用
|
|
340
|
-
const eventModuleContainer = new Container({ parent: rootContainer });
|
|
341
|
-
const emitter = new EventEmitterService();
|
|
342
|
-
eventModuleContainer.registerInstance(EVENT_EMITTER_TOKEN, emitter);
|
|
343
|
-
eventModuleContainer.register(CollectedService, { implementation: CollectedService });
|
|
344
|
-
|
|
345
|
-
// 模拟 ModuleRegistry 的 getModuleRef 返回
|
|
346
|
-
const originalGetModuleRef = registry.getModuleRef.bind(registry);
|
|
347
|
-
registry.getModuleRef = (moduleClass: any) => {
|
|
348
|
-
if (moduleClass === EventModule) {
|
|
349
|
-
return {
|
|
350
|
-
moduleClass: EventModule,
|
|
351
|
-
container: eventModuleContainer,
|
|
352
|
-
metadata: { providers: [], exports: [], imports: [], controllers: [] },
|
|
353
|
-
controllersRegistered: false,
|
|
354
|
-
attachedParents: new Set(),
|
|
355
|
-
extensions: [],
|
|
356
|
-
middlewares: [],
|
|
357
|
-
isGlobal: false,
|
|
358
|
-
} as any;
|
|
359
|
-
}
|
|
360
|
-
return originalGetModuleRef(moduleClass);
|
|
361
|
-
};
|
|
362
|
-
|
|
363
|
-
// initializeListeners 会包含通过 registerListeners 注册的类
|
|
364
|
-
EventModule.initializeListeners(eventModuleContainer);
|
|
365
|
-
|
|
366
|
-
emitter.emit('collected.event', 'test');
|
|
367
|
-
|
|
368
|
-
expect(handler).toHaveBeenCalledWith('test');
|
|
369
|
-
|
|
370
|
-
// 恢复原始方法
|
|
371
|
-
registry.getModuleRef = originalGetModuleRef;
|
|
200
|
+
// Use listenerCount method instead
|
|
201
|
+
expect(service.listenerCount('event')).toBe(2);
|
|
202
|
+
});
|
|
372
203
|
});
|
|
373
204
|
});
|