Add tests

This commit is contained in:
pjmalandrino 2026-03-20 09:42:14 +01:00
parent 7821cd397b
commit ea71f7247c
3 changed files with 242 additions and 0 deletions

View file

@ -0,0 +1,195 @@
import { describe, it, expect, vi, beforeEach } from 'vitest'
import { setActivePinia, createPinia } from 'pinia'
// Mock vue-router
const mockPush = vi.fn()
vi.mock('vue-router', () => ({
useRouter: () => ({ push: mockPush }),
}))
vi.mock('./api.js', () => ({
fetchAnalyses: vi.fn(),
deleteAnalysis: vi.fn(),
}))
vi.mock('../analysis/api.js', () => ({
fetchAnalyses: vi.fn(),
fetchAnalysis: vi.fn(),
createAnalysis: vi.fn(),
deleteAnalysis: vi.fn(),
}))
vi.mock('../document/api.js', () => ({
fetchDocuments: vi.fn(),
uploadDocument: vi.fn(),
deleteDocument: vi.fn(),
getPreviewUrl: vi.fn(),
}))
import { useHistoryStore } from './store.js'
import { useAnalysisStore } from '../analysis/store.js'
import { useDocumentStore } from '../document/store.js'
describe('History → Studio navigation', () => {
beforeEach(() => {
setActivePinia(createPinia())
vi.clearAllMocks()
})
describe('History store provides data for navigation', () => {
it('analyses contain documentId for document selection', async () => {
const { fetchAnalyses } = await import('./api.js')
fetchAnalyses.mockResolvedValue([
{ id: 'a1', documentId: 'd1', documentFilename: 'test.pdf', status: 'COMPLETED' },
{ id: 'a2', documentId: 'd2', documentFilename: 'other.pdf', status: 'FAILED' },
])
const store = useHistoryStore()
await store.load()
expect(store.analyses[0].documentId).toBe('d1')
expect(store.analyses[1].documentId).toBe('d2')
})
})
describe('Analysis store select() restores analysis state', () => {
it('select() sets currentAnalysis from fetched data', async () => {
const { fetchAnalysis } = await import('../analysis/api.js')
const analysis = {
id: 'a1',
documentId: 'd1',
status: 'COMPLETED',
contentMarkdown: '# Hello',
pagesJson: '[{"page_number":1}]',
}
fetchAnalysis.mockResolvedValue(analysis)
const store = useAnalysisStore()
await store.select('a1')
expect(store.currentAnalysis).toEqual(analysis)
expect(store.currentAnalysis.documentId).toBe('d1')
})
it('select() allows document store to select the associated document', async () => {
const { fetchAnalysis } = await import('../analysis/api.js')
fetchAnalysis.mockResolvedValue({
id: 'a1',
documentId: 'd1',
status: 'COMPLETED',
})
const analysisStore = useAnalysisStore()
const docStore = useDocumentStore()
docStore.documents = [
{ id: 'd1', filename: 'test.pdf' },
{ id: 'd2', filename: 'other.pdf' },
]
await analysisStore.select('a1')
docStore.select(analysisStore.currentAnalysis.documentId)
expect(docStore.selectedId).toBe('d1')
})
})
describe('Navigation intent from history items', () => {
it('completed analysis navigates to studio with analysisId query', () => {
// Simulates what HistoryList.openAnalysis does
const analysis = { id: 'a1', documentId: 'd1', status: 'COMPLETED' }
mockPush({ name: 'studio', query: { analysisId: analysis.id } })
expect(mockPush).toHaveBeenCalledWith({
name: 'studio',
query: { analysisId: 'a1' },
})
})
it('pending analysis navigates with same pattern', () => {
const analysis = { id: 'a2', documentId: 'd2', status: 'PENDING' }
mockPush({ name: 'studio', query: { analysisId: analysis.id } })
expect(mockPush).toHaveBeenCalledWith({
name: 'studio',
query: { analysisId: 'a2' },
})
})
it('failed analysis navigates with same pattern', () => {
const analysis = { id: 'a3', documentId: 'd3', status: 'FAILED' }
mockPush({ name: 'studio', query: { analysisId: analysis.id } })
expect(mockPush).toHaveBeenCalledWith({
name: 'studio',
query: { analysisId: 'a3' },
})
})
})
describe('Full restore flow (store-level integration)', () => {
it('restores completed analysis: selects analysis + document + verifier mode', async () => {
const { fetchAnalysis } = await import('../analysis/api.js')
fetchAnalysis.mockResolvedValue({
id: 'a1',
documentId: 'd1',
status: 'COMPLETED',
contentMarkdown: '# Result',
pagesJson: '[{"page_number":1,"width":612,"height":792}]',
})
const analysisStore = useAnalysisStore()
const docStore = useDocumentStore()
docStore.documents = [{ id: 'd1', filename: 'test.pdf' }]
// Simulate what StudioPage.onMounted does with ?analysisId=a1
await analysisStore.select('a1')
const analysis = analysisStore.currentAnalysis
expect(analysis).not.toBeNull()
docStore.select(analysis.documentId)
expect(docStore.selectedId).toBe('d1')
// Mode would be set to 'verifier' since status is COMPLETED
const mode = analysis.status === 'COMPLETED' ? 'verifier' : 'configurer'
expect(mode).toBe('verifier')
})
it('restores failed analysis: selects analysis + document, stays in configurer mode', async () => {
const { fetchAnalysis } = await import('../analysis/api.js')
fetchAnalysis.mockResolvedValue({
id: 'a2',
documentId: 'd2',
status: 'FAILED',
errorMessage: 'parse error',
})
const analysisStore = useAnalysisStore()
const docStore = useDocumentStore()
docStore.documents = [{ id: 'd2', filename: 'broken.pdf' }]
await analysisStore.select('a2')
const analysis = analysisStore.currentAnalysis
docStore.select(analysis.documentId)
expect(docStore.selectedId).toBe('d2')
const mode = analysis.status === 'COMPLETED' ? 'verifier' : 'configurer'
expect(mode).toBe('configurer')
})
it('handles missing analysis gracefully', async () => {
const { fetchAnalysis } = await import('../analysis/api.js')
fetchAnalysis.mockRejectedValue(new Error('Not found'))
vi.spyOn(console, 'error').mockImplementation(() => {})
const analysisStore = useAnalysisStore()
await analysisStore.select('nonexistent')
// currentAnalysis stays null on error — StudioPage would not proceed
expect(analysisStore.currentAnalysis).toBeNull()
})
})
})

