test(docs-infra): ensure all redirect rules are tested (#42452)
This commit adds a test assertion to verify that all redirect rules defined in `firebase.json` are tested, i.e. that each rule is applied to at least one testcase from `URLS_TO_REDIRECT.txt`. This will ensure that any redirect rules added in the future will be tested. PR Close #42452
This commit is contained in:
parent
c66423ab2a
commit
c397b59855
|
@ -12,6 +12,7 @@ import { FirebaseRedirector, FirebaseRedirectConfig } from '../../../tools/fireb
|
||||||
|
|
||||||
|
|
||||||
const AIO_DIR = resolvePath(__dirname, '../../..');
|
const AIO_DIR = resolvePath(__dirname, '../../..');
|
||||||
|
export const PATH_TO_LEGACY_URLS = resolvePath(__dirname, 'URLS_TO_REDIRECT.txt');
|
||||||
|
|
||||||
export function getRedirector() {
|
export function getRedirector() {
|
||||||
return new FirebaseRedirector(loadRedirects());
|
return new FirebaseRedirector(loadRedirects());
|
||||||
|
@ -40,8 +41,7 @@ export function loadRedirects(): FirebaseRedirectConfig[] {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function loadLegacyUrls() {
|
export function loadLegacyUrls() {
|
||||||
const pathToLegacyUrls = `${__dirname}/URLS_TO_REDIRECT.txt`;
|
const urls = readFileSync(PATH_TO_LEGACY_URLS, 'utf8')
|
||||||
const urls = readFileSync(pathToLegacyUrls, 'utf8')
|
|
||||||
.split('\n')
|
.split('\n')
|
||||||
.filter(line => line.trim() !== '')
|
.filter(line => line.trim() !== '')
|
||||||
.map(line => line.split(/\s*-->\s*/));
|
.map(line => line.split(/\s*-->\s*/));
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
import { getRedirector, loadLegacyUrls, loadLocalSitemapUrls, loadRedirects } from '../shared/helpers';
|
import {
|
||||||
|
getRedirector, loadLegacyUrls, loadLocalSitemapUrls, loadRedirects, PATH_TO_LEGACY_URLS,
|
||||||
|
} from '../shared/helpers';
|
||||||
|
|
||||||
describe('firebase.json redirect config', () => {
|
describe('firebase.json redirect config', () => {
|
||||||
describe('with sitemap urls', () => {
|
describe('with sitemap urls', () => {
|
||||||
|
@ -14,6 +16,14 @@ describe('firebase.json redirect config', () => {
|
||||||
describe('with legacy urls', () => {
|
describe('with legacy urls', () => {
|
||||||
const redirector = getRedirector();
|
const redirector = getRedirector();
|
||||||
|
|
||||||
|
afterAll(() => {
|
||||||
|
expect(redirector.unusedRedirectConfigs)
|
||||||
|
.withContext(
|
||||||
|
'Some redirect rules from \'firebase.json\' were not tested. ' +
|
||||||
|
`Ensure there is at least one testcase for each redirect rule in '${PATH_TO_LEGACY_URLS}'.`)
|
||||||
|
.toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
loadLegacyUrls().forEach(urlPair => {
|
loadLegacyUrls().forEach(urlPair => {
|
||||||
it(`should redirect legacy URL '${urlPair[0]}'`, () => {
|
it(`should redirect legacy URL '${urlPair[0]}'`, () => {
|
||||||
const redirected = redirector.redirect(urlPair[0]);
|
const redirected = redirector.redirect(urlPair[0]);
|
||||||
|
|
|
@ -6,7 +6,8 @@ export class FirebaseRedirect {
|
||||||
source: FirebaseRedirectSource;
|
source: FirebaseRedirectSource;
|
||||||
destination: string;
|
destination: string;
|
||||||
|
|
||||||
constructor({source, regex, destination}: FirebaseRedirectConfig) {
|
constructor(readonly rawConfig: FirebaseRedirectConfig) {
|
||||||
|
const {source, regex, destination} = rawConfig;
|
||||||
this.source = (typeof source === 'string') ?
|
this.source = (typeof source === 'string') ?
|
||||||
FirebaseRedirectSource.fromGlobPattern(source) :
|
FirebaseRedirectSource.fromGlobPattern(source) :
|
||||||
FirebaseRedirectSource.fromRegexPattern(regex!);
|
FirebaseRedirectSource.fromRegexPattern(regex!);
|
||||||
|
|
|
@ -39,4 +39,25 @@ describe('FirebaseRedirector', () => {
|
||||||
]);
|
]);
|
||||||
expect(() => redirector.redirect('a')).toThrowError('infinite redirect loop');
|
expect(() => redirector.redirect('a')).toThrowError('infinite redirect loop');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should keep track of unused redirects', () => {
|
||||||
|
const redirects = [
|
||||||
|
{ source: '/a', destination: '/A' },
|
||||||
|
{ regex: '^/b$', destination: '/B' },
|
||||||
|
{ source: '/c', destination: '/C' },
|
||||||
|
];
|
||||||
|
const redirector = new FirebaseRedirector(redirects);
|
||||||
|
|
||||||
|
expect(redirector.unusedRedirectConfigs).toEqual([redirects[0], redirects[1], redirects[2]]);
|
||||||
|
|
||||||
|
redirector.redirect('/a');
|
||||||
|
expect(redirector.unusedRedirectConfigs).toEqual([redirects[1], redirects[2]]);
|
||||||
|
|
||||||
|
redirector.redirect('/not-redirected');
|
||||||
|
expect(redirector.unusedRedirectConfigs).toEqual([redirects[1], redirects[2]]);
|
||||||
|
|
||||||
|
redirector.redirect('/b');
|
||||||
|
redirector.redirect('/c');
|
||||||
|
expect(redirector.unusedRedirectConfigs).toEqual([]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -6,8 +6,15 @@ export type FirebaseRedirectConfig =
|
||||||
|
|
||||||
export class FirebaseRedirector {
|
export class FirebaseRedirector {
|
||||||
private redirects: FirebaseRedirect[];
|
private redirects: FirebaseRedirect[];
|
||||||
|
private unusedRedirects: Set<FirebaseRedirect>;
|
||||||
|
|
||||||
|
get unusedRedirectConfigs(): FirebaseRedirectConfig[] {
|
||||||
|
return [...this.unusedRedirects].map(({rawConfig}) => rawConfig);
|
||||||
|
}
|
||||||
|
|
||||||
constructor(redirects: FirebaseRedirectConfig[]) {
|
constructor(redirects: FirebaseRedirectConfig[]) {
|
||||||
this.redirects = redirects.map(redirect => new FirebaseRedirect(redirect));
|
this.redirects = redirects.map(redirect => new FirebaseRedirect(redirect));
|
||||||
|
this.unusedRedirects = new Set(this.redirects);
|
||||||
}
|
}
|
||||||
|
|
||||||
redirect(url: string): string {
|
redirect(url: string): string {
|
||||||
|
@ -28,6 +35,7 @@ export class FirebaseRedirector {
|
||||||
for (const redirect of this.redirects) {
|
for (const redirect of this.redirects) {
|
||||||
const newUrl = redirect.replace(url);
|
const newUrl = redirect.replace(url);
|
||||||
if (newUrl !== undefined) {
|
if (newUrl !== undefined) {
|
||||||
|
this.unusedRedirects.delete(redirect);
|
||||||
return newUrl;
|
return newUrl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue