Adds tests for all components

This commit is contained in:
Patrick McDonagh
2018-04-13 15:52:24 -05:00
parent 568a3eebb3
commit 9f97e05a22
17 changed files with 9580 additions and 283 deletions

View File

@@ -0,0 +1,145 @@
import React from "react";
import { shallow, configure } from "enzyme";
import Adapter from "enzyme-adapter-react-16";
configure({ adapter: new Adapter() });
import _ from "lodash";
import { Controls, mapStateToProps } from "../../app/src/components/Controls";
describe("Controls", () => {
const tags = {
cfg_PID_FlowSP: { value: 0 },
cfg_PID_FluidLevelSP: { value: 0 },
cfg_PID_TubingPressureSP: { value: 0 },
cfg_PID_ManualSP: { value: 0 },
Device_Status_INT: { value: 0 },
sts_PID_Control: { value: 5 }
};
it("should render loading if no tags prop", () => {
const wrapper = shallow(<Controls tags={undefined}/>);
expect(wrapper.find(".loading-notags")).toHaveLength(1);
});
it("should render loading if no Device_Status_INT in tags", () => {
const wrapper = shallow(<Controls tags={_.omit(tags, "Device_Status_INT")} />);
expect(wrapper.find(".loading-nostatus")).toHaveLength(1);
});
it("should render controls div", () => {
const wrapper = shallow(<Controls tags={tags} />);
expect(wrapper.find(".controls")).toHaveLength(1);
});
describe("control parameters", () => {
let writeTag;
beforeEach(() => {
writeTag = jest.fn((tag, val) => {
return {tag, val};
});
});
it("should run the writeTag function with cmd_Start and true on writeStart", () => {
tags.Device_Status_INT.value = 4;
const wrapper = shallow(<Controls tags={tags} writeTag={writeTag} />);
wrapper.find(".start-button").simulate("click", null);
expect(writeTag).toHaveBeenCalledWith("cmd_Start", true);
});
it("should run the writeTag function with cmd_Stop and true on writeStop", () => {
tags.Device_Status_INT.value = 0;
const wrapper = shallow(<Controls tags={tags} writeTag={writeTag} />);
wrapper.find(".stop-button").simulate("click", null);
expect(writeTag).toHaveBeenCalledWith("cmd_Stop", true);
});
it("should disable set button on flowrate select button if parameter already selected", () => {
tags.sts_PID_Control.value = 0;
const wrapper = shallow(<Controls tags={tags} writeTag={writeTag} />);
expect(wrapper.find(".flowrate-select").hasClass("disabled")).toBeTruthy();
});
it("should disable set button on fluidlevel select button if parameter already selected", () => {
tags.sts_PID_Control.value = 1;
const wrapper = shallow(<Controls tags={tags} writeTag={writeTag} />);
expect(wrapper.find(".fluidlevel-select").hasClass("disabled")).toBeTruthy();
});
it("should disable set button on tubingpressure select button if parameter already selected", () => {
tags.sts_PID_Control.value = 2;
const wrapper = shallow(<Controls tags={tags} writeTag={writeTag} />);
expect(wrapper.find(".tubingpressure-select").hasClass("disabled")).toBeTruthy();
});
it("should disable set button on frequency select button if parameter already selected", () => {
tags.sts_PID_Control.value = 3;
const wrapper = shallow(<Controls tags={tags} writeTag={writeTag} />);
expect(wrapper.find(".frequency-select").hasClass("disabled")).toBeTruthy();
});
});
describe("control setpoints", () => {
let writeTag;
let wrapper;
beforeEach(() => {
writeTag = jest.fn((tag, val) => {
return {tag, val};
});
wrapper = shallow(<Controls tags={tags} writeTag={writeTag} />);
});
it("should update setpoint state on setpoint change", () => {
wrapper.find(".flowrate-input").simulate("change", {target: {value: 100.0 }});
expect(wrapper.state().setpoints.flowrate).toEqual(100.0);
wrapper.find(".fluidlevel-input").simulate("change", {target: {value: 200.0 }});
expect(wrapper.state().setpoints.fluidlevel).toEqual(200.0);
wrapper.find(".tubingpressure-input").simulate("change", {target: {value: 300.0 }});
expect(wrapper.state().setpoints.tubingpressure).toEqual(300.0);
wrapper.find(".frequency-input").simulate("change", {target: {value: 400.0 }});
expect(wrapper.state().setpoints.frequency).toEqual(400.0);
});
it("should call writeTag with the setpoint tag and the value", () => {
wrapper.find(".flowrate-input").simulate("change", {target: {value: 100.0 }});
wrapper.find(".flowrate-submit").simulate("click", {preventDefault: jest.fn()});
expect(writeTag).toBeCalledWith("cfg_PID_FlowSP", 100.0);
wrapper.find(".fluidlevel-input").simulate("change", {target: {value: 200.0 }});
wrapper.find(".fluidlevel-submit").simulate("click", {preventDefault: jest.fn()});
expect(writeTag).toBeCalledWith("cfg_PID_FluidLevelSP", 200.0);
wrapper.find(".tubingpressure-input").simulate("change", {target: {value: 300.0 }});
wrapper.find(".tubingpressure-submit").simulate("click", {preventDefault: jest.fn()});
expect(writeTag).toBeCalledWith("cfg_PID_TubingPressureSP", 300.0);
wrapper.find(".frequency-input").simulate("change", {target: {value: 400.0 }});
wrapper.find(".frequency-submit").simulate("click", {preventDefault: jest.fn()});
expect(writeTag).toBeCalledWith("cfg_PID_ManualSP", 400.0);
});
it("should call writeTag with cfg_PID_* and true when selecting control parameter", () => {
wrapper.find(".flowrate-select").simulate("click", {preventDefault: jest.fn()});
expect(writeTag).toHaveBeenCalledWith("cfg_PID_Flow", true);
wrapper.find(".fluidlevel-select").simulate("click", {preventDefault: jest.fn()});
expect(writeTag).toHaveBeenCalledWith("cfg_PID_FluidLevel", true);
wrapper.find(".tubingpressure-select").simulate("click", {preventDefault: jest.fn()});
expect(writeTag).toHaveBeenCalledWith("cfg_PID_TubingPressure", true);
wrapper.find(".frequency-select").simulate("click", {preventDefault: jest.fn()});
expect(writeTag).toHaveBeenCalledWith("cfg_PID_Manual", true);
});
});
it("should map state to props", () => {
expect(mapStateToProps({ tags: "tags", extra: "extra" })).toEqual({ tags: "tags" });
});
});

