|
1 | | -import { TestBed } from '@angular/core/testing'; |
| 1 | +import { TestBed, fakeAsync, tick } from '@angular/core/testing'; |
2 | 2 | import { PLATFORM_ID } from '@angular/core'; |
3 | 3 | import { provideStore } from '@ngrx/store'; |
4 | 4 | import { provideEffects, EffectSources } from '@ngrx/effects'; |
5 | 5 |
|
6 | 6 | import { ActionsInterceptorService, DevToolMessage } from '../core/actions-interceptor.service'; |
7 | 7 | import { EffectTrackerService } from '../core/effect-tracker.service'; |
8 | | -import { DevToolsEffectSources } from '../core/devtools-effect-sources'; |
| 8 | +import { DevToolsEffectSources, EffectEvent } from '../core/devtools-effect-sources'; |
9 | 9 | import { WebSocketService } from '../core/websocket.service'; |
10 | 10 | import { TestEffects, testActions, testReducer } from './test-effects'; |
11 | 11 | import { MockWebSocket, WebSocketConstants } from './mock-websocket'; |
@@ -172,6 +172,94 @@ describe('ActionsInterceptorService', () => { |
172 | 172 | }); |
173 | 173 | }); |
174 | 174 |
|
| 175 | + describe('Effect Event Forwarding', () => { |
| 176 | + function getEffectSources(): DevToolsEffectSources { |
| 177 | + return TestBed.inject(EffectSources) as DevToolsEffectSources; |
| 178 | + } |
| 179 | + |
| 180 | + function emitEffectEvent(event: EffectEvent): void { |
| 181 | + getEffectSources().effectEvents$.next(event); |
| 182 | + } |
| 183 | + |
| 184 | + it('should include errorMessage and errorStack in EFFECT_EVENT when lifecycle is error', fakeAsync(() => { |
| 185 | + interceptorService.initialize(); |
| 186 | + const ws = getCreatedWebSocket(); |
| 187 | + ws.simulateOpen(); |
| 188 | + ws.clearMessages(); |
| 189 | + |
| 190 | + const error = new Error('Something went wrong'); |
| 191 | + |
| 192 | + emitEffectEvent({ |
| 193 | + effectName: 'TestEffects.failingEffect$', |
| 194 | + sourceName: 'TestEffects', |
| 195 | + propertyName: 'failingEffect$', |
| 196 | + lifecycle: 'error', |
| 197 | + error, |
| 198 | + timestamp: Date.now(), |
| 199 | + executionId: 'test-exec-error-1', |
| 200 | + }); |
| 201 | + tick(0); |
| 202 | + |
| 203 | + const messages = ws.getSentMessagesAsObjects<DevToolMessage>(); |
| 204 | + const effectMsg = messages.find((m) => m.type === 'EFFECT_EVENT'); |
| 205 | + |
| 206 | + expect(effectMsg).toBeDefined(); |
| 207 | + expect(effectMsg!.effectEvent?.errorMessage).toBe('Something went wrong'); |
| 208 | + expect(effectMsg!.effectEvent?.errorStack).toContain('Error: Something went wrong'); |
| 209 | + })); |
| 210 | + |
| 211 | + it('should include errorMessage for non-Error thrown values', fakeAsync(() => { |
| 212 | + interceptorService.initialize(); |
| 213 | + const ws = getCreatedWebSocket(); |
| 214 | + ws.simulateOpen(); |
| 215 | + ws.clearMessages(); |
| 216 | + |
| 217 | + emitEffectEvent({ |
| 218 | + effectName: 'TestEffects.failingEffect$', |
| 219 | + sourceName: 'TestEffects', |
| 220 | + propertyName: 'failingEffect$', |
| 221 | + lifecycle: 'error', |
| 222 | + error: 'plain string error', |
| 223 | + timestamp: Date.now(), |
| 224 | + executionId: 'test-exec-error-2', |
| 225 | + }); |
| 226 | + tick(0); |
| 227 | + |
| 228 | + const messages = ws.getSentMessagesAsObjects<DevToolMessage>(); |
| 229 | + const effectMsg = messages.find((m) => m.type === 'EFFECT_EVENT'); |
| 230 | + |
| 231 | + expect(effectMsg).toBeDefined(); |
| 232 | + expect(effectMsg!.effectEvent?.errorMessage).toBe('plain string error'); |
| 233 | + expect(effectMsg!.effectEvent?.errorStack).toBeUndefined(); |
| 234 | + })); |
| 235 | + |
| 236 | + it('should not include errorMessage or errorStack for non-error lifecycle', fakeAsync(() => { |
| 237 | + interceptorService.initialize(); |
| 238 | + const ws = getCreatedWebSocket(); |
| 239 | + ws.simulateOpen(); |
| 240 | + ws.clearMessages(); |
| 241 | + |
| 242 | + emitEffectEvent({ |
| 243 | + effectName: 'TestEffects.loadItems$', |
| 244 | + sourceName: 'TestEffects', |
| 245 | + propertyName: 'loadItems$', |
| 246 | + lifecycle: 'emitted', |
| 247 | + action: testActions.loadItemsSuccess({ items: [] }), |
| 248 | + timestamp: Date.now(), |
| 249 | + executionId: 'test-exec-emitted-1', |
| 250 | + dispatch: true, |
| 251 | + }); |
| 252 | + tick(0); |
| 253 | + |
| 254 | + const messages = ws.getSentMessagesAsObjects<DevToolMessage>(); |
| 255 | + const effectMsg = messages.find((m) => m.type === 'EFFECT_EVENT'); |
| 256 | + |
| 257 | + expect(effectMsg).toBeDefined(); |
| 258 | + expect(effectMsg!.effectEvent?.errorMessage).toBeUndefined(); |
| 259 | + expect(effectMsg!.effectEvent?.errorStack).toBeUndefined(); |
| 260 | + })); |
| 261 | + }); |
| 262 | + |
175 | 263 | describe('Platform Detection', () => { |
176 | 264 | it('should not create WebSocket on non-browser platform', () => { |
177 | 265 | TestBed.resetTestingModule(); |
|
0 commit comments