Skip to content
63 changes: 63 additions & 0 deletions __tests__/admin/LearningAnalyticsPage.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@ function makeEngagement(overrides = {}) {
sessionLength: { tracked: false, avgMinutes: null },
lessonsCompleted: { tracked: false, buckets: [{ range: "1–5", value: 0 }] },
readingDepth: { tracked: false, buckets: [{ range: "0–25%", value: 0 }] },
geographic: {
tracked: true,
coverage: { label: "Country Data Coverage", value: 68, tracked: true },
countries: [
{ code: "US", name: "United States", learners: 214, revenue: 12840, tracked: true },
{ code: "GB", name: "United Kingdom", learners: 156, revenue: 9360, tracked: true },
],
},
...overrides,
};
}
Expand Down Expand Up @@ -95,3 +103,58 @@ describe("LearningAnalyticsPage — states", () => {
expect(screen.getByText("Service unavailable")).toBeInTheDocument();
});
});

describe("LearningAnalyticsPage — geographic distribution", () => {
it("renders the geographic distribution card with coverage percentage", async () => {
serviceState.current = () => Promise.resolve(makeEngagement());
render(<LearningAnalyticsPage />);

expect(await screen.findByText("Geographic Distribution")).toBeInTheDocument();
expect(screen.getByText("Country Data Coverage")).toBeInTheDocument();
expect(screen.getByText("68%")).toBeInTheDocument();
expect(screen.getByText("United States")).toBeInTheDocument();
expect(screen.getByText("United Kingdom")).toBeInTheDocument();
});

it("renders the top-countries table with learner counts and revenue", async () => {
serviceState.current = () => Promise.resolve(makeEngagement());
render(<LearningAnalyticsPage />);

expect(await screen.findByText("Top Countries")).toBeInTheDocument();
expect(screen.getByText("Learners")).toBeInTheDocument();
expect(screen.getByText("Revenue")).toBeInTheDocument();
expect(screen.getByText("214")).toBeInTheDocument();
expect(screen.getByText("$12,840")).toBeInTheDocument();
expect(screen.getByText("156")).toBeInTheDocument();
expect(screen.getByText("$9,360")).toBeInTheDocument();
});

it("shows a coverage note when country data is incomplete", async () => {
serviceState.current = () => Promise.resolve(makeEngagement());
render(<LearningAnalyticsPage />);

await screen.findByText("Geographic Distribution");
expect(
screen.getByText(/Country data is available for 68% of learners/i)
).toBeInTheDocument();
});

it("renders a not-tracked placeholder when geographic data is unavailable", async () => {
serviceState.current = () =>
Promise.resolve(
makeEngagement({
geographic: {
tracked: false,
coverage: { label: "Country Data Coverage", value: 0, tracked: false },
countries: [],
},
})
);
render(<LearningAnalyticsPage />);

expect(await screen.findByText("Geographic Distribution")).toBeInTheDocument();
expect(
screen.getByText(/Country data from learner profiles isn't instrumented yet/i)
).toBeInTheDocument();
});
});
27 changes: 27 additions & 0 deletions __tests__/admin/admin-learning-analytics.service.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,31 @@ describe("fetchEngagementAnalytics", () => {
expect(typeof bucket.value).toBe("number");
}
});

it("resolves a geographic snapshot with coverage and country shapes", async () => {
const data = await fetchEngagementAnalytics();
expect(data.geographic).toBeDefined();
expect(typeof data.geographic.tracked).toBe("boolean");
expect(typeof data.geographic.coverage.label).toBe("string");
expect(typeof data.geographic.coverage.value).toBe("number");
expect(typeof data.geographic.coverage.tracked).toBe("boolean");
expect(Array.isArray(data.geographic.countries)).toBe(true);
expect(data.geographic.countries.length).toBeGreaterThan(0);
for (const country of data.geographic.countries) {
expect(typeof country.code).toBe("string");
expect(typeof country.name).toBe("string");
expect(typeof country.learners).toBe("number");
expect(typeof country.revenue).toBe("number");
expect(typeof country.tracked).toBe("boolean");
}
});

it("accepts an optional date range and still resolves the snapshot", async () => {
const data = await fetchEngagementAnalytics({
from: "2026-01-01T00:00:00.000Z",
to: "2026-03-31T23:59:59.999Z",
});
expect(typeof data.generatedAt).toBe("string");
expect(data.geographic.countries.length).toBeGreaterThan(0);
});
});
Loading
Loading