Finalize metrics verification and backlog updates

This commit is contained in:
2026-06-05 21:49:57 +02:00
parent d3928d61c4
commit f069b74b08
15 changed files with 240 additions and 36 deletions

View File

@@ -61,6 +61,7 @@ test("analytics dashboard renders filters, Convex metrics, and Rybbit error stat
assert.doesNotMatch(pageSource, /DashboardPlaceholderPage/);
assert.match(pageSource, /AnalyticsDashboard/);
assert.match(componentSource, /api\.campaignMetrics\.getDashboard/);
assert.match(componentSource, /\/api\/internal\/rybbit\/campaign/);
assert.match(componentSource, /Kampagne/);
assert.match(componentSource, /Nische/);
assert.match(componentSource, /PLZ/);
@@ -69,4 +70,6 @@ test("analytics dashboard renders filters, Convex metrics, and Rybbit error stat
assert.match(componentSource, /Status/);
assert.match(componentSource, /Zeitraum/);
assert.match(componentSource, /Rybbit-Daten konnten nicht geladen werden/);
assert.match(componentSource, /Audit-Öffnungen/);
assert.match(componentSource, /CTA-Klicks/);
});

View File

@@ -192,6 +192,27 @@ test("toLeadFunnelCard maps blocked priority to deferred stage with blocker labe
assert.equal(card.nextAction, "Zurückstellung prüfen");
});
test("toLeadFunnelCard shows do-not-contact rechecks after the block window", () => {
const card = toLeadFunnelCard({
id: "lead-recheck",
companyName: "Agentur Recheck",
priority: "medium",
contactStatus: "do_not_contact",
blacklistStatus: "clear",
outreach: {
approvalStatus: "approved",
sendStatus: "sent",
responseStatus: "no_interest",
salesStatus: "do_not_pursue",
doNotContactUntil: Date.UTC(2026, 0, 1),
},
now: Date.UTC(2026, 0, 2),
});
assert.equal(card.stageId, "deferred");
assert.equal(card.nextAction, "Erneut prüfen");
});
test("dashboard-model exposes stable lead label helpers for UI mapping", () => {
assert.deepEqual(leadPriorityOptions, [
"high",

View File

@@ -32,3 +32,12 @@ test("manual sales status mutation updates lead suppression states", () => {
assert.match(outreachSource, /not_interested[\s\S]*outreachPatch\.responseStatus\s*=\s*"no_interest"/);
assert.match(outreachSource, /do_not_pursue[\s\S]*outreachPatch\.doNotContactUntil\s*=\s*now\s*\+\s*DO_NOT_CONTACT_RECHECK_MS/);
});
test("lead funnel query exposes do-not-contact recheck dates", () => {
const leadsSource = readFileSync(
join(process.cwd(), "convex", "leads.ts"),
"utf8",
);
assert.match(leadsSource, /doNotContactUntil:\s*latestOutreach\.doNotContactUntil/);
});

View File

@@ -3,6 +3,7 @@ import test from "node:test";
import {
buildRybbitEventsUrl,
summarizeCampaignRybbitEvents,
summarizeAuditRybbitEvents,
type RybbitEvent,
} from "../lib/rybbit-analytics";
@@ -70,3 +71,19 @@ test("summarizeAuditRybbitEvents returns graceful empty metrics", () => {
deviceTypes: [],
});
});
test("summarizeCampaignRybbitEvents aggregates public audit activity", () => {
assert.deepEqual(
summarizeCampaignRybbitEvents([
{ type: "pageview", pathname: "/audit/a" },
{ type: "pageview", pathname: "/dashboard" },
{ type: "custom_event", event_name: "audit_cta_click", pathname: "/audit/a" },
{ type: "outbound_link", pathname: "/audit/a" },
]),
{
auditOpens: 1,
ctaClicks: 1,
outboundClicks: 1,
},
);
});