@ -28,6 +28,15 @@ vi.mock('~/api/config', () => ({
} ,
} ) ) ;
vi . mock ( '~/api/themes' , ( ) = > ( {
themesApi : {
list : vi.fn ( ) ,
create : vi.fn ( ) ,
update : vi.fn ( ) ,
remove : vi.fn ( ) ,
} ,
} ) ) ;
// Mock the SSE connection utility
vi . mock ( '~/utils/sse' , ( ) = > ( {
createSSEConnection : vi.fn ( ) ,
@ -36,6 +45,7 @@ vi.mock('~/utils/sse', () => ({
import { synthesesApi } from '~/api/syntheses' ;
import { settingsApi } from '~/api/settings' ;
import { configApi } from '~/api/config' ;
import { themesApi } from '~/api/themes' ;
import { createSSEConnection } from '~/utils/sse' ;
import GenerateSynthesis from '~/pages/GenerateSynthesis' ;
@ -44,6 +54,11 @@ const mockedListProviders = vi.mocked(configApi.listProviders);
const mockedGenerate = vi . mocked ( synthesesApi . generate ) ;
const mockedProgressUrl = vi . mocked ( synthesesApi . progressUrl ) ;
const mockedCreateSSE = vi . mocked ( createSSEConnection ) ;
const mockedListThemes = vi . mocked ( themesApi . list ) ;
const MOCK_THEMES = [
{ id : 'theme-1' , name : 'IA' , theme : 'Intelligence Artificielle' , categories : [ 'Cat1' ] , max_items_per_category : 5 , max_age_days : 7 , summary_length : 2 , created_at : '2026-03-01T00:00:00Z' , updated_at : '2026-03-01T00:00:00Z' } ,
] ;
afterEach ( ( ) = > {
vi . clearAllMocks ( ) ;
@ -53,6 +68,7 @@ describe('GenerateSynthesis Page', () => {
it ( 'should render launch button with settings info' , async ( ) = > {
mockedGetSettings . mockResolvedValue ( MOCK_SETTINGS ) ;
mockedListProviders . mockResolvedValue ( MOCK_PROVIDER_CONFIGS ) ;
mockedListThemes . mockResolvedValue ( MOCK_THEMES ) ;
renderWithProviders ( ( ) = > < GenerateSynthesis / > ) ;
@ -69,6 +85,7 @@ describe('GenerateSynthesis Page', () => {
it ( 'should call POST /syntheses/generate on launch' , async ( ) = > {
mockedGetSettings . mockResolvedValue ( MOCK_SETTINGS ) ;
mockedListProviders . mockResolvedValue ( MOCK_PROVIDER_CONFIGS ) ;
mockedListThemes . mockResolvedValue ( MOCK_THEMES ) ;
mockedGenerate . mockResolvedValue ( { job_id : 'job-123' } ) ;
mockedProgressUrl . mockReturnValue ( '/api/v1/syntheses/generate/job-123/progress' ) ;
@ -101,15 +118,16 @@ describe('GenerateSynthesis Page', () => {
it ( 'should show progress bar from SSE events' , async ( ) = > {
mockedGetSettings . mockResolvedValue ( MOCK_SETTINGS ) ;
mockedListProviders . mockResolvedValue ( MOCK_PROVIDER_CONFIGS ) ;
mockedListThemes . mockResolvedValue ( MOCK_THEMES ) ;
mockedGenerate . mockResolvedValue ( { job_id : 'job-123' } ) ;
mockedProgressUrl . mockReturnValue ( '/api/v1/syntheses/generate/job-123/progress' ) ;
const mockSSEConnection = {
events : vi.fn ( ( ) = > [
{ type : 'progress' as const , data : { step : 's earch', message : 'Recherche ...', percent : 25 } } ,
{ type : 'progress' as const , data : { step : 's ources', message : 'Analyse des sources ...', percent : 25 } } ,
] ) ,
status : vi.fn ( ( ) = > 'connected' as const ) ,
latestProgress : vi.fn ( ( ) = > ( { step : 's earch', message : 'Recherche ...', percent : 25 } ) ) ,
latestProgress : vi.fn ( ( ) = > ( { step : 's ources', message : 'Analyse des sources ...', percent : 25 } ) ) ,
completedSynthesisId : vi.fn ( ( ) = > null ) ,
errorMessage : vi.fn ( ( ) = > null ) ,
close : vi.fn ( ) ,
@ -128,22 +146,23 @@ describe('GenerateSynthesis Page', () => {
await waitFor ( ( ) = > {
expect ( screen . getByText ( '25%' ) ) . toBeInTheDocument ( ) ;
} ) ;
expect ( screen . getByText ( ' Recherche ...') ) . toBeInTheDocument ( ) ;
expect ( screen . getByText ( ' Analyse des sources ...') ) . toBeInTheDocument ( ) ;
} ) ;
it ( 'should render step checklist with correct states' , async ( ) = > {
mockedGetSettings . mockResolvedValue ( MOCK_SETTINGS ) ;
mockedListProviders . mockResolvedValue ( MOCK_PROVIDER_CONFIGS ) ;
mockedListThemes . mockResolvedValue ( MOCK_THEMES ) ;
mockedGenerate . mockResolvedValue ( { job_id : 'job-123' } ) ;
mockedProgressUrl . mockReturnValue ( '/api/v1/syntheses/generate/job-123/progress' ) ;
const mockSSEConnection = {
events : vi.fn ( ( ) = > [
{ type : 'progress' as const , data : { step : 's earch', message : 'Recherch e...', percent : 25 } } ,
{ type : 'progress' as const , data : { step : ' scraping', message : 'Verification ...', percent : 50 } } ,
{ type : 'progress' as const , data : { step : 's ources', message : 'Analys e...', percent : 25 } } ,
{ type : 'progress' as const , data : { step : ' websearch', message : 'Recherche web ...', percent : 50 } } ,
] ) ,
status : vi.fn ( ( ) = > 'connected' as const ) ,
latestProgress : vi.fn ( ( ) = > ( { step : ' scraping', message : 'Verification ...', percent : 50 } ) ) ,
latestProgress : vi.fn ( ( ) = > ( { step : ' websearch', message : 'Recherche web ...', percent : 50 } ) ) ,
completedSynthesisId : vi.fn ( ( ) = > null ) ,
errorMessage : vi.fn ( ( ) = > null ) ,
close : vi.fn ( ) ,
@ -161,14 +180,11 @@ describe('GenerateSynthesis Page', () => {
await waitFor ( ( ) = > {
expect (
screen . getByText ( "Recherche d'actualites" ) ,
screen . getByText ( 'Sources personnalisees' ) ,
) . toBeInTheDocument ( ) ;
} ) ;
expect (
screen . getByText ( 'Verification des sources' ) ,
) . toBeInTheDocument ( ) ;
expect (
screen . getByText ( 'Redaction des resumes' ) ,
screen . getByText ( 'Recherche web' ) ,
) . toBeInTheDocument ( ) ;
expect ( screen . getByText ( 'Sauvegarde' ) ) . toBeInTheDocument ( ) ;
} ) ;
@ -176,6 +192,7 @@ describe('GenerateSynthesis Page', () => {
it ( 'should show retry button on error' , async ( ) = > {
mockedGetSettings . mockResolvedValue ( MOCK_SETTINGS ) ;
mockedListProviders . mockResolvedValue ( MOCK_PROVIDER_CONFIGS ) ;
mockedListThemes . mockResolvedValue ( MOCK_THEMES ) ;
mockedGenerate . mockResolvedValue ( { job_id : 'job-123' } ) ;
mockedProgressUrl . mockReturnValue ( '/api/v1/syntheses/generate/job-123/progress' ) ;
@ -209,6 +226,7 @@ describe('GenerateSynthesis Page', () => {
it ( 'should show completion message on success' , async ( ) = > {
mockedGetSettings . mockResolvedValue ( MOCK_SETTINGS ) ;
mockedListProviders . mockResolvedValue ( MOCK_PROVIDER_CONFIGS ) ;
mockedListThemes . mockResolvedValue ( MOCK_THEMES ) ;
mockedGenerate . mockResolvedValue ( { job_id : 'job-123' } ) ;
mockedProgressUrl . mockReturnValue ( '/api/v1/syntheses/generate/job-123/progress' ) ;