146 lines
5.1 KiB
TypeScript
146 lines
5.1 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import { readFile } from "node:fs/promises";
|
|
import { join } from "node:path";
|
|
import test from "node:test";
|
|
|
|
const leadsReviewPath = join(
|
|
process.cwd(),
|
|
"components",
|
|
"leads",
|
|
"leads-review-table.tsx",
|
|
);
|
|
|
|
test("LeadsReviewTable uses compact card summaries with modal review details", async () => {
|
|
const source = await readFile(leadsReviewPath, "utf8");
|
|
|
|
assert.doesNotMatch(source, /<table\b/i);
|
|
assert.doesNotMatch(source, /<thead\b/i);
|
|
assert.doesNotMatch(source, /<tbody\b/i);
|
|
assert.doesNotMatch(source, /<tr\b/i);
|
|
assert.doesNotMatch(source, /<td\b/i);
|
|
assert.doesNotMatch(source, /<th\b/i);
|
|
assert.doesNotMatch(source, /min-w-\[/i);
|
|
|
|
assert.match(source, /Dialog/);
|
|
assert.match(source, /DialogContent/);
|
|
assert.match(source, /DialogHeader/);
|
|
assert.match(source, /DialogTitle/);
|
|
assert.match(source, /DialogDescription/);
|
|
assert.match(source, /max-h-\[calc\(100dvh-2rem\)\]/);
|
|
assert.match(source, /overflow-y-auto/);
|
|
assert.match(source, /Mehr anzeigen/);
|
|
assert.match(source, /id=\{[^}]+\}/);
|
|
assert.doesNotMatch(source, /Weniger anzeigen/);
|
|
assert.doesNotMatch(source, /aria-expanded=\{[^}]+\}/);
|
|
assert.doesNotMatch(source, /aria-controls=\{[^}]+\}/);
|
|
assert.doesNotMatch(source, /hidden=\{!?isExpanded\}/);
|
|
|
|
const companyNameMatch = source.match(
|
|
/<p className="([^"]+)"[^>]*>\s*\{lead\.companyName\}\s*<\/p>/,
|
|
);
|
|
assert.ok(
|
|
companyNameMatch !== null &&
|
|
/(?:^|\s)(truncate|max-w-full|min-w-0|break-words)(?:\s|$)/.test(
|
|
companyNameMatch[1],
|
|
),
|
|
"Company name should use overflow-safe text classes in compact card.",
|
|
);
|
|
|
|
const nicheMatch = source.match(
|
|
/lead\.niche\s+\?\?\s+"Nische offen"\}\s*<\/span>/,
|
|
);
|
|
assert.ok(
|
|
nicheMatch !== null,
|
|
"Niche rendering should still be asserted in test fixture.",
|
|
);
|
|
const nicheContainerMatch = source.match(
|
|
/<span className="([^"]+)">\s*\{lead\.niche\s+\?\?\s+"Nische offen"\}\s*<\/span>/,
|
|
);
|
|
assert.ok(
|
|
nicheContainerMatch !== null &&
|
|
/(?:^|\s)(truncate|max-w-full|break-all|break-words)(?:\s|$)/.test(
|
|
nicheContainerMatch[1],
|
|
),
|
|
"Niche should use overflow-safe text classes in compact card.",
|
|
);
|
|
|
|
const locationMatch = source.match(/\{location\}/);
|
|
assert.ok(
|
|
locationMatch !== null,
|
|
"Location rendering should still be present in compact card.",
|
|
);
|
|
const locationContainerMatch = source.match(
|
|
/<span className="([^"]+)">\s*\{location\}\s*<\/span>/,
|
|
);
|
|
assert.ok(
|
|
locationContainerMatch !== null &&
|
|
/(?:^|\s)(truncate|max-w-full|break-words)(?:\s|$)/.test(
|
|
locationContainerMatch[1],
|
|
),
|
|
"Location should use overflow-safe text classes in compact card.",
|
|
);
|
|
|
|
const emailAnchorMatch = source.match(
|
|
/<a className="([^"]+)" href=\{emailHref\}>\s*\{lead\.email\}\s*<\/a>/,
|
|
);
|
|
assert.ok(
|
|
emailAnchorMatch !== null &&
|
|
/(?:^|\s)(break-all|max-w-full|min-w-0)(?:\s|$)/.test(
|
|
emailAnchorMatch[1],
|
|
),
|
|
"Lead email should use an overflow-safe mailto link in compact card.",
|
|
);
|
|
assert.match(source, /<span className="[^"]*">\s*Keine E-Mail\s*<\/span>/);
|
|
|
|
const phoneAnchorMatch = source.match(
|
|
/<a className="([^"]+)" href=\{phoneHref\}>\s*\{lead\.phone\}\s*<\/a>/,
|
|
);
|
|
assert.ok(
|
|
phoneAnchorMatch !== null &&
|
|
/(?:^|\s)(break-all|max-w-full|min-w-0)(?:\s|$)/.test(phoneAnchorMatch[1]),
|
|
"Lead phone should use an overflow-safe tel link in compact card.",
|
|
);
|
|
assert.match(source, /toEmailHref/);
|
|
assert.match(source, /mailto:\$\{normalizedEmail\}/);
|
|
assert.match(source, /toPhoneHref/);
|
|
assert.match(source, /tel:\$\{dialablePhone\}/);
|
|
assert.match(source, /toWebsiteHref/);
|
|
assert.match(source, /href=\{websiteHref\}/);
|
|
assert.match(source, /target="_blank"/);
|
|
assert.match(source, /rel="noreferrer"/);
|
|
|
|
assert.match(source, /Kontaktstatus/);
|
|
assert.match(source, /Review-E-Mail/);
|
|
assert.match(source, /Review-Quelle/);
|
|
assert.match(source, /Ansprechperson/);
|
|
assert.match(source, /Genannte E-Mail als Business-Kontakt/);
|
|
assert.match(source, /Duplikatstatus/);
|
|
assert.match(source, /Sperrstatus/);
|
|
assert.match(source, /Sperren/);
|
|
assert.match(source, /Speichern/);
|
|
});
|
|
|
|
test("LeadsReviewTable exposes count filters and live status feedback", async () => {
|
|
const source = await readFile(leadsReviewPath, "utf8");
|
|
|
|
assert.match(source, /leadStatusFilters/);
|
|
assert.match(source, /setActiveFilter/);
|
|
assert.match(source, /Alle Leads/);
|
|
assert.match(source, /Hohe Priorit(?:aet|ät)/);
|
|
assert.match(source, /Gesperrt/);
|
|
assert.match(source, /role="status"/);
|
|
assert.match(source, /role="alert"/);
|
|
});
|
|
|
|
test("LeadsReviewTable exposes explicit manual audit start action", async () => {
|
|
const source = await readFile(leadsReviewPath, "utf8");
|
|
|
|
assert.match(source, /api\.pageSpeed\.requestLeadAudit/);
|
|
assert.match(source, /api\.pageSpeed\.getLeadAuditStartStates/);
|
|
assert.match(source, /Audit starten/);
|
|
assert.match(source, /auditStartDisabledReason/);
|
|
assert.match(source, /Website fehlt|Keine Website/);
|
|
assert.match(source, /Audit l(?:ä|ae)uft|Audit läuft/);
|
|
assert.doesNotMatch(source, /api\.websiteEnrichment\.queueLeadEnrichment/);
|
|
});
|