vue-grid-layout
Version:
A draggable and resizable grid layout, as a Vue component.
314 lines (295 loc) • 9.64 kB
JavaScript
// @flow
/* eslint-env jest */
import {
bottom,
collides,
compact,
moveElement,
sortLayoutItemsByRowCol,
validateLayout
} from "../../src/helpers/utils";
describe("bottom", () => {
it("Handles an empty layout as input", () => {
expect(bottom([])).toEqual(0);
});
it("Returns the bottom coordinate of the layout", () => {
expect(
bottom([
{ i: "1", x: 0, y: 1, w: 1, h: 1 },
{ i: "2", x: 1, y: 2, w: 1, h: 1 }
])
).toEqual(3);
});
});
describe("sortLayoutItemsByRowCol", () => {
it("should sort by top to bottom right", () => {
const layout = [
{ x: 1, y: 1, w: 1, h: 1, i: "2" },
{ x: 1, y: 0, w: 1, h: 1, i: "1" },
{ x: 0, y: 1, w: 2, h: 2, i: "3" }
];
expect(sortLayoutItemsByRowCol(layout)).toEqual([
{ x: 1, y: 0, w: 1, h: 1, i: "1" },
{ x: 0, y: 1, w: 2, h: 2, i: "3" },
{ x: 1, y: 1, w: 1, h: 1, i: "2" }
]);
});
});
describe("collides", () => {
it("Returns whether the layout items collide", () => {
expect(
collides(
{ i: "1", x: 0, y: 1, w: 1, h: 1 },
{ i: "2", x: 1, y: 2, w: 1, h: 1 }
)
).toEqual(false);
expect(
collides(
{ i: "1", x: 0, y: 1, w: 1, h: 1 },
{ i: "2", x: 0, y: 1, w: 1, h: 1 }
)
).toEqual(true);
});
});
describe("validateLayout", () => {
it("Validates an empty layout", () => {
validateLayout([]);
});
it("Validates a populated layout", () => {
validateLayout([
{ i: "1", x: 0, y: 1, w: 1, h: 1 },
{ i: "2", x: 1, y: 2, w: 1, h: 1 }
]);
});
it("Throws errors on invalid input", () => {
expect(() => {
validateLayout([
{ i: "1", x: 0, y: 1, w: 1, h: 1 },
{ i: "2", x: 1, y: 2, w: 1 }
]);
}).toThrowError(/layout\[1\]\.h must be a number!/i);
});
});
describe("moveElement", () => {
function compactAndMove(
layout,
layoutItem,
x,
y,
isUserAction,
preventCollision
) {
return compact(
moveElement(
layout,
layoutItem,
x,
y,
isUserAction,
preventCollision
)
);
}
it("Does not change layout when colliding on no rearrangement mode", () => {
const layout = [
{ i: "1", x: 0, y: 1, w: 1, h: 1, moved: false },
{ i: "2", x: 1, y: 2, w: 1, h: 1, moved: false }
];
const layoutItem = layout[0];
expect(
moveElement(
layout,
layoutItem,
1,
2, // x, y
true,
true // isUserAction, preventCollision
)
).toEqual([
{ i: "1", x: 0, y: 1, w: 1, h: 1, moved: false },
{ i: "2", x: 1, y: 2, w: 1, h: 1, moved: false }
]);
});
it("Does change layout when colliding in rearrangement mode", () => {
const layout = [
{ i: "1", x: 0, y: 0, w: 1, h: 1, moved: false },
{ i: "2", x: 1, y: 0, w: 1, h: 1, moved: false }
];
const layoutItem = layout[0];
expect(
moveElement(
layout,
layoutItem,
1,
0, // x, y
true,
false // isUserAction, preventCollision
)
).toEqual([
{ i: "1", x: 1, y: 0, w: 1, h: 1, moved: true },
{ i: "2", x: 1, y: 1, w: 1, h: 1, moved: true }
]);
});
it("Moves elements out of the way without causing panel jumps when compaction is vertical", () => {
const layout = [
{ x: 0, y: 0, w: 1, h: 10, i: "A" },
{ x: 0, y: 10, w: 1, h: 1, i: "B" },
{ x: 0, y: 11, w: 1, h: 1, i: "C" }
];
// move A down slightly so it collides with C; can cause C to jump above B.
// We instead want B to jump above A (it has the room)
const itemA = layout[0];
expect(
compactAndMove(
layout,
itemA,
0,
1, // x, y
true,
false // isUserAction, preventCollision
)
).toEqual([
expect.objectContaining({ x: 0, y: 1, w: 1, h: 10, i: "A" }),
expect.objectContaining({ x: 0, y: 0, w: 1, h: 1, i: "B" }),
expect.objectContaining({ x: 0, y: 11, w: 1, h: 1, i: "C" })
]);
});
it("Calculates the correct collision when moving large object far", () => {
const layout = [
{ x: 0, y: 0, w: 1, h: 10, i: "A" },
{ x: 0, y: 10, w: 1, h: 1, i: "B" },
{ x: 0, y: 11, w: 1, h: 1, i: "C" }
];
// Move A down by 2. This should move B above, but since we don't compact in between,
// C should move below.
const itemA = layout[0];
expect(
moveElement(
layout,
itemA,
0,
2, // x, y
true,
false // isUserAction, preventCollision
)
).toEqual([
expect.objectContaining({ x: 0, y: 2, w: 1, h: 10, i: "A" }),
expect.objectContaining({ x: 0, y: 1, w: 1, h: 1, i: "B" }),
expect.objectContaining({ x: 0, y: 12, w: 1, h: 1, i: "C" })
]);
});
it("Moves elements out of the way without causing panel jumps when compaction is vertical", () => {
const layout = [
{ x: 0, y: 0, w: 1, h: 1, i: "A" },
{ x: 1, y: 0, w: 1, h: 1, i: "B" },
{ x: 0, y: 1, w: 2, h: 2, i: "C" }
];
// move A over slightly so it collides with B; can cause C to jump above B
// this test will check that that does not happen
const itemA = layout[0];
expect(
moveElement(
layout,
itemA,
1,
0, // x, y
true,
false // isUserAction, preventCollision
)
).toEqual([
{ x: 1, y: 0, w: 1, h: 1, i: "A", moved: true },
{ x: 1, y: 1, w: 1, h: 1, i: "B", moved: true },
{ x: 0, y: 2, w: 2, h: 2, i: "C", moved: true }
]);
});
it("Moves one element to another should cause moving down panels, vert compact", () => {
// | A | B |
// |C| D |
const layout = [
{ x: 0, y: 0, w: 2, h: 1, i: "A" },
{ x: 2, y: 0, w: 2, h: 1, i: "B" },
{ x: 0, y: 1, w: 1, h: 1, i: "C" },
{ x: 1, y: 1, w: 3, h: 1, i: "D" }
];
// move B left slightly so it collides with A; can cause C to jump above A
// this test will check that that does not happen
const itemB = layout[1];
expect(
compactAndMove(
layout,
itemB,
1,
0, // x, y
true,
false // isUserAction, preventCollision
)
).toEqual([
expect.objectContaining({ x: 0, y: 1, w: 2, h: 1, i: "A" }),
expect.objectContaining({ x: 1, y: 0, w: 2, h: 1, i: "B" }),
expect.objectContaining({ x: 0, y: 2, w: 1, h: 1, i: "C" }),
expect.objectContaining({ x: 1, y: 2, w: 3, h: 1, i: "D" })
]);
});
it("Moves one element to another should cause moving down panels, vert compact", () => {
// | A |
// |B|C|
// | |
//
// Moving C above A should not move B above A
const layout = [
{ x: 0, y: 0, w: 2, h: 1, i: "A" },
{ x: 0, y: 1, w: 1, h: 1, i: "B" },
{ x: 1, y: 1, w: 1, h: 2, i: "C" }
];
// Move C up.
const itemB = layout[2];
expect(
compactAndMove(
layout,
itemB,
1,
0, // x, y
true,
false // isUserAction, preventCollision
)
).toEqual([
expect.objectContaining({ x: 0, y: 2, w: 2, h: 1, i: "A" }),
expect.objectContaining({ x: 0, y: 3, w: 1, h: 1, i: "B" }),
expect.objectContaining({ x: 1, y: 0, w: 1, h: 2, i: "C" })
]);
});
});
describe("compact vertical", () => {
it("Removes empty vertical space above item", () => {
const layout = [{ i: "1", x: 0, y: 1, w: 1, h: 1 }];
expect(compact(layout, true)).toEqual([
{ i: "1", x: 0, y: 0, w: 1, h: 1, moved: false }
]);
});
it("Resolve collision by moving item further down in array", () => {
const layout = [
{ x: 0, y: 0, w: 1, h: 5, i: "1" },
{ x: 0, y: 1, w: 1, h: 1, i: "2" }
];
expect(compact(layout, true)).toEqual([
{ x: 0, y: 0, w: 1, h: 5, i: "1", moved: false },
{ x: 0, y: 5, w: 1, h: 1, i: "2", moved: false }
]);
});
it("Handles recursive collision by moving new collisions out of the way before moving item down", () => {
const layout = [
{ x: 0, y: 0, w: 2, h: 5, i: "1" },
{ x: 0, y: 0, w: 10, h: 1, i: "2" },
{ x: 5, y: 1, w: 1, h: 1, i: "3" },
{ x: 5, y: 2, w: 1, h: 1, i: "4" },
{ x: 5, y: 3, w: 1, h: 1, i: "5", static: true }
];
expect(compact(layout, true)).toEqual([
{ x: 0, y: 0, w: 2, h: 5, i: "1", moved: false },
{ x: 0, y: 5, w: 10, h: 1, i: "2", moved: false },
{ x: 5, y: 0, w: 1, h: 1, i: "3", moved: false },
{ x: 5, y: 1, w: 1, h: 1, i: "4", moved: false },
{ x: 5, y: 3, w: 1, h: 1, i: "5", moved: false, static: true }
]);
});
});