Skip to content

Commit

Permalink
Merge pull request #199 from ericblade/test
Browse files Browse the repository at this point in the history
update camera and media tests, cleanup camera and media code
  • Loading branch information
ericblade authored May 18, 2020
2 parents a442b36 + bdf81a2 commit 0e7228e
Show file tree
Hide file tree
Showing 12 changed files with 395 additions and 246 deletions.
3 changes: 2 additions & 1 deletion cypress/integration/browser.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ window.ENV = { development: true, production: false, node: false };

import '../../src/analytics/test/browser/result_collector.spec';
import '../../src/input/test/browser/exif_helper.spec';
import '../../src/input/test/browser/camera_access.spec';
import '../../src/input/test/browser/camera_access.spec';
import '../../src/common/test/browser/mediaDevices.spec';
244 changes: 117 additions & 127 deletions package-lock.json

Large diffs are not rendered by default.

18 changes: 9 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@ericblade/quagga2",
"version": "1.0.4",
"version": "1.0.5",
"description": "An advanced barcode-scanner written in JavaScript",
"main": "lib/quagga.js",
"types": "type-definitions/quagga.d.ts",
Expand All @@ -15,17 +15,17 @@
"@babel/preset-env": "^7.9.6",
"@babel/preset-typescript": "^7.9.0",
"@babel/runtime": "^7.9.6",
"@cypress/code-coverage": "^3.7.2",
"@cypress/webpack-preprocessor": "^5.2.0",
"@cypress/code-coverage": "^3.7.4",
"@cypress/webpack-preprocessor": "^5.2.1",
"@std/esm": "^0.26.0",
"@types/chai": "^4.2.11",
"@types/gl-vec2": "^1.3.0",
"@types/lodash": "^4.14.150",
"@types/lodash": "^4.14.151",
"@types/mocha": "^5.2.7",
"@types/react": "^16.9.35",
"@types/sinon": "^9.0.0",
"@types/sinon": "^9.0.1",
"@types/sinon-chai": "^3.2.4",
"@typescript-eslint/eslint-plugin": "^2.24.0",
"@typescript-eslint/eslint-plugin": "^2.33.0",
"babel-loader": "^8.1.0",
"babel-plugin-add-module-exports": "^1.0.2",
"babel-plugin-istanbul": "^6.0.0",
Expand All @@ -35,7 +35,7 @@
"cypress": "^4.5.0",
"eslint": "^6.8.0",
"eslint-config-airbnb-typescript": "^7.2.1",
"eslint-plugin-import": "^2.20.1",
"eslint-plugin-import": "^2.20.2",
"eslint-plugin-jsx-a11y": "^6.2.3",
"eslint-plugin-react": "^7.20.0",
"mocha": "^5.2.0",
Expand All @@ -45,7 +45,7 @@
"source-map-loader": "^0.2.4",
"ts-mocha": "^7.0.0",
"ts-node": "^8.10.1",
"typescript": "^3.8.3",
"typescript": "^3.9.2",
"webpack": "^4.43.0",
"webpack-cli": "^3.3.11"
},
Expand Down Expand Up @@ -138,7 +138,7 @@
"lodash": "^4.17.15",
"ndarray": "^1.0.19",
"ndarray-linear-interpolate": "^1.0.0",
"snyk": "^1.320.2"
"snyk": "^1.321.0"
},
"snyk": true,
"nyc": {
Expand Down
42 changes: 26 additions & 16 deletions src/analytics/result_collector.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,48 @@
import ImageDebug from '../common/image_debug';
import { QuaggaJSCodeResult, QuaggaJSResultCollector, QuaggaJSResultCollectorFilterFunction, XYSize, QuaggaImageData } from '../../type-definitions/quagga';
import {
QuaggaJSCodeResult,
QuaggaJSResultCollector,
QuaggaJSResultCollectorFilterFunction,
XYSize,
QuaggaImageData,
} from '../../type-definitions/quagga.d';

function contains(codeResult: QuaggaJSCodeResult, list: Array<QuaggaJSCodeResult>) {
if (!list) return false;
return list.some((item) => {
function contains(codeResult: QuaggaJSCodeResult, list: Array<QuaggaJSCodeResult>): boolean {
return list && list.some((item) => {
const keys = Object.keys(item) as Array<keyof QuaggaJSCodeResult>;
return keys.every((key) => item[key] === codeResult[key]);
});
}

function passesFilter(codeResult: QuaggaJSCodeResult, filter: QuaggaJSResultCollectorFilterFunction | undefined) {
if (typeof filter === 'function') {
return filter(codeResult);
}
return true;
function passesFilter(
codeResult: QuaggaJSCodeResult,
filter: QuaggaJSResultCollectorFilterFunction | undefined,
): boolean {
return typeof filter === 'function' ? filter(codeResult) : true;
}

interface ResultCollector {
addResult: (data: QuaggaImageData, imageSize: XYSize, codeResult: QuaggaJSCodeResult) => void;
getResults: () => Array<QuaggaJSCodeResult>;
}

export default {
create: function(config: QuaggaJSResultCollector) {
create(config: QuaggaJSResultCollector): ResultCollector {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d') as CanvasRenderingContext2D;
const results:Array<QuaggaJSCodeResult> = [];
const results: Array<QuaggaJSCodeResult> = [];
let capacity = config.capacity ?? 20;
const capture = config.capture === true;

function matchesConstraints(codeResult: QuaggaJSCodeResult) {
return capacity
function matchesConstraints(codeResult: QuaggaJSCodeResult): boolean {
return !!capacity
&& codeResult
&& !contains(codeResult, config.blacklist as Array<QuaggaJSCodeResult>)
&& passesFilter(codeResult, config.filter);
}

return {
addResult: function(data: QuaggaImageData, imageSize: XYSize, codeResult: QuaggaJSCodeResult) {
addResult(data: QuaggaImageData, imageSize: XYSize, codeResult: QuaggaJSCodeResult): void {
const result: any = { }; // this is 'any' to avoid having to construct a whole QuaggaJSCodeResult :|
if (matchesConstraints(codeResult)) {
capacity--;
Expand All @@ -46,7 +56,7 @@ export default {
results.push(result);
}
},
getResults: function() {
getResults(): Array<QuaggaJSCodeResult> {
return results;
},
};
Expand Down
85 changes: 44 additions & 41 deletions src/analytics/test/browser/result_collector.spec.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
/// <reference path="mocha">

import ResultCollector from '../../result_collector';
import ImageDebug from '../../../common/image_debug';
import { XYSize, QuaggaJSResultCollector, QuaggaJSCodeResult } from '../../../../type-definitions/quagga';
// import { describe, beforeEach, afterEach, it } from 'mocha';
import { expect } from 'chai';
import sinon, { SinonSpy } from 'sinon';
import {
describe,
beforeEach,
afterEach,
it,
} from 'mocha';
import ResultCollector from '../../result_collector';
import ImageDebug from '../../../common/image_debug';
import { XYSize, QuaggaJSResultCollector, QuaggaJSCodeResult } from '../../../../type-definitions/quagga.d';

interface MockCanvas {
getContext(): {};
Expand All @@ -18,24 +21,24 @@ let canvasMock: MockCanvas;
let imageSize: XYSize;
let config: QuaggaJSResultCollector;

describe("Result Collector", () => {
beforeEach(function() {
imageSize = {x: 320, y: 240};
describe('Result Collector', () => {
beforeEach(() => {
imageSize = { x: 320, y: 240 };
config = {
capture: true,
capacity: 20,
blacklist: [{code: "3574660239843", format: "ean_13"}],
filter: function() {
blacklist: [{ code: '3574660239843', format: 'ean_13' }],
filter(): boolean {
return true;
}
},
};
canvasMock = {
getContext: function() {
getContext(): {} {
return {};
},
toDataURL: sinon.spy(),
width: 0,
height: 0
height: 0,
};
sinon.stub(document, 'createElement').callsFake((type) => {
if (type === 'canvas') {
Expand All @@ -45,74 +48,74 @@ describe("Result Collector", () => {
});
});

afterEach(function() {
afterEach(() => {
(document.createElement as SinonSpy).restore();
});


describe('create', function () {
it("should return a new collector", function() {
describe('create', () => {
it('should return a new collector', () => {
ResultCollector.create(config);
expect( (document.createElement as SinonSpy).calledOnce).to.be.equal(true);
expect( (document.createElement as SinonSpy).getCall(0).args[0]).to.equal("canvas");
expect((document.createElement as SinonSpy).calledOnce).to.be.equal(true);
expect((document.createElement as SinonSpy).getCall(0).args[0]).to.equal('canvas');
});
});

describe('addResult', function() {
beforeEach(function() {
sinon.stub(ImageDebug, 'drawImage').callsFake(() => { return true; });
describe('addResult', () => {
beforeEach(() => {
sinon.stub(ImageDebug, 'drawImage').callsFake(() => true);
});

afterEach(function() {
afterEach(() => {
(ImageDebug.drawImage as SinonSpy).restore();
});

it("should not add result if capacity is full", function(){
it('should not add result if capacity is full', () => {
config.capacity = 1;
var collector = ResultCollector.create(config);
const collector = ResultCollector.create(config);
collector.addResult([], imageSize, {});
collector.addResult([], imageSize, {});
collector.addResult([], imageSize, {});
expect(collector.getResults()).to.have.length(1);
});

it("should only add results which match constraints", function() {
it('should only add results which match constraints', () => {
const collector = ResultCollector.create(config);

collector.addResult([], imageSize, {code: "423423443", format: "ean_13"});
collector.addResult([], imageSize, {code: "3574660239843", format: "ean_13"});
collector.addResult([], imageSize, {code: "3574660239843", format: "code_128"});
collector.addResult([], imageSize, { code: '423423443', format: 'ean_13' });
collector.addResult([], imageSize, { code: '3574660239843', format: 'ean_13' });
collector.addResult([], imageSize, { code: '3574660239843', format: 'code_128' });

const results = collector.getResults();
expect(results).to.have.length(2);

results.forEach(function(result: QuaggaJSCodeResult) {
results.forEach((result: QuaggaJSCodeResult) => {
expect(result).not.to.deep.equal(config.blacklist![0]);
});
});

it("should add result if no filter is set", function() {
it('should add result if no filter is set', () => {
delete config.filter;
var collector = ResultCollector.create(config);
const collector = ResultCollector.create(config);

collector.addResult([], imageSize, {code: "423423443", format: "ean_13"});
collector.addResult([], imageSize, { code: '423423443', format: 'ean_13' });
expect(collector.getResults()).to.have.length(1);
});

it("should not add results if filter returns false", function() {
config.filter = () => (false);
var collector = ResultCollector.create(config);
it('should not add results if filter returns false', () => {
config.filter = (): boolean => (false);
const collector = ResultCollector.create(config);

collector.addResult([], imageSize, {code: "423423443", format: "ean_13"});
collector.addResult([], imageSize, { code: '423423443', format: 'ean_13' });
expect(collector.getResults()).to.have.length(0);
});

it("should add result if no blacklist is set", function() {
it('should add result if no blacklist is set', () => {
delete config.blacklist;
var collector = ResultCollector.create(config);
const collector = ResultCollector.create(config);

collector.addResult([], imageSize, {code: "3574660239843", format: "ean_13"});
collector.addResult([], imageSize, { code: '3574660239843', format: 'ean_13' });
expect(collector.getResults()).to.have.length(1);
});
});
})
});
12 changes: 10 additions & 2 deletions src/common/mediaDevices.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
export function enumerateDevices(): Promise<Array<MediaDeviceInfo>> {
return navigator?.mediaDevices?.enumerateDevices?.() ?? Promise.reject(new Error('enumerateDevices is not defined'));
try {
return navigator.mediaDevices.enumerateDevices();
} catch (err) {
return Promise.reject(new Error('enumerateDevices is not defined'));
}
}

export function getUserMedia(constraints: MediaStreamConstraints): Promise<MediaStream> {
return navigator?.mediaDevices?.getUserMedia(constraints) ?? Promise.reject(new Error('getUserMedia is not defined'));
try {
return navigator.mediaDevices.getUserMedia(constraints);
} catch (err) {
return Promise.reject(new Error('getUserMedia is not defined'));
}
}
24 changes: 24 additions & 0 deletions src/common/test/browser/mediaDevices.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { describe, it } from 'mocha';
import { expect } from 'chai';
import { enumerateDevices, getUserMedia } from '../../mediaDevices';

describe('mediaDevices (browser)', () => {
describe('enumerateDevices', () => {
it('TODO: rejects with an error if enumerateDevices is not supported in browser version');
it('returns a Promise', () => {
expect(enumerateDevices()).to.be.a('Promise');
});
it('resolves with an Array of InputDeviceInfo', async () => {
const d = await enumerateDevices();
expect(d).to.be.an('Array').of.length.greaterThan(1);
console.warn('* d=', d);
expect(d[0]).to.be.an.instanceof(InputDeviceInfo);
});
});
describe('getUserMedia', () => {
it('TODO: rejects with an error if getUserMedia is not supported');
it('returns a Promise', () => {
expect(getUserMedia({})).to.be.a('Promise');
});
});
});
24 changes: 24 additions & 0 deletions src/common/test/node/mediaDevices.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { describe, it } from 'mocha';
import { expect } from 'chai';
import { enumerateDevices, getUserMedia } from '../../mediaDevices';

describe('mediaDevices (node)', () => {
it('enumerateDevices rejects', async () => {
try {
const x = await enumerateDevices();
// eslint-disable-next-line @typescript-eslint/no-unused-expressions,no-unused-expressions
expect(x).to.not.exist;
} catch (err) {
expect(err.message).to.equal('enumerateDevices is not defined');
}
});
it('getUserMedia rejects', async () => {
try {
const x = await getUserMedia({});
// eslint-disable-next-line @typescript-eslint/no-unused-expressions,no-unused-expressions
expect(x).to.not.exist;
} catch (err) {
expect(err.message).to.equal('getUserMedia is not defined');
}
});
});
Loading

0 comments on commit 0e7228e

Please sign in to comment.