Skip to content

Commit

Permalink
Jest24 (#20)
Browse files Browse the repository at this point in the history
* reapply changes so it avoids conflicts

* add pattern setTransform parameter check, increase code coverage to 100%, update to @babel/plugin-proposal-class-properties

* add path 2d tests

* fix var, double quotes to single quotes

* fix addHitRegion, arcTo tests, update travis to remove node 4 and 5, add 9, 10, 11
  • Loading branch information
jtenner authored and hustcc committed Jan 30, 2019
1 parent ca486a1 commit 75fd360
Show file tree
Hide file tree
Showing 80 changed files with 1,521 additions and 1,489 deletions.
4 changes: 2 additions & 2 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"presets": ["env"],
"plugins": ["transform-class-properties", "version"]
"presets": ["@babel/env"],
"plugins": ["@babel/proposal-class-properties", "version"]
}
5 changes: 3 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
language: node_js
node_js:
- "4"
- "5"
- "6"
- "7"
- "8"
- "9"
- "10"
- "11"
after_success:
- npm run coveralls
30 changes: 30 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,36 @@ Add that file to your `setupFiles` array:
}
```

## Mock Strategy

This mock strategy implements all the canvas functions and actually verifies the parameters. If a
known condition would cause the browser to throw a `TypeError` or a `DOMException`, it emulates the
error. For instance, the `CanvasRenderingContext2D#arc` function will throw a `TypeError` if the
radius is negative, or if it was not provided with enough parameters.

```ts
expect(() => ctx.arc(1, 2, 3, 4)).toThrow(TypeError);
expect(() => ctx.arc(0, 0, -10, 0, Math.PI * 2)).toThrow(TypeError);
```

The function will do `Number` type coercion and verify the inputs exactly like the browser does. So
this is valid input.

```ts
expect(() => ctx.arc("10", "10", "20", "0", "6.14")).not.toThrow();
```

Another part of the strategy is to validate input types. When using the
`CanvasRenderingContext2D#fill` function, if you pass it an invalid `fillRule` it will throw a
`TypeError` just like the browser does.

```ts
expect(() => ctx.fill("invalid!")).toThrow(TypeError);
expect(() => ctx.fill(new Path2D(), "invalid!")).toThrow(TypeError);
```

We try to follow the ECMAScript specification as closely as possible.


## License

Expand Down
27 changes: 12 additions & 15 deletions __tests__/classes/CanvasGradient.js
Original file line number Diff line number Diff line change
@@ -1,29 +1,26 @@
import mockWindow from '../../src/window';
let ctx;
let grd;

beforeEach(() => {
ctx = document.createElement('canvas').getContext('2d');
grd = ctx.createLinearGradient(1, 2, 3, 4);
});

describe('CanvasGradient', () => {

test('CanvasGradient', () => {
const canvasGradient = new CanvasGradient();

expect(canvasGradient).toBeDefined();

canvasGradient.addColorStop();
expect(grd).toBeDefined();
grd.addColorStop();
expect(grd.addColorStop).toBeCalled();

expect(canvasGradient.addColorStop).toBeCalled();

const other = new CanvasGradient();
expect(other.addColorStop).not.toBeCalled();
const grd2 = ctx.createLinearGradient(2, 3, 4, 5);
expect(grd2.addColorStop).not.toBeCalled();
});

test('CanvasGradient different instance', () => {
const canvasGradient1 = new CanvasGradient();
const canvasGradient2 = new CanvasGradient();
expect(canvasGradient1.addColorStop).not.toBe(canvasGradient2.addColorStop);
});

test('CanvasGradient not override', () => {
const saved = window.CanvasGradient;
mockWindow(window);
expect(saved === window.CanvasGradient).toBe(true);
});
});
41 changes: 27 additions & 14 deletions __tests__/classes/CanvasPattern.js
Original file line number Diff line number Diff line change
@@ -1,29 +1,42 @@
import mockWindow from '../../src/window';
let ctx;
let canvas;
const img = new Image();
img.src = 'https://placekitten.com/400/300';

beforeEach(() => {
canvas = document.createElement('canvas');
canvas.width = 400;
canvas.height = 300;
ctx = canvas.getContext('2d');
});

