scandit-datacapture-frameworks-core 7.6.2 → 8.0.0-beta.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.
Files changed (32) hide show
  1. package/__mocks__/Defaults.ts +64 -0
  2. package/__mocks__/ScanditDataCaptureCore.ts +148 -0
  3. package/dist/dts/camera/Camera.d.ts +32 -5
  4. package/dist/dts/camera/CameraController.d.ts +2 -2
  5. package/dist/dts/camera/VideoResolution.d.ts +1 -0
  6. package/dist/dts/camerahelpers/CameraOwner.d.ts +3 -0
  7. package/dist/dts/camerahelpers/CameraOwnershipHelper.d.ts +42 -0
  8. package/dist/dts/camerahelpers/CameraOwnershipManager.d.ts +24 -0
  9. package/dist/dts/camerahelpers/index.d.ts +3 -0
  10. package/dist/dts/common/Payload.d.ts +2 -0
  11. package/dist/dts/context/DataCaptureContext.d.ts +6 -10
  12. package/dist/dts/frame/FrameSource.d.ts +1 -0
  13. package/dist/dts/view/DataCaptureView.d.ts +2 -2
  14. package/dist/dts/view/index.d.ts +1 -1
  15. package/dist/index.js +647 -222
  16. package/dist/index.js.map +1 -1
  17. package/jest.config.js +39 -0
  18. package/node_modules/eventemitter3/LICENSE +21 -0
  19. package/node_modules/eventemitter3/README.md +94 -0
  20. package/node_modules/eventemitter3/dist/eventemitter3.esm.js +347 -0
  21. package/node_modules/eventemitter3/dist/eventemitter3.esm.min.js +1 -0
  22. package/node_modules/eventemitter3/dist/eventemitter3.esm.min.js.map +1 -0
  23. package/node_modules/eventemitter3/dist/eventemitter3.umd.js +355 -0
  24. package/node_modules/eventemitter3/dist/eventemitter3.umd.min.js +1 -0
  25. package/node_modules/eventemitter3/dist/eventemitter3.umd.min.js.map +1 -0
  26. package/node_modules/eventemitter3/index.d.ts +135 -0
  27. package/node_modules/eventemitter3/index.js +336 -0
  28. package/node_modules/eventemitter3/index.mjs +4 -0
  29. package/node_modules/eventemitter3/package.json +67 -0
  30. package/package.json +4 -4
  31. package/test/Camera.test.ts +294 -0
  32. package/dist/dts/view/ScreenStateManager.d.ts +0 -8
