Files
2026-06-25 20:08:39 -04:00

98 lines
3.2 KiB
TypeScript

import { clearIdempotencyStoreForTests } from '@/lib/demo/idempotency';
import type { LeadDestinationAdapter } from '@/lib/demo/adapters';
import { submitDemoLead } from '@/lib/demo/service';
import type { DemoLead } from '@/lib/demo/schema';
import type { IntegrationEnvironment } from '@/lib/integrations/environment';
import { beforeEach, describe, expect, it, vi } from 'vitest';
const environment: IntegrationEnvironment = {
NODE_ENV: 'test',
NEXT_PUBLIC_DEMO_ENABLED: true,
DEMO_SUBMISSION_MODE: 'local',
DEMO_REQUEST_TIMEOUT_MS: 250,
DEMO_IDEMPOTENCY_TTL_SECONDS: 900,
DEMO_TEST_SCENARIOS_ENABLED: true,
DEMO_LOCAL_TEST_MODE: false,
NEXT_PUBLIC_ANALYTICS_MODE: 'disabled',
};
const lead: DemoLead = {
fullName: 'Avery Example',
workEmail: 'avery@example.test',
company: 'Example Rental Lab',
fleetSize: '10-24',
preferredLanguage: 'en',
idempotencyKey: '6b4992d5-d88e-4e44-9b66-adc18fd8ee37',
source: 'hero',
};
beforeEach(clearIdempotencyStoreForTests);
describe('demo submission orchestration', () => {
it('confirms acceptance before returning success', async () => {
const adapter: LeadDestinationAdapter = {
name: 'test-success',
submitLead: vi.fn(async () => ({
ok: true as const,
externalId: 'local_test',
acceptedAt: '2026-06-25T00:00:00.000Z',
mode: 'local' as const,
})),
};
const result = await submitDemoLead(lead, { environment, adapter });
expect(result.ok).toBe(true);
expect(adapter.submitLead).toHaveBeenCalledOnce();
});
it('coalesces repeated transport with the same idempotency key', async () => {
const adapter: LeadDestinationAdapter = {
name: 'test-idempotent',
submitLead: vi.fn(async () => ({
ok: true as const,
externalId: 'local_once',
acceptedAt: '2026-06-25T00:00:00.000Z',
mode: 'local' as const,
})),
};
const [first, second] = await Promise.all([
submitDemoLead(lead, { environment, adapter }),
submitDemoLead(lead, { environment, adapter }),
]);
expect(first).toEqual(second);
expect(adapter.submitLead).toHaveBeenCalledOnce();
});
it('normalizes adapter failures without exposing vendor bodies', async () => {
const adapter: LeadDestinationAdapter = {
name: 'test-error',
submitLead: async () => ({
ok: false,
category: 'integration',
retryable: true,
code: 'normalized_failure',
}),
};
const result = await submitDemoLead(lead, { environment, adapter });
expect(result).toMatchObject({
ok: false,
category: 'integration',
formErrorCode: 'normalized_failure',
retryable: true,
});
});
it('bounds a hung integration with a timeout', async () => {
const adapter: LeadDestinationAdapter = {
name: 'test-timeout',
submitLead: (_lead, context) =>
new Promise((_resolve, reject) => {
context.signal.addEventListener('abort', () =>
reject(new DOMException('Aborted', 'AbortError')),
);
}),
};
const result = await submitDemoLead(lead, { environment, adapter });
expect(result).toMatchObject({ ok: false, category: 'timeout', retryable: true });
});
});