describe('CanvasPattern', () => {

test('CanvasPattern', () => {
const canvasPattern = new CanvasPattern();

const canvasPattern = ctx.createPattern(img, 'no-repeat');
expect(canvasPattern).toBeDefined();
expect(canvasPattern).toBeInstanceOf(CanvasPattern);
});

canvasPattern.setTransform();
it('should have a setTransform function', () => {
const canvasPattern = ctx.createPattern(img, 'no-repeat');
expect(typeof canvasPattern.setTransform).toBe('function');
});

it('should have callable setTransform', () => {
const canvasPattern = ctx.createPattern(img, 'no-repeat');
canvasPattern.setTransform(ctx.getTransform());
expect(canvasPattern.setTransform).toBeCalled();
});

const other = new CanvasPattern();
expect(other.setTransform).not.toBeCalled();
it('should throw if arguments.length > 0 and transform not instanceof Object', () => {
const canvasPattern = ctx.createPattern(img, 'no-repeat');
expect(() => canvasPattern.setTransform(1)).toThrow(TypeError);
});

test('CanvasPattern different instance', () => {
const canvasPattern1 = new CanvasPattern();
const canvasPattern2 = new CanvasPattern();
const canvasPattern1 = ctx.createPattern(img, 'no-repeat');
const canvasPattern2 = ctx.createPattern(img, 'no-repeat');
expect(canvasPattern1.setTransform).not.toBe(canvasPattern2.setTransform);
});

test('CanvasPattern not override', () => {
const saved = window.CanvasPattern;
mockWindow(window);
expect(saved === window.CanvasPattern).toBe(true);
});
});
27 changes: 14 additions & 13 deletions __tests__/classes/CanvasRenderingContext2D.addHitRegion.js
Original file line number Diff line number Diff line change
@@ -1,29 +1,30 @@
var canvas;
var ctx;
let canvas;
let ctx;

beforeEach(() => {
canvas = document.createElement("canvas");
ctx = canvas.getContext("2d");
canvas = document.createElement('canvas');
ctx = canvas.getContext('2d');
canvas.width = 400;
canvas.height = 300;
});

