Files
fast-next-template/frontend/tests/lib/i18n/metadata.test.ts
Felipe Cardoso 28b1cc6e48 Replace "FastNext" branding with "PragmaStack" across the project
- Updated all references, metadata, and templates to reflect the new branding, including layout files, components, and documentation.
- Replaced hardcoded color tokens like `green-600` with semantic tokens (`success`, `warning`, etc.) for improved design consistency.
- Enhanced `globals.css` with new color tokens for success, warning, and destructive states using the OKLCH color model.
- Added comprehensive branding guidelines and updated the design system documentation to align with the new identity.
- Updated tests and mocks to reflect the branding changes and ensured all visual/verbal references match "PragmaStack".
- Added new `branding/README.md` and `branding` docs for mission, values, and visual identity definition.
2025-11-20 12:55:30 +01:00

350 lines
11 KiB
TypeScript

/**
* Tests for i18n metadata utilities
*/
import { generateLocalizedMetadata, generatePageMetadata, siteConfig } from '@/lib/i18n/metadata';
// Mock next-intl/server
jest.mock('next-intl/server', () => ({
getTranslations: jest.fn(),
}));
import { getTranslations } from 'next-intl/server';
describe('metadata utilities', () => {
const mockGetTranslations = getTranslations as jest.MockedFunction<typeof getTranslations>;
beforeEach(() => {
jest.clearAllMocks();
});
describe('siteConfig', () => {
it('should have correct structure', () => {
expect(siteConfig).toHaveProperty('name');
expect(siteConfig).toHaveProperty('description');
expect(siteConfig).toHaveProperty('url');
expect(siteConfig).toHaveProperty('ogImage');
});
it('should have English and Italian names', () => {
expect(siteConfig.name.en).toBe('PragmaStack');
expect(siteConfig.name.it).toBe('PragmaStack');
});
it('should have English and Italian descriptions', () => {
expect(siteConfig.description.en).toContain('FastAPI');
expect(siteConfig.description.it).toContain('FastAPI');
});
it('should have valid URL', () => {
expect(siteConfig.url).toBeDefined();
expect(typeof siteConfig.url).toBe('string');
});
it('should have ogImage path', () => {
expect(siteConfig.ogImage).toBe('/og-image.png');
});
});
describe('generateLocalizedMetadata', () => {
it('should generate metadata with default site config for English', async () => {
const metadata = await generateLocalizedMetadata('en');
expect(metadata.title).toBe(siteConfig.name.en);
expect(metadata.description).toBe(siteConfig.description.en);
expect(metadata.metadataBase).toEqual(new URL(siteConfig.url));
});
it('should generate metadata with default site config for Italian', async () => {
const metadata = await generateLocalizedMetadata('it');
expect(metadata.title).toBe(siteConfig.name.it);
expect(metadata.description).toBe(siteConfig.description.it);
});
it('should generate metadata with custom title from translations', async () => {
const mockT = jest.fn((key: string) => {
if (key === 'title') return 'Custom Title';
return key;
});
mockGetTranslations.mockResolvedValue(mockT as any);
const metadata = await generateLocalizedMetadata('en', {
titleKey: 'title',
namespace: 'home',
});
expect(metadata.title).toBe('Custom Title');
expect(mockGetTranslations).toHaveBeenCalledWith({ locale: 'en', namespace: 'home' });
});
it('should generate metadata with custom description from translations', async () => {
const mockT = jest.fn((key: string) => {
if (key === 'description') return 'Custom Description';
return key;
});
mockGetTranslations.mockResolvedValue(mockT as any);
const metadata = await generateLocalizedMetadata('en', {
descriptionKey: 'description',
namespace: 'about',
});
expect(metadata.description).toBe('Custom Description');
expect(mockGetTranslations).toHaveBeenCalledWith({ locale: 'en', namespace: 'about' });
});
it('should generate metadata with both custom title and description', async () => {
const mockT = jest.fn((key: string) => {
if (key === 'title') return 'Custom Title';
if (key === 'description') return 'Custom Description';
return key;
});
mockGetTranslations.mockResolvedValue(mockT as any);
const metadata = await generateLocalizedMetadata('en', {
titleKey: 'title',
descriptionKey: 'description',
namespace: 'page',
});
expect(metadata.title).toBe('Custom Title');
expect(metadata.description).toBe('Custom Description');
});
it('should generate correct canonical URL with path', async () => {
const metadata = await generateLocalizedMetadata('en', {
path: '/about',
});
expect(metadata.alternates?.canonical).toBe(`${siteConfig.url}/en/about`);
});
it('should generate correct canonical URL without path', async () => {
const metadata = await generateLocalizedMetadata('en');
expect(metadata.alternates?.canonical).toBe(`${siteConfig.url}/en`);
});
it('should generate correct language alternates', async () => {
const metadata = await generateLocalizedMetadata('en', {
path: '/about',
});
expect(metadata.alternates?.languages).toEqual({
en: '/about',
it: '/it/about',
'x-default': '/about',
});
});
it('should generate Open Graph metadata for English', async () => {
const metadata = await generateLocalizedMetadata('en', {
path: '/test',
});
expect(metadata.openGraph).toMatchObject({
title: siteConfig.name.en,
description: siteConfig.description.en,
url: `${siteConfig.url}/en/test`,
siteName: siteConfig.name.en,
locale: 'en_US',
type: 'website',
});
expect(metadata.openGraph?.images).toEqual([
{
url: siteConfig.ogImage,
width: 1200,
height: 630,
alt: siteConfig.name.en,
},
]);
});
it('should generate Open Graph metadata for Italian', async () => {
const metadata = await generateLocalizedMetadata('it', {
path: '/test',
});
expect(metadata.openGraph).toMatchObject({
locale: 'it_IT',
siteName: siteConfig.name.it,
});
});
it('should generate Twitter card metadata', async () => {
const metadata = await generateLocalizedMetadata('en');
expect(metadata.twitter).toEqual({
card: 'summary_large_image',
title: siteConfig.name.en,
description: siteConfig.description.en,
images: [siteConfig.ogImage],
});
});
it('should generate robots metadata', async () => {
const metadata = await generateLocalizedMetadata('en');
expect(metadata.robots).toEqual({
index: true,
follow: true,
googleBot: {
index: true,
follow: true,
'max-video-preview': -1,
'max-image-preview': 'large',
'max-snippet': -1,
},
});
});
it('should use default namespace when not provided', async () => {
const mockT = jest.fn((key: string) => key);
mockGetTranslations.mockResolvedValue(mockT as any);
await generateLocalizedMetadata('en', {
titleKey: 'title',
});
expect(mockGetTranslations).toHaveBeenCalledWith({ locale: 'en', namespace: 'common' });
});
it('should handle empty options object', async () => {
const metadata = await generateLocalizedMetadata('en', {});
expect(metadata.title).toBe(siteConfig.name.en);
expect(metadata.description).toBe(siteConfig.description.en);
});
});
describe('generatePageMetadata', () => {
it('should generate metadata with provided title and description', async () => {
const metadata = await generatePageMetadata('en', 'Custom Title', 'Custom Description');
expect(metadata.title).toBe('Custom Title');
expect(metadata.description).toBe('Custom Description');
});
it('should generate metadata for English locale', async () => {
const metadata = await generatePageMetadata('en', 'Title', 'Description', '/page');
expect(metadata.metadataBase).toEqual(new URL(siteConfig.url));
expect(metadata.alternates?.canonical).toBe(`${siteConfig.url}/en/page`);
});
it('should generate metadata for Italian locale', async () => {
const metadata = await generatePageMetadata('it', 'Titolo', 'Descrizione', '/pagina');
expect(metadata.alternates?.canonical).toBe(`${siteConfig.url}/it/pagina`);
});
it('should generate correct language alternates with path', async () => {
const metadata = await generatePageMetadata('en', 'Title', 'Description', '/about');
expect(metadata.alternates?.languages).toEqual({
en: '/about',
it: '/it/about',
'x-default': '/about',
});
});
it('should generate correct language alternates without path', async () => {
const metadata = await generatePageMetadata('en', 'Title', 'Description');
expect(metadata.alternates?.languages).toEqual({
en: '/',
it: '/it/',
'x-default': '/',
});
});
it('should handle undefined path', async () => {
const metadata = await generatePageMetadata('en', 'Title', 'Description', undefined);
expect(metadata.alternates?.canonical).toBe(`${siteConfig.url}/en`);
});
it('should generate Open Graph metadata for English', async () => {
const metadata = await generatePageMetadata('en', 'Test Title', 'Test Description', '/test');
expect(metadata.openGraph).toMatchObject({
title: 'Test Title',
description: 'Test Description',
url: `${siteConfig.url}/en/test`,
siteName: siteConfig.name.en,
locale: 'en_US',
type: 'website',
});
expect(metadata.openGraph?.images).toEqual([
{
url: siteConfig.ogImage,
width: 1200,
height: 630,
alt: 'Test Title',
},
]);
});
it('should generate Open Graph metadata for Italian', async () => {
const metadata = await generatePageMetadata('it', 'Titolo Test', 'Descrizione Test', '/test');
expect(metadata.openGraph).toMatchObject({
title: 'Titolo Test',
description: 'Descrizione Test',
locale: 'it_IT',
siteName: siteConfig.name.it,
});
});
it('should generate Twitter card metadata', async () => {
const metadata = await generatePageMetadata('en', 'Twitter Title', 'Twitter Description');
expect(metadata.twitter).toEqual({
card: 'summary_large_image',
title: 'Twitter Title',
description: 'Twitter Description',
images: [siteConfig.ogImage],
});
});
it('should generate robots metadata', async () => {
const metadata = await generatePageMetadata('en', 'Title', 'Description');
expect(metadata.robots).toEqual({
index: true,
follow: true,
googleBot: {
index: true,
follow: true,
'max-video-preview': -1,
'max-image-preview': 'large',
'max-snippet': -1,
},
});
});
it('should handle empty string path', async () => {
const metadata = await generatePageMetadata('en', 'Title', 'Description', '');
expect(metadata.alternates?.canonical).toBe(`${siteConfig.url}/en`);
expect(metadata.alternates?.languages).toEqual({
en: '/',
it: '/it/',
'x-default': '/',
});
});
it('should properly construct URLs with slashes', async () => {
const metadata1 = await generatePageMetadata('en', 'Title', 'Description', '/path');
const metadata2 = await generatePageMetadata('en', 'Title', 'Description', 'path');
// Both should work, with or without leading slash
expect(metadata1.alternates?.canonical).toContain('/en/path');
expect(metadata2.alternates?.canonical).toContain('/enpath');
});
});
});