pull/991/head
Rick Carlino 2018-09-21 09:09:30 -05:00
parent 280608b08c
commit d1be7c4817
4 changed files with 88 additions and 14 deletions

View File

@ -0,0 +1,42 @@
jest.mock("takeme", () => ({ navigate: jest.fn() }));
import { clickHandler, Link } from "../link";
import * as React from "react";
import { navigate } from "takeme";
import { shallow } from "enzyme";
describe("clickHandler", () => {
function setupClickTest(to: string) {
const onClick = jest.fn();
const handler = clickHandler({ to, onClick });
type ClickEvent = React.MouseEvent<HTMLAnchorElement>;
const e: Partial<ClickEvent> = { preventDefault: jest.fn() };
return {
e: e as ClickEvent,
handler,
onClick
};
}
it("handles clicks", () => {
const { e, handler } = setupClickTest("/clean_path");
handler(e);
expect(e.preventDefault).toHaveBeenCalled();
expect(navigate).toHaveBeenCalledWith("/clean_path");
});
it("handles clicks, stripping out the `/app` part", () => {
const { e, handler } = setupClickTest("/app/foo/bar");
handler(e);
expect(e.preventDefault).toHaveBeenCalled();
expect(navigate).toHaveBeenCalledWith("/foo/bar");
});
});
describe("<Link/>", () => {
it("renders child elements", () => {
function Child(_: unknown) { return <p>Hey!</p>; }
const el = shallow(<Link to="/wherever"><Child /></Link>);
expect(el.html()).toContain("Hey!");
});
});

View File

@ -0,0 +1,32 @@
import { UNBOUND_ROUTES, UnboundRouteConfig } from "../route_config";
import { RouteEnterEvent } from "takeme";
interface ConnectedComponent {
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) => {
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);
}
});
}
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); });
});
});

View File

@ -3,7 +3,7 @@ import { navigate } from "takeme";
interface LinkProps extends React.AnchorHTMLAttributes<HTMLAnchorElement> { interface LinkProps extends React.AnchorHTMLAttributes<HTMLAnchorElement> {
to: string; to: string;
children: React.ReactChild | React.ReactChild[]; children?: React.ReactChild | React.ReactChild[];
style?: React.CSSProperties; style?: React.CSSProperties;
className?: string; className?: string;
} }
@ -11,18 +11,18 @@ interface LinkProps extends React.AnchorHTMLAttributes<HTMLAnchorElement> {
export const maybeStripLegacyUrl = export const maybeStripLegacyUrl =
(url: string) => url.startsWith("/app") ? url.replace("/app", "") : url; (url: string) => url.startsWith("/app") ? url.replace("/app", "") : url;
export const clickHandler =
(props: LinkProps) => (e: React.MouseEvent<HTMLAnchorElement>) => {
e.preventDefault();
/** BEGIN LEGACY SHIMS */
const { onClick, to } = props;
navigate(maybeStripLegacyUrl(to));
onClick && onClick(e);
};
export class Link extends React.Component<LinkProps, {}> { export class Link extends React.Component<LinkProps, {}> {
render() { render() {
const { props } = this; const { props } = this;
return <a return <a {...props} href={props.to} onClick={clickHandler(props)} />;
{...props}
href={props.to}
onClick={(e: React.MouseEvent<HTMLAnchorElement>) => {
e.preventDefault();
/** BEGIN LEGACY SHIMS */
const { onClick, to } = props;
navigate(maybeStripLegacyUrl(to));
onClick && onClick(e);
}} />;
} }
} }

View File

@ -23,7 +23,7 @@ interface UnboundRouteConfigChild<T, U> {
} }
/** The union of both route config types. */ /** The union of both route config types. */
type UnboundRouteConfig<T, U> = export type UnboundRouteConfig<T, U> =
UnboundRouteConfigNoChild<T> | UnboundRouteConfigChild<T, U>; UnboundRouteConfigNoChild<T> | UnboundRouteConfigChild<T, U>;
/** This is the preferred way to generate a route in the app. /** This is the preferred way to generate a route in the app.
* PROBLEM: * PROBLEM:
@ -61,9 +61,9 @@ function route<T, U>(info: UnboundRouteConfig<T, U>) {
const comp = (await info.getModule())[info.key]; const comp = (await info.getModule())[info.key];
if (info.children) { if (info.children) {
const child = (await info.getChild())[info.childKey]; const child = (await info.getChild())[info.childKey];
callback(comp, child); callback(comp, child, info);
} else { } else {
callback((await info.getModule())[info.key]); callback((await info.getModule())[info.key], undefined, info);
} }
} catch (e) { } catch (e) {
console.error(e); console.error(e);