test cleanup

pull/1130/head
gabrielburnworth 2019-03-11 19:34:49 -07:00
parent 4017f087b9
commit 3ca67764b9
9 changed files with 103 additions and 68 deletions

View File

@ -2,36 +2,50 @@ import { UNBOUND_ROUTES, UnboundRouteConfig } from "../route_config";
import { RouteEnterEvent } from "takeme";
interface ConnectedComponent {
name: string;
WrappedComponent: React.ComponentType;
name: string;
WrappedComponent: React.ComponentType;
}
type Info = UnboundRouteConfig<{}, {}>;
function mapper(bind_to: Function, index: number) {
return bind_to((x: ConnectedComponent, y: ConnectedComponent | undefined, z: Info) => {
if (z.$ == "*") {
expect(x.WrappedComponent.name).toEqual("FourOhFour");
return;
}
const fakeCallback = (
component: ConnectedComponent,
child: ConnectedComponent | undefined,
info: Info
) => {
if (info.$ == "*") {
expect(component.name).toEqual("FourOhFour");
} else {
expect(component.name).toBe("Connect");
expect(component.WrappedComponent.name).toContain(info.key);
if (child && info.children) {
expect(child.name).toBe("Connect");
expect(child.WrappedComponent.name).toContain(info.childKey);
}
}
};
expect(index).toBeGreaterThan(-1);
expect(x.name).toBe("Connect");
expect(x.WrappedComponent.name).toContain(z.key);
if (y && z.children) {
expect(y.name).toBe("Connect");
expect(y.WrappedComponent.name).toContain(z.childKey);
}
});
}
const fakeRouteEnterEvent: RouteEnterEvent = {
params: { splat: "????" },
oldPath: "??",
newPath: "??"
};
describe("UNBOUND_ROUTES", () => {
it("generates correct routes", () => {
const fake: RouteEnterEvent = {
params: { splat: "????" },
oldPath: "??",
newPath: "??"
};
UNBOUND_ROUTES.map(mapper).map(x => { x.enter && x.enter(fake); });
});
it("generates correct routes", () => {
UNBOUND_ROUTES
.map(r => r(fakeCallback))
.map(r => r.enter && r.enter(fakeRouteEnterEvent));
});
it("generates crash route", async () => {
const fakeError = new Error("fake callback error");
const cb = jest.fn()
.mockImplementationOnce(() => { throw fakeError; })
.mockImplementationOnce(x => { expect(x.name).toEqual("Apology"); });
const r = UNBOUND_ROUTES[0](cb);
console.error = jest.fn();
r.enter && await r.enter(fakeRouteEnterEvent);
expect(console.error).toHaveBeenCalledWith(fakeError);
});
});

View File

@ -13,7 +13,7 @@ describe("destroyCatch", () => {
uuid,
statusBeforeError
});
handler(err);
handler(err).catch(() => { });
const expected = destroyNO({ err, uuid, statusBeforeError });
expect(dispatch).toHaveBeenCalledWith(expected);
});

View File

