phase 16 implementation
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
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 });
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user