1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 | import test from "ava";
|
7 | import * as sinon from "sinon";
|
8 |
|
9 | import {
|
10 | Barcode,
|
11 | BrowserHelper,
|
12 | configure,
|
13 | ImageSettings,
|
14 | Parser,
|
15 | ParserField,
|
16 | ParserResult,
|
17 | Scanner,
|
18 | ScanResult,
|
19 | ScanSettings
|
20 | } from "..";
|
21 |
|
22 | declare const global: any;
|
23 |
|
24 | const postMessageStub: sinon.SinonStub = sinon.stub();
|
25 | const terminateStub: sinon.SinonStub = sinon.stub();
|
26 |
|
27 | const stubs: sinon.SinonStub[] = [postMessageStub, terminateStub];
|
28 |
|
29 | global.Worker = sinon.stub().returns({
|
30 | postMessage: postMessageStub,
|
31 | terminate: terminateStub
|
32 | });
|
33 | URL.createObjectURL = sinon.stub();
|
34 |
|
35 | function resetStubs(): void {
|
36 | stubs.forEach(mock => {
|
37 | mock.resetHistory();
|
38 | });
|
39 | }
|
40 |
|
41 | function checkBrowserCompatibility(): any {
|
42 | return {
|
43 | fullSupport: true,
|
44 | scannerSupport: true,
|
45 | missingFeatures: []
|
46 | };
|
47 | }
|
48 |
|
49 | async function prepareBrowserAndLibrary(): Promise<void> {
|
50 | BrowserHelper.checkBrowserCompatibility = checkBrowserCompatibility;
|
51 | await configure("#".repeat(64));
|
52 | }
|
53 |
|
54 | test.serial("constructor", async t => {
|
55 | let s: Scanner;
|
56 | let error: Error = t.throws(() => {
|
57 | s = new Scanner();
|
58 | });
|
59 | t.is(error.name, "UnsupportedBrowserError");
|
60 |
|
61 | BrowserHelper.checkBrowserCompatibility = checkBrowserCompatibility;
|
62 |
|
63 | error = t.throws(() => {
|
64 | s = new Scanner();
|
65 | });
|
66 | t.is(error.name, "LibraryNotConfiguredError");
|
67 |
|
68 | await configure("#".repeat(64));
|
69 | resetStubs();
|
70 | s = new Scanner();
|
71 | t.false(s.isReady());
|
72 | t.false(s.isBusyProcessing());
|
73 | t.is(postMessageStub.callCount, 3);
|
74 | t.deepEqual(postMessageStub.getCall(0).args, [
|
75 | {
|
76 | deviceId: BrowserHelper.getDeviceId(),
|
77 | deviceModelName: undefined,
|
78 | uaBrowserName: "WebKit",
|
79 | libraryLocation: "https://example.com/",
|
80 | path: "/",
|
81 | type: "load-library"
|
82 | }
|
83 | ]);
|
84 | t.deepEqual(postMessageStub.getCall(1).args, [
|
85 | {
|
86 | licenseKey: "#".repeat(64),
|
87 | type: "license-key"
|
88 | }
|
89 | ]);
|
90 | t.deepEqual(postMessageStub.getCall(2).args, [
|
91 | {
|
92 | settings: new ScanSettings().toJSONString(),
|
93 | type: "settings"
|
94 | }
|
95 | ]);
|
96 | resetStubs();
|
97 | const ss: ScanSettings = new ScanSettings({
|
98 | enabledSymbologies: Barcode.Symbology.QR,
|
99 | codeDuplicateFilter: 10,
|
100 | maxNumberOfCodesPerFrame: 10,
|
101 | searchArea: { x: 0.5, y: 0.5, width: 0.5, height: 0.1 }
|
102 | });
|
103 | s = new Scanner({
|
104 | scanSettings: ss
|
105 | });
|
106 | t.is(postMessageStub.callCount, 3);
|
107 | t.deepEqual(postMessageStub.getCall(2).args, [
|
108 | {
|
109 | settings: ss.toJSONString(),
|
110 | type: "settings"
|
111 | }
|
112 | ]);
|
113 | resetStubs();
|
114 | const is: ImageSettings = {
|
115 | width: 640,
|
116 | height: 480,
|
117 | format: ImageSettings.Format.RGBA_8U
|
118 | };
|
119 | s = new Scanner({
|
120 | imageSettings: is
|
121 | });
|
122 | t.is(postMessageStub.callCount, 4);
|
123 | t.deepEqual(postMessageStub.getCall(3).args, [
|
124 | {
|
125 | imageSettings: is,
|
126 | type: "image-settings"
|
127 | }
|
128 | ]);
|
129 | });
|
130 |
|
131 | test.serial("destroy", async t => {
|
132 | await prepareBrowserAndLibrary();
|
133 | resetStubs();
|
134 | let s: Scanner = new Scanner();
|
135 | s.destroy();
|
136 | t.true(terminateStub.called);
|
137 | resetStubs();
|
138 | s = new Scanner();
|
139 | (<any>s).engineWorker = null;
|
140 | s.destroy();
|
141 | t.false(terminateStub.called);
|
142 | });
|
143 |
|
144 | test.serial("applyScanSettings", async t => {
|
145 | await prepareBrowserAndLibrary();
|
146 | resetStubs();
|
147 | const ss: ScanSettings = new ScanSettings({
|
148 | enabledSymbologies: Barcode.Symbology.QR,
|
149 | codeDuplicateFilter: 10,
|
150 | maxNumberOfCodesPerFrame: 10,
|
151 | searchArea: { x: 0.5, y: 0.5, width: 0.5, height: 0.1 }
|
152 | });
|
153 | const s: Scanner = new Scanner();
|
154 | t.is(postMessageStub.callCount, 3);
|
155 | t.deepEqual(postMessageStub.getCall(2).args, [
|
156 | {
|
157 | settings: new ScanSettings().toJSONString(),
|
158 | type: "settings"
|
159 | }
|
160 | ]);
|
161 | s.applyScanSettings(ss);
|
162 | t.is(postMessageStub.callCount, 4);
|
163 | t.deepEqual(postMessageStub.getCall(3).args, [
|
164 | {
|
165 | settings: ss.toJSONString(),
|
166 | type: "settings"
|
167 | }
|
168 | ]);
|
169 | });
|
170 |
|
171 | test.serial("applyImageSettings", async t => {
|
172 | await prepareBrowserAndLibrary();
|
173 | resetStubs();
|
174 | const is: ImageSettings = {
|
175 | width: 640,
|
176 | height: 480,
|
177 | format: ImageSettings.Format.RGBA_8U
|
178 | };
|
179 | const s: Scanner = new Scanner();
|
180 | t.is(postMessageStub.callCount, 3);
|
181 | t.deepEqual(postMessageStub.getCall(2).args, [
|
182 | {
|
183 | settings: new ScanSettings().toJSONString(),
|
184 | type: "settings"
|
185 | }
|
186 | ]);
|
187 | s.applyImageSettings(is);
|
188 | t.is(postMessageStub.callCount, 4);
|
189 | t.deepEqual(postMessageStub.getCall(3).args, [
|
190 | {
|
191 | imageSettings: is,
|
192 | type: "image-settings"
|
193 | }
|
194 | ]);
|
195 | });
|
196 |
|
197 | test.serial("clearSession", async t => {
|
198 | await prepareBrowserAndLibrary();
|
199 | resetStubs();
|
200 | const s: Scanner = new Scanner();
|
201 | t.is(postMessageStub.callCount, 3);
|
202 | s.clearSession();
|
203 | t.is(postMessageStub.callCount, 4);
|
204 | t.deepEqual(postMessageStub.getCall(3).args, [
|
205 | {
|
206 | type: "clear-session"
|
207 | }
|
208 | ]);
|
209 | });
|
210 |
|
211 | test.serial("addListener", async t => {
|
212 | await prepareBrowserAndLibrary();
|
213 | resetStubs();
|
214 | const s: Scanner = new Scanner();
|
215 | const onSpy: sinon.SinonSpy<["ready", () => void], Scanner> = sinon.spy(s, "on");
|
216 | const callbackSpy: sinon.SinonSpy = sinon.spy();
|
217 | s.addListener("ready", callbackSpy);
|
218 | t.true(onSpy.calledOnceWithExactly("ready", callbackSpy));
|
219 | });
|
220 |
|
221 |
|
222 | test.serial("onReady", async t => {
|
223 | await prepareBrowserAndLibrary();
|
224 | resetStubs();
|
225 | const s: Scanner = new Scanner();
|
226 | const onSpy: sinon.SinonSpy<["ready", () => void], Scanner> = sinon.spy(s, "on");
|
227 | const callbackSpy: sinon.SinonSpy = sinon.spy();
|
228 | s.onReady(callbackSpy);
|
229 | t.true(onSpy.calledOnceWithExactly("ready", callbackSpy));
|
230 | });
|
231 |
|
232 | test.serial("isReady & on ready", async t => {
|
233 | await prepareBrowserAndLibrary();
|
234 | resetStubs();
|
235 | let s: Scanner = new Scanner();
|
236 | const callbackSpy1: sinon.SinonSpy = sinon.spy();
|
237 | const callbackSpy2: sinon.SinonSpy = sinon.spy();
|
238 | t.false(s.isReady());
|
239 | s.on("ready", callbackSpy1);
|
240 | s.on("ready", callbackSpy2);
|
241 | t.false(callbackSpy1.called);
|
242 | t.false(callbackSpy2.called);
|
243 | (<any>s).engineWorkerOnMessage({
|
244 | data: ["status", "example-not-ready"]
|
245 | });
|
246 | t.false(s.isReady());
|
247 | t.false(callbackSpy1.called);
|
248 | t.false(callbackSpy2.called);
|
249 | (<any>s).engineWorkerOnMessage({
|
250 | data: ["status", "ready"]
|
251 | });
|
252 | t.true(s.isReady());
|
253 | t.true(callbackSpy1.called);
|
254 | t.true(callbackSpy2.called);
|
255 | t.true(callbackSpy2.calledAfter(callbackSpy1));
|
256 | s = new Scanner();
|
257 | (<any>s).engineWorkerOnMessage({
|
258 | data: ["status", "ready"]
|
259 | });
|
260 | const callbackSpy3: sinon.SinonSpy = sinon.spy();
|
261 | t.true(s.isReady());
|
262 | s.on("ready", callbackSpy3);
|
263 | t.true(callbackSpy3.called);
|
264 | });
|
265 |
|
266 |
|
267 | test.serial("processImage calls", async t => {
|
268 | await prepareBrowserAndLibrary();
|
269 | const s: Scanner = new Scanner();
|
270 | resetStubs();
|
271 | let error: Error = await t.throwsAsync(s.processImage(new Uint8ClampedArray(0)));
|
272 | t.is(error.name, "NoImageSettings");
|
273 | t.is((<any>s).workerScanRequestId, 0);
|
274 | t.is((<any>s).workerScanQueueLength, 0);
|
275 | t.false(s.isBusyProcessing());
|
276 | t.false(postMessageStub.called);
|
277 | s.applyImageSettings({
|
278 | width: 3,
|
279 | height: 2,
|
280 | format: ImageSettings.Format.RGBA_8U
|
281 | });
|
282 | resetStubs();
|
283 | error = await t.throwsAsync(s.processImage(new Uint8ClampedArray(0)));
|
284 | t.is(error.name, "ImageSettingsDataMismatch");
|
285 | t.is((<any>s).workerScanRequestId, 0);
|
286 | t.is((<any>s).workerScanQueueLength, 0);
|
287 | t.false(s.isBusyProcessing());
|
288 | t.false(postMessageStub.called);
|
289 | resetStubs();
|
290 | let imageData: Uint8ClampedArray = Uint8ClampedArray.from({ length: 24 }, () => {
|
291 | return Math.floor(Math.random() * 255);
|
292 | });
|
293 |
|
294 | s.processImage(imageData);
|
295 | t.true(s.isBusyProcessing());
|
296 | t.is(postMessageStub.callCount, 1);
|
297 | t.deepEqual(postMessageStub.getCall(0).args, [
|
298 | {
|
299 | type: "work",
|
300 | requestId: 1,
|
301 | data: imageData,
|
302 | highQualitySingleFrameMode: false
|
303 | },
|
304 | [imageData.buffer]
|
305 | ]);
|
306 | s.applyImageSettings({
|
307 | width: 3,
|
308 | height: 2,
|
309 | format: ImageSettings.Format.RGB_8U
|
310 | });
|
311 | resetStubs();
|
312 | imageData = Uint8ClampedArray.from({ length: 18 }, () => {
|
313 | return Math.floor(Math.random() * 255);
|
314 | });
|
315 |
|
316 | s.processImage(imageData);
|
317 | t.is(postMessageStub.callCount, 1);
|
318 | t.deepEqual(postMessageStub.getCall(0).args, [
|
319 | {
|
320 | type: "work",
|
321 | requestId: 2,
|
322 | data: imageData,
|
323 | highQualitySingleFrameMode: false
|
324 | },
|
325 | [imageData.buffer]
|
326 | ]);
|
327 | s.applyImageSettings({
|
328 | width: 3,
|
329 | height: 2,
|
330 | format: ImageSettings.Format.GRAY_8U
|
331 | });
|
332 | resetStubs();
|
333 | imageData = Uint8ClampedArray.from({ length: 6 }, () => {
|
334 | return Math.floor(Math.random() * 255);
|
335 | });
|
336 |
|
337 | s.processImage(imageData);
|
338 | t.is(postMessageStub.callCount, 1);
|
339 | t.deepEqual(postMessageStub.getCall(0).args, [
|
340 | {
|
341 | type: "work",
|
342 | requestId: 3,
|
343 | data: imageData,
|
344 | highQualitySingleFrameMode: false
|
345 | },
|
346 | [imageData.buffer]
|
347 | ]);
|
348 | s.applyImageSettings({
|
349 | width: 3,
|
350 | height: 2,
|
351 | format: 999
|
352 | });
|
353 | resetStubs();
|
354 | imageData = Uint8ClampedArray.from({ length: 6 }, () => {
|
355 | return Math.floor(Math.random() * 255);
|
356 | });
|
357 |
|
358 | s.processImage(imageData);
|
359 | t.is((<any>s).workerScanRequestId, 4);
|
360 | t.is((<any>s).workerScanQueueLength, 4);
|
361 | t.is(postMessageStub.callCount, 1);
|
362 | t.deepEqual(postMessageStub.getCall(0).args, [
|
363 | {
|
364 | type: "work",
|
365 | requestId: 4,
|
366 | data: imageData,
|
367 | highQualitySingleFrameMode: false
|
368 | },
|
369 | [imageData.buffer]
|
370 | ]);
|
371 | });
|
372 |
|
373 | test.serial("processImage highQualitySingleFrameMode calls", async t => {
|
374 | await prepareBrowserAndLibrary();
|
375 | const s: Scanner = new Scanner();
|
376 | resetStubs();
|
377 | let error: Error = await t.throwsAsync(s.processImage(new Uint8ClampedArray(0), true));
|
378 | t.is(error.name, "NoImageSettings");
|
379 | t.is((<any>s).workerScanRequestId, 0);
|
380 | t.is((<any>s).workerScanQueueLength, 0);
|
381 | t.false(s.isBusyProcessing());
|
382 | t.false(postMessageStub.called);
|
383 | s.applyImageSettings({
|
384 | width: 3,
|
385 | height: 2,
|
386 | format: ImageSettings.Format.RGBA_8U
|
387 | });
|
388 | resetStubs();
|
389 | error = await t.throwsAsync(s.processImage(new Uint8ClampedArray(0), true));
|
390 | t.is(error.name, "ImageSettingsDataMismatch");
|
391 | t.is((<any>s).workerScanRequestId, 0);
|
392 | t.is((<any>s).workerScanQueueLength, 0);
|
393 | t.false(s.isBusyProcessing());
|
394 | t.false(postMessageStub.called);
|
395 | resetStubs();
|
396 | const imageData: Uint8ClampedArray = Uint8ClampedArray.from({ length: 24 }, () => {
|
397 | return Math.floor(Math.random() * 255);
|
398 | });
|
399 |
|
400 | s.processImage(imageData, true);
|
401 | t.true(s.isBusyProcessing());
|
402 | t.is(postMessageStub.callCount, 1);
|
403 | t.deepEqual(postMessageStub.getCall(0).args, [
|
404 | {
|
405 | type: "work",
|
406 | requestId: 1,
|
407 | data: imageData,
|
408 | highQualitySingleFrameMode: true
|
409 | },
|
410 | [imageData.buffer]
|
411 | ]);
|
412 | });
|
413 |
|
414 | test.serial("processImage calls with ImageData", async t => {
|
415 | async function getImageFromCanvas(canvasElement: HTMLCanvasElement): Promise<HTMLImageElement> {
|
416 | return new Promise(resolve => {
|
417 | const image: HTMLImageElement = new Image();
|
418 | image.onload = () => {
|
419 | resolve(image);
|
420 | };
|
421 | image.src = canvasElement.toDataURL();
|
422 | });
|
423 | }
|
424 |
|
425 | await prepareBrowserAndLibrary();
|
426 | const s: Scanner = new Scanner();
|
427 | const canvas: HTMLCanvasElement = document.createElement("canvas");
|
428 | canvas.width = 3;
|
429 | canvas.height = 2;
|
430 | let imageData: HTMLImageElement = await getImageFromCanvas(canvas);
|
431 | s.applyImageSettings({
|
432 | width: 3,
|
433 | height: 2,
|
434 | format: ImageSettings.Format.RGBA_8U
|
435 | });
|
436 | resetStubs();
|
437 |
|
438 | s.processImage(imageData);
|
439 | t.true(s.isBusyProcessing());
|
440 | t.is(postMessageStub.callCount, 1);
|
441 | t.deepEqual(postMessageStub.getCall(0).args, [
|
442 | {
|
443 | type: "work",
|
444 | requestId: 1,
|
445 | data: new Uint8ClampedArray(3 * 2 * 4),
|
446 | highQualitySingleFrameMode: false
|
447 | },
|
448 | [new Uint8ClampedArray(3 * 2 * 4).buffer]
|
449 | ]);
|
450 | s.applyImageSettings({
|
451 | width: 5,
|
452 | height: 4,
|
453 | format: ImageSettings.Format.RGBA_8U
|
454 | });
|
455 | resetStubs();
|
456 | canvas.width = 5;
|
457 | canvas.height = 4;
|
458 | imageData = await getImageFromCanvas(canvas);
|
459 |
|
460 | s.processImage(imageData);
|
461 | t.is(postMessageStub.callCount, 1);
|
462 | t.deepEqual(postMessageStub.getCall(0).args, [
|
463 | {
|
464 | type: "work",
|
465 | requestId: 2,
|
466 | data: new Uint8ClampedArray(5 * 4 * 4),
|
467 | highQualitySingleFrameMode: false
|
468 | },
|
469 | [new Uint8ClampedArray(5 * 4 * 4).buffer]
|
470 | ]);
|
471 | });
|
472 |
|
473 |
|
474 | test.serial("processImage scan results", async t => {
|
475 | await prepareBrowserAndLibrary();
|
476 | resetStubs();
|
477 | const s: Scanner = new Scanner();
|
478 | const imageSettings: ImageSettings = {
|
479 | width: 3,
|
480 | height: 2,
|
481 | format: ImageSettings.Format.RGBA_8U
|
482 | };
|
483 | s.applyImageSettings(imageSettings);
|
484 | const imageData1: Uint8ClampedArray = Uint8ClampedArray.from({ length: 24 }, () => {
|
485 | return Math.floor(Math.random() * 255);
|
486 | });
|
487 | const processImage1: Promise<ScanResult> = s.processImage(imageData1);
|
488 | t.true(s.isBusyProcessing());
|
489 | const imageData2: Uint8ClampedArray = Uint8ClampedArray.from({ length: 24 }, () => {
|
490 | return Math.floor(Math.random() * 255);
|
491 | });
|
492 | const processImage2: Promise<ScanResult> = s.processImage(imageData2);
|
493 | const imageData3: Uint8ClampedArray = Uint8ClampedArray.from({ length: 24 }, () => {
|
494 | return Math.floor(Math.random() * 255);
|
495 | });
|
496 | const processImage3: Promise<ScanResult> = s.processImage(imageData3);
|
497 | t.is((<any>s).workerScanRequestId, 3);
|
498 | t.is((<any>s).workerScanQueueLength, 3);
|
499 | (<any>s).engineWorkerOnMessage({
|
500 | data: [
|
501 | "work-error",
|
502 | {
|
503 | requestId: 2,
|
504 | error: {
|
505 | errorCode: 123,
|
506 | errorMessage: "example_error"
|
507 | }
|
508 | }
|
509 | ]
|
510 | });
|
511 | const error: Error = await t.throwsAsync(processImage2);
|
512 | t.deepEqual(error.message, "example_error (123)");
|
513 | t.is((<any>s).workerScanQueueLength, 2);
|
514 | (<any>s).engineWorkerOnMessage({
|
515 | data: [
|
516 | "work-result",
|
517 | {
|
518 | requestId: 1,
|
519 | result: {
|
520 | scanResult: [],
|
521 | matrixScanResult: {
|
522 | barcodesAppeared: [],
|
523 | barcodesUpdated: [],
|
524 | barcodesLost: [],
|
525 | barcodesPredicted: []
|
526 | }
|
527 | }
|
528 | }
|
529 | ]
|
530 | });
|
531 | let scanResult: ScanResult = await processImage1;
|
532 | t.deepEqual(scanResult, new ScanResult([], imageData1, imageSettings));
|
533 | t.is((<any>s).workerScanQueueLength, 1);
|
534 | (<any>s).engineWorkerOnMessage({
|
535 | data: [
|
536 | "work-result",
|
537 | {
|
538 | requestId: 3,
|
539 | result: {
|
540 | scanResult: [
|
541 | {
|
542 | symbology: Barcode.Symbology.QR,
|
543 | rawData: [97, 98, 99, 100],
|
544 | location: [[1, 2], [3, 4], [5, 6], [7, 8]],
|
545 | compositeFlag: Barcode.CompositeFlag.NONE,
|
546 | isGs1DataCarrier: false,
|
547 | encodingArray: [],
|
548 | isRecognized: true
|
549 | }
|
550 | ],
|
551 | matrixScanResult: {
|
552 | barcodesAppeared: [],
|
553 | barcodesUpdated: [],
|
554 | barcodesLost: [],
|
555 | barcodesPredicted: []
|
556 | }
|
557 | }
|
558 | }
|
559 | ]
|
560 | });
|
561 | scanResult = await processImage3;
|
562 | t.deepEqual(
|
563 | scanResult,
|
564 | new ScanResult(
|
565 | [
|
566 | {
|
567 | compositeFlag: Barcode.CompositeFlag.NONE,
|
568 | data: "abcd",
|
569 | encodingArray: [],
|
570 | isGs1DataCarrier: false,
|
571 | location: {
|
572 | bottomLeft: {
|
573 | x: 7,
|
574 | y: 8
|
575 | },
|
576 | bottomRight: {
|
577 | x: 5,
|
578 | y: 6
|
579 | },
|
580 | topLeft: {
|
581 | x: 1,
|
582 | y: 2
|
583 | },
|
584 | topRight: {
|
585 | x: 3,
|
586 | y: 4
|
587 | }
|
588 | },
|
589 | rawData: new Uint8Array([97, 98, 99, 100]),
|
590 | symbology: Barcode.Symbology.QR
|
591 | }
|
592 | ],
|
593 | imageData3,
|
594 | imageSettings
|
595 | )
|
596 | );
|
597 | t.is((<any>s).workerScanQueueLength, 0);
|
598 | (<any>s).engineWorkerOnMessage({
|
599 | data: []
|
600 | });
|
601 | });
|
602 |
|
603 | test.serial("getImageSettings", async t => {
|
604 | await prepareBrowserAndLibrary();
|
605 | resetStubs();
|
606 | const ss: ImageSettings = {
|
607 | width: 640,
|
608 | height: 480,
|
609 | format: ImageSettings.Format.RGBA_8U
|
610 | };
|
611 | const s: Scanner = new Scanner();
|
612 | t.is(s.getImageSettings(), undefined);
|
613 | s.applyImageSettings(ss);
|
614 | t.deepEqual(s.getImageSettings(), ss);
|
615 | });
|
616 |
|
617 | test.serial("getScanSettings", async t => {
|
618 | await prepareBrowserAndLibrary();
|
619 | resetStubs();
|
620 | const ss: ScanSettings = new ScanSettings({
|
621 | enabledSymbologies: Barcode.Symbology.QR,
|
622 | codeDuplicateFilter: 10,
|
623 | maxNumberOfCodesPerFrame: 10,
|
624 | searchArea: { x: 0.5, y: 0.5, width: 0.5, height: 0.1 }
|
625 | });
|
626 | const s: Scanner = new Scanner();
|
627 | t.deepEqual(s.getScanSettings(), new ScanSettings());
|
628 | s.applyScanSettings(ss);
|
629 | t.deepEqual(s.getScanSettings(), ss);
|
630 | });
|
631 |
|
632 |
|
633 | test.serial("createParserForFormat & parseString", async t => {
|
634 | const parseStringType: string = "parse-string";
|
635 | await prepareBrowserAndLibrary();
|
636 | const s: Scanner = new Scanner();
|
637 | resetStubs();
|
638 | const parser: Parser = s.createParserForFormat(Parser.DataFormat.DLID);
|
639 | t.not(parser, null);
|
640 | t.is((<any>s).workerParseRequestId, 0);
|
641 | t.false(s.isBusyProcessing());
|
642 | t.false(postMessageStub.called);
|
643 | const parseString1: Promise<ParserResult> = s.parseString(Parser.DataFormat.DLID, "abcd");
|
644 | t.is((<any>s).workerParseRequestId, 1);
|
645 | t.false(s.isBusyProcessing());
|
646 | t.is(postMessageStub.callCount, 1);
|
647 | t.deepEqual(postMessageStub.getCall(0).args, [
|
648 | {
|
649 | type: parseStringType,
|
650 | requestId: 1,
|
651 | dataFormat: Parser.DataFormat.DLID,
|
652 | dataString: "abcd",
|
653 | options: "{}"
|
654 | }
|
655 | ]);
|
656 | resetStubs();
|
657 | const parseString2: Promise<ParserResult> = s.parseString(Parser.DataFormat.GS1_AI, "efgh");
|
658 | t.is((<any>s).workerParseRequestId, 2);
|
659 | t.false(s.isBusyProcessing());
|
660 | t.is(postMessageStub.callCount, 1);
|
661 | t.deepEqual(postMessageStub.getCall(0).args, [
|
662 | {
|
663 | type: parseStringType,
|
664 | requestId: 2,
|
665 | dataFormat: Parser.DataFormat.GS1_AI,
|
666 | dataString: "efgh",
|
667 | options: "{}"
|
668 | }
|
669 | ]);
|
670 | resetStubs();
|
671 | const parseString3: Promise<ParserResult> = s.parseString(Parser.DataFormat.HIBC, "ijkl", {
|
672 | exampleOption: true
|
673 | });
|
674 | t.is((<any>s).workerParseRequestId, 3);
|
675 | t.false(s.isBusyProcessing());
|
676 | t.is(postMessageStub.callCount, 1);
|
677 | t.deepEqual(postMessageStub.getCall(0).args, [
|
678 | {
|
679 | type: parseStringType,
|
680 | requestId: 3,
|
681 | dataFormat: Parser.DataFormat.HIBC,
|
682 | dataString: "ijkl",
|
683 | options: '{"exampleOption":true}'
|
684 | }
|
685 | ]);
|
686 | resetStubs();
|
687 | (<any>s).engineWorkerOnMessage({
|
688 | data: [
|
689 | "parse-string-error",
|
690 | {
|
691 | requestId: 2,
|
692 | error: {
|
693 | errorCode: 123,
|
694 | errorMessage: "example_error"
|
695 | }
|
696 | }
|
697 | ]
|
698 | });
|
699 | const error: Error = await t.throwsAsync(parseString2);
|
700 | t.deepEqual(error.message, "example_error (123)");
|
701 | const resultData: ParserField[] = [
|
702 | {
|
703 | name: "field1",
|
704 | parsed: 1,
|
705 | rawString: "123"
|
706 | },
|
707 | {
|
708 | name: "field2",
|
709 | parsed: "abcd",
|
710 | rawString: "efgh"
|
711 | },
|
712 | {
|
713 | name: "field3",
|
714 | parsed: {
|
715 | subField1: 1,
|
716 | subField2: 2
|
717 | },
|
718 | rawString: "sf1sf2"
|
719 | }
|
720 | ];
|
721 | (<any>s).engineWorkerOnMessage({
|
722 | data: [
|
723 | "parse-string-result",
|
724 | {
|
725 | requestId: 1,
|
726 | result: JSON.stringify(resultData)
|
727 | }
|
728 | ]
|
729 | });
|
730 | let parserResult: ParserResult = await parseString1;
|
731 | const fieldsByName: { [fieldName: string]: ParserField } = {};
|
732 | resultData.forEach(parserField => {
|
733 | fieldsByName[parserField.name] = parserField;
|
734 | });
|
735 | t.deepEqual(parserResult, {
|
736 | fields: resultData,
|
737 | fieldsByName,
|
738 | jsonString: JSON.stringify(resultData)
|
739 | });
|
740 | (<any>s).engineWorkerOnMessage({
|
741 | data: [
|
742 | "parse-string-result",
|
743 | {
|
744 | requestId: 3,
|
745 | result: JSON.stringify([])
|
746 | }
|
747 | ]
|
748 | });
|
749 | parserResult = await parseString3;
|
750 | t.deepEqual(parserResult, {
|
751 | fields: [],
|
752 | fieldsByName: {},
|
753 | jsonString: JSON.stringify([])
|
754 | });
|
755 | });
|
756 |
|
757 | test.serial("onLicenseFeaturesReady", async t => {
|
758 | const licenseFeaturesType: string = "license-features";
|
759 | await prepareBrowserAndLibrary();
|
760 | resetStubs();
|
761 | const s: Scanner = new Scanner();
|
762 | const callbackSpy1: sinon.SinonSpy = sinon.spy();
|
763 | const callbackSpy2: sinon.SinonSpy = sinon.spy();
|
764 | const callbackSpy3: sinon.SinonSpy = sinon.spy();
|
765 | s.onLicenseFeaturesReady(callbackSpy1);
|
766 | s.onLicenseFeaturesReady(callbackSpy2);
|
767 | t.false(callbackSpy1.called);
|
768 | t.false(callbackSpy2.called);
|
769 | (<any>s).engineWorkerOnMessage({
|
770 | data: [licenseFeaturesType]
|
771 | });
|
772 | t.false(callbackSpy1.called);
|
773 | t.false(callbackSpy2.called);
|
774 | (<any>s).engineWorkerOnMessage({
|
775 | data: [
|
776 | licenseFeaturesType,
|
777 | {
|
778 | hiddenScanditLogoAllowed: true
|
779 | }
|
780 | ]
|
781 | });
|
782 | t.true(callbackSpy1.called);
|
783 | t.true(callbackSpy2.called);
|
784 | t.true(callbackSpy2.calledAfter(callbackSpy1));
|
785 | t.deepEqual(callbackSpy1.getCall(0).args, [
|
786 | {
|
787 | hiddenScanditLogoAllowed: true
|
788 | }
|
789 | ]);
|
790 | t.deepEqual(callbackSpy1.getCall(0).args, callbackSpy2.getCall(0).args);
|
791 | s.onLicenseFeaturesReady(callbackSpy3);
|
792 | t.true(callbackSpy3.called);
|
793 | t.deepEqual(callbackSpy1.getCall(0).args, callbackSpy3.getCall(0).args);
|
794 | callbackSpy1.resetHistory();
|
795 | callbackSpy2.resetHistory();
|
796 | callbackSpy3.resetHistory();
|
797 | (<any>s).engineWorkerOnMessage({
|
798 | data: [
|
799 | licenseFeaturesType,
|
800 | {
|
801 | hiddenScanditLogoAllowed: true
|
802 | }
|
803 | ]
|
804 | });
|
805 | t.false(callbackSpy1.called);
|
806 | t.false(callbackSpy2.called);
|
807 | t.false(callbackSpy3.called);
|
808 | });
|