/* * Copyright 2016 Palantir Technologies, Inc. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import { mount, type ReactWrapper } from "enzyme"; import sinon from "sinon"; import { afterEach, beforeEach, describe, expect, it } from "@blueprintjs/test-commons/vitest"; import { Cell } from "./cell/cell"; import { Batcher } from "./common/batcher"; import { FocusMode } from "./common/cellTypes"; import * as Classes from "./common/classes"; import { Grid } from "./common/grid"; import { Rect } from "./common/rect"; import { RenderMode } from "./common/renderMode"; import type { MenuContext } from "./interactions/menus/menuContext"; import { type Region, Regions } from "./regions"; import { TableBody, type TableBodyProps } from "./tableBody"; import { cellClassNames } from "./tableBodyCells"; describe("TableBody", () => { // use enough rows that batching won't render all of them in one pass. // and careful: if this value is too big (~100), the batcher's reliance // on `requestIdleCallback` may cause the tests to run multiple times. const LARGE_NUM_ROWS = Batcher.DEFAULT_ADD_LIMIT * 2; const NUM_COLUMNS = 1; const COLUMN_WIDTH = 100; const ROW_HEIGHT = 20; let containerElement: HTMLElement | undefined; let mountedWrappers: ReactWrapper[] = []; beforeEach(() => { containerElement = document.createElement("div"); document.body.appendChild(containerElement); }); afterEach(() => { try { for (const wrapper of mountedWrappers) { try { wrapper.unmount(); } catch { // best-effort cleanup } } } finally { mountedWrappers = []; containerElement?.remove(); } }); it("cellClassNames", () => { expect(cellClassNames(0, 0)).to.deep.equal([Classes.rowCellIndexClass(0), Classes.columnCellIndexClass(0)]); expect(cellClassNames(4096, 1024)).to.deep.equal([ Classes.rowCellIndexClass(4096), Classes.columnCellIndexClass(1024), ]); }); describe("onCompleteRender", () => { it("triggers onCompleteRender immediately when renderMode={RenderMode.NONE}", () => { const onCompleteRenderSpy = sinon.spy(); mountTableBody({ columnIndexEnd: 10, onCompleteRender: onCompleteRenderSpy, renderMode: RenderMode.NONE, rowIndexEnd: 50, }); expect(onCompleteRenderSpy.calledOnce).to.be.true; }); it("doesn't triggers onCompleteRender immediately when renderMode={RenderMode.BATCH}", () => { const onCompleteRenderSpy = sinon.spy(); mountTableBody({ columnIndexEnd: 10, onCompleteRender: onCompleteRenderSpy, renderMode: RenderMode.BATCH, rowIndexEnd: 500, }); expect(onCompleteRenderSpy.called).to.be.false; }); }); describe("renderMode", () => { it("renders all cells immediately if renderMode === RenderMode.NONE", () => { const tableBody = mountTableBodyForRenderModeTest(RenderMode.NONE); // expect all cells to have rendered in one pass expect(tableBody.find(Cell)).to.have.lengthOf(LARGE_NUM_ROWS); }); it("uses batch rendering if renderMode === RenderMode.BATCH", () => { const tableBody = mountTableBodyForRenderModeTest(RenderMode.BATCH); // run this assertion immediately, expecting that the batching hasn't finished yet. expect(tableBody.find(Cell)).to.have.lengthOf(Batcher.DEFAULT_ADD_LIMIT); }); function mountTableBodyForRenderModeTest(renderMode: RenderMode.BATCH | RenderMode.NONE) { const rowHeights = Array(LARGE_NUM_ROWS).fill(ROW_HEIGHT); const columnWidths = Array(NUM_COLUMNS).fill(COLUMN_WIDTH); const grid = new Grid(rowHeights, columnWidths); const viewportRect = new Rect(0, 0, NUM_COLUMNS * COLUMN_WIDTH, LARGE_NUM_ROWS * ROW_HEIGHT); return mountTableBody({ columnIndexEnd: NUM_COLUMNS - 1, grid, renderMode, rowIndexEnd: LARGE_NUM_ROWS - 1, viewportRect, }); } }); describe("bodyContextMenuRenderer", () => { // 0-indexed coordinates const TARGET_ROW = 1; const TARGET_COLUMN = 1; const TARGET_CELL_COORDS = { col: TARGET_COLUMN, row: TARGET_ROW }; const TARGET_REGION = Regions.cell(TARGET_ROW, TARGET_COLUMN); const onFocusedRegion = sinon.spy(); const onSelection = sinon.spy(); const bodyContextMenuRenderer = sinon.stub().returns(
); afterEach(() => { onFocusedRegion.resetHistory(); onSelection.resetHistory(); bodyContextMenuRenderer.resetHistory(); }); describe("on right-click", () => { const simulateAction = (tableBody: ReactWrapper