packages/__tests__/src/router/smoke-tests.spec.ts
import {
Constructable,
kebabCase,
} from '@aurelia/kernel';
import {
assert,
} from '@aurelia/testing';
import {
Router,
IRouter,
LoadInstruction,
Parameters,
RoutingInstruction,
Navigation,
IRouterOptions,
} from '@aurelia/router';
import {
customElement,
CustomElement,
} from '@aurelia/runtime-html';
import { createFixture, translateOptions } from './_shared/create-fixture.js';
import { IHIAConfig } from './_shared/hook-invocation-tracker.js';
function vp(count: number, name = ''): string {
if (count === 1) {
return `<au-viewport${name.length > 0 ? ` name="${name}"` : ''}></au-viewport>`;
}
let template = '';
for (let i = 0; i < count; ++i) {
template = `${template}<au-viewport name="${name}$${i}"></au-viewport>`;
}
return template;
}
function name(type: Constructable): string {
return kebabCase(type.name);
}
function getDefaultHIAConfig(): IHIAConfig {
return {
resolveTimeoutMs: 100,
resolveLabels: [],
};
}
type C = Constructable;
type CSpec = (C | CSpec)[];
function getText(spec: CSpec): string {
return spec.map(function (x) {
if (x instanceof Array) {
return getText(x);
}
return kebabCase(x.name);
}).join('');
}
function assertComponentsVisible(host: HTMLElement, spec: CSpec, msg: string = ''): void {
assert.strictEqual(host.textContent, getText(spec), msg);
}
function assertIsActive(
router: IRouter,
instruction: LoadInstruction,
options: any,
expected: boolean,
assertId: number,
): void {
if (options instanceof Router) {
options = {};
}
const isActive = router.checkActive(instruction, options);
assert.strictEqual(isActive, expected, `expected isActive to return ${expected} (assertId ${assertId})`);
}
describe('router/smoke-tests.spec.ts', function () {
describe('without any configuration, deps registered globally', function () {
@customElement({ name: 'a01', template: `a01${vp(0)}` })
class A01 { }
@customElement({ name: 'a02', template: `a02${vp(0)}` })
class A02 { }
const A0 = [A01, A02];
@customElement({ name: 'root1', template: `root1${vp(1)}` })
class Root1 { }
@customElement({ name: 'a11', template: `a11${vp(1)}` })
class A11 { }
@customElement({ name: 'a12', template: `a12${vp(1)}` })
class A12 { }
const A1 = [A11, A12];
@customElement({ name: 'root2', template: `root2${vp(2)}` })
class Root2 { }
@customElement({ name: 'a21', template: `a21${vp(2)}` })
class A21 { }
@customElement({ name: 'a22', template: `a22${vp(2)}` })
class A22 { }
const A2 = [A21, A22];
const A = [...A0, ...A1, ...A2];
@customElement({ name: 'b01', template: `b01${vp(0)}` })
class B01 {
public async canUnload(
_params: Parameters,
_instruction: RoutingInstruction,
_navigation: Navigation,
): Promise<true> {
await new Promise(function (resolve) { setTimeout(resolve, 0); });
return true;
}
}
@customElement({ name: 'b02', template: `b02${vp(0)}` })
class B02 {
public async canUnload(
_params: Parameters,
_instruction: RoutingInstruction,
_navigation: Navigation,
): Promise<false> {
await new Promise(function (resolve) { setTimeout(resolve, 0); });
return false;
}
}
const B0 = [B01, B02];
@customElement({ name: 'b11', template: `b11${vp(1)}` })
class B11 {
public async canUnload(
_params: Parameters,
_instruction: RoutingInstruction,
_navigation: Navigation,
): Promise<true> {
await new Promise(function (resolve) { setTimeout(resolve, 0); });
return true;
}
}
@customElement({ name: 'b12', template: `b12${vp(1)}` })
class B12 {
public async canUnload(
_params: Parameters,
_instruction: RoutingInstruction,
_navigation: Navigation,
): Promise<false> {
await new Promise(function (resolve) { setTimeout(resolve, 0); });
return false;
}
}
const B1 = [B11, B12];
const B = [...B0, ...B1];
const Z = [...A, ...B];
const getRouterOptions = (): IRouterOptions => translateOptions({});
// Start with a broad sample of non-generated tests that are easy to debug and mess around with.
it(`${name(Root1)} can load ${name(A01)} as a string and can determine if it's active`, async function () {
const { router, host, tearDown } = await createFixture(Root1, Z, getDefaultHIAConfig, getRouterOptions);
await router.load('a01');
assertComponentsVisible(host, [Root1, A01]);
assertIsActive(router, A01, {}, true, 1);
await tearDown();
});
it(`${name(Root1)} can load ${name(A01)} as a type and can determine if it's active`, async function () {
const { router, host, tearDown } = await createFixture(Root1, Z, getDefaultHIAConfig, getRouterOptions);
await router.load(A01);
assertComponentsVisible(host, [Root1, A01]);
assertIsActive(router, A01, {}, true, 1);
await tearDown();
});
it(`${name(Root1)} can load ${name(A01)} as a RoutingInstruction and can determine if it's active`, async function () {
const { router, host, tearDown } = await createFixture(Root1, Z, getDefaultHIAConfig, getRouterOptions);
await router.load({ component: A01 });
assertComponentsVisible(host, [Root1, A01]);
assertIsActive(router, { component: A01 }, {}, true, 1);
await tearDown();
});
it(`${name(Root1)} can load ${name(A01)} as a CustomElementDefinition and can determine if it's active`, async function () {
const { router, host, tearDown } = await createFixture(Root1, Z, getDefaultHIAConfig, getRouterOptions);
await router.load(CustomElement.getDefinition(A01));
assertComponentsVisible(host, [Root1, A01]);
assertIsActive(router, CustomElement.getDefinition(A01), {}, true, 1);
await tearDown();
});
it(`${name(Root1)} can load ({ name: 'a31', template: \`A31\${vp(0)}\` } as an object and can determine if it's active`, async function () {
const { router, host, tearDown } = await createFixture(Root1, Z, getDefaultHIAConfig, getRouterOptions);
const def = { name: 'a31', template: `a31${vp(0)}` };
await router.load(def);
const A31 = CustomElement.define(def);
assertComponentsVisible(host, [Root1, A31]);
assertIsActive(router, CustomElement.getDefinition(A31), {}, true, 1);
await tearDown();
});
it(`${name(Root1)} can load ${name(A01)},${name(A02)} in order and can determine if it's active`, async function () {
const { router, host, tearDown } = await createFixture(Root1, Z, getDefaultHIAConfig, getRouterOptions);
await router.load('a01');
assertComponentsVisible(host, [Root1, A01]);
assertIsActive(router, A01, {}, true, 1);
await router.load('a02');
assertComponentsVisible(host, [Root1, A02]);
assertIsActive(router, A02, {}, true, 2);
await tearDown();
});
it(`${name(Root1)} can load ${name(A11)},${name(A11)}/${name(A02)} in order with context and can determine if it's active`, async function () {
const { router, host, tearDown } = await createFixture(Root1, Z, getDefaultHIAConfig, getRouterOptions);
await router.load(A11);
assertComponentsVisible(host, [Root1, A11]);
assertIsActive(router, A11, {}, true, 1);
const loadOptions = { origin: router.allEndpoints('Viewport')[0].getContent().componentInstance }; // A11 view model
await router.load(A02, loadOptions);
assertComponentsVisible(host, [Root1, A11, A02]);
assertIsActive(router, A02, loadOptions, true, 2);
assertIsActive(router, A02, {}, false, 3);
assertIsActive(router, A11, {}, true, 3);
await tearDown();
});
it(`${name(Root1)} can load ${name(A11)}/${name(A01)},${name(A11)}/${name(A02)} in order with context`, async function () {
const { router, host, tearDown } = await createFixture(Root1, Z, getDefaultHIAConfig, getRouterOptions);
await router.load({ component: A11, children: [A01] });
assertComponentsVisible(host, [Root1, A11, A01]);
const loadOptions = { origin: router.allEndpoints('Viewport')[0].getContent().componentInstance }; // A11 view model
await router.load(A02, loadOptions);
assertComponentsVisible(host, [Root1, A11, A02]);
await tearDown();
});
it(`${name(Root1)} correctly handles canUnload with load ${name(B01)},${name(A01)} in order`, async function () {
const { router, host, tearDown } = await createFixture(Root1, Z, getDefaultHIAConfig, getRouterOptions);
let result = await router.load(B01);
assertComponentsVisible(host, [Root1, B01]);
assert.strictEqual(result, true, '#1 result===true');
result = await router.load(A01);
assertComponentsVisible(host, [Root1, A01]);
assert.strictEqual(result, true, '#2 result===true');
await tearDown();
});
it(`${name(Root1)} correctly handles canUnload with load ${name(B02)},${name(A01)} in order`, async function () {
const { router, host, tearDown } = await createFixture(Root1, Z, getDefaultHIAConfig, getRouterOptions);
let result = await router.load(B02);
assertComponentsVisible(host, [Root1, B02]);
assert.strictEqual(result, true, '#1 result===true');
result = await router.load(A01);
assertComponentsVisible(host, [Root1, B02]);
assert.strictEqual(result, false, '#2 result===false');
await tearDown();
});
it(`${name(Root1)} correctly handles canUnload with load ${name(B02)},${name(A01)},${name(A02)} in order`, async function () {
const { router, host, tearDown } = await createFixture(Root1, Z, getDefaultHIAConfig, getRouterOptions);
let result = await router.load(B02);
assertComponentsVisible(host, [Root1, B02], '#1');
assert.strictEqual(result, true, '#1 result===true');
result = await router.load(A01);
assertComponentsVisible(host, [Root1, B02], '#2');
assert.strictEqual(result, false, '#2 result===false');
result = await router.load(A02);
assertComponentsVisible(host, [Root1, B02], '#3');
assert.strictEqual(result, false, '#3 result===false');
await tearDown();
});
it(`${name(Root1)} correctly handles canUnload with load ${name(B11)}/${name(B02)},${name(B11)}/${name(A02)} in order`, async function () {
const { router, host, tearDown } = await createFixture(Root1, Z, getDefaultHIAConfig, getRouterOptions);
let result = await router.load(`b11/b02`);
assertComponentsVisible(host, [Root1, B11, [B02]]);
assert.strictEqual(result, true, '#1 result===true');
result = await router.load(`b11/a02`);
assertComponentsVisible(host, [Root1, B11, [B02]]);
assert.strictEqual(result, false, '#2 result===false');
await tearDown();
});
it(`${name(Root1)} correctly handles canUnload with load ${name(B12)}/${name(B01)},${name(B11)}/${name(B01)} in order`, async function () {
const { router, host, tearDown } = await createFixture(Root1, Z, getDefaultHIAConfig, getRouterOptions);
let result = await router.load(`b12/b01`);
assertComponentsVisible(host, [Root1, B12, [B01]]);
assert.strictEqual(result, true, '#1 result===true');
result = await router.load(`b11/b01`);
assertComponentsVisible(host, [Root1, B12, [B01]]);
assert.strictEqual(result, false, '#2 result===false');
await tearDown();
});
it(`${name(Root1)} correctly handles canUnload with load ${name(B12)}/${name(B01)},${name(B12)}/${name(A01)} in order`, async function () {
const { router, host, tearDown } = await createFixture(Root1, Z, getDefaultHIAConfig, getRouterOptions);
let result = await router.load(`b12/b01`);
assertComponentsVisible(host, [Root1, B12, [B01]]);
assert.strictEqual(result, true, '#1 result===true');
result = await router.load(`b12/a01`);
assertComponentsVisible(host, [Root1, B12, [A01]]);
assert.strictEqual(result, true, '#2 result===true');
await tearDown();
});
it(`${name(Root1)} can load ${name(A11)}/${name(A01)} as a string`, async function () {
const { router, host, tearDown } = await createFixture(Root1, Z, getDefaultHIAConfig, getRouterOptions);
await router.load(`a11/a01`);
assertComponentsVisible(host, [Root1, A11, A01]);
await tearDown();
});
it(`${name(Root1)} can load ${name(A11)}/${name(A01)} as a RoutingInstruction`, async function () {
const { router, host, tearDown } = await createFixture(Root1, Z, getDefaultHIAConfig, getRouterOptions);
await router.load({ component: A11, children: [A01] });
assertComponentsVisible(host, [Root1, A11, A01]);
await tearDown();
});
it(`${name(Root1)} can load ${name(A11)}/${name(A01)},${name(A11)}/${name(A02)} in order`, async function () {
const { router, host, tearDown } = await createFixture(Root1, Z, getDefaultHIAConfig, getRouterOptions);
await router.load(`a11/a01`);
assertComponentsVisible(host, [Root1, A11, A01]);
await router.load(`a11/a02`);
assertComponentsVisible(host, [Root1, A11, A02]);
await tearDown();
});
it(`${name(Root2)} can load ${name(A01)}@$0+${name(A02)}@$1 as a string`, async function () {
const { router, host, tearDown } = await createFixture(Root2, Z, getDefaultHIAConfig, getRouterOptions);
await router.load(`${name(A01)}@$0+${name(A02)}@$1`);
assertComponentsVisible(host, [Root2, A01, A02]);
await tearDown();
});
it(`${name(Root2)} can load ${name(A01)}@$0+${name(A02)}@$1 as an array of strings`, async function () {
const { router, host, tearDown } = await createFixture(Root2, Z, getDefaultHIAConfig, getRouterOptions);
await router.load([`${name(A01)}@$0`, `${name(A02)}@$1`]);
assertComponentsVisible(host, [Root2, A01, A02]);
await tearDown();
});
it(`${name(Root2)} can load ${name(A01)}@$0+${name(A02)}@$1 as an array of types`, async function () {
const { router, host, tearDown } = await createFixture(Root2, Z, getDefaultHIAConfig, getRouterOptions);
await router.load([{ component: A01, viewport: '$0' }, { component: A02, viewport: '$1' }]);
assertComponentsVisible(host, [Root2, A01, A02]);
await tearDown();
});
it(`${name(Root2)} can load ${name(A01)}@$0+${name(A02)}@$1 as a mixed array type and string`, async function () {
const { router, host, tearDown } = await createFixture(Root2, Z, getDefaultHIAConfig, getRouterOptions);
await router.load([{ component: A01, viewport: '$0' }, `${name(A02)}@$1`]);
assertComponentsVisible(host, [Root2, A01, A02]);
await tearDown();
});
it(`${name(Root2)} can load ${name(A01)}@$0+${name(A02)}@$1,${name(A02)}@$0+${name(A01)}@$1 in order`, async function () {
const { router, host, tearDown } = await createFixture(Root2, Z, getDefaultHIAConfig, getRouterOptions);
await router.load(`${name(A01)}@$0+${name(A02)}@$1`);
assertComponentsVisible(host, [Root2, A01, A02]);
await router.load(`${name(A02)}@$0+${name(A01)}@$1`);
assertComponentsVisible(host, [Root2, A02, A01]);
await tearDown();
});
it(`${name(Root2)} can load ${name(A11)}@$0/${name(A12)}/${name(A01)}+${name(A12)}@$1/${name(A01)},${name(A11)}@$0/${name(A12)}/${name(A01)}+${name(A12)}@$1/${name(A11)}/${name(A01)},${name(A11)}@$0/${name(A12)}/${name(A02)}+${name(A12)}@$1/${name(A11)}/${name(A01)} in order with context`, async function () {
const { router, host, tearDown } = await createFixture(Root2, Z, getDefaultHIAConfig, getRouterOptions);
await router.load(`${name(A11)}@$0/${name(A12)}/${name(A01)}+${name(A12)}@$1/${name(A01)}`);
assertComponentsVisible(host, [Root2, [A11, [A12, [A01]]], [A12, [A01]]], '#1');
let loadOptions = { origin: router.allEndpoints('Viewport')[1].getContent().componentInstance }; // Top A12 view model
await router.load(`${name(A11)}@$0/${name(A01)}`, loadOptions);
assertComponentsVisible(host, [Root2, [A11, [A12, [A01]]], [A12, [A11, [A01]]]], '#2');
loadOptions = { origin: router.allEndpoints('Viewport')[2].getContent().componentInstance }; // Second level A12 view model
await router.load(`${name(A02)}`, loadOptions);
assertComponentsVisible(host, [Root2, [A11, [A12, [A02]]], [A12, [A11, [A01]]]], '#3');
await tearDown();
});
// Now generate stuff
const $1vp: Record<string, CSpec> = {
// [x]
[`a01`]: [A01],
[`a02`]: [A02],
// [x/x]
[`a11/a01`]: [A11, [A01]],
[`a11/a02`]: [A11, [A02]],
[`a12/a01`]: [A12, [A01]],
[`a12/a02`]: [A12, [A02]],
// [x/x/x]
[`a11/a12/a01`]: [A11, [A12, [A01]]],
[`a11/a12/a02`]: [A11, [A12, [A02]]],
[`a12/a11/a01`]: [A12, [A11, [A01]]],
[`a12/a11/a02`]: [A12, [A11, [A02]]],
};
const $2vps: Record<string, CSpec> = {
// [x+x]
[`${name(A01)}@$0+${name(A02)}@$1`]: [[A01], [A02]],
[`${name(A02)}@$0+${name(A01)}@$1`]: [[A02], [A01]],
// [x/x+x]
[`${name(A11)}@$0/${name(A01)}+${name(A02)}@$1`]: [[A11, [A01]], [A02]],
[`${name(A11)}@$0/${name(A02)}+${name(A01)}@$1`]: [[A11, [A02]], [A01]],
[`${name(A12)}@$0/${name(A01)}+${name(A02)}@$1`]: [[A12, [A01]], [A02]],
[`${name(A12)}@$0/${name(A02)}+${name(A01)}@$1`]: [[A12, [A02]], [A01]],
// [x+x/x]
[`${name(A01)}@$0+${name(A11)}@$1/${name(A02)}`]: [[A01], [A11, [A02]]],
[`${name(A02)}@$0+${name(A11)}@$1/${name(A01)}`]: [[A02], [A11, [A01]]],
[`${name(A01)}@$0+${name(A12)}@$1/${name(A02)}`]: [[A01], [A12, [A02]]],
[`${name(A02)}@$0+${name(A12)}@$1/${name(A01)}`]: [[A02], [A12, [A01]]],
// [x/x+x/x]
[`${name(A11)}@$0/${name(A01)}+${name(A12)}@$1/${name(A02)}`]: [[A11, [A01]], [A12, [A02]]],
[`${name(A11)}@$0/${name(A02)}+${name(A12)}@$1/${name(A01)}`]: [[A11, [A02]], [A12, [A01]]],
[`${name(A12)}@$0/${name(A01)}+${name(A11)}@$1/${name(A02)}`]: [[A12, [A01]], [A11, [A02]]],
[`${name(A12)}@$0/${name(A02)}+${name(A11)}@$1/${name(A01)}`]: [[A12, [A02]], [A11, [A01]]],
};
const $1vpKeys = Object.keys($1vp);
for (let i = 0, ii = $1vpKeys.length; i < ii; ++i) {
const key11 = $1vpKeys[i];
const value11 = $1vp[key11];
it(`${name(Root1)} can load ${key11}`, async function () {
const { router, host, tearDown } = await createFixture(Root1, Z, getDefaultHIAConfig, getRouterOptions);
await router.load(key11);
assertComponentsVisible(host, [Root1, value11]);
await tearDown();
});
if (i >= 1) {
const key11prev = $1vpKeys[i - 1];
const value11prev = $1vp[key11prev];
it(`${name(Root1)} can load ${key11prev},${key11} in order`, async function () {
const { router, host, tearDown } = await createFixture(Root1, Z, getDefaultHIAConfig, getRouterOptions);
await router.load(key11prev);
assertComponentsVisible(host, [Root1, value11prev]);
await router.load(key11);
assertComponentsVisible(host, [Root1, value11]);
await tearDown();
});
it(`${name(Root1)} can load ${key11},${key11prev} in order`, async function () {
const { router, host, tearDown } = await createFixture(Root1, Z, getDefaultHIAConfig, getRouterOptions);
await router.load(key11);
assertComponentsVisible(host, [Root1, value11]);
await router.load(key11prev);
assertComponentsVisible(host, [Root1, value11prev]);
await tearDown();
});
}
}
const $2vpsKeys = Object.keys($2vps);
for (let i = 0, ii = $2vpsKeys.length; i < ii; ++i) {
const key21 = $2vpsKeys[i];
const value21 = $2vps[key21];
it(`${name(Root2)} can load ${key21}`, async function () {
const { router, host, tearDown } = await createFixture(Root2, Z, getDefaultHIAConfig, getRouterOptions);
await router.load(key21);
assertComponentsVisible(host, [Root2, value21]);
await tearDown();
});
if (i >= 1) {
const key21prev = $2vpsKeys[i - 1];
const value21prev = $2vps[key21prev];
it(`${name(Root2)} can load ${key21prev},${key21} in order`, async function () {
const { router, host, tearDown } = await createFixture(Root2, Z, getDefaultHIAConfig, getRouterOptions);
await router.load(key21prev);
assertComponentsVisible(host, [Root2, value21prev]);
await router.load(key21);
assertComponentsVisible(host, [Root2, value21]);
await tearDown();
});
it(`${name(Root2)} can load ${key21},${key21prev} in order`, async function () {
const { router, host, tearDown } = await createFixture(Root2, Z, getDefaultHIAConfig, getRouterOptions);
await router.load(key21);
assertComponentsVisible(host, [Root2, value21]);
await router.load(key21prev);
assertComponentsVisible(host, [Root2, value21prev]);
await tearDown();
});
}
}
});
});