Skip to content

Commit

Permalink
feat(history): provide option to not clean url on dispose (#5966)
Browse files Browse the repository at this point in the history
  • Loading branch information
dhayab committed Dec 19, 2023
1 parent 0820455 commit e60ac95
Show file tree
Hide file tree
Showing 12 changed files with 176 additions and 17 deletions.
2 changes: 1 addition & 1 deletion bundlesize.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
},
{
"path": "./packages/instantsearch.js/dist/instantsearch.development.js",
"maxSize": "167 kB"
"maxSize": "167.25 kB"
},
{
"path": "packages/react-instantsearch-core/dist/umd/ReactInstantSearchCore.min.js",
Expand Down
1 change: 1 addition & 0 deletions examples/js/e-commerce-umd/src/routing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ function getCategoryName(slug: string): string {
const originalWindowTitle = document.title;

const router = window.instantsearch.routers.history<RouteState>({
cleanUrlOnDispose: false,
windowTitle({ category, query }) {
const queryTitle = query ? `Results for "${query}"` : '';

Expand Down
1 change: 1 addition & 0 deletions examples/js/e-commerce/src/routing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ function getCategoryName(slug: string): string {
const originalWindowTitle = document.title;

const router = historyRouter<RouteState>({
cleanUrlOnDispose: false,
windowTitle({ category, query }) {
const queryTitle = query ? `Results for "${query}"` : '';

Expand Down
1 change: 1 addition & 0 deletions examples/react/e-commerce/routing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ function getCategoryName(slug: string): string {
const originalWindowTitle = document.title;

const router = historyRouter<RouteState>({
cleanUrlOnDispose: false,
windowTitle({ category, query }) {
const queryTitle = query ? `Results for "${query}"` : '';

Expand Down
3 changes: 3 additions & 0 deletions examples/react/next-routing/pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ export default function HomePage({ serverState, url }: HomePageProps) {
router: createInstantSearchRouterNext({
singletonRouter,
serverUrl: url,
routerOptions: {
cleanUrlOnDispose: false,
},
}),
}}
insights={true}
Expand Down
3 changes: 3 additions & 0 deletions examples/react/next/pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ export default function HomePage({ serverState, url }: HomePageProps) {
router: createInstantSearchRouterNext({
serverUrl: url,
singletonRouter,
routerOptions: {
cleanUrlOnDispose: false,
},
}),
}}
insights={true}
Expand Down
1 change: 1 addition & 0 deletions examples/react/ssr/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ function App({ serverState, location }) {
routing={{
stateMapping: simple(),
router: history({
cleanUrlOnDispose: false,
getLocation() {
if (typeof window === 'undefined') {
return location;
Expand Down
4 changes: 3 additions & 1 deletion examples/vue/default-theme/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,9 @@ export default {
'6be0576ff61c053d5f9a3225e2a90f76'
),
routing: {
router: historyRouter(),
router: historyRouter({
cleanUrlOnDispose: false,
}),
stateMapping: simpleMapping(),
},
};
Expand Down
1 change: 1 addition & 0 deletions examples/vue/e-commerce/src/routing.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ function getCategoryName(slug) {
const originalWindowTitle = document.title;

const router = historyRouter({
cleanUrlOnDispose: false,
windowTitle({ category, query }) {
const queryTitle = query ? `Results for "${query}"` : '';

Expand Down
4 changes: 3 additions & 1 deletion examples/vue/media/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,9 @@ export default {
'6be0576ff61c053d5f9a3225e2a90f76'
),
routing: {
router: historyRouter(),
router: historyRouter({
cleanUrlOnDispose: false,
}),
stateMapping: simpleMapping(),
},
};
Expand Down
138 changes: 128 additions & 10 deletions packages/instantsearch.js/src/lib/routers/__tests__/history.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ describe('life cycle', () => {
describe('pushState', () => {
test('calls pushState on write', () => {
const windowPushState = jest.spyOn(window.history, 'pushState');
const router = historyRouter<UiState>();
const router = historyRouter<UiState>({ cleanUrlOnDispose: true });

router.write({ indexName: { query: 'query' } });
jest.runAllTimers();
Expand All @@ -43,7 +43,7 @@ describe('life cycle', () => {

test('debounces history push calls', () => {
const windowPushState = jest.spyOn(window.history, 'pushState');
const router = historyRouter<UiState>();
const router = historyRouter<UiState>({ cleanUrlOnDispose: true });

router.write({ indexName: { query: 'query1' } });
router.write({ indexName: { query: 'query2' } });
Expand All @@ -61,7 +61,10 @@ describe('life cycle', () => {
test('calls user-provided push if set', () => {
const windowPushState = jest.spyOn(window.history, 'pushState');
const customPush = jest.fn();
const router = historyRouter<UiState>({ push: customPush });
const router = historyRouter<UiState>({
push: customPush,
cleanUrlOnDispose: true,
});

router.write({ indexName: { query: 'query' } });
jest.runAllTimers();
Expand All @@ -83,14 +86,18 @@ describe('life cycle', () => {
return 'Search';
},
getLocation,
cleanUrlOnDispose: true,
});

expect(getLocation).toHaveBeenCalledTimes(1);
});

test('calls getLocation on read', () => {
const getLocation = jest.fn(() => window.location);
const router = historyRouter<UiState>({ getLocation });
const router = historyRouter<UiState>({
getLocation,
cleanUrlOnDispose: true,
});

expect(getLocation).toHaveBeenCalledTimes(0);

Expand All @@ -106,7 +113,10 @@ describe('life cycle', () => {

test('calls getLocation on createURL', () => {
const getLocation = jest.fn(() => window.location);
const router = historyRouter<UiState>({ getLocation });
const router = historyRouter<UiState>({
getLocation,
cleanUrlOnDispose: true,
});

router.createURL({ indexName: { query: 'query1' } });

Expand All @@ -117,7 +127,7 @@ describe('life cycle', () => {
describe('pop state', () => {
test('skips history push on browser back/forward actions', () => {
const pushState = jest.spyOn(window.history, 'pushState');
const router = historyRouter<UiState>();
const router = historyRouter<UiState>({ cleanUrlOnDispose: true });
router.onUpdate((routeState) => {
router.write(routeState);
});
Expand Down Expand Up @@ -145,7 +155,7 @@ describe('life cycle', () => {
});

test("doesn't throw if an index history state is null", () => {
const router = historyRouter<UiState>();
const router = historyRouter<UiState>({ cleanUrlOnDispose: true });
const stateMapping = simple();

router.onUpdate((routeState) => {
Expand Down Expand Up @@ -195,6 +205,7 @@ describe('life cycle', () => {
search: '',
} as unknown as Location;
},
cleanUrlOnDispose: true,
});
const search = instantsearch({
indexName: 'indexName',
Expand Down Expand Up @@ -226,6 +237,7 @@ describe('life cycle', () => {
search: '',
} as unknown as Location;
},
cleanUrlOnDispose: true,
});

// We run the whole lifecycle to make sure none of the steps access `window`.
Expand All @@ -243,7 +255,10 @@ describe('life cycle', () => {
describe('onUpdate', () => {
test('calls user-provided start function', () => {
const start = jest.fn();
const router = historyRouter<UiState>({ start });
const router = historyRouter<UiState>({
start,
cleanUrlOnDispose: true,
});

router.onUpdate(jest.fn());

Expand All @@ -254,19 +269,122 @@ describe('life cycle', () => {
describe('dispose', () => {
test('calls user-provided dispose function', () => {
const dispose = jest.fn();
const router = historyRouter<UiState>({ dispose });
const router = historyRouter<UiState>({
dispose,
cleanUrlOnDispose: true,
});

router.dispose();

expect(dispose).toHaveBeenCalledTimes(1);
});

describe('cleanUrlOnDispose', () => {
const consoleSpy = jest.spyOn(global.console, 'info');
consoleSpy.mockImplementation(() => {});

beforeEach(() => {
consoleSpy.mockReset();
});

test('cleans refinements from URL if not defined', () => {
const windowPushState = jest.spyOn(window.history, 'pushState');
const router = historyRouter<UiState>();

expect(consoleSpy)
.toHaveBeenCalledWith(`Starting from the next major version, InstantSearch will not clean up the URL from active refinements when it is disposed.
We recommend setting \`cleanUrlOnDispose\` to false to adopt this change today.
To stay with the current behaviour and remove this warning, set the option to true.
See documentation: https://www.algolia.com/doc/api-reference/widgets/history-router/js/#widget-param-cleanurlondispose`);

router.write({ indexName: { query: 'query1' } });
jest.runAllTimers();

expect(windowPushState).toHaveBeenCalledTimes(1);
expect(windowPushState).toHaveBeenLastCalledWith(
{
indexName: { query: 'query1' },
},
'',
'http://localhost/?indexName%5Bquery%5D=query1'
);

router.dispose();
jest.runAllTimers();

expect(windowPushState).toHaveBeenCalledTimes(2);
expect(windowPushState).toHaveBeenLastCalledWith(
{},
'',
'http://localhost/'
);
});

test('cleans refinements from URL if `true`', () => {
const windowPushState = jest.spyOn(window.history, 'pushState');
const router = historyRouter<UiState>({ cleanUrlOnDispose: true });

expect(consoleSpy).not.toHaveBeenCalled();

router.write({ indexName: { query: 'query1' } });
jest.runAllTimers();

expect(windowPushState).toHaveBeenCalledTimes(1);
expect(windowPushState).toHaveBeenLastCalledWith(
{
indexName: { query: 'query1' },
},
'',
'http://localhost/?indexName%5Bquery%5D=query1'
);

router.dispose();
jest.runAllTimers();

expect(windowPushState).toHaveBeenCalledTimes(2);
expect(windowPushState).toHaveBeenLastCalledWith(
{},
'',
'http://localhost/'
);
});

test('does not clean refinements from URL if `false`', () => {
const windowPushState = jest.spyOn(window.history, 'pushState');
const router = historyRouter<UiState>({ cleanUrlOnDispose: false });

expect(consoleSpy).not.toHaveBeenCalled();

router.write({ indexName: { query: 'query1' } });
jest.runAllTimers();

expect(windowPushState).toHaveBeenCalledTimes(1);
expect(windowPushState).toHaveBeenLastCalledWith(
{
indexName: { query: 'query1' },
},
'',
'http://localhost/?indexName%5Bquery%5D=query1'
);

router.dispose();
jest.runAllTimers();

expect(windowPushState).toHaveBeenCalledTimes(1);
});
});
});

describe('createURL', () => {
test('prints a warning when created URL is not valid', () => {
warning.cache = {};

const router = historyRouter<UiState>({ createURL: () => '/search' });
const router = historyRouter<UiState>({
createURL: () => '/search',
cleanUrlOnDispose: true,
});

expect(() => router.createURL({ indexName: {} }))
.toWarnDev(`[InstantSearch.js]: The URL returned by the \`createURL\` function is invalid.
Expand Down

0 comments on commit e60ac95

Please sign in to comment.