mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-06-19 13:21:46 +00:00
fd48169219
Add and extend tests across 32 files (+10 595 lines) covering Admin panels (AuditLog, Backup, DevNotifications, GitHub), Collab (Chat, Notes, Panel, Polls), Planner (DayDetailPanel, DayPlanSidebar), Settings (DisplaySettings, Integrations, MapSettings), Files (FileManager, FilesPage), Map, Layout (DemoBanner, InAppNotificationBell), shared pickers (CustomDateTimePicker, CustomTimePicker), Vacay holidays, pages (Dashboard, Login), unit stores (authStore, inAppNotificationStore), API (authUrl, client integration), and i18n. Also updates sonar-project.properties and MSW trip handlers to support the new cases.
211 lines
7.2 KiB
TypeScript
211 lines
7.2 KiB
TypeScript
import { describe, it, expect, beforeEach, vi } from 'vitest'
|
|
import { render } from '@testing-library/react'
|
|
import React from 'react'
|
|
import {
|
|
TranslationProvider,
|
|
useTranslation,
|
|
getLocaleForLanguage,
|
|
getIntlLanguage,
|
|
isRtlLanguage,
|
|
SUPPORTED_LANGUAGES,
|
|
} from '../../../src/i18n'
|
|
import { resetAllStores, seedStore } from '../../helpers/store'
|
|
import { useSettingsStore } from '../../../src/store/settingsStore'
|
|
import { buildSettings } from '../../helpers/factories'
|
|
|
|
beforeEach(() => {
|
|
resetAllStores()
|
|
vi.clearAllMocks()
|
|
})
|
|
|
|
// ── FE-COMP-I18N-001: Barrel re-exports ───────────────────────────────────────
|
|
|
|
describe('barrel re-exports', () => {
|
|
it('FE-COMP-I18N-001: all named exports are defined with expected types', () => {
|
|
expect(TranslationProvider).toBeDefined()
|
|
expect(typeof TranslationProvider).toBe('function')
|
|
expect(useTranslation).toBeDefined()
|
|
expect(typeof useTranslation).toBe('function')
|
|
expect(getLocaleForLanguage).toBeDefined()
|
|
expect(typeof getLocaleForLanguage).toBe('function')
|
|
expect(getIntlLanguage).toBeDefined()
|
|
expect(typeof getIntlLanguage).toBe('function')
|
|
expect(isRtlLanguage).toBeDefined()
|
|
expect(typeof isRtlLanguage).toBe('function')
|
|
expect(SUPPORTED_LANGUAGES).toBeDefined()
|
|
expect(Array.isArray(SUPPORTED_LANGUAGES)).toBe(true)
|
|
})
|
|
})
|
|
|
|
// ── FE-COMP-I18N-002/003: getLocaleForLanguage ────────────────────────────────
|
|
|
|
describe('getLocaleForLanguage', () => {
|
|
it('FE-COMP-I18N-002: returns correct locale for known languages', () => {
|
|
expect(getLocaleForLanguage('en')).toBe('en-US')
|
|
expect(getLocaleForLanguage('de')).toBe('de-DE')
|
|
expect(getLocaleForLanguage('zh-TW')).toBe('zh-TW')
|
|
expect(getLocaleForLanguage('ar')).toBe('ar-SA')
|
|
expect(getLocaleForLanguage('br')).toBe('pt-BR')
|
|
})
|
|
|
|
it('FE-COMP-I18N-003: falls back to en-US for unknown language codes', () => {
|
|
expect(getLocaleForLanguage('xx')).toBe('en-US')
|
|
})
|
|
})
|
|
|
|
// ── FE-COMP-I18N-004/005/006: getIntlLanguage ─────────────────────────────────
|
|
|
|
describe('getIntlLanguage', () => {
|
|
it('FE-COMP-I18N-004: returns language code for known supported languages', () => {
|
|
expect(getIntlLanguage('de')).toBe('de')
|
|
expect(getIntlLanguage('fr')).toBe('fr')
|
|
expect(getIntlLanguage('zh-TW')).toBe('zh-TW')
|
|
})
|
|
|
|
it('FE-COMP-I18N-005: maps br to pt-BR', () => {
|
|
expect(getIntlLanguage('br')).toBe('pt-BR')
|
|
})
|
|
|
|
it('FE-COMP-I18N-006: falls back to en for unknown codes', () => {
|
|
expect(getIntlLanguage('xx')).toBe('en')
|
|
})
|
|
})
|
|
|
|
// ── FE-COMP-I18N-007/008: isRtlLanguage ──────────────────────────────────────
|
|
|
|
describe('isRtlLanguage', () => {
|
|
it('FE-COMP-I18N-007: returns true only for Arabic', () => {
|
|
expect(isRtlLanguage('ar')).toBe(true)
|
|
})
|
|
|
|
it('FE-COMP-I18N-008: returns false for all other supported languages', () => {
|
|
expect(isRtlLanguage('en')).toBe(false)
|
|
expect(isRtlLanguage('de')).toBe(false)
|
|
expect(isRtlLanguage('zh-TW')).toBe(false)
|
|
})
|
|
})
|
|
|
|
// ── FE-COMP-I18N-009: SUPPORTED_LANGUAGES ────────────────────────────────────
|
|
|
|
describe('SUPPORTED_LANGUAGES', () => {
|
|
it('FE-COMP-I18N-009: contains expected entries with value/label shape', () => {
|
|
expect(Array.isArray(SUPPORTED_LANGUAGES)).toBe(true)
|
|
expect(SUPPORTED_LANGUAGES).toHaveLength(14)
|
|
expect(SUPPORTED_LANGUAGES).toContainEqual({ value: 'en', label: 'English' })
|
|
expect(SUPPORTED_LANGUAGES).toContainEqual({ value: 'ar', label: 'العربية' })
|
|
})
|
|
})
|
|
|
|
// ── FE-COMP-I18N-010 to 015: TranslationProvider + useTranslation ─────────────
|
|
|
|
describe('TranslationProvider + useTranslation integration', () => {
|
|
it('FE-COMP-I18N-010: useTranslation returns t, language, and locale', () => {
|
|
seedStore(useSettingsStore, { settings: buildSettings({ language: 'en' }) })
|
|
|
|
let result: { language: string; locale: string; tResult: string } | null = null
|
|
|
|
function TestComponent() {
|
|
const { t, language, locale } = useTranslation()
|
|
result = { language, locale, tResult: t('common.loading') }
|
|
return null
|
|
}
|
|
|
|
render(
|
|
React.createElement(TranslationProvider, null, React.createElement(TestComponent))
|
|
)
|
|
|
|
expect(result).not.toBeNull()
|
|
expect(result!.language).toBe('en')
|
|
expect(result!.locale).toBe('en-US')
|
|
expect(result!.tResult).toBeTruthy()
|
|
expect(typeof result!.tResult).toBe('string')
|
|
})
|
|
|
|
it('FE-COMP-I18N-011: t() with params substitutes {count} placeholders', () => {
|
|
seedStore(useSettingsStore, { settings: buildSettings({ language: 'en' }) })
|
|
|
|
let translated = ''
|
|
|
|
function TestComponent() {
|
|
const { t } = useTranslation()
|
|
translated = t('dashboard.subtitle.trips', { count: 5, archived: 2 })
|
|
return null
|
|
}
|
|
|
|
render(
|
|
React.createElement(TranslationProvider, null, React.createElement(TestComponent))
|
|
)
|
|
|
|
expect(translated).toContain('5')
|
|
expect(translated).toContain('2')
|
|
expect(translated).not.toContain('{count}')
|
|
expect(translated).not.toContain('{archived}')
|
|
})
|
|
|
|
it('FE-COMP-I18N-012: TranslationProvider sets document.documentElement.lang', () => {
|
|
seedStore(useSettingsStore, { settings: buildSettings({ language: 'de' }) })
|
|
|
|
function TestComponent() {
|
|
useTranslation()
|
|
return null
|
|
}
|
|
|
|
render(
|
|
React.createElement(TranslationProvider, null, React.createElement(TestComponent))
|
|
)
|
|
|
|
expect(document.documentElement.lang).toBe('de')
|
|
})
|
|
|
|
it('FE-COMP-I18N-013: TranslationProvider sets dir=rtl for Arabic', () => {
|
|
seedStore(useSettingsStore, { settings: buildSettings({ language: 'ar' }) })
|
|
|
|
function TestComponent() {
|
|
useTranslation()
|
|
return null
|
|
}
|
|
|
|
render(
|
|
React.createElement(TranslationProvider, null, React.createElement(TestComponent))
|
|
)
|
|
|
|
expect(document.documentElement.dir).toBe('rtl')
|
|
})
|
|
|
|
it('FE-COMP-I18N-014: TranslationProvider sets dir=ltr for non-RTL language', () => {
|
|
seedStore(useSettingsStore, { settings: buildSettings({ language: 'en' }) })
|
|
|
|
function TestComponent() {
|
|
useTranslation()
|
|
return null
|
|
}
|
|
|
|
render(
|
|
React.createElement(TranslationProvider, null, React.createElement(TestComponent))
|
|
)
|
|
|
|
expect(document.documentElement.dir).toBe('ltr')
|
|
})
|
|
|
|
it('FE-COMP-I18N-015: t() falls back to English for unknown language', () => {
|
|
// Seed with a non-existent language to trigger fallback to English translations
|
|
seedStore(useSettingsStore, { settings: buildSettings({ language: 'xx' as any }) })
|
|
|
|
let translated = ''
|
|
|
|
function TestComponent() {
|
|
const { t } = useTranslation()
|
|
translated = t('common.loading')
|
|
return null
|
|
}
|
|
|
|
render(
|
|
React.createElement(TranslationProvider, null, React.createElement(TestComponent))
|
|
)
|
|
|
|
// Should fall back to English translation (non-empty, not the key itself if key exists in en)
|
|
expect(typeof translated).toBe('string')
|
|
expect(translated.length).toBeGreaterThan(0)
|
|
})
|
|
})
|