316 lines
9.0 KiB
TypeScript
316 lines
9.0 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import test from "node:test";
|
|
|
|
import {
|
|
buildLeadDiscoveryLeadRecord,
|
|
buildLeadDiscoveryCounters,
|
|
canStartAgentRun,
|
|
isStalePendingAgentRun,
|
|
getLeadDiscoveryContactStatus,
|
|
getLeadDiscoveryPriority,
|
|
shouldScheduleWebsiteEnrichment,
|
|
} from "../lib/lead-discovery-run";
|
|
|
|
test("agent run guard ignores stale pending runs but blocks active runs", () => {
|
|
const now = Date.UTC(2026, 5, 4, 13, 20, 0);
|
|
|
|
assert.equal(canStartAgentRun([{ status: "succeeded" }], now), true);
|
|
assert.equal(
|
|
canStartAgentRun([{ status: "pending", updatedAt: now - 20 * 60 * 1000 }], now),
|
|
true,
|
|
);
|
|
assert.equal(
|
|
canStartAgentRun([{ status: "pending", updatedAt: now - 30_000 }], now),
|
|
false,
|
|
);
|
|
assert.equal(
|
|
canStartAgentRun([{ status: "failed" }, { status: "running" }], now),
|
|
false,
|
|
);
|
|
});
|
|
|
|
test("stale pending runs are older than the discovery startup grace period", () => {
|
|
const now = Date.UTC(2026, 5, 4, 13, 20, 0);
|
|
|
|
assert.equal(
|
|
isStalePendingAgentRun({ status: "pending", updatedAt: now - 11 * 60 * 1000 }, now),
|
|
true,
|
|
);
|
|
assert.equal(
|
|
isStalePendingAgentRun({ status: "pending", updatedAt: now - 9 * 60 * 1000 }, now),
|
|
false,
|
|
);
|
|
assert.equal(
|
|
isStalePendingAgentRun({ status: "running", updatedAt: now - 60 * 60 * 1000 }, now),
|
|
false,
|
|
);
|
|
});
|
|
|
|
test("lead discovery counters preserve audit and outreach counters", () => {
|
|
const counters = buildLeadDiscoveryCounters({
|
|
leadsFound: 12,
|
|
leadsCreated: 3,
|
|
errors: 1,
|
|
});
|
|
|
|
assert.deepEqual(counters, {
|
|
leadsFound: 12,
|
|
leadsCreated: 3,
|
|
auditsCreated: 0,
|
|
outreachPrepared: 0,
|
|
errors: 1,
|
|
});
|
|
});
|
|
|
|
test("lead discovery contact status separates leads without any contact route", () => {
|
|
assert.equal(
|
|
getLeadDiscoveryContactStatus({ usableEmail: null }),
|
|
"missing_contact",
|
|
);
|
|
assert.equal(
|
|
getLeadDiscoveryContactStatus({ usableEmail: "info@example.de" }),
|
|
"new",
|
|
);
|
|
assert.equal(
|
|
getLeadDiscoveryContactStatus({ usableEmail: null }),
|
|
"missing_contact",
|
|
);
|
|
});
|
|
|
|
test("lead discovery lead record marks contact missing when no usable email exists", () => {
|
|
const record = buildLeadDiscoveryLeadRecord({
|
|
campaignId: "campaign-1",
|
|
runId: "run-1",
|
|
niche: "Restaurant",
|
|
postalCode: "10115",
|
|
now: 1717480000000,
|
|
candidate: {
|
|
placeId: "place-2",
|
|
businessName: "Kontaktlos GmbH",
|
|
address: "Hauptstraße 2",
|
|
websiteUrl: "https://www.beispiel.de",
|
|
websiteDomain: "example.de",
|
|
phone: "+49 30 123",
|
|
rating: 3.9,
|
|
userRatingCount: 9,
|
|
businessStatus: "OPERATIONAL",
|
|
googleTypes: ["consulting"],
|
|
googlePrimaryType: "consulting",
|
|
googleMapsUrl: "https://maps.google.com/place-2",
|
|
sourceProvider: "google_places",
|
|
sourceFetchedAt: 1717480001000,
|
|
contactEmails: [{ email: "Herr.Bewerber@Beispiel.de", isBusinessContactAddress: false }],
|
|
},
|
|
});
|
|
|
|
assert.equal(record.contactStatus, "missing_contact");
|
|
assert.equal(record.phone, "+49 30 123");
|
|
assert.equal(record.websiteDomain, "example.de");
|
|
assert.equal(record.email, undefined);
|
|
});
|
|
|
|
test("lead discovery lead record keeps raw website url and normalized domain", () => {
|
|
const record = buildLeadDiscoveryLeadRecord({
|
|
campaignId: "campaign-1",
|
|
runId: "run-1",
|
|
niche: "Restaurant",
|
|
postalCode: "10115",
|
|
now: 1717480000000,
|
|
candidate: {
|
|
placeId: "place-1",
|
|
businessName: "Beispiel GmbH",
|
|
address: "Hauptstraße 1",
|
|
websiteUrl: "https://www.example.de/path",
|
|
websiteDomain: "example.de",
|
|
phone: "+49 30 123",
|
|
rating: 4.5,
|
|
userRatingCount: 12,
|
|
businessStatus: "OPERATIONAL",
|
|
googleTypes: ["restaurant"],
|
|
googlePrimaryType: "restaurant",
|
|
googleMapsUrl: "https://maps.google.com/place-1",
|
|
sourceProvider: "google_places",
|
|
sourceFetchedAt: 1717480001000,
|
|
},
|
|
});
|
|
|
|
assert.equal(record.websiteUrl, "https://www.example.de/path");
|
|
assert.equal(record.websiteDomain, "example.de");
|
|
assert.equal(record.googleRating, 4.5);
|
|
assert.equal(record.googleUserRatingCount, 12);
|
|
assert.equal(record.sourceFetchedAt, 1717480001000);
|
|
});
|
|
|
|
test("lead discovery lead record stores valid email and sets contactStatus to new", () => {
|
|
const record = buildLeadDiscoveryLeadRecord({
|
|
campaignId: "campaign-1",
|
|
runId: "run-1",
|
|
niche: "Restaurant",
|
|
postalCode: "10115",
|
|
now: 1717480000000,
|
|
candidate: {
|
|
placeId: "place-3",
|
|
businessName: "Beispiel GmbH",
|
|
address: "Hauptstraße 1",
|
|
websiteUrl: "https://www.example.de/path",
|
|
websiteDomain: "example.de",
|
|
phone: "+49 30 123",
|
|
rating: 4.5,
|
|
userRatingCount: 12,
|
|
businessStatus: "OPERATIONAL",
|
|
googleTypes: ["restaurant"],
|
|
googlePrimaryType: "restaurant",
|
|
googleMapsUrl: "https://maps.google.com/place-3",
|
|
sourceProvider: "google_places",
|
|
sourceFetchedAt: 1717480001000,
|
|
contactEmails: [
|
|
{
|
|
email: "Herr@Beispiel.de",
|
|
isBusinessContactAddress: false,
|
|
},
|
|
{
|
|
email: "info@beispiel.de",
|
|
isBusinessContactAddress: false,
|
|
},
|
|
],
|
|
},
|
|
});
|
|
|
|
assert.equal(record.contactStatus, "new");
|
|
assert.equal(record.email, "info@beispiel.de");
|
|
assert.equal(record.contactPerson, undefined);
|
|
});
|
|
|
|
test("scheduling helper triggers website enrichment for missing contact leads with website data", () => {
|
|
assert.equal(
|
|
shouldScheduleWebsiteEnrichment({
|
|
websiteUrl: "https://www.example.de",
|
|
websiteDomain: "example.de",
|
|
contactStatus: "missing_contact",
|
|
}),
|
|
true,
|
|
);
|
|
});
|
|
|
|
test("scheduling helper does not trigger without website data", () => {
|
|
assert.equal(
|
|
shouldScheduleWebsiteEnrichment({
|
|
websiteUrl: null,
|
|
websiteDomain: "",
|
|
contactStatus: "missing_contact",
|
|
}),
|
|
false,
|
|
);
|
|
});
|
|
|
|
test("scheduling helper does not trigger when contact status is already usable", () => {
|
|
assert.equal(
|
|
shouldScheduleWebsiteEnrichment({
|
|
websiteUrl: "https://www.example.de",
|
|
websiteDomain: "example.de",
|
|
contactStatus: "new",
|
|
}),
|
|
false,
|
|
);
|
|
});
|
|
|
|
test("scheduling helper does not trigger for audit-ready leads", () => {
|
|
assert.equal(
|
|
shouldScheduleWebsiteEnrichment({
|
|
websiteUrl: "https://www.example.de",
|
|
websiteDomain: "example.de",
|
|
contactStatus: "audit_ready",
|
|
}),
|
|
false,
|
|
);
|
|
});
|
|
|
|
test("scheduling helper preserves existing contact-status behavior beyond TASK-7", () => {
|
|
assert.equal(
|
|
shouldScheduleWebsiteEnrichment({
|
|
websiteUrl: "https://www.example.de",
|
|
websiteDomain: "example.de",
|
|
contactStatus: "outreach_ready",
|
|
}),
|
|
false,
|
|
);
|
|
assert.equal(
|
|
shouldScheduleWebsiteEnrichment({
|
|
websiteUrl: "https://www.example.de",
|
|
websiteDomain: "example.de",
|
|
contactStatus: "do_not_contact",
|
|
}),
|
|
false,
|
|
);
|
|
});
|
|
|
|
test("lead discovery lead record stores normalized matching fields", () => {
|
|
const record = buildLeadDiscoveryLeadRecord({
|
|
campaignId: "campaign-1",
|
|
runId: "run-1",
|
|
niche: "Restaurant",
|
|
postalCode: "10115",
|
|
now: 1717480000000,
|
|
candidate: {
|
|
placeId: "place-4",
|
|
businessName: "Muster GmbH",
|
|
address: "Hauptstraße 1 60311 Berlin",
|
|
websiteUrl: "https://www.example.de/",
|
|
websiteDomain: "Example.de",
|
|
phone: "+49 30 123 456",
|
|
rating: 4.5,
|
|
userRatingCount: 12,
|
|
businessStatus: "OPERATIONAL",
|
|
googleTypes: ["restaurant"],
|
|
googlePrimaryType: "restaurant",
|
|
googleMapsUrl: "https://maps.google.com/place-4",
|
|
sourceProvider: "google_places",
|
|
sourceFetchedAt: 1717480001000,
|
|
email: "Info@Example.de",
|
|
contactEmails: [
|
|
{
|
|
email: "Info@Example.de",
|
|
isBusinessContactAddress: false,
|
|
},
|
|
],
|
|
},
|
|
});
|
|
|
|
assert.equal(record.normalizedEmail, "info@example.de");
|
|
assert.equal(record.normalizedPhone, "4930123456");
|
|
assert.equal(record.normalizedCompanyName, "muster gmbh");
|
|
assert.equal(record.normalizedAddress, "hauptstraße 1 60311 berlin");
|
|
});
|
|
|
|
test("lead discovery priority helper classifies blocked, deferred, and low-potential leads", () => {
|
|
assert.deepEqual(getLeadDiscoveryPriority({ isBlacklisted: true }), {
|
|
priority: "blocked",
|
|
reason: "Lead ist auf der Sperrliste.",
|
|
});
|
|
|
|
assert.deepEqual(getLeadDiscoveryPriority({ isDuplicate: true }), {
|
|
priority: "defer",
|
|
reason: "Dublettenprüfung oder Reviewpause.",
|
|
});
|
|
|
|
assert.deepEqual(getLeadDiscoveryPriority({ hasWebsite: false }), {
|
|
priority: "high",
|
|
reason: "Kein Website-Indikator vorhanden.",
|
|
});
|
|
|
|
assert.deepEqual(getLeadDiscoveryPriority({ hasWebsite: true, hasWebsiteSignal: true }), {
|
|
priority: "low",
|
|
reason: "Website vorhanden: geringer Kontaktaufwand.",
|
|
});
|
|
|
|
assert.deepEqual(getLeadDiscoveryPriority({ hasWebsite: true, hasWebsiteSignal: false }), {
|
|
priority: "medium",
|
|
reason: "Standardpriorität.",
|
|
});
|
|
|
|
assert.deepEqual(getLeadDiscoveryPriority({ hasWebsite: true }), {
|
|
priority: "medium",
|
|
reason: "Standardpriorität.",
|
|
});
|
|
});
|