- {groups.map((group) => {
- const sectionStart = globalIndex;
+ {groups.map((group, gi) => {
+ const sectionStart = groupOffsets[gi];
return (
{group.tracks.map((track, i) => {
const cardIndex = sectionStart + i;
- globalIndex = cardIndex + 1;
return (
{
expect(screen.getAllByText("Step Sequence").length).toBe(10);
});
- it("lists homepage categories as actual app surfaces", () => {
- render();
-
- expect(screen.getByText("THE FULL APP")).not.toBeNull();
- expect(screen.queryByText("Core Capabilities")).toBeNull();
-
- // All 22 area titles present
- expect(screen.getAllByText("Save & Import").length).toBeGreaterThan(0);
- expect(screen.getAllByText("Organizer").length).toBeGreaterThan(0);
- expect(screen.getAllByText("Career Accelerator").length).toBeGreaterThan(0);
- expect(screen.getAllByText("Engine").length).toBeGreaterThan(0);
- expect(screen.getAllByText("Projects").length).toBeGreaterThan(0);
- expect(screen.getAllByText("Chat").length).toBeGreaterThan(0);
- expect(screen.getAllByText("Library").length).toBeGreaterThan(0);
- expect(screen.getAllByText("LinkedIn & Events").length).toBeGreaterThan(0);
- expect(screen.getAllByText("Dev Reference").length).toBeGreaterThan(0);
- expect(screen.getAllByText("Interview Prep").length).toBeGreaterThan(0);
- expect(screen.getAllByText("Maths").length).toBeGreaterThan(0);
- expect(screen.getAllByText("Chinese").length).toBeGreaterThan(0);
- expect(screen.getAllByText(/Culture G/).length).toBeGreaterThan(0);
- expect(screen.getAllByText("Applied Systems").length).toBeGreaterThan(0);
- expect(screen.getAllByText("Embodied AI").length).toBeGreaterThan(0);
- expect(screen.getAllByText("Bio-Augmentation").length).toBeGreaterThan(0);
- expect(screen.getAllByText("Cognitive Toolkit").length).toBeGreaterThan(0);
- expect(screen.getAllByText("Innervisions").length).toBeGreaterThan(0);
- expect(screen.getAllByText("Shopify & Module 48").length).toBeGreaterThan(
- 0,
- );
- expect(screen.getAllByText("Elite Freelance").length).toBeGreaterThan(0);
- expect(screen.getAllByText("Productivity").length).toBeGreaterThan(0);
- expect(screen.getAllByText("System Health").length).toBeGreaterThan(0);
-
- // Spot-check descriptions
- expect(
- screen.getAllByText(/Paste a URL or upload a file/).length,
- ).toBeGreaterThan(0);
- expect(
- screen.getAllByText(/Module 48 fashion operations/).length,
- ).toBeGreaterThan(0);
- });
-
it("describes the source-to-proof user workflow", () => {
render();
@@ -375,50 +333,6 @@ describe("Landing sections", () => {
expect(openModule48.getAttribute("href")).toBe("/module-48");
});
- it("adds a dedicated why section for Adrien's mission", () => {
- render();
-
- expect(screen.getByText("SAMARITAN RAISON D'ETRE")).not.toBeNull();
- expect(
- screen.getByText(
- "Why this system exists: help Adrien Le Doussal turn learning into compounding capability and real-world leverage.",
- ),
- ).not.toBeNull();
- expect(
- screen.getByText(
- /Compound \+ Harness - compound high-signal evidence and harness execution with explicit constraints and verification loops\./i,
- { selector: "li" },
- ),
- ).not.toBeNull();
- expect(
- screen.getByText(
- /superpowers profile and better execution decisions over time\./i,
- { selector: "li" },
- ),
- ).not.toBeNull();
- expect(
- screen.getAllByText("I am building my brand Module 48.").length,
- ).toBeGreaterThan(0);
- expect(
- screen.getAllByText(
- "It is also a RAG since I can query all of Samaritan's knowledge scope.",
- ).length,
- ).toBeGreaterThan(0);
-
- const whySectionHeading = screen.getByText(
- "Why this system exists: help Adrien Le Doussal turn learning into compounding capability and real-world leverage.",
- );
- const whySection = whySectionHeading.closest("section");
- expect(whySection).not.toBeNull();
-
- const sectionScope = within(whySection as HTMLElement);
- expect(sectionScope.getAllByTestId("why-adrien-point")).toHaveLength(18);
- expect(sectionScope.getAllByTestId("why-adrien-how")).toHaveLength(18);
- expect(
- sectionScope.getAllByText(/How this app delivers:/i).length,
- ).toBeGreaterThan(0);
- });
-
it("adds a dedicated Innervisions section on the homepage", () => {
render();
diff --git a/frontend/tests/MathRefreshView.test.tsx b/frontend/tests/MathRefreshView.test.tsx
deleted file mode 100644
index 6de62f10..00000000
--- a/frontend/tests/MathRefreshView.test.tsx
+++ /dev/null
@@ -1,211 +0,0 @@
-import { render, screen } from "@testing-library/react";
-import { beforeEach, describe, expect, it, vi } from "vitest";
-
-import { MathRefreshView } from "../src/views/MathRefreshView";
-
-const router_mocks = vi.hoisted(() => ({
- navigate: vi.fn(),
- use_search: vi.fn(() => ({})),
-}));
-
-vi.mock("@tanstack/react-router", () => ({
- useNavigate: () => router_mocks.navigate,
- useSearch: () => router_mocks.use_search(),
-}));
-
-describe("MathRefreshView", () => {
- beforeEach(() => {
- router_mocks.navigate.mockReset();
- router_mocks.use_search.mockReset();
- router_mocks.use_search.mockReturnValue({});
- });
-
- it("renders Zero to One track with methode tab by default", () => {
- render();
-
- expect(
- screen.getByText("Principe : progression sequentielle stricte"),
- ).not.toBeNull();
- expect(screen.getByText("Semaines totales (track)")).not.toBeNull();
- });
-
- it("falls back to methode tab when tab is invalid", () => {
- router_mocks.use_search.mockReturnValue({ tab: "unknown_tab" });
- render();
-
- expect(
- screen.getByText("Principe : progression sequentielle stricte"),
- ).not.toBeNull();
- });
-
- it("renders diagnostic tab with enriched content", () => {
- router_mocks.use_search.mockReturnValue({ tab: "diagnostic" });
- render();
-
- expect(screen.getByText("Vue d'ensemble")).not.toBeNull();
- expect(screen.getByText("Diagnostic de positionnement")).not.toBeNull();
- expect(screen.getByText("Semaines estimees")).not.toBeNull();
- });
-
- it("renders college tab content from URL", () => {
- router_mocks.use_search.mockReturnValue({ tab: "college" });
- render();
-
- expect(
- screen.getByRole("heading", { level: 1, name: "College (6e-3e)" }),
- ).not.toBeNull();
- expect(document.title).toBe("Maths - College (6e-3e) | Samaritan");
- expect(screen.getByText("Nombres et calcul litteral")).not.toBeNull();
- expect(screen.getByText("Prerequis")).not.toBeNull();
- });
-
- it("renders terminale tab with progression gate", () => {
- router_mocks.use_search.mockReturnValue({ tab: "terminale" });
- render();
-
- expect(
- screen.getByText("Criteres de passage au niveau suivant"),
- ).not.toBeNull();
- expect(screen.getByText("Ressources recommandees")).not.toBeNull();
- });
-
- it("renders evaluation tab for zero_to_one track", () => {
- router_mocks.use_search.mockReturnValue({ tab: "evaluation" });
- render();
-
- expect(screen.getByText("Competences a valider")).not.toBeNull();
- expect(screen.getByText("Decision de progression")).not.toBeNull();
- expect(screen.getByText("Diagnostic & Arithmetique")).not.toBeNull();
- });
-
- it("renders linear algebra content in prepa_ml track", () => {
- router_mocks.use_search.mockReturnValue({
- track: "prepa_ml",
- tab: "linear_algebra",
- });
- render();
-
- expect(screen.getByText("Espaces vectoriels")).not.toBeNull();
- expect(
- screen.getByText("Diagonalisation et trigonalisation"),
- ).not.toBeNull();
- expect(screen.getByText("Ressources recommandees")).not.toBeNull();
- });
-
- it("renders applied ML tab in prepa_ml track", () => {
- router_mocks.use_search.mockReturnValue({
- track: "prepa_ml",
- tab: "applied_ml",
- });
- render();
-
- expect(screen.getByText("Theorie de l'information")).not.toBeNull();
- expect(
- screen.getByText("Criteres de passage au niveau suivant"),
- ).not.toBeNull();
- });
-
- it("renders methode tab for prepa_ml track", () => {
- router_mocks.use_search.mockReturnValue({
- track: "prepa_ml",
- tab: "methode",
- });
- render();
-
- expect(
- screen.getByText("Principe : progression sequentielle stricte"),
- ).not.toBeNull();
- // Prepa ML specific values
- expect(screen.getByText("120 min")).not.toBeNull();
- });
-
- it("renders evaluation tab for prepa_ml track", () => {
- router_mocks.use_search.mockReturnValue({
- track: "prepa_ml",
- tab: "evaluation",
- });
- render();
-
- expect(screen.getByText("Competences a valider")).not.toBeNull();
- expect(screen.getAllByText("Algebre Lineaire").length).toBeGreaterThan(0);
- expect(screen.getAllByText("Maths Appliquees ML").length).toBeGreaterThan(
- 0,
- );
- });
-
- it("renders geometry_3d tab content in prepa_ml track", () => {
- router_mocks.use_search.mockReturnValue({
- track: "prepa_ml",
- tab: "geometry_3d",
- });
- render();
-
- expect(screen.getByText("Vue d'ensemble")).not.toBeNull();
- expect(screen.getByText(/Geometrie projective/)).not.toBeNull();
- });
-
- it("renders dynamics_physics tab content in prepa_ml track", () => {
- router_mocks.use_search.mockReturnValue({
- track: "prepa_ml",
- tab: "dynamics_physics",
- });
- render();
-
- expect(screen.getByText("Vue d'ensemble")).not.toBeNull();
- expect(screen.getByText(/mecanique lagrangienne/)).not.toBeNull();
- });
-
- it("defaults to methode when prepa_ml track has invalid tab", () => {
- router_mocks.use_search.mockReturnValue({
- track: "prepa_ml",
- tab: "diagnostic",
- });
- render();
-
- // diagnostic is not valid for prepa_ml track, should fall back to methode
- expect(
- screen.getByText("Principe : progression sequentielle stricte"),
- ).not.toBeNull();
- });
-
- it("shows enriched topic blocks with concepts and exercises", () => {
- router_mocks.use_search.mockReturnValue({ tab: "diagnostic" });
- render();
-
- // Check for enriched content sections
- expect(screen.getAllByText("Concepts cles").length).toBeGreaterThan(0);
- expect(screen.getAllByText("Exercices pratiques").length).toBeGreaterThan(
- 0,
- );
- expect(screen.getAllByText(/Je maitrise si/).length).toBeGreaterThan(0);
- });
-
- it("renders pratique tab with practice dashboard", () => {
- router_mocks.use_search.mockReturnValue({ tab: "pratique" });
- render();
-
- expect(screen.getByText("Choisissez un sujet")).not.toBeNull();
- expect(screen.getByText("Exercices faits")).not.toBeNull();
- expect(screen.getByText("Precision globale")).not.toBeNull();
- });
-
- it("renders pratique tab for prepa_ml track", () => {
- router_mocks.use_search.mockReturnValue({
- track: "prepa_ml",
- tab: "pratique",
- });
- render();
-
- expect(screen.getByText("Choisissez un sujet")).not.toBeNull();
- expect(screen.getByText("Algebre Lineaire")).not.toBeNull();
- });
-
- it("renders pratique tab topics for zero_to_one when URL has pratique", () => {
- router_mocks.use_search.mockReturnValue({ tab: "pratique" });
- render();
-
- // The pratique tab shows topic names for zero_to_one track
- expect(screen.getByText("Diagnostic & Arithmetique")).not.toBeNull();
- expect(screen.getByText("Terminale S")).not.toBeNull();
- });
-});
diff --git a/frontend/tests/Sidebar.test.tsx b/frontend/tests/Sidebar.test.tsx
index e8d89124..7cce9d50 100644
--- a/frontend/tests/Sidebar.test.tsx
+++ b/frontend/tests/Sidebar.test.tsx
@@ -180,25 +180,6 @@ describe("Sidebar", () => {
});
});
- it("opens side projects view from sidebar nav", () => {
- render(
-
- {}}
- onDeleteConversation={() => {}}
- />
- ,
- );
-
- fireEvent.click(screen.getByRole("button", { name: "Side Projects" }));
- expect(routerMocks.navigate).toHaveBeenCalledWith({
- to: "/module-48",
- });
- });
-
it("opens changelog view from sidebar nav", () => {
render(
@@ -443,109 +424,6 @@ describe("Sidebar", () => {
});
});
- it("renders all expected primary sidebar pages", { timeout: 15_000 }, () => {
- window.localStorage.setItem(
- "sidebar-sub-nav-expanded",
- JSON.stringify({ reference: true, system_tools: true }),
- );
-
- render(
-
- {}}
- onDeleteConversation={() => {}}
- />
- ,
- );
-
- // Top-level items always visible
- const alwaysVisible = [
- "Ingest",
- "Library",
- "Chat",
- "Career",
- "Projects",
- "Organizer",
- "Mission Control",
- "Reference",
- "Learning",
- "Personal",
- "Side Projects",
- "Monitor",
- "Changelog",
- "System Tools",
- "How It Works",
- ];
-
- alwaysVisible.forEach((name) => {
- expect(screen.getByRole("button", { name })).not.toBeNull();
- });
-
- // Expanded-by-default sub-items
- const expandedByDefault = [
- "Profile",
- "Accelerator",
- "Network",
- "Opportunities",
- "Enterprise projects",
- "AI-powered projects",
- "Health",
- "Eval Runs (Local)",
- "Test Cases",
- "Databases",
- "LLM Costs",
- "Tracing",
- "Plan Usage",
- "Token Playbook",
- "Control Tower",
- "Launch Plan",
- "Ingestion",
- "Build Progress",
- "Weekly Plan",
- "Activity",
- "Site Map",
- "Overview",
- "Contracts",
- "Event-Driven",
- "Models",
- ];
-
- expandedByDefault.forEach((name) => {
- expect(screen.getByRole("button", { name })).not.toBeNull();
- });
-
- // Items visible via localStorage expand (reference + system_tools)
- const expandedViaLocalStorage = [
- "Engine",
- "Taxonomy",
- "Product Completion",
- "FAANG Prep",
- "SQL Prep",
- "System Design Prep",
- "LLMOps",
- "RecSys",
- "DataOps",
- "Evals",
- "3D Vision",
- ];
-
- expandedViaLocalStorage.forEach((name) => {
- expect(screen.getByRole("button", { name })).not.toBeNull();
- });
-
- // Items that appear more than once across different sections
- const duplicatedPages = ["Website TODO", "Module 48", "Architecture"];
-
- duplicatedPages.forEach((name) => {
- expect(
- screen.getAllByRole("button", { name }).length,
- ).toBeGreaterThanOrEqual(2);
- });
- });
-
it("renders grouped nav section labels in expanded mode", () => {
render(
@@ -808,295 +686,6 @@ describe("Sidebar", () => {
).toContain("bg-white/[0.12]");
});
- it("opens prep tabs from sidebar sub-nav", () => {
- window.localStorage.setItem(
- "sidebar-sub-nav-expanded",
- JSON.stringify({ reference: true }),
- );
-
- render(
-
- {}}
- onDeleteConversation={() => {}}
- />
- ,
- );
-
- fireEvent.click(screen.getByRole("button", { name: "FAANG Prep" }));
- expect(routerMocks.navigate).toHaveBeenCalledWith({
- to: "/reference",
- search: { section: "prep", tab: "faang" },
- });
-
- fireEvent.click(screen.getByRole("button", { name: "SQL Prep" }));
- expect(routerMocks.navigate).toHaveBeenCalledWith({
- to: "/reference",
- search: { section: "prep", tab: "sql" },
- });
-
- fireEvent.click(screen.getByRole("button", { name: "System Design Prep" }));
- expect(routerMocks.navigate).toHaveBeenCalledWith({
- to: "/reference",
- search: { section: "prep", tab: "system_design" },
- });
- });
-
- it("opens extended dev reference tabs from sidebar sub-nav", () => {
- window.localStorage.setItem(
- "sidebar-sub-nav-expanded",
- JSON.stringify({ reference: true }),
- );
-
- render(
-
- {}}
- onDeleteConversation={() => {}}
- />
- ,
- );
-
- fireEvent.click(screen.getByText(/Dev Ref — Stack/));
-
- fireEvent.click(screen.getByRole("button", { name: "Databricks" }));
- expect(routerMocks.navigate).toHaveBeenCalledWith({
- to: "/reference",
- search: { section: "dev-ref", tab: "databricks" },
- });
-
- fireEvent.click(screen.getByRole("button", { name: "OpenAI" }));
- expect(routerMocks.navigate).toHaveBeenCalledWith({
- to: "/reference",
- search: { section: "dev-ref", tab: "openai" },
- });
- });
-
- it("keeps section headers visible for cognitive toolkit, behavioral design, and elite freelance under /reference", () => {
- window.localStorage.setItem(
- "sidebar-sub-nav-expanded",
- JSON.stringify({ reference: true }),
- );
-
- const { rerender } = render(
-
- {}}
- onDeleteConversation={() => {}}
- />
- ,
- );
-
- fireEvent.click(screen.getByText("More..."));
-
- routerMocks.pathname = "/reference";
- routerMocks.search = { section: "cognitive-toolkit", tab: "techniques" };
- rerender(
-
- {}}
- onDeleteConversation={() => {}}
- />
- ,
- );
- expect(screen.getByText("Cognitive Toolkit")).not.toBeNull();
-
- routerMocks.search = {
- section: "behavioral-design",
- tab: "variable_rewards",
- };
- rerender(
-
- {}}
- onDeleteConversation={() => {}}
- />
- ,
- );
- expect(screen.getByText("Behavioral Design")).not.toBeNull();
-
- routerMocks.search = { section: "elite-freelance", tab: "apis_at_scale" };
- rerender(
-
- {}}
- onDeleteConversation={() => {}}
- />
- ,
- );
- expect(screen.getByText("Elite Freelance")).not.toBeNull();
- });
-
- it("splits dev reference into language and tooling groups", () => {
- window.localStorage.setItem(
- "sidebar-sub-nav-expanded",
- JSON.stringify({ reference: true }),
- );
-
- render(
-
- {}}
- onDeleteConversation={() => {}}
- />
- ,
- );
-
- const language_group = screen.getByText(/Dev Ref — Languages/);
- const stack_group = screen.getByText(/Dev Ref — Stack/);
-
- fireEvent.click(language_group);
- fireEvent.click(stack_group);
-
- const swift = screen.getByRole("button", { name: "Swift" });
- const databricks = screen.getByRole("button", { name: "Databricks" });
-
- expect(
- swift.compareDocumentPosition(stack_group) &
- Node.DOCUMENT_POSITION_FOLLOWING,
- ).toBeTruthy();
- expect(
- stack_group.compareDocumentPosition(databricks) &
- Node.DOCUMENT_POSITION_FOLLOWING,
- ).toBeTruthy();
- expect(language_group).not.toBeNull();
- });
-
- it("shows the extended tooling tabs in dev reference", () => {
- window.localStorage.setItem(
- "sidebar-sub-nav-expanded",
- JSON.stringify({ reference: true }),
- );
-
- render(
-
- {}}
- onDeleteConversation={() => {}}
- />
- ,
- );
-
- fireEvent.click(screen.getByText(/Dev Ref — Stack/));
-
- expect(screen.getByRole("button", { name: "D3" })).not.toBeNull();
- expect(screen.getByRole("button", { name: "AWS" })).not.toBeNull();
- expect(screen.getByRole("button", { name: "GCP" })).not.toBeNull();
- expect(
- screen.getByRole("button", { name: "OpenTelemetry" }),
- ).not.toBeNull();
- expect(screen.getByRole("button", { name: "GraphQL" })).not.toBeNull();
- expect(screen.getByRole("button", { name: "gRPC" })).not.toBeNull();
- expect(screen.getByRole("button", { name: "Terraform" })).not.toBeNull();
- expect(
- screen.getByRole("button", { name: "GitHub Actions" }),
- ).not.toBeNull();
- expect(screen.getByRole("button", { name: "Iceberg" })).not.toBeNull();
- expect(screen.getByRole("button", { name: "Feast" })).not.toBeNull();
- });
-
- it("opens applied systems tabs from sidebar sub-nav", () => {
- window.localStorage.setItem(
- "sidebar-sub-nav-expanded",
- JSON.stringify({ reference: true }),
- );
-
- render(
-
- {}}
- onDeleteConversation={() => {}}
- />
- ,
- );
-
- fireEvent.click(screen.getByRole("button", { name: "LLMOps" }));
- expect(routerMocks.navigate).toHaveBeenCalledWith({
- to: "/reference",
- search: { section: "applied-systems", tab: "llmops" },
- });
-
- fireEvent.click(screen.getByRole("button", { name: "RecSys" }));
- expect(routerMocks.navigate).toHaveBeenCalledWith({
- to: "/reference",
- search: { section: "applied-systems", tab: "recsys" },
- });
-
- fireEvent.click(screen.getByRole("button", { name: "DataOps" }));
- expect(routerMocks.navigate).toHaveBeenCalledWith({
- to: "/reference",
- search: { section: "applied-systems", tab: "dataops" },
- });
- });
-
- it("opens culture generale tabs from sidebar sub-nav", () => {
- window.localStorage.setItem(
- "sidebar-sub-nav-expanded",
- JSON.stringify({ reference: true }),
- );
-
- render(
-
- {}}
- onDeleteConversation={() => {}}
- />
- ,
- );
-
- fireEvent.click(screen.getByText("More..."));
-
- fireEvent.click(screen.getByRole("button", { name: "Philo des Sciences" }));
- expect(routerMocks.navigate).toHaveBeenCalledWith({
- to: "/reference",
- search: {
- section: "culture-generale",
- track: "humanites",
- tab: "philo_science",
- },
- });
-
- fireEvent.click(screen.getByRole("button", { name: "Economie & Jeux" }));
- expect(routerMocks.navigate).toHaveBeenCalledWith({
- to: "/reference",
- search: {
- section: "culture-generale",
- track: "sciences_sociales",
- tab: "economics",
- },
- });
- });
-
it("uses tight divider spacing between core and workspaces sections", () => {
render(
diff --git a/frontend/tests/math-exercise/answer-check.test.ts b/frontend/tests/math-exercise/answer-check.test.ts
deleted file mode 100644
index b28ecede..00000000
--- a/frontend/tests/math-exercise/answer-check.test.ts
+++ /dev/null
@@ -1,108 +0,0 @@
-import { describe, expect, it } from "vitest";
-
-import {
- check_expression,
- check_numeric,
- check_qcm,
- parse_numeric,
-} from "../../src/components/math-exercise/answer-check";
-
-describe("check_qcm", () => {
- it("returns true when selected matches correct", () => {
- expect(check_qcm(0, 0)).toBe(true);
- expect(check_qcm(3, 3)).toBe(true);
- });
-
- it("returns false when selected differs from correct", () => {
- expect(check_qcm(0, 1)).toBe(false);
- expect(check_qcm(2, 3)).toBe(false);
- });
-});
-
-describe("parse_numeric", () => {
- it("parses integers", () => {
- expect(parse_numeric("42")).toBe(42);
- expect(parse_numeric("-7")).toBe(-7);
- expect(parse_numeric("0")).toBe(0);
- });
-
- it("parses decimals", () => {
- expect(parse_numeric("3.14")).toBeCloseTo(3.14);
- expect(parse_numeric("-0.5")).toBeCloseTo(-0.5);
- });
-
- it("parses fractions", () => {
- expect(parse_numeric("7/12")).toBeCloseTo(7 / 12);
- expect(parse_numeric("1/3")).toBeCloseTo(1 / 3);
- expect(parse_numeric("-3/4")).toBeCloseTo(-0.75);
- });
-
- it("returns NaN for empty input", () => {
- expect(parse_numeric("")).toBeNaN();
- expect(parse_numeric(" ")).toBeNaN();
- });
-
- it("returns NaN for division by zero", () => {
- expect(parse_numeric("5/0")).toBeNaN();
- });
-
- it("returns NaN for non-numeric input", () => {
- expect(parse_numeric("abc")).toBeNaN();
- });
-});
-
-describe("check_numeric", () => {
- it("accepts correct integers", () => {
- expect(check_numeric("21", 21)).toBe(true);
- expect(check_numeric("-5", -5)).toBe(true);
- });
-
- it("accepts correct decimals within tolerance", () => {
- expect(check_numeric("0.583", 7 / 12, 0.001)).toBe(true);
- });
-
- it("accepts correct fractions", () => {
- expect(check_numeric("7/12", 7 / 12)).toBe(true);
- expect(check_numeric("29/24", 29 / 24)).toBe(true);
- });
-
- it("rejects wrong answers", () => {
- expect(check_numeric("10", 21)).toBe(false);
- expect(check_numeric("1/2", 1 / 3)).toBe(false);
- });
-
- it("rejects empty input", () => {
- expect(check_numeric("", 5)).toBe(false);
- });
-
- it("uses custom tolerance", () => {
- expect(check_numeric("2.66", 8 / 3, 0.01)).toBe(true);
- expect(check_numeric("2.66", 8 / 3, 0.001)).toBe(false);
- });
-});
-
-describe("check_expression", () => {
- it("matches identical expressions", () => {
- expect(check_expression("6x-4", "6x-4")).toBe(true);
- expect(check_expression("x^2+6x+9", "x^2+6x+9")).toBe(true);
- });
-
- it("matches with different whitespace", () => {
- expect(check_expression("6x - 4", "6x-4")).toBe(true);
- });
-
- it("matches algebraically equivalent via point evaluation", () => {
- // (x-3)(x+3) = x^2 - 9
- expect(check_expression("x^2-9", "x^2 - 9")).toBe(true);
- });
-
- it("rejects different expressions", () => {
- expect(check_expression("6x+4", "6x-4")).toBe(false);
- expect(check_expression("x^2", "x^3")).toBe(false);
- });
-
- it("handles simple constant expressions", () => {
- expect(check_expression("3", "3")).toBe(true);
- expect(check_expression("4", "3")).toBe(false);
- });
-});
diff --git a/tests/test_oss_projects.py b/tests/test_oss_projects.py
index 884c2102..cd3e3551 100644
--- a/tests/test_oss_projects.py
+++ b/tests/test_oss_projects.py
@@ -121,7 +121,9 @@ def test_good_license_adds_points(self):
assert score_mit > score_none
def test_recent_update_adds_reason(self):
- repo = self._make_repo(updated_at="2026-02-15T00:00:00Z", topics=[])
+ from datetime import datetime, timedelta, timezone
+ recent = (datetime.now(timezone.utc) - timedelta(days=5)).strftime("%Y-%m-%dT%H:%M:%SZ")
+ repo = self._make_repo(updated_at=recent, topics=[])
skills: set[str] = set()
_, _, reasons = _score_repo(repo, skills)
assert any("30 days" in r for r in reasons)
diff --git a/tests/test_teaching_profiles.py b/tests/test_teaching_profiles.py
index bbd75d4e..e9e8db46 100644
--- a/tests/test_teaching_profiles.py
+++ b/tests/test_teaching_profiles.py
@@ -298,29 +298,31 @@ def test_practice_backward_compatible(self, chat_db):
class TestServiceLayerValidation:
"""Service layer raises ValueError on invalid profile/lens IDs, never falls back silently."""
- def _mock_retriever(self):
- """Create a mock retriever that returns some docs so the function reaches profile/lens validation."""
+ def _mock_explainer_deps(self):
+ """Mock retriever and dossier so explain_concept reaches profile/lens validation."""
mock_doc = type("Doc", (), {
"metadata": {"source_id": "src-1", "title": "Test"},
"page_content": "Test content about the concept.",
})()
mock_retriever = type("Retriever", (), {
- "retrieve_with_timing": lambda self, q: ([mock_doc], {}),
+ "retrieve_with_timing": lambda self, q: ([mock_doc], {"scores": [0.95]}),
})()
- return patch(
- "backend.services.retrieval.get_retriever",
- return_value=mock_retriever,
- ), patch(
- "backend.services.retrieval.get_retriever",
- return_value=mock_retriever,
+ mock_dossier = type("Dossier", (), {
+ "atom_count": 4, "formal_definition": "test", "intuitive_definition": "test",
+ "formulas": [], "examples": [], "key_insights": [], "prerequisite_claims": [],
+ "source_ids": [], "source_count": 0,
+ })()
+ return (
+ patch("backend.services.retrieval.get_retriever", return_value=mock_retriever),
+ patch("backend.services.learning.dossier_builder.get_dossier", return_value=mock_dossier),
)
@pytest.mark.anyio
async def test_explain_raises_on_invalid_profile(self):
from backend.services.learning.concept_explainer import explain_concept
- explain_patch, _ = self._mock_retriever()
- with explain_patch, pytest.raises(ValueError, match="Invalid teaching_profile_id"):
+ retriever_patch, dossier_patch = self._mock_explainer_deps()
+ with retriever_patch, dossier_patch, pytest.raises(ValueError, match="Invalid teaching_profile_id"):
await explain_concept(
concept_id="test",
concept_name="Test",
@@ -332,8 +334,8 @@ async def test_explain_raises_on_invalid_profile(self):
async def test_explain_raises_on_invalid_lens(self):
from backend.services.learning.concept_explainer import explain_concept
- explain_patch, _ = self._mock_retriever()
- with explain_patch, pytest.raises(ValueError, match="Invalid teaching_lens"):
+ retriever_patch, dossier_patch = self._mock_explainer_deps()
+ with retriever_patch, dossier_patch, pytest.raises(ValueError, match="Invalid teaching_lens"):
await explain_concept(
concept_id="test",
concept_name="Test",
@@ -345,8 +347,8 @@ async def test_explain_raises_on_invalid_lens(self):
async def test_practice_raises_on_invalid_profile(self):
from backend.services.learning.practice_generator import generate_practice
- _, practice_patch = self._mock_retriever()
- with practice_patch, pytest.raises(ValueError, match="Invalid teaching_profile_id"):
+ retriever_patch, _ = self._mock_explainer_deps()
+ with retriever_patch, pytest.raises(ValueError, match="Invalid teaching_profile_id"):
await generate_practice(
concept_id="test",
concept_name="Test",
@@ -358,8 +360,8 @@ async def test_practice_raises_on_invalid_profile(self):
async def test_practice_raises_on_invalid_lens(self):
from backend.services.learning.practice_generator import generate_practice
- _, practice_patch = self._mock_retriever()
- with practice_patch, pytest.raises(ValueError, match="Invalid teaching_lens"):
+ retriever_patch, _ = self._mock_explainer_deps()
+ with retriever_patch, pytest.raises(ValueError, match="Invalid teaching_lens"):
await generate_practice(
concept_id="test",
concept_name="Test",