webamp/js/snapUtils.test.ts
2018-09-17 17:04:05 -07:00

477 lines
17 KiB
TypeScript

import {
top,
bottom,
left,
right,
near,
snap,
overlapY,
overlapX,
snapWithin,
applySnap,
snapDiff,
boundingBox,
applyMultipleDiffs
} from "./snapUtils";
describe("side functions", () => {
const box = { x: 10, y: 15, width: 50, height: 100 };
it("can find the top of a box", () => {
const actual = top(box);
const expected = 15;
expect(actual).toEqual(expected);
});
it("can find the bottom of a box", () => {
const actual = bottom(box);
const expected = 115;
expect(actual).toEqual(expected);
});
it("can find the left of a box", () => {
const actual = left(box);
const expected = 10;
expect(actual).toEqual(expected);
});
it("can find the right of a box", () => {
const actual = right(box);
const expected = 60;
expect(actual).toEqual(expected);
});
});
describe("near function", () => {
it("can tell if A is near B", () => {
const actual = near(10, 20);
const expected = true;
expect(actual).toEqual(expected);
});
it("can tell if A is near B", () => {
const actual = near(10, 30);
const expected = false;
expect(actual).toEqual(expected);
});
});
describe("overlap functions", () => {
it("overlapY detects when the boxes overlap in the Y axis", () => {
const a = { y: 10, height: 50, width: 100, x: 0 };
const b = { y: 40, height: 50, width: 100, x: 0 };
const actual = overlapY(a, b);
const expected = true;
expect(actual).toEqual(expected);
});
it("overlapY detects when the boxes are within SNAP_DISTANCE on the Y axis", () => {
const a = { y: 10, height: 50, width: 100, x: 0 };
const b = { y: 70, height: 50, width: 100, x: 0 };
const actual = overlapY(a, b);
const expected = true;
expect(actual).toEqual(expected);
});
it("overlapY detects when the boxes do not overlap in the Y axis", () => {
const a = { y: 10, height: 50, width: 100, x: 0 };
const b = { y: 90, height: 50, width: 100, x: 0 };
const actual = overlapY(a, b);
const expected = false;
expect(actual).toEqual(expected);
});
it("overlapX detects when the boxes overlap in the X axis", () => {
const a = { x: 10, width: 50, height: 100, y: 0 };
const b = { x: 40, width: 50, height: 100, y: 0 };
const actual = overlapX(a, b);
const expected = true;
expect(actual).toEqual(expected);
});
it("overlapX detects when the boxes are within SNAP_DISTANCE on the X axis", () => {
const a = { x: 10, width: 50, height: 100, y: 0 };
const b = { x: 70, width: 50, height: 100, y: 0 };
const actual = overlapX(a, b);
const expected = true;
expect(actual).toEqual(expected);
});
it("overlapX detects when the boxes do not overlap in the X axis", () => {
const a = { x: 10, width: 50, height: 100, y: 0 };
const b = { x: 90, width: 50, height: 100, y: 0 };
const actual = overlapX(a, b);
const expected = false;
expect(actual).toEqual(expected);
});
});
describe("snap function", () => {
it("does not snap if A and B are obviously far apart", () => {
const a = { x: 10, y: 10, width: 100, height: 100 };
const b = { x: 200, y: 200, width: 100, height: 100 };
const actual = snap(a, b);
const expected = {};
expect(actual).toEqual(expected);
});
it("snaps the left of A to the right of B", () => {
const a = { x: 120, y: 30, width: 100, height: 100 };
const b = { x: 10, y: 10, width: 100, height: 100 };
const actual = snap(a, b);
const expected = { x: 110 };
expect(actual).toEqual(expected);
});
it("snaps the right of A to the left of B", () => {
const a = { x: 10, y: 30, width: 100, height: 100 };
const b = { x: 120, y: 10, width: 100, height: 100 };
const actual = snap(a, b);
const expected = { x: 20 };
expect(actual).toEqual(expected);
});
it("snaps the top of A to the bottom of B", () => {
const a = { x: 30, y: 10, width: 100, height: 100 };
const b = { x: 10, y: 120, width: 100, height: 100 };
const actual = snap(a, b);
const expected = { y: 20 };
expect(actual).toEqual(expected);
});
it("snaps the bottom of A to the top of B", () => {
const a = { x: 30, y: 120, width: 100, height: 100 };
const b = { x: 10, y: 10, width: 100, height: 100 };
const actual = snap(a, b);
const expected = { y: 110 };
expect(actual).toEqual(expected);
});
it("does not snap to the X axis if A is below B", () => {
const a = { x: 10, y: 10, width: 100, height: 100 };
const b = { x: 110, y: 150, width: 100, height: 100 };
const actual = snap(a, b);
const expected = {};
expect(actual).toEqual(expected);
});
it("snaps in both axis if the corners are within SNAP_DISTANCE", () => {
const a = { x: 10, y: 10, width: 100, height: 100 };
const b = { x: 120, y: 120, width: 100, height: 100 };
const actual = snap(a, b);
const expected = { x: 20, y: 20 };
expect(actual).toEqual(expected);
});
it("snaps the left of A to the left of B", () => {
const a = { x: 10, y: 10, width: 100, height: 100 };
const b = { x: 15, y: 110, width: 100, height: 100 };
const actual = snap(a, b);
const expected = { x: 15, y: 10 };
expect(actual).toEqual(expected);
});
it("snaps the top of A to the bottom of B", () => {
const a = { x: 10, y: 10, width: 100, height: 100 };
const b = { x: 110, y: 15, width: 100, height: 100 };
const actual = snap(a, b);
const expected = { x: 10, y: 15 };
expect(actual).toEqual(expected);
});
it("snaps the top left corner of A to the bottom right corner of B", () => {
const a = { x: 110, y: 110, width: 100, height: 100 };
const b = { x: 0, y: 0, width: 100, height: 100 };
const actual = snap(a, b);
const expected = { x: 100, y: 100 };
expect(actual).toEqual(expected);
});
it("snaps the top of A down to the bottom of B, if A slighterly overlaps B", () => {
const a = { x: 0, y: 90, width: 100, height: 100 };
const b = { x: 0, y: 0, width: 100, height: 100 };
const actual = snap(a, b);
const expected = { x: 0, y: 100 };
expect(actual).toEqual(expected);
});
it("snaps the top of A down to the bottom of B, if A slighterly overlaps B", () => {
const a = { x: 0, y: 90, width: 100, height: 100 };
const b = { x: 0, y: 0, width: 100, height: 100 };
const actual = snap(a, b);
const expected = { x: 0, y: 100 };
expect(actual).toEqual(expected);
});
});
describe("snapWithin function", () => {
it("snaps the inner box to the top of the outer box", () => {
const inner = { x: 120, y: 10, width: 100, height: 100 };
const outer = { width: 1000, height: 1000 };
const actual = snapWithin(inner, outer);
const expected = { y: 0 };
expect(actual).toEqual(expected);
});
it("snaps the inner box to the bottom of the outer box", () => {
const inner = { x: 120, y: 910, width: 100, height: 100 };
const outer = { width: 1000, height: 1000 };
const actual = snapWithin(inner, outer);
const expected = { y: 900 };
expect(actual).toEqual(expected);
});
it("snaps the inner box to the right of the outer box", () => {
const inner = { x: 910, y: 120, width: 100, height: 100 };
const outer = { width: 1000, height: 1000 };
const actual = snapWithin(inner, outer);
const expected = { x: 900 };
expect(actual).toEqual(expected);
});
it("snaps the inner box to the left of the outer box", () => {
const inner = { x: 10, y: 120, width: 100, height: 100 };
const outer = { width: 1000, height: 1000 };
const actual = snapWithin(inner, outer);
const expected = { x: 0 };
expect(actual).toEqual(expected);
});
it("snaps the inner box to the top-left of the outer box", () => {
const inner = { x: 10, y: 10, width: 100, height: 100 };
const outer = { width: 1000, height: 1000 };
const actual = snapWithin(inner, outer);
const expected = { x: 0, y: 0 };
expect(actual).toEqual(expected);
});
});
describe("applySnap function", () => {
it("does not apply undefined values", () => {
const original = { x: 10, y: 10 };
const snapped = { x: undefined, y: undefined };
const actual = applySnap(original, snapped);
const expected = original;
expect(actual).toEqual(expected);
});
it("preserves other values on original", () => {
const original = { x: 10, y: 10, foo: "bar" };
const snapped = { x: 50, y: 50 };
const actual = applySnap(original, snapped);
const expected = { x: 50, y: 50, foo: "bar" };
expect(actual).toEqual(expected);
});
it('will clobber original with falsy "0" values', () => {
const original = { x: 10, y: 10 };
const snapped = { x: 0, y: 0 };
const actual = applySnap(original, snapped);
expect(actual).toEqual(snapped);
});
it('will clobber original with falsy "0" values', () => {
const original = { x: 10, y: 10 };
const snapped = { x: 0, y: 0 };
const actual = applySnap(original, snapped);
expect(actual).toEqual(snapped);
});
it("can apply multiple snaps", () => {
const original = { x: 10, y: 10 };
const snapped1 = { x: 0 };
const snapped2 = { y: 0 };
const actual = applySnap(original, snapped1, snapped2);
const expected = { x: 0, y: 0 };
expect(actual).toEqual(expected);
});
it("the last snap wins", () => {
const original = { x: 10, y: 10 };
const snapped1 = { x: 50, y: 20 };
const snapped2 = { x: 60, y: 60 };
const actual = applySnap(original, snapped1, snapped2);
const expected = { x: 60, y: 60 };
expect(actual).toEqual(expected);
});
});
describe("snap diff", () => {
it("does not snap if A and B are obviously far apart", () => {
const a = { x: 10, y: 10, width: 100, height: 100 };
const b = { x: 200, y: 200, width: 100, height: 100 };
const actual = snapDiff(a, b);
const expected = { x: 0, y: 0 };
expect(actual).toEqual(expected);
});
it("snaps the left of A to the right of B", () => {
const a = { x: 120, y: 30, width: 100, height: 100 };
const b = { x: 10, y: 10, width: 100, height: 100 };
const actual = snapDiff(a, b);
const expected = { x: -10, y: 0 };
expect(actual).toEqual(expected);
});
it("snaps the right of A to the left of B", () => {
const a = { x: 10, y: 30, width: 100, height: 100 };
const b = { x: 120, y: 10, width: 100, height: 100 };
const actual = snapDiff(a, b);
const expected = { x: 10, y: 0 };
expect(actual).toEqual(expected);
});
it("snaps the top of A to the bottom of B", () => {
const a = { x: 30, y: 10, width: 100, height: 100 };
const b = { x: 10, y: 120, width: 100, height: 100 };
const actual = snapDiff(a, b);
const expected = { x: 0, y: 10 };
expect(actual).toEqual(expected);
});
it("snaps the bottom of A to the top of B", () => {
const a = { x: 30, y: 120, width: 100, height: 100 };
const b = { x: 10, y: 10, width: 100, height: 100 };
const actual = snapDiff(a, b);
const expected = { x: 0, y: -10 };
expect(actual).toEqual(expected);
});
it("does not snap to the X axis if A is below B", () => {
const a = { x: 10, y: 10, width: 100, height: 100 };
const b = { x: 110, y: 150, width: 100, height: 100 };
const actual = snapDiff(a, b);
const expected = { x: 0, y: 0 };
expect(actual).toEqual(expected);
});
it("snaps in both axis if the corners are within SNAP_DISTANCE", () => {
const a = { x: 10, y: 10, width: 100, height: 100 };
const b = { x: 120, y: 120, width: 100, height: 100 };
const actual = snapDiff(a, b);
const expected = { x: 10, y: 10 };
expect(actual).toEqual(expected);
});
it("snaps the left of A to the left of B", () => {
const a = { x: 10, y: 10, width: 100, height: 100 };
const b = { x: 15, y: 110, width: 100, height: 100 };
const actual = snapDiff(a, b);
const expected = { x: 5, y: 0 };
expect(actual).toEqual(expected);
});
it("snaps the top of A to the bottom of B", () => {
const a = { x: 10, y: 10, width: 100, height: 100 };
const b = { x: 110, y: 15, width: 100, height: 100 };
const actual = snapDiff(a, b);
const expected = { x: 0, y: 5 };
expect(actual).toEqual(expected);
});
it("snaps the top left corner of A to the bottom right corner of B", () => {
const a = { x: 110, y: 110, width: 100, height: 100 };
const b = { x: 0, y: 0, width: 100, height: 100 };
const actual = snapDiff(a, b);
const expected = { x: -10, y: -10 };
expect(actual).toEqual(expected);
});
});
describe("snapWithin function", () => {
it("snaps the inner box to the top of the outer box", () => {
const inner = { x: 120, y: 10, width: 100, height: 100 };
const outer = { width: 1000, height: 1000 };
const actual = snapWithin(inner, outer);
const expected = { y: 0 };
expect(actual).toEqual(expected);
});
it("snaps the inner box to the bottom of the outer box", () => {
const inner = { x: 120, y: 910, width: 100, height: 100 };
const outer = { width: 1000, height: 1000 };
const actual = snapWithin(inner, outer);
const expected = { y: 900 };
expect(actual).toEqual(expected);
});
it("snaps the inner box to the right of the outer box", () => {
const inner = { x: 910, y: 120, width: 100, height: 100 };
const outer = { width: 1000, height: 1000 };
const actual = snapWithin(inner, outer);
const expected = { x: 900 };
expect(actual).toEqual(expected);
});
it("snaps the inner box to the left of the outer box", () => {
const inner = { x: 10, y: 120, width: 100, height: 100 };
const outer = { width: 1000, height: 1000 };
const actual = snapWithin(inner, outer);
const expected = { x: 0 };
expect(actual).toEqual(expected);
});
it("snaps the inner box to the top-left of the outer box", () => {
const inner = { x: 10, y: 10, width: 100, height: 100 };
const outer = { width: 1000, height: 1000 };
const actual = snapWithin(inner, outer);
const expected = { x: 0, y: 0 };
expect(actual).toEqual(expected);
});
});
describe("boundingBox function", () => {
it("does not mutate the given array", () => {
const box = { x: 10, y: 10, width: 100, height: 100 };
const boxesA = [box];
const boxesB = [box];
boundingBox(boxesA);
expect(boxesA).toEqual(boxesB);
});
it("returns iteself when called on a single box", () => {
const box = { x: 10, y: 10, width: 100, height: 100 };
expect(boundingBox([box])).toEqual(box);
});
it("returns the larger box when one fits entire within another", () => {
const boxes = [
{ x: 10, y: 10, width: 100, height: 100 },
{ x: 20, y: 20, width: 80, height: 80 }
];
expect(boundingBox(boxes)).toEqual(boxes[0]);
});
it("returns countaing box of two boxes", () => {
const boxes = [
{ x: 10, y: 10, width: 100, height: 100 },
{ x: 120, y: 220, width: 100, height: 100 }
];
expect(boundingBox(boxes)).toEqual({
x: 10,
y: 10,
width: 210,
height: 310
});
});
it("returns countaing box of three boxes", () => {
const boxes = [
{ x: 10, y: 10, width: 100, height: 100 },
{ x: 120, y: 220, width: 100, height: 100 },
{ x: 3, y: 220, width: 100, height: 100 }
];
expect(boundingBox(boxes)).toEqual({
x: 3,
y: 10,
width: 217,
height: 310
});
});
});
describe("applySnap function", () => {
it("does not apply undefined values", () => {
const original = { x: 10, y: 10 };
const snapped = { x: undefined, y: undefined };
const actual = applySnap(original, snapped);
const expected = original;
expect(actual).toEqual(expected);
});
it("preserves other values on original", () => {
const original = { x: 10, y: 10, foo: "bar" };
const snapped = { x: 50, y: 50 };
const actual = applySnap(original, snapped);
const expected = { x: 50, y: 50, foo: "bar" };
expect(actual).toEqual(expected);
});
it('will clobber original with falsy "0" values', () => {
const original = { x: 10, y: 10 };
const snapped = { x: 0, y: 0 };
const actual = applySnap(original, snapped);
expect(actual).toEqual(snapped);
});
it('will clobber original with falsy "0" values', () => {
const original = { x: 10, y: 10 };
const snapped = { x: 0, y: 0 };
const actual = applySnap(original, snapped);
expect(actual).toEqual(snapped);
});
it("can apply multiple snaps", () => {
const original = { x: 10, y: 10 };
const snapped1 = { x: 0 };
const snapped2 = { y: 0 };
const actual = applySnap(original, snapped1, snapped2);
const expected = { x: 0, y: 0 };
expect(actual).toEqual(expected);
});
it("the last snap wins", () => {
const original = { x: 10, y: 10 };
const snapped1 = { x: 50, y: 20 };
const snapped2 = { x: 60, y: 60 };
const actual = applySnap(original, snapped1, snapped2);
const expected = { x: 60, y: 60 };
expect(actual).toEqual(expected);
});
describe("applyMultipleDiffs", () => {
it("uses the smallest non-zero value for each axis", () => {
expect(
applyMultipleDiffs({ x: 31, y: -8 }, { x: 0, y: 8 }, { x: 0, y: 0 })
).toEqual({ x: 31, y: 0 });
});
});
});