/* Copyright 2026 Marimo. All rights reserved. */
import type { Column } from "@tanstack/react-table";
import { fireEvent, render } from "@testing-library/react";
import { I18nProvider } from "react-aria";
import { describe, expect, it, test, vi } from "vitest";
import { TooltipProvider } from "@/components/ui/tooltip";
import { parseContent } from "@/utils/url-parser";
import {
generateColumns,
inferFieldTypes,
LocaleNumber,
renderCellValue,
} from "../columns";
import { getMimeValues, isMimeValue, MimeCell } from "../mime-cell";
import type { FieldTypesWithExternalType } from "../types";
import { uniformSample } from "../uniformSample";
import { UrlDetector } from "../url-detector";
test("uniformSample", () => {
const items = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J"];
expect(uniformSample(items, 2)).toMatchInlineSnapshot(`
[
"A",
"J",
]
`);
expect(uniformSample(items, 4)).toMatchInlineSnapshot(`
[
"A",
"C",
"F",
"J",
]
`);
expect(uniformSample(items, 100)).toBe(items);
});
test("UrlDetector renders URLs as hyperlinks", () => {
const text = "Check this link: https://example.com";
const { container } = render();
const link = container.querySelector("a");
expect(link).toBeTruthy();
expect(link?.href).toBe("https://example.com/");
});
test("inferFieldTypes", () => {
const data = [
{
a: 1,
b: "foo",
c: null,
d: { mime: "text/csv" },
e: [1, 2, 3],
f: true,
g: false,
h: new Date(),
},
];
const fieldTypes = inferFieldTypes(data);
expect(fieldTypes).toMatchInlineSnapshot(`
[
[
"a",
[
"number",
"number",
],
],
[
"b",
[
"string",
"string",
],
],
[
"c",
[
"unknown",
"object",
],
],
[
"d",
[
"unknown",
"object",
],
],
[
"e",
[
"unknown",
"object",
],
],
[
"f",
[
"boolean",
"boolean",
],
],
[
"g",
[
"boolean",
"boolean",
],
],
[
"h",
[
"datetime",
"datetime",
],
],
]
`);
});
test("inferFieldTypes with nulls", () => {
const data = [{ a: 1, b: null }];
const fieldTypes = inferFieldTypes(data);
expect(fieldTypes).toMatchInlineSnapshot(`
[
[
"a",
[
"number",
"number",
],
],
[
"b",
[
"unknown",
"object",
],
],
]
`);
});
test("inferFieldTypes with mimetypes", () => {
const data = [{ a: { mime: "text/csv" }, b: { mime: "image/png" } }];
const fieldTypes = inferFieldTypes(data);
expect(fieldTypes).toMatchInlineSnapshot(`
[
[
"a",
[
"unknown",
"object",
],
],
[
"b",
[
"unknown",
"object",
],
],
]
`);
});
describe("generateColumns", () => {
const fieldTypes: FieldTypesWithExternalType = [
["name", ["string", "text"]],
["age", ["number", "integer"]],
];
it("should generate columns with row headers", () => {
const columns = generateColumns({
rowHeaders: [["name", ["string", "text"]]],
selection: null,
fieldTypes,
});
expect(columns).toHaveLength(3);
expect(columns[0].id).toBe("name");
expect(columns[0].meta?.rowHeader).toBe(true);
expect(columns[0].enableSorting).toBe(true);
});
it("should generate columns with nameless row headers", () => {
const columns = generateColumns({
rowHeaders: [["", ["string", "text"]]],
selection: null,
fieldTypes,
});
expect(columns).toHaveLength(3);
expect(columns[0].id).toMatchInlineSnapshot(`"__m_column__0"`);
expect(columns[0].meta?.rowHeader).toBe(true);
expect(columns[0].enableSorting).toBe(false);
});
it("should include selection column for multi selection", () => {
const columns = generateColumns({
rowHeaders: [],
selection: "multi",
fieldTypes,
});
expect(columns[0].id).toBe("__select__");
expect(columns[0].enableSorting).toBe(false);
});
it("should generate columns with correct meta data", () => {
const columns = generateColumns({
rowHeaders: [],
selection: null,
fieldTypes,
});
expect(columns.length).toBe(2);
expect(columns[0].meta?.dataType).toBe("string");
expect(columns[1].meta?.dataType).toBe("number");
});
it("should auto right-align numeric columns", () => {
const columns = generateColumns({
rowHeaders: [],
selection: null,
fieldTypes,
});
// "age" is a number column — should auto right-align
// oxlint-disable-next-line typescript/no-explicit-any
const cell = (columns[1].cell as any)({
column: {
columnDef: columns[1],
},
renderValue: () => 25,
getValue: () => 25,
});
expect(cell?.props.className).toContain("text-right");
// "name" is a string column — should remain left-aligned
// oxlint-disable-next-line typescript/no-explicit-any
const nameCell = (columns[0].cell as any)({
column: {
columnDef: columns[0],
},
renderValue: () => "John",
getValue: () => "John",
});
expect(nameCell?.props.className).not.toContain("text-right");
});
it("should respect explicit textJustifyColumns over auto alignment", () => {
const columns = generateColumns({
rowHeaders: [],
selection: null,
fieldTypes,
textJustifyColumns: { age: "left" },
});
// "age" is numeric but explicitly set to left
// oxlint-disable-next-line typescript/no-explicit-any
const cell = (columns[1].cell as any)({
column: {
columnDef: columns[1],
},
renderValue: () => 25,
getValue: () => 25,
});
expect(cell?.props.className).not.toContain("text-right");
});
it("should set minFractionDigits from fractionDigitsByColumn", () => {
const numericFieldTypes: FieldTypesWithExternalType = [
["price", ["number", "float64"]],
["count", ["integer", "int64"]],
];
const columns = generateColumns({
rowHeaders: [],
selection: null,
fieldTypes: numericFieldTypes,
fractionDigitsByColumn: { price: 2 },
});
// price has 2 fraction digits
expect(columns[0].meta?.minFractionDigits).toBe(2);
// count not in fractionDigitsByColumn
expect(columns[1].meta?.minFractionDigits).toBeUndefined();
});
it("should handle text justification and wrapping", () => {
const columns = generateColumns({
rowHeaders: [],
selection: null,
fieldTypes,
textJustifyColumns: { name: "center" },
wrappedColumns: ["age"],
});
// Assuming getCellStyleClass is a function that returns a class name
// oxlint-disable-next-line typescript/no-explicit-any
const cell = (columns[0].cell as any)({
column: {
columnDef: columns[0],
},
renderValue: () => "John",
getValue: () => "John",
});
expect(cell?.props.className).toContain("center");
});
it("should align column headers to match textJustifyColumns", () => {
const columns = generateColumns({
rowHeaders: [],
selection: null,
fieldTypes,
textJustifyColumns: { name: "right", age: "center" },
});
const mockColumn = (col: (typeof columns)[number]) => ({
id: col.id,
getCanSort: () => true,
getCanFilter: () => false,
getIsSorted: () => false,
getSortIndex: () => -1,
getFilterValue: () => undefined,
columnDef: { meta: col.meta },
});
// Right-justified column: outer summary wrapper aligns to end, and the
// header row uses flex-row-reverse so the title sits at the right edge.
const { container: rightContainer } = render(
{/* oxlint-disable-next-line typescript/no-explicit-any */}
{(columns[0].header as any)({ column: mockColumn(columns[0]) })}
,
);
expect(
rightContainer.querySelector("[data-testid='data-table-sort-button']"),
).toBeTruthy();
expect(
rightContainer.querySelector(
"[data-testid='data-table-column-menu-button']",
),
).toBeTruthy();
expect(rightContainer.firstElementChild?.className).toContain("items-end");
expect(rightContainer.querySelector(".flex-row-reverse")).toBeTruthy();
// Center-justified column: outer summary wrapper centers; header row
// keeps natural order.
const { container: centerContainer } = render(
{/* oxlint-disable-next-line typescript/no-explicit-any */}
{(columns[1].header as any)({ column: mockColumn(columns[1]) })}
,
);
expect(
centerContainer.querySelector("[data-testid='data-table-sort-button']"),
).toBeTruthy();
expect(
centerContainer.querySelector(
"[data-testid='data-table-column-menu-button']",
),
).toBeTruthy();
expect(centerContainer.firstElementChild?.className).toContain(
"items-center",
);
expect(centerContainer.querySelector(".flex-row-reverse")).toBeNull();
});
it("should not auto-align numeric column headers without explicit override", () => {
const columns = generateColumns({
rowHeaders: [],
selection: null,
fieldTypes,
});
const mockColumn = (col: (typeof columns)[number]) => ({
id: col.id,
getCanSort: () => true,
getCanFilter: () => false,
getIsSorted: () => false,
getSortIndex: () => -1,
getFilterValue: () => undefined,
columnDef: { meta: col.meta },
});
// "age" is numeric: cells auto right-align, but the header stays
// left-aligned unless the user explicitly opts in via text_justify_columns.
const { container } = render(
{/* oxlint-disable-next-line typescript/no-explicit-any */}
{(columns[1].header as any)({ column: mockColumn(columns[1]) })}
,
);
expect(container.firstElementChild?.className).not.toContain("items-end");
expect(container.querySelector(".flex-row-reverse")).toBeNull();
});
it("should cycle sort button through asc, desc, and clear on clicks", () => {
const columns = generateColumns({
rowHeaders: [],
selection: null,
fieldTypes,
});
const toggleSorting = vi.fn();
const clearSorting = vi.fn();
let sortDirection: false | "asc" | "desc" = false;
const mockColumn = (col: (typeof columns)[number]) => ({
id: col.id,
getCanSort: () => true,
getCanFilter: () => false,
getIsSorted: () => sortDirection,
getSortIndex: () => -1,
getFilterValue: () => undefined,
toggleSorting,
clearSorting,
columnDef: { meta: col.meta },
});
const mock = mockColumn(columns[0]);
const { container, rerender } = render(
{/* oxlint-disable-next-line typescript/no-explicit-any */}
{(columns[0].header as any)({ column: mock })}
,
);
const sortButton = container.querySelector(
"[data-testid='data-table-sort-button']",
);
expect(sortButton).toBeTruthy();
// first click unsorted > asc
fireEvent.click(sortButton!);
expect(toggleSorting).toHaveBeenCalledWith(false, true);
// Simulate asc state and re-render
sortDirection = "asc";
rerender(
{/* oxlint-disable-next-line typescript/no-explicit-any */}
{(columns[0].header as any)({ column: mock })}
,
);
// second click asc >dsc
fireEvent.click(sortButton!);
expect(toggleSorting).toHaveBeenCalledWith(true, true);
// Simulate desc state and re-render
sortDirection = "desc";
rerender(
{/* oxlint-disable-next-line typescript/no-explicit-any */}
{(columns[0].header as any)({ column: mock })}
,
);
// third click back to unsorted
fireEvent.click(sortButton!);
expect(clearSorting).toHaveBeenCalled();
});
it("should not include index column if it exists", () => {
const columns = generateColumns({
rowHeaders: [],
selection: null,
fieldTypes: [...fieldTypes, ["_marimo_row_id", ["string", "text"]]],
});
expect(columns).toHaveLength(2);
expect(columns[0].id).toBe("name");
expect(columns[1].id).toBe("age");
});
it("should render header with tooltip when headerTooltip is provided", () => {
const columns = generateColumns({
rowHeaders: [],
selection: null,
fieldTypes,
headerTooltip: { name: "Custom Name Tooltip" },
});
// Get the header function for the first column
const headerFunction = columns[0].header;
expect(headerFunction).toBeTypeOf("function");
const mockColumn = {
id: "name",
getCanSort: () => false,
getCanFilter: () => false,
columnDef: {
meta: {
dtype: "string",
dataType: "string",
},
},
};
const { container } = render(
{/* @ts-expect-error: mock column and header function */}
{headerFunction({ column: mockColumn })}
,
);
expect(container.textContent).toContain("name");
// The tooltip functionality is tested by verifying that the header renders correctly
// when headerTooltip is provided.
expect(container.firstChild).toBeTruthy();
});
});
describe("MimeCell", () => {
it("renders with correct mime data", () => {
const value = { mimetype: "text/plain", data: "Hello World" };
const { container } = render();
expect(container.textContent).toContain("Hello World");
});
});
describe("isMimeValue", () => {
it("should return true for valid MimeValue objects", () => {
const value = { mimetype: "text/plain", data: "test data" };
expect(isMimeValue(value)).toBe(true);
});
it("should return false for null", () => {
expect(isMimeValue(null)).toBe(false);
});
it("should return false for primitive values", () => {
expect(isMimeValue("string")).toBe(false);
expect(isMimeValue(123)).toBe(false);
expect(isMimeValue(true)).toBe(false);
});
it("should return false for objects missing required properties", () => {
expect(isMimeValue({})).toBe(false);
expect(isMimeValue({ mimetype: "text/plain" })).toBe(false);
expect(isMimeValue({ data: "test data" })).toBe(false);
});
});
describe("getMimeValues", () => {
it("should return array with single MimeValue when input is a MimeValue", () => {
const value = { mimetype: "text/plain", data: "test data" };
expect(getMimeValues(value)).toEqual([value]);
});
it("should return array with MimeValue when input has serialized_mime_bundle", () => {
const mimeValue = { mimetype: "text/plain", data: "test data" };
const value = { serialized_mime_bundle: mimeValue };
expect(getMimeValues(value)).toEqual([mimeValue]);
});
it("should return array with MimeValue when input has _serialized_mime_bundle", () => {
const mimeValue = { mimetype: "text/plain", data: "test data" };
const value = { _serialized_mime_bundle: mimeValue };
expect(getMimeValues(value)).toEqual([mimeValue]);
});
it("should return array of MimeValues when input is an array of MimeValues", () => {
const values = [
{ mimetype: "text/plain", data: "test data 1" },
{ mimetype: "text/html", data: "
test data 2
" },
];
expect(getMimeValues(values)).toEqual(values);
});
it("should return undefined for null input", () => {
expect(getMimeValues(null)).toBeUndefined();
});
it("should return undefined for primitive values", () => {
expect(getMimeValues("string")).toBeUndefined();
expect(getMimeValues(123)).toBeUndefined();
expect(getMimeValues(true)).toBeUndefined();
});
it("should return undefined for objects that don't match any pattern", () => {
expect(getMimeValues({})).toBeUndefined();
expect(getMimeValues({ random: "property" })).toBeUndefined();
});
it("should return undefined for invalid serialized_mime_bundle", () => {
expect(
getMimeValues({ serialized_mime_bundle: "not a mime value" }),
).toBeUndefined();
});
it("should return undefined for invalid _serialized_mime_bundle", () => {
expect(
getMimeValues({ _serialized_mime_bundle: "not a mime value" }),
).toBeUndefined();
});
it("should return undefined for array with non-MimeValue items", () => {
const values = [
{ mimetype: "text/plain", data: "test data" },
"not a mime value",
];
expect(getMimeValues(values)).toBeUndefined();
});
});
describe("LocaleNumber", () => {
it("should format numbers correctly for en-US locale", () => {
const { container } = render(
,
);
expect(container.textContent).toMatchInlineSnapshot(`"1,234,567.89"`);
});
it("should format numbers correctly for de-DE locale", () => {
const { container } = render(
,
);
expect(container.textContent).toMatchInlineSnapshot(`"1.234.567,89"`);
});
it("should format integers correctly", () => {
const { container } = render(
,
);
expect(container.textContent).toMatchInlineSnapshot(`"1,000"`);
});
it("should format zero correctly", () => {
const { container } = render(
,
);
expect(container.textContent).toMatchInlineSnapshot(`"0"`);
});
it("should format negative numbers correctly", () => {
const { container } = render(
,
);
expect(container.textContent).toMatchInlineSnapshot(`"-1,234.56"`);
});
it("should format small decimal numbers correctly", () => {
const { container } = render(
,
);
expect(container.textContent).toMatchInlineSnapshot(`"0.123456789"`);
});
it("should format large numbers correctly", () => {
const { container } = render(
,
);
expect(container.textContent).toMatchInlineSnapshot(`"999,999,999.99"`);
});
it("should format numbers correctly for fr-FR locale", () => {
const { container } = render(
,
);
// oxlint-disable-next-line no-irregular-whitespace
expect(container.textContent).toMatchInlineSnapshot(`"1 234 567,89"`);
});
it("should format numbers correctly for ja-JP locale", () => {
const { container } = render(
,
);
expect(container.textContent).toMatchInlineSnapshot(`"1,234,567.89"`);
});
it("should respect maximumFractionDigits based on locale", () => {
// Test with a number that has many decimal places
const { container } = render(
,
);
expect(container.textContent).toMatchInlineSnapshot(`"1.1234567890123457"`);
});
it("should handle very large numbers", () => {
const { container } = render(
,
);
expect(container.textContent).toMatchInlineSnapshot(
`"123,456,789,012,345.67"`,
);
});
it("should handle Infinity", () => {
const { container } = render(
,
);
expect(container.textContent).toMatchInlineSnapshot(`"∞"`);
});
it("should handle negative Infinity", () => {
const { container } = render(
,
);
expect(container.textContent).toMatchInlineSnapshot(`"-∞"`);
});
it("should handle NaN", () => {
const { container } = render(
,
);
expect(container.textContent).toMatchInlineSnapshot(`"NaN"`);
});
it("should handle numbers with scientific notation", () => {
const { container } = render(
,
);
expect(container.textContent).toMatchInlineSnapshot(`"10,000,000,000"`);
});
it("should pad decimals with minFractionDigits", () => {
const { container } = render(
,
);
expect(container.textContent).toMatchInlineSnapshot(`"42.00"`);
});
it("should pad to minFractionDigits for numbers with fewer decimals", () => {
const { container } = render(
,
);
expect(container.textContent).toMatchInlineSnapshot(`"1,234.500"`);
});
it("should not truncate decimals beyond minFractionDigits", () => {
const { container } = render(
,
);
expect(container.textContent).toMatchInlineSnapshot(`"1.23456"`);
});
});
describe("renderCellValue with string + edge whitespace", () => {
const createMockStringColumn = () =>
({
id: "desc",
columnDef: {
meta: {
dataType: "string" as const,
dtype: "object",
},
},
getColumnFormatting: () => undefined,
getColumnWrapping: () => undefined,
applyColumnFormatting: (value: unknown) => value,
}) as unknown as Column;
const renderWithProviders = (node: React.ReactNode) =>
render(
{node}
,
);
it("renders edge whitespace markers and still detects the URL in the middle", () => {
const mockColumn = createMockStringColumn();
const value = " https://example.com ";
const result = renderCellValue({
column: mockColumn,
renderValue: () => value,
getValue: () => value,
selectCell: undefined,
cellStyles: "",
});
const { container } = renderWithProviders(result);
// URL detection runs on the middle, so the anchor is still rendered.
const link = container.querySelector("a");
expect(link).toBeTruthy();
expect(link?.href).toBe("https://example.com/");
// The link text is exactly the URL — no leading/trailing whitespace
// leaked into the anchor.
expect(link?.textContent).toBe("https://example.com");
// Both edge-whitespace marker containers are present and render
// visible glyphs (U+2423 "open box" for regular spaces).
const markerSpans = container.querySelectorAll(
"span[aria-label$='space'], span[aria-label$='spaces']",
);
expect(markerSpans.length).toBeGreaterThanOrEqual(2);
expect(container.textContent?.includes("\u2423")).toBe(true);
});
it("does not split URLs on whitespace padding (regression)", () => {
const mockColumn = createMockStringColumn();
// Trailing whitespace would previously be consumed by the URL regex
// (\S+). We render the middle only through parseContent to avoid that.
const value = "go here: https://example.com/path ";
const result = renderCellValue({
column: mockColumn,
renderValue: () => value,
getValue: () => value,
selectCell: undefined,
cellStyles: "",
});
const { container } = renderWithProviders(result);
const link = container.querySelector("a");
expect(link).toBeTruthy();
// href is URL-normalized by the browser — should not include the
// trailing spaces as part of the URL path.
expect(link?.href).toBe("https://example.com/path");
expect(link?.textContent?.trimEnd()).toBe("https://example.com/path");
});
it("renders no marker span when the string has no edge whitespace", () => {
const mockColumn = createMockStringColumn();
const value = "https://example.com";
const result = renderCellValue({
column: mockColumn,
renderValue: () => value,
getValue: () => value,
selectCell: undefined,
cellStyles: "",
});
const { container } = renderWithProviders(result);
// No marker glyph leaked through.
expect(container.textContent?.includes("\u2423")).toBe(false);
// And no WhitespaceMarkers wrapper was rendered at all. The component
// returns null for empty strings, and always sets an aria-label
// generated by `describeWhitespace` when it does render (e.g.
// "1 space", "2 spaces", "1 tab", "1 unicode whitespace").
// Matching the "space"/"spaces" suffix is enough here because the
// test value contains no whitespace, so no marker of any kind should
// appear.
const markerSpans = container.querySelectorAll(
"span[aria-label$='space'], span[aria-label$='spaces']",
);
expect(markerSpans.length).toBe(0);
});
});
describe("renderCellValue with boolean values", () => {
const createMockColumn = () =>
({
id: "active",
columnDef: {
meta: {
dataType: "boolean" as const,
dtype: "bool",
},
},
getColumnFormatting: () => undefined,
getColumnWrapping: () => undefined,
applyColumnFormatting: (value: unknown) => value,
}) as unknown as Column;
it("should render true as True", () => {
const mockColumn = createMockColumn();
const result = renderCellValue({
column: mockColumn,
renderValue: () => true,
getValue: () => true,
selectCell: undefined,
cellStyles: "",
});
const { container } = render(result);
expect(container.textContent).toBe("True");
});
it("should render false as False", () => {
const mockColumn = createMockColumn();
const result = renderCellValue({
column: mockColumn,
renderValue: () => false,
getValue: () => false,
selectCell: undefined,
cellStyles: "",
});
const { container } = render(result);
expect(container.textContent).toBe("False");
});
});
describe("renderCellValue with datetime values", () => {
const createMockColumn = () =>
({
id: "created",
columnDef: {
meta: {
dataType: "datetime" as const,
dtype: "datetime64[ns]",
},
},
getColumnFormatting: () => undefined,
getColumnWrapping: () => undefined,
applyColumnFormatting: (value: unknown) => value,
}) as unknown as Column;
it("should handle null, empty string, and 'null' string datetime values without throwing RangeError", () => {
const mockColumn = createMockColumn();
// Test null, empty string, and "null" string (as they might come from SQL)
const nullishValues = [null, "", "null"];
nullishValues.forEach((value) => {
const result = renderCellValue({
column: mockColumn,
renderValue: () => value,
getValue: () => value,
selectCell: undefined,
cellStyles: "",
});
expect(result).toBeDefined();
// Should not throw RangeError when rendering
expect(() => {
render(
{result}
,
);
}).not.toThrow();
});
});
it("should handle invalid date strings without throwing RangeError", () => {
const mockColumn = createMockColumn();
const invalidDates = [
"invalid-date",
"2024-13-45", // Invalid month/day
"not-a-date",
"2024-06-14 12:34:20.665332",
];
invalidDates.forEach((invalidDate) => {
const result = renderCellValue({
column: mockColumn,
renderValue: () => invalidDate,
getValue: () => invalidDate,
selectCell: undefined,
cellStyles: "",
});
expect(result).toBeDefined();
// Should not throw RangeError when rendering
expect(() => {
render(
{result}
,
);
}).not.toThrow();
});
});
it("should still render valid datetime strings correctly", () => {
const mockColumn = createMockColumn();
const validDates = [
"2024-06-14T12:34:20Z",
"2024-06-14 12:34:20",
"2024-06-14",
];
validDates.forEach((validDate) => {
const result = renderCellValue({
column: mockColumn,
renderValue: () => validDate,
getValue: () => validDate,
selectCell: undefined,
cellStyles: "",
});
expect(result).toBeDefined();
// Should render as a date component, not as plain string
expect(result).not.toBeNull();
// Should not throw when rendering
expect(() => {
render(
{result}
,
);
}).not.toThrow();
});
});
it("should handle invalid Date instances without throwing RangeError", () => {
const mockColumn = createMockColumn();
const invalidDate = new Date("invalid");
const result = renderCellValue({
column: mockColumn,
renderValue: () => invalidDate,
getValue: () => invalidDate,
selectCell: undefined,
cellStyles: "",
});
expect(result).toBeDefined();
// Should not throw RangeError when rendering
expect(() => {
render(
{result}
,
);
}).not.toThrow();
});
it("should handle mixed valid and null datetime values in a column", () => {
const mockColumn = createMockColumn();
const values = [
"2024-06-14T12:34:20Z", // Valid
null,
"2024-06-15T12:34:20Z", // Valid
"",
"2024-06-16T12:34:20Z", // Valid
];
values.forEach((value) => {
const result = renderCellValue({
column: mockColumn,
renderValue: () => value,
getValue: () => value,
selectCell: undefined,
cellStyles: "",
});
expect(result).toBeDefined();
// Should not throw RangeError when rendering
expect(() => {
render(
{result}
,
);
}).not.toThrow();
});
});
});