154 lines
4.5 KiB
TypeScript
154 lines
4.5 KiB
TypeScript
import assert from "node:assert/strict"
|
|
import test from "node:test"
|
|
import {
|
|
processLeadSubmission,
|
|
type ContactLeadPayload,
|
|
type RequestMachineLeadPayload,
|
|
} from "@/lib/server/contact-submission"
|
|
|
|
test("processLeadSubmission stores and syncs a contact lead", async () => {
|
|
const calls: string[] = []
|
|
const payload: ContactLeadPayload = {
|
|
kind: "contact",
|
|
firstName: "John",
|
|
lastName: "Doe",
|
|
email: "john@example.com",
|
|
phone: "(435) 555-1212",
|
|
company: "ACME",
|
|
intent: "Repairs",
|
|
message: "Need vending help for our office.",
|
|
serviceTextConsent: true,
|
|
marketingTextConsent: false,
|
|
consentVersion: "sms-consent-v1-2026-03-26",
|
|
consentCapturedAt: "2026-03-25T00:00:00.000Z",
|
|
consentSourcePage: "/contact-us",
|
|
source: "website",
|
|
page: "/contact",
|
|
timestamp: "2026-03-25T00:00:00.000Z",
|
|
url: "https://rmv.example/contact",
|
|
}
|
|
|
|
const result = await processLeadSubmission(payload, "rmv.example", {
|
|
storageConfigured: true,
|
|
emailConfigured: true,
|
|
ghlConfigured: true,
|
|
tenantSlug: "rocky_mountain_vending",
|
|
tenantName: "Rocky Mountain Vending",
|
|
tenantDomains: ["rockymountainvending.com"],
|
|
ingest: async () => {
|
|
calls.push("ingest")
|
|
return {
|
|
inserted: true,
|
|
leadId: "lead_123",
|
|
idempotencyKey: "abc",
|
|
tenantId: "tenant_123",
|
|
}
|
|
},
|
|
updateLeadStatus: async () => {
|
|
calls.push("update")
|
|
return { ok: true }
|
|
},
|
|
sendEmail: async () => {
|
|
calls.push("email")
|
|
return {}
|
|
},
|
|
createContact: async () => {
|
|
calls.push("ghl")
|
|
return { contact: { id: "ghl_123" } }
|
|
},
|
|
logger: console,
|
|
})
|
|
|
|
assert.equal(result.status, 200)
|
|
assert.equal(result.body.success, true)
|
|
assert.deepEqual(result.body.deliveredVia, ["convex", "email", "ghl"])
|
|
assert.equal(calls.filter((call) => call === "email").length, 2)
|
|
assert.ok(calls.includes("ingest"))
|
|
assert.ok(calls.includes("update"))
|
|
assert.ok(calls.includes("ghl"))
|
|
})
|
|
|
|
test("processLeadSubmission validates request-machine submissions", async () => {
|
|
const payload: RequestMachineLeadPayload = {
|
|
kind: "request-machine",
|
|
firstName: "Jane",
|
|
lastName: "Smith",
|
|
email: "jane@example.com",
|
|
phone: "4352339668",
|
|
company: "Warehouse Co",
|
|
employeeCount: "0",
|
|
machineType: "snack",
|
|
machineCount: "2",
|
|
serviceTextConsent: true,
|
|
marketingTextConsent: false,
|
|
consentVersion: "sms-consent-v1-2026-03-26",
|
|
consentCapturedAt: "2026-03-25T00:00:00.000Z",
|
|
consentSourcePage: "/",
|
|
}
|
|
|
|
const result = await processLeadSubmission(payload, "rmv.example", {
|
|
storageConfigured: false,
|
|
emailConfigured: false,
|
|
ghlConfigured: false,
|
|
tenantSlug: "rocky_mountain_vending",
|
|
tenantName: "Rocky Mountain Vending",
|
|
tenantDomains: [],
|
|
ingest: async () => {
|
|
throw new Error("should not run")
|
|
},
|
|
updateLeadStatus: async () => {
|
|
throw new Error("should not run")
|
|
},
|
|
sendEmail: async () => {
|
|
throw new Error("should not run")
|
|
},
|
|
createContact: async () => {
|
|
throw new Error("should not run")
|
|
},
|
|
logger: console,
|
|
})
|
|
|
|
assert.equal(result.status, 400)
|
|
assert.equal(result.body.success, false)
|
|
assert.match(result.body.error || "", /Invalid number of employees/)
|
|
})
|
|
|
|
test("processLeadSubmission returns deduped success when Convex already has the lead", async () => {
|
|
const payload: ContactLeadPayload = {
|
|
kind: "contact",
|
|
firstName: "John",
|
|
lastName: "Doe",
|
|
email: "john@example.com",
|
|
phone: "(435) 555-1212",
|
|
message: "Need vending help for our office.",
|
|
serviceTextConsent: true,
|
|
marketingTextConsent: false,
|
|
consentVersion: "sms-consent-v1-2026-03-26",
|
|
consentCapturedAt: "2026-03-25T00:00:00.000Z",
|
|
consentSourcePage: "/contact-us",
|
|
}
|
|
|
|
const result = await processLeadSubmission(payload, "rmv.example", {
|
|
storageConfigured: true,
|
|
emailConfigured: false,
|
|
ghlConfigured: false,
|
|
tenantSlug: "rocky_mountain_vending",
|
|
tenantName: "Rocky Mountain Vending",
|
|
tenantDomains: [],
|
|
ingest: async () => ({
|
|
inserted: false,
|
|
leadId: "lead_123",
|
|
idempotencyKey: "abc",
|
|
tenantId: "tenant_123",
|
|
}),
|
|
updateLeadStatus: async () => ({ ok: true }),
|
|
sendEmail: async () => ({}),
|
|
createContact: async () => null,
|
|
logger: console,
|
|
})
|
|
|
|
assert.equal(result.status, 200)
|
|
assert.equal(result.body.success, true)
|
|
assert.equal(result.body.deduped, true)
|
|
assert.deepEqual(result.body.deliveredVia, ["convex"])
|
|
})
|