View File

@@ -0,0 +1,52 @@
import React from "react";
import { shallow, configure } from "enzyme";
import Adapter from "enzyme-adapter-react-16";
configure({ adapter: new Adapter() });
import { EventLog, mapStateToProps } from "../../app/src/components/EventLog";
describe("EventLog", () => {
const writeTag = jest.fn();
it("renders loading div if events not defined", () => {
const wrapper = shallow(<EventLog />);
expect(wrapper.find(".loading")).toHaveLength(1);
expect(wrapper.find(".loading").text()).toMatch("Loading");
});
it("should call writeTag with cmd_ResetAlarms and true on Reset button click", () => {
const wrapper = shallow(<EventLog events={[]} writeTag={writeTag} />);
wrapper.find(".reset-button").simulate("click", null);
expect(writeTag).toBeCalledWith("cmd_ResetAlarms", true);
});
describe("event timeline", () => {
let events, wrapper;
beforeEach(() => {
events = [
{ tag: "test", timestamp: new Date(), eventType: "alarm"},
{ tag: "tttt", timestamp: new Date(), eventType: "cmd" }
];
wrapper = shallow(<EventLog events={events} />);
});
it("should return a Timeline Event for each event", () => {
expect(wrapper.find("TimelineEvent")).toHaveLength(2);
});
it("shows a calendar icon for non-alarm events", () => {
expect(wrapper.find("TimelineEvent").last().html()).toMatch("calendar");
});
it("shows an exclamation triangle for alarm events", () => {
expect(wrapper.find("TimelineEvent").first().html()).toMatch("exclamation-triangle");
});
});
it("should map state to props", () => {
expect(mapStateToProps({ events: "events", extra: "extra" })).toEqual({ events: "events" });
});
});

View File

