@relax.dev/router
Version:
Router for VKUI
272 lines (239 loc) • 8.92 kB
text/typescript
/**
* @jest-environment jsdom
*/
import { Router } from './Router';
import { Page } from './Page';
import { Route } from './Route';
import { dangerousResetGlobalRouterUseForTestOnly } from '../methods';
import { HistoryUpdateType, RouterGenericBase } from './Types';
type PanelIdType = 'panel_main' | 'user' | 'info' | 'done' | 'main' | 'create';
type ViewIdType = 'main' | 'create';
type PageIdType = '/' | '/user' | '/info' | '/done' | '/create' | '/product';
interface RouterTypes extends RouterGenericBase {
panelId: PanelIdType;
viewId: ViewIdType;
pageId: PageIdType;
}
function delay(time = 100) {
return new Promise((resolve) => setTimeout(resolve, time));
}
test('route basic usage', async (done) => {
dangerousResetGlobalRouterUseForTestOnly();
const r = new Router<RouterTypes>(
{
'/': new Page<RouterTypes>(),
'/user': new Page<RouterTypes>('user'),
'/info': new Page<RouterTypes>('info'),
},
null
);
const recordEvents: Array<{
newRoute: Route;
oldRoute: Route | undefined;
isNewRoute: boolean;
type: HistoryUpdateType;
}> = [];
r.on('update', (newRoute, oldRoute, isNewRoute, type) => {
recordEvents.push({ newRoute, oldRoute, isNewRoute, type });
});
r.start();
expect(r.history.getCurrentIndex()).toBe(0);
r.pushPage('/user');
expect(r.history.getCurrentIndex()).toBe(1);
await delay(10);
r.pushPage('/info');
expect(r.history.getCurrentIndex()).toBe(2);
await delay(10);
r.popPage();
await delay(10);
expect(r.history.getCurrentIndex()).toBe(1);
r.replacePage('/info');
await delay(10);
expect(r.history.getCurrentIndex()).toBe(1);
setTimeout(() => {
// одно событие update приходит после старта роутера
expect(recordEvents.length).toBe(4 + 1);
expect(recordEvents[0].isNewRoute).toBeTruthy();
expect(recordEvents[1].isNewRoute).toBeTruthy();
expect(recordEvents[2].isNewRoute).toBeTruthy();
expect(recordEvents[3].isNewRoute).toBeFalsy();
expect(recordEvents[4].isNewRoute).toBeTruthy();
done();
r.stop();
}, 10);
});
test('route first page push', async (done) => {
dangerousResetGlobalRouterUseForTestOnly();
const r = new Router<RouterTypes>(
{
'/': new Page<RouterTypes>(),
'/user': new Page<RouterTypes>('user'),
'/info': new Page<RouterTypes>('info'),
},
null
);
r.start();
await delay(100);
expect(r.getCurrentLocation().isFirstPage()).toBe(true); // После старта страница всегда first
r.pushPage('/info');
await delay(100);
expect(r.getCurrentLocation().isFirstPage()).toBe(false); // После push страница всегда не будет first
r.popPage();
await delay(100);
expect(r.getCurrentLocation().isFirstPage()).toBe(true); // Вернулись назад на первую страницу, она была и осталась first
r.stop();
done();
});
test('route first page replace', async (done) => {
dangerousResetGlobalRouterUseForTestOnly();
const r = new Router<RouterTypes>(
{
'/': new Page<RouterTypes>(),
'/user': new Page<RouterTypes>('user'),
'/info': new Page<RouterTypes>('info'),
},
null
);
r.start();
await delay(100);
expect(r.getCurrentLocation().isFirstPage()).toBe(true); // После старта страница всегда first
r.replacePage('/info');
await delay(100);
expect(r.getCurrentLocation().isFirstPage()).toBe(true); // Мы заменили first страницу на какую-то другу, она осталась first
r.pushPage('/user');
await delay(100);
expect(r.getCurrentLocation().isFirstPage()).toBe(false); // Был push страница уже не first
r.popPage();
await delay(100);
expect(r.getCurrentLocation().isFirstPage()).toBe(true); // Вернулись обратно на first страницу
r.stop();
done();
});
test('check history', async (done) => {
dangerousResetGlobalRouterUseForTestOnly();
const r = new Router<RouterTypes>(
{
'/': new Page<RouterTypes>('main', 'main'),
'/user': new Page<RouterTypes>('user', 'main'),
'/info': new Page<RouterTypes>('info', 'main'),
'/create': new Page<RouterTypes>('create', 'create'),
'/done': new Page('done', 'create'),
},
null
);
r.start();
expect(r.getCurrentLocation().getViewHistory('main')).toEqual(['main']);
expect(r.getCurrentLocation().getPanelId()).toBe('main');
expect(r.getCurrentLocation().getViewId()).toBe('main');
r.pushPage('/user');
expect(r.getCurrentLocation().getViewHistory('main')).toEqual(['main', 'user']);
expect(r.getCurrentLocation().getPanelId()).toBe('user');
expect(r.getCurrentLocation().getViewId()).toBe('main');
r.pushPage('/info');
expect(r.getCurrentLocation().getViewHistory('main')).toEqual(['main', 'user', 'info']);
expect(r.getCurrentLocation().getPanelId()).toBe('info');
expect(r.getCurrentLocation().getViewId()).toBe('main');
r.pushPage('/create');
expect(r.getCurrentLocation().getViewHistory('main')).toEqual(['info']);
expect(r.getCurrentLocation().getViewHistory('create')).toEqual(['create']);
expect(r.getCurrentLocation().getPanelId()).toBe('create');
expect(r.getCurrentLocation().getViewId()).toBe('create');
r.pushPage('/done');
expect(r.getCurrentLocation().getViewHistory('create')).toEqual(['create', 'done']);
expect(r.getCurrentLocation().getViewHistory('main')).toEqual(['info']);
expect(r.getCurrentLocation().getPanelId()).toBe('done');
expect(r.getCurrentLocation().getViewId()).toBe('create');
expect(r.getCurrentLocation().getLastPanelInView('main')).toBe('info');
r.popPage();
await delay(100);
expect(r.getCurrentLocation().getViewHistory('create')).toEqual(['create']);
expect(r.getCurrentLocation().getLastPanelInView('main')).toBe('info');
r.stop();
done();
});
test('route preventSameLocationChange', async (done) => {
dangerousResetGlobalRouterUseForTestOnly();
const r = new Router<RouterTypes>(
{
'/': new Page(),
'/user': new Page('user'),
'/info': new Page<RouterTypes>('info'),
},
{ preventSameLocationChange: true }
);
r.start();
expect(r.history.getCurrentIndex()).toBe(0);
r.pushPage('/user');
expect(r.history.getCurrentIndex()).toBe(1);
await delay(10);
// Пушим точно такую же страницу, ничего не должно произойти
let wasUpdates = false;
r.once('update', () => (wasUpdates = true));
r.pushPage('/user');
expect(r.history.getCurrentIndex()).toBe(1);
expect(wasUpdates).toBe(false);
done();
});
test('fixBrokenHistory', async (done) => {
dangerousResetGlobalRouterUseForTestOnly();
const r = new Router({
'/': new Page(),
'/user': new Page('user'),
'/product': new Page<RouterTypes>('panel_main'),
});
r.start();
r.pushPage('/user');
r.pushPage('/product');
// Эмитируем открытие м закрытие левого приложения
window.history.pushState(null, 'OTHER PAGE OPEN', '#PAGE OPEN');
r.fixBrokenHistory();
expect(r.getCurrentLocation().getPageId()).toBe('/product');
r.popPage();
await r.afterUpdate();
expect(r.getCurrentLocation().getPageId()).toBe('/user');
done();
});
test('popPageToAndReplace', async (done) => {
dangerousResetGlobalRouterUseForTestOnly();
const r = new Router<RouterTypes>({
'/': new Page<RouterTypes>(),
'/user': new Page('user'),
'/product': new Page<RouterTypes>('user'),
'/done': new Page<RouterTypes>('done'),
});
r.start();
r.pushPage('/user');
r.pushPage('/product');
// r.popPageToAndReplace(-2, '/done', {});
// await r.afterUpdate();
// expect(r.history.getCurrentIndex()).toBe(0);
await done();
});
test('it should use certain parameter as hash', () => {
dangerousResetGlobalRouterUseForTestOnly();
window.history.pushState(null, '', `http://localhost?app_hash=${btoa('user')}&hash=done#product`);
const r = new Router<RouterTypes>({
'/': new Page<RouterTypes>(),
'/user': new Page('user'),
'/product': new Page<RouterTypes>('user'),
'/done': new Page<RouterTypes>('done'),
});
r.start('app_hash');
expect(r.getCurrentLocation().getPageId()).toBe('/user');
});
test('it should use modal id from query parameter', () => {
dangerousResetGlobalRouterUseForTestOnly();
window.history.pushState(
null,
'',
`http://localhost?app_hash=${btoa('?m=modal_features_intro&feature_key=museum_intro')}&hash=done#product`
);
const r = new Router<RouterTypes>({
'/': new Page<RouterTypes>(),
'/user': new Page('user'),
'/product': new Page<RouterTypes>('user'),
'/done': new Page<RouterTypes>('done'),
});
r.start('app_hash');
expect(r.getCurrentLocation().getModalId()).toBe('modal_features_intro');
});