11import { beforeEach , describe , expect , it , vi } from 'vitest'
22
3+ import type { QueryExecutor } from '../../queryExecutor'
4+ import {
5+ buildTimeline ,
6+ resolveAffiliationsByMemberIds ,
7+ selectPrimaryWorkExperience ,
8+ } from '../index'
9+ import type { IWorkExperienceResolution } from '../index'
10+
311// Mocks are hoisted before imports — intercept transitive dependencies that
412// require a live database or external services.
513vi . mock ( '@crowd/database' , ( ) => ( { } ) )
@@ -21,14 +29,6 @@ vi.mock('../../members/base', () => ({
2129 BLACKLISTED_MEMBER_TITLES : [ 'investor' , 'mentor' , 'board member' ] ,
2230} ) )
2331
24- import type { QueryExecutor } from '../../queryExecutor'
25- import {
26- buildTimeline ,
27- resolveAffiliationsByMemberIds ,
28- selectPrimaryWorkExperience ,
29- } from '../index'
30- import type { IWorkExperienceResolution } from '../index'
31-
3232// ---------------------------------------------------------------------------
3333// Helpers
3434// ---------------------------------------------------------------------------
@@ -70,8 +70,16 @@ describe('selectPrimaryWorkExperience', () => {
7070 } )
7171
7272 it ( 'picks the manual affiliation (segmentId != null) over work experiences' , ( ) => {
73- const workExp = makeRow ( { organizationId : 'work' , organizationName : 'Work Inc' , segmentId : null } )
74- const manual = makeRow ( { organizationId : 'manual' , organizationName : 'Manual Org' , segmentId : 'seg-1' } )
73+ const workExp = makeRow ( {
74+ organizationId : 'work' ,
75+ organizationName : 'Work Inc' ,
76+ segmentId : null ,
77+ } )
78+ const manual = makeRow ( {
79+ organizationId : 'manual' ,
80+ organizationName : 'Manual Org' ,
81+ segmentId : 'seg-1' ,
82+ } )
7583 const result = selectPrimaryWorkExperience ( [ workExp , manual ] )
7684 expect ( result . organizationName ) . toBe ( 'Manual Org' )
7785 } )
@@ -96,7 +104,11 @@ describe('selectPrimaryWorkExperience', () => {
96104 } )
97105
98106 it ( 'picks the isPrimaryWorkExperience=true row when no manual affiliations exist' , ( ) => {
99- const plain = makeRow ( { organizationId : 'plain' , organizationName : 'Plain' , dateStart : '2018-01-01' } )
107+ const plain = makeRow ( {
108+ organizationId : 'plain' ,
109+ organizationName : 'Plain' ,
110+ dateStart : '2018-01-01' ,
111+ } )
100112 const primary = makeRow ( {
101113 organizationId : 'primary' ,
102114 organizationName : 'Primary' ,
@@ -126,7 +138,11 @@ describe('selectPrimaryWorkExperience', () => {
126138
127139 it ( 'picks the single dated org when no primary and only one has a dateStart' , ( ) => {
128140 const undated = makeRow ( { organizationId : 'u' , organizationName : 'Undated' , dateStart : null } )
129- const dated = makeRow ( { organizationId : 'd' , organizationName : 'Dated' , dateStart : '2020-01-01' } )
141+ const dated = makeRow ( {
142+ organizationId : 'd' ,
143+ organizationName : 'Dated' ,
144+ dateStart : '2020-01-01' ,
145+ } )
130146 const result = selectPrimaryWorkExperience ( [ undated , dated ] )
131147 expect ( result . organizationName ) . toBe ( 'Dated' )
132148 } )
@@ -189,7 +205,11 @@ describe('buildTimeline', () => {
189205 } )
190206
191207 it ( 'produces a single closed period for an org with both start and end dates' , ( ) => {
192- const org = makeRow ( { organizationName : 'Acme' , dateStart : '2020-01-01' , dateEnd : '2022-12-31' } )
208+ const org = makeRow ( {
209+ organizationName : 'Acme' ,
210+ dateStart : '2020-01-01' ,
211+ dateEnd : '2022-12-31' ,
212+ } )
193213 // afterEnd boundary: day after dateEnd
194214 const boundaries = [ startOfDay ( '2020-01-01' ) , startOfDay ( '2023-01-01' ) ]
195215
@@ -205,10 +225,24 @@ describe('buildTimeline', () => {
205225 } )
206226
207227 it ( 'produces two sequential periods when orgs share a boundary with no gap' , ( ) => {
208- const org1 = makeRow ( { organizationId : 'o1' , organizationName : 'Org1' , dateStart : '2018-01-01' , dateEnd : '2020-12-31' } )
209- const org2 = makeRow ( { organizationId : 'o2' , organizationName : 'Org2' , dateStart : '2021-01-01' , dateEnd : null } )
228+ const org1 = makeRow ( {
229+ organizationId : 'o1' ,
230+ organizationName : 'Org1' ,
231+ dateStart : '2018-01-01' ,
232+ dateEnd : '2020-12-31' ,
233+ } )
234+ const org2 = makeRow ( {
235+ organizationId : 'o2' ,
236+ organizationName : 'Org2' ,
237+ dateStart : '2021-01-01' ,
238+ dateEnd : null ,
239+ } )
210240 // 2021-01-01 is both the afterEnd of org1 and the dateStart of org2
211- const boundaries = [ startOfDay ( '2018-01-01' ) , startOfDay ( '2021-01-01' ) , startOfDay ( '2026-01-01' ) ]
241+ const boundaries = [
242+ startOfDay ( '2018-01-01' ) ,
243+ startOfDay ( '2021-01-01' ) ,
244+ startOfDay ( '2026-01-01' ) ,
245+ ]
212246
213247 const result = buildTimeline ( [ org1 , org2 ] , null , boundaries )
214248
@@ -227,10 +261,25 @@ describe('buildTimeline', () => {
227261 } )
228262
229263 it ( 'fills a gap between two orgs with the fallback org' , ( ) => {
230- const org1 = makeRow ( { organizationId : 'o1' , organizationName : 'Org1' , dateStart : '2018-01-01' , dateEnd : '2019-12-31' } )
231- const org2 = makeRow ( { organizationId : 'o2' , organizationName : 'Org2' , dateStart : '2021-01-01' , dateEnd : null } )
264+ const org1 = makeRow ( {
265+ organizationId : 'o1' ,
266+ organizationName : 'Org1' ,
267+ dateStart : '2018-01-01' ,
268+ dateEnd : '2019-12-31' ,
269+ } )
270+ const org2 = makeRow ( {
271+ organizationId : 'o2' ,
272+ organizationName : 'Org2' ,
273+ dateStart : '2021-01-01' ,
274+ dateEnd : null ,
275+ } )
232276 const fallback = makeRow ( { organizationId : 'fb' , organizationName : 'Fallback' } )
233- const boundaries = [ startOfDay ( '2018-01-01' ) , startOfDay ( '2020-01-01' ) , startOfDay ( '2021-01-01' ) , startOfDay ( '2026-01-01' ) ]
277+ const boundaries = [
278+ startOfDay ( '2018-01-01' ) ,
279+ startOfDay ( '2020-01-01' ) ,
280+ startOfDay ( '2021-01-01' ) ,
281+ startOfDay ( '2026-01-01' ) ,
282+ ]
234283
235284 const result = buildTimeline ( [ org1 , org2 ] , fallback , boundaries )
236285
@@ -254,9 +303,24 @@ describe('buildTimeline', () => {
254303 } )
255304
256305 it ( 'leaves a gap unfilled when there is no fallback org' , ( ) => {
257- const org1 = makeRow ( { organizationId : 'o1' , organizationName : 'Org1' , dateStart : '2018-01-01' , dateEnd : '2019-12-31' } )
258- const org2 = makeRow ( { organizationId : 'o2' , organizationName : 'Org2' , dateStart : '2021-01-01' , dateEnd : null } )
259- const boundaries = [ startOfDay ( '2018-01-01' ) , startOfDay ( '2020-01-01' ) , startOfDay ( '2021-01-01' ) , startOfDay ( '2026-01-01' ) ]
306+ const org1 = makeRow ( {
307+ organizationId : 'o1' ,
308+ organizationName : 'Org1' ,
309+ dateStart : '2018-01-01' ,
310+ dateEnd : '2019-12-31' ,
311+ } )
312+ const org2 = makeRow ( {
313+ organizationId : 'o2' ,
314+ organizationName : 'Org2' ,
315+ dateStart : '2021-01-01' ,
316+ dateEnd : null ,
317+ } )
318+ const boundaries = [
319+ startOfDay ( '2018-01-01' ) ,
320+ startOfDay ( '2020-01-01' ) ,
321+ startOfDay ( '2021-01-01' ) ,
322+ startOfDay ( '2026-01-01' ) ,
323+ ]
260324
261325 const result = buildTimeline ( [ org1 , org2 ] , null , boundaries )
262326
@@ -275,9 +339,18 @@ describe('buildTimeline', () => {
275339 } )
276340
277341 it ( 'extends the fallback org to cover a trailing gap after the last dated org ends' , ( ) => {
278- const org1 = makeRow ( { organizationId : 'o1' , organizationName : 'Org1' , dateStart : '2018-01-01' , dateEnd : '2019-12-31' } )
342+ const org1 = makeRow ( {
343+ organizationId : 'o1' ,
344+ organizationName : 'Org1' ,
345+ dateStart : '2018-01-01' ,
346+ dateEnd : '2019-12-31' ,
347+ } )
279348 const fallback = makeRow ( { organizationId : 'fb' , organizationName : 'Fallback' } )
280- const boundaries = [ startOfDay ( '2018-01-01' ) , startOfDay ( '2020-01-01' ) , startOfDay ( '2026-01-01' ) ]
349+ const boundaries = [
350+ startOfDay ( '2018-01-01' ) ,
351+ startOfDay ( '2020-01-01' ) ,
352+ startOfDay ( '2026-01-01' ) ,
353+ ]
281354
282355 const result = buildTimeline ( [ org1 ] , fallback , boundaries )
283356
@@ -310,7 +383,12 @@ describe('buildTimeline', () => {
310383 dateEnd : null ,
311384 memberCount : 100 ,
312385 } )
313- const boundaries = [ startOfDay ( '2018-01-01' ) , startOfDay ( '2020-01-01' ) , startOfDay ( '2022-01-01' ) , startOfDay ( '2026-01-01' ) ]
386+ const boundaries = [
387+ startOfDay ( '2018-01-01' ) ,
388+ startOfDay ( '2020-01-01' ) ,
389+ startOfDay ( '2022-01-01' ) ,
390+ startOfDay ( '2026-01-01' ) ,
391+ ]
314392
315393 const result = buildTimeline ( [ low , high ] , null , boundaries )
316394
@@ -329,9 +407,23 @@ describe('buildTimeline', () => {
329407 } )
330408
331409 it ( 'undated org in allRows competes at every boundary and takes over after the dated org ends' , ( ) => {
332- const undated = makeRow ( { organizationId : 'undated' , organizationName : 'Undated' , dateStart : null , dateEnd : null } )
333- const dated = makeRow ( { organizationId : 'dated' , organizationName : 'Dated' , dateStart : '2020-01-01' , dateEnd : '2020-12-31' } )
334- const boundaries = [ startOfDay ( '2020-01-01' ) , startOfDay ( '2021-01-01' ) , startOfDay ( '2026-01-01' ) ]
410+ const undated = makeRow ( {
411+ organizationId : 'undated' ,
412+ organizationName : 'Undated' ,
413+ dateStart : null ,
414+ dateEnd : null ,
415+ } )
416+ const dated = makeRow ( {
417+ organizationId : 'dated' ,
418+ organizationName : 'Dated' ,
419+ dateStart : '2020-01-01' ,
420+ dateEnd : '2020-12-31' ,
421+ } )
422+ const boundaries = [
423+ startOfDay ( '2020-01-01' ) ,
424+ startOfDay ( '2021-01-01' ) ,
425+ startOfDay ( '2026-01-01' ) ,
426+ ]
335427
336428 const result = buildTimeline ( [ undated , dated ] , null , boundaries )
337429
@@ -447,8 +539,22 @@ describe('resolveAffiliationsByMemberIds', () => {
447539 } )
448540
449541 it ( 'processes multiple members independently' , async ( ) => {
450- const m1row = makeRow ( { id : 'r1' , memberId : 'm1' , organizationId : 'o1' , organizationName : 'Acme' , dateStart : '2020-01-01' , dateEnd : null } )
451- const m2row = makeRow ( { id : 'r2' , memberId : 'm2' , organizationId : 'o2' , organizationName : 'CERN' , dateStart : '2019-01-01' , dateEnd : null } )
542+ const m1row = makeRow ( {
543+ id : 'r1' ,
544+ memberId : 'm1' ,
545+ organizationId : 'o1' ,
546+ organizationName : 'Acme' ,
547+ dateStart : '2020-01-01' ,
548+ dateEnd : null ,
549+ } )
550+ const m2row = makeRow ( {
551+ id : 'r2' ,
552+ memberId : 'm2' ,
553+ organizationId : 'o2' ,
554+ organizationName : 'CERN' ,
555+ dateStart : '2019-01-01' ,
556+ dateEnd : null ,
557+ } )
452558 mockSelect . mockResolvedValueOnce ( [ m1row , m2row ] ) . mockResolvedValueOnce ( [ ] )
453559
454560 const result = await resolveAffiliationsByMemberIds ( mockQx , [ 'm1' , 'm2' ] )
@@ -582,21 +688,21 @@ describe('resolveAffiliationsByMemberIds', () => {
582688 const result = await resolveAffiliationsByMemberIds ( mockQx , [ 'm1' ] )
583689 const orgs = result . get ( 'm1' ) . map ( ( a ) => a . organization )
584690
585- expect ( orgs ) . toContain ( 'ManualOrg' ) // manual survived the filter
691+ expect ( orgs ) . toContain ( 'ManualOrg' ) // manual survived the filter
586692 expect ( orgs ) . not . toContain ( 'ExtraUndated' ) // extra undated work-exp was dropped
587693 } )
588694
589695 // Error cases
590696 it ( 'propagates errors thrown by qx.select' , async ( ) => {
591697 mockSelect . mockRejectedValueOnce ( new Error ( 'DB connection lost' ) )
592698
593- await expect ( resolveAffiliationsByMemberIds ( mockQx , [ 'm1' ] ) ) . rejects . toThrow ( 'DB connection lost' )
699+ await expect ( resolveAffiliationsByMemberIds ( mockQx , [ 'm1' ] ) ) . rejects . toThrow (
700+ 'DB connection lost' ,
701+ )
594702 } )
595703
596704 it ( 'propagates errors thrown by the second qx.select (manual affiliations query)' , async ( ) => {
597- mockSelect
598- . mockResolvedValueOnce ( [ ] )
599- . mockRejectedValueOnce ( new Error ( 'query timeout' ) )
705+ mockSelect . mockResolvedValueOnce ( [ ] ) . mockRejectedValueOnce ( new Error ( 'query timeout' ) )
600706
601707 await expect ( resolveAffiliationsByMemberIds ( mockQx , [ 'm1' ] ) ) . rejects . toThrow ( 'query timeout' )
602708 } )
0 commit comments