@@ -0,0 +1,89 @@
import React from "react";
import { shallow, configure } from "enzyme";
import Adapter from "enzyme-adapter-react-16";
configure({ adapter: new Adapter() });
import { Header, mapStateToProps } from "../../app/src/components/Header";
describe("Header", () => {
it("should display a nav item", () => {
const wrapper = shallow(<Header />);
expect(wrapper.find("nav")).toHaveLength(1);
});
describe("alarm button", () => {
it("does not display anything if props haven't been set", () => {
const wrapper = shallow(<Header alarms={undefined} />);
expect(wrapper.find(".no-alarm")).toHaveLength(1);
});
it("renders button for no alarms", () => {
const wrapper = shallow(<Header alarms={[]} />);
expect(wrapper.find(".alarm-button")).toHaveLength(1);
});
it("renders button for alarms", () => {
const wrapper = shallow(<Header alarms={["alarm_Test"]} />);
expect(wrapper.find(".alarm-button")).toHaveLength(1);
});
});
describe("running state indicator", () => {
const tags = {
Device_Status_INT: { name: "Device_Status_INT", value: 0 }
};
it("renders an empty span for no tags", () => {
const wrapper = shallow(<Header alarms={[]} tags={undefined} />);
expect(wrapper.find(".no-tags").text()).toEqual("");
});
it("renders and empty span for tags, but no Device_Status_INT", () => {
const wrapper = shallow(<Header alarms={[]} tags={[]} />);
expect(wrapper.find(".no-device-status").text()).toEqual("");
});
it("renders Running for value 0", () => {
const wrapper = shallow(<Header alarms={[]} tags={tags} />);
expect(wrapper.find(".status-indicator").text()).toMatch("Running");
});
it("renders Pumped Off for value 1", () => {
tags.Device_Status_INT.value = 1;
const wrapper = shallow(<Header alarms={[]} tags={tags} />);
expect(wrapper.find(".status-indicator").text()).toMatch("Pumped Off");
});
it("renders Alarmed for value 2", () => {
tags.Device_Status_INT.value = 2;
const wrapper = shallow(<Header alarms={[]} tags={tags} />);
expect(wrapper.find(".status-indicator").text()).toMatch("Alarmed");
});
it("renders Locked Out for value 3", () => {
tags.Device_Status_INT.value = 3;
const wrapper = shallow(<Header alarms={[]} tags={tags} />);
expect(wrapper.find(".status-indicator").text()).toMatch("Locked Out");
});
it("renders Stopped for value 4", () => {
tags.Device_Status_INT.value = 4;
const wrapper = shallow(<Header alarms={[]} tags={tags} />);
expect(wrapper.find(".status-indicator").text()).toMatch("Stopped");
});
it("renders Unknown for value 5", () => {
tags.Device_Status_INT.value = 5;
const wrapper = shallow(<Header alarms={[]} tags={tags} />);
expect(wrapper.find(".status-indicator").text()).toMatch("Unknown");
});
});
it("should map state to props", () => {
const state = { tags: "tags", alarms: "alarms", extra: "extra"};
expect(mapStateToProps(state)).toEqual({ tags: "tags", alarms: "alarms" });
});
});

View File

@@ -0,0 +1,83 @@
import React from "react";
import { shallow, configure } from "enzyme";
import Adapter from "enzyme-adapter-react-16";
configure({ adapter: new Adapter() });
import { Main, mapStateToProps } from "../../app/src/components/Main";
describe("Main", () => {
const tags = {
val_FluidLevel: { name: "val_FluidLevel", value: 100.0 },
val_Flowmeter_BarrelsPerDay: { name: "val_Flowmeter_BarrelsPerDay", value: 200.0 },
val_TubingPressure: { name: "val_TubingPressure", value: 150.0 },
VFD_OutCurrent: { name: "VFD_OutCurrent", value: 30.0 },
VFD_SpeedFdbk: { name: "VFD_SpeedFdbk", value: 60.0 }
};
const tagHistory = {
val_FluidLevel: [{ timestamp: 0, value: 100.0 }],
val_Flowmeter_BarrelsPerDay: [{ timestamp: 0, value: 200.0 }],
val_TubingPressure: [{ timestamp: 0, value: 150.0 }],
VFD_OutCurrent: [{ timestamp: 0, value: 30.0 }],
VFD_SpeedFdbk: [{ timestamp: 0, value: 60.0 }]
};
it("should render loading div if no tag history", () =>{
const wrapper = shallow(<Main tagHistory={undefined} />);
expect(wrapper.find(".loading").text()).toMatch("Loading");
});
it("should render plc error class if PLC error", () => {
const wrapper = shallow(<Main tagHistory={{}} plc={{ error: true }} />);
expect(wrapper.find(".plc-error").text()).toMatch("PLC Error");
});
it("should render waiting if no tags yet", () => {
const wrapper = shallow(<Main tagHistory={{}} plc={{}} tags={{}} />);
expect(wrapper.find(".waiting").text()).toMatch("Waiting for data");
});
it("should render the main container if everything ready", () => {
const wrapper = shallow(<Main tagHistory={tagHistory} plc={{}} tags={tags} />);
expect(wrapper.find(".main")).toHaveLength(1);
});
describe("tag current values", () => {
let wrapper;
beforeEach(() => {
wrapper = shallow(<Main tagHistory={tagHistory} plc={{}} tags={tags} />);
});
it("should render a liquid fill gauge for all gauges", () => {
expect(wrapper.find(".liquidfill")).toHaveLength(5);
});
it("should render a liquidfill gauge for val_FluidLevel", () => {
expect(wrapper.find(".lqdfill-val_FluidLevel")).toHaveLength(1);
});
it("should render a liquidfill gauge for val_Flowmeter_BarrelsPerDay", () => {
expect(wrapper.find(".lqdfill-val_Flowmeter_BarrelsPerDay")).toHaveLength(1);
});
it("should render a liquidfill gauge for val_TubingPressure", () => {
expect(wrapper.find(".lqdfill-val_TubingPressure")).toHaveLength(1);
});
it("should render a liquidfill gauge for VFD_OutCurrent", () => {
expect(wrapper.find(".lqdfill-VFD_OutCurrent")).toHaveLength(1);
});
it("should render a liquidfill gauge for VFD_SpeedFdbk", () => {
expect(wrapper.find(".lqdfill-VFD_SpeedFdbk")).toHaveLength(1);
});
});
it("should map state to props", () => {
expect(mapStateToProps({ tags: "tags", plc: "plc", tagHistory: "tagHistory", extra: "extra" })).toEqual({ tags: "tags", plc: "plc", tagHistory: "tagHistory" });
});
});

