('../../common/utils'),
- isServerEnvironment: jest.fn(),
-}));
-
-describe('', () => {
- describe('Browser environment', () => {
- beforeEach(() => {
- (isServerEnvironment as any).mockImplementation(() => false);
- mockHistory.listen.mockReturnValue(unlistenMock);
- });
-
- afterEach(() => {
- jest.resetAllMocks();
- });
-
- it('renders a RouterContainer', () => {
- const wrapper = mount(
- // @ts-ignore
-
- hello
-
- );
-
- const component = wrapper.find('UniversalRouterContainer');
-
- expect(component).toHaveLength(1);
-
- expect(component.props()).toEqual(
- expect.objectContaining({
- history: mockHistory,
- routes,
- })
- );
- });
-
- it('should call the history unlistener on unmount', () => {
- const wrapper = mount(
- // @ts-ignore
-
- hello
-
- );
-
- wrapper.unmount();
-
- expect(unlistenMock).toHaveBeenCalledTimes(1);
- });
-
- describe('when the router is re-mounted by a parent component', () => {
- it('should clean up the original history listener', () => {
- // @ts-ignore
- const RemountingParent = ({ shouldRemount = false, children }) => {
- if (shouldRemount) {
- return <>{children}>;
- }
-
- return {children}
;
- };
- const newUnlistener = jest.fn();
- const router = (
- // @ts-ignore
-
- hello
-
- );
- const wrapper = mount({router});
-
- // first listener is created on mount
- expect(mockHistory.listen).toHaveBeenCalledTimes(1);
-
- mockHistory.listen.mockReturnValue(newUnlistener);
-
- // trigger the re-mount
- wrapper.setProps({ shouldRemount: true });
-
- // second listener is created by the RouterContainer on re-mount
- expect(mockHistory.listen).toHaveBeenCalledTimes(2);
-
- // the original unlistener is called and the new one is not called
- expect(unlistenMock).toHaveBeenCalledTimes(1);
- expect(newUnlistener).toHaveBeenCalledTimes(0);
- });
- });
- });
-
- describe('Server environment', () => {
- beforeEach(() => {
- jest
- .spyOn(historyHelper, 'createMemoryHistory')
- // @ts-ignore
- .mockImplementation(() => mockHistory);
- mockHistory.listen.mockReturnValue(unlistenMock);
- });
-
- afterEach(() => {
- jest.resetAllMocks();
- jest.restoreAllMocks();
- });
-
- it('should listen to memory history if no history provided', () => {
- mount(
-
-
- {() => I am a subscriber
}
-
-
- );
-
- expect(mockHistory.listen).toHaveBeenCalled();
- });
-
- describe('static requestResources', () => {
- const type = 'type';
- const key = 'key';
- const result = 'result';
- const resolver = (r: any, d = 0) =>
- new Promise(resolve => setTimeout(() => resolve(r), d));
- const getDataPromise = Promise.resolve(result);
- const mockResource = {
- type,
- getKey: () => key,
- getData: () => getDataPromise,
- };
- const mockedRoutes = [
- {
- ...mockRoute,
- path: mockLocation.pathname,
- component: () => foo
,
- resources: [
- {
- ...mockResource,
- ...{ type: 'HI', getData: () => resolver('hello world', 250) },
- },
- {
- ...mockResource,
- ...{
- type: 'BYE',
- getData: () => resolver('goodbye cruel world', 500),
- },
- },
- ],
- },
- ];
-
- it('should expose a static requestResources method', () => {
- expect(typeof Router.requestResources).toBe('function');
- });
-
- it('should return hydratable, cleaned resource store state.data when awaited', async () => {
- const data = await Router.requestResources({
- // @ts-ignore
- routes: mockedRoutes,
- });
-
- expect(data).toEqual({
- BYE: {
- key: {
- data: 'goodbye cruel world',
- error: null,
- loading: false,
- promise: null,
- expiresAt,
- accessedAt,
- },
- },
- HI: {
- key: {
- data: 'hello world',
- error: null,
- loading: false,
- promise: null,
- expiresAt,
- accessedAt,
- },
- },
- });
- });
-
- it('should maintain the pre-requested state in the resource store when mounted', async () => {
- await Router.requestResources({
- // @ts-ignore
- routes: mockedRoutes,
- location: '/',
- });
-
- const resourceData = {
- BYE: {
- key: {
- data: 'goodbye cruel world',
- error: null,
- loading: false,
- promise: null,
- expiresAt,
- accessedAt,
- },
- },
- HI: {
- key: {
- data: 'hello world',
- error: null,
- loading: false,
- promise: null,
- expiresAt,
- accessedAt,
- },
- },
- };
-
- mount(
-
-
- {() => I am a subscriber
}
-
-
- );
-
- expect(getResourceStore().actions.getSafeData()).toEqual(resourceData);
- });
-
- it('should not re-request resources on mount if resources have already been requested by requestResources', async () => {
- const { pathname: location } = mockLocation;
- const resourceSpy1 = jest.spyOn(
- mockedRoutes[0].resources[0],
- 'getData'
- );
- const resourceSpy2 = jest.spyOn(
- mockedRoutes[0].resources[1],
- 'getData'
- );
-
- await Router.requestResources({
- // @ts-ignore
- routes: mockedRoutes,
- location,
- });
-
- mount(
-
-
- {() => I am a subscriber
}
-
-
- );
-
- expect(resourceSpy1).toHaveBeenCalledTimes(1);
- expect(resourceSpy2).toHaveBeenCalledTimes(1);
- });
- });
- });
-
- describe('Memory environment', () => {
- it('should register an instance of memory history in the router store when mounted with a location set', () => {
- let memoryHistory;
-
- mount(
-
-
- {
- /* @ts-ignore */
- ({ history }) => {
- memoryHistory = history;
-
- return null;
- }
- }
-
-
- );
-
- expect(memoryHistory).toHaveProperty('canGo');
- });
- });
-});
diff --git a/src/controllers/universal-router/types.ts b/src/controllers/universal-router/types.ts
deleted file mode 100644
index 7fd16317..00000000
--- a/src/controllers/universal-router/types.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-import { ReactNode } from 'react';
-
-import {
- BrowserHistory,
- ResourceStoreContext,
- ResourceStoreData,
- RouterContext,
- Routes,
-} from '../../common/types';
-
-export type UniversalRouterProps = {
- history?: BrowserHistory;
- isGlobal?: boolean;
- location?: string;
- resourceContext?: ResourceStoreContext;
- resourceData?: ResourceStoreData;
- routes: Routes;
- children: ReactNode;
- onPrefetch?: (routerContext: RouterContext) => void;
-};
-
-export type RequestResourcesParams = {
- location: string;
- routes: Routes;
- resourceContext?: ResourceStoreContext;
- timeout?: number;
-};
diff --git a/src/controllers/use-path-param/test.tsx b/src/controllers/use-path-param/test.tsx
index e0346ec7..4a9d1cdf 100644
--- a/src/controllers/use-path-param/test.tsx
+++ b/src/controllers/use-path-param/test.tsx
@@ -9,6 +9,8 @@ import { getRouterStore } from '../router-store';
import { usePathParam } from './index';
+jest.mock('../../common/utils/is-server-environment');
+
const mockLocation = {
pathname: '/projects/123/board/456',
search: '?foo=hello&bar=world',
diff --git a/src/controllers/use-query-param/test.tsx b/src/controllers/use-query-param/test.tsx
index 99762f92..13971aba 100644
--- a/src/controllers/use-query-param/test.tsx
+++ b/src/controllers/use-query-param/test.tsx
@@ -9,6 +9,8 @@ import { getRouterStore } from '../../controllers/router-store';
import { useQueryParam } from './index';
+jest.mock('../../common/utils/is-server-environment');
+
const mockLocation = {
pathname: '/projects/123/board/456',
search: '?foo=hello&bar=world',
diff --git a/src/controllers/use-router-actions/test.tsx b/src/controllers/use-router-actions/test.tsx
index 01da67ec..10550cfe 100644
--- a/src/controllers/use-router-actions/test.tsx
+++ b/src/controllers/use-router-actions/test.tsx
@@ -18,7 +18,6 @@ describe('useRouterActions()', () => {
expect(routerActions).toMatchInlineSnapshot(`
Object {
"bootstrapStore": [Function],
- "bootstrapStoreUniversal": [Function],
"getBasePath": [Function],
"getContext": [Function],
"goBack": [Function],
diff --git a/src/controllers/use-router/test.tsx b/src/controllers/use-router/test.tsx
index 2687a1e5..65da20ca 100644
--- a/src/controllers/use-router/test.tsx
+++ b/src/controllers/use-router/test.tsx
@@ -30,7 +30,6 @@ describe('useRouter()', () => {
expect(actions).toMatchInlineSnapshot(`
Object {
"bootstrapStore": [Function],
- "bootstrapStoreUniversal": [Function],
"getBasePath": [Function],
"getContext": [Function],
"goBack": [Function],
diff --git a/src/controllers/with-router/test.tsx b/src/controllers/with-router/test.tsx
index c766fff0..bf65c7d4 100644
--- a/src/controllers/with-router/test.tsx
+++ b/src/controllers/with-router/test.tsx
@@ -10,6 +10,8 @@ import { withRouter } from './index';
const waitALilBit = () => new Promise(resolve => setTimeout(resolve));
+jest.mock('../../common/utils/is-server-environment');
+
describe('withRouter()', () => {
const ComponentToBeWrapped = (props: any) => (
deep component {props.foo}
diff --git a/src/index.js.flow b/src/index.js.flow
index a53c7ea9..3fb361b4 100644
--- a/src/index.js.flow
+++ b/src/index.js.flow
@@ -4,38 +4,38 @@ import type { ComponentType, ElementConfig, Node } from 'react';
import type {
BrowserHistory,
+ CreateRouterContextOptions,
+ GetData,
HistoryUpdateType,
LinkProps,
Location,
MatchParams,
MemoryRouterProps,
Query,
+ RequestResourcesParams,
ResourceOptions,
ResourceStoreContext,
+ ResourceStoreData,
+ ResourceType,
Route,
RouteContext,
RouterActionsType,
- ResourceType,
- RouteResourceBase,
- GetData,
+ RouterContext,
+ RouterProps,
+ RouterState,
+ RouterSubscriberProps,
RouteResource,
+ RouteResourceBase,
RouteResourceData,
RouteResourceResponse,
RouteResourceUpdater,
- RouterProps,
- RouterState,
- RouterContext,
- RouterSubscriberProps,
- StaticRouterProps,
- CreateRouterContextOptions,
- ResourceStoreData,
- RequestResourcesParams,
} from './types.js.flow';
export * from './utils.js.flow';
export * from './types.js.flow';
declare export function Link(props: LinkProps): Node;
+
declare export function Redirect(props: {
to: Location | Route | string,
push?: boolean,
@@ -47,16 +47,13 @@ declare export function RouterActions(props: {|
children: (actions: RouterActionsType) => Node,
|}): Node;
-declare export function Router(props: RouterProps): Node;
-declare export var MemoryRouter: {
- (props: MemoryRouterProps): Node,
- requestResources: RequestResourcesParams => Promise,
-};
-declare export var StaticRouter: {
- (props: StaticRouterProps): Node,
+declare export var Router: {
+ (props: RouterProps): Node,
requestResources: RequestResourcesParams => Promise,
};
+declare export function MemoryRouter(props: MemoryRouterProps): Node;
+
declare export function ResourceSubscriber(props: {
children: (
resource: RouteResourceResponse & {
@@ -86,6 +83,7 @@ declare export function useResource(
clear: () => void,
clearAll: () => void,
|};
+
declare export function useRouter(): [RouterState, RouterActionsType];
declare export function useRouterActions(): RouterActionsType;
declare export function useResourceStoreContext(): ResourceStoreContext;
@@ -100,6 +98,7 @@ declare export function useQueryParam(
string | void,
(newValue: string | void, updateType?: HistoryUpdateType) => void
];
+
declare export function usePathParam(
paramKey: string
): [
diff --git a/src/index.ts b/src/index.ts
index c98186b8..233cf15b 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -11,7 +11,6 @@ export {
Router,
RouterActions,
RouterSubscriber,
- StaticRouter,
usePathParam,
useQueryParam,
useResource,
@@ -43,6 +42,7 @@ export type {
CreateRouterContextOptions,
FindRouterContextOptions,
GenerateLocationOptions,
+ History,
HistoryAction,
HistoryActions,
HistoryBlocker,
@@ -54,7 +54,6 @@ export type {
MatchParams,
MatchedInvariantRoute,
MatchedRoute,
- MemoryRouterProps,
Query,
ResourceStoreContext,
ResourceStoreData,
diff --git a/src/types.js.flow b/src/types.js.flow
index 1ac7af29..1eba6614 100644
--- a/src/types.js.flow
+++ b/src/types.js.flow
@@ -5,6 +5,8 @@ import type { Action } from 'react-sweet-state';
export type BrowserHistory = any;
export type MemoryHistory = any;
+export type History = BrowserHistory | MemoryHistory;
+
export type LocationShape = any;
export type Location = {|
@@ -164,36 +166,24 @@ export type InvariantRoutes = InvariantRoute[];
export type Routes = Route[];
type ContainerProps = {|
- isStatic?: boolean,
- history: BrowserHistory,
- location?: Location,
- routes: Routes,
+ history: History,
resourceData?: ResourceStoreData,
resourceContext?: ResourceStoreContext,
-|};
-
-export type UniversalRouterContainerProps = {|
- isGlobal?: boolean,
- history: BrowserHistory | MemoryHistory,
- location?: Location,
routes: Routes,
- resourceData?: ResourceStoreData,
- resourceContext?: ResourceStoreContext,
|};
type PublicStateProperties = {|
+ action: HistoryAction,
location: Location,
+ match: Match,
query: Query,
route: Route,
- match: Match,
- action: HistoryAction,
|};
type PrivateStateProperties = {|
routes: Routes,
- history: BrowserHistory,
+ history: History,
unlisten: (() => void) | null,
- isStatic: boolean,
shouldUseSuspense: boolean,
|};
@@ -214,69 +204,40 @@ export type RouterAction = Action;
type UnregisterCallback = () => void;
export type RouterActionsType = {|
+ getBasePath: () => string,
+ goBack: () => void,
+ goForward: () => void,
push: (path: Href | Location, state?: any) => void,
pushTo: (route: Route, attributes: ToAttributes) => void,
+ registerBlock: (blocker: HistoryBlocker | any) => UnregisterCallback,
replace: (path: Href | Location, state?: any) => void,
replaceTo: (route: Route, attributes: ToAttributes) => void,
- goBack: () => void,
- goForward: () => void,
- registerBlock: (blocker: HistoryBlocker | any) => UnregisterCallback,
- getBasePath: () => string,
|};
-// TODO: DRY out all these different router props if possible
export type RouterProps = {
- isStatic?: boolean,
- history?: BrowserHistory,
- resourceContext?: ResourceStoreContext,
- resourceData?: ResourceStoreData,
- routes: Routes,
+ basePath?: string,
children: Node,
+ history: History,
initialRoute?: Route,
isGlobal?: boolean,
- basePath?: string,
onPrefetch?: (routerContext: RouterContext) => void,
-};
-
-export type UniversalRouterProps = {
- isGlobal?: boolean,
- history?: BrowserHistory | MemoryHistory,
resourceContext?: ResourceStoreContext,
resourceData?: ResourceStoreData,
routes: Routes,
- children: Node,
- initialRoute?: Route,
- onPrefetch?: (routerContext: RouterContext) => void,
};
export type MemoryRouterProps = {
- isStatic?: boolean,
- isGlobal?: boolean,
- location?: string,
- routes?: Routes,
- children: Node,
- resourceData?: ResourceStoreData,
- resourceContext?: ResourceStoreContext,
- initialRoute?: Route,
basePath?: string,
- onPrefetch?: (routerContext: RouterContext) => void,
-};
-
-export type StaticRouterProps = {
- isStatic?: boolean,
- location?: string,
- routes: Routes,
children: Node,
- resourceData?: ResourceStoreData,
- resourceContext?: ResourceStoreContext,
- initialRoute?: Route,
- basePath?: string,
+ location?: string,
+ routes?: Routes,
};
export type RequestResourcesParams = {
+ history?: BrowserHistory,
location: string,
- routes: Routes,
resourceContext?: ResourceStoreContext,
+ routes: Routes,
timeout?: number,
};