@@ -199,51 +199,74 @@ describe("fetchAllCategories", () => {
199199} ) ;
200200
201201describe ( "fetchPreviousYearJobCategories" , ( ) => {
202- it ( "returns null when no submitted declaration exists for previous year" , async ( ) => {
202+ type PreviousDeclarationRow = { id : string } ;
203+ type JobCategoryRow = {
204+ name : string ;
205+ detail : string | null ;
206+ source : string ;
207+ categoryIndex : number ;
208+ } ;
209+
210+ /**
211+ * Builds a mocked Drizzle `tx` where:
212+ * - the first `select()` chain (declarations query) resolves to
213+ * `previousDeclarations` after `.orderBy()`
214+ * - each subsequent `select()` chain (jobCategories query per declaration)
215+ * resolves to the next entry in `jobsPerDeclaration` after `.where()`
216+ */
217+ const makeTx = (
218+ previousDeclarations : PreviousDeclarationRow [ ] ,
219+ jobsPerDeclaration : JobCategoryRow [ ] [ ] ,
220+ ) => {
221+ let selectCallCount = 0 ;
222+ const queuedJobs = [ ...jobsPerDeclaration ] ;
223+
224+ const mockSelect = vi . fn ( ) . mockImplementation ( ( ) => {
225+ selectCallCount ++ ;
226+ if ( selectCallCount === 1 ) {
227+ const mockOrderBy = vi . fn ( ) . mockResolvedValue ( previousDeclarations ) ;
228+ const mockWhere = vi . fn ( ) . mockReturnValue ( { orderBy : mockOrderBy } ) ;
229+ const mockFrom = vi . fn ( ) . mockReturnValue ( { where : mockWhere } ) ;
230+ return { from : mockFrom } ;
231+ }
232+ const mockWhere = vi . fn ( ) . mockResolvedValue ( queuedJobs . shift ( ) ?? [ ] ) ;
233+ const mockFrom = vi . fn ( ) . mockReturnValue ( { where : mockWhere } ) ;
234+ return { from : mockFrom } ;
235+ } ) ;
236+
237+ return { select : mockSelect } as never ;
238+ } ;
239+
240+ it ( "returns null when no submitted previous declaration exists" , async ( ) => {
203241 const { fetchPreviousYearJobCategories } = await import (
204242 "../declarationHelpers"
205243 ) ;
206244
207- const mockLimit = vi . fn ( ) . mockResolvedValue ( [ ] ) ;
208- const mockWhere = vi . fn ( ) . mockReturnValue ( { limit : mockLimit } ) ;
209- const mockFrom = vi . fn ( ) . mockReturnValue ( { where : mockWhere } ) ;
210- const mockSelect = vi . fn ( ) . mockReturnValue ( { from : mockFrom } ) ;
211-
212- const tx = { select : mockSelect } as never ;
245+ const tx = makeTx ( [ ] , [ ] ) ;
213246
214247 const result = await fetchPreviousYearJobCategories ( tx , "123456789" , 2026 ) ;
215248
216249 expect ( result ) . toBeNull ( ) ;
217250 } ) ;
218251
219- it ( "returns null when declaration exists but has no job categories" , async ( ) => {
252+ it ( "returns null when no previous declaration contains job categories" , async ( ) => {
220253 const { fetchPreviousYearJobCategories } = await import (
221254 "../declarationHelpers"
222255 ) ;
223256
224- let selectCallCount = 0 ;
225- const mockLimit = vi . fn ( ) . mockResolvedValue ( [ { id : "decl-prev" } ] ) ;
226- const mockWhere = vi . fn ( ) . mockImplementation ( ( ) => {
227- selectCallCount ++ ;
228- if ( selectCallCount === 1 ) return { limit : mockLimit } ;
229- return Promise . resolve ( [ ] ) ;
230- } ) ;
231- const mockFrom = vi . fn ( ) . mockReturnValue ( { where : mockWhere } ) ;
232- const mockSelect = vi . fn ( ) . mockReturnValue ( { from : mockFrom } ) ;
233-
234- const tx = { select : mockSelect } as never ;
257+ const tx = makeTx ( [ { id : "decl-2025" } , { id : "decl-2024" } ] , [ [ ] , [ ] ] ) ;
235258
236259 const result = await fetchPreviousYearJobCategories ( tx , "123456789" , 2026 ) ;
237260
238261 expect ( result ) . toBeNull ( ) ;
239262 } ) ;
240263
241- it ( "returns categories sorted by index with source from previous year " , async ( ) => {
264+ it ( "returns categories from the most recent previous declaration " , async ( ) => {
242265 const { fetchPreviousYearJobCategories } = await import (
243266 "../declarationHelpers"
244267 ) ;
245268
246- const mockJobs = [
269+ const mostRecentJobs : JobCategoryRow [ ] = [
247270 {
248271 name : "Employés" ,
249272 detail : "Support" ,
@@ -258,17 +281,7 @@ describe("fetchPreviousYearJobCategories", () => {
258281 } ,
259282 ] ;
260283
261- let selectCallCount = 0 ;
262- const mockLimit = vi . fn ( ) . mockResolvedValue ( [ { id : "decl-prev" } ] ) ;
263- const mockWhere = vi . fn ( ) . mockImplementation ( ( ) => {
264- selectCallCount ++ ;
265- if ( selectCallCount === 1 ) return { limit : mockLimit } ;
266- return Promise . resolve ( mockJobs ) ;
267- } ) ;
268- const mockFrom = vi . fn ( ) . mockReturnValue ( { where : mockWhere } ) ;
269- const mockSelect = vi . fn ( ) . mockReturnValue ( { from : mockFrom } ) ;
270-
271- const tx = { select : mockSelect } as never ;
284+ const tx = makeTx ( [ { id : "decl-2025" } ] , [ mostRecentJobs ] ) ;
272285
273286 const result = await fetchPreviousYearJobCategories ( tx , "123456789" , 2026 ) ;
274287
@@ -281,31 +294,48 @@ describe("fetchPreviousYearJobCategories", () => {
281294 } ) ;
282295 } ) ;
283296
284- it ( "uses empty string for null detail " , async ( ) => {
297+ it ( "falls back to an earlier year when N-1 has no job categories " , async ( ) => {
285298 const { fetchPreviousYearJobCategories } = await import (
286299 "../declarationHelpers"
287300 ) ;
288301
289- const mockJobs = [
302+ const olderJobs : JobCategoryRow [ ] = [
290303 {
291304 name : "Cadres" ,
292- detail : null ,
305+ detail : "Managers" ,
293306 source : "autre" ,
294307 categoryIndex : 0 ,
295308 } ,
296309 ] ;
297310
298- let selectCallCount = 0 ;
299- const mockLimit = vi . fn ( ) . mockResolvedValue ( [ { id : "decl-prev" } ] ) ;
300- const mockWhere = vi . fn ( ) . mockImplementation ( ( ) => {
301- selectCallCount ++ ;
302- if ( selectCallCount === 1 ) return { limit : mockLimit } ;
303- return Promise . resolve ( mockJobs ) ;
311+ const tx = makeTx (
312+ [ { id : "decl-2025" } , { id : "decl-2023" } ] ,
313+ [ [ ] , olderJobs ] ,
314+ ) ;
315+
316+ const result = await fetchPreviousYearJobCategories ( tx , "123456789" , 2026 ) ;
317+
318+ expect ( result ) . toEqual ( {
319+ source : "autre" ,
320+ categories : [ { name : "Cadres" , detail : "Managers" } ] ,
304321 } ) ;
305- const mockFrom = vi . fn ( ) . mockReturnValue ( { where : mockWhere } ) ;
306- const mockSelect = vi . fn ( ) . mockReturnValue ( { from : mockFrom } ) ;
322+ } ) ;
307323
308- const tx = { select : mockSelect } as never ;
324+ it ( "uses empty string for null detail" , async ( ) => {
325+ const { fetchPreviousYearJobCategories } = await import (
326+ "../declarationHelpers"
327+ ) ;
328+
329+ const jobs : JobCategoryRow [ ] = [
330+ {
331+ name : "Cadres" ,
332+ detail : null ,
333+ source : "autre" ,
334+ categoryIndex : 0 ,
335+ } ,
336+ ] ;
337+
338+ const tx = makeTx ( [ { id : "decl-2025" } ] , [ jobs ] ) ;
309339
310340 const result = await fetchPreviousYearJobCategories ( tx , "123456789" , 2026 ) ;
311341
0 commit comments