Skip to content

Commit 9a8c25a

Browse files
authored
feat: error specific @EmitOnFail() (#539)
1 parent b48b67d commit 9a8c25a

File tree

4 files changed

+98
-2
lines changed

4 files changed

+98
-2
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,8 @@ import { SocketController, OnMessage, EmitOnSuccess, EmitOnFail } from 'socket-c
258258
export class MessageController {
259259
@OnMessage('save')
260260
@EmitOnSuccess('save_successfully')
261+
@EmitOnFail('save_error_range', {errorType: RangeError})
262+
@EmitOnFail('save_error_type', {errorType: TypeError})
261263
@EmitOnFail('save_error')
262264
save() {
263265
if (1 === 1) {
@@ -272,6 +274,7 @@ export class MessageController {
272274
```
273275

274276
In this case `save_error` message will be sent to the client with `One is equal to one! Fatal error!` error message.
277+
The order is important when defining multiple `@EmitOnFail()` decorators, the first matching errorType will be served
275278

276279
Sometimes you may want to not emit success/error message if returned result is null or undefined.
277280
In such cases you can use `@SkipEmitOnEmptyResult()` decorator.

src/SocketControllers.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,13 +222,26 @@ export class SocketControllers {
222222
}
223223

224224
private handleActionResult(socket: Socket, action: ActionMetadata, result: any, resultType: ResultType) {
225-
const onResultActions = action.results?.filter(result => result.type === resultType) || [];
225+
const allOnResultActions = action.results?.filter(result => result.type === resultType) || [];
226226
const skipOnEmpty = action.results?.some(result => result.type === ResultType.SKIP_EMIT_ON_EMPTY_RESULT);
227227

228228
if (result == null && skipOnEmpty) {
229229
return;
230230
}
231231

232+
let onResultActions = allOnResultActions;
233+
if (onResultActions.some(action => action.options.errorType)) {
234+
const firstFittingAction = allOnResultActions.find(
235+
action => action.options.errorType && result instanceof (action.options.errorType as Function)
236+
);
237+
238+
if (!firstFittingAction) {
239+
onResultActions = allOnResultActions.filter(action => !action.options.errorType);
240+
} else {
241+
onResultActions = [firstFittingAction];
242+
}
243+
}
244+
232245
for (const onResultAction of onResultActions) {
233246
const transformedValue =
234247
result instanceof Error

src/decorators/EmitOnFail.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { addResultToActionMetadata } from '../util/add-result-to-action-metadata
22
import { ResultType } from '../types/enums/ResultType';
33
import { ActionTransformOptions } from '../types/ActionTransformOptions';
44

5-
export function EmitOnFail(messageName: string, options?: ActionTransformOptions): Function {
5+
export function EmitOnFail(messageName: string, options?: ActionTransformOptions & { errorType: unknown }): Function {
66
return function (object: Object, methodName: string) {
77
addResultToActionMetadata(object.constructor, methodName, {
88
type: ResultType.EMIT_ON_FAIL,

test/functional/emit-on-fail.spec.ts

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { OnConnect } from '../../src/decorators/OnConnect';
88
import { ConnectedSocket } from '../../src/decorators/ConnectedSocket';
99
import { waitForEvent } from '../utilities/waitForEvent';
1010
import { EmitOnFail, OnMessage } from '../../src';
11+
import { waitForTime } from '../utilities/waitForTime';
1112

1213
describe('EmitOnFail', () => {
1314
const PORT = 8080;
@@ -124,4 +125,83 @@ describe('EmitOnFail', () => {
124125
expect(errors[0]).toEqual('error string');
125126
expect(errors.length).toEqual(1);
126127
});
128+
129+
it('Emit defined event on failing with specific error type', async () => {
130+
@SocketController('/string')
131+
@Service()
132+
class TestController {
133+
@OnConnect()
134+
connected(@ConnectedSocket() socket: Socket) {
135+
socket.emit('connected');
136+
}
137+
138+
@OnMessage('request')
139+
@EmitOnFail('fail1', { errorType: RangeError })
140+
@EmitOnFail('fail2', { errorType: TypeError })
141+
@EmitOnFail('fail3')
142+
async testEvent() {
143+
throw new RangeError('range error');
144+
}
145+
146+
@OnMessage('request2')
147+
@EmitOnFail('fail1', { errorType: RangeError })
148+
@EmitOnFail('fail2', { errorType: TypeError })
149+
@EmitOnFail('fail3')
150+
async testEvent2() {
151+
throw new TypeError('type error');
152+
}
153+
154+
@OnMessage('request3')
155+
@EmitOnFail('fail1', { errorType: RangeError })
156+
@EmitOnFail('fail2', { errorType: TypeError })
157+
@EmitOnFail('fail3')
158+
async testEvent3() {
159+
throw new Error('test error');
160+
}
161+
162+
@OnMessage('request4')
163+
@EmitOnFail('fail1', { errorType: Error })
164+
@EmitOnFail('fail2', { errorType: TypeError })
165+
@EmitOnFail('fail3')
166+
async testEvent4() {
167+
throw new TypeError('type error 2');
168+
}
169+
}
170+
171+
socketControllers = new SocketControllers({
172+
io: wsApp,
173+
container: Container,
174+
controllers: [TestController],
175+
});
176+
wsClient = io(PATH_FOR_CLIENT + '/string', { reconnection: false, timeout: 5000, forceNew: true });
177+
178+
const errors = { fail1: [], fail2: [], fail3: [] };
179+
180+
wsClient.on('fail1', data => {
181+
errors.fail1.push(data);
182+
});
183+
184+
wsClient.on('fail2', data => {
185+
errors.fail2.push(data);
186+
});
187+
188+
wsClient.on('fail3', data => {
189+
errors.fail3.push(data);
190+
});
191+
192+
await waitForEvent(wsClient, 'connected');
193+
194+
wsClient.emit('request');
195+
wsClient.emit('request2');
196+
wsClient.emit('request3');
197+
wsClient.emit('request4');
198+
199+
await waitForTime(1000);
200+
201+
expect(errors).toEqual({
202+
fail1: ['range error', 'type error 2'],
203+
fail2: ['type error'],
204+
fail3: ['test error'],
205+
});
206+
});
127207
});

0 commit comments

Comments
 (0)