Stock tools button and bot position logs (#546)

* add button to add stock tools

* show bot position in logs

* controls page test
pull/547/head
Gabriel Burnworth 2017-11-29 13:14:04 -08:00 committed by Rick Carlino
parent 44283e020c
commit 0a8dedcc66
7 changed files with 134 additions and 34 deletions

View File

@ -0,0 +1,55 @@
jest.mock("react-redux", () => ({
connect: jest.fn()
}));
const mockStorj: Dictionary<boolean> = {};
jest.mock("../../session", () => {
return {
Session: {
getBool: (k: string) => {
mockStorj[k] = !!mockStorj[k];
return mockStorj[k];
}
}
};
});
import * as React from "react";
import { mount } from "enzyme";
import { Controls } from "../controls";
import { bot } from "../../__test_support__/fake_state/bot";
import { fakePeripheral, fakeWebcamFeed } from "../../__test_support__/fake_state/resources";
import { fakeState } from "../../__test_support__/fake_state";
import { Dictionary } from "farmbot";
import { BooleanSetting } from "../../session_keys";
import { Props } from "../interfaces";
describe("<Controls />", () => {
function fakeProps(): Props {
return {
dispatch: jest.fn(),
bot: bot,
feeds: [fakeWebcamFeed()],
user: undefined,
peripherals: [fakePeripheral()],
resources: fakeState().resources
};
}
it("shows webcam widget", () => {
mockStorj[BooleanSetting.hideWebcamWidget] = false;
const wrapper = mount(<Controls {...fakeProps() } />);
const txt = wrapper.text().toLowerCase();
["webcam", "move", "peripherals"]
.map(string => expect(txt).toContain(string));
});
it("hides webcam widget", () => {
mockStorj[BooleanSetting.hideWebcamWidget] = true;
const wrapper = mount(<Controls {...fakeProps() } />);
const txt = wrapper.text().toLowerCase();
["move", "peripherals"].map(string => expect(txt).toContain(string));
expect(txt).not.toContain("webcam");
});
});

View File

@ -56,24 +56,24 @@ export class Peripherals extends React.Component<PeripheralsProps, PeripheralSta
}
}
emptyPeripheral = (): TaggedPeripheral => {
taggedPeripheral = (pin: number, label: string): TaggedPeripheral => {
return {
uuid: "WILL_BE_CHANGED_BY_REDUCER",
specialStatus: SpecialStatus.SAVED,
kind: "Peripheral",
body: { pin: 0, label: "New Peripheral" }
body: { pin, label }
};
}
emptyPeripheral = (): TaggedPeripheral => {
return this.taggedPeripheral(0, "New Peripheral");
}
farmduinoPeripherals = (dispatch: Function) => {
function newPeripheral(pin: number, label: string) {
dispatch(init({
uuid: "WILL_BE_CHANGED_BY_REDUCER",
specialStatus: SpecialStatus.SAVED,
kind: "Peripheral",
body: { pin, label }
}));
}
const newPeripheral = (pin: number, label: string) => {
dispatch(init(this.taggedPeripheral(pin, label)));
};
newPeripheral(7, "Lighting");
newPeripheral(8, "Water");
newPeripheral(9, "Vacuum");

View File

@ -25,7 +25,12 @@ export interface SelectOptionsParams {
export interface Log {
id?: number | undefined;
message: string;
meta: { type: ALLOWED_MESSAGE_TYPES; };
meta: {
type: ALLOWED_MESSAGE_TYPES;
x?: number;
y?: number;
z?: number;
};
channels: string[];
created_at: number;
}

View File

@ -59,6 +59,17 @@ describe("<Logs />", () => {
expect(filterBtn.text().toLowerCase()).toEqual("filters active");
expect(filterBtn.hasClass("green")).toBeTruthy();
});
it("shows position", () => {
const logs = fakeLogs();
logs[0].body.meta.x = 100;
logs[1].body.meta.x = 0;
logs[1].body.meta.y = 1;
logs[1].body.meta.z = 2;
const wrapper = mount(<Logs logs={logs} />);
expect(wrapper.text()).toContain("Unknown");
expect(wrapper.text()).toContain("0, 1, 2");
});
});
describe("<LogsFilterMenu />", () => {

View File

@ -19,7 +19,7 @@ const LogsTable = (props: LogsTableProps) => {
<tr>
<th><label>{t("Type")}</label></th>
<th><label>{t("Message")}</label></th>
{/* <th><label>{t("Position (x, y, z)")}</label></th> */}
<th><label>{t("Position (x, y, z)")}</label></th>
<th><label>{t("Time")}</label></th>
</tr>
</thead>
@ -38,6 +38,7 @@ const LogsRow = (tlog: TaggedLog, state: LogsState) => {
const type = (log.meta || {}).type;
const filtered = state[type as keyof LogsState];
const displayLog = _.isUndefined(filtered) || filtered;
const { x, y, z } = log.meta;
return displayLog ?
<tr key={tlog.uuid}>
<td>
@ -47,7 +48,13 @@ const LogsRow = (tlog: TaggedLog, state: LogsState) => {
<td>
{log.message || "Loading"}
</td>
{/* <td>0, 0, 0</td> // TODO: display log position data*/}
<td>
{
(_.isNumber(x) && _.isNumber(y) && _.isNumber(z))
? `${x}, ${y}, ${z}`
: "Unknown"
}
</td>
<td>
{time}
</td>

View File

@ -1,31 +1,30 @@
import * as React from "react";
import { ToolForm } from "../tool_form";
import { render } from "enzyme";
import { mapStateToProps } from "../../state_to_props";
import { fakeState } from "../../../__test_support__/fake_state";
import { mount } from "enzyme";
import { fakeTool } from "../../../__test_support__/fake_state/resources";
describe("<ToolForm/>", () => {
function bootstrapTest() {
const state = fakeState();
const toggle = jest.fn();
const props = mapStateToProps(state);
function fakeProps() {
return {
state,
toggle,
props,
component: render(<ToolForm dispatch={state.dispatch}
tools={props.tools}
toggle={toggle} />)
dispatch: jest.fn(),
toggle: jest.fn(),
tools: [fakeTool(), fakeTool()]
};
}
it("renders", () => {
const test = bootstrapTest();
// FAILED
expect(test.component.find("input").length)
.toEqual(test.props.tools.length);
const p = fakeProps();
const wrapper = mount(<ToolForm {...p} />);
expect(wrapper.find("input").length).toEqual(p.tools.length);
});
it("shows a DIRTY flag when any of the tools are dirty", () => {
pending("Might not need this test- seems to be testing getArrayStatus()");
it("adds stock tools", () => {
const p = fakeProps();
const wrapper = mount(<ToolForm {...p} />);
const add = wrapper.find("button").at(3);
expect(add.text()).toEqual("Stock Tools");
add.simulate("click");
expect(p.dispatch).toHaveBeenCalledTimes(6);
});
});

View File

@ -15,15 +15,32 @@ import { edit, destroy, init, saveAll } from "../../api/crud";
import { ToolTips } from "../../constants";
export class ToolForm extends React.Component<ToolFormProps, {}> {
emptyTool = (): TaggedTool => {
taggedTool = (name: string): TaggedTool => {
return {
uuid: "ERROR: GENERATED BY REDUCER - UUID SHOULD BE UNSEEN",
specialStatus: SpecialStatus.SAVED,
kind: "Tool",
body: { name: "Tool " + (this.props.tools.length + 1) }
body: { name }
};
}
emptyTool = (): TaggedTool => {
return this.taggedTool("Tool " + (this.props.tools.length + 1));
}
stockTools = (dispatch: Function) => {
const newTool = (name: string) => {
dispatch(init(this.taggedTool(name)));
};
newTool("Seeder");
newTool("Watering Nozzle");
newTool("Weeder");
newTool("Soil Sensor");
newTool("Seed Bin");
newTool("Seed Tray");
}
render() {
const toggle = () => this.props.toggle();
const { dispatch, tools } = this.props;
@ -46,6 +63,12 @@ export class ToolForm extends React.Component<ToolFormProps, {}> {
onClick={() => { dispatch(init(this.emptyTool())); }}>
<i className="fa fa-plus" />
</button>
<button
className="fb-button green"
onClick={() => { this.stockTools(dispatch); }}>
<i className="fa fa-plus" style={{ marginRight: "0.5rem" }} />
Stock Tools
</button>
</WidgetHeader>
<WidgetBody>
<Row>