release: v0.20.0
This commit is contained in:
72
app/__tests__/gate-page.test.tsx
Normal file
72
app/__tests__/gate-page.test.tsx
Normal file
@@ -0,0 +1,72 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { renderToStaticMarkup } from 'react-dom/server';
|
||||
|
||||
/**
|
||||
* A locked site still serves /impressum and /privacy (proxy.ts, UNGATED_PAGES),
|
||||
* and the gate is where a visitor who cannot get in finds them. A link to a
|
||||
* page that is switched off would lead to a 404, so each appears only when its
|
||||
* page exists.
|
||||
*/
|
||||
|
||||
const config = {
|
||||
siteTitle: 'Test Folio',
|
||||
lang: 'en',
|
||||
legal: { enabled: true },
|
||||
privacy: { enabled: true },
|
||||
};
|
||||
let privacy = true;
|
||||
|
||||
vi.mock('@/lib/config', () => ({
|
||||
getConfig: () => config,
|
||||
getConfigOrNull: () => config,
|
||||
}));
|
||||
vi.mock('@/lib/auth', () => ({
|
||||
isSiteLocked: () => true,
|
||||
SITE_AUTH_KEY: '__site__',
|
||||
}));
|
||||
vi.mock('@/lib/privacy', () => ({
|
||||
privacyAvailable: () => privacy,
|
||||
}));
|
||||
|
||||
import GatePage from '../gate/page';
|
||||
|
||||
const html = () => renderToStaticMarkup(<GatePage />);
|
||||
|
||||
describe('site gate page', () => {
|
||||
beforeEach(() => {
|
||||
config.lang = 'en';
|
||||
config.legal.enabled = true;
|
||||
privacy = true;
|
||||
});
|
||||
|
||||
it('links the legal notice and the privacy policy', () => {
|
||||
const out = html();
|
||||
expect(out).toContain('href="/impressum"');
|
||||
expect(out).toContain('href="/privacy"');
|
||||
expect(out).toContain('aria-label="Legal information"');
|
||||
});
|
||||
|
||||
it('leaves out a page that is switched off', () => {
|
||||
config.legal.enabled = false;
|
||||
expect(html()).not.toContain('href="/impressum"');
|
||||
expect(html()).toContain('href="/privacy"');
|
||||
|
||||
config.legal.enabled = true;
|
||||
privacy = false;
|
||||
expect(html()).toContain('href="/impressum"');
|
||||
expect(html()).not.toContain('href="/privacy"');
|
||||
});
|
||||
|
||||
it('renders no empty link list when neither page exists', () => {
|
||||
config.legal.enabled = false;
|
||||
privacy = false;
|
||||
expect(html()).not.toContain('<nav');
|
||||
});
|
||||
|
||||
it('labels the links in the site language', () => {
|
||||
config.lang = 'de';
|
||||
const out = html();
|
||||
expect(out).toContain('>Impressum</a>');
|
||||
expect(out).toContain('>Datenschutz</a>');
|
||||
});
|
||||
});
|
||||
29
app/__tests__/not-found-metadata.test.ts
Normal file
29
app/__tests__/not-found-metadata.test.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { describe, it, expect, vi } from 'vitest';
|
||||
|
||||
/**
|
||||
* A 404 decided before streaming — by proxy.ts, or by a page calling
|
||||
* notFound() outside any Suspense boundary — is rendered from app/not-found.tsx
|
||||
* inside the root layout, and Next takes its metadata from the layouts and
|
||||
* that file, never from the page. Without metadata of its own the tab showed
|
||||
* the bare site title, and the layout's `index, follow` sat next to Next's
|
||||
* `noindex`; the soft-404 path meanwhile read "Not found".
|
||||
*/
|
||||
|
||||
vi.mock('@/lib/i18n/server', async () => {
|
||||
const { getDictionary } = await import('@/lib/i18n');
|
||||
return { getServerDictionary: () => getDictionary('de') };
|
||||
});
|
||||
|
||||
import * as notFoundModule from '../not-found';
|
||||
import { getDictionary } from '@/lib/i18n';
|
||||
|
||||
describe('app/not-found.tsx metadata', () => {
|
||||
it('titles a hard 404 from the dictionary and drops the layout robots tag', async () => {
|
||||
const { generateMetadata } = notFoundModule as { generateMetadata?: () => unknown };
|
||||
expect(typeof generateMetadata).toBe('function');
|
||||
expect(await generateMetadata!()).toEqual({
|
||||
title: getDictionary('de').error.notFoundTitle,
|
||||
robots: null,
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user