@v4fire/client
Version:
V4Fire client core library
342 lines (266 loc) • 9.43 kB
JavaScript
// @ts-check
/*!
* V4Fire Client Core
* https://github.com/V4Fire/Client
*
* Released under the MIT license
* https://github.com/V4Fire/Client/blob/master/LICENSE
*/
/**
* @typedef {import('playwright').Page} Page
*/
const
{initRouter} = include('src/base/b-router/test/helpers/init');
/**
* Generates common specs for all router engines of "transition" runners
*
* @param {Page} page
* @param {'historyApiRouterEngine'|'inMemoryRouterEngine'} engineName
*/
module.exports.generateTransitionCommonSpecs = function generateTransitionCommonSpecs(page, engineName) {
describe('common', () => {
let
root;
beforeEach(async () => {
root = await initRouter(page, engineName);
});
it('transition to the default page', async () => {
expect(await root.evaluate(async (ctx) => {
await ctx.router.push('/some/fake/page');
return ctx.route.meta.content;
})).toBe('404');
expect(await root.evaluate(({route}) => route.name)).toBe('notFound');
if (engineName === 'historyApiRouterEngine') {
expect(new URL(await page.url()).pathname).toBe('/some/fake/page');
}
});
it('transition to an alias with parameters', async () => {
expect(await root.evaluate(async (ctx) => {
await ctx.router.push('/tpl-alias/foo/bar');
return ctx.route.params;
})).toEqual({param1: 'foo', param2: 'bar'});
if (engineName === 'historyApiRouterEngine') {
expect(new URL(await page.url()).pathname).toBe('/tpl-alias/foo/bar');
}
});
it('transition to an alias', async () => {
expect(await root.evaluate(async (ctx) => {
await ctx.router.push('/second/alias');
return ctx.route.meta.content;
})).toBe('Second page');
expect(await root.evaluate(({route}) => route.name)).toBe('secondAlias');
});
it('transition to an alias with redirect', async () => {
expect(await root.evaluate(async (ctx) => {
await ctx.router.push('/second/alias-redirect');
return ctx.route.meta.content;
})).toBe('Main page');
expect(await root.evaluate(({route}) => route.name)).toBe('aliasToRedirect');
});
it('transition to chained aliases', async () => {
expect(await root.evaluate(async (ctx) => {
await ctx.router.push('/alias-to-alias');
return ctx.route.meta.content;
})).toBe('Second page');
expect(await root.evaluate(({route}) => route.name)).toBe('aliasToAlias');
});
describe('transition with redirect', () => {
it('without parameters', async () => {
expect(await root.evaluate(async (ctx) => {
await ctx.router.push('/second/redirect');
return ctx.route.meta.content;
})).toBe('Second page');
expect(await root.evaluate(({route}) => route.name)).toBe('second');
});
it('with parameters', async () => {
expect(await root.evaluate(async (ctx) => {
await ctx.router.push('/tpl/redirect/1/2');
return ctx.route.params;
})).toEqual({param1: '1', param2: '2'});
if (engineName === 'historyApiRouterEngine') {
expect(new URL(await page.url()).pathname).toBe('/tpl/1/2');
}
});
});
it('transition with redirect and alias', async () => {
expect(await root.evaluate(async (ctx) => {
await ctx.router.push('/redirect-alias');
return ctx.route.meta.content;
})).toBe('Second page');
expect(await root.evaluate(({route}) => route.name)).toBe('secondAlias');
});
it('transition with chained redirect', async () => {
expect(await root.evaluate(async (ctx) => {
await ctx.router.push('/redirect-redirect');
return ctx.route.meta.content;
})).toBe('Second page');
expect(await root.evaluate(({route}) => route.name)).toBe('second');
});
it('moving back and forward from one page to another', async () => {
expect(await root.evaluate(async (ctx) => {
await ctx.router.push('main');
return ctx.route.meta.content;
})).toBe('Main page');
expect(await root.evaluate(async (ctx) => {
await ctx.router.push('second');
return ctx.route.meta.content;
})).toBe('Second page');
expect(await root.evaluate(async (ctx) => {
await ctx.router.back();
return ctx.route.meta.content;
})).toBe('Main page');
expect(await root.evaluate(async (ctx) => {
await ctx.router.forward();
return ctx.route.meta.content;
})).toBe('Second page');
});
it('moving back and forward from one page to another by using .go', async () => {
expect(await root.evaluate(async ({router}) => {
await router.push('main');
await router.push('second');
await router.push('main');
await router.push('second');
return router.route.meta.content;
})).toBe('Second page');
expect(await root.evaluate(async ({router}) => {
await router.go(-2);
return router.route.meta.content;
})).toBe('Second page');
expect(await root.evaluate(async ({router}) => {
await router.go(1);
return router.route.meta.content;
})).toBe('Main page');
});
it('soft transition', async () => {
expect(await root.evaluate(async (ctx) => {
const
{router} = ctx;
const
result = {};
await router.push('/second');
await router.push('/');
result.initialQuery = location.search;
result.initialContent = ctx.route.meta.content;
router.on('onSoftChange', (route) => {
if (result.onSoftChange) {
result.onSoftChange.push(Object.fastClone(route.query));
} else {
result.onSoftChange = [
Object.fastClone(ctx.route.query),
Object.fastClone(route.query)
];
}
});
await router.push(null, {query: {foo: 1}});
result.modifiedQuery = location.search;
result.modifiedContent = ctx.route.meta.content;
await router.push(null, {query: {bar: 2}});
result.modifiedQuery2 = location.search;
result.modifiedContent2 = ctx.route.meta.content;
await router.push(null, {query: {foo: null, bar: undefined}});
result.modifiedQuery3 = location.search;
result.modifiedContent3 = ctx.route.meta.content;
await router.push(null, {query: {bla: [1, 2]}});
result.modifiedQuery4 = location.search;
result.modifiedContent4 = ctx.route.meta.content;
await router.push(null, {query: {bla: [3]}});
result.modifiedQuery5 = location.search;
result.modifiedContent5 = ctx.route.meta.content;
return result;
})).toEqual({
initialContent: 'Main page',
initialQuery: '',
modifiedContent: 'Main page',
modifiedQuery: engineName === 'inMemoryRouterEngine' ? '' : '?foo=1',
modifiedContent2: 'Main page',
modifiedQuery2: engineName === 'inMemoryRouterEngine' ? '' : '?bar=2&foo=1',
modifiedContent3: 'Main page',
modifiedQuery3: engineName === 'inMemoryRouterEngine' ? '' : '?bar=2',
modifiedContent4: 'Main page',
modifiedQuery4: engineName === 'inMemoryRouterEngine' ? '' : '?bar=2&bla=1&bla=2',
modifiedContent5: 'Main page',
modifiedQuery5: engineName === 'inMemoryRouterEngine' ? '' : '?bar=2&bla=3',
onSoftChange: [
{},
{foo: 1},
{foo: 1, bar: 2},
{foo: null, bar: 2},
{foo: null, bar: 2, bla: [1, 2]},
{foo: null, bar: 2, bla: [3]}
]
});
});
it('transition event flow', async () => {
expect(await root.evaluate(async (ctx) => {
const
{router} = ctx;
const
result = {};
await router.push('/second');
await router.push('/');
result.initialQuery = location.search;
result.initialContent = ctx.route.meta.content;
router.once('onBeforeChange', (route, {query}) => {
query.bla = 1;
});
router.once('onHardChange', (route) => {
result.onHardChange = [
Object.fastClone(ctx.route.query),
Object.fastClone(route.query)
];
});
router.once('onChange', (route) => {
result.onChange = [
Object.fastClone(ctx.route.query),
Object.fastClone(route.query)
];
});
router.once('onTransition', (route) => {
result.onTransition = [
Object.fastClone(ctx.route.query),
Object.fastClone(route.query)
];
});
ctx.rootEmitter.once('onTransition', (route) => {
result.onRootTransition = [
Object.fastClone(ctx.route.query),
Object.fastClone(route.query)
];
});
await router.push('second', {query: {foo: 1}});
result.modifiedQuery = location.search;
result.modifiedContent = ctx.route.meta.content;
return result;
})).toEqual({
initialContent: 'Main page',
initialQuery: '',
modifiedContent: 'Second page',
modifiedQuery: engineName === 'inMemoryRouterEngine' ? '' : '?bla=1&foo=1',
onHardChange: [{}, {foo: 1, bla: 1}],
onChange: [{foo: 1, bla: 1}, {foo: 1, bla: 1}],
onTransition: [{foo: 1, bla: 1}, {foo: 1, bla: 1}],
onRootTransition: [{foo: 1, bla: 1}, {foo: 1, bla: 1}]
});
});
it('transition with root parameters', async () => {
expect(await root.evaluate(async (ctx) => {
const
{router} = ctx;
await router.push('/second');
await router.push('/');
// eslint-disable-next-line require-atomic-updates
ctx.rootParam = 1;
await router.push('second');
// eslint-disable-next-line require-atomic-updates
ctx.rootParam = undefined;
return {
queryObject: ctx.route.query,
queryString: location.search
};
})).toEqual({
queryObject: {rootParam: 1},
queryString: engineName === 'inMemoryRouterEngine' ? '' : '?rootParam=1'
});
});
});
};