test the fixing of fractional indices

mrazator/test-fractional-index-and-granular-history
Ryan Di 1 year ago
parent 741380bd43
commit 5e98047267

@ -59,7 +59,7 @@ const __createSceneForElementsHack__ = (
// ids to Scene instances so that we don't override the editor elements
// mapping.
// We still need to clone the objects themselves to regen references.
scene.replaceAllElements(cloneJSON(elements), false);
scene.replaceAllElements(cloneJSON(elements));
return scene;
};

@ -1,10 +1,13 @@
import { nanoid } from "nanoid";
import {
fixFractionalIndices,
restoreFractionalIndicies,
validateFractionalIndicies,
} from "../fractionalIndex";
import { ExcalidrawElement } from "../element/types";
import { API } from "./helpers/api";
import { arrayToMap } from "../utils";
import { moveAllLeft, moveOneLeft, moveOneRight } from "../zindex";
import { AppState } from "../types";
const createElementWithIndex = (
fractionalIndex: string | null = null,
@ -15,6 +18,30 @@ const createElementWithIndex = (
});
};
const testLengthAndOrder = (
before: ExcalidrawElement[],
after: ExcalidrawElement[],
) => {
// length is not changed
expect(after.length).toBe(before.length);
// order is not changed
expect(after.map((e) => e.id)).deep.equal(before.map((e) => e.id));
};
const testValidity = (elements: ExcalidrawElement[]) => {
expect(validateFractionalIndicies(elements)).toBe(true);
};
const genrateElementsAtLength = (length: number) => {
const elements: ExcalidrawElement[] = [];
for (let i = 0; i < length; i++) {
elements.push(createElementWithIndex());
}
return elements;
};
describe("restoring fractional indicies", () => {
it("restore all null fractional indices", () => {
const randomNumOfElements = Math.floor(Math.random() * 100);
@ -30,14 +57,8 @@ describe("restoring fractional indicies", () => {
const restoredElements = restoreFractionalIndicies(elements);
// length is not changed
expect(restoredElements.length).toBe(randomNumOfElements);
// order is not changed
expect(restoredElements.map((e) => e.id)).deep.equal(
elements.map((e) => e.id),
);
// fractional indices are valid
expect(validateFractionalIndicies(restoredElements)).toBe(true);
testLengthAndOrder(elements, restoredElements);
testValidity(restoredElements);
});
it("restore out of order fractional indices", () => {
@ -50,14 +71,8 @@ describe("restoring fractional indicies", () => {
const restoredElements = restoreFractionalIndicies(elements);
// length is not changed
expect(restoredElements.length).toBe(4);
// order is not changed
expect(restoredElements.map((e) => e.id)).deep.equal(
elements.map((e) => e.id),
);
// fractional indices are valid
expect(validateFractionalIndicies(restoredElements)).toBe(true);
testLengthAndOrder(elements, restoredElements);
testValidity(restoredElements);
// should only fix the second element's fractional index
expect(elements[1].fractionalIndex).not.toEqual(
restoredElements[1].fractionalIndex,
@ -81,14 +96,8 @@ describe("restoring fractional indicies", () => {
const restoredElements = restoreFractionalIndicies(elements);
// length is not changed
expect(restoredElements.length).toBe(randomNumOfElements);
// order is not changed
expect(restoredElements.map((e) => e.id)).deep.equal(
elements.map((e) => e.id),
);
// should've restored fractional indices properly
expect(validateFractionalIndicies(restoredElements)).toBe(true);
testLengthAndOrder(elements, restoredElements);
testValidity(restoredElements);
expect(new Set(restoredElements.map((e) => e.fractionalIndex)).size).toBe(
randomNumOfElements,
);
@ -108,16 +117,213 @@ describe("restoring fractional indicies", () => {
const restoredElements = restoreFractionalIndicies(elements);
// length is not changed
expect(restoredElements.length).toBe(elements.length);
// order is not changed
expect(restoredElements.map((e) => e.id)).deep.equal(
elements.map((e) => e.id),
);
// should've restored fractional indices properly
expect(validateFractionalIndicies(restoredElements)).toBe(true);
testLengthAndOrder(elements, restoredElements);
testValidity(restoredElements);
expect(new Set(restoredElements.map((e) => e.fractionalIndex)).size).toBe(
elements.length,
);
});
});
describe("fix fractional indices", () => {
it("add each new element properly", () => {
const elements = [
createElementWithIndex(),
createElementWithIndex(),
createElementWithIndex(),
createElementWithIndex(),
];
const fixedElements = elements.reduce((acc, el) => {
return fixFractionalIndices([...acc, el], arrayToMap([el]));
}, [] as ExcalidrawElement[]);
testLengthAndOrder(elements, fixedElements);
testValidity(fixedElements);
});
it("add multiple new elements properly", () => {
const elements = genrateElementsAtLength(Math.floor(Math.random() * 100));
const fixedElements = fixFractionalIndices(elements, arrayToMap(elements));
testLengthAndOrder(elements, fixedElements);
testValidity(fixedElements);
const elements2 = genrateElementsAtLength(Math.floor(Math.random() * 100));
const allElements2 = [...elements, ...elements2];
const fixedElements2 = fixFractionalIndices(
allElements2,
arrayToMap(elements2),
);
testLengthAndOrder(allElements2, fixedElements2);
testValidity(fixedElements2);
});
it("fix properly after z-index changes", () => {
const elements = genrateElementsAtLength(Math.random() * 100);
const fixedElements = fixFractionalIndices(elements, arrayToMap(elements));
let randomlySelected = [
...new Set([
fixedElements[Math.floor(Math.random() * fixedElements.length)],
fixedElements[Math.floor(Math.random() * fixedElements.length)],
fixedElements[Math.floor(Math.random() * fixedElements.length)],
fixedElements[Math.floor(Math.random() * fixedElements.length)],
fixedElements[Math.floor(Math.random() * fixedElements.length)],
fixedElements[Math.floor(Math.random() * fixedElements.length)],
fixedElements[Math.floor(Math.random() * fixedElements.length)],
]),
];
const movedOneLeftFixedElements = moveOneLeft(
fixedElements,
randomlySelected.reduce(
(acc, el) => {
acc.selectedElementIds[el.id] = true;
return acc;
},
{
selectedElementIds: {},
} as {
selectedElementIds: Record<string, boolean>;
},
) as any as AppState,
);
testValidity(movedOneLeftFixedElements);
randomlySelected = [
...new Set([
movedOneLeftFixedElements[
Math.floor(Math.random() * fixedElements.length)
],
movedOneLeftFixedElements[
Math.floor(Math.random() * fixedElements.length)
],
movedOneLeftFixedElements[
Math.floor(Math.random() * fixedElements.length)
],
movedOneLeftFixedElements[
Math.floor(Math.random() * fixedElements.length)
],
movedOneLeftFixedElements[
Math.floor(Math.random() * fixedElements.length)
],
movedOneLeftFixedElements[
Math.floor(Math.random() * fixedElements.length)
],
movedOneLeftFixedElements[
Math.floor(Math.random() * fixedElements.length)
],
]),
];
const movedOneRightFixedElements = moveOneRight(
movedOneLeftFixedElements,
randomlySelected.reduce(
(acc, el) => {
acc.selectedElementIds[el.id] = true;
return acc;
},
{
selectedElementIds: {},
} as {
selectedElementIds: Record<string, boolean>;
},
) as any as AppState,
);
testValidity(movedOneRightFixedElements);
randomlySelected = [
...new Set([
movedOneRightFixedElements[
Math.floor(Math.random() * fixedElements.length)
],
movedOneRightFixedElements[
Math.floor(Math.random() * fixedElements.length)
],
movedOneRightFixedElements[
Math.floor(Math.random() * fixedElements.length)
],
movedOneRightFixedElements[
Math.floor(Math.random() * fixedElements.length)
],
movedOneRightFixedElements[
Math.floor(Math.random() * fixedElements.length)
],
movedOneRightFixedElements[
Math.floor(Math.random() * fixedElements.length)
],
movedOneRightFixedElements[
Math.floor(Math.random() * fixedElements.length)
],
]),
];
const movedAllLeftFixedElements = moveAllLeft(
movedOneRightFixedElements,
randomlySelected.reduce(
(acc, el) => {
acc.selectedElementIds[el.id] = true;
return acc;
},
{
selectedElementIds: {},
} as {
selectedElementIds: Record<string, boolean>;
},
) as any as AppState,
) as ExcalidrawElement[];
testValidity(movedAllLeftFixedElements);
randomlySelected = [
...new Set([
movedAllLeftFixedElements[
Math.floor(Math.random() * fixedElements.length)
],
movedAllLeftFixedElements[
Math.floor(Math.random() * fixedElements.length)
],
movedAllLeftFixedElements[
Math.floor(Math.random() * fixedElements.length)
],
movedAllLeftFixedElements[
Math.floor(Math.random() * fixedElements.length)
],
movedAllLeftFixedElements[
Math.floor(Math.random() * fixedElements.length)
],
movedAllLeftFixedElements[
Math.floor(Math.random() * fixedElements.length)
],
movedAllLeftFixedElements[
Math.floor(Math.random() * fixedElements.length)
],
]),
];
const movedAllRightFixedElements = moveAllLeft(
movedAllLeftFixedElements,
randomlySelected.reduce(
(acc, el) => {
acc.selectedElementIds[el.id] = true;
return acc;
},
{
selectedElementIds: {},
} as {
selectedElementIds: Record<string, boolean>;
},
) as any as AppState,
) as ExcalidrawElement[];
testValidity(movedAllRightFixedElements);
});
});

@ -1,4 +1,3 @@
import { bumpVersion } from "./element/mutateElement";
import { isFrameLikeElement } from "./element/typeChecks";
import { ExcalidrawElement, ExcalidrawFrameLikeElement } from "./element/types";
import { fixFractionalIndices } from "./fractionalIndex";

Loading…
Cancel
Save