scandit-sdk
Version:
Scandit Barcode Scanner SDK for the Web
670 lines • 29.7 kB
JavaScript
"use strict";
var _this = this;
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
/* tslint:disable:no-implicit-dependencies no-any */
/**
* BarcodePicker tests
*/
var ava_1 = tslib_1.__importDefault(require("ava"));
var crypto_1 = tslib_1.__importDefault(require("crypto"));
var fs_1 = tslib_1.__importDefault(require("fs"));
var node_fetch_1 = require("node-fetch");
var sinon = tslib_1.__importStar(require("sinon"));
var imageSettings_1 = require("../imageSettings");
var parser_1 = require("../parser");
var scanSettings_1 = require("../scanSettings");
var engineWorker_1 = require("./engineWorker");
function wait(ms) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
return tslib_1.__generator(this, function (_a) {
return [2 /*return*/, new Promise(function (resolve) {
setTimeout(resolve, ms);
})];
});
});
}
function setupSpyModuleFunctions(m) {
m.HEAPU8 = new Uint8Array(1);
m.HEAPU8.set = function (a, p) {
p.a = a;
};
m.lengthBytesUTF8 = sinon.spy(function (_) {
return 0;
});
m.UTF8ToString = sinon.spy(function (p) {
return p.s;
});
m.stringToUTF8 = sinon.spy(function (s, p) {
p.s = s;
});
m._malloc = sinon.spy(function (_) {
return {};
});
m._free = sinon.spy();
m._create_context = sinon.spy();
m._scanner_settings_new_from_json = sinon.spy(function (p) {
// Mock invalid config
if (p.s === JSON.stringify({})) {
return {
s: ""
};
}
return {
s: JSON.stringify({})
};
});
m._scanner_image_settings_new = sinon.spy();
m._scanner_session_clear = sinon.spy();
m._can_hide_logo = sinon.spy(function () {
return 1;
});
m._scanner_scan = sinon.spy(function (imageData) {
// Mock error
if (imageData.a[0] === 255) {
return {
s: JSON.stringify({
error: {
errorCode: 1,
errorMessage: "Error."
}
})
};
}
return {
s: JSON.stringify({ scanResult: [] })
};
});
m._parser_parse_string = sinon.spy(function (parserType) {
// Mock error
if (parserType >= 255) {
return {
s: JSON.stringify({
error: {
errorCode: parserType,
errorMessage: "Error. This is a domain name."
}
})
};
}
return {
s: JSON.stringify({ result: { x: "y" } })
};
});
m.callMain = sinon.spy();
}
var moduleInstance;
Object.defineProperty(global, "self", {
writable: true
});
Object.defineProperty(global, "postMessage", {
writable: true
});
Object.defineProperty(global, "window", {
writable: true
});
Object.defineProperty(global, "document", {
writable: true
});
global.self = global;
global.Module = {};
global.crypto = {
subtle: {
digest: function (_, data) {
return Promise.resolve(crypto_1.default
.createHash("sha256")
.update(new DataView(data))
.digest());
}
}
};
global.fetch = function (filePath) {
return new Promise(function (resolve, reject) {
filePath = filePath.split("?")[0];
// tslint:disable-next-line:non-literal-fs-path
if (!fs_1.default.existsSync(filePath)) {
reject(new Error("File not found: " + filePath));
}
try {
// tslint:disable-next-line:non-literal-fs-path
resolve(new node_fetch_1.Response(fs_1.default.readFileSync(filePath)));
}
catch (error) {
reject(error);
}
});
};
global.importScripts = function (filePath) {
filePath = filePath.split("?")[0];
// tslint:disable-next-line:non-literal-fs-path
if (!fs_1.default.existsSync(filePath)) {
throw new Error("File not found: " + filePath);
}
moduleInstance = global.Module;
setupSpyModuleFunctions(moduleInstance);
return new Promise(function (resolve) {
// Retrieve wasmJSVersion variable
// tslint:disable-next-line:non-literal-fs-path
var readStream = fs_1.default.createReadStream(filePath, { encoding: "utf8" });
readStream.on("readable", function () {
var dataString = "";
var character = readStream.read(1);
while (character !== ";") {
dataString += character;
character = readStream.read(1);
}
readStream.destroy();
var regexMatch = dataString.match(/'(.+)'/);
if (regexMatch != null) {
self.wasmJSVersion = regexMatch[1];
}
moduleInstance.instantiateWasm({ env: {} }, function () {
moduleInstance.preRun();
moduleInstance.onRuntimeInitialized();
resolve();
});
});
});
};
global.FS = {
mkdir: sinon.spy(),
mount: sinon.spy(),
syncfs: function (_, callback) {
callback(undefined);
}
};
global.IDBFS = null;
global.WebAssembly.instantiate = global.WebAssembly.instantiateStreaming = function () {
return Promise.resolve({
module: "module",
instance: "instance"
});
};
global.OffscreenCanvas = function () {
return;
};
var postMessageSpy = sinon.spy();
global.postMessage = postMessageSpy;
ava_1.default.serial("engine load", function (t) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
var engineInstance, importScriptsSpy, consoleErrorSpy, originalSetTimeout, setTimeoutStub, fetchStub, instantiateStreamingStub, instantiateStub, instantiateStreamingFunction;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0:
engineInstance = engineWorker_1.engine();
importScriptsSpy = sinon.spy(global, "importScripts");
consoleErrorSpy = sinon.spy(console, "error");
originalSetTimeout = global.setTimeout;
setTimeoutStub = sinon.stub(global, "setTimeout").callsFake(function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
return originalSetTimeout(args[0], args[1] / 100);
});
// importScripts fails (js)
return [4 /*yield*/, engineInstance.loadLibrary("fakeDeviceId", "./wrong-path/", "fakePath", "fakeDevice", "fakeBrowserName")];
case 1:
// importScripts fails (js)
_a.sent();
t.is(importScriptsSpy.callCount, 5);
t.is(consoleErrorSpy.callCount, 2);
fetchStub = sinon.stub(global, "fetch").rejects();
importScriptsSpy.resetHistory();
consoleErrorSpy.resetHistory();
engineInstance = engineWorker_1.engine();
// tslint:disable-next-line: no-floating-promises
engineInstance.loadLibrary("fakeDeviceId", "./build/", "fakePath", "fakeDevice", "fakeBrowserName");
return [4 /*yield*/, wait(8500)];
case 2:
_a.sent();
t.is(importScriptsSpy.callCount, 1);
t.is(consoleErrorSpy.callCount, 2);
t.is(fetchStub.callCount, 5);
t.false(moduleInstance.callMain.called);
fetchStub.restore();
importScriptsSpy.restore();
setTimeoutStub.restore();
// instantiateStreaming fails, instantiate fails
consoleErrorSpy.resetHistory();
instantiateStreamingStub = sinon.stub(global.WebAssembly, "instantiateStreaming").rejects();
instantiateStub = sinon.stub(global.WebAssembly, "instantiate").rejects();
engineInstance = engineWorker_1.engine();
// tslint:disable-next-line: no-floating-promises
engineInstance.loadLibrary("fakeDeviceId", "./build/", "fakePath", "fakeDevice", "fakeBrowserName");
return [4 /*yield*/, wait(2000)];
case 3:
_a.sent();
t.is(consoleErrorSpy.callCount, 2);
t.true(instantiateStreamingStub.called);
t.true(instantiateStub.called);
t.false(moduleInstance.callMain.called);
// instantiateStreaming fails, instantiate succeeds
consoleErrorSpy.resetHistory();
instantiateStub.restore();
postMessageSpy.resetHistory();
engineInstance = engineWorker_1.engine();
return [4 /*yield*/, engineInstance.loadLibrary("fakeDeviceId", "./build/", "fakePath", "fakeDevice", "fakeBrowserName")];
case 4:
_a.sent();
t.false(consoleErrorSpy.called);
t.true(moduleInstance.callMain.called);
t.true(postMessageSpy.calledOnceWithExactly(["status", "ready"]));
instantiateStreamingStub.restore();
// instantiateStreaming doesn't exist, instantiate succeeds
consoleErrorSpy.resetHistory();
instantiateStreamingFunction = global.WebAssembly.instantiateStreaming;
global.WebAssembly.instantiateStreaming = null;
postMessageSpy.resetHistory();
engineInstance = engineWorker_1.engine();
return [4 /*yield*/, engineInstance.loadLibrary("fakeDeviceId", "./build/", "fakePath", "fakeDevice", "fakeBrowserName")];
case 5:
_a.sent();
t.false(consoleErrorSpy.called);
t.true(moduleInstance.callMain.called);
t.true(postMessageSpy.calledOnceWithExactly(["status", "ready"]));
global.WebAssembly.instantiateStreaming = instantiateStreamingFunction;
// instantiateStreaming succeeds
consoleErrorSpy.resetHistory();
postMessageSpy.resetHistory();
engineInstance = engineWorker_1.engine();
return [4 /*yield*/, engineInstance.loadLibrary("fakeDeviceId", "./build/", "fakePath", "fakeDevice", "fakeBrowserName")];
case 6:
_a.sent();
t.false(consoleErrorSpy.called);
t.true(moduleInstance.callMain.called);
t.true(postMessageSpy.calledOnceWithExactly(["status", "ready"]));
engineInstance.workOnScanQueue(); // Try to work on queue with non-ready engine
t.is(postMessageSpy.callCount, 1);
engineInstance.createContext("");
t.is(postMessageSpy.callCount, 2);
engineInstance.setSettings(JSON.stringify({})); // Try to set invalid settings
engineInstance.workOnScanQueue(); // Try to work on queue with non-ready engine
t.is(postMessageSpy.callCount, 2);
engineInstance.clearSession(); // Try to clear non-existent session
engineInstance.setImageSettings({
width: 1,
height: 1,
format: imageSettings_1.ImageSettings.Format.RGBA_8U
});
engineInstance.setImageSettings({
width: 1,
height: 1,
format: imageSettings_1.ImageSettings.Format.RGBA_8U
}); // Set image settings again
engineInstance.addScanWorkUnit({
requestId: 0,
data: new Uint8ClampedArray([0, 0, 0, 0]),
highQualitySingleFrameMode: true
}); // Add work unit to allow settings to be set
engineInstance.setSettings(new scanSettings_1.ScanSettings().toJSONString());
engineInstance.clearSession();
consoleErrorSpy.restore();
return [2 /*return*/];
}
});
}); });
ava_1.default.serial("engine load - CDN", function (t) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
var originalSetTimeout, setTimeoutStub, engineInstance, importScriptsSpy;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0:
originalSetTimeout = global.setTimeout;
setTimeoutStub = sinon.stub(global, "setTimeout").callsFake(function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
return originalSetTimeout(args[0], args[1] / 100);
});
engineInstance = engineWorker_1.engine();
importScriptsSpy = sinon.spy(global, "importScripts");
return [4 /*yield*/, engineInstance.loadLibrary("fakeDeviceId", "https://cdn.jsdelivr.net/npm/scandit-sdk", "fakePath", "fakeDevice", "fakeBrowserName")];
case 1:
_a.sent();
t.is(importScriptsSpy.callCount, 5);
t.regex(importScriptsSpy.lastCall.args[0], /https:\/\/cdn.jsdelivr.net\/npm\/scandit-sdk@([1-9]+\.[0-9]+\.[0-9]+|%VER%)\/build\/scandit-engine-sdk.min.js/);
engineInstance = engineWorker_1.engine();
return [4 /*yield*/, engineInstance.loadLibrary("fakeDeviceId",
// tslint:disable-next-line:no-http-string
"http://cdn.jsdelivr.net/npm/scandit-sdk@0.0.1", "fakePath", "fakeDevice", "fakeBrowserName")];
case 2:
_a.sent();
t.is(importScriptsSpy.callCount, 10);
t.regex(importScriptsSpy.lastCall.args[0], /https:\/\/cdn.jsdelivr.net\/npm\/scandit-sdk@([1-9]+\.[0-9]+\.[0-9]+|%VER%)\/build\/scandit-engine-sdk.min.js/);
engineInstance = engineWorker_1.engine();
return [4 /*yield*/, engineInstance.loadLibrary("fakeDeviceId", "https://unpkg.com/scandit-sdk@4.0.0", "fakePath", "fakeDevice", "fakeBrowserName")];
case 3:
_a.sent();
t.is(importScriptsSpy.callCount, 15);
t.regex(importScriptsSpy.lastCall.args[0], /https:\/\/unpkg.com\/scandit-sdk@([1-9]+\.[0-9]+\.[0-9]+|%VER%)\/build\/scandit-engine-sdk.min.js/);
engineInstance = engineWorker_1.engine();
return [4 /*yield*/, engineInstance.loadLibrary("fakeDeviceId",
// tslint:disable-next-line:no-http-string
"http://unpkg.com/scandit-sdk@0.0.1", "fakePath", "fakeDevice", "fakeBrowserName")];
case 4:
_a.sent();
t.is(importScriptsSpy.callCount, 20);
t.regex(importScriptsSpy.lastCall.args[0], /https:\/\/unpkg.com\/scandit-sdk@([1-9]+\.[0-9]+\.[0-9]+|%VER%)\/build\/scandit-engine-sdk.min.js/);
engineInstance = engineWorker_1.engine();
return [4 /*yield*/, engineInstance.loadLibrary("fakeDeviceId", "./wrong-path/", "fakePath", "fakeDevice", "fakeBrowserName")];
case 5:
_a.sent();
t.is(importScriptsSpy.callCount, 25);
t.regex(importScriptsSpy.lastCall.args[0], /^\.\/wrong-path\//);
setTimeoutStub.restore();
importScriptsSpy.restore();
return [2 /*return*/];
}
});
}); });
ava_1.default.serial("engine license features", function (t) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
var engineInstance;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0:
postMessageSpy.resetHistory();
engineInstance = engineWorker_1.engine();
return [4 /*yield*/, engineInstance.loadLibrary("fakeDeviceId", "./build/", "fakePath", "fakeDevice", "fakeBrowserName")];
case 1:
_a.sent();
t.true(moduleInstance.callMain.called);
t.true(postMessageSpy.calledOnceWithExactly(["status", "ready"]));
engineInstance.createContext("");
t.is(postMessageSpy.callCount, 2);
t.deepEqual(postMessageSpy.getCall(1).args[0], [
"license-features",
{
hiddenScanditLogoAllowed: true
}
]);
return [2 /*return*/];
}
});
}); });
ava_1.default.serial("engine scan", function (t) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
function getWorkResult(requestId) {
return [
"work-result",
{
result: {
scanResult: []
},
requestId: requestId
}
];
}
var engineInstance, engineInstance2;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0:
postMessageSpy.resetHistory();
engineInstance = engineWorker_1.engine();
return [4 /*yield*/, engineInstance.loadLibrary("fakeDeviceId", "./build/", "fakePath", "fakeDevice", "fakeBrowserName")];
case 1:
_a.sent();
t.true(moduleInstance.callMain.called);
t.true(postMessageSpy.calledOnceWithExactly(["status", "ready"]));
engineInstance.createContext("");
t.is(postMessageSpy.callCount, 2);
engineInstance.addScanWorkUnit({
requestId: 0,
data: new Uint8ClampedArray([0, 0, 0, 0]),
highQualitySingleFrameMode: true
}); // Try to add work unit with non-ready engine
t.is(postMessageSpy.callCount, 2);
engineInstance.setSettings(new scanSettings_1.ScanSettings().toJSONString());
engineInstance.setImageSettings({
width: 1,
height: 1,
format: imageSettings_1.ImageSettings.Format.RGBA_8U
});
engineInstance.addScanWorkUnit({
requestId: 1,
data: new Uint8ClampedArray([0, 0, 0, 0]),
highQualitySingleFrameMode: true
});
t.is(postMessageSpy.callCount, 4);
t.deepEqual(postMessageSpy.getCall(2).args, [getWorkResult(0), undefined]);
t.deepEqual(postMessageSpy.getCall(3).args, [getWorkResult(1), undefined]);
engineInstance.setImageSettings({
width: 1,
height: 1,
format: imageSettings_1.ImageSettings.Format.RGB_8U
}); // Set image settings again
engineInstance.addScanWorkUnit({
requestId: 2,
data: new Uint8ClampedArray([0, 0, 0]),
highQualitySingleFrameMode: false
});
t.is(postMessageSpy.callCount, 5);
t.deepEqual(postMessageSpy.getCall(4).args, [getWorkResult(2), undefined]);
engineInstance.setImageSettings({
width: 1,
height: 1,
format: imageSettings_1.ImageSettings.Format.GRAY_8U
}); // Set image settings again
engineInstance.addScanWorkUnit({
requestId: 3,
data: new Uint8ClampedArray([0]),
highQualitySingleFrameMode: false
});
t.is(postMessageSpy.callCount, 6);
t.deepEqual(postMessageSpy.getCall(5).args, [getWorkResult(3), undefined]);
postMessageSpy.resetHistory();
engineInstance2 = engineWorker_1.engine();
return [4 /*yield*/, engineInstance2.loadLibrary("fakeDeviceId", "./build/", "fakePath", "fakeDevice", "Firefox")];
case 2:
_a.sent();
t.true(moduleInstance.callMain.called);
t.true(postMessageSpy.calledOnceWithExactly(["status", "ready"]));
engineInstance2.createContext("");
t.is(postMessageSpy.callCount, 2);
engineInstance2.setSettings(new scanSettings_1.ScanSettings().toJSONString());
engineInstance2.setImageSettings({
width: 1,
height: 1,
format: imageSettings_1.ImageSettings.Format.GRAY_8U
});
engineInstance2.addScanWorkUnit({
requestId: 0,
data: new Uint8ClampedArray([0]),
highQualitySingleFrameMode: false
});
t.is(postMessageSpy.callCount, 3);
t.deepEqual(postMessageSpy.getCall(2).args[0], getWorkResult(0));
t.truthy(postMessageSpy.getCall(2).args[0]);
return [2 /*return*/];
}
});
}); });
ava_1.default.serial("engine scan error", function (t) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
var engineInstance, engineInstance2;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0:
postMessageSpy.resetHistory();
engineInstance = engineWorker_1.engine();
return [4 /*yield*/, engineInstance.loadLibrary("fakeDeviceId", "./build/", "fakePath", "fakeDevice", "fakeBrowserName")];
case 1:
_a.sent();
engineInstance.createContext("");
engineInstance.setSettings(new scanSettings_1.ScanSettings().toJSONString());
engineInstance.setImageSettings({
width: 1,
height: 1,
format: imageSettings_1.ImageSettings.Format.RGB_8U
});
engineInstance.addScanWorkUnit({
requestId: 0,
data: new Uint8ClampedArray([255, 255, 255]),
highQualitySingleFrameMode: false
});
t.is(postMessageSpy.callCount, 3);
t.deepEqual(postMessageSpy.getCall(2).args, [
[
"work-error",
{
error: {
errorCode: 1,
errorMessage: "Error."
},
requestId: 0
}
],
undefined
]);
postMessageSpy.resetHistory();
engineInstance2 = engineWorker_1.engine();
return [4 /*yield*/, engineInstance2.loadLibrary("fakeDeviceId", "./build/", "fakePath", "fakeDevice", "Firefox")];
case 2:
_a.sent();
engineInstance2.createContext("");
engineInstance2.setSettings(new scanSettings_1.ScanSettings().toJSONString());
engineInstance2.setImageSettings({
width: 1,
height: 1,
format: imageSettings_1.ImageSettings.Format.RGB_8U
});
engineInstance2.addScanWorkUnit({
requestId: 0,
data: new Uint8ClampedArray([255, 255, 255]),
highQualitySingleFrameMode: false
});
t.is(postMessageSpy.callCount, 3);
t.deepEqual(postMessageSpy.getCall(2).args[0], [
"work-error",
{
error: {
errorCode: 1,
errorMessage: "Error."
},
requestId: 0
}
]);
t.truthy(postMessageSpy.getCall(2).args[1]);
return [2 /*return*/];
}
});
}); });
ava_1.default.serial("engine parse", function (t) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
var engineInstance;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0:
postMessageSpy.resetHistory();
engineInstance = engineWorker_1.engine();
return [4 /*yield*/, engineInstance.loadLibrary("fakeDeviceId", "./build/", "fakePath", "fakeDevice", "fakeBrowserName")];
case 1:
_a.sent();
t.true(moduleInstance.callMain.called);
t.true(postMessageSpy.calledOnceWithExactly(["status", "ready"]));
engineInstance.addParseWorkUnit({
requestId: 0,
dataFormat: parser_1.Parser.DataFormat.DLID,
dataString: "test",
options: JSON.stringify({})
}); // Try to add work unit with non-ready engine
t.is(postMessageSpy.callCount, 1);
engineInstance.createContext("");
t.is(postMessageSpy.callCount, 2);
engineInstance.addParseWorkUnit({
requestId: 1,
dataFormat: parser_1.Parser.DataFormat.GS1_AI,
dataString: "test",
options: JSON.stringify({})
});
t.is(postMessageSpy.callCount, 4);
t.deepEqual(postMessageSpy.getCall(2).args[0], [
"parse-string-result",
{
result: {
x: "y"
},
requestId: 0
}
]);
t.deepEqual(postMessageSpy.getCall(3).args[0], [
"parse-string-result",
{
result: {
x: "y"
},
requestId: 1
}
]);
engineInstance.addParseWorkUnit({
requestId: 2,
dataFormat: parser_1.Parser.DataFormat.HIBC,
dataString: "test",
options: JSON.stringify({})
});
engineInstance.addParseWorkUnit({
requestId: 3,
dataFormat: parser_1.Parser.DataFormat.MRTD,
dataString: "test",
options: JSON.stringify({})
});
engineInstance.addParseWorkUnit({
requestId: 4,
dataFormat: parser_1.Parser.DataFormat.SWISSQR,
dataString: "test",
options: JSON.stringify({})
});
t.is(postMessageSpy.callCount, 7);
return [2 /*return*/];
}
});
}); });
ava_1.default.serial("engine parse error", function (t) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
var engineInstance;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0:
postMessageSpy.resetHistory();
engineInstance = engineWorker_1.engine();
return [4 /*yield*/, engineInstance.loadLibrary("fakeDeviceId", "./build/", "fakePath", "fakeDevice", "fakeBrowserName")];
case 1:
_a.sent();
t.true(moduleInstance.callMain.called);
t.true(postMessageSpy.calledOnceWithExactly(["status", "ready"]));
engineInstance.createContext("");
t.is(postMessageSpy.callCount, 2);
engineInstance.addParseWorkUnit({
requestId: 0,
dataFormat: 255,
dataString: "test",
options: JSON.stringify({})
});
t.is(postMessageSpy.callCount, 3);
t.deepEqual(postMessageSpy.getCall(2).args[0], [
"parse-string-error",
{
error: {
errorCode: 255,
errorMessage: "Error. This is a domain name."
},
requestId: 0
}
]);
engineInstance.addParseWorkUnit({
requestId: 1,
dataFormat: 260,
dataString: "test",
options: JSON.stringify({})
});
t.is(postMessageSpy.callCount, 4);
t.deepEqual(postMessageSpy.getCall(3).args[0], [
"parse-string-error",
{
error: {
errorCode: 260,
errorMessage: "Error. This is a domain name (example.com)."
},
requestId: 1
}
]);
return [2 /*return*/];
}
});
}); });
//# sourceMappingURL=engineWorker.spec.js.map