Skip to content

Commit 79df4e8

Browse files
committed
fix: resolve pr review comments
Signed-off-by: Yeganathan S <63534555+skwowet@users.noreply.github.com>
1 parent 806d9f5 commit 79df4e8

1 file changed

Lines changed: 67 additions & 24 deletions

File tree

  • services/libs/data-access-layer/src/member-organization-affiliation

services/libs/data-access-layer/src/member-organization-affiliation/index.test.ts

Lines changed: 67 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { test as base, describe, expect } from 'vitest'
1+
import { afterEach, test as base, beforeEach, describe, expect, vi } from 'vitest'
22

33
import type { QueryExecutor } from '@crowd/database'
44
import { withQx } from '@crowd/test-kit/db'
@@ -40,6 +40,18 @@ const test = withQx(base)
4040

4141
const EPOCH = new Date('1970-01-01').toISOString()
4242

43+
/** Frozen "now" so prepare() dateEnd boundaries stay deterministic. */
44+
const NOW = '2024-06-15T00:00:00.000Z'
45+
46+
beforeEach(() => {
47+
vi.useFakeTimers({ toFake: ['Date'] })
48+
vi.setSystemTime(new Date(NOW))
49+
})
50+
51+
afterEach(() => {
52+
vi.useRealTimers()
53+
})
54+
4355
const SEGMENT_TREES = withSegmentDefaults([
4456
{
4557
name: 'Cloud Native Computing Foundation',
@@ -104,7 +116,7 @@ function expectTimeline(
104116
expected: Array<{
105117
organizationId: string | null
106118
dateStart: string
107-
dateEnd: unknown
119+
dateEnd: string | null
108120
segmentId?: string | null
109121
matchEmailDomain?: string | null
110122
}>,
@@ -149,9 +161,7 @@ describe('prepareMemberOrganizationAffiliationTimeline', () => {
149161

150162
const timeline = await prepareMemberOrganizationAffiliationTimeline(qx, member.id)
151163

152-
expectTimeline(baseItems(timeline), [
153-
{ organizationId: null, dateStart: EPOCH, dateEnd: expect.any(String) },
154-
])
164+
expectTimeline(baseItems(timeline), [{ organizationId: null, dateStart: EPOCH, dateEnd: NOW }])
155165
expect(manualItems(timeline)).toHaveLength(0)
156166
expect(emailItems(timeline)).toHaveLength(0)
157167
})
@@ -176,7 +186,7 @@ describe('prepareMemberOrganizationAffiliationTimeline', () => {
176186
const timeline = await prepareMemberOrganizationAffiliationTimeline(qx, member.id)
177187

178188
expectTimeline(baseItems(timeline), [
179-
{ organizationId: org.id, dateStart: EPOCH, dateEnd: expect.any(String) },
189+
{ organizationId: org.id, dateStart: EPOCH, dateEnd: NOW },
180190
])
181191
})
182192

@@ -206,17 +216,24 @@ describe('prepareMemberOrganizationAffiliationTimeline', () => {
206216
])
207217

208218
const timeline = await prepareMemberOrganizationAffiliationTimeline(qx, member.id)
209-
const base = baseItems(timeline)
210-
const orgIds = base.map((item) => item.organizationId)
211219

212-
expect(orgIds[0]).toBe(undated.id)
213-
expect(base[0].dateStart).toBe(EPOCH)
214-
expect(orgIds).toContain(employer.id)
215-
expect(base.find((item) => item.organizationId === employer.id)?.dateStart).toBe(
216-
'2017-07-01T00:00:00.000Z',
217-
)
218-
// Dated stint ended — undated fills the post-career gap through now as well.
219-
expect(orgIds[orgIds.length - 1]).toBe(undated.id)
220+
expectTimeline(baseItems(timeline), [
221+
{
222+
organizationId: undated.id,
223+
dateStart: EPOCH,
224+
dateEnd: '2017-06-30T00:00:00.000Z',
225+
},
226+
{
227+
organizationId: employer.id,
228+
dateStart: '2017-07-01T00:00:00.000Z',
229+
dateEnd: '2020-01-01T00:00:00.000Z',
230+
},
231+
{
232+
organizationId: undated.id,
233+
dateStart: '2020-01-02T00:00:00.000Z',
234+
dateEnd: null,
235+
},
236+
])
220237
})
221238

222239
test('gap between jobs is filled by the undated fallback', async ({ qx }) => {
@@ -386,9 +403,7 @@ describe('prepareMemberOrganizationAffiliationTimeline', () => {
386403

387404
const timeline = await prepareMemberOrganizationAffiliationTimeline(qx, member.id)
388405

389-
expectTimeline(baseItems(timeline), [
390-
{ organizationId: null, dateStart: EPOCH, dateEnd: expect.any(String) },
391-
])
406+
expectTimeline(baseItems(timeline), [{ organizationId: null, dateStart: EPOCH, dateEnd: NOW }])
392407
})
393408

394409
test('primary undated MO wins over other undated as fallback', async ({ qx }) => {
@@ -426,7 +441,7 @@ describe('prepareMemberOrganizationAffiliationTimeline', () => {
426441
const timeline = await prepareMemberOrganizationAffiliationTimeline(qx, member.id)
427442

428443
expectTimeline(baseItems(timeline), [
429-
{ organizationId: orgB.id, dateStart: EPOCH, dateEnd: expect.any(String) },
444+
{ organizationId: orgB.id, dateStart: EPOCH, dateEnd: NOW },
430445
])
431446
expect(baseItems(timeline).every((item) => item.organizationId !== orgA.id)).toBe(true)
432447
})
@@ -753,7 +768,7 @@ describe('prepareMemberOrganizationAffiliationTimeline', () => {
753768
{
754769
organizationId: null,
755770
dateStart: '2024-02-02T00:00:00.000Z',
756-
dateEnd: expect.any(String),
771+
dateEnd: NOW,
757772
},
758773
])
759774
})
@@ -800,7 +815,7 @@ describe('prepareMemberOrganizationAffiliationTimeline', () => {
800815
{
801816
organizationId: null,
802817
dateStart: '2023-01-02T00:00:00.000Z',
803-
dateEnd: expect.any(String),
818+
dateEnd: NOW,
804819
},
805820
])
806821
})
@@ -880,7 +895,7 @@ describe('prepareMemberOrganizationAffiliationTimeline', () => {
880895
{
881896
organizationId: null,
882897
dateStart: '2023-01-02T00:00:00.000Z',
883-
dateEnd: expect.any(String),
898+
dateEnd: NOW,
884899
},
885900
])
886901
})
@@ -959,7 +974,7 @@ describe('prepareMemberOrganizationAffiliationTimeline', () => {
959974
{
960975
organizationId: null,
961976
dateStart: '2022-01-02T00:00:00.000Z',
962-
dateEnd: expect.any(String),
977+
dateEnd: NOW,
963978
},
964979
])
965980
})
@@ -1347,4 +1362,32 @@ describe('refreshMemberOrganizationAffiliations', () => {
13471362
expect(await countByOrg(qx, member.id, kubernetes.id, company.id)).toBe(16) // 10 GH + 6 @intel.com
13481363
expect(await countByOrg(qx, member.id, kubernetes.id, university.id)).toBe(8) // @nyu.edu
13491364
})
1365+
1366+
test('clears stale organizationId when timeline resolves to null', async ({ qx }) => {
1367+
const [staleOrg] = await createOrganizations(
1368+
qx,
1369+
withOrganizationDefaults([{ displayName: 'Stale Co' }]),
1370+
)
1371+
const { member, identities } = await createMemberWithIdentity(qx, { value: 'no-employer' })
1372+
const { kubernetes } = await createLeafSegments(qx)
1373+
1374+
// No member organizations → prepare yields a null fallback for the whole timeline.
1375+
const seeded = await createActivityRelations(
1376+
qx,
1377+
generateActivityRelations({
1378+
memberId: member.id,
1379+
segmentId: kubernetes.id,
1380+
identities,
1381+
count: 20,
1382+
timestamp: { from: '2021-01-01T00:00:00.000Z', to: '2021-06-01T00:00:00.000Z' },
1383+
}).map((row) => ({ ...row, organizationId: staleOrg.id })),
1384+
)
1385+
1386+
expect(await countByOrg(qx, member.id, kubernetes.id, staleOrg.id)).toBe(seeded.length)
1387+
1388+
await refreshMemberOrganizationAffiliations(qx, member.id)
1389+
1390+
expect(await countByOrg(qx, member.id, kubernetes.id, staleOrg.id)).toBe(0)
1391+
expect(await countByOrg(qx, member.id, kubernetes.id, null)).toBe(seeded.length)
1392+
})
13501393
})

0 commit comments

Comments
 (0)