Add audit analytics and campaign metrics

This commit is contained in:
2026-06-05 21:43:43 +02:00
parent 70951789d2
commit df8ca1f049
12 changed files with 737 additions and 20 deletions

View File

@@ -0,0 +1,72 @@
import assert from "node:assert/strict";
import test from "node:test";
import {
buildRybbitEventsUrl,
summarizeAuditRybbitEvents,
type RybbitEvent,
} from "../lib/rybbit-analytics";
test("buildRybbitEventsUrl targets the documented events endpoint", () => {
const url = buildRybbitEventsUrl({
apiUrl: "https://analytics.example.com/",
siteId: "site_123",
startDate: "2026-06-01T00:00:00.000Z",
endDate: "2026-06-05T00:00:00.000Z",
});
assert.equal(
url.toString(),
"https://analytics.example.com/api/sites/site_123/events?start_date=2026-06-01T00%3A00%3A00.000Z&end_date=2026-06-05T00%3A00%3A00.000Z",
);
});
test("summarizeAuditRybbitEvents extracts opens, clicks, last view, and devices", () => {
const events: RybbitEvent[] = [
{
type: "pageview",
timestamp: "2026-06-05T10:00:00.000Z",
pathname: "/audit/demo",
properties: { device: "desktop" },
},
{
type: "custom_event",
timestamp: "2026-06-05T10:05:00.000Z",
event_name: "audit_cta_click",
pathname: "/audit/demo",
properties: { target: "cta", deviceType: "mobile" },
},
{
type: "outbound_link",
timestamp: "2026-06-05T10:06:00.000Z",
pathname: "/audit/demo",
properties: { href: "https://example.com", device: "mobile" },
},
{
type: "pageview",
timestamp: "2026-06-05T11:00:00.000Z",
pathname: "/pricing",
properties: { device: "desktop" },
},
];
assert.deepEqual(summarizeAuditRybbitEvents(events, "/audit/demo"), {
opened: true,
viewCount: 1,
lastView: "2026-06-05T10:00:00.000Z",
ctaClicks: 1,
websiteLinkClicks: 1,
deviceTypes: ["desktop", "mobile"],
});
});
test("summarizeAuditRybbitEvents returns graceful empty metrics", () => {
assert.deepEqual(summarizeAuditRybbitEvents([], "/audit/demo"), {
opened: false,
viewCount: 0,
lastView: null,
ctaClicks: 0,
websiteLinkClicks: 0,
deviceTypes: [],
});
});