Skip to content

Commit 2c70b43

Browse files
committed
add tests for input keyframe type checks
1 parent 22a48be commit 2c70b43

File tree

7 files changed

+186
-7
lines changed

7 files changed

+186
-7
lines changed

internal/animate/testing/script.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,11 @@ const loopBetween = (percentage: number, a: Point[], b: Point[]): Point[] => {
259259
}
260260
};
261261

262-
const genAnimation = (speed: number, offset: number, timing: blobs2Animate.CanvasKeyframe["timingFunction"]) => {
262+
const genAnimation = (
263+
speed: number,
264+
offset: number,
265+
timing: blobs2Animate.CanvasKeyframe["timingFunction"],
266+
) => {
263267
const animation = blobs2Animate.canvasPath();
264268

265269
const loopAnimation = () => {

internal/errors.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ export const error = (message: string) => {
33
};
44

55
export const typeCheck = (name: string, val: any, expected: string[]) => {
6-
const actual = typeof val;
6+
let actual: string = typeof val;
7+
if (actual === "number" && isNaN(val)) actual = "NaN";
78
if (!expected.includes(actual)) {
89
error(`"${name}" should have type "${expected.join("|")}" but was "${actual}".`);
910
}

internal/gen.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,14 @@ export const genBlob = (pointCount: number, offset: () => number): Point[] => {
2828
};
2929

3030
export const genFromOptions = (blobOptions: BlobOptions): Point[] => {
31-
const rgen = rand(String(blobOptions.seed));
32-
3331
typeCheck("blobOptions", blobOptions, ["object"]);
3432
typeCheck("seed", blobOptions.seed, ["string", "number"]);
3533
typeCheck("extraPoints", blobOptions.extraPoints, ["number"]);
3634
typeCheck("randomness", blobOptions.randomness, ["number"]);
3735
typeCheck("size", blobOptions.size, ["number"]);
3836

37+
const rgen = rand(String(blobOptions.seed));
38+
3939
// Scale of random movement increases as randomness approaches infinity.
4040
// randomness = 0 -> rangeStart = 1
4141
// randomness = 2 -> rangeStart = 0.8333

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@
4242
"blob",
4343
"svg",
4444
"path",
45-
"canvas"
45+
"canvas",
46+
"animation"
4647
],
4748
"prettier": {
4849
"tabWidth": 4,

public/animate.test.ts

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
import {canvasPath, CanvasKeyframe} from "./animate";
2+
3+
const genKeyframe = (): CanvasKeyframe => ({
4+
duration: 1000 * Math.random(),
5+
delay: 1000 * Math.random(),
6+
timingFunction: "linear",
7+
callback: () => {},
8+
blobOptions: {
9+
extraPoints: Math.floor(10 * Math.random()),
10+
randomness: Math.floor(10 * Math.random()),
11+
seed: Math.random(),
12+
size: 100 + 200 * Math.random(),
13+
},
14+
canvasOptions: {
15+
offsetX: 100 * Math.random(),
16+
offsetY: 100 * Math.random(),
17+
},
18+
});
19+
20+
describe("animate", () => {
21+
describe("canvasPath", () => {
22+
describe("transition", () => {
23+
describe("keyframe", () => {
24+
// TODO test for errors in the nth keyframe.
25+
it("should accept minimal generated keyframe", () => {
26+
const animation = canvasPath();
27+
const keyframe = genKeyframe();
28+
29+
expect(() => animation.transition(keyframe)).not.toThrow();
30+
});
31+
32+
interface TestCase {
33+
test: string;
34+
edit: (keyframe: CanvasKeyframe) => void;
35+
error?: RegExp;
36+
}
37+
38+
const testCases: Array<TestCase> = [
39+
{
40+
test: "should accept valid duration",
41+
edit: (keyframe) => (keyframe.duration = 100),
42+
},
43+
{
44+
test: "should accept zero duration",
45+
edit: (keyframe) => (keyframe.duration = 0),
46+
},
47+
{
48+
test: "should reject undefined duration",
49+
edit: (keyframe) => delete keyframe.duration,
50+
error: /duration.*number.*undefined/g,
51+
},
52+
{
53+
test: "should reject negative duration",
54+
edit: (keyframe) => (keyframe.duration = -10),
55+
error: /duration.*invalid/g,
56+
},
57+
{
58+
test: "should reject broken duration",
59+
edit: (keyframe) => (keyframe.duration = NaN),
60+
error: /duration.*number.*NaN/g,
61+
},
62+
{
63+
test: "should reject invalid duration",
64+
edit: (keyframe) => (keyframe.duration = "123" as any),
65+
error: /duration.*number.*string/g,
66+
},
67+
{
68+
test: "should accept valid delay",
69+
edit: (keyframe) => (keyframe.delay = 200),
70+
},
71+
{
72+
test: "should accept zero delay",
73+
edit: (keyframe) => (keyframe.delay = 0),
74+
},
75+
{
76+
test: "should accept undefined delay",
77+
edit: (keyframe) => delete keyframe.delay,
78+
},
79+
{
80+
test: "should reject negative delay",
81+
edit: (keyframe) => (keyframe.delay = -10),
82+
error: /delay.*invalid/g,
83+
},
84+
{
85+
test: "should reject broken delay",
86+
edit: (keyframe) => (keyframe.delay = NaN),
87+
error: /delay.*number.*NaN/g,
88+
},
89+
{
90+
test: "should reject invalid delay",
91+
edit: (keyframe) => (keyframe.delay = "123" as any),
92+
error: /delay.*number.*string/g,
93+
},
94+
{
95+
test: "should accept known timingFunction",
96+
edit: (keyframe) => (keyframe.timingFunction = "ease"),
97+
},
98+
{
99+
test: "should accept undefined timingFunction",
100+
edit: (keyframe) => delete keyframe.timingFunction,
101+
},
102+
{
103+
test: "should reject invalid timingFunction",
104+
edit: (keyframe) => (keyframe.timingFunction = (() => 0) as any),
105+
error: /timingFunction.*string.*function/g,
106+
},
107+
{
108+
test: "should reject unknown timingFunction",
109+
edit: (keyframe) => (keyframe.timingFunction = "unknown" as any),
110+
error: /timingFunction.*not recognized.*unknown/g,
111+
},
112+
{
113+
test: "should accept valid callback",
114+
edit: (keyframe) => (keyframe.callback = () => console.log("test")),
115+
},
116+
{
117+
test: "should accept undefined callback",
118+
edit: (keyframe) => delete keyframe.callback,
119+
},
120+
{
121+
test: "should reject invalid callback",
122+
edit: (keyframe) => (keyframe.callback = {} as any),
123+
error: /callback.*function.*object/g,
124+
},
125+
// TODO complete blobOptions type tests, should be the same as non-animated.
126+
{
127+
test: "should reject undefined blobOptions",
128+
edit: (keyframe) => delete keyframe.blobOptions,
129+
error: /blobOptions.*object.*undefined/g,
130+
},
131+
{
132+
test: "should accept empty canvasOptions",
133+
edit: (keyframe) => (keyframe.canvasOptions = {}),
134+
},
135+
{
136+
test: "should accept undefined canvasOptions",
137+
edit: (keyframe) => delete keyframe.canvasOptions,
138+
},
139+
{
140+
test: "should accept undefined canvasOptions offsetX",
141+
edit: (keyframe) => delete keyframe.canvasOptions?.offsetX,
142+
},
143+
{
144+
test: "should reject broken canvasOptions offsetX",
145+
edit: (keyframe) => (keyframe.canvasOptions = {offsetX: NaN}),
146+
error: /canvasOptions.*offsetX.*number.*NaN/g,
147+
},
148+
{
149+
test: "should accept undefined canvasOptions offsetY",
150+
edit: (keyframe) => delete keyframe.canvasOptions?.offsetY,
151+
},
152+
{
153+
test: "should reject broken canvasOptions offsetY",
154+
edit: (keyframe) => (keyframe.canvasOptions = {offsetY: NaN}),
155+
error: /canvasOptions.*offsetY.*number.*NaN/g,
156+
},
157+
];
158+
159+
for (const testCase of testCases) {
160+
it(testCase.test, () => {
161+
const animation = canvasPath();
162+
const keyframe = genKeyframe();
163+
testCase.edit(keyframe);
164+
if (testCase.error) {
165+
expect(() => animation.transition(keyframe)).toThrow(testCase.error);
166+
} else {
167+
expect(() => animation.transition(keyframe)).not.toThrow();
168+
}
169+
});
170+
}
171+
});
172+
});
173+
});
174+
});

public/animate.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ const canvasBlobGenerator = (keyframe: CanvasKeyframe): Point[] => {
3939
};
4040

4141
// Only need to check properties unique to the canvas animation generator.
42-
// TODO test bad inputs.
4342
const canvasKeyframeChecker = (keyframe: CanvasKeyframe, index: number) => {
4443
typeCheck(`keyframe[${index}].canvasOptions`, keyframe.canvasOptions, ["object", "undefined"]);
4544
if (keyframe.canvasOptions) {

public/legacy.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ const genMinimalOptions = (): BlobOptions => ({
77
color: "#fff",
88
});
99

10-
describe("blobs", () => {
10+
describe("legacy", () => {
1111
it("should return a different result when seed is not provided", () => {
1212
const options = genMinimalOptions();
1313

0 commit comments

Comments
 (0)