chore(template): clean-slate template snapshot from bb4a0c7
Curated, product-agnostic snapshot of the post-story-04 tree: demo content deleted, auth-only reference feature, web-next shell, all gates green. Product-specific docs, ADRs 027-029, PRDs/epics/archive, editor library traces, and product naming are curated out; generic template repairs (coverage provider devDeps, root test:coverage script, live lint fixes, root-only release-please) are kept. See TEMPLATE.md for provenance, curation list, and usage. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016j8z4VHjedXDTjEDNg7qHK
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { render, renderHook } from "@testing-library/react";
|
||||
import { RecordingAnalytics } from "@repo/core-testing";
|
||||
import {
|
||||
AnalyticsContextError,
|
||||
AnalyticsProvider,
|
||||
useAnalytics,
|
||||
} from "@/react/index";
|
||||
|
||||
function Tracker() {
|
||||
const analytics = useAnalytics();
|
||||
analytics.track("test.event");
|
||||
return null;
|
||||
}
|
||||
|
||||
describe("AnalyticsProvider", () => {
|
||||
it("makes analytics available through context and track flows through", () => {
|
||||
const recording = new RecordingAnalytics();
|
||||
|
||||
render(
|
||||
<AnalyticsProvider value={recording}>
|
||||
<Tracker />
|
||||
</AnalyticsProvider>,
|
||||
);
|
||||
|
||||
expect(recording.tracked).toContainEqual({ event: "test.event" });
|
||||
});
|
||||
});
|
||||
|
||||
describe("useAnalytics", () => {
|
||||
it("throws AnalyticsContextError when called outside a provider", () => {
|
||||
const spy = vi.spyOn(console, "error").mockImplementation(() => {});
|
||||
try {
|
||||
expect(() => renderHook(() => useAnalytics())).toThrow(
|
||||
AnalyticsContextError,
|
||||
);
|
||||
} finally {
|
||||
spy.mockRestore();
|
||||
}
|
||||
});
|
||||
});
|
||||
33
packages/core-analytics/src/react/analytics-provider.tsx
Normal file
33
packages/core-analytics/src/react/analytics-provider.tsx
Normal file
@@ -0,0 +1,33 @@
|
||||
import { createContext, useContext, type ReactNode } from "react";
|
||||
import type { IAnalytics } from "../analytics.interface";
|
||||
|
||||
const AnalyticsContext = createContext<IAnalytics | null>(null);
|
||||
|
||||
export class AnalyticsContextError extends Error {
|
||||
constructor() {
|
||||
super("useAnalytics() must be called within an <AnalyticsProvider>.");
|
||||
this.name = "AnalyticsContextError";
|
||||
}
|
||||
}
|
||||
|
||||
export function AnalyticsProvider({
|
||||
value,
|
||||
children,
|
||||
}: {
|
||||
value: IAnalytics;
|
||||
children: ReactNode;
|
||||
}) {
|
||||
return (
|
||||
<AnalyticsContext.Provider value={value}>
|
||||
{children}
|
||||
</AnalyticsContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export function useAnalytics(): IAnalytics {
|
||||
const analytics = useContext(AnalyticsContext);
|
||||
if (analytics === null) {
|
||||
throw new AnalyticsContextError();
|
||||
}
|
||||
return analytics;
|
||||
}
|
||||
5
packages/core-analytics/src/react/index.ts
Normal file
5
packages/core-analytics/src/react/index.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export {
|
||||
AnalyticsProvider,
|
||||
useAnalytics,
|
||||
AnalyticsContextError,
|
||||
} from "./analytics-provider";
|
||||
Reference in New Issue
Block a user