UNPKG

22 kBPlain TextView Raw
1/* tslint:disable:no-implicit-dependencies no-any */
2/* tslint:disable:insecure-random */
3/**
4 * Scanner tests
5 */
6import test from "ava";
7import * as sinon from "sinon";
8
9import {
10 Barcode,
11 BrowserHelper,
12 configure,
13 ImageSettings,
14 Parser,
15 ParserField,
16 ParserResult,
17 Scanner,
18 ScanResult,
19 ScanSettings
20} from "..";
21
22declare const global: any;
23
24const postMessageStub: sinon.SinonStub = sinon.stub();
25const terminateStub: sinon.SinonStub = sinon.stub();
26
27const stubs: sinon.SinonStub[] = [postMessageStub, terminateStub];
28
29global.Worker = sinon.stub().returns({
30 postMessage: postMessageStub,
31 terminate: terminateStub
32});
33URL.createObjectURL = sinon.stub();
34
35function resetStubs(): void {
36 stubs.forEach(mock => {
37 mock.resetHistory();
38 });
39}
40
41function checkBrowserCompatibility(): any {
42 return {
43 fullSupport: true,
44 scannerSupport: true,
45 missingFeatures: []
46 };
47}
48
49async function prepareBrowserAndLibrary(): Promise<void> {
50 BrowserHelper.checkBrowserCompatibility = checkBrowserCompatibility;
51 await configure("#".repeat(64));
52}
53
54test.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
131test.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
144test.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
171test.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
197test.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
211test.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// Deprecated method
222test.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
232test.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// tslint:disable-next-line:max-func-body-length
267test.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 // tslint:disable-next-line: no-floating-promises
294 s.processImage(imageData); // 3 * 2 * 4
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 // tslint:disable-next-line: no-floating-promises
316 s.processImage(imageData); // 3 * 2 * 3
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 // tslint:disable-next-line: no-floating-promises
337 s.processImage(imageData); // 3 * 2 * 1
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 // Fake format
352 });
353 resetStubs();
354 imageData = Uint8ClampedArray.from({ length: 6 }, () => {
355 return Math.floor(Math.random() * 255);
356 });
357 // tslint:disable-next-line: no-floating-promises
358 s.processImage(imageData); // 3 * 2 * 1
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
373test.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 // tslint:disable-next-line: no-floating-promises
400 s.processImage(imageData, true); // 3 * 2 * 4
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
414test.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 // tslint:disable-next-line: no-floating-promises
438 s.processImage(imageData); // 3 * 2 * 4
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 // tslint:disable-next-line: no-floating-promises
460 s.processImage(imageData); // 5 * 4 * 4
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// tslint:disable-next-line:max-func-body-length
474test.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); // 3 * 2 * 4
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); // 3 * 2 * 4
493 const imageData3: Uint8ClampedArray = Uint8ClampedArray.from({ length: 24 }, () => {
494 return Math.floor(Math.random() * 255);
495 });
496 const processImage3: Promise<ScanResult> = s.processImage(imageData3); // 3 * 2 * 4
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
603test.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
617test.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// tslint:disable-next-line:max-func-body-length
633test.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
757test.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});