Farmbot-Web-App/frontend/farm_designer/map/__tests__/util_test.ts

489 lines
15 KiB
TypeScript

let mockPath = "";
jest.mock("../../../history", () => ({
getPathArray: jest.fn(() => mockPath.split("/")),
history: { getCurrentLocation: () => ({ pathname: mockPath }) }
}));
let mockGardenOpen = true;
jest.mock("../../saved_gardens/saved_gardens", () => ({
savedGardenOpen: () => mockGardenOpen,
}));
import {
round,
translateScreenToGarden,
getBotSize,
getMapSize,
transformXY,
transformForQuadrant,
getGardenCoordinates,
MapPanelStatus,
mapPanelClassName,
getMode,
cursorAtPlant,
allowInteraction,
allowGroupAreaInteraction,
} from "../util";
import { McuParams } from "farmbot";
import {
AxisNumberProperty, BotSize, MapTransformProps, Mode,
} from "../interfaces";
import { StepsPerMmXY } from "../../../devices/interfaces";
import {
fakeMapTransformProps,
} from "../../../__test_support__/map_transform_props";
import { fakePlant } from "../../../__test_support__/fake_state/resources";
describe("round()", () => {
it("rounds a number", () => {
expect(round(44)).toEqual(40);
expect(round(98)).toEqual(100);
});
});
describe("mapPanelClassName()", () => {
it("returns correct panel status: short panel", () => {
Object.defineProperty(window, "innerWidth", {
value: 400,
configurable: true
});
mockPath = "/app/designer/move_to";
expect(mapPanelClassName()).toEqual("short-panel");
mockPath = "/app/designer/plants/crop_search/mint/add";
expect(mapPanelClassName()).toEqual("short-panel");
});
it("returns correct panel status: panel open", () => {
Object.defineProperty(window, "innerWidth", {
value: 500,
configurable: true
});
mockPath = "/app/designer/move_to";
expect(mapPanelClassName()).toEqual("panel-open");
mockPath = "/app/designer/plants/crop_search/mint/add";
expect(mapPanelClassName()).toEqual("panel-open");
});
});
describe("translateScreenToGarden()", () => {
it("translates screen coords to garden coords: zoomLvl = 1", () => {
const result = translateScreenToGarden({
mapTransformProps: fakeMapTransformProps(),
page: { x: 520, y: 212 },
scroll: { left: 10, top: 20 },
zoomLvl: 1,
gridOffset: { x: 30, y: 40 },
panelStatus: MapPanelStatus.open,
});
expect(result).toEqual({ x: 180, y: 80 });
});
it("translates screen coords to garden coords: zoomLvl < 1", () => {
const result = translateScreenToGarden({
mapTransformProps: fakeMapTransformProps(),
page: { x: 1132, y: 382 },
scroll: { left: 10, top: 20 },
zoomLvl: 0.33,
gridOffset: { x: 30, y: 40 },
panelStatus: MapPanelStatus.open,
});
expect(result).toEqual({ x: 2470, y: 840 });
});
it("translates screen coords to garden coords: zoomLvl > 1", () => {
const result = translateScreenToGarden({
mapTransformProps: fakeMapTransformProps(),
page: { x: 1132, y: 382 },
scroll: { left: 10, top: 20 },
zoomLvl: 1.5,
gridOffset: { x: 30, y: 40 },
panelStatus: MapPanelStatus.open,
});
expect(result).toEqual({ x: 520, y: 150 });
});
it("translates screen coords to garden coords: other case", () => {
const mapTransformProps = fakeMapTransformProps();
mapTransformProps.quadrant = 3;
mapTransformProps.gridSize = { x: 300, y: 150 };
const result = translateScreenToGarden({
mapTransformProps,
page: { x: 332, y: 132 },
scroll: { left: 10, top: 20 },
zoomLvl: 0.75,
gridOffset: { x: 30, y: 40 },
panelStatus: MapPanelStatus.open,
});
expect(result).toEqual({ x: 0, y: 130 });
});
it("translates screen coords to garden coords: swapped X&Y", () => {
const mapTransformProps = fakeMapTransformProps();
mapTransformProps.xySwap = true;
mapTransformProps.quadrant = 3;
mapTransformProps.gridSize = { x: 150, y: 300 };
const result = translateScreenToGarden({
mapTransformProps,
page: { x: 332, y: 132 },
scroll: { left: 10, top: 20 },
zoomLvl: 0.75,
gridOffset: { x: 30, y: 40 },
panelStatus: MapPanelStatus.open,
});
expect(result).toEqual({ x: 130, y: 0 });
});
it("translates screen coords to garden coords: panel closed", () => {
const result = translateScreenToGarden({
mapTransformProps: fakeMapTransformProps(),
page: { x: 520, y: 212 },
scroll: { left: 10, top: 20 },
zoomLvl: 1,
gridOffset: { x: 30, y: 40 },
panelStatus: MapPanelStatus.closed,
});
expect(result).toEqual({ x: 480, y: 30 });
});
it("translates screen coords to garden coords: short panel", () => {
const result = translateScreenToGarden({
mapTransformProps: fakeMapTransformProps(),
page: { x: 520, y: 412 },
scroll: { left: 10, top: 20 },
zoomLvl: 1,
gridOffset: { x: 30, y: 40 },
panelStatus: MapPanelStatus.short,
});
expect(result).toEqual({ x: 480, y: 40 });
});
});
describe("getbotSize()", () => {
function fakeProps() {
const botMcuParams: McuParams = {
movement_stop_at_max_x: undefined,
movement_stop_at_max_y: undefined,
movement_axis_nr_steps_x: undefined,
movement_axis_nr_steps_y: undefined
};
const stepsPerMmXY: StepsPerMmXY = { x: undefined, y: undefined };
const defaultLength: AxisNumberProperty = { x: 3000, y: 1500 };
return {
botMcuParams,
stepsPerMmXY,
defaultLength
};
}
function expectDefaultSize(botSize: BotSize) {
expect(botSize).toEqual({
x: { value: 3000, isDefault: true },
y: { value: 1500, isDefault: true }
});
}
it("returns default bed size: when settings undefined", () => {
const p = fakeProps();
const botSize = getBotSize(p.botMcuParams, p.stepsPerMmXY, p.defaultLength);
expectDefaultSize(botSize);
});
it("returns default bed size: when stop at max disabled", () => {
const p = fakeProps();
p.botMcuParams = {
movement_stop_at_max_x: 0,
movement_stop_at_max_y: 0,
movement_axis_nr_steps_x: 100,
movement_axis_nr_steps_y: 100
};
const botSize = getBotSize(p.botMcuParams, p.stepsPerMmXY, p.defaultLength);
expectDefaultSize(botSize);
});
it("returns default bed size: when axis length is default", () => {
const p = fakeProps();
p.botMcuParams = {
movement_stop_at_max_x: 1,
movement_stop_at_max_y: 1,
movement_axis_nr_steps_x: 0,
movement_axis_nr_steps_y: 0
};
const botSize = getBotSize(p.botMcuParams, p.stepsPerMmXY, p.defaultLength);
expectDefaultSize(botSize);
});
it("returns default bed size: when steps per mm is 0", () => {
const p = fakeProps();
p.botMcuParams = {
movement_stop_at_max_x: 1,
movement_stop_at_max_y: 1,
movement_axis_nr_steps_x: 100,
movement_axis_nr_steps_y: 100
};
p.stepsPerMmXY = { x: 0, y: 0 };
const botSize = getBotSize(p.botMcuParams, p.stepsPerMmXY, p.defaultLength);
expectDefaultSize(botSize);
});
it("calculates correct bed size: both axes", () => {
const p = fakeProps();
p.botMcuParams = {
movement_stop_at_max_x: 1,
movement_stop_at_max_y: 1,
movement_axis_nr_steps_x: 500,
movement_axis_nr_steps_y: 1400
};
p.stepsPerMmXY = { x: 5, y: 7 };
const botSize = getBotSize(p.botMcuParams, p.stepsPerMmXY, p.defaultLength);
expect(botSize).toEqual({
x: { value: 100, isDefault: false },
y: { value: 200, isDefault: false }
});
});
it("calculates correct bed size: one axis", () => {
const p = fakeProps();
p.botMcuParams = {
movement_stop_at_max_x: 0,
movement_stop_at_max_y: 1,
movement_axis_nr_steps_x: 500,
movement_axis_nr_steps_y: 1400
};
p.stepsPerMmXY = { x: 5, y: 7 };
const botSize = getBotSize(p.botMcuParams, p.stepsPerMmXY, p.defaultLength);
expect(botSize).toEqual({
x: { value: 3000, isDefault: true },
y: { value: 200, isDefault: false }
});
});
});
describe("getMapSize()", () => {
it("calculates map size", () => {
const mapSize = getMapSize(
fakeMapTransformProps(),
{ x: 100, y: 50 });
expect(mapSize).toEqual({ h: 1600, w: 3200 });
});
it("calculates map size: X&Y Swapped", () => {
const fakeMPT = fakeMapTransformProps();
fakeMPT.xySwap = true;
const mapSize = getMapSize(
fakeMPT,
{ x: 100, y: 50 });
expect(mapSize).toEqual({ h: 3200, w: 1600 });
});
});
describe("transformXY", () => {
const mapTransformProps = fakeMapTransformProps();
mapTransformProps.gridSize = { x: 2000, y: 1000 };
type QXY = { qx: number, qy: number };
const transformCheck =
(original: QXY, transformed: QXY, transformProps: MapTransformProps) => {
transformProps.xySwap = false;
expect(transformXY(original.qx, original.qy, transformProps))
.toEqual(transformed);
expect(transformXY(transformed.qx, transformed.qy, transformProps))
.toEqual(original);
transformProps.xySwap = true;
const transformedYX = { qx: transformed.qy, qy: transformed.qx };
expect(transformXY(original.qx, original.qy, transformProps))
.toEqual(transformedYX);
expect(transformXY(transformed.qx, transformed.qy, transformProps))
.toEqual({ qx: original.qy, qy: original.qx });
};
it("calculates transformed coordinate: quadrant 2", () => {
const original = { qx: 100, qy: 200 };
const transformed = { qx: 100, qy: 200 };
mapTransformProps.quadrant = 2;
transformCheck(original, transformed, mapTransformProps);
});
it("calculates transformed coordinate: quadrant 4", () => {
const original = { qx: 100, qy: 200 };
const transformed = { qx: 1900, qy: 800 };
mapTransformProps.quadrant = 4;
transformCheck(original, transformed, mapTransformProps);
});
it("calculates transformed coordinate: quadrant 4 (outside of grid)", () => {
const original = { qx: 2200, qy: 1100 };
const transformed = { qx: -200, qy: -100 };
mapTransformProps.quadrant = 4;
transformCheck(original, transformed, mapTransformProps);
});
});
describe("transformForQuadrant()", () => {
const mapTransformProps = fakeMapTransformProps();
mapTransformProps.gridSize = { x: 200, y: 100 };
it("calculates transform for quadrant 1", () => {
mapTransformProps.quadrant = 1;
expect(transformForQuadrant(mapTransformProps))
.toEqual("scale(-1, 1) translate(-200, 0)");
});
it("calculates transform for quadrant 2", () => {
mapTransformProps.quadrant = 2;
expect(transformForQuadrant(mapTransformProps))
.toEqual("scale(1, 1) translate(0, 0)");
});
it("calculates transform for quadrant 3", () => {
mapTransformProps.quadrant = 3;
expect(transformForQuadrant(mapTransformProps))
.toEqual("scale(1, -1) translate(0, -100)");
});
it("calculates transform for quadrant 4", () => {
mapTransformProps.quadrant = 4;
expect(transformForQuadrant(mapTransformProps))
.toEqual("scale(-1, -1) translate(-200, -100)");
});
});
describe("getMode()", () => {
it("returns correct Mode", () => {
mockPath = "/app/designer/plants/crop_search/mint/add";
expect(getMode()).toEqual(Mode.clickToAdd);
mockPath = "/app/designer/plants/1/edit";
expect(getMode()).toEqual(Mode.editPlant);
mockPath = "/app/designer/gardens/templates/1/edit";
expect(getMode()).toEqual(Mode.editPlant);
mockPath = "/app/designer/plants/1";
expect(getMode()).toEqual(Mode.editPlant);
mockPath = "/app/designer/gardens/templates/1";
expect(getMode()).toEqual(Mode.editPlant);
mockPath = "/app/designer/plants/select";
expect(getMode()).toEqual(Mode.boxSelect);
mockPath = "/app/designer/plants/crop_search/mint";
expect(getMode()).toEqual(Mode.addPlant);
mockPath = "/app/designer/move_to";
expect(getMode()).toEqual(Mode.moveTo);
mockPath = "/app/designer/points";
expect(getMode()).toEqual(Mode.points);
mockPath = "/app/designer/points/add";
expect(getMode()).toEqual(Mode.createPoint);
mockPath = "/app/designer/weeds";
expect(getMode()).toEqual(Mode.weeds);
mockPath = "/app/designer/weeds/add";
expect(getMode()).toEqual(Mode.createWeed);
mockPath = "/app/designer/gardens";
mockGardenOpen = true;
expect(getMode()).toEqual(Mode.templateView);
mockPath = "/app/designer/groups/1";
expect(getMode()).toEqual(Mode.editGroup);
mockPath = "";
mockGardenOpen = false;
expect(getMode()).toEqual(Mode.none);
});
});
describe("getGardenCoordinates()", () => {
beforeEach(() => {
Object.defineProperty(document, "querySelector", {
value: () => ({ scrollLeft: 1, scrollTop: 2 }),
configurable: true
});
Object.defineProperty(window, "getComputedStyle", {
value: () => ({ transform: "scale(1)" }), configurable: true
});
});
const fakeProps = () => ({
mapTransformProps: fakeMapTransformProps(),
gridOffset: { x: 10, y: 20 },
pageX: 500,
pageY: 200,
});
it("returns garden coordinates", () => {
const result = getGardenCoordinates(fakeProps());
expect(result).toEqual({ x: 170, y: 70 });
});
it("falls back to zoom level", () => {
Object.defineProperty(window, "getComputedStyle", {
value: () => ({ transform: undefined }), configurable: true
});
const result = getGardenCoordinates(fakeProps());
expect(result).toEqual({ x: 170, y: 70 });
});
it("returns undefined", () => {
Object.defineProperty(document, "querySelector", {
value: () => { },
configurable: true
});
const result = getGardenCoordinates(fakeProps());
expect(result).toEqual(undefined);
});
});
describe("allowInteraction()", () => {
it("allows interaction", () => {
mockPath = "/app/designer/plants";
expect(allowInteraction()).toBeTruthy();
});
it("disallows interaction", () => {
mockPath = "/app/designer/plants/crop_search/mint/add";
expect(allowInteraction()).toBeFalsy();
mockPath = "/app/designer/move_to";
expect(allowInteraction()).toBeFalsy();
mockPath = "/app/designer/points/add";
expect(allowInteraction()).toBeFalsy();
mockPath = "/app/designer/weeds/add";
expect(allowInteraction()).toBeFalsy();
});
});
describe("allowGroupAreaInteraction()", () => {
it("allows interaction", () => {
mockPath = "/app/designer/plants";
expect(allowGroupAreaInteraction()).toBeTruthy();
});
it("disallows interaction", () => {
mockPath = "/app/designer/plants/select";
expect(allowGroupAreaInteraction()).toBeFalsy();
mockPath = "/app/designer/move_to";
expect(allowGroupAreaInteraction()).toBeFalsy();
mockPath = "/app/designer/groups/1";
expect(allowGroupAreaInteraction()).toBeFalsy();
});
});
describe("cursorAtPlant()", () => {
const plant = fakePlant();
plant.body.radius = 25;
plant.body.x = 100;
plant.body.y = 200;
const isAwayFromPlant = (cursor: { x: number, y: number } | undefined) =>
expect(cursorAtPlant(plant, cursor)).toBeFalsy();
const isAtPlant = (cursor: { x: number, y: number } | undefined) =>
expect(cursorAtPlant(plant, cursor)).toBeTruthy();
it("cursor is at the plant", () => {
isAtPlant({ x: 100, y: 200 });
isAtPlant({ x: 75, y: 175 });
isAtPlant({ x: 125, y: 225 });
});
it("cursor is away from the plant", () => {
isAwayFromPlant({ x: 140, y: 200 });
isAwayFromPlant({ x: 60, y: 200 });
isAwayFromPlant({ x: 100, y: 240 });
isAwayFromPlant({ x: 100, y: 160 });
isAwayFromPlant(undefined);
});
});