View File

@@ -0,0 +1,53 @@
import React from "react";
import { shallow, configure } from "enzyme";
import Adapter from "enzyme-adapter-react-16";
configure({ adapter: new Adapter() });
import { Permissives, mapStateToProps } from "../../app/src/components/Permissives";
describe("Permissives", () => {
it("should render a loading page if no tags", () => {
const wrapper = shallow(<Permissives tags={undefined} />);
expect(wrapper.find(".loading").text()).toMatch("Loading");
});
it("should render the permissives page", () => {
const wrapper = shallow(<Permissives tags={[]} />);
expect(wrapper.find(".permissives")).toHaveLength(1);
});
it("should render green button for permissive true", () => {
const tags = {
sp_ALL: { value: true },
rp_ALL: { value: true },
sp_Flowmeter: { value: true },
rp_Flowmeter: { value: true },
sp_IntakePressure: { value: true },
rp_IntakePressure: { value: true },
sp_IntakeTemperature: { value: true },
rp_IntakeTemperature: { value: true }
};
const wrapper = shallow(<Permissives tags={tags} />);
expect(wrapper.find(".btn-success")).toHaveLength(8);
});
it("should render red button for permissive false", () => {
const tags = {
sp_ALL: { value: false },
rp_ALL: { value: false },
sp_Flowmeter: { value: false },
rp_Flowmeter: { value: false },
sp_IntakePressure: { value: false },
rp_IntakePressure: { value: false },
sp_IntakeTemperature: { value: false },
rp_IntakeTemperature: { value: false }
};
const wrapper = shallow(<Permissives tags={tags} />);
expect(wrapper.find(".btn-danger")).toHaveLength(8);
});
it("should map state to props correctly", () => {
const state = { tags: "tags", extra: "extra" };
expect(mapStateToProps(state)).toEqual({ tags: "tags" });
});
});

View File

