Add 16 new test files covering: - Composables: useBackend, useMeta, useDataJson - Type classes: QueryResult, ResumeContent - UI components: BadgeList, BadgeListCard - Navbar components: LanguageSwitcher, ThemeSwitcher - App components: AppNavbar, AppFooter - VocalSynth components: Projects, Tools - Pages: contact, resume, [...slug] Tests focus on pure logic, interfaces, and component rendering where possible, avoiding complex mocking of Nuxt auto-imported composables. Total: 174 tests across 17 test files (including existing useApi tests).
162 lines
4.6 KiB
TypeScript
162 lines
4.6 KiB
TypeScript
import { describe, it, expect, vi } from 'vitest';
|
|
|
|
describe('AppFooter', () => {
|
|
describe('navigation items logic', () => {
|
|
const mockT = (key: string) => {
|
|
const translations: Record<string, string> = {
|
|
'footer.links.source': 'Source Code',
|
|
'footer.links.nuxt': 'Nuxt',
|
|
'footer.links.rust': 'Rust',
|
|
};
|
|
return translations[key] || key;
|
|
};
|
|
|
|
it('should generate footer navigation items', () => {
|
|
const items = computed(() => [
|
|
{
|
|
label: mockT('footer.links.source'),
|
|
to: 'https://labs.phundrak.com/phundrak/phundrak.com',
|
|
},
|
|
{
|
|
label: mockT('footer.links.nuxt'),
|
|
to: 'https://nuxt.com/',
|
|
},
|
|
{
|
|
label: mockT('footer.links.rust'),
|
|
to: 'https://rust-lang.org/',
|
|
},
|
|
]);
|
|
|
|
expect(items.value).toHaveLength(3);
|
|
expect(items.value[0].label).toBe('Source Code');
|
|
expect(items.value[0].to).toBe('https://labs.phundrak.com/phundrak/phundrak.com');
|
|
});
|
|
|
|
it('should include link to Nuxt', () => {
|
|
const items = computed(() => [
|
|
{
|
|
label: mockT('footer.links.nuxt'),
|
|
to: 'https://nuxt.com/',
|
|
},
|
|
]);
|
|
|
|
expect(items.value[0].to).toBe('https://nuxt.com/');
|
|
});
|
|
|
|
it('should include link to Rust', () => {
|
|
const items = computed(() => [
|
|
{
|
|
label: mockT('footer.links.rust'),
|
|
to: 'https://rust-lang.org/',
|
|
},
|
|
]);
|
|
|
|
expect(items.value[0].to).toBe('https://rust-lang.org/');
|
|
});
|
|
});
|
|
|
|
describe('backend version logic', () => {
|
|
const mockT = (key: string) => {
|
|
const translations: Record<string, string> = {
|
|
'backend.loading': 'Loading...',
|
|
'backend.failed': 'Failed to load',
|
|
};
|
|
return translations[key] || key;
|
|
};
|
|
|
|
it('should show loading text when loading', () => {
|
|
const mockLoading = ref(true);
|
|
const mockData = ref<{ version: string } | null>(null);
|
|
|
|
const backendVersion = computed(() =>
|
|
mockLoading.value ? 'backend.loading' : mockData.value?.version || mockT('backend.failed'),
|
|
);
|
|
|
|
expect(backendVersion.value).toBe('backend.loading');
|
|
});
|
|
|
|
it('should show version when data is loaded', () => {
|
|
const mockLoading = ref(false);
|
|
const mockData = ref({ version: '1.2.3' });
|
|
|
|
const backendVersion = computed(() =>
|
|
mockLoading.value ? 'backend.loading' : mockData.value?.version || mockT('backend.failed'),
|
|
);
|
|
|
|
expect(backendVersion.value).toBe('1.2.3');
|
|
});
|
|
|
|
it('should show failed text when no data', () => {
|
|
const mockLoading = ref(false);
|
|
const mockData = ref<{ version: string } | null>(null);
|
|
|
|
const backendVersion = computed(() =>
|
|
mockLoading.value ? 'backend.loading' : mockData.value?.version || mockT('backend.failed'),
|
|
);
|
|
|
|
expect(backendVersion.value).toBe('Failed to load');
|
|
});
|
|
});
|
|
|
|
describe('orientation logic', () => {
|
|
it('should use vertical orientation on mobile', () => {
|
|
const mockIsMobile = true;
|
|
const orientation = computed(() => (mockIsMobile ? 'vertical' : 'horizontal'));
|
|
|
|
expect(orientation.value).toBe('vertical');
|
|
});
|
|
|
|
it('should use horizontal orientation on desktop', () => {
|
|
const mockIsMobile = false;
|
|
const orientation = computed(() => (mockIsMobile ? 'vertical' : 'horizontal'));
|
|
|
|
expect(orientation.value).toBe('horizontal');
|
|
});
|
|
});
|
|
|
|
describe('error toast watcher', () => {
|
|
it('should call toast.add when error occurs', () => {
|
|
const mockToastAdd = vi.fn();
|
|
const mockError = ref<{ message: string } | null>(null);
|
|
|
|
// Simulate the watcher behavior
|
|
const triggerErrorWatcher = (error: { message: string } | null) => {
|
|
if (error) {
|
|
mockToastAdd({
|
|
title: 'Error',
|
|
description: error.message,
|
|
color: 'error',
|
|
});
|
|
}
|
|
};
|
|
|
|
mockError.value = { message: 'backend.errors.unknown' };
|
|
triggerErrorWatcher(mockError.value);
|
|
|
|
expect(mockToastAdd).toHaveBeenCalledWith({
|
|
title: 'Error',
|
|
description: 'backend.errors.unknown',
|
|
color: 'error',
|
|
});
|
|
});
|
|
|
|
it('should not call toast.add when error is null', () => {
|
|
const mockToastAdd = vi.fn();
|
|
|
|
const triggerErrorWatcher = (error: { message: string } | null) => {
|
|
if (error) {
|
|
mockToastAdd({
|
|
title: 'Error',
|
|
description: error.message,
|
|
color: 'error',
|
|
});
|
|
}
|
|
};
|
|
|
|
triggerErrorWatcher(null);
|
|
|
|
expect(mockToastAdd).not.toHaveBeenCalled();
|
|
});
|
|
});
|
|
});
|