@incodetech/core 2.0.0-alpha.2 → 2.0.0-alpha.3

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.
Files changed (134) hide show
  1. package/package.json +4 -1
  2. package/.turbo/turbo-build.log +0 -33
  3. package/.turbo/turbo-coverage.log +0 -22
  4. package/.turbo/turbo-format.log +0 -6
  5. package/.turbo/turbo-lint$colon$fix.log +0 -77
  6. package/.turbo/turbo-lint.log +0 -95
  7. package/.turbo/turbo-test.log +0 -870
  8. package/.turbo/turbo-typecheck.log +0 -5
  9. package/coverage/base.css +0 -224
  10. package/coverage/block-navigation.js +0 -87
  11. package/coverage/favicon.png +0 -0
  12. package/coverage/index.html +0 -221
  13. package/coverage/prettify.css +0 -1
  14. package/coverage/prettify.js +0 -2
  15. package/coverage/sort-arrow-sprite.png +0 -0
  16. package/coverage/sorter.js +0 -210
  17. package/coverage/src/camera/cameraService.ts.html +0 -580
  18. package/coverage/src/camera/cameraServices.ts.html +0 -163
  19. package/coverage/src/camera/cameraStateMachine.ts.html +0 -877
  20. package/coverage/src/camera/index.html +0 -146
  21. package/coverage/src/email/emailActor.ts.html +0 -130
  22. package/coverage/src/email/emailManager.ts.html +0 -1366
  23. package/coverage/src/email/emailStateMachine.ts.html +0 -1186
  24. package/coverage/src/email/index.html +0 -146
  25. package/coverage/src/flow/flowActor.ts.html +0 -124
  26. package/coverage/src/flow/flowAnalyzer.ts.html +0 -196
  27. package/coverage/src/flow/flowManager.ts.html +0 -790
  28. package/coverage/src/flow/flowServices.ts.html +0 -124
  29. package/coverage/src/flow/flowStateMachine.ts.html +0 -631
  30. package/coverage/src/flow/index.html +0 -221
  31. package/coverage/src/flow/moduleLoader.ts.html +0 -304
  32. package/coverage/src/flow/orchestratedFlowManager.ts.html +0 -778
  33. package/coverage/src/flow/orchestratedFlowStateMachine.ts.html +0 -1060
  34. package/coverage/src/http/api.ts.html +0 -355
  35. package/coverage/src/http/endpoints.ts.html +0 -136
  36. package/coverage/src/http/index.html +0 -131
  37. package/coverage/src/index.html +0 -116
  38. package/coverage/src/phone/index.html +0 -146
  39. package/coverage/src/phone/phoneActor.ts.html +0 -130
  40. package/coverage/src/phone/phoneManager.ts.html +0 -1459
  41. package/coverage/src/phone/phoneStateMachine.ts.html +0 -1351
  42. package/coverage/src/recordings/index.html +0 -116
  43. package/coverage/src/recordings/recordingsRepository.ts.html +0 -229
  44. package/coverage/src/selfie/index.html +0 -191
  45. package/coverage/src/selfie/selfieActor.ts.html +0 -136
  46. package/coverage/src/selfie/selfieErrorUtils.ts.html +0 -283
  47. package/coverage/src/selfie/selfieManager.ts.html +0 -988
  48. package/coverage/src/selfie/selfieStateMachine.ts.html +0 -2497
  49. package/coverage/src/selfie/selfieUploadService.ts.html +0 -328
  50. package/coverage/src/selfie/types.ts.html +0 -394
  51. package/coverage/src/setup.ts.html +0 -598
  52. package/src/camera/cameraActor.ts +0 -21
  53. package/src/camera/cameraService.test.ts +0 -437
  54. package/src/camera/cameraService.ts +0 -165
  55. package/src/camera/cameraServices.test.ts +0 -66
  56. package/src/camera/cameraServices.ts +0 -26
  57. package/src/camera/cameraStateMachine.test.ts +0 -602
  58. package/src/camera/cameraStateMachine.ts +0 -264
  59. package/src/camera/index.ts +0 -5
  60. package/src/camera/types.ts +0 -17
  61. package/src/device/getBrowser.ts +0 -31
  62. package/src/device/getDeviceClass.ts +0 -29
  63. package/src/device/index.ts +0 -2
  64. package/src/email/__mocks__/emailMocks.ts +0 -59
  65. package/src/email/emailActor.ts +0 -15
  66. package/src/email/emailManager.test.ts +0 -573
  67. package/src/email/emailManager.ts +0 -427
  68. package/src/email/emailServices.ts +0 -66
  69. package/src/email/emailStateMachine.test.ts +0 -741
  70. package/src/email/emailStateMachine.ts +0 -367
  71. package/src/email/index.ts +0 -39
  72. package/src/email/types.ts +0 -60
  73. package/src/events/addEvent.ts +0 -20
  74. package/src/events/types.ts +0 -7
  75. package/src/flow/__mocks__/flowMocks.ts +0 -84
  76. package/src/flow/flowActor.ts +0 -13
  77. package/src/flow/flowAnalyzer.test.ts +0 -266
  78. package/src/flow/flowAnalyzer.ts +0 -37
  79. package/src/flow/flowCompletionService.ts +0 -21
  80. package/src/flow/flowManager.test.ts +0 -560
  81. package/src/flow/flowManager.ts +0 -235
  82. package/src/flow/flowServices.test.ts +0 -109
  83. package/src/flow/flowServices.ts +0 -13
  84. package/src/flow/flowStateMachine.test.ts +0 -334
  85. package/src/flow/flowStateMachine.ts +0 -182
  86. package/src/flow/index.ts +0 -21
  87. package/src/flow/moduleLoader.test.ts +0 -136
  88. package/src/flow/moduleLoader.ts +0 -73
  89. package/src/flow/orchestratedFlowManager.test.ts +0 -240
  90. package/src/flow/orchestratedFlowManager.ts +0 -231
  91. package/src/flow/orchestratedFlowStateMachine.test.ts +0 -199
  92. package/src/flow/orchestratedFlowStateMachine.ts +0 -325
  93. package/src/flow/types.ts +0 -434
  94. package/src/http/__mocks__/api.ts +0 -88
  95. package/src/http/api.test.ts +0 -231
  96. package/src/http/api.ts +0 -90
  97. package/src/http/endpoints.ts +0 -17
  98. package/src/index.ts +0 -33
  99. package/src/permissions/index.ts +0 -2
  100. package/src/permissions/permissionServices.ts +0 -31
  101. package/src/permissions/types.ts +0 -3
  102. package/src/phone/__mocks__/phoneMocks.ts +0 -71
  103. package/src/phone/index.ts +0 -39
  104. package/src/phone/phoneActor.ts +0 -15
  105. package/src/phone/phoneManager.test.ts +0 -393
  106. package/src/phone/phoneManager.ts +0 -458
  107. package/src/phone/phoneServices.ts +0 -98
  108. package/src/phone/phoneStateMachine.test.ts +0 -918
  109. package/src/phone/phoneStateMachine.ts +0 -422
  110. package/src/phone/types.ts +0 -83
  111. package/src/recordings/recordingsRepository.test.ts +0 -87
  112. package/src/recordings/recordingsRepository.ts +0 -48
  113. package/src/recordings/streamingEvents.ts +0 -10
  114. package/src/selfie/__mocks__/selfieMocks.ts +0 -26
  115. package/src/selfie/index.ts +0 -14
  116. package/src/selfie/selfieActor.ts +0 -17
  117. package/src/selfie/selfieErrorUtils.test.ts +0 -116
  118. package/src/selfie/selfieErrorUtils.ts +0 -66
  119. package/src/selfie/selfieManager.test.ts +0 -297
  120. package/src/selfie/selfieManager.ts +0 -301
  121. package/src/selfie/selfieServices.ts +0 -362
  122. package/src/selfie/selfieStateMachine.test.ts +0 -283
  123. package/src/selfie/selfieStateMachine.ts +0 -804
  124. package/src/selfie/selfieUploadService.test.ts +0 -90
  125. package/src/selfie/selfieUploadService.ts +0 -81
  126. package/src/selfie/types.ts +0 -103
  127. package/src/session/index.ts +0 -5
  128. package/src/session/sessionService.ts +0 -78
  129. package/src/setup.test.ts +0 -61
  130. package/src/setup.ts +0 -171
  131. package/tsconfig.json +0 -13
  132. package/tsdown.config.ts +0 -22
  133. package/vitest.config.ts +0 -37
  134. package/vitest.setup.ts +0 -135
