Alan Agius 2640bf7a68 fix(@angular/ssr): correct route extraction and error handling
This commit introduces the following changes:
- Disallows paths starting with a slash to match Angular router behavior.
- Errors are now stored and displayed at a later stage, improving UX by avoiding unnecessary stack traces that are not useful in this context.
2024-09-16 21:22:10 +02:00

133 lines
4.2 KiB
TypeScript

/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.dev/license
*/
// The compiler is needed as tests are in JIT.
/* eslint-disable import/no-unassigned-import */
import '@angular/compiler';
/* eslint-enable import/no-unassigned-import */
import { Component } from '@angular/core';
import { AngularAppManifest, getAngularAppManifest } from '../../src/manifest';
import { RenderMode } from '../../src/routes/route-config';
import { ServerRouter } from '../../src/routes/router';
import { setAngularAppTestingManifest } from '../testing-utils';
describe('ServerRouter', () => {
let router: ServerRouter;
let manifest: AngularAppManifest;
beforeAll(() => {
@Component({
standalone: true,
selector: 'app-dummy',
template: `dummy works`,
})
class DummyComponent {}
setAngularAppTestingManifest(
[
{ path: 'home', component: DummyComponent },
{ path: 'redirect', redirectTo: 'home' },
{ path: 'encoding url', component: DummyComponent },
{ path: 'user/:id', component: DummyComponent },
],
[
{ path: 'redirect', renderMode: RenderMode.Server, status: 301 },
{ path: '**', renderMode: RenderMode.Server },
],
);
manifest = getAngularAppManifest();
});
describe('from', () => {
it('should build the route tree', async () => {
router = await ServerRouter.from(manifest, new URL('http://localhost'));
// Check that routes are correctly built
expect(router.match(new URL('http://localhost/home'))).toEqual({
route: '/home',
renderMode: RenderMode.Server,
});
expect(router.match(new URL('http://localhost/redirect'))).toEqual({
redirectTo: '/home',
route: '/redirect',
renderMode: RenderMode.Server,
status: 301,
});
expect(router.match(new URL('http://localhost/user/123'))).toEqual({
route: '/user/:id',
renderMode: RenderMode.Server,
});
});
it('should return the existing promise if a build from is already in progress', () => {
const promise1 = ServerRouter.from(manifest, new URL('http://localhost'));
const promise2 = ServerRouter.from(manifest, new URL('http://localhost'));
expect(promise1).toBe(promise2); // Ensure both promises are the same
});
});
describe('match', () => {
beforeAll(async () => {
router = await ServerRouter.from(manifest, new URL('http://localhost'));
});
it('should match a URL to the route tree metadata', () => {
const homeMetadata = router.match(new URL('http://localhost/home'));
const redirectMetadata = router.match(new URL('http://localhost/redirect'));
const userMetadata = router.match(new URL('http://localhost/user/123'));
expect(homeMetadata).toEqual({
route: '/home',
renderMode: RenderMode.Server,
});
expect(redirectMetadata).toEqual({
redirectTo: '/home',
route: '/redirect',
status: 301,
renderMode: RenderMode.Server,
});
expect(userMetadata).toEqual({
route: '/user/:id',
renderMode: RenderMode.Server,
});
});
it('should correctly match URLs ending with /index.html', () => {
const homeMetadata = router.match(new URL('http://localhost/home/index.html'));
const userMetadata = router.match(new URL('http://localhost/user/123/index.html'));
const redirectMetadata = router.match(new URL('http://localhost/redirect/index.html'));
expect(homeMetadata).toEqual({
route: '/home',
renderMode: RenderMode.Server,
});
expect(redirectMetadata).toEqual({
redirectTo: '/home',
route: '/redirect',
status: 301,
renderMode: RenderMode.Server,
});
expect(userMetadata).toEqual({
route: '/user/:id',
renderMode: RenderMode.Server,
});
});
it('should handle encoded URLs', () => {
const encodedUserMetadata = router.match(new URL('http://localhost/encoding%20url'));
expect(encodedUserMetadata).toEqual({
route: '/encoding url',
renderMode: RenderMode.Server,
});
});
});
});