Add tests

This commit is contained in:
cte 2025-05-12 11:38:02 -07:00
parent 6ee2266c36
commit b4cd909650
10 changed files with 108 additions and 16 deletions

View file

@ -55,7 +55,7 @@ jobs:
# CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
# - name: Install Playwright (used for Storybook and E2E tests)
# run: pnpx playwright install --with-deps
# run: npx playwright install --with-deps
# - name: Run storybook tests
# run: pnpm test-storybook:ci

View file

@ -5,4 +5,4 @@ if [ "$branch" = "main" ]; then
exit 1
fi
pnpx lint-staged
npx lint-staged

View file

@ -6,7 +6,7 @@
"check-types": "tsc --noEmit --pretty",
"test": "vitest run",
"test:e2e": "playwright test",
"dev:spotlight": "pnpx @spotlightjs/spotlight",
"dev:spotlight": "npx @spotlightjs/spotlight",
"dev:next": "next dev --turbopack",
"dev": "run-p dev:*",
"build": "next build",
@ -117,7 +117,7 @@
"prettier --write"
],
"src/**/*.{ts,tsx}": [
"pnpx eslint --max-warnings=0 --fix"
"npx eslint --max-warnings=0 --fix"
]
}
}

View file

@ -1,6 +1,6 @@
'use server';
import type { Locale } from '@/types/locale';
import type { Locale } from '@/lib/locale';
import { cookies } from 'next/headers';
export const setLocale = async (locale: Locale) => {

View file

@ -3,10 +3,10 @@ import '@/styles/globals.css';
import type { Metadata } from 'next';
import { NextIntlClientProvider } from 'next-intl';
import { getLocale } from 'next-intl/server';
import { enUS, frFR } from '@clerk/localizations';
import { ClerkProvider } from '@clerk/nextjs';
import { ThemeProvider } from '@/components/layout/ThemeProvider';
import { getClerkLocale } from '@/lib/locale';
import { ThemeProvider } from '@/components/layout';
export const metadata: Metadata = {
icons: [
@ -41,13 +41,8 @@ export default async function RootLayout({
suppressHydrationWarning
>
<NextIntlClientProvider>
<ThemeProvider
attribute="class"
defaultTheme="system"
enableSystem
disableTransitionOnChange
>
<ClerkProvider localization={locale === 'fr' ? frFR : enUS}>
<ThemeProvider attribute="class" defaultTheme="system" enableSystem>
<ClerkProvider localization={getClerkLocale(locale)}>
{children}
</ClerkProvider>
</ThemeProvider>

View file

@ -4,7 +4,7 @@ import { useCallback } from 'react';
import { useRouter } from 'next/navigation';
import { useLocale } from 'next-intl';
import { Locales, isLocale } from '@/types/locale';
import { Locales, isLocale } from '@/lib/locale';
import { setLocale } from '@/actions/locale';
import {
Button,

View file

@ -2,5 +2,6 @@ export { Navbar } from './Navbar';
export { Footer } from './Footer';
export { Section } from './Section';
export { LocaleSwitcher } from './LocaleSwitcher';
export { ThemeProvider } from './ThemeProvider';
export { ThemeSwitcher } from './ThemeSwitcher';
export { Logo } from './Logo';

View file

@ -1,5 +1,5 @@
import { cookies } from 'next/headers';
import { isLocale } from '@/types/locale';
import { isLocale } from '@/lib/locale';
import { getRequestConfig } from 'next-intl/server';
export default getRequestConfig(async (params) => {

81
src/lib/locale.test.ts Normal file
View file

@ -0,0 +1,81 @@
// npx vitest run src/lib/locale.test.ts
import { enUS, frFR } from '@clerk/localizations';
import { locales, isLocale, Locales, getClerkLocale, Locale } from './locale';
describe('locale module', () => {
describe('locales', () => {
it('should contain supported locales', () => {
expect(locales).toEqual(['en', 'fr']);
});
});
describe('isLocale', () => {
it('should return true for valid locales', () => {
expect(isLocale('en')).toBe(true);
expect(isLocale('fr')).toBe(true);
});
it('should return false for invalid locales', () => {
expect(isLocale('es')).toBe(false);
expect(isLocale('de')).toBe(false);
expect(isLocale('')).toBe(false);
expect(isLocale(undefined)).toBe(false);
});
it('should properly type-narrow the input', () => {
const testLocale = (locale: string | undefined): Locale | null => {
if (isLocale(locale)) {
const validLocale: Locale = locale;
return validLocale;
}
return null;
};
expect(testLocale('en')).toBe('en');
expect(testLocale('invalid')).toBe(null);
});
});
describe('Locales', () => {
it('should map locale codes to display names', () => {
expect(Locales).toEqual({
en: 'English',
fr: 'Français',
});
});
it('should have an entry for each supported locale', () => {
locales.forEach((locale) => {
expect(Locales[locale]).toBeDefined();
});
});
});
describe('getClerkLocale', () => {
it('should return enUS for "en" locale', () => {
expect(getClerkLocale('en')).toBe(enUS);
});
it('should return frFR for "fr" locale', () => {
expect(getClerkLocale('fr')).toBe(frFR);
});
it('should return enUS for invalid locales', () => {
expect(getClerkLocale('es')).toBe(enUS);
expect(getClerkLocale('de')).toBe(enUS);
expect(getClerkLocale('')).toBe(enUS);
// @ts-expect-error Testing with invalid type
expect(getClerkLocale(undefined)).toBe(enUS);
// @ts-expect-error Testing with invalid type
expect(getClerkLocale(null)).toBe(enUS);
});
it('should handle case sensitivity correctly', () => {
expect(getClerkLocale('EN')).toBe(enUS);
expect(getClerkLocale('Fr')).toBe(enUS);
});
});
});

View file

@ -1,3 +1,5 @@
import { enUS, frFR } from '@clerk/localizations';
export const locales = ['en', 'fr'] as const;
export type Locale = (typeof locales)[number];
@ -9,3 +11,16 @@ export const Locales: Record<Locale, string> = {
en: 'English',
fr: 'Français',
};
export const getClerkLocale = (locale: string) => {
if (!isLocale(locale)) {
return enUS;
}
switch (locale) {
case 'fr':
return frFR;
default:
return enUS;
}
};