@@ -0,0 +1,109 @@
import React from "react";
import { shallow, configure } from "enzyme";
import Adapter from "enzyme-adapter-react-16";
configure({ adapter: new Adapter() });
import { Settings, mapStateToProps } from "../../app/src/components/Settings";
describe("Settings", () => {
let container;
const testTagList = [
{
name: "test1",
value: 100
},
{
name: "test2",
value: 200
}
];
const plcTestData = {
details: {
name: "test PLC"
},
ipAddress: "192.168.1.10"
};
const setPlcIpAddress = jest.fn((ipAddress) => ipAddress);
const storeNewTag = jest.fn((tagName) => tagName);
const deleteTag = jest.fn((tagName) => tagName);
const ipcPlcInitializeSend = jest.fn((addr, tagList) => {
return {addr, tagList};
});
beforeEach(() => {
container = shallow(
<Settings
plc={plcTestData}
tags={testTagList}
setPlcIpAddress={setPlcIpAddress}
storeNewTag={storeNewTag}
deleteTag={deleteTag}
ipcPlcInitializeSend={ipcPlcInitializeSend}
history={[]}
/>);
});
it("should display a settings item", () => {
expect(container.find(".settings")).toHaveLength(1);
});
describe("ip address field", () => {
it("should update state when ip address changed", () => {
container.find(".ip-address-field").simulate("change", {target: {value: "1.1.1.1"}});
expect(container.state().ipAddress).toEqual("1.1.1.1");
});
it("should run the setPlcIpaddress function when update clicked", () =>{
container.find(".ip-address-field").simulate("change", {target: {value: "1.1.1.1"}});
container.find(".ip-submit-button").simulate("click", {preventDefault: jest.fn()});
expect(setPlcIpAddress).toHaveBeenCalled();
});
it("should not allow setting ip address if ip address not changed", () => {
expect(container.find(".ip-submit-button").hasClass("disabled")).toBeTruthy();
container.find(".ip-address-field").simulate("change", {target: {value: "1.1.1.1"}});
expect(container.find(".ip-submit-button").hasClass("disabled")).toBeFalsy();
});
});
describe("tag list", () => {
it("should have one row for each tag", () => {
expect(container.find(".tag-list li")).toHaveLength(2);
});
it("should update state when new tag input changed", () => {
container.find(".tag-name-input").simulate("change", {target: {value: "testtag"}});
expect(container.state().newTag).toEqual("testtag");
});
it("should run the storeNewTag function on submit button click", () => {
container.find(".tag-name-input").simulate("change", {target: {value: "testtag"}});
container.find(".add-tag-button").simulate("click", {preventDefault: jest.fn()});
expect(storeNewTag).toHaveBeenCalled();
});
it("should run the ipcPlcInitializeSend function on save button click", () => {
container.find(".ip-address-field").simulate("change", {target: {value: "1.1.1.1"}});
container.find(".ip-submit-button").simulate("click", {preventDefault: jest.fn()});
container.find(".tag-name-input").simulate("change", {target: {value: "testtag"}});
container.find(".add-tag-button").simulate("click", {preventDefault: jest.fn()});
container.find(".save-button").simulate("click", {preventDefault: jest.fn()});
expect(ipcPlcInitializeSend).toHaveBeenCalled();
});
it("should run the deleteTag function on delete button click", () => {
container.find(".delete-button").first().simulate("click", {preventDefault: jest.fn()});
expect(deleteTag).toHaveBeenCalled();
});
});
it("should map state to props", () => {
expect(mapStateToProps({ tags: "tags", plc: "plc", extra: "extra" })).toEqual({ tags: "tags", plc: "plc" });
});
});

View File

@@ -0,0 +1,75 @@
import React from "react";
import { shallow, configure } from "enzyme";
import Adapter from "enzyme-adapter-react-16";
configure({ adapter: new Adapter() });
import { TagsIndex, mapStateToProps } from "../../app/src/components/TagsIndex";
describe("TagsIndex", () => {
let container;
beforeEach(() => {
null;
});
it("should display a div for no tags found", () => {
container = shallow(<TagsIndex plc={{}} tags={[]} />);
expect(container.find(".tags-index-notags")).toHaveLength(1);
});
describe("when tags are found", () => {
const testTagList = [
{
name: "test1",
value: 100
},
{
name: "test2",
value: 200
}
];
const plcTestData = {
details: {
name: "test PLC"
},
ipAddress: "192.168.1.10"
};
const writeTag = jest.fn();
beforeEach(() => {
container = shallow(<TagsIndex plc={plcTestData} tags={testTagList} writeTag={writeTag} />);
});
it("should display a div for tags found", () => {
expect(container.find(".tags-index-withtags")).toHaveLength(1);
});
it("should render 1 row for each tag", () => {
expect(container.find(".tags-index-withtags table tbody tr")).toHaveLength(2);
});
it("should display a plc IP address", () => {
expect(container.find(".tags-index-withtags h2").text()).toMatch("192.168.1.10");
});
it("should update state on changing write value", () => {
container.find(".tag-write-input").first().simulate("change", {target: {value: 111.1}});
expect(container.state().writes["test1"]).toEqual(111.1);
});
it("should run the writeTag function when clicking Write", () => {
container.find(".tag-write-input").first().simulate("change", {target: {value: 111.1}});
container.find(".tag-write-button").first().simulate("click", {preventDefault: jest.fn()});
expect(writeTag).toHaveBeenCalled();
});
});
it("should map state to props", () => {
expect(mapStateToProps({ tags: "tags", plc: "plc", extra: "extra" })).toEqual({ tags: "tags", plc: "plc" });
});
});