/* * Copyright 2017 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 } from "enzyme"; import { afterEach, beforeEach, describe, expect, it } from "@blueprintjs/test-commons/vitest"; import { type Region, Regions } from "../../regions"; import * as ScrollUtils from "./scrollUtils"; describe("scrollUtils", () => { describe("getScrollPositionForRegion", () => { const COLUMN_WIDTH = 150; const ROW_HEIGHT = 20; const INITIAL_SCROLL_LEFT = 17; const INITIAL_SCROLL_TOP = 33; const NUM_FROZEN_ROWS = 2; const NUM_FROZEN_COLUMNS = 2; describe("no frozen rows or columns", () => { const TARGET_ROW = 2; const TARGET_COLUMN = 3; function fn(region: Region) { return ScrollUtils.getScrollPositionForRegion( region, INITIAL_SCROLL_LEFT, INITIAL_SCROLL_TOP, getLeftOffset, getTopOffset, ); } it("scrolling to cell", () => { const region = Regions.cell(TARGET_ROW, TARGET_COLUMN); const { scrollLeft, scrollTop } = fn(region); expect(scrollLeft).to.equal(TARGET_COLUMN * COLUMN_WIDTH); expect(scrollTop).to.equal(TARGET_ROW * ROW_HEIGHT); }); it("scrolling to row", () => { const region = Regions.row(TARGET_ROW); const { scrollLeft, scrollTop } = fn(region); expect(scrollLeft).to.equal(INITIAL_SCROLL_LEFT); expect(scrollTop).to.equal(TARGET_ROW * ROW_HEIGHT); }); it("scrolling to column", () => { const region = Regions.column(TARGET_COLUMN); const { scrollLeft, scrollTop } = fn(region); expect(scrollLeft).to.equal(TARGET_COLUMN * COLUMN_WIDTH); expect(scrollTop).to.equal(INITIAL_SCROLL_TOP); }); it("scrolling to full table", () => { const region = Regions.table(); const { scrollLeft, scrollTop } = fn(region); expect(scrollLeft).to.equal(0); expect(scrollTop).to.equal(0); }); }); describe("with frozen rows", () => { function fn(region: Region) { return ScrollUtils.getScrollPositionForRegion( region, INITIAL_SCROLL_LEFT, INITIAL_SCROLL_TOP, getLeftOffset, getTopOffset, NUM_FROZEN_ROWS, ); } it("scrolling to a frozen cell", () => { const TARGET_ROW = NUM_FROZEN_ROWS - 1; const TARGET_COLUMN = 3; const region = Regions.cell(TARGET_ROW, TARGET_COLUMN); const { scrollLeft, scrollTop } = fn(region); expect(scrollLeft).to.equal(TARGET_COLUMN * COLUMN_WIDTH); expect(scrollTop).to.equal(0); }); it("scrolling to a non-frozen cell", () => { const TARGET_ROW = NUM_FROZEN_ROWS; // 1 row beyond the last frozen row, b/c num is 1-indexed const TARGET_COLUMN = 3; const region = Regions.cell(TARGET_ROW, TARGET_COLUMN); const { scrollLeft, scrollTop } = fn(region); expect(scrollLeft).to.equal(TARGET_COLUMN * COLUMN_WIDTH); expect(scrollTop).to.equal(TARGET_ROW * ROW_HEIGHT - NUM_FROZEN_ROWS * ROW_HEIGHT); }); it("scrolling to a column", () => { const TARGET_COLUMN = 3; const region = Regions.column(TARGET_COLUMN); const { scrollLeft, scrollTop } = fn(region); expect(scrollLeft).to.equal(TARGET_COLUMN * COLUMN_WIDTH); expect(scrollTop).to.equal(INITIAL_SCROLL_TOP); }); it("scrolling to a frozen row", () => { const TARGET_ROW = NUM_FROZEN_ROWS - 1; const region = Regions.row(TARGET_ROW); const { scrollLeft, scrollTop } = fn(region); expect(scrollLeft).to.equal(INITIAL_SCROLL_LEFT); expect(scrollTop).to.equal(0); }); it("scrolling to a non-frozen row", () => { const TARGET_ROW = NUM_FROZEN_ROWS; // 1 row beyond the frozen region const region = Regions.row(TARGET_ROW); const { scrollLeft, scrollTop } = fn(region); expect(scrollLeft).to.equal(INITIAL_SCROLL_LEFT); expect(scrollTop).to.equal(TARGET_ROW * ROW_HEIGHT - NUM_FROZEN_ROWS * ROW_HEIGHT); }); it("scrolling to full table", () => { const region = Regions.table(); const { scrollLeft, scrollTop } = fn(region); expect(scrollLeft).to.equal(0); expect(scrollTop).to.equal(0); }); }); describe("with frozen columns", () => { function fn(region: Region) { return ScrollUtils.getScrollPositionForRegion( region, INITIAL_SCROLL_LEFT, INITIAL_SCROLL_TOP, getLeftOffset, getTopOffset, 0, NUM_FROZEN_COLUMNS, ); } it("scrolling to a frozen cell", () => { const TARGET_ROW = 3; const TARGET_COLUMN = NUM_FROZEN_COLUMNS - 1; const region = Regions.cell(TARGET_ROW, TARGET_COLUMN); const { scrollLeft, scrollTop } = fn(region); expect(scrollLeft).to.equal(0); expect(scrollTop).to.equal(TARGET_ROW * ROW_HEIGHT); }); it("scrolling to a non-frozen cell", () => { const TARGET_ROW = 3; const TARGET_COLUMN = NUM_FROZEN_COLUMNS; const region = Regions.cell(TARGET_ROW, TARGET_COLUMN); const { scrollLeft, scrollTop } = fn(region); expect(scrollTop).to.equal(TARGET_ROW * ROW_HEIGHT); expect(scrollLeft).to.equal(TARGET_COLUMN * COLUMN_WIDTH - NUM_FROZEN_COLUMNS * COLUMN_WIDTH); }); it("scrolling to a frozen column", () => { const TARGET_COLUMN = NUM_FROZEN_COLUMNS - 1; const region = Regions.column(TARGET_COLUMN); const { scrollLeft, scrollTop } = fn(region); expect(scrollLeft).to.equal(0); expect(scrollTop).to.equal(INITIAL_SCROLL_TOP); }); it("scrolling to a non-frozen column", () => { const TARGET_COLUMN = NUM_FROZEN_COLUMNS; // 1 row beyond the frozen region const region = Regions.column(TARGET_COLUMN); const { scrollLeft, scrollTop } = fn(region); expect(scrollLeft).to.equal(TARGET_COLUMN * COLUMN_WIDTH - NUM_FROZEN_COLUMNS * COLUMN_WIDTH); expect(scrollTop).to.equal(INITIAL_SCROLL_TOP); }); it("scrolling to a row", () => { const TARGET_ROW = 3; const region = Regions.row(TARGET_ROW); const { scrollLeft, scrollTop } = fn(region); expect(scrollLeft).to.equal(INITIAL_SCROLL_LEFT); expect(scrollTop).to.equal(TARGET_ROW * ROW_HEIGHT); }); it("scrolling to full table", () => { const region = Regions.table(); const { scrollLeft, scrollTop } = fn(region); expect(scrollLeft).to.equal(0); expect(scrollTop).to.equal(0); }); }); describe("with frozen rows and columns", () => { function fn(region: Region) { return ScrollUtils.getScrollPositionForRegion( region, INITIAL_SCROLL_LEFT, INITIAL_SCROLL_TOP, getLeftOffset, getTopOffset, NUM_FROZEN_ROWS, NUM_FROZEN_COLUMNS, ); } it("scrolling to a frozen cell", () => { const TARGET_ROW = NUM_FROZEN_ROWS - 1; const TARGET_COLUMN = NUM_FROZEN_COLUMNS - 1; const region = Regions.cell(TARGET_ROW, TARGET_COLUMN); const { scrollLeft, scrollTop } = fn(region); expect(scrollLeft).to.equal(0); expect(scrollTop).to.equal(0); }); it("scrolling to a non-frozen cell", () => { const TARGET_ROW = NUM_FROZEN_ROWS; const TARGET_COLUMN = NUM_FROZEN_COLUMNS; const region = Regions.cell(TARGET_ROW, TARGET_COLUMN); const { scrollLeft, scrollTop } = fn(region); expect(scrollTop).to.equal(TARGET_ROW * ROW_HEIGHT - NUM_FROZEN_ROWS * ROW_HEIGHT); expect(scrollLeft).to.equal(TARGET_COLUMN * COLUMN_WIDTH - NUM_FROZEN_COLUMNS * COLUMN_WIDTH); }); it("scrolling to a frozen column", () => { const TARGET_COLUMN = NUM_FROZEN_COLUMNS - 1; const region = Regions.column(TARGET_COLUMN); const { scrollLeft, scrollTop } = fn(region); expect(scrollLeft).to.equal(0); expect(scrollTop).to.equal(INITIAL_SCROLL_TOP); }); it("scrolling to a non-frozen column", () => { const TARGET_COLUMN = NUM_FROZEN_COLUMNS; // 1 row beyond the frozen region const region = Regions.column(TARGET_COLUMN); const { scrollLeft, scrollTop } = fn(region); expect(scrollLeft).to.equal(TARGET_COLUMN * COLUMN_WIDTH - NUM_FROZEN_COLUMNS * COLUMN_WIDTH); expect(scrollTop).to.equal(INITIAL_SCROLL_TOP); }); it("scrolling to a frozen row", () => { const TARGET_ROW = NUM_FROZEN_ROWS - 1; const region = Regions.row(TARGET_ROW); const { scrollLeft, scrollTop } = fn(region); expect(scrollLeft).to.equal(INITIAL_SCROLL_LEFT); expect(scrollTop).to.equal(0); }); it("scrolling to a non-frozen row", () => { const TARGET_ROW = NUM_FROZEN_ROWS; // 1 row beyond the frozen region const region = Regions.row(TARGET_ROW); const { scrollLeft, scrollTop } = fn(region); expect(scrollLeft).to.equal(INITIAL_SCROLL_LEFT); expect(scrollTop).to.equal(TARGET_ROW * ROW_HEIGHT - NUM_FROZEN_ROWS * ROW_HEIGHT); }); it("scrolling to full table", () => { const region = Regions.table(); const { scrollLeft, scrollTop } = fn(region); expect(scrollLeft).to.equal(0); expect(scrollTop).to.equal(0); }); }); function getTopOffset(rowIndex: number) { return ROW_HEIGHT * rowIndex; } function getLeftOffset(columnIndex: number) { return COLUMN_WIDTH * columnIndex; } }); describe("measureScrollBarThickness", () => { const PARENT_WIDTH = 100; const PARENT_HEIGHT = 100; let containerElement: HTMLElement; const baseStyles = { display: "block" }; const parentStyle: React.CSSProperties = { ...baseStyles, background: "yellow", height: PARENT_HEIGHT, overflow: "auto", width: PARENT_WIDTH, }; const fn = ScrollUtils.measureScrollBarThickness; const VERTICAL_ERROR = "measures vertical scrollbar correctly"; const HORIZONTAL_ERROR = "measures horizontal scrollbar correctly"; beforeEach(() => { containerElement = document.createElement("div"); document.body.appendChild(containerElement); }); afterEach(() => { document.body.removeChild(containerElement); }); // NOTE: these tests will fail locally on OS X if you have your scrollbars set to "When scrolling" // in System Preferences > General it("measures correctly when neither scrollbar is showing", () => { const element = mountElementsWithContentSize(PARENT_WIDTH / 2, PARENT_HEIGHT / 2); expect(fn(element, "vertical"), VERTICAL_ERROR).to.equal(0); expect(fn(element, "horizontal"), HORIZONTAL_ERROR).to.equal(0); }); // skip: requires real browser layout engine (jsdom limitation) it.skip("measures correctly when only vertical scrollbar is showing", () => { const element = mountElementsWithContentSize(PARENT_WIDTH / 2, PARENT_HEIGHT * 2); expect(fn(element, "vertical"), VERTICAL_ERROR).to.be.greaterThan(0); expect(fn(element, "horizontal"), HORIZONTAL_ERROR).to.equal(0); }); // skip: requires real browser layout engine (jsdom limitation) it.skip("measures correctly when only horizontal scrollbar is showing", () => { const element = mountElementsWithContentSize(PARENT_WIDTH * 2, PARENT_HEIGHT / 2); expect(fn(element, "vertical"), VERTICAL_ERROR).to.equal(0); expect(fn(element, "horizontal"), HORIZONTAL_ERROR).to.be.greaterThan(0); }); // skip: requires real browser layout engine (jsdom limitation) it.skip("measures correctly when both scrollbars are showing", () => { const element = mountElementsWithContentSize(PARENT_WIDTH * 2, PARENT_HEIGHT * 2); expect(fn(element, "vertical"), VERTICAL_ERROR).to.be.greaterThan(0); expect(fn(element, "horizontal"), HORIZONTAL_ERROR).to.be.greaterThan(0); }); function mountElementsWithContentSize(contentWidth: number, contentHeight: number) { const wrapper = mount(