tests and cleanup

pull/455/head
gabrielburnworth 2017-09-15 22:51:12 -07:00
parent b1ae7a4e94
commit a263cee971
15 changed files with 270 additions and 120 deletions

View File

@ -2,13 +2,15 @@ jest.mock("fastclick", () => ({
attach: jest.fn(),
}));
jest.mock("react-redux", () => ({
connect: jest.fn()
}));
import * as React from "react";
import { App, AppProps } from "../app";
import { mount } from "enzyme";
import { bot } from "../__test_support__/fake_state/bot";
import { fakeUser } from "../__test_support__/fake_state/resources";
import { createStore } from "redux";
import { reducers } from "../redux/root_reducer";
describe("<App />: Controls Pop-Up", () => {
function fakeProps(): AppProps {
@ -26,8 +28,7 @@ describe("<App />: Controls Pop-Up", () => {
Object.defineProperty(location, "pathname", {
value: "/app/" + page, configurable: true
});
const wrapper = mount(<App {...fakeProps() } />,
{ context: { store: createStore(reducers) } });
const wrapper = mount(<App {...fakeProps() } />);
if (exists) {
expect(wrapper.html()).toContain("controls-popup");
} else {
@ -61,24 +62,21 @@ describe.skip("<App />: Loading", () => {
}
it("MUST_LOADs not loaded", () => {
const wrapper = mount(<App {...fakeProps() } />,
{ context: { store: createStore(reducers) } });
const wrapper = mount(<App {...fakeProps() } />);
expect(wrapper.html()).toContain("spinner");
});
it("MUST_LOADs partially loaded", () => {
const p = fakeProps();
p.loaded = ["sequences"];
const wrapper = mount(<App {...p } />,
{ context: { store: createStore(reducers) } });
const wrapper = mount(<App {...p } />);
expect(wrapper.html()).toContain("spinner");
});
it("MUST_LOADs loaded", () => {
const p = fakeProps();
p.loaded = ["sequences", "regimens", "farm_events", "points"];
const wrapper = mount(<App {...p } />,
{ context: { store: createStore(reducers) } });
const wrapper = mount(<App {...p } />);
expect(wrapper.html()).not.toContain("spinner");
});
});
@ -95,15 +93,13 @@ describe("<App />: NavBar", () => {
}
it("displays links", () => {
const wrapper = mount(<App {...fakeProps() } />,
{ context: { store: createStore(reducers) } });
const wrapper = mount(<App {...fakeProps() } />);
expect(wrapper.text())
.toContain("Farm DesignerControlsDeviceSequencesRegimensToolsFarmware");
});
it("displays ticker", () => {
const wrapper = mount(<App {...fakeProps() } />,
{ context: { store: createStore(reducers) } });
const wrapper = mount(<App {...fakeProps() } />);
expect(wrapper.text()).toContain("No logs yet.");
});
});

View File

@ -0,0 +1,38 @@
jest.mock("react-redux", () => ({
connect: jest.fn()
}));
import * as React from "react";
import { mount } from "enzyme";
import { AddPlant } from "../add_plant";
describe("<AddPlant />", () => {
it("renders", () => {
const props = {
OFSearch: jest.fn(),
cropSearchResults: [{
image: "a",
crop: {
name: "Mint",
slug: "mint",
binomial_name: "",
common_names: [""],
description: "",
sun_requirements: "",
sowing_method: "",
processing_pictures: 1,
svg_icon: "fake_mint_svg"
}
}],
dispatch: jest.fn(),
};
Object.defineProperty(location, "pathname", {
value: "//app/plants/crop_search/mint/add"
});
const wrapper = mount(<AddPlant {...props} />);
expect(wrapper.text()).toContain("Mint");
expect(wrapper.text()).toContain("Done");
expect(wrapper.find("img").props().src)
.toEqual("data:image/svg+xml;utf8,fake_mint_svg");
});
});

View File

@ -0,0 +1,21 @@
jest.mock("react-redux", () => ({
connect: jest.fn()
}));
import * as React from "react";
import { CropCatalog } from "../crop_catalog";
import { mount } from "enzyme";
describe("<CropCatalog />", () => {
it("renders", () => {
const wrapper = mount(
<CropCatalog
OFSearch={jest.fn()}
dispatch={jest.fn()}
cropSearchResults={[]}
cropSearchQuery={""} />);
expect(wrapper.text()).toContain("Choose a crop");
expect(wrapper.find("input").props().placeholder)
.toEqual("Search OpenFarm...");
});
});

View File

@ -0,0 +1,42 @@
jest.mock("react-redux", () => ({
connect: jest.fn()
}));
jest.mock("../../search_selectors", () => ({
findBySlug: () => {
return {
image: "", crop: {
name: "Mint",
slug: "mint",
binomial_name: "",
common_names: [""],
description: "",
sun_requirements: "",
sowing_method: "",
processing_pictures: 1,
svg_icon: "fake_mint_svg"
}
};
}
}));
import * as React from "react";
import { CropInfo } from "../crop_info";
import { shallow } from "enzyme";
describe("<CropInfo />", () => {
it("renders", () => {
Object.defineProperty(location, "pathname", {
value: "//app/plants/crop_search/mint"
});
const wrapper = shallow(
<CropInfo
OFSearch={jest.fn()}
dispatch={jest.fn()}
cropSearchResults={[]} />);
expect(wrapper.text()).toContain("Mint");
expect(wrapper.text()).toContain("Drag and drop into map");
expect(wrapper.find("img").last().props().src)
.toEqual("data:image/svg+xml;utf8,fake_mint_svg");
});
});

View File

@ -0,0 +1,38 @@
jest.mock("react-redux", () => ({
connect: jest.fn()
}));
const mockErr = jest.fn();
jest.mock("farmbot-toastr", () => ({ error: mockErr }));
import * as React from "react";
import { EditPlantInfo } from "../edit_plant_info";
import { mount } from "enzyme";
import { fakePlant } from "../../../__test_support__/fake_state/resources";
describe("<EditPlantInfo />", () => {
it("renders", async () => {
const wrapper = mount(
<EditPlantInfo
push={jest.fn()}
dispatch={jest.fn()}
findPlant={fakePlant} />);
expect(wrapper.text()).toContain("Strawberry Plant 1");
expect(wrapper.text().replace(/\s+/g, " "))
.toContain("Plant Type: Strawberry");
});
it("deletes plant", async () => {
const dispatch = jest.fn(() => { return Promise.resolve(); });
const wrapper = mount(
<EditPlantInfo
push={jest.fn()}
dispatch={dispatch}
findPlant={fakePlant} />);
expect(wrapper.find("button").props().hidden).toBeFalsy();
wrapper.find("button").simulate("click");
expect(dispatch).toHaveBeenCalled();
});
});

View File

@ -1,19 +1,23 @@
jest.mock("react-redux", () => ({
connect: jest.fn()
}));
import * as React from "react";
import { PlantInfo } from "../plant_info";
import { mount } from "enzyme";
import { fakePlant } from "../../../__test_support__/fake_state/resources";
import { createStore } from "redux";
import { reducers } from "../../../redux/root_reducer";
describe("<PlantInfo />", () => {
it("redirects", () => {
it("renders", () => {
const dispatch = jest.fn();
const wrapper = mount(
<PlantInfo
push={jest.fn()}
dispatch={() => dispatch}
findPlant={fakePlant} />,
{ context: { store: createStore(reducers) } });
expect(wrapper.text()).toEqual("Redirecting...");
findPlant={fakePlant} />);
expect(wrapper.text()).toContain("Strawberry Plant 1");
expect(wrapper.text().replace(/\s+/g, " "))
.toContain("Plant Type: Strawberry");
expect(wrapper.find("button").props().hidden).toBeTruthy();
});
});

View File

@ -1,18 +1,20 @@
jest.mock("react-redux", () => ({
connect: jest.fn()
}));
import * as React from "react";
import { Plants } from "../plant_inventory";
import { mount } from "enzyme";
import { fakePlant } from "../../../__test_support__/fake_state/resources";
import { createStore } from "redux";
import { reducers } from "../../../redux/root_reducer";
describe("<PlantInventory />", () => {
it("renders", () => {
const wrapper = mount(
<Plants
plants={[fakePlant()]}
dispatch={jest.fn()} />,
{ context: { store: createStore(reducers) } });
expect(wrapper.text()).toEqual("DesignerPlantsFarm Events");
dispatch={jest.fn()} />);
expect(wrapper.text()).toContain("DesignerPlantsFarm Events");
expect(wrapper.text()).toContain("Strawberry Plant 11 days old");
expect(wrapper.find("input").props().placeholder)
.toEqual("Search your plants...");
});

View File

@ -44,7 +44,7 @@ export class PlantInfo extends PlantInfoBase {
}
render() {
const plant_info = this.plant && this.plant;
const plant_info = this.plant;
return plant_info ? this.default(plant_info) : this.fallback();
}
}

View File

@ -0,0 +1,26 @@
jest.mock("react-redux", () => ({
connect: jest.fn()
}));
import * as React from "react";
import { mount } from "enzyme";
import { FarmwarePage } from "../index";
import { FarmwareProps } from "../../devices/interfaces";
describe("<FarmwarePage />", () => {
it("renders widgets", () => {
const props: FarmwareProps = {
farmwares: {},
syncStatus: "unknown",
env: {},
dispatch: jest.fn(),
currentImage: undefined,
images: []
};
const wrapper = mount(<FarmwarePage {...props} />);
expect(wrapper.text()).toContain("Take Photo");
expect(wrapper.text()).toContain("Farmware");
expect(wrapper.text()).toContain("Camera Calibration");
expect(wrapper.text()).toContain("Weed Detector");
});
});

View File

@ -0,0 +1,16 @@
import { mapStateToProps } from "../state_to_props";
import { fakeState } from "../../__test_support__/fake_state";
describe("mapStateToProps()", () => {
it("sync status unknown", () => {
const props = mapStateToProps(fakeState());
expect(props.syncStatus).toEqual("unknown");
});
it("currentImage undefined", () => {
const props = mapStateToProps(fakeState());
expect(props.currentImage).toBeFalsy();
});
});

View File

@ -0,0 +1,32 @@
import * as React from "react";
import { mount } from "enzyme";
import { CameraCalibration } from "../camera_calibration";
import { CameraCalibrationProps } from "../interfaces";
describe("<CameraCalibration/>", () => {
it("renders", () => {
const props: CameraCalibrationProps = {
dispatch: jest.fn(),
currentImage: undefined,
images: [],
env: {},
iteration: 1,
morph: 2,
blur: 3,
H_LO: 4,
S_LO: 5,
V_LO: 6,
H_HI: 7,
S_HI: 8,
V_HI: 9
};
const wrapper = mount(<CameraCalibration {...props} />);
expect(wrapper.text()).toContain("Camera Calibration");
expect(wrapper.text()).toContain("Color Range");
expect(wrapper.text()).toContain("HUE017947");
expect(wrapper.text()).toContain("SATURATION025558");
expect(wrapper.text()).toContain("VALUE025569");
expect(wrapper.text()).toContain("Processing Parameters");
expect(wrapper.text()).toContain("Scan image");
});
});

View File

@ -9,7 +9,6 @@ export interface CameraCalibrationProps {
dispatch: Function;
images: TaggedImage[];
currentImage: TaggedImage | undefined;
onProcessPhoto(id: number): void;
env: Partial<WD_ENV>;
iteration: number;
morph: number;

View File

@ -30,7 +30,6 @@ export class FarmwarePage extends React.Component<FarmwareProps, {}> {
<Col xs={12} sm={5}>
<CameraCalibration
dispatch={this.props.dispatch}
onProcessPhoto={() => { }}
currentImage={this.props.currentImage}
images={this.props.images}
env={this.props.env}

View File

@ -0,0 +1,29 @@
jest.mock("react-redux", () => ({
connect: jest.fn()
}));
import * as React from "react";
import { mount } from "enzyme";
import { WeedDetector } from "../index";
import { FarmwareProps } from "../../../devices/interfaces";
describe("<WeedDetector />", () => {
it("renders", () => {
const props: FarmwareProps = {
farmwares: {},
syncStatus: "unknown",
env: {},
dispatch: jest.fn(),
currentImage: undefined,
images: []
};
const wrapper = mount(<WeedDetector {...props} />);
expect(wrapper.text()).toContain("Weed Detector");
expect(wrapper.text()).toContain("Color Range");
expect(wrapper.text()).toContain("HUE01793090");
expect(wrapper.text()).toContain("SATURATION025550255");
expect(wrapper.text()).toContain("VALUE025550255");
expect(wrapper.text()).toContain("Processing Parameters");
expect(wrapper.text()).toContain("Scan image");
});
});

View File

@ -1,92 +0,0 @@
import * as React from "react";
import { HSV, HiLo, EnvSliderProps, EnvSliderState } from "./interfaces";
import { RangeSlider } from "@blueprintjs/core/dist/components/slider/rangeSlider";
/** Max HSV allowed by farmbot weed detector. */
const RANGE: Record<HSV, HiLo> = {
H: { lo: 0, hi: 179 },
S: { lo: 0, hi: 255 },
V: { lo: 0, hi: 255 }
};
/** Default HSV if none found on bot. */
const DEFAULTS: Record<HSV, HiLo> = {
H: { lo: 30, hi: 90 },
S: { lo: 50, hi: 255 },
V: { lo: 50, hi: 255 }
};
export class HsvSlider extends React.Component<EnvSliderProps, EnvSliderState> {
constructor() {
super();
this.state = {
sliding: false
};
}
componentDidMount() {
this.onRelease();
}
onChange = (range: [number, number]) => {
this.setState({
hi: range[1],
lo: range[0],
sliding: true
});
}
get name(): HSV {
switch (this.props.name) {
case "H": case "S": case "V": return this.props.name;
default: throw new Error("HSV is bad.");
}
}
/** Triggered on componentDidMount() and when the user snaps the slider to a
* position. */
onRelease = () => {
const cb = this.props.onChange;
if (cb) { cb(this.name, [this.lo, this.hi]); }
this.setState({ sliding: false });
}
/** Retrieves the pair of hi/lo values from the remote end (bot).
* Returns [number, number] if bot is online running the farmware.
* Returns undefined otherwise.
*/
get remoteValues() {
console.error(`FIX THIS!`);
return [];
}
/** The slider's high value */
get hi() {
const { hi } = this.state;
if (this.state.sliding) {
return hi || 1;
} else {
return this.remoteValues[1] || DEFAULTS[this.name].hi || 0;
}
}
/** The slider's low value */
get lo() {
const { lo } = this.state;
if (this.state.sliding) {
return lo || 1;
} else {
return this.remoteValues[1] || DEFAULTS[this.name].lo || 0;
}
}
render() {
return <RangeSlider
onChange={this.onChange}
onRelease={this.onRelease}
labelStepSize={RANGE[this.name].hi}
min={RANGE[this.name].lo}
max={RANGE[this.name].hi}
value={[this.lo, this.hi]} />;
}
}