Skip to content

Commit

Permalink
feat(history-service): support multiple location changes in one navig…
Browse files Browse the repository at this point in the history
…ation

closes #496
fixes #441

Co-authored-by: Stefan Meyer <stefan.meyer@sinnerschrader.com>
  • Loading branch information
unstubbable and stemey committed Jul 4, 2019
1 parent 5f4a3d3 commit 4c816c3
Show file tree
Hide file tree
Showing 15 changed files with 1,821 additions and 610 deletions.
2 changes: 1 addition & 1 deletion packages/demos/src/history-service/integrator.node.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export default async function renderApp({
const {featureAppManager} = createFeatureHub('test:integrator', {
featureServiceDefinitions: [
defineServerRequest(req),
defineHistoryService(rootLocationTransformer)
defineHistoryService(rootLocationTransformer, {mode: 'static'})
]
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,7 @@ export const rootLocationTransformer: RootLocationTransformer = {
createRootLocation: (rootLocation, consumerLocation, consumerId) => {
const searchParams = new URLSearchParams(rootLocation.search);

if (consumerLocation) {
searchParams.set(consumerId, createPath(consumerLocation));
} else {
searchParams.delete(consumerId);
}
searchParams.set(consumerId, createPath(consumerLocation));

const {pathname, state} = rootLocation;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import {Location} from 'history';
import {createRootLocationTransformer} from '..';
import {ConsumerPaths} from '../create-root-location-transformer';

const encodeConsumerPaths = (consumerPaths: ConsumerPaths) =>
encodeURIComponent(JSON.stringify(consumerPaths));

describe('#createRootLocationTransformer', () => {
describe('#createRootLocation', () => {
Expand All @@ -10,79 +14,23 @@ describe('#createRootLocationTransformer', () => {
});

let rootLocation = locationTransformer.createRootLocation(
{pathname: '/'} as Location,
{pathname: '/foo'} as Location,
'test:1'
);

rootLocation = locationTransformer.createRootLocation(
rootLocation as Location,
{
pathname: '/bar',
search: 'baz=1'
} as Location,
'test:2'
);

expect(rootLocation).toMatchObject({
pathname: '/',
search:
'---=%7B%22test%3A1%22%3A%22%2Ffoo%22%2C%22test%3A2%22%3A%22%2Fbar%3Fbaz%3D1%22%7D'
});
});

it('removes undefined consumer locations from the query parameter', () => {
const locationTransformer = createRootLocationTransformer({
consumerPathsQueryParamName: '---'
});

let rootLocation = locationTransformer.createRootLocation(
{
pathname: '/',
search: '---=%7B%22test%3A2%22%3A%22%2Fbar%22%7D'
} as Location,
{pathname: '/foo'} as Location,
'test:1'
);

rootLocation = locationTransformer.createRootLocation(
rootLocation as Location,
undefined,
'test:1'
);

expect(rootLocation).toMatchObject({
pathname: '/',
search: '---=%7B%22test%3A2%22%3A%22%2Fbar%22%7D'
});
});

it('does not throw when a consumer location is removed twice', () => {
const locationTransformer = createRootLocationTransformer({
consumerPathsQueryParamName: '---'
});

let rootLocation = locationTransformer.createRootLocation(
{pathname: '/'} as Location,
{pathname: '/foo'} as Location,
'test:1'
);

rootLocation = locationTransformer.createRootLocation(
rootLocation as Location,
undefined,
'test:1'
{pathname: '/'},
{pathname: '/foo'},
'test1'
);

rootLocation = locationTransformer.createRootLocation(
rootLocation as Location,
undefined,
'test:1'
rootLocation,
{pathname: '/bar', search: 'baz=1'},
'test2'
);

expect(rootLocation).toMatchObject({
pathname: '/',
search: ''
search: `?---=${encodeConsumerPaths({
test1: '/foo',
test2: '/bar?baz=1'
})}`
});
});
});
Expand All @@ -91,55 +39,34 @@ describe('#createRootLocationTransformer', () => {
it('puts the location pathname, query params, and hash directly to the root location', () => {
const locationTransformer = createRootLocationTransformer({
consumerPathsQueryParamName: '---',
primaryConsumerId: 'test:pri'
primaryConsumerHistoryKey: 'testPri'
});

const rootLocation = locationTransformer.createRootLocation(
{pathname: '/'} as Location,
{pathname: '/foo', search: 'bar=1&baz=2', hash: '#qux'} as Location,
'test:pri'
{pathname: '/'},
{pathname: '/foo', search: '?bar=1&baz=2', hash: '#qux'},
'testPri'
);

expect(rootLocation).toMatchObject({
pathname: '/foo',
search: 'bar=1&baz=2',
search: '?bar=1&baz=2',
hash: '#qux'
});
});

it('removes undefined consumer locations from the query parameter', () => {
const locationTransformer = createRootLocationTransformer({
consumerPathsQueryParamName: '---',
primaryConsumerId: 'test:pri'
});

let rootLocation = locationTransformer.createRootLocation(
{pathname: '/'} as Location,
{pathname: '/foo', search: 'bar=1&baz=2', hash: '#qux'} as Location,
'test:pri'
);

rootLocation = locationTransformer.createRootLocation(
rootLocation as Location,
undefined,
'test:pri'
);

expect(rootLocation).toMatchObject({pathname: '/', search: ''});
});

describe('when the primary tries to set a query param that conflicts with the consumer paths query param', () => {
it('throws an error', () => {
const locationTransformer = createRootLocationTransformer({
consumerPathsQueryParamName: '---',
primaryConsumerId: 'test:pri'
primaryConsumerHistoryKey: 'testPri'
});

expect(() =>
locationTransformer.createRootLocation(
{pathname: '/'} as Location,
{pathname: '/foo', search: '---=1'} as Location,
'test:pri'
{pathname: '/'},
{pathname: '/foo', search: '?---=1'},
'testPri'
)
).toThrowError(
new Error(
Expand All @@ -154,31 +81,33 @@ describe('#createRootLocationTransformer', () => {
it('takes the pathname, query params, and hash of the primary consumer directly, and the pathname and query params of the other consumers encoded as a single query param, into the root location', () => {
const locationTransformer = createRootLocationTransformer({
consumerPathsQueryParamName: '---',
primaryConsumerId: 'test:pri'
primaryConsumerHistoryKey: 'testPri'
});

let rootLocation = locationTransformer.createRootLocation(
{pathname: '/'} as Location,
{pathname: '/baz', search: 'qux=3'} as Location,
'test:1'
{pathname: '/'},
{pathname: '/baz', search: '?qux=3'},
'test1'
);

rootLocation = locationTransformer.createRootLocation(
rootLocation as Location,
{pathname: '/foo', search: 'bar=1', hash: '#qux'} as Location,
'test:pri'
rootLocation,
{pathname: '/foo', search: '?bar=1', hash: '#qux'},
'testPri'
);

rootLocation = locationTransformer.createRootLocation(
rootLocation as Location,
{pathname: '/some', search: 'thing=else'} as Location,
'test:2'
rootLocation,
{pathname: '/some', search: '?thing=else'},
'test2'
);

expect(rootLocation).toMatchObject({
pathname: '/foo',
search:
'bar=1&---=%7B%22test%3A1%22%3A%22%2Fbaz%3Fqux%3D3%22%2C%22test%3A2%22%3A%22%2Fsome%3Fthing%3Delse%22%7D',
search: `?bar=1&---=${encodeConsumerPaths({
test1: '/baz?qux=3',
test2: '/some?thing=else'
})}`,
hash: '#qux'
});
});
Expand All @@ -190,32 +119,32 @@ describe('#createRootLocationTransformer', () => {
it('returns the consumer-specific locations', () => {
const locationTransformer = createRootLocationTransformer({
consumerPathsQueryParamName: '---',
primaryConsumerId: 'test:pri'
primaryConsumerHistoryKey: 'testPri'
});

const rootLocation = {
pathname: '/foo',
search: 'bar=1&---=%7B%22test%3A1%22%3A%22%2Fbaz%3Fqux%3D3%22%7D'
search: `?bar=1&---=${encodeConsumerPaths({test1: '/baz?qux=3'})}`
};

expect(
locationTransformer.getConsumerPathFromRootLocation(
rootLocation as Location,
'test:pri'
'testPri'
)
).toEqual('/foo?bar=1');

expect(
locationTransformer.getConsumerPathFromRootLocation(
rootLocation as Location,
'test:1'
'test1'
)
).toEqual('/baz?qux=3');

expect(
locationTransformer.getConsumerPathFromRootLocation(
rootLocation as Location,
'test:2'
'test2'
)
).toBeUndefined();
});
Expand All @@ -225,18 +154,18 @@ describe('#createRootLocationTransformer', () => {
it('returns undefined for a non-primary consumer', () => {
const locationTransformer = createRootLocationTransformer({
consumerPathsQueryParamName: '---',
primaryConsumerId: 'test:pri'
primaryConsumerHistoryKey: 'testPri'
});

const rootLocation = {
pathname: '/foo',
search: 'bar=1'
search: '?bar=1'
};

expect(
locationTransformer.getConsumerPathFromRootLocation(
rootLocation as Location,
'test:2'
'test2'
)
).toBeUndefined();
});
Expand Down
Loading

0 comments on commit 4c816c3

Please sign in to comment.