@@ -1,602 +0,0 @@
1
- import { createActor, MockCameraProvider } from '@incodetech/infra';
2
- import { beforeEach, describe, expect, it, vi } from 'vitest';
3
- import { cameraMachine } from './cameraStateMachine';
4
-
5
- const createTestActor = () => {
6
- const camera = new MockCameraProvider();
7
- return createActor(cameraMachine, {
8
- input: { camera },
9
- }).start();
10
- };
11
-
12
- // Helper to mock permission query result
13
- const mockPermissionQuery = (state: 'granted' | 'denied' | 'prompt') => {
14
- const setPermissionState = (
15
- globalThis as {
16
- __setPermissionState?: (state: 'granted' | 'denied' | 'prompt') => void;
17
- }
18
- ).__setPermissionState;
19
- if (setPermissionState) {
20
- setPermissionState(state);
21
- }
22
- };
23
-
24
- describe('CameraStateMachine', () => {
25
- describe('Initial state', () => {
26
- it('should start in idle state', () => {
27
- const actor = createTestActor();
28
-
29
- expect(actor.getSnapshot().value).toBe('idle');
30
- actor.stop();
31
- });
32
-
33
- it('should have initial context with camera capability', () => {
34
- const actor = createTestActor();
35
-
36
- const { context } = actor.getSnapshot();
37
- expect(context.camera).toBeDefined();
38
- expect(context.stream).toBeUndefined();
39
- expect(context.permissionResult).toBeUndefined();
40
- expect(context.error).toBeUndefined();
41
- expect(context.errorType).toBeUndefined();
42
-
43
- actor.stop();
44
- });
45
- });
46
-
47
- describe('START event', () => {
48
- it('should transition from idle to checkingPermission', () => {
49
- const actor = createTestActor();
50
-
51
- actor.send({ type: 'START' });
52
-
53
- expect(actor.getSnapshot().value).toBe('checkingPermission');
54
- actor.stop();
55
- });
56
- });
57
-
58
- describe('Permission checking flow', () => {
59
- it('should transition to routing after permission check', async () => {
60
- const actor = createTestActor();
61
-
62
- actor.send({ type: 'START' });
63
-
64
- await vi.waitFor(
65
- () => {
66
- const snapshot = actor.getSnapshot();
67
- expect(['routing', 'requesting', 'streaming']).toContain(
68
- snapshot.value,
69
- );
70
- },
71
- { timeout: 2000 },
72
- );
73
-
74
- actor.stop();
75
- });
76
-
77
- it('should set permission result in context', async () => {
78
- const actor = createTestActor();
79
-
80
- actor.send({ type: 'START' });
81
-
82
- await vi.waitFor(
83
- () => {
84
- const snapshot = actor.getSnapshot();
85
- if (
86
- snapshot.value === 'routing' ||
87
- snapshot.value === 'requesting' ||
88
- snapshot.value === 'streaming'
89
- ) {
90
- expect(snapshot.context.permissionResult).toBeDefined();
91
- }
92
- },
93
- { timeout: 2000 },
94
- );
95
-
96
- actor.stop();
97
- });
98
- });
99
-
100
- describe('Stream request flow', () => {
101
- it('should transition to streaming on successful stream', async () => {
102
- const camera = new MockCameraProvider();
103
- const mockStream = new MediaStream();
104
- camera.setMockStream(mockStream);
105
- const actor = createActor(cameraMachine, {
106
- input: { camera },
107
- }).start();
108
-
109
- actor.send({ type: 'START' });
110
-
111
- await vi.waitFor(
112
- () => {
113
- const value = actor.getSnapshot().value;
114
- if (value !== 'streaming' && value !== 'error') {
115
- throw new Error(`Still in state: ${value}`);
116
- }
117
- },
118
- { timeout: 5000, interval: 50 },
119
- );
120
-
121
- const snapshot = actor.getSnapshot();
122
- expect(snapshot.value).toBe('streaming');
123
- expect(snapshot.context.stream).toBe(mockStream);
124
-
125
- actor.stop();
126
- });
127
-
128
- it('should transition to error on stream failure', async () => {
129
- const camera = new MockCameraProvider();
130
- camera.setShouldReject(true);
131
- const actor = createActor(cameraMachine, {
132
- input: { camera },
133
- }).start();
134
-
135
- actor.send({ type: 'START' });
136
-
137
- await vi.waitFor(
138
- () => {
139
- const value = actor.getSnapshot().value;
140
- if (value !== 'error' && value !== 'streaming') {
141
- throw new Error(`Still in state: ${value}`);
142
- }
143
- },
144
- { timeout: 5000, interval: 50 },
145
- );
146
-
147
- const snapshot = actor.getSnapshot();
148
- expect(snapshot.value).toBe('error');
149
- expect(snapshot.context.error).toBeDefined();
150
- expect(snapshot.context.errorType).toBeDefined();
151
-
152
- actor.stop();
153
- });
154
- });
155
-
156
- describe('STOP event', () => {
157
- it('should transition from checkingPermission to idle', () => {
158
- const actor = createTestActor();
159
-
160
- actor.send({ type: 'START' });
161
- actor.send({ type: 'STOP' });
162
-
163
- expect(actor.getSnapshot().value).toBe('idle');
164
- actor.stop();
165
- });
166
-
167
- it('should transition from requesting to idle', () => {
168
- const actor = createTestActor();
169
-
170
- actor.send({ type: 'START' });
171
- actor.send({ type: 'STOP' });
172
-
173
- expect(actor.getSnapshot().value).toBe('idle');
174
- actor.stop();
175
- });
176
- });
177
-
178
- describe('Routing state', () => {
179
- beforeEach(() => {
180
- // Reset permission mock to default
181
- mockPermissionQuery('prompt');
182
- });
183
-
184
- it('should route to requesting when permission is granted', async () => {
185
- // Set mock BEFORE creating actor
186
- mockPermissionQuery('granted');
187
- const camera = new MockCameraProvider();
188
- const mockStream = new MediaStream();
189
- camera.setMockStream(mockStream);
190
- const actor = createActor(cameraMachine, {
191
- input: { camera },
192
- }).start();
193
-
194
- actor.send({ type: 'START' });
195
-
196
- // Wait for streaming state (granted -> routing -> requesting -> streaming)
197
- await vi.waitFor(
198
- () => {
199
- const value = actor.getSnapshot().value;
200
- if (value !== 'streaming' && value !== 'error') {
201
- throw new Error(`Still in state: ${value}`);
202
- }
203
- },
204
- { timeout: 5000, interval: 50 },
205
- );
206
-
207
- expect(actor.getSnapshot().value).toBe('streaming');
208
- expect(actor.getSnapshot().context.permissionResult).toBe('granted');
209
-
210
- actor.stop();
211
- });
212
-
213
- it('should route to error when permission is denied', async () => {
214
- // Set mock BEFORE creating actor
215
- mockPermissionQuery('denied');
216
- const camera = new MockCameraProvider();
217
- const actor = createActor(cameraMachine, {
218
- input: { camera },
219
- }).start();
220
-
221
- actor.send({ type: 'START' });
222
-
223
- // Wait for error state (denied -> routing -> error)
224
- await vi.waitFor(
225
- () => {
226
- const value = actor.getSnapshot().value;
227
- if (value !== 'error' && value !== 'streaming') {
228
- throw new Error(`Still in state: ${value}`);
229
- }
230
- },
231
- { timeout: 5000, interval: 50 },
232
- );
233
-
234
- const snapshot = actor.getSnapshot();
235
- expect(snapshot.value).toBe('error');
236
- expect(snapshot.context.permissionResult).toBe('denied');
237
- expect(snapshot.context.errorType).toBe('permission_denied');
238
-
239
- actor.stop();
240
- });
241
-
242
- it('should route to requesting when permission is prompt', async () => {
243
- // Set mock BEFORE creating actor
244
- mockPermissionQuery('prompt');
245
- const camera = new MockCameraProvider();
246
- const mockStream = new MediaStream();
247
- camera.setMockStream(mockStream);
248
- const actor = createActor(cameraMachine, {
249
- input: { camera },
250
- }).start();
251
-
252
- actor.send({ type: 'START' });
253
-
254
- // Wait for streaming (prompt -> routing -> requesting -> streaming)
255
- await vi.waitFor(
256
- () => {
257
- const value = actor.getSnapshot().value;
258
- if (value !== 'streaming' && value !== 'error') {
259
- throw new Error(`Still in state: ${value}`);
260
- }
261
- },
262
- { timeout: 5000, interval: 50 },
263
- );
264
-
265
- expect(actor.getSnapshot().value).toBe('streaming');
266
- expect(actor.getSnapshot().context.permissionResult).toBe('prompt');
267
-
268
- actor.stop();
269
- });
270
- });
271
-
272
- describe('Streaming state', () => {
273
- it('should transition to idle when STOP is sent from streaming', async () => {
274
- const camera = new MockCameraProvider();
275
- const mockStream = new MediaStream();
276
- camera.setMockStream(mockStream);
277
- const stopSpy = vi.spyOn(camera, 'stopStream');
278
- const actor = createActor(cameraMachine, {
279
- input: { camera },
280
- }).start();
281
-
282
- actor.send({ type: 'START' });
283
-
284
- // Wait for streaming state
285
- await vi.waitFor(
286
- () => {
287
- const snapshot = actor.getSnapshot();
288
- if (snapshot.value !== 'streaming' || !snapshot.context.stream) {
289
- throw new Error(`Not streaming yet: ${snapshot.value}`);
290
- }
291
- },
292
- { timeout: 5000, interval: 50 },
293
- );
294
-
295
- // Send STOP
296
- actor.send({ type: 'STOP' });
297
-
298
- // STOP should transition immediately (synchronous)
299
- const stopSnapshot = actor.getSnapshot();
300
- expect(stopSnapshot.value).toBe('idle');
301
-
302
- // stopStream should be called because stream was in context
303
- expect(stopSpy).toHaveBeenCalled();
304
-
305
- actor.stop();
306
- });
307
- });
308
-
309
- describe('Error state', () => {
310
- it('should transition to idle when RESET is sent from error', () => {
311
- const actor = createTestActor();
312
-
313
- // Manually transition to error state
314
- actor.send({ type: 'START' });
315
- actor.send({
316
- type: 'STREAM_ERROR',
317
- error: 'Test error',
318
- errorType: 'unknown',
319
- });
320
-
321
- // Wait a tick for state update
322
- const errorSnapshot = actor.getSnapshot();
323
- if (errorSnapshot.value === 'error') {
324
- actor.send({ type: 'RESET' });
325
- expect(actor.getSnapshot().value).toBe('idle');
326
- expect(actor.getSnapshot().context.error).toBeUndefined();
327
- expect(actor.getSnapshot().context.errorType).toBeUndefined();
328
- }
329
-
330
- actor.stop();
331
- });
332
-
333
- it('should transition to idle when STOP is sent from error', () => {
334
- const actor = createTestActor();
335
-
336
- // Manually transition to error state
337
- actor.send({ type: 'START' });
338
- actor.send({
339
- type: 'STREAM_ERROR',
340
- error: 'Test error',
341
- errorType: 'unknown',
342
- });
343
-
344
- // Wait a tick for state update
345
- const errorSnapshot = actor.getSnapshot();
346
- if (errorSnapshot.value === 'error') {
347
- actor.send({ type: 'STOP' });
348
- expect(actor.getSnapshot().value).toBe('idle');
349
- }
350
-
351
- actor.stop();
352
- });
353
- });
354
-
355
- describe('Error handling', () => {
356
- it('should set error type for NotAllowedError', async () => {
357
- const camera = new MockCameraProvider();
358
- camera.setShouldReject(
359
- true,
360
- new DOMException('Permission denied', 'NotAllowedError'),
361
- );
362
- const actor = createActor(cameraMachine, {
363
- input: { camera },
364
- }).start();
365
-
366
- actor.send({ type: 'START' });
367
-
368
- await vi.waitFor(
369
- () => {
370
- if (actor.getSnapshot().value !== 'error') {
371
- throw new Error('Not in error state yet');
372
- }
373
- },
374
- { timeout: 5000, interval: 50 },
375
- );
376
-
377
- const errorSnapshot = actor.getSnapshot();
378
- expect(errorSnapshot.value).toBe('error');
379
- expect(errorSnapshot.context.errorType).toBe('permission_denied');
380
-
381
- actor.stop();
382
- });
383
-
384
- it('should set error type for NotFoundError', async () => {
385
- const camera = new MockCameraProvider();
386
- camera.setShouldReject(
387
- true,
388
- new DOMException('Camera not found', 'NotFoundError'),
389
- );
390
- const actor = createActor(cameraMachine, {
391
- input: { camera },
392
- }).start();
393
-
394
- actor.send({ type: 'START' });
395
-
396
- await vi.waitFor(
397
- () => {
398
- if (actor.getSnapshot().value !== 'error') {
399
- throw new Error('Not in error state yet');
400
- }
401
- },
402
- { timeout: 5000, interval: 50 },
403
- );
404
-
405
- const errorSnapshot = actor.getSnapshot();
406
- expect(errorSnapshot.value).toBe('error');
407
- expect(errorSnapshot.context.errorType).toBe('not_found');
408
-
409
- actor.stop();
410
- });
411
-
412
- it('should set error type for NotReadableError', async () => {
413
- const camera = new MockCameraProvider();
414
- camera.setShouldReject(
415
- true,
416
- new DOMException('Camera in use', 'NotReadableError'),
417
- );
418
- const actor = createActor(cameraMachine, {
419
- input: { camera },
420
- }).start();
421
-
422
- actor.send({ type: 'START' });
423
-
424
- await vi.waitFor(
425
- () => {
426
- if (actor.getSnapshot().value !== 'error') {
427
- throw new Error('Not in error state yet');
428
- }
429
- },
430
- { timeout: 5000, interval: 50 },
431
- );
432
-
433
- const errorSnapshot = actor.getSnapshot();
434
- expect(errorSnapshot.value).toBe('error');
435
- expect(errorSnapshot.context.errorType).toBe('not_readable');
436
-
437
- actor.stop();
438
- });
439
-
440
- it('should set error type for OverconstrainedError', async () => {
441
- const camera = new MockCameraProvider();
442
- camera.setShouldReject(
443
- true,
444
- new DOMException('Constraints not supported', 'OverconstrainedError'),
445
- );
446
- const actor = createActor(cameraMachine, {
447
- input: { camera },
448
- }).start();
449
-
450
- actor.send({ type: 'START' });
451
-
452
- await vi.waitFor(
453
- () => {
454
- if (actor.getSnapshot().value !== 'error') {
455
- throw new Error('Not in error state yet');
456
- }
457
- },
458
- { timeout: 5000, interval: 50 },
459
- );
460
-
461
- const errorSnapshot = actor.getSnapshot();
462
- expect(errorSnapshot.value).toBe('error');
463
- expect(errorSnapshot.context.errorType).toBe('overconstrained');
464
-
465
- actor.stop();
466
- });
467
-
468
- it('should set error type for SecurityError', async () => {
469
- const camera = new MockCameraProvider();
470
- camera.setShouldReject(
471
- true,
472
- new DOMException('Security error', 'SecurityError'),
473
- );
474
- const actor = createActor(cameraMachine, {
475
- input: { camera },
476
- }).start();
477
-
478
- actor.send({ type: 'START' });
479
-
480
- await vi.waitFor(
481
- () => {
482
- if (actor.getSnapshot().value !== 'error') {
483
- throw new Error('Not in error state yet');
484
- }
485
- },
486
- { timeout: 5000, interval: 50 },
487
- );
488
-
489
- const errorSnapshot = actor.getSnapshot();
490
- expect(errorSnapshot.value).toBe('error');
491
- expect(errorSnapshot.context.errorType).toBe('security');
492
-
493
- actor.stop();
494
- });
495
-
496
- it('should set error type for AbortError', async () => {
497
- const camera = new MockCameraProvider();
498
- camera.setShouldReject(
499
- true,
500
- new DOMException('Request aborted', 'AbortError'),
501
- );
502
- const actor = createActor(cameraMachine, {
503
- input: { camera },
504
- }).start();
505
-
506
- actor.send({ type: 'START' });
507
-
508
- await vi.waitFor(
509
- () => {
510
- if (actor.getSnapshot().value !== 'error') {
511
- throw new Error('Not in error state yet');
512
- }
513
- },
514
- { timeout: 5000, interval: 50 },
515
- );
516
-
517
- const errorSnapshot = actor.getSnapshot();
518
- expect(errorSnapshot.value).toBe('error');
519
- expect(errorSnapshot.context.errorType).toBe('abort');
520
-
521
- actor.stop();
522
- });
523
-
524
- it('should set error type to unknown for unrecognized errors', async () => {
525
- const camera = new MockCameraProvider();
526
- camera.setShouldReject(true, new Error('Unknown error'));
527
- const actor = createActor(cameraMachine, {
528
- input: { camera },
529
- }).start();
530
-
531
- actor.send({ type: 'START' });
532
-
533
- await vi.waitFor(
534
- () => {
535
- if (actor.getSnapshot().value !== 'error') {
536
- throw new Error('Not in error state yet');
537
- }
538
- },
539
- { timeout: 5000, interval: 50 },
540
- );
541
-
542
- const errorSnapshot = actor.getSnapshot();
543
- expect(errorSnapshot.value).toBe('error');
544
- expect(errorSnapshot.context.errorType).toBe('unknown');
545
- expect(errorSnapshot.context.error).toBe('Unknown error');
546
-
547
- actor.stop();
548
- });
549
-
550
- it('should handle error without message', async () => {
551
- const camera = new MockCameraProvider();
552
- const errorWithoutMessage = new Error();
553
- errorWithoutMessage.message = '';
554
- camera.setShouldReject(true, errorWithoutMessage);
555
- const actor = createActor(cameraMachine, {
556
- input: { camera },
557
- }).start();
558
-
559
- actor.send({ type: 'START' });
560
-
561
- await vi.waitFor(
562
- () => {
563
- if (actor.getSnapshot().value !== 'error') {
564
- throw new Error('Not in error state yet');
565
- }
566
- },
567
- { timeout: 5000, interval: 50 },
568
- );
569
-
570
- const errorSnapshot = actor.getSnapshot();
571
- expect(errorSnapshot.value).toBe('error');
572
- expect(errorSnapshot.context.error).toBeDefined();
573
- expect(errorSnapshot.context.errorType).toBe('unknown');
574
-
575
- actor.stop();
576
- });
577
- });
578
-
579
- describe('Permission check error handling', () => {
580
- it('should handle permission check failure gracefully', async () => {
581
- const actor = createTestActor();
582
-
583
- actor.send({ type: 'START' });
584
-
585
- // Wait for permission check to complete (even if it fails)
586
- await vi.waitFor(
587
- () => {
588
- const snapshot = actor.getSnapshot();
589
- // Should transition to routing even on error (with prompt as default)
590
- return (
591
- snapshot.value === 'routing' ||
592
- snapshot.value === 'requesting' ||
593
- snapshot.value === 'streaming'
594
- );
595
- },
596
- { timeout: 2000 },
597
- );
598
-
599
- actor.stop();
600
- });
601
- });
602
- });