@ -7,7 +7,7 @@ import { Mode } from "../interfaces";
let mockMode = Mode.none;
jest.mock("../util", () => ({
getMode: () => mockMode,
getMapSize: () => ({ h: undefined, w: undefined }),
getMapSize: () => ({ h: 100, w: 100 }),
getGardenCoordinates: jest.fn(),
transformXY: jest.fn(() => ({ qx: 0, qy: 0 })),
transformForQuadrant: jest.fn(),

View File

@ -11,7 +11,8 @@ jest.mock("../../config_storage/actions", () => ({
toggleWebAppBool: jest.fn()
}));
let mockDestroyAllPromise: Promise<void | never> = Promise.reject("error");
let mockDestroyAllPromise: Promise<void | never> =
Promise.reject("error").catch(() => { });
jest.mock("../../api/crud", () => ({
destroyAll: jest.fn(() => mockDestroyAllPromise)
}));
@ -33,14 +34,14 @@ describe("<FarmwareConfigMenu />", () => {
shouldDisplay: () => false,
});
it("calls install 1st party farmwares", () => {
it("calls install 1st party farmware", () => {
const wrapper = mount(<FarmwareConfigMenu {...fakeProps()} />);
const button = wrapper.find("button").first();
expect(button.hasClass("fa-download")).toBeTruthy();
button.simulate("click");
});
it("1st party farmwares all installed", () => {
it("1st party farmware all installed", () => {
const p = fakeProps();
p.firstPartyFwsInstalled = true;
const wrapper = mount(<FarmwareConfigMenu {...p} />);

View File

@ -4,10 +4,11 @@ jest.mock("axios", () => ({
post: jest.fn(() => mockAxiosResponse)
}));
let mockAuth: AuthState | undefined = undefined;
jest.mock("../../session", () => ({
Session: {
replaceToken: jest.fn(),
fetchStoredToken: jest.fn(),
fetchStoredToken: () => mockAuth,
}
}));
@ -33,8 +34,12 @@ import { API } from "../../api";
import { Session } from "../../session";
import { success, error } from "farmbot-toastr";
import { Content } from "../../constants";
import { AuthState } from "../../auth/interfaces";
import { auth } from "../../__test_support__/fake_state/token";
describe("<FrontPage />", () => {
beforeEach(() => { mockAuth = undefined; });
type FormEvent = React.FormEvent<{}>;
const fakeEvent: Partial<FormEvent> = {
preventDefault: jest.fn()
@ -55,8 +60,17 @@ describe("<FrontPage />", () => {
.map(string => expect(el.html()).toContain(string));
});
it("redirects when already logged in", () => {
mockAuth = auth;
location.assign = jest.fn();
const el = mount(<FrontPage />);
el.mount();
expect(location.assign).toHaveBeenCalledWith("/app/controls");
});
it("submits login: success", async () => {
mockAxiosResponse = Promise.resolve({ data: "new data" });
location.assign = jest.fn();
const el = mount<FrontPage>(<FrontPage />);
el.setState({ email: "foo@bar.io", loginPassword: "password" });
await el.instance().submitLogin(fakeEvent as FormEvent);
@ -65,6 +79,7 @@ describe("<FrontPage />", () => {
"://localhost:3000/api/tokens/",
{ user: { email: "foo@bar.io", password: "password" } });
expect(Session.replaceToken).toHaveBeenCalledWith("new data");
expect(location.assign).toHaveBeenCalledWith("/app/controls");
});
it("submits login: not verified", async () => {

View File

@ -69,7 +69,7 @@ export class FrontPage extends React.Component<{}, Partial<FrontPageState>> {
}
componentDidMount() {
if (Session.fetchStoredToken()) { window.location.href = "/app/controls"; }
if (Session.fetchStoredToken()) { window.location.assign("/app/controls"); }
logInit();
API.setBaseUrl(API.fetchBrowserLocation());
this.setState({});
@ -83,7 +83,7 @@ export class FrontPage extends React.Component<{}, Partial<FrontPageState>> {
axios.post<AuthState>(API.current.tokensPath, payload)
.then(resp => {
Session.replaceToken(resp.data);
window.location.href = "/app/controls";
window.location.assign("/app/controls");
}).catch((error: Error) => {
switch (get(error, "response.status")) {
case 451: // TOS was updated; User must agree to terms.

View File

@ -63,7 +63,7 @@ function route<T, U>(info: UnboundRouteConfig<T, U>) {
const child = (await info.getChild())[info.childKey];
callback(comp, child, info);
} else {
callback((await info.getModule())[info.key], undefined, info);
callback(comp, undefined, info);
}
} catch (e) {
console.error(e);
@ -89,8 +89,9 @@ const key = "FarmDesigner";
/** Bind the route to a callback by calling in a function that passes the
callback in as the first argument.
*
* DO NOT RE-ORDER ITEMS FOR READABILITY- they are order dependant.
* DO NOT RE-ORDER ITEMS FOR READABILITY--they are order-dependent.
* Stuff will break if the route order is changed.
* (e.g., must be "a" then "a/:b/c" then "a/:b", 404 must be last, etc.)
*/
export const UNBOUND_ROUTES = [
route({

View File

@ -1,24 +1,20 @@
jest.mock("../../i18n", () => {
return {
detectLanguage: () => Promise.resolve({})
};
});
jest.mock("../../i18n", () => ({ detectLanguage: () => Promise.resolve({}) }));
jest.mock("axios", () => {
return {
post: jest.fn(() => {
return Promise.resolve({
data: { token: { unencoded: {}, encoded: "========" } }
});
})
};
});
const mockToken = { token: { unencoded: {}, encoded: "========" } };
let mockPostResponse = Promise.resolve({ data: mockToken });
jest.mock("axios", () => ({
post: jest.fn(() => mockPostResponse),
}));
jest.mock("../../session", () => ({ Session: { replaceToken: jest.fn() } }));
import * as React from "react";
import { TosUpdate } from "../component";
import { shallow, mount } from "enzyme";
import axios from "axios";
import { API } from "../../api/index";
import { Session } from "../../session";
import { error } from "farmbot-toastr";
type E = React.FormEvent<HTMLInputElement>;
@ -43,27 +39,35 @@ describe("<TosUpdate/>", () => {
expect(wow.setState).toHaveBeenCalledWith({ email: "foo@bar.com" });
});
it("submits a form", () => {
type FormEvent = React.FormEvent<HTMLFormElement>;
const fakeEvent: Partial<FormEvent> = { preventDefault: jest.fn() };
type FormEvent = React.FormEvent<HTMLFormElement>;
const fakeEvent: Partial<FormEvent> = { preventDefault: jest.fn() };
const fake = {
email: "foo@bar.com",
password: "password123",
agree_to_terms: true
};
it("submits a form", async () => {
location.assign = jest.fn();
const i = instance();
i.setState({
email: "foo@bar.com",
password: "password123",
agree_to_terms: true
});
i.forceUpdate();
i.submit(fakeEvent as FormEvent);
i.setState(fake);
await i.submit(fakeEvent as FormEvent);
expect(fakeEvent.preventDefault).toHaveBeenCalled();
const expectation = {
user: {
agree_to_terms: true,
email: "foo@bar.com",
password: "password123"
}
};
expect(axios.post)
.toHaveBeenCalledWith(API.current.tokensPath, expectation);
.toHaveBeenCalledWith(API.current.tokensPath, { user: fake });
expect(Session.replaceToken).toHaveBeenCalledWith(mockToken);
expect(location.assign).toHaveBeenCalledWith("/app/controls");
});
it("errors while submitting", async () => {
mockPostResponse = Promise.reject({ response: { data: ["error"] } });
const i = instance();
i.setState(fake);
await i.submit(fakeEvent as FormEvent);
expect(fakeEvent.preventDefault).toHaveBeenCalled();
await expect(axios.post)
.toHaveBeenCalledWith(API.current.tokensPath, { user: fake });
await expect(error).toHaveBeenCalledWith(expect.stringContaining("error"));
});
it("shows TOS and Privacy links", () => {

View File

@ -38,7 +38,7 @@ export class TosUpdate extends React.Component<Props, Partial<State>> {
.post<AuthState>(API.current.tokensPath, payload)
.then(resp => {
Session.replaceToken(resp.data);
window.location.href = "/app/controls";
window.location.assign("/app/controls");
})
.catch(error => {
logError(prettyPrintApiErrors(error));