From 3ca67764b9da20acd215eba83e615ba13da4b198 Mon Sep 17 00:00:00 2001 From: gabrielburnworth Date: Mon, 11 Mar 2019 19:34:49 -0700 Subject: [PATCH] test cleanup --- frontend/__tests__/route_config_test.tsx | 64 ++++++++++------- frontend/api/__tests__/destroy_catch_tests.ts | 2 +- .../map/__tests__/garden_map_test.tsx | 2 +- .../__tests__/farmware_config_menu_test.tsx | 7 +- .../front_page/__tests__/front_page_test.tsx | 17 ++++- frontend/front_page/front_page.tsx | 4 +- frontend/route_config.tsx | 5 +- .../tos_update/__tests__/component_test.tsx | 68 ++++++++++--------- frontend/tos_update/component.tsx | 2 +- 9 files changed, 103 insertions(+), 68 deletions(-) diff --git a/frontend/__tests__/route_config_test.tsx b/frontend/__tests__/route_config_test.tsx index b7a2cf522..ec7980fb6 100644 --- a/frontend/__tests__/route_config_test.tsx +++ b/frontend/__tests__/route_config_test.tsx @@ -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); + }); }); diff --git a/frontend/api/__tests__/destroy_catch_tests.ts b/frontend/api/__tests__/destroy_catch_tests.ts index a666ee15b..3b88f9481 100644 --- a/frontend/api/__tests__/destroy_catch_tests.ts +++ b/frontend/api/__tests__/destroy_catch_tests.ts @@ -13,7 +13,7 @@ describe("destroyCatch", () => { uuid, statusBeforeError }); - handler(err); + handler(err).catch(() => { }); const expected = destroyNO({ err, uuid, statusBeforeError }); expect(dispatch).toHaveBeenCalledWith(expected); }); diff --git a/frontend/farm_designer/map/__tests__/garden_map_test.tsx b/frontend/farm_designer/map/__tests__/garden_map_test.tsx index 663421539..e7bd8352f 100644 --- a/frontend/farm_designer/map/__tests__/garden_map_test.tsx +++ b/frontend/farm_designer/map/__tests__/garden_map_test.tsx @@ -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(), diff --git a/frontend/farmware/__tests__/farmware_config_menu_test.tsx b/frontend/farmware/__tests__/farmware_config_menu_test.tsx index ef7ff4c44..8f2284d8a 100644 --- a/frontend/farmware/__tests__/farmware_config_menu_test.tsx +++ b/frontend/farmware/__tests__/farmware_config_menu_test.tsx @@ -11,7 +11,8 @@ jest.mock("../../config_storage/actions", () => ({ toggleWebAppBool: jest.fn() })); -let mockDestroyAllPromise: Promise = Promise.reject("error"); +let mockDestroyAllPromise: Promise = + Promise.reject("error").catch(() => { }); jest.mock("../../api/crud", () => ({ destroyAll: jest.fn(() => mockDestroyAllPromise) })); @@ -33,14 +34,14 @@ describe("", () => { shouldDisplay: () => false, }); - it("calls install 1st party farmwares", () => { + it("calls install 1st party farmware", () => { const wrapper = mount(); 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(); diff --git a/frontend/front_page/__tests__/front_page_test.tsx b/frontend/front_page/__tests__/front_page_test.tsx index 0a3b51e86..1de0c4de3 100644 --- a/frontend/front_page/__tests__/front_page_test.tsx +++ b/frontend/front_page/__tests__/front_page_test.tsx @@ -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("", () => { + beforeEach(() => { mockAuth = undefined; }); + type FormEvent = React.FormEvent<{}>; const fakeEvent: Partial = { preventDefault: jest.fn() @@ -55,8 +60,17 @@ describe("", () => { .map(string => expect(el.html()).toContain(string)); }); + it("redirects when already logged in", () => { + mockAuth = auth; + location.assign = jest.fn(); + const el = mount(); + 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(); el.setState({ email: "foo@bar.io", loginPassword: "password" }); await el.instance().submitLogin(fakeEvent as FormEvent); @@ -65,6 +79,7 @@ describe("", () => { "://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 () => { diff --git a/frontend/front_page/front_page.tsx b/frontend/front_page/front_page.tsx index 4abe376dd..48c3dabd1 100644 --- a/frontend/front_page/front_page.tsx +++ b/frontend/front_page/front_page.tsx @@ -69,7 +69,7 @@ export class FrontPage extends React.Component<{}, Partial> { } 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> { axios.post(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. diff --git a/frontend/route_config.tsx b/frontend/route_config.tsx index adb6dc5cf..b0fb8594a 100644 --- a/frontend/route_config.tsx +++ b/frontend/route_config.tsx @@ -63,7 +63,7 @@ function route(info: UnboundRouteConfig) { 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({ diff --git a/frontend/tos_update/__tests__/component_test.tsx b/frontend/tos_update/__tests__/component_test.tsx index 607689727..9cdf74b24 100644 --- a/frontend/tos_update/__tests__/component_test.tsx +++ b/frontend/tos_update/__tests__/component_test.tsx @@ -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; @@ -43,27 +39,35 @@ describe("", () => { expect(wow.setState).toHaveBeenCalledWith({ email: "foo@bar.com" }); }); - it("submits a form", () => { - type FormEvent = React.FormEvent; - const fakeEvent: Partial = { preventDefault: jest.fn() }; + type FormEvent = React.FormEvent; + const fakeEvent: Partial = { 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", () => { diff --git a/frontend/tos_update/component.tsx b/frontend/tos_update/component.tsx index 59db9f348..999b6c154 100644 --- a/frontend/tos_update/component.tsx +++ b/frontend/tos_update/component.tsx @@ -38,7 +38,7 @@ export class TosUpdate extends React.Component> { .post(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));