@@ -0,0 +1,294 @@
1
+ import { describe, it, expect, jest, beforeEach } from '@jest/globals';
2
+ import { Camera, CameraSettings, FrameSourceState, TorchState, CameraPosition, createNativeProxy, FactoryMaker } from '../src';
3
+ import { MockCaller, MockNativeEventEmitter, MockDataCaptureContext, createMockCameraNativeModule, createMockDataCaptureContextNativeModule, createMockFeedbackNativeModule } from '../__mocks__/ScanditDataCaptureCore';
4
+ import { CameraProxy } from '../src/camera/CameraController';
5
+ import { DataCaptureContextProxy } from '../src/context/controller/DataCaptureContextController';
6
+ import { FeedbackProxy } from '../src/feedback/FeedbackController';
7
+ import { loadMockDefaults } from '../__mocks__/Defaults';
8
+
9
+ describe('Camera Lifecycle with Promise-based Waiting', () => {
10
+ let nativeEventEmitter: MockNativeEventEmitter;
11
+ let mockContext: MockDataCaptureContext;
12
+ let mockCameraNativeModule: any;
13
+ let mockContextNativeModule: any;
14
+ let mockFeedbackNativeModule: any;
15
+
16
+ beforeEach(() => {
17
+ jest.clearAllMocks();
18
+
19
+ (Camera as any)._cameraInstances.clear();
20
+ FactoryMaker.instances.delete('CameraProxy');
21
+ FactoryMaker.instances.delete('DataCaptureContextProxy');
22
+ FactoryMaker.instances.delete('FeedbackProxy');
23
+
24
+ mockCameraNativeModule = createMockCameraNativeModule();
25
+ mockContextNativeModule = createMockDataCaptureContextNativeModule();
26
+ mockFeedbackNativeModule = createMockFeedbackNativeModule();
27
+ nativeEventEmitter = new MockNativeEventEmitter();
28
+
29
+ loadMockDefaults();
30
+
31
+ FactoryMaker.bindLazyInstance('CameraProxy', () => {
32
+ const caller = new MockCaller(mockCameraNativeModule, nativeEventEmitter);
33
+ return createNativeProxy<CameraProxy>(caller);
34
+ });
35
+
36
+ FactoryMaker.bindLazyInstance('DataCaptureContextProxy', () => {
37
+ const caller = new MockCaller(mockContextNativeModule, nativeEventEmitter);
38
+ return createNativeProxy<DataCaptureContextProxy>(caller);
39
+ });
40
+
41
+ FactoryMaker.bindLazyInstance('FeedbackProxy', () => {
42
+ const caller = new MockCaller(mockFeedbackNativeModule, nativeEventEmitter);
43
+ return createNativeProxy<FeedbackProxy>(caller);
44
+ });
45
+
46
+ mockContext = new MockDataCaptureContext();
47
+ });
48
+
49
+ describe('Phase 1: Initial State', () => {
50
+ it('operations only update properties, no native calls', () => {
51
+ const camera = Camera.default!;
52
+ const settings = new CameraSettings();
53
+
54
+ camera.desiredTorchState = TorchState.On;
55
+ camera.applySettings(settings);
56
+
57
+ expect(camera.desiredTorchState).toBe(TorchState.On);
58
+ expect((camera as any).settings).toBe(settings);
59
+ expect(mockContext.update).not.toHaveBeenCalled();
60
+ });
61
+ });
62
+
63
+ describe('Phase 2: Native Creation In Progress', () => {
64
+ it('operations wait for native camera to be ready', async () => {
65
+ const camera = Camera.default!;
66
+
67
+ const setFrameSourcePromise = mockContext.setFrameSource(camera);
68
+
69
+ camera.desiredTorchState = TorchState.On;
70
+
71
+ await setFrameSourcePromise;
72
+ await new Promise(resolve => setTimeout(resolve, 50));
73
+
74
+ expect(mockContext.controller.updateContextFromJSON).toHaveBeenCalled();
75
+ });
76
+
77
+ it('switchToDesiredState waits for native camera', async () => {
78
+ const camera = Camera.default!;
79
+
80
+ const setFrameSourcePromise = mockContext.setFrameSource(camera);
81
+ const switchPromise = camera.switchToDesiredState(FrameSourceState.On);
82
+
83
+ const controllerSpy = jest.spyOn((camera as any).controller, 'switchCameraToDesiredState');
84
+
85
+ await setFrameSourcePromise;
86
+ await switchPromise;
87
+
88
+ expect(controllerSpy).toHaveBeenCalledWith(FrameSourceState.On);
89
+ });
90
+
91
+ it('applySettings waits for native camera', async () => {
92
+ const camera = Camera.default!;
93
+ const settings = new CameraSettings();
94
+
95
+ const setFrameSourcePromise = mockContext.setFrameSource(camera);
96
+ const applyPromise = camera.applySettings(settings);
97
+
98
+ await setFrameSourcePromise;
99
+ await applyPromise;
100
+
101
+ expect(mockContext.controller.updateContextFromJSON).toHaveBeenCalled();
102
+ });
103
+ });
104
+
105
+ describe('Phase 3: Active State', () => {
106
+ it('operations execute immediately', async () => {
107
+ const camera = Camera.default!;
108
+
109
+ await mockContext.setFrameSource(camera);
110
+ await new Promise(resolve => setTimeout(resolve, 50));
111
+
112
+ mockContext.controller.updateContextFromJSON.mockClear();
113
+
114
+ camera.desiredTorchState = TorchState.On;
115
+ await new Promise(resolve => setTimeout(resolve, 50));
116
+
117
+ expect(mockContext.controller.updateContextFromJSON).toHaveBeenCalled();
118
+ });
119
+ });
120
+
121
+ describe('Phase transitions', () => {
122
+ it('transitions from Phase 1 → Phase 2 → Phase 3 correctly', async () => {
123
+ const camera = Camera.default!;
124
+
125
+ camera.desiredTorchState = TorchState.On;
126
+ expect(mockContext.controller.updateContextFromJSON).not.toHaveBeenCalled();
127
+
128
+ const setFrameSourcePromise = mockContext.setFrameSource(camera);
129
+ expect((camera as any).nativeReadyPromise).not.toBeNull();
130
+
131
+ camera.desiredTorchState = TorchState.Off;
132
+
133
+ await setFrameSourcePromise;
134
+ await new Promise(resolve => setTimeout(resolve, 50));
135
+
136
+ expect((camera as any).nativeReadyPromise).toBeNull();
137
+ expect(mockContext.controller.updateContextFromJSON).toHaveBeenCalled();
138
+ });
139
+
140
+ it('context set to null clears native ready promise', async () => {
141
+ const camera = Camera.default!;
142
+
143
+ mockContext.setFrameSource(camera);
144
+ expect((camera as any).nativeReadyPromise).not.toBeNull();
145
+
146
+ (camera as any).context = null;
147
+
148
+ expect((camera as any).nativeReadyPromise).toBeNull();
149
+ });
150
+ });
151
+
152
+ describe('Multiple operations in Phase 2', () => {
153
+ it('multiple operations all wait and execute after native is ready', async () => {
154
+ const camera = Camera.default!;
155
+ const settings = new CameraSettings();
156
+
157
+ const setFrameSourcePromise = mockContext.setFrameSource(camera);
158
+
159
+ camera.desiredTorchState = TorchState.On;
160
+ const switchPromise = camera.switchToDesiredState(FrameSourceState.On);
161
+ const applyPromise = camera.applySettings(settings);
162
+
163
+ const controllerSpy = jest.spyOn((camera as any).controller, 'switchCameraToDesiredState');
164
+
165
+ await setFrameSourcePromise;
166
+ await Promise.all([switchPromise, applyPromise]);
167
+
168
+ expect(mockContext.controller.updateContextFromJSON).toHaveBeenCalled();
169
+ expect(controllerSpy).toHaveBeenCalledWith(FrameSourceState.On);
170
+ });
171
+
172
+ it('property updates are preserved even when operations are waiting', async () => {
173
+ const camera = Camera.default!;
174
+ const settings = new CameraSettings();
175
+
176
+ const setFrameSourcePromise = mockContext.setFrameSource(camera);
177
+
178
+ camera.desiredTorchState = TorchState.On;
179
+ camera.desiredTorchState = TorchState.Off;
180
+
181
+ expect(camera.desiredTorchState).toBe(TorchState.Off);
182
+
183
+ await setFrameSourcePromise;
184
+ await new Promise(resolve => setTimeout(resolve, 50));
185
+
186
+ expect(camera.desiredTorchState).toBe(TorchState.Off);
187
+ });
188
+ });
189
+
190
+ describe('Camera singleton behavior', () => {
191
+ it('returns same camera instance for same position', () => {
192
+ const camera1 = Camera.atPosition(CameraPosition.WorldFacing);
193
+ const camera2 = Camera.atPosition(CameraPosition.WorldFacing);
194
+
195
+ expect(camera1).toBe(camera2);
196
+ });
197
+
198
+ it('resetPhaseState clears promise when camera is retrieved from cache', () => {
199
+ const camera1 = Camera.atPosition(CameraPosition.WorldFacing)!;
200
+
201
+ mockContext.setFrameSource(camera1);
202
+ expect((camera1 as any).nativeReadyPromise).not.toBeNull();
203
+
204
+ const camera2 = Camera.create(CameraPosition.WorldFacing);
205
+
206
+ expect(camera2).toBe(camera1);
207
+ expect((camera2 as any).nativeReadyPromise).toBeNull();
208
+ });
209
+
210
+ it('different camera positions are independent instances', () => {
211
+ const worldCamera = Camera.atPosition(CameraPosition.WorldFacing);
212
+ const userCamera = Camera.atPosition(CameraPosition.UserFacing);
213
+
214
+ expect(worldCamera).not.toBe(userCamera);
215
+ });
216
+ });
217
+
218
+ describe('Edge cases', () => {
219
+ it('switchToDesiredState in Phase 1 shows warning', async () => {
220
+ const camera = Camera.default!;
221
+ const consoleWarnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});
222
+
223
+ await camera.switchToDesiredState(FrameSourceState.On);
224
+
225
+ expect(consoleWarnSpy).toHaveBeenCalledWith(
226
+ expect.stringContaining('not added to the DataCaptureContext')
227
+ );
228
+
229
+ consoleWarnSpy.mockRestore();
230
+ });
231
+
232
+ it('multiple property changes in Phase 1 only update TS properties', () => {
233
+ const camera = Camera.default!;
234
+
235
+ camera.desiredTorchState = TorchState.On;
236
+ camera.desiredTorchState = TorchState.Off;
237
+ camera.desiredTorchState = TorchState.On;
238
+
239
+ expect(camera.desiredTorchState).toBe(TorchState.On);
240
+ expect(mockContext.controller.updateContextFromJSON).not.toHaveBeenCalled();
241
+ });
242
+
243
+ it('handles operations during rapid phase transitions', async () => {
244
+ const camera = Camera.default!;
245
+
246
+ camera.desiredTorchState = TorchState.On;
247
+ const setFrameSourcePromise = mockContext.setFrameSource(camera);
248
+ camera.desiredTorchState = TorchState.Off;
249
+
250
+ await setFrameSourcePromise;
251
+ await new Promise(resolve => setTimeout(resolve, 50));
252
+
253
+ expect(camera.desiredTorchState).toBe(TorchState.Off);
254
+ expect(mockContext.controller.updateContextFromJSON).toHaveBeenCalled();
255
+ });
256
+
257
+ it('times out if native camera is not ready after 5 seconds', async () => {
258
+ jest.useFakeTimers();
259
+ const camera = Camera.default!;
260
+
261
+ (camera as any).setNativeFrameSourceIsBeingCreated();
262
+
263
+ const switchPromise = camera.switchToDesiredState(FrameSourceState.On);
264
+
265
+ jest.advanceTimersByTime(5000);
266
+
267
+ await expect(switchPromise).rejects.toThrow('Camera native initialization timed out after 5 seconds');
268
+
269
+ jest.useRealTimers();
270
+ });
271
+
272
+ it('timeout is cleared when context is set', async () => {
273
+ jest.useFakeTimers();
274
+ const camera = Camera.default!;
275
+
276
+ mockContext.setFrameSource(camera);
277
+
278
+ const switchPromise = camera.switchToDesiredState(FrameSourceState.On);
279
+
280
+ jest.advanceTimersByTime(1000);
281
+
282
+ (camera as any).context = mockContext;
283
+
284
+ await switchPromise;
285
+
286
+ jest.advanceTimersByTime(5000);
287
+
288
+ jest.useRealTimers();
289
+ });
290
+ });
291
+ });
292
+
293
+
294
+
@@ -1,8 +0,0 @@
1
- export declare class ScreenStateManager {
2
- private static instance;
3
- private activeScreenId;
4
- private constructor();
5
- static getInstance(): ScreenStateManager;
6
- setActiveScreen(screenId: number): void;
7
- isScreenActive(screenId: number): boolean;
8
- }