import { describe, expect, it, vi } from 'vitest' import { renderHook } from '../../test/utils' import type { OutboundResolver } from '../../types' import { buildOutboundsByRecordId, useOutboundsByRecordId, } from './OutboundContext' describe('buildOutboundsByRecordId', () => { it('returns undefined when no resolver is provided', () => { expect( buildOutboundsByRecordId( [{ metadata: { outbound_id: 'outbound-1' } }], undefined ) ).toBeUndefined() }) it('returns undefined without invoking the resolver when there are no messages', () => { const resolveOutbound = vi.fn() expect(buildOutboundsByRecordId(undefined, resolveOutbound)).toBeUndefined() expect(buildOutboundsByRecordId([], resolveOutbound)).toBeUndefined() expect(resolveOutbound).not.toHaveBeenCalled() }) it('resolves each unique outbound record id once', () => { const resolveOutbound = vi.fn((outboundRecordId: string) => ({ id: `automation-for-${outboundRecordId}`, name: `name-for-${outboundRecordId}`, })) expect( buildOutboundsByRecordId( [ { metadata: { outbound_id: 'outbound-1' } }, { metadata: { outbound_id: 'outbound-1' } }, { metadata: { outbound_id: 'outbound-2' } }, { metadata: {} }, ], resolveOutbound ) ).toEqual({ 'outbound-1': { id: 'automation-for-outbound-1', name: 'name-for-outbound-1', }, 'outbound-2': { id: 'automation-for-outbound-2', name: 'name-for-outbound-2', }, }) expect(resolveOutbound).toHaveBeenCalledTimes(2) }) it('omits outbound records the resolver cannot resolve', () => { expect( buildOutboundsByRecordId( [{ metadata: { outbound_id: 'outbound-1' } }], () => undefined ) ).toBeUndefined() }) }) describe('useOutboundsByRecordId', () => { const messages = [{ metadata: { outbound_id: 'outbound-1' } }] const renderWithResolver = (resolver: OutboundResolver) => renderHook( ({ resolveOutbound }: { resolveOutbound: OutboundResolver }) => useOutboundsByRecordId(messages, resolveOutbound), { initialProps: { resolveOutbound: resolver } } ) it('publishes a renamed automation under the same outbound record id', () => { const { result, rerender } = renderWithResolver(() => ({ id: 'automation-1', name: 'July 9th Class absentee', })) expect(result.current).toEqual({ 'outbound-1': { id: 'automation-1', name: 'July 9th Class absentee', }, }) rerender({ resolveOutbound: () => ({ id: 'automation-1', name: 'July 9th Class waitlist', }), }) expect(result.current).toEqual({ 'outbound-1': { id: 'automation-1', name: 'July 9th Class waitlist', }, }) }) it('publishes changes when the resolver mutates and reuses its cached object', () => { const cachedOutbound = { id: 'automation-1', name: 'July 9th Class absentee', } const { result, rerender } = renderWithResolver(() => cachedOutbound) const firstPublished = result.current cachedOutbound.name = 'July 9th Class waitlist' rerender({ resolveOutbound: () => cachedOutbound }) expect(result.current).not.toBe(firstPublished) expect(result.current).toEqual({ 'outbound-1': { id: 'automation-1', name: 'July 9th Class waitlist', }, }) }) it('publishes a new automation id when an outbound record is repointed', () => { const { result, rerender } = renderWithResolver(() => ({ id: 'automation-1', name: 'July 9th Class absentee', })) expect(result.current).toEqual({ 'outbound-1': { id: 'automation-1', name: 'July 9th Class absentee', }, }) rerender({ resolveOutbound: () => ({ id: 'automation-2', name: 'July 9th Class absentee', }), }) expect(result.current).toEqual({ 'outbound-1': { id: 'automation-2', name: 'July 9th Class absentee', }, }) }) it('keeps the published map referentially stable when resolved values are unchanged', () => { const { result, rerender } = renderWithResolver(() => ({ id: 'automation-1', name: 'July 9th Class absentee', })) const firstPublished = result.current rerender({ resolveOutbound: () => ({ id: 'automation-1', name: 'July 9th Class absentee', }), }) expect(result.current).toBe(firstPublished) }) })