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> {
to: string;
children: React.ReactChild | React.ReactChild[];
children?: React.ReactChild | React.ReactChild[];
style?: React.CSSProperties;
className?: string;
}
@ -11,18 +11,18 @@ interface LinkProps extends React.AnchorHTMLAttributes<HTMLAnchorElement> {
export const maybeStripLegacyUrl =
(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, {}> {
render() {
const { props } = this;
return <a
{...props}
href={props.to}
onClick={(e: React.MouseEvent<HTMLAnchorElement>) => {
e.preventDefault();
/** BEGIN LEGACY SHIMS */
const { onClick, to } = props;
navigate(maybeStripLegacyUrl(to));
onClick && onClick(e);
}} />;
return <a {...props} href={props.to} onClick={clickHandler(props)} />;
}
}

View File

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