Add tests
This commit is contained in:
parent
7821cd397b
commit
ea71f7247c
3 changed files with 242 additions and 0 deletions
Binary file not shown.
195
frontend/src/features/history/navigation.test.js
Normal file
195
frontend/src/features/history/navigation.test.js
Normal 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()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
@ -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)
|
||||
})
|
||||
})
|
||||
|
|
|
|||
Loading…
Reference in a new issue