let mockPath = ""; jest.mock("../../../history", () => ({ getPathArray: jest.fn(() => mockPath.split("/")), history: { getCurrentLocation: () => ({ pathname: mockPath }) } })); import { round, translateScreenToGarden, getBotSize, getMapSize, transformXY, transformForQuadrant, getGardenCoordinates, MapPanelStatus, mapPanelClassName, getMode, cursorAtPlant, allowInteraction, allowGroupAreaInteraction, savedGardenOpen, } 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/1"; expect(getMode()).toEqual(Mode.templateView); mockPath = "/app/designer/groups/1"; expect(getMode()).toEqual(Mode.editGroup); mockPath = ""; expect(getMode()).toEqual(Mode.none); }); }); describe("savedGardenOpen", () => { it("is open", () => { const result = savedGardenOpen(["", "", "", "gardens", "4", ""]); expect(result).toEqual(4); }); }); 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); }); });