import * as React from "react"; import { render, fireEvent, screen, cleanup } from "@testing-library/react"; import DataGrid, { type DataGridProps, type DataGridRef } from "../src/internal/data-grid/data-grid.js"; import { CompactSelection, GridCellKind } from "../src/internal/data-grid/data-grid-types.js"; import { getDefaultTheme } from "../src/index.js"; import { AllCellRenderers } from "../src/cells/index.js"; import { vi, expect, describe, test, beforeEach, afterEach } from "vitest"; import ImageWindowLoaderImpl from "../src/common/image-window-loader.js"; import { mergeAndRealizeTheme } from "../src/common/styles.js"; const basicProps: DataGridProps = { cellXOffset: 0, cellYOffset: 0, headerIcons: undefined, isDraggable: undefined, onCanvasBlur: () => undefined, onCanvasFocused: () => undefined, onCellFocused: () => undefined, onContextMenu: () => undefined, onDragEnd: () => undefined, onDragLeave: () => undefined, onDragOverCell: () => undefined, onDragStart: () => undefined, onDrop: () => undefined, onItemHovered: () => undefined, onKeyDown: () => undefined, onKeyUp: () => undefined, onMouseDown: () => undefined, onMouseMoveRaw: () => undefined, onMouseUp: () => undefined, smoothScrollX: undefined, smoothScrollY: undefined, allowResize: undefined, canvasRef: undefined, disabledRows: undefined, eventTargetRef: undefined, fillHandle: undefined, fixedShadowX: undefined, fixedShadowY: undefined, getGroupDetails: undefined, getRowThemeOverride: undefined, highlightRegions: undefined, imageWindowLoader: new ImageWindowLoaderImpl(), onHeaderMenuClick: undefined, prelightCells: undefined, translateX: undefined, translateY: undefined, dragAndDropState: undefined, drawFocusRing: true, drawHeader: undefined, drawCell: undefined, isFocused: true, experimental: undefined, columns: [ { title: "A", width: 150, }, { title: "B", width: 160, }, { title: "C", width: 170, }, { title: "D", width: 180, }, { title: "E", width: 190, }, ], isFilling: false, enableGroups: false, theme: mergeAndRealizeTheme(getDefaultTheme()), freezeColumns: 0, selection: { current: undefined, rows: CompactSelection.empty(), columns: CompactSelection.empty(), }, firstColAccessible: true, onMouseMove: () => undefined, getCellContent: cell => ({ kind: GridCellKind.Text, allowOverlay: false, data: `${cell[0]},${cell[1]}`, displayData: `${cell[0]},${cell[1]}`, }), groupHeaderHeight: 0, headerHeight: 36, accessibilityHeight: 50, height: 1000, width: 1000, isDragging: false, isResizing: false, resizeColumn: undefined, freezeTrailingRows: 0, hasAppendRow: false, rowHeight: 32, rows: 1000, verticalBorder: () => true, getCellRenderer: cell => { if (cell.kind === GridCellKind.Custom) return undefined; return AllCellRenderers.find(x => x.kind === cell.kind) as any; }, }; const dataGridCanvasId = "data-grid-canvas"; describe("data-grid", () => { beforeEach(() => { 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("Emits mouse down", () => { const spy = vi.fn(); render(); fireEvent.mouseDown(screen.getByTestId(dataGridCanvasId), { clientX: 300, // Col B clientY: 36 + 32 + 16, // Row 1 (0 indexed) }); fireEvent.mouseUp(screen.getByTestId(dataGridCanvasId), { clientX: 300, // Col B clientY: 36 + 32 + 16, // Row 1 (0 indexed) }); fireEvent.click(screen.getByTestId(dataGridCanvasId), { clientX: 300, // Col B clientY: 36 + 32 + 16, // Row 1 (0 indexed) }); expect(spy).toHaveBeenCalled(); expect(spy).toHaveBeenCalledWith( expect.objectContaining({ location: [1, 1], kind: "cell", }) ); }); test("OOB mouse down", () => { const spy = vi.fn(); render(); fireEvent.mouseDown(screen.getByTestId(dataGridCanvasId), { clientX: 990, // Col B clientY: 36 + 32 + 16, // Row 1 (0 indexed) }); expect(spy).toHaveBeenCalled(); expect(spy).toHaveBeenCalledWith( expect.objectContaining({ kind: "out-of-bounds", }) ); }); test("Emits mouse up", () => { const spy = vi.fn(); render(); fireEvent.mouseDown(screen.getByTestId(dataGridCanvasId), { clientX: 300, // Col B clientY: 36 + 32 * 5 + 16, // Row 5 (0 indexed) }); fireEvent.mouseUp(screen.getByTestId(dataGridCanvasId), { clientX: 300, // Col B clientY: 36 + 32 * 5 + 16, // Row 5 (0 indexed) }); fireEvent.click(screen.getByTestId(dataGridCanvasId), { clientX: 300, // Col B clientY: 36 + 32 * 5 + 16, // Row 5 (0 indexed) }); expect(spy).toHaveBeenCalledWith( expect.objectContaining({ location: [1, 5], kind: "cell", localEventX: 150, localEventY: 16, }), false ); }); test("Does not emit mousedown/up over header menu", () => { const downSpy = vi.fn(); const upSpy = vi.fn(); render( ({ ...c, hasMenu: true }))} onMouseUp={upSpy} onMouseDown={downSpy} /> ); const el = screen.getByTestId(dataGridCanvasId); fireEvent.mouseDown(el, { clientX: 140, clientY: 18, }); fireEvent.mouseUp(el, { clientX: 140, clientY: 18, }); expect(downSpy).not.toBeCalled(); expect(upSpy).not.toBeCalled(); }); test("Cell hovered", () => { const spy = vi.fn(); render(); const el = screen.getByTestId(dataGridCanvasId); fireEvent.mouseMove(el, { clientX: 350, // Col C clientY: 36 + 32 * 5 + 16, // Row 5 (0 indexed) }); expect(spy).toBeCalledWith( expect.objectContaining({ kind: "cell", location: [2, 5], }) ); }); test("Cell is not hovered when target is not data grid", () => { const spy = vi.fn(); render( <>
); const outsideElement = screen.getByTestId("outside-element"); fireEvent.mouseMove(outsideElement, { clientX: 350, // Col C clientY: 36 + 32 * 5 + 16, // Row 5 (0 indexed) }); expect(spy).not.toHaveBeenCalled(); }); test("Header hovered", () => { const spy = vi.fn(); render(); const el = screen.getByTestId(dataGridCanvasId); fireEvent.mouseMove(el, { clientX: 350, // Col C clientY: 16, // Header }); expect(spy).toBeCalledWith( expect.objectContaining({ kind: "header", location: [2, -1], }) ); }); test("Header hovered when scrolled", () => { const spy = vi.fn(); render( ); const el = screen.getByTestId(dataGridCanvasId); fireEvent.mouseMove(el, { clientX: 350, // Col C clientY: 46, // Header }); expect(spy).toBeCalledWith( expect.objectContaining({ kind: "header", location: [2, -1], }) ); }); test("Group header hovered", () => { const spy = vi.fn(); render(); const el = screen.getByTestId(dataGridCanvasId); fireEvent.mouseMove(el, { clientX: 350, // Col C clientY: 14, // Header }); expect(spy).toBeCalledWith( expect.objectContaining({ kind: "group-header", location: [2, -2], }) ); }); test("Simple damage", () => { const spy = vi.fn(basicProps.getCellContent); const ref = React.createRef(); render(); spy.mockClear(); expect(spy).not.toBeCalled(); ref.current?.damage([{ cell: [1, 1] }]); expect(spy).toBeCalled(); }); test("Out of bounds damage", () => { const spy = vi.fn(basicProps.getCellContent); const ref = React.createRef(); render(); spy.mockClear(); expect(spy).not.toBeCalled(); ref.current?.damage([{ cell: [1, 900] }]); expect(spy).not.toBeCalled(); }); test("Freeze column simple check", () => { const spy = vi.fn(); render(); fireEvent.mouseDown(screen.getByTestId(dataGridCanvasId), { clientX: 50, // Col A clientY: 36 + 32 * 5 + 16, // Row 5 (0 indexed) }); fireEvent.mouseUp(screen.getByTestId(dataGridCanvasId), { clientX: 50, // Col A clientY: 36 + 32 * 5 + 16, // Row 5 (0 indexed) }); fireEvent.click(screen.getByTestId(dataGridCanvasId), { clientX: 50, // Col A clientY: 36 + 32 * 5 + 16, // Row 5 (0 indexed) }); expect(spy).toHaveBeenCalledWith( expect.objectContaining({ location: [0, 5], kind: "cell", localEventX: 50, localEventY: 16, }), false ); }); });