Farmbot-Web-App/webpack/farm_designer/map/__tests__/garden_map_test.tsx

420 lines
14 KiB
TypeScript

jest.mock("../../../open_farm/icons", () => ({
cachedCrop: jest.fn(() => { return Promise.resolve({ spread: 100 }); })
}));
jest.mock("farmbot-toastr", () => ({ error: jest.fn() }));
jest.mock("../../actions", () => ({
closePlantInfo: jest.fn(),
movePlant: jest.fn(),
unselectPlant: jest.fn(() => jest.fn()),
}));
jest.mock("../../../api/crud", () => ({
initSave: jest.fn(),
edit: () => "edit resource",
save: () => "save resource",
}));
let mockPath = "";
jest.mock("../../../history", () => ({
getPathArray: jest.fn(() => { return mockPath.split("/"); })
}));
import * as React from "react";
import { GardenMap } from "../garden_map";
import { shallow } from "enzyme";
import { GardenMapProps } from "../../interfaces";
import { fakePlant } from "../../../__test_support__/fake_state/resources";
import { Actions } from "../../../constants";
import { initSave } from "../../../api/crud";
import { setEggStatus, EggKeys } from "../easter_eggs/status";
import { movePlant, unselectPlant } from "../../actions";
import { error } from "farmbot-toastr";
function fakeProps(): GardenMapProps {
return {
showPoints: true,
showPlants: true,
showSpread: false,
showFarmbot: false,
showImages: false,
selectedPlant: fakePlant(),
crops: [],
dispatch: jest.fn(),
designer: {
selectedPlants: undefined,
hoveredPlant: {
plantUUID: "",
icon: ""
},
hoveredPlantListItem: undefined,
cropSearchQuery: "",
cropSearchResults: [{
crop: {
name: "strawberry",
slug: "strawberry",
binomial_name: "",
common_names: [],
description: "",
sun_requirements: "",
sowing_method: "",
processing_pictures: 0
}, image: ""
}],
chosenLocation: { x: undefined, y: undefined, z: undefined },
currentPoint: undefined,
},
plants: [fakePlant(), fakePlant()],
points: [],
toolSlots: [],
botLocationData: {
position: { x: 0, y: 0, z: 0 },
scaled_encoders: { x: undefined, y: undefined, z: undefined },
raw_encoders: { x: undefined, y: undefined, z: undefined },
},
botSize: {
x: { value: 3000, isDefault: true },
y: { value: 1500, isDefault: true }
},
stopAtHome: { x: true, y: true },
hoveredPlant: fakePlant(),
zoomLvl: 1,
botOriginQuadrant: 2,
gridSize: { x: 1000, y: 1000 },
gridOffset: { x: 100, y: 100 },
peripherals: [],
eStopStatus: false,
latestImages: [],
cameraCalibrationData: {
scale: undefined, rotation: undefined,
offset: { x: undefined, y: undefined },
origin: undefined,
calibrationZ: undefined
},
getConfigValue: jest.fn(),
};
}
describe("<GardenPlant/>", () => {
beforeEach(function () {
jest.clearAllMocks();
Object.defineProperty(document, "querySelector", {
value: () => { return { scrollLeft: 1, scrollTop: 2 }; },
configurable: true
});
Object.defineProperty(window, "getComputedStyle", {
value: () => { return { zoom: 1 }; }, configurable: true
});
});
it("drops plant", () => {
const p = fakeProps();
const dispatch = jest.fn();
p.dispatch = dispatch;
const wrapper = shallow(<GardenMap {...p} />);
mockPath = "/app/designer/plants/crop_search/strawberry/add";
wrapper.find("#drop-area-svg").simulate("click", {
preventDefault: jest.fn()
});
expect(initSave).toHaveBeenCalledWith(expect.objectContaining({
body: expect.objectContaining({ name: "strawberry" })
}));
});
it("doesn't drop plant: error", () => {
const wrapper = shallow(<GardenMap {...fakeProps()} />);
mockPath = "/app/designer/plants/crop_search/aplant/add";
Object.defineProperty(document, "querySelector", {
value: () => { }, configurable: true
});
const add = () =>
wrapper.find("#drop-area-svg").simulate("click", {
preventDefault: jest.fn()
});
expect(add).toThrow(/while trying to add a plant./);
});
it("doesn't drop plant: outside planting area", () => {
const wrapper = shallow(<GardenMap {...fakeProps()} />);
mockPath = "/app/designer/plants/crop_search/aplant/add";
wrapper.find("#drop-area-svg").simulate("click", {
preventDefault: jest.fn(), pageX: -100, pageY: -100
});
expect(error).toHaveBeenCalledWith(
expect.stringContaining("Outside of planting area"));
});
it("starts drag and sets activeSpread", async () => {
const wrapper = shallow(<GardenMap {...fakeProps()} />);
expect(wrapper.state()).toEqual({});
mockPath = "/app/designer/plants/1/edit/";
await wrapper.find("#drop-area-svg").simulate("mouseDown");
expect(wrapper.state()).toEqual({
activeDragSpread: 1000,
isDragging: true
});
});
it("ends drag", () => {
const p = fakeProps();
const wrapper = shallow(<GardenMap {...p} />);
expect(wrapper.state()).toEqual({});
wrapper.find("#drop-area-svg").simulate("mouseUp");
expect(p.dispatch).not.toHaveBeenCalled();
expect(wrapper.state()).toEqual({
activeDragSpread: undefined,
activeDragXY: { x: undefined, y: undefined, z: undefined },
isDragging: false,
pageX: 0,
pageY: 0
});
wrapper.setState({ isDragging: true });
wrapper.find("#drop-area-svg").simulate("mouseUp");
expect(p.dispatch).toHaveBeenCalled();
expect(wrapper.state().isDragging).toBeFalsy();
});
it("drags: editing", () => {
mockPath = "/app/designer/plants/1/edit";
Object.defineProperty(window, "getComputedStyle", {
value: () => { return { zoom: 0.5 }; }, configurable: true
});
const p = fakeProps();
const wrapper = shallow(<GardenMap {...p} />);
expect(wrapper.state()).toEqual({});
wrapper.find("#drop-area-svg").simulate("mouseMove");
expect(p.dispatch).not.toHaveBeenCalled();
expect(wrapper.state()).toEqual({});
wrapper.setState({ isDragging: true, pageX: 200, pageY: 300 });
wrapper.find("#drop-area-svg").simulate("mouseMove", {
pageX: 400, pageY: 500
});
expect(wrapper.state()).toEqual({
activeDragXY: { x: 500, y: 600, z: 0 },
isDragging: true,
pageX: 400,
pageY: 500
});
expect(movePlant).toHaveBeenCalledWith(expect.objectContaining({
deltaX: 400, deltaY: 400
}));
});
it("drags: editing, zoom undefined", () => {
mockPath = "/app/designer/plants/1/edit";
Object.defineProperty(window, "getComputedStyle", {
value: () => { return { zoom: undefined }; }, configurable: true
});
const p = fakeProps();
const wrapper = shallow(<GardenMap {...p} />);
expect(wrapper.state()).toEqual({});
wrapper.find("#drop-area-svg").simulate("mouseMove");
expect(p.dispatch).not.toHaveBeenCalled();
expect(wrapper.state()).toEqual({});
wrapper.setState({ isDragging: true, pageX: 300, pageY: 400 });
wrapper.find("#drop-area-svg").simulate("mouseMove", {
pageX: 400, pageY: 500
});
expect(wrapper.state()).toEqual({
activeDragXY: { x: 200, y: 300, z: 0 },
isDragging: true,
pageX: 400,
pageY: 500
});
expect(movePlant).toHaveBeenCalledWith(expect.objectContaining({
deltaX: 100, deltaY: 100
}));
});
it("drags: editing, X&Y swapped", () => {
mockPath = "/app/designer/plants/1/edit";
const p = fakeProps();
p.getConfigValue = () => true;
p.botOriginQuadrant = 1;
const wrapper = shallow(<GardenMap {...p} />);
expect(wrapper.state()).toEqual({});
wrapper.find("#drop-area-svg").simulate("mouseMove");
expect(p.dispatch).not.toHaveBeenCalled();
expect(wrapper.state()).toEqual({});
wrapper.setState({ isDragging: true, pageX: 300, pageY: 500 });
wrapper.find("#drop-area-svg").simulate("mouseMove", {
pageX: 400, pageY: 500
});
expect(wrapper.state()).toEqual({
activeDragXY: { x: -100, y: 300, z: 0 },
isDragging: true,
pageX: 500,
pageY: 400
});
expect(movePlant).toHaveBeenCalledWith(expect.objectContaining({
deltaX: -200, deltaY: 100
}));
});
it("starts drag: selecting", async () => {
const p = fakeProps();
const wrapper = shallow(<GardenMap {...p} />);
expect(wrapper.state()).toEqual({});
mockPath = "/app/designer/plants/select";
await wrapper.find("#drop-area-svg").simulate("mouseDown", {
pageX: 1000, pageY: 2000
});
expect(wrapper.state()).toEqual({
selectionBox: {
x0: 580, y0: 1790, x1: undefined, y1: undefined
}
});
expect(p.dispatch).toHaveBeenCalledWith({
payload: undefined,
type: Actions.SELECT_PLANT
});
});
it("drags: selecting", () => {
mockPath = "/app/designer/plants/select";
const p = fakeProps();
const wrapper = shallow(<GardenMap {...p} />);
expect(wrapper.state()).toEqual({});
wrapper.find("#drop-area-svg").simulate("mouseMove");
expect(p.dispatch).not.toHaveBeenCalled();
expect(wrapper.state()).toEqual({});
wrapper.setState({
selectionBox: {
x0: 0, y0: 0, x1: undefined, y1: undefined
}
});
wrapper.find("#drop-area-svg").simulate("mouseMove", {
pageX: 2000, pageY: 2000
});
expect(wrapper.state()).toEqual({
selectionBox: {
x0: 0, y0: 0, x1: 1580, y1: 1790
}
});
expect(p.dispatch).toHaveBeenCalledWith(expect.objectContaining({
type: Actions.SELECT_PLANT,
payload: [expect.any(String), expect.any(String)]
}));
});
it("selects location", async () => {
const p = fakeProps();
const wrapper = shallow(<GardenMap {...p} />);
expect(wrapper.state()).toEqual({});
mockPath = "/app/designer/plants/move_to";
await wrapper.find("#drop-area-svg").simulate("click", {
pageX: 1000, pageY: 2000, preventDefault: jest.fn()
});
expect(p.dispatch).toHaveBeenCalledWith({
payload: { x: 580, y: 1790, z: 0 },
type: Actions.CHOOSE_LOCATION
});
});
it("selects location: zoom undefined", async () => {
const p = fakeProps();
const wrapper = shallow(<GardenMap {...p} />);
Object.defineProperty(window, "getComputedStyle", {
value: () => { return { zoom: undefined }; }, configurable: true
});
expect(wrapper.state()).toEqual({});
mockPath = "/app/designer/plants/move_to";
await wrapper.find("#drop-area-svg").simulate("click", {
pageX: 1000, pageY: 2000, preventDefault: jest.fn()
});
expect(p.dispatch).toHaveBeenCalledWith({
payload: { x: 580, y: 1790, z: 0 },
type: Actions.CHOOSE_LOCATION
});
});
it("starts drawing point", async () => {
const p = fakeProps();
const wrapper = shallow(<GardenMap {...p} />);
expect(wrapper.state()).toEqual({});
mockPath = "/app/designer/plants/create_point/";
await wrapper.find("#drop-area-svg").simulate("mouseDown", {
pageX: 1, pageY: 2
});
expect(wrapper.state()).toEqual({ isDragging: true });
expect(p.dispatch).toHaveBeenCalledWith({
payload: { cx: -420, cy: -210, r: 0 },
type: Actions.SET_CURRENT_POINT_DATA
});
});
it("sets drawn point radius", async () => {
const p = fakeProps();
p.designer.currentPoint = { cx: -420, cy: -210, r: 0 };
const wrapper = shallow(<GardenMap {...p} />);
expect(wrapper.state()).toEqual({});
mockPath = "/app/designer/plants/create_point/";
wrapper.setState({ isDragging: true });
await wrapper.find("#drop-area-svg").simulate("mouseMove", {
pageX: 10, pageY: 20
});
expect(p.dispatch).toHaveBeenCalledWith({
payload: { cx: -420, cy: -210, r: 22 },
type: Actions.SET_CURRENT_POINT_DATA
});
});
it("lays eggs", () => {
setEggStatus(EggKeys.BRING_ON_THE_BUGS, "");
setEggStatus(EggKeys.BUGS_ARE_STILL_ALIVE, "");
const noEggs = shallow(<GardenMap {...fakeProps()} />);
expect(noEggs.find("Bugs").length).toEqual(0);
setEggStatus(EggKeys.BRING_ON_THE_BUGS, "true");
setEggStatus(EggKeys.BUGS_ARE_STILL_ALIVE, "");
const eggs = shallow(<GardenMap {...fakeProps()} />);
expect(eggs.find("Bugs").length).toEqual(1);
});
const expectHandledDragOver = () => {
const wrapper = shallow(<GardenMap {...fakeProps()} />);
const e = {
dataTransfer: { dropEffect: undefined },
preventDefault: jest.fn()
};
wrapper.find(".drop-area").simulate("dragOver", e);
expect(e.dataTransfer.dropEffect).toEqual("move");
expect(e.preventDefault).toHaveBeenCalled();
};
it(".drop-area: handles drag over (crop page)", () => {
mockPath = "/app/designer/plants/crop_search/mint";
expectHandledDragOver();
});
it(".drop-area: handles drag over (click-to-add mode)", () => {
mockPath = "/app/designer/plants/crop_search/mint/add";
expectHandledDragOver();
});
it(".drop-area: handles drag start", () => {
mockPath = "/app/designer/plants";
const wrapper = shallow(<GardenMap {...fakeProps()} />);
const e = { preventDefault: jest.fn() };
wrapper.find(".drop-area").simulate("dragStart", e);
expect(e.preventDefault).toHaveBeenCalled();
});
it(".drop-area: handles drag enter", () => {
mockPath = "/app/designer/plants/crop_search";
const wrapper = shallow(<GardenMap {...fakeProps()} />);
const e = { preventDefault: jest.fn() };
wrapper.find(".drop-area").simulate("dragEnter", e);
expect(e.preventDefault).toHaveBeenCalled();
});
it("calls unselectPlant on unmount", () => {
const p = fakeProps();
const wrapper = shallow(<GardenMap {...p} />);
// tslint:disable-next-line:no-any
const instance = wrapper.instance() as any;
instance.componentWillUnmount();
expect(unselectPlant).toHaveBeenCalled();
});
});