/* Copyright 2026 Marimo. All rights reserved. */ import type { Table } from "@tanstack/react-table"; import { render, screen } from "@testing-library/react"; import { useEffect } from "react"; import { I18nProvider } from "react-aria"; import { describe, expect, it } from "vitest"; import { TooltipProvider } from "@/components/ui/tooltip"; import { SELECT_COLUMN_ID } from "../../types"; import { useCellSelectionReducerActions } from "../atoms"; import { CellSelectionStats } from "../cell-selection-stats"; import { CellSelectionProvider } from "../provider"; import { createMockCell, createMockRow, createMockTable } from "./test-utils"; const TestHarness = ({ table, selectedCellIds, }: { table: Table; selectedCellIds: Set; }) => { const actions = useCellSelectionReducerActions(); useEffect(() => { actions.setSelectedCells(selectedCellIds); }, [actions, selectedCellIds]); return ( ); }; describe("CellSelectionStats", () => { it("should show hint when fewer than 2 cells are selected", () => { const row = createMockRow("0", [ createMockCell("0_0", 10), createMockCell("0_1", 20), ]); const table = createMockTable([row], []); render( , ); expect(screen.getByText("No selection")).toBeInTheDocument(); expect(screen.queryByText(/Count:/)).not.toBeInTheDocument(); }); it("should display Count stat when 2 or more cells are selected", () => { const row = createMockRow("0", [ createMockCell("0_0", 10), createMockCell("0_1", 20), ]); const table = createMockTable([row], []); render( , ); expect(screen.getByText("Count: 2")).toBeInTheDocument(); }); it("should display Sum when selection contains numeric values", () => { const row = createMockRow("0", [ createMockCell("0_0", 10), createMockCell("0_1", 20), ]); const table = createMockTable([row], []); render( , ); expect(screen.getByText("Sum: 30")).toBeInTheDocument(); }); it("should display Average when selection contains numeric values", () => { const row = createMockRow("0", [ createMockCell("0_0", 10), createMockCell("0_1", 20), ]); const table = createMockTable([row], []); render( , ); expect(screen.getByText("Average: 15")).toBeInTheDocument(); }); it("should not display Sum or Average when selection has no numeric values", () => { const row = createMockRow("0", [ createMockCell("0_0", "a"), createMockCell("0_1", "b"), ]); const table = createMockTable([row], []); render( , ); expect(screen.getByText("Count: 2")).toBeInTheDocument(); expect(screen.queryByText(/Sum:/)).not.toBeInTheDocument(); expect(screen.queryByText(/Average:/)).not.toBeInTheDocument(); }); it("should round sum and average to 3 decimal places", () => { const row = createMockRow("0", [ createMockCell("0_0", 0.112_233_441_1), createMockCell("0_1", 0.112_233_441_1), ]); const table = createMockTable([row], []); render( , ); expect(screen.getByText("Sum: 0.224")).toBeInTheDocument(); expect(screen.getByText("Average: 0.112")).toBeInTheDocument(); }); it("should correctly round sum and average to 3 decimal places", () => { const row = createMockRow("0", [ createMockCell("0_0", 0.112_833_443_3), createMockCell("0_1", 0.112_833_443_3), ]); const table = createMockTable([row], []); render( , ); expect(screen.getByText("Sum: 0.226")).toBeInTheDocument(); expect(screen.getByText("Average: 0.113")).toBeInTheDocument(); }); it("should not add extra decimal places to sum and average", () => { const row = createMockRow("0", [ createMockCell("0_0", 0.1), createMockCell("0_1", 0.2), ]); const table = createMockTable([row], []); render( , ); expect(screen.getByText("Sum: 0.3")).toBeInTheDocument(); expect(screen.getByText("Average: 0.15")).toBeInTheDocument(); }); it("should display Sum: 0 and Average: 0 when all selected values are zero", () => { const row = createMockRow("0", [ createMockCell("0_0", 0), createMockCell("0_1", 0), ]); const table = createMockTable([row], []); render( , ); expect(screen.getByText("Count: 2")).toBeInTheDocument(); expect(screen.getByText("Sum: 0")).toBeInTheDocument(); expect(screen.getByText("Average: 0")).toBeInTheDocument(); }); it("should show hint instead of stats when exactly one cell is selected", () => { const row = createMockRow("0", [ createMockCell("0_0", 10), createMockCell("0_1", 20), ]); const table = createMockTable([row], []); render( , ); expect(screen.getByText("No selection")).toBeInTheDocument(); expect(screen.queryByText(/Count:/)).not.toBeInTheDocument(); }); it("should display Sum and Average for negative numbers", () => { const row = createMockRow("0", [ createMockCell("0_0", -10), createMockCell("0_1", -20), ]); const table = createMockTable([row], []); render( , ); expect(screen.getByText("Count: 2")).toBeInTheDocument(); expect(screen.getByText("Sum: -30")).toBeInTheDocument(); expect(screen.getByText("Average: -15")).toBeInTheDocument(); }); it("should display Sum and Average for number strings", () => { const row = createMockRow("0", [ createMockCell("0_0", "42"), createMockCell("0_1", "3.14"), ]); const table = createMockTable([row], []); render( , ); expect(screen.getByText("Count: 2")).toBeInTheDocument(); expect(screen.getByText("Sum: 45.14")).toBeInTheDocument(); expect(screen.getByText("Average: 22.57")).toBeInTheDocument(); }); it("should skip NaN and Infinity and show stats for finite values only", () => { const row = createMockRow("0", [ createMockCell("0_0", 5), createMockCell("0_1", Number.NaN), createMockCell("0_2", Infinity), ]); const table = createMockTable([row], []); render( , ); expect(screen.getByText("Count: 3")).toBeInTheDocument(); expect(screen.getByText("Sum: 5")).toBeInTheDocument(); expect(screen.getByText("Average: 5")).toBeInTheDocument(); }); it("should exclude booleans from Sum and Average", () => { const row = createMockRow("0", [ createMockCell("0_0", 10), createMockCell("0_1", true), createMockCell("0_2", false), ]); const table = createMockTable([row], []); render( , ); expect(screen.getByText("Count: 3")).toBeInTheDocument(); expect(screen.getByText("Sum: 10")).toBeInTheDocument(); expect(screen.getByText("Average: 10")).toBeInTheDocument(); }); it("should ignore select checkbox column for Count, Sum and Average", () => { const selectCellId = `0_${SELECT_COLUMN_ID}`; const row = createMockRow("0", [ createMockCell(selectCellId, 10), createMockCell("0_0", 20), createMockCell("0_1", 30), ]); const table = createMockTable([row], []); render( , ); expect(screen.getByText("Count: 2")).toBeInTheDocument(); expect(screen.getByText("Sum: 50")).toBeInTheDocument(); expect(screen.getByText("Average: 25")).toBeInTheDocument(); }); it("should show hint when only checkbox column cells are selected", () => { const selectCellId1 = `0_${SELECT_COLUMN_ID}`; const selectCellId2 = `1_${SELECT_COLUMN_ID}`; const row1 = createMockRow("0", [createMockCell(selectCellId1, true)]); const row2 = createMockRow("1", [createMockCell(selectCellId2, false)]); const table = createMockTable([row1, row2], []); render( , ); expect(screen.getByText("No selection")).toBeInTheDocument(); expect(screen.queryByText(/Count:/)).not.toBeInTheDocument(); }); it("should show Sum and Average only for numeric cells when selection has mixed types", () => { const row = createMockRow("0", [ createMockCell("0_0", 10), createMockCell("0_1", "abc"), createMockCell("0_2", undefined), ]); const table = createMockTable([row], []); render( , ); expect(screen.getByText("Count: 3")).toBeInTheDocument(); expect(screen.getByText("Sum: 10")).toBeInTheDocument(); expect(screen.getByText("Average: 10")).toBeInTheDocument(); }); it("should display stats for multiple numeric cells across rows", () => { const row1 = createMockRow("0", [ createMockCell("0_0", 1), createMockCell("0_1", 2), ]); const row2 = createMockRow("1", [ createMockCell("1_0", 3), createMockCell("1_1", 4), ]); const table = createMockTable([row1, row2], []); render( , ); expect(screen.getByText("Count: 4")).toBeInTheDocument(); expect(screen.getByText("Sum: 10")).toBeInTheDocument(); expect(screen.getByText("Average: 2.5")).toBeInTheDocument(); }); });