feat(core-analytics): add IAnalytics interface, types, and NoopAnalytics
Replaces generator placeholder with IAnalytics interface (track, identify, pageView, flush), AnalyticsAttributeValue + AnalyticsUser types, and NoopAnalytics implementation. Adds sibling tests covering all four methods with 100% coverage. All conformance + coverage gates pass. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,18 +1,18 @@
|
||||
{
|
||||
"generatedAt": "2026-05-13T18:36:10.133Z",
|
||||
"commit": "9800fed",
|
||||
"generatedAt": "2026-05-18T11:31:45.093Z",
|
||||
"commit": "80c702e",
|
||||
"repo": {
|
||||
"statements": 95.86,
|
||||
"branches": 88.91,
|
||||
"statements": 95.87,
|
||||
"branches": 89.02,
|
||||
"functions": 100,
|
||||
"lines": 95.86,
|
||||
"lines": 95.87,
|
||||
"counts": {
|
||||
"lf": 3113,
|
||||
"lh": 2984,
|
||||
"brf": 487,
|
||||
"brh": 433,
|
||||
"fnf": 142,
|
||||
"fnh": 142
|
||||
"lf": 3121,
|
||||
"lh": 2992,
|
||||
"brf": 492,
|
||||
"brh": 438,
|
||||
"fnf": 147,
|
||||
"fnh": 147
|
||||
}
|
||||
},
|
||||
"byPackage": {
|
||||
@@ -44,6 +44,20 @@
|
||||
"fnh": 29
|
||||
}
|
||||
},
|
||||
"@repo/core-analytics": {
|
||||
"statements": 100,
|
||||
"branches": 100,
|
||||
"functions": 100,
|
||||
"lines": 100,
|
||||
"counts": {
|
||||
"lf": 8,
|
||||
"lh": 8,
|
||||
"brf": 5,
|
||||
"brh": 5,
|
||||
"fnf": 5,
|
||||
"fnh": 5
|
||||
}
|
||||
},
|
||||
"@repo/marketing-pages": {
|
||||
"statements": 95.64,
|
||||
"branches": 83.93,
|
||||
|
||||
21
packages/core-analytics/src/analytics.interface.ts
Normal file
21
packages/core-analytics/src/analytics.interface.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
export type AnalyticsAttributeValue = string | number | boolean;
|
||||
|
||||
export type AnalyticsUser = {
|
||||
id: string;
|
||||
};
|
||||
|
||||
export interface IAnalytics {
|
||||
track(
|
||||
event: string,
|
||||
attributes?: Record<string, AnalyticsAttributeValue>,
|
||||
): void;
|
||||
identify(
|
||||
user: AnalyticsUser,
|
||||
attributes?: Record<string, AnalyticsAttributeValue>,
|
||||
): void;
|
||||
pageView(
|
||||
path: string,
|
||||
attributes?: Record<string, AnalyticsAttributeValue>,
|
||||
): void;
|
||||
flush(): Promise<void>;
|
||||
}
|
||||
@@ -1,2 +1,6 @@
|
||||
// placeholder — populated by story 01-scaffold-core-analytics-package
|
||||
export {};
|
||||
export type {
|
||||
AnalyticsAttributeValue,
|
||||
AnalyticsUser,
|
||||
IAnalytics,
|
||||
} from "./analytics.interface";
|
||||
export { NoopAnalytics } from "./noop-analytics";
|
||||
|
||||
54
packages/core-analytics/src/noop-analytics.test.ts
Normal file
54
packages/core-analytics/src/noop-analytics.test.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { NoopAnalytics } from "@/noop-analytics";
|
||||
|
||||
describe("NoopAnalytics", () => {
|
||||
it("track() does not throw with event name only", () => {
|
||||
const analytics = new NoopAnalytics();
|
||||
expect(() => analytics.track("page_viewed")).not.toThrow();
|
||||
});
|
||||
|
||||
it("track() does not throw with event name and attributes", () => {
|
||||
const analytics = new NoopAnalytics();
|
||||
expect(() =>
|
||||
analytics.track("button_clicked", {
|
||||
label: "signup",
|
||||
count: 1,
|
||||
active: true,
|
||||
}),
|
||||
).not.toThrow();
|
||||
});
|
||||
|
||||
it("identify() does not throw with user only", () => {
|
||||
const analytics = new NoopAnalytics();
|
||||
expect(() => analytics.identify({ id: "user-123" })).not.toThrow();
|
||||
});
|
||||
|
||||
it("identify() does not throw with user and attributes", () => {
|
||||
const analytics = new NoopAnalytics();
|
||||
expect(() =>
|
||||
analytics.identify({ id: "user-123" }, { plan: "pro", trial: false }),
|
||||
).not.toThrow();
|
||||
});
|
||||
|
||||
it("pageView() does not throw with path only", () => {
|
||||
const analytics = new NoopAnalytics();
|
||||
expect(() => analytics.pageView("/dashboard")).not.toThrow();
|
||||
});
|
||||
|
||||
it("pageView() does not throw with path and attributes", () => {
|
||||
const analytics = new NoopAnalytics();
|
||||
expect(() =>
|
||||
analytics.pageView("/dashboard", { referrer: "/home", duration: 120 }),
|
||||
).not.toThrow();
|
||||
});
|
||||
|
||||
it("flush() resolves without throwing", async () => {
|
||||
const analytics = new NoopAnalytics();
|
||||
await expect(analytics.flush()).resolves.toBeUndefined();
|
||||
});
|
||||
|
||||
it("flush() returns a Promise", () => {
|
||||
const analytics = new NoopAnalytics();
|
||||
expect(analytics.flush()).toBeInstanceOf(Promise);
|
||||
});
|
||||
});
|
||||
23
packages/core-analytics/src/noop-analytics.ts
Normal file
23
packages/core-analytics/src/noop-analytics.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import type {
|
||||
AnalyticsAttributeValue,
|
||||
AnalyticsUser,
|
||||
IAnalytics,
|
||||
} from "./analytics.interface";
|
||||
|
||||
export class NoopAnalytics implements IAnalytics {
|
||||
track(
|
||||
_event: string,
|
||||
_attributes?: Record<string, AnalyticsAttributeValue>,
|
||||
): void {}
|
||||
identify(
|
||||
_user: AnalyticsUser,
|
||||
_attributes?: Record<string, AnalyticsAttributeValue>,
|
||||
): void {}
|
||||
pageView(
|
||||
_path: string,
|
||||
_attributes?: Record<string, AnalyticsAttributeValue>,
|
||||
): void {}
|
||||
flush(): Promise<void> {
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user