View file

@ -59,4 +59,51 @@ describe('useI18n', () => {
const { t } = useI18n()
expect(t('results.pageOf', { current: 1, total: 5 })).toBe('Page 1 sur 5')
})
it('has history tab keys in French', () => {
useSettingsStore.mockReturnValue({ locale: 'fr' })
const { t } = useI18n()
expect(t('history.tabAnalyses')).toBe('Analyses')
expect(t('history.tabDocuments')).toBe('Documents')
expect(t('history.emptyDocs')).toBe('Aucun document. Importez un document depuis le Studio.')
})
it('has history tab keys in English', () => {
useSettingsStore.mockReturnValue({ locale: 'en' })
const { t } = useI18n()
expect(t('history.tabAnalyses')).toBe('Analyses')
expect(t('history.tabDocuments')).toBe('Documents')
expect(t('history.emptyDocs')).toBe('No documents yet. Upload a document from the Studio.')
})
it('has detailed pipeline option hints in French', () => {
useSettingsStore.mockReturnValue({ locale: 'fr' })
const { t } = useI18n()
// Hints should be longer than simple labels
expect(t('config.ocrHint').length).toBeGreaterThan(40)
expect(t('config.tableStructureHint').length).toBeGreaterThan(40)
expect(t('config.codeEnrichmentHint').length).toBeGreaterThan(40)
expect(t('config.formulaEnrichmentHint').length).toBeGreaterThan(40)
expect(t('config.pictureClassificationHint').length).toBeGreaterThan(40)
expect(t('config.pictureDescriptionHint').length).toBeGreaterThan(40)
expect(t('config.generatePictureImagesHint').length).toBeGreaterThan(40)
expect(t('config.generatePageImagesHint').length).toBeGreaterThan(40)
})
it('has detailed pipeline option hints in English', () => {
useSettingsStore.mockReturnValue({ locale: 'en' })
const { t } = useI18n()
expect(t('config.ocrHint').length).toBeGreaterThan(40)
expect(t('config.tableStructureHint').length).toBeGreaterThan(40)
expect(t('config.codeEnrichmentHint').length).toBeGreaterThan(40)
expect(t('config.formulaEnrichmentHint').length).toBeGreaterThan(40)
expect(t('config.pictureClassificationHint').length).toBeGreaterThan(40)
expect(t('config.pictureDescriptionHint').length).toBeGreaterThan(40)
expect(t('config.generatePictureImagesHint').length).toBeGreaterThan(40)
expect(t('config.generatePageImagesHint').length).toBeGreaterThan(40)
})
})