import { describe, it, expect, beforeEach } from 'vitest';
import { mount, flushPromises } from '@vue/test-utils';
import { createPinia, setActivePinia } from 'pinia';
import { createRouter, createMemoryHistory } from 'vue-router';
import AppSidebar from '../components/AppSidebar.vue';
import { useVocabularyStore } from '../stores/vocabulary';
import { useUiStore } from '../stores/ui';
import type { Manifest } from '../adapters/types';
function makeManifest(id = 'test'): Manifest {
return {
id,
datasetUri: `https://glossarist.org/${id}/concept`,
title: `Test ${id}`,
description: 'A test dataset',
owner: 'ISO',
baseUrl: `/data/${id}`,
languages: ['eng'],
conceptCount: 50,
conceptUrlTemplate: `/data/${id}/concepts/{id}.json`,
indexUrl: `/data/${id}/index.json`,
contextUrl: `/data/${id}/context.json`,
uriBase: 'https://glossarist.org',
status: 'published',
schemaVersion: '1.0',
tags: [],
lastUpdated: '2025-01-01',
sourceRepo: 'https://example.com/repo',
chunkSize: 1000,
color: '#3366ff',
};
}
async function createTestRouter(initialPath = '/') {
const router = createRouter({
history: createMemoryHistory(),
routes: [
{ path: '/', name: 'home', component: { template: '
' } },
{ path: '/dataset/:registerId', name: 'dataset', component: { template: '' } },
{ path: '/dataset/:registerId/concept/:conceptId', name: 'concept', component: { template: '' } },
{ path: '/search', name: 'search', component: { template: '' } },
{ path: '/graph', name: 'graph', component: { template: '' } },
],
});
router.push(initialPath);
await router.isReady();
return router;
}
describe('AppSidebar', () => {
let pinia: ReturnType;
beforeEach(() => {
pinia = createPinia();
setActivePinia(pinia);
});
function seedStore(datasets: string[] = ['test']) {
const store = useVocabularyStore();
for (const id of datasets) {
store.manifests.set(id, makeManifest(id));
store.datasets.set(id, { index: [], getConceptCount: () => 0, getConcepts: () => [] } as any);
}
}
async function mountSidebar(initialPath = '/') {
const router = await createTestRouter(initialPath);
return mount(AppSidebar, {
global: { plugins: [pinia, router], stubs: { NavIcon: true } },
});
}
it('renders navigation section', async () => {
seedStore();
const wrapper = await mountSidebar();
expect(wrapper.text()).toContain('Navigation');
});
it('renders dataset entries in sidebar', async () => {
seedStore(['iso1', 'iso2']);
const wrapper = await mountSidebar();
expect(wrapper.text()).toContain('Test iso1');
expect(wrapper.text()).toContain('Test iso2');
});
it('shows concept count for loaded datasets', async () => {
seedStore();
const wrapper = await mountSidebar();
expect(wrapper.text()).toContain('50 concepts');
});
it('navigates to dataset on click', async () => {
seedStore();
const router = await createTestRouter('/');
const wrapper = mount(AppSidebar, {
global: { plugins: [pinia, router], stubs: { NavIcon: true } },
});
const dsBtn = wrapper.findAll('button').find(b => b.text().includes('Test test'));
expect(dsBtn).toBeDefined();
await dsBtn!.trigger('click');
await flushPromises();
expect(router.currentRoute.value.name).toBe('dataset');
expect(router.currentRoute.value.params.registerId).toBe('test');
});
it('closes sidebar on dataset click (mobile)', async () => {
seedStore();
const wrapper = await mountSidebar();
const ui = useUiStore();
ui.sidebarOpen = true;
const dsBtn = wrapper.findAll('button').find(b => b.text().includes('Test test'));
await dsBtn!.trigger('click');
expect(ui.sidebarOpen).toBe(false);
});
it('shows mobile backdrop when sidebar open', async () => {
seedStore();
const wrapper = await mountSidebar();
const ui = useUiStore();
ui.sidebarOpen = true;
await wrapper.vm.$nextTick();
const backdrop = wrapper.find('.fixed.inset-0');
expect(backdrop.exists()).toBe(true);
});
it('hides mobile backdrop when sidebar closed', async () => {
seedStore();
const wrapper = await mountSidebar();
const ui = useUiStore();
ui.sidebarOpen = false;
await wrapper.vm.$nextTick();
const backdrop = wrapper.find('.fixed.inset-0');
expect(backdrop.exists()).toBe(false);
});
it('closes sidebar on backdrop click', async () => {
seedStore();
const wrapper = await mountSidebar();
const ui = useUiStore();
ui.sidebarOpen = true;
await wrapper.vm.$nextTick();
const backdrop = wrapper.find('.fixed.inset-0');
await backdrop.trigger('click');
expect(ui.sidebarOpen).toBe(false);
});
it('shows dataset-level nav when on dataset route', async () => {
seedStore();
const wrapper = await mountSidebar('/dataset/test');
// The dataset nav section shows when currentManifest exists
expect(wrapper.text()).toContain('Test test');
});
});