@@ -99,14 +99,31 @@ function emailItems(timeline: TimelineItem[]) {
9999 return timeline . filter ( ( item ) => ! ! item . matchEmailDomain )
100100}
101101
102- function expectItems (
102+ function expectTimeline (
103103 actual : TimelineItem [ ] ,
104- expected : Array < Partial < TimelineItem > & Pick < TimelineItem , 'organizationId' | 'dateStart' > > ,
104+ expected : Array < {
105+ organizationId : string | null
106+ dateStart : string
107+ dateEnd : unknown
108+ segmentId ?: string | null
109+ matchEmailDomain ?: string | null
110+ } > ,
105111) {
106- expect ( actual ) . toHaveLength ( expected . length )
107- for ( let i = 0 ; i < expected . length ; i ++ ) {
108- expect ( actual [ i ] , `item[${ i } ]` ) . toMatchObject ( expected [ i ] )
109- }
112+ expect (
113+ actual . map ( ( item ) => ( {
114+ organizationId : item . organizationId ,
115+ dateStart : item . dateStart ,
116+ dateEnd : item . dateEnd ,
117+ segmentId : item . segmentId ?? null ,
118+ matchEmailDomain : item . matchEmailDomain ?? null ,
119+ } ) ) ,
120+ ) . toEqual (
121+ expected . map ( ( item ) => ( {
122+ segmentId : null ,
123+ matchEmailDomain : null ,
124+ ...item ,
125+ } ) ) ,
126+ )
110127}
111128
112129async function countByOrg (
@@ -132,7 +149,9 @@ describe('prepareMemberOrganizationAffiliationTimeline', () => {
132149
133150 const timeline = await prepareMemberOrganizationAffiliationTimeline ( qx , member . id )
134151
135- expectItems ( baseItems ( timeline ) , [ { organizationId : null , dateStart : EPOCH } ] )
152+ expectTimeline ( baseItems ( timeline ) , [
153+ { organizationId : null , dateStart : EPOCH , dateEnd : expect . any ( String ) } ,
154+ ] )
136155 expect ( manualItems ( timeline ) ) . toHaveLength ( 0 )
137156 expect ( emailItems ( timeline ) ) . toHaveLength ( 0 )
138157 } )
@@ -156,7 +175,9 @@ describe('prepareMemberOrganizationAffiliationTimeline', () => {
156175
157176 const timeline = await prepareMemberOrganizationAffiliationTimeline ( qx , member . id )
158177
159- expectItems ( baseItems ( timeline ) , [ { organizationId : org . id , dateStart : EPOCH } ] )
178+ expectTimeline ( baseItems ( timeline ) , [
179+ { organizationId : org . id , dateStart : EPOCH , dateEnd : expect . any ( String ) } ,
180+ ] )
160181 } )
161182
162183 test ( 'undated MO covers pre-career when dated stints exist' , async ( { qx } ) => {
@@ -235,7 +256,7 @@ describe('prepareMemberOrganizationAffiliationTimeline', () => {
235256
236257 const timeline = await prepareMemberOrganizationAffiliationTimeline ( qx , member . id )
237258
238- expectItems ( baseItems ( timeline ) , [
259+ expectTimeline ( baseItems ( timeline ) , [
239260 {
240261 organizationId : undated . id ,
241262 dateStart : EPOCH ,
@@ -332,7 +353,7 @@ describe('prepareMemberOrganizationAffiliationTimeline', () => {
332353 expect ( orgIds ) . toContain ( employer . id )
333354 expect ( orgIds ) . not . toContain ( internship . id )
334355 expect ( orgIds ) . not . toContain ( foundation . id )
335- expectItems (
356+ expectTimeline (
336357 base . filter ( ( item ) => item . organizationId === employer . id ) ,
337358 [ { organizationId : employer . id , dateStart : '2021-08-01T00:00:00.000Z' , dateEnd : null } ] ,
338359 )
@@ -365,7 +386,9 @@ describe('prepareMemberOrganizationAffiliationTimeline', () => {
365386
366387 const timeline = await prepareMemberOrganizationAffiliationTimeline ( qx , member . id )
367388
368- expectItems ( baseItems ( timeline ) , [ { organizationId : null , dateStart : EPOCH } ] )
389+ expectTimeline ( baseItems ( timeline ) , [
390+ { organizationId : null , dateStart : EPOCH , dateEnd : expect . any ( String ) } ,
391+ ] )
369392 } )
370393
371394 test ( 'primary undated MO wins over other undated as fallback' , async ( { qx } ) => {
@@ -402,7 +425,9 @@ describe('prepareMemberOrganizationAffiliationTimeline', () => {
402425
403426 const timeline = await prepareMemberOrganizationAffiliationTimeline ( qx , member . id )
404427
405- expectItems ( baseItems ( timeline ) , [ { organizationId : orgB . id , dateStart : EPOCH } ] )
428+ expectTimeline ( baseItems ( timeline ) , [
429+ { organizationId : orgB . id , dateStart : EPOCH , dateEnd : expect . any ( String ) } ,
430+ ] )
406431 expect ( baseItems ( timeline ) . every ( ( item ) => item . organizationId !== orgA . id ) ) . toBe ( true )
407432 } )
408433
@@ -565,8 +590,13 @@ describe('prepareMemberOrganizationAffiliationTimeline', () => {
565590
566591 const timeline = await prepareMemberOrganizationAffiliationTimeline ( qx , member . id )
567592
568- expectItems ( manualItems ( timeline ) , [
569- { organizationId : sponsor . id , dateStart : EPOCH , segmentId : kubernetes . id } ,
593+ expectTimeline ( manualItems ( timeline ) , [
594+ {
595+ organizationId : sponsor . id ,
596+ dateStart : EPOCH ,
597+ dateEnd : null ,
598+ segmentId : kubernetes . id ,
599+ } ,
570600 ] )
571601 expect ( baseItems ( timeline ) . length ) . toBeGreaterThan ( 0 )
572602 expect ( baseItems ( timeline ) . every ( ( item ) => item . skipManualAffiliationSegments === true ) ) . toBe (
@@ -616,7 +646,7 @@ describe('prepareMemberOrganizationAffiliationTimeline', () => {
616646
617647 const timeline = await prepareMemberOrganizationAffiliationTimeline ( qx , member . id )
618648
619- expectItems ( manualItems ( timeline ) , [
649+ expectTimeline ( manualItems ( timeline ) , [
620650 {
621651 organizationId : org . id ,
622652 dateStart : '2021-08-01T00:00:00.000Z' ,
@@ -698,11 +728,34 @@ describe('prepareMemberOrganizationAffiliationTimeline', () => {
698728 ] )
699729
700730 const timeline = await prepareMemberOrganizationAffiliationTimeline ( qx , member . id )
701- const duringOverlap = baseItems ( timeline ) . find (
702- ( item ) => item . organizationId === uiOrg . id && item . dateStart === '2020-01-01T00:00:00.000Z' ,
703- )
704731
705- expect ( duringOverlap ) . toBeDefined ( )
732+ expectTimeline ( baseItems ( timeline ) , [
733+ {
734+ organizationId : null ,
735+ dateStart : EPOCH ,
736+ dateEnd : '2017-12-31T00:00:00.000Z' ,
737+ } ,
738+ {
739+ organizationId : enrichmentOrg . id ,
740+ dateStart : '2018-01-01T00:00:00.000Z' ,
741+ dateEnd : '2019-12-31T00:00:00.000Z' ,
742+ } ,
743+ {
744+ organizationId : uiOrg . id ,
745+ dateStart : '2020-01-01T00:00:00.000Z' ,
746+ dateEnd : '2023-01-01T00:00:00.000Z' ,
747+ } ,
748+ {
749+ organizationId : enrichmentOrg . id ,
750+ dateStart : '2023-01-02T00:00:00.000Z' ,
751+ dateEnd : '2024-02-01T00:00:00.000Z' ,
752+ } ,
753+ {
754+ organizationId : null ,
755+ dateStart : '2024-02-02T00:00:00.000Z' ,
756+ dateEnd : expect . any ( String ) ,
757+ } ,
758+ ] )
706759 } )
707760
708761 test ( 'longer stint wins when overlapping dated MOs share source and memberCount' , async ( {
@@ -732,17 +785,24 @@ describe('prepareMemberOrganizationAffiliationTimeline', () => {
732785 ] )
733786
734787 const timeline = await prepareMemberOrganizationAffiliationTimeline ( qx , member . id )
735- const duringOverlap = baseItems ( timeline ) . find (
736- ( item ) => item . organizationId === longer . id && item . dateStart === '2020-01-01T00:00:00.000Z' ,
737- )
738788
739- expect ( duringOverlap ) . toBeDefined ( )
740- expect (
741- baseItems ( timeline ) . some (
742- ( item ) =>
743- item . organizationId === shorter . id && item . dateStart === '2021-01-01T00:00:00.000Z' ,
744- ) ,
745- ) . toBe ( false )
789+ expectTimeline ( baseItems ( timeline ) , [
790+ {
791+ organizationId : null ,
792+ dateStart : EPOCH ,
793+ dateEnd : '2019-12-31T00:00:00.000Z' ,
794+ } ,
795+ {
796+ organizationId : longer . id ,
797+ dateStart : '2020-01-01T00:00:00.000Z' ,
798+ dateEnd : '2023-01-01T00:00:00.000Z' ,
799+ } ,
800+ {
801+ organizationId : null ,
802+ dateStart : '2023-01-02T00:00:00.000Z' ,
803+ dateEnd : expect . any ( String ) ,
804+ } ,
805+ ] )
746806 } )
747807
748808 test ( 'higher memberCount wins when overlapping dated MOs share source' , async ( { qx } ) => {
@@ -796,17 +856,33 @@ describe('prepareMemberOrganizationAffiliationTimeline', () => {
796856
797857 const timeline = await prepareMemberOrganizationAffiliationTimeline ( qx , member . id )
798858
799- expect (
800- baseItems ( timeline ) . some (
801- ( item ) =>
802- item . organizationId === popular . id && item . dateStart === '2021-01-01T00:00:00.000Z' ,
803- ) ,
804- ) . toBe ( true )
805- expect (
806- baseItems ( timeline ) . some (
807- ( item ) => item . organizationId === niche . id && item . dateStart === '2021-01-01T00:00:00.000Z' ,
808- ) ,
809- ) . toBe ( false )
859+ expectTimeline ( baseItems ( timeline ) , [
860+ {
861+ organizationId : null ,
862+ dateStart : EPOCH ,
863+ dateEnd : '2019-12-31T00:00:00.000Z' ,
864+ } ,
865+ {
866+ organizationId : niche . id ,
867+ dateStart : '2020-01-01T00:00:00.000Z' ,
868+ dateEnd : '2020-12-31T00:00:00.000Z' ,
869+ } ,
870+ {
871+ organizationId : popular . id ,
872+ dateStart : '2021-01-01T00:00:00.000Z' ,
873+ dateEnd : '2022-01-01T00:00:00.000Z' ,
874+ } ,
875+ {
876+ organizationId : niche . id ,
877+ dateStart : '2022-01-02T00:00:00.000Z' ,
878+ dateEnd : '2023-01-01T00:00:00.000Z' ,
879+ } ,
880+ {
881+ organizationId : null ,
882+ dateStart : '2023-01-02T00:00:00.000Z' ,
883+ dateEnd : expect . any ( String ) ,
884+ } ,
885+ ] )
810886 } )
811887
812888 test ( 'company is preferred over university when dated stints overlap' , async ( { qx } ) => {
@@ -858,26 +934,34 @@ describe('prepareMemberOrganizationAffiliationTimeline', () => {
858934 ] )
859935
860936 const timeline = await prepareMemberOrganizationAffiliationTimeline ( qx , member . id )
861- const base = baseItems ( timeline )
862937
863- expect (
864- base . some (
865- ( item ) =>
866- item . organizationId === company . id && item . dateStart === '2021-06-01T00:00:00.000Z' ,
867- ) ,
868- ) . toBe ( true )
869- expect (
870- base . some (
871- ( item ) =>
872- item . organizationId === university . id && item . dateStart === '2021-06-01T00:00:00.000Z' ,
873- ) ,
874- ) . toBe ( false )
875- expect (
876- base . some (
877- ( item ) =>
878- item . organizationId === university . id && item . dateStart === '2021-01-01T00:00:00.000Z' ,
879- ) ,
880- ) . toBe ( true )
938+ expectTimeline ( baseItems ( timeline ) , [
939+ {
940+ organizationId : null ,
941+ dateStart : EPOCH ,
942+ dateEnd : '2020-12-31T00:00:00.000Z' ,
943+ } ,
944+ {
945+ organizationId : university . id ,
946+ dateStart : '2021-01-01T00:00:00.000Z' ,
947+ dateEnd : '2021-05-31T00:00:00.000Z' ,
948+ } ,
949+ {
950+ organizationId : company . id ,
951+ dateStart : '2021-06-01T00:00:00.000Z' ,
952+ dateEnd : '2021-09-01T00:00:00.000Z' ,
953+ } ,
954+ {
955+ organizationId : university . id ,
956+ dateStart : '2021-09-02T00:00:00.000Z' ,
957+ dateEnd : '2022-01-01T00:00:00.000Z' ,
958+ } ,
959+ {
960+ organizationId : null ,
961+ dateStart : '2022-01-02T00:00:00.000Z' ,
962+ dateEnd : expect . any ( String ) ,
963+ } ,
964+ ] )
881965 } )
882966
883967 test ( 'verified primary-domain yields an email timeline item' , async ( { qx } ) => {
@@ -909,7 +993,7 @@ describe('prepareMemberOrganizationAffiliationTimeline', () => {
909993
910994 const timeline = await prepareMemberOrganizationAffiliationTimeline ( qx , member . id )
911995
912- expectItems ( emailItems ( timeline ) , [
996+ expectTimeline ( emailItems ( timeline ) , [
913997 {
914998 organizationId : org . id ,
915999 dateStart : EPOCH ,
0 commit comments