describe("addHitRegion", () => {
it("should be a function", () => {
describe('addHitRegion', () => {
it('should be a function', () => {
expect(ctx.addHitRegion).toBeTruthy();
});
it("should be callable", () => {
ctx.addHitRegion({ id: "test" });

it('should be callable', () => {
ctx.addHitRegion({ id: 'test' });
expect(ctx.addHitRegion).toBeCalled();
});

it("should throw if called with no parameters", () => {
it('should throw if called with no parameters', () => {
expect(() => ctx.addHitRegion()).toThrow(DOMException);
});

it("should throw if fillRule is set and isn't 'evenodd' or 'nonzero'", () => {
expect(() => ctx.addHitRegion({ id: "test", fillRule: "wrong!" })).toThrow();
expect(() => ctx.addHitRegion({ id: "test", fillRule: "evenodd", })).not.toThrow();
expect(() => ctx.addHitRegion({ id: "test", fillRule: "nonzero", })).not.toThrow();
it('should throw if fillRule is set and isn\'t \'evenodd\' or \'nonzero\'', () => {
expect(() => ctx.addHitRegion({ id: 'test', fillRule: 'wrong!' })).toThrow();
expect(() => ctx.addHitRegion({ id: 'test', fillRule: 'evenodd', })).not.toThrow();
expect(() => ctx.addHitRegion({ id: 'test', fillRule: 'nonzero', })).not.toThrow();
});
});
22 changes: 11 additions & 11 deletions __tests__/classes/CanvasRenderingContext2D.arc.js
Original file line number Diff line number Diff line change
@@ -1,36 +1,36 @@
var canvas;
var ctx;
let canvas;
let ctx;

beforeEach(() => {
canvas = document.createElement("canvas");
ctx = canvas.getContext("2d");
canvas = document.createElement('canvas');
ctx = canvas.getContext('2d');
canvas.width = 400;
canvas.height = 300;
});

describe("arc", () => {
it("should be a function", () => {
expect(typeof ctx.arc === "function").toBeTruthy();
describe('arc', () => {
it('should be a function', () => {
expect(typeof ctx.arc === 'function').toBeTruthy();
});

it("should be callable", () => {
it('should be callable', () => {
ctx.arc(1, 2, 3, 4, 5);
expect(ctx.arc).toBeCalled();
});

it("shouldn't accept parameters less than 7", () => {
it('shouldn\'t accept parameters less than 7', () => {
expect(() => ctx.arc()).toThrow(TypeError);
expect(() => ctx.arc(1)).toThrow(TypeError);
expect(() => ctx.arc(1, 2,)).toThrow(TypeError);
expect(() => ctx.arc(1, 2, 3)).toThrow(TypeError);
expect(() => ctx.arc(1, 2, 3, 4)).toThrow(TypeError);
});

it("should throw when radius is negative", () => {
it('should throw when radius is negative', () => {
expect(() => ctx.arc(1, 2, -1, 4, 5)).toThrow(DOMException);
});

it("should not throw if any value is `NaN`", () => {
it('should not throw if any value is `NaN`', () => {
[
[NaN, 2, 3, 4, 5],
[1, NaN, 3, 4, 5],
Expand Down
26 changes: 13 additions & 13 deletions __tests__/classes/CanvasRenderingContext2D.arcTo.js
Original file line number Diff line number Diff line change
@@ -1,42 +1,42 @@
var canvas;
var ctx;
let canvas;
let ctx;

beforeEach(() => {
canvas = document.createElement("canvas");
ctx = canvas.getContext("2d");
canvas = document.createElement('canvas');
ctx = canvas.getContext('2d');
canvas.width = 400;
canvas.height = 300;
});

describe("arcTo", () => {
it("should be a function", () => {
expect(typeof ctx.arcTo === "function").toBeTruthy();
describe('arcTo', () => {
it('should be a function', () => {
expect(typeof ctx.arcTo).toBe('function');
});

it("should be callable", () => {
it('should be callable', () => {
ctx.arcTo(1, 2, 3, 4, 5);
expect(ctx.arcTo).toBeCalled();
});

it("shouldn't accept parameters less than 5", () => {
it('shouldn\'t accept parameters less than 5', () => {
expect(() => ctx.arcTo(1, 2, 3)).toThrow(TypeError);
});

it("should throw when radius is negative", () => {
it('should throw when radius is negative', () => {
expect(() => ctx.arcTo(1, 2, -1, 3, -1)).toThrow(TypeError);
});

it("should accept 5 parameters regardless of type", () => {
it('should accept 5 parameters regardless of type', () => {
[
[1, 2, 3, 4, 5],
[null, void 0, "", NaN, Infinity],
[null, void 0, '', NaN, Infinity],
[-100, -100, 100, 0, 0],
].forEach(e => {
expect(() => ctx.arcTo(...e)).not.toThrow();
});
});

it("should not throw for negative radius values if either control point is not a valid point", () => {
it('should not throw for negative radius values if either control point is not a valid point', () => {
[
[NaN, 1, 2, 3, -1],
[1, NaN, 2, 3, -1],
Expand Down
16 changes: 8 additions & 8 deletions __tests__/classes/CanvasRenderingContext2D.beginPath.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
var canvas;
var ctx;
let canvas;
let ctx;

beforeEach(() => {
canvas = document.createElement("canvas");
ctx = canvas.getContext("2d");
canvas = document.createElement('canvas');
ctx = canvas.getContext('2d');
canvas.width = 400;
canvas.height = 300;
});

describe("beginPath", () => {
it("should be a function", () => {
expect(typeof ctx.beginPath).toBe("function");
describe('beginPath', () => {
it('should be a function', () => {
expect(typeof ctx.beginPath).toBe('function');
});

it("should be callable", () => {
it('should be callable', () => {
ctx.beginPath();
expect(ctx.beginPath).toBeCalled();
});
Expand Down
18 changes: 9 additions & 9 deletions __tests__/classes/CanvasRenderingContext2D.bezierCurveTo.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
var canvas;
var ctx;
let canvas;
let ctx;

beforeEach(() => {
canvas = document.createElement("canvas");
ctx = canvas.getContext("2d");
canvas = document.createElement('canvas');
ctx = canvas.getContext('2d');
canvas.width = 400;
canvas.height = 300;
});

describe("bezierCurveTo", () => {
it("should be a function", () => {
expect(typeof ctx.bezierCurveTo).toBe("function");
describe('bezierCurveTo', () => {
it('should be a function', () => {
expect(typeof ctx.bezierCurveTo).toBe('function');
});

it("should be callable", () => {
it('should be callable', () => {
ctx.bezierCurveTo(1, 2, 3, 4, 5, 6);
expect(ctx.bezierCurveTo).toBeCalled();
});

it("should throw if less than 6 parameters are given", () => {
it('should throw if less than 6 parameters are given', () => {
expect(() => ctx.bezierCurveTo()).toThrow(TypeError);
expect(() => ctx.bezierCurveTo(1)).toThrow(TypeError);
expect(() => ctx.bezierCurveTo(1, 2)).toThrow(TypeError);
Expand Down
16 changes: 8 additions & 8 deletions __tests__/classes/CanvasRenderingContext2D.clearHitRegions.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
var canvas;
var ctx;
let canvas;
let ctx;

beforeEach(() => {
canvas = document.createElement("canvas");
ctx = canvas.getContext("2d");
canvas = document.createElement('canvas');
ctx = canvas.getContext('2d');
canvas.width = 400;
canvas.height = 300;
});

describe("clearHitRegions", () => {
it("should be a function", () => {
expect(typeof ctx.clearHitRegions).toBe("function");
describe('clearHitRegions', () => {
it('should be a function', () => {
expect(typeof ctx.clearHitRegions).toBe('function');
});

it("should be callable", () => {
it('should be callable', () => {
ctx.clearHitRegions();
expect(ctx.clearHitRegions).toBeCalled();
});
Expand Down
Loading

0 comments on commit 75fd360

Please sign in to comment.