/* eslint-disable sonarjs/no-duplicate-string */
import * as React from "react";
import { render, fireEvent, screen, act, cleanup } from "@testing-library/react";
import {
DataEditor,
type DataEditorProps,
type GridCell,
GridCellKind,
type GridSelection,
type Item,
} from "../src/index.js";
import type { DataEditorRef } from "../src/data-editor/data-editor.js";
import { CompactSelection } from "../src/internal/data-grid/data-grid-types.js";
import { vi, expect, describe, test, beforeEach, afterEach } from "vitest";
const makeCell = (cell: Item): GridCell => {
const [col, row] = cell;
switch (col) {
case 0: {
return {
kind: GridCellKind.RowID,
allowOverlay: false,
data: `Data: ${col}, ${row}`,
};
}
case 3: {
return {
kind: GridCellKind.Number,
allowOverlay: true,
data: 10,
displayData: `${row}`,
};
}
case 4: {
return {
kind: GridCellKind.Drilldown,
allowOverlay: false,
data: [
{
img: "https://cdn.pixabay.com/photo/2017/02/20/18/03/cat-2083492_1280.jpg",
text: "Foobar",
},
],
};
}
case 5: {
return {
kind: GridCellKind.Protected,
allowOverlay: false,
};
}
case 6: {
return {
kind: GridCellKind.Bubble,
allowOverlay: false,
data: ["Foobar"],
};
}
case 7: {
return {
kind: GridCellKind.Boolean,
allowOverlay: false,
data: row % 2 === 0,
readonly: false,
};
}
case 8: {
return {
kind: GridCellKind.Text,
allowOverlay: true,
data: `Data: ${col}, ${row}`,
displayData: `שלום ${col}, ${row}`,
};
}
case 9: {
return {
kind: GridCellKind.Markdown,
allowOverlay: true,
data: `# Header: ${col}, ${row}`,
};
}
// No default
}
return {
kind: GridCellKind.Text,
allowOverlay: true,
data: `Data: ${col}, ${row}`,
displayData: `${col}, ${row}`,
};
};
const basicProps: DataEditorProps = {
columns: [
{
title: "A",
width: 150,
icon: "headerRowID",
},
{
title: "B",
width: 160,
icon: "headerCode",
},
{
title: "C",
width: 170,
icon: "headerNumber",
},
{
title: "D",
width: 180,
icon: "headerString",
},
{
title: "E",
width: 40,
icon: "headerBoolean",
},
{
title: "F",
width: 50,
icon: "headerUri",
},
{
title: "G",
width: 60,
icon: "headerVideoUri",
},
{
title: "H",
width: 70,
icon: "headerEmoji",
},
{
title: "I",
width: 80,
icon: "headerImage",
},
{
title: "J",
width: 90,
icon: "headerPhone",
},
],
getCellContent: makeCell,
getCellsForSelection: true,
groupHeaderHeight: 32,
headerHeight: 36,
rowHeight: 32,
onRowAppended: () => undefined,
trailingRowOptions: {
hint: "New row",
sticky: true,
tint: true,
},
rowMarkers: "both",
rowMarkerWidth: 50,
rows: 1000,
};
function prep(resetTimers: boolean = true) {
const scroller = document.getElementsByClassName("dvn-scroller").item(0);
if (scroller !== null) {
vi.spyOn(scroller, "clientWidth", "get").mockImplementation(() => 1000);
vi.spyOn(scroller, "offsetWidth" as any, "get").mockImplementation(() => 1000);
vi.spyOn(scroller, "clientHeight", "get").mockImplementation(() => 1000);
vi.spyOn(scroller, "offsetHeight" as any, "get").mockImplementation(() => 1000);
}
act(() => {
vi.runAllTimers();
});
if (resetTimers) {
vi.useRealTimers();
}
return scroller;
}
const Context: React.FC = p => {
return (
<>
{p.children}
>
);
};
// eslint-disable-next-line react/display-name
const EventedDataEditor = React.forwardRef((p, ref) => {
const [sel, setSel] = React.useState(p.gridSelection);
const [extraRows, setExtraRows] = React.useState(0);
const onGridSelectionChange = React.useCallback(
(s: GridSelection) => {
setSel(s);
p.onGridSelectionChange?.(s);
},
[p]
);
const onRowAppened = React.useCallback(() => {
setExtraRows(cv => cv + 1);
void p.onRowAppended?.();
}, [p]);
return (
);
});
describe("data-editor-input", () => {
vi.mock("../src/common/resize-detector", () => {
return {
useResizeDetector: () => ({ ref: undefined, width: 1000, height: 1000 }),
};
});
beforeEach(() => {
Element.prototype.scrollTo = vi.fn() as any;
Element.prototype.scrollBy = vi.fn() as any;
Object.assign(navigator, {
clipboard: {
writeText: vi.fn(() => Promise.resolve()),
readText: vi.fn(() =>
Promise.resolve(`Sunday Dogs https://google.com
Monday Cats https://google.com
Tuesday Turtles https://google.com
Wednesday Bears https://google.com
Thursday "L ions" https://google.com
Friday Pigs https://google.com
Saturday "Turkeys and some ""quotes"" and
a new line char ""more quotes"" plus a tab ." https://google.com`)
),
},
});
Element.prototype.getBoundingClientRect = () => ({
bottom: 1000,
height: 1000,
left: 0,
right: 1000,
top: 0,
width: 1000,
x: 0,
y: 0,
toJSON: () => "",
});
Image.prototype.decode = vi.fn();
});
afterEach(() => {
cleanup();
});
test("Select range - single-cell", async () => {
const spy = vi.fn();
vi.useFakeTimers();
render(, {
wrapper: Context,
});
prep();
const canvas = screen.getByTestId("data-grid-canvas");
fireEvent.mouseDown(canvas, {
clientX: 350,
clientY: 36 + 32 * 2 + 16,
});
fireEvent.mouseMove(canvas, {
clientX: 650,
clientY: 36 + 32 * 12 + 16,
});
fireEvent.mouseUp(canvas, {
clientX: 650,
clientY: 36 + 32 * 12 + 16,
});
expect(spy).toBeCalledWith(
expect.objectContaining({
current: {
cell: [1, 2],
range: { height: 1, width: 1, x: 1, y: 2 },
rangeStack: [],
},
})
);
});
test("Select range - single-cell with row/column blending", async () => {
const spy = vi.fn();
vi.useFakeTimers();
render(
,
{
wrapper: Context,
}
);
prep();
const canvas = screen.getByTestId("data-grid-canvas");
fireEvent.mouseDown(canvas, {
ctrlKey: true,
clientX: 350,
clientY: 36 + 32 * 2 + 16,
});
fireEvent.mouseMove(canvas, {
ctrlKey: true,
clientX: 650,
clientY: 36 + 32 * 12 + 16,
});
fireEvent.mouseUp(canvas, {
ctrlKey: true,
clientX: 650,
clientY: 36 + 32 * 12 + 16,
});
expect(spy).toBeCalledWith({
current: {
cell: [1, 2],
range: { height: 1, width: 1, x: 1, y: 2 },
rangeStack: [],
},
columns: CompactSelection.fromSingleSelection(2),
rows: CompactSelection.fromSingleSelection(3),
});
});
test("Select row - single-cell with row blending", async () => {
const spy = vi.fn();
vi.useFakeTimers();
render(
,
{
wrapper: Context,
}
);
prep();
const canvas = screen.getByTestId("data-grid-canvas");
fireEvent.mouseDown(canvas, {
ctrlKey: true,
clientX: 20,
clientY: 36 + 32 * 3 + 16,
});
fireEvent.mouseMove(canvas, {
ctrlKey: true,
clientX: 20,
clientY: 36 + 32 * 3 + 16,
});
fireEvent.mouseUp(canvas, {
ctrlKey: true,
clientX: 20,
clientY: 36 + 32 * 3 + 16,
});
expect(spy).toBeCalledWith({
current: {
cell: [1, 2],
range: { height: 1, width: 1, x: 1, y: 2 },
rangeStack: [],
},
columns: CompactSelection.empty(),
rows: CompactSelection.fromSingleSelection(3),
});
});
test("Select row - single-cell/single-row with row blending", async () => {
const spy = vi.fn();
vi.useFakeTimers();
render(
,
{
wrapper: Context,
}
);
prep();
const canvas = screen.getByTestId("data-grid-canvas");
fireEvent.mouseDown(canvas, {
ctrlKey: true,
clientX: 20,
clientY: 36 + 32 * 3 + 16,
});
fireEvent.mouseMove(canvas, {
ctrlKey: true,
clientX: 20,
clientY: 36 + 32 * 3 + 16,
});
fireEvent.mouseUp(canvas, {
ctrlKey: true,
clientX: 20,
clientY: 36 + 32 * 3 + 16,
});
expect(spy).toBeCalledWith({
current: {
cell: [1, 2],
range: { height: 1, width: 1, x: 1, y: 2 },
rangeStack: [],
},
columns: CompactSelection.empty(),
rows: CompactSelection.fromSingleSelection(3),
});
});
test("Select col - single-cell with col blending", async () => {
const spy = vi.fn();
vi.useFakeTimers();
render(
,
{
wrapper: Context,
}
);
prep();
const canvas = screen.getByTestId("data-grid-canvas");
fireEvent.mouseDown(canvas, {
ctrlKey: true,
clientX: 220,
clientY: 16,
});
fireEvent.mouseMove(canvas, {
ctrlKey: true,
clientX: 220,
clientY: 16,
});
fireEvent.mouseUp(canvas, {
ctrlKey: true,
clientX: 220,
clientY: 16,
});
expect(spy).toBeCalledWith({
current: {
cell: [1, 2],
range: { height: 1, width: 1, x: 1, y: 2 },
rangeStack: [],
},
columns: CompactSelection.fromSingleSelection(1),
rows: CompactSelection.empty(),
});
});
test("Select col - single-cell/single-col with col blending", async () => {
const spy = vi.fn();
vi.useFakeTimers();
render(
,
{
wrapper: Context,
}
);
prep();
const canvas = screen.getByTestId("data-grid-canvas");
fireEvent.mouseDown(canvas, {
ctrlKey: true,
clientX: 220,
clientY: 16,
});
fireEvent.mouseMove(canvas, {
ctrlKey: true,
clientX: 220,
clientY: 16,
});
fireEvent.mouseUp(canvas, {
ctrlKey: true,
clientX: 220,
clientY: 16,
});
expect(spy).toBeCalledWith({
current: {
cell: [1, 2],
range: { height: 1, width: 1, x: 1, y: 2 },
rangeStack: [],
},
columns: CompactSelection.fromSingleSelection(1),
rows: CompactSelection.empty(),
});
});
});