blob: 350782b924816348fb8c5117f21df6d826a375a4 [file] [log] [blame]
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
const {assert} = chai;
import {renderElementIntoDOM, assertElements, assertElement} from './DOMHelpers.js';
import type {
CanvasSize, GridPositionNormalizedDataWithNames, NormalizePositionDataConfig} from
'../../../../inspector_overlay/css_grid_label_helpers.js';
import {
normalizePositionData,
drawGridAreaNames,
drawGridLineNumbers,
drawGridLineNames,
} from '../../../../inspector_overlay/css_grid_label_helpers.js';
import type {AreaBounds, Bounds} from '../../../../inspector_overlay/common.js';
import {gridStyle} from '../../../../inspector_overlay/highlight_grid_common.js';
const GRID_LABEL_CONTAINER_ID = 'grid-label-container';
const DEFAULT_GRID_LABEL_LAYER_ID = 'grid-labels';
const GRID_LINE_NUMBER_LABEL_CONTAINER_CLASS = 'line-numbers';
const GRID_LINE_NAME_LABEL_CONTAINER_CLASS = 'line-names';
const GRID_LINE_AREA_LABEL_CONTAINER_CLASS = 'area-names';
const GRID_TRACK_SIZES_LABEL_CONTAINER_CLASS = 'track-sizes';
/**
* This does the same as initFrame but also prepares the DOM for testing grid labels.
*/
export function initFrameForGridLabels() {
const styleTag = document.createElement('style');
styleTag.textContent = gridStyle;
document.head.append(styleTag);
createGridLabelContainer();
}
export function initFrameForMultipleGridLabels(numGrids: number) {
for (let i = 1; i <= numGrids; i++) {
createGridLabelContainer(i);
}
}
export function createGridLabelContainer(layerId?: number) {
// Ensure main layer is created first
let el = document.getElementById(GRID_LABEL_CONTAINER_ID);
if (!el) {
el = document.createElement('div');
el.id = GRID_LABEL_CONTAINER_ID;
}
const layerEl = el.createChild('div');
layerEl.id = layerId ? `grid-${layerId}-labels` : DEFAULT_GRID_LABEL_LAYER_ID;
layerEl.createChild('div', GRID_LINE_NUMBER_LABEL_CONTAINER_CLASS);
layerEl.createChild('div', GRID_LINE_NAME_LABEL_CONTAINER_CLASS);
layerEl.createChild('div', GRID_LINE_AREA_LABEL_CONTAINER_CLASS);
layerEl.createChild('div', GRID_TRACK_SIZES_LABEL_CONTAINER_CLASS);
renderElementIntoDOM(el, {allowMultipleChildren: true});
}
export function getMainGridLabelContainer(): HTMLElement {
const el = document.getElementById(GRID_LABEL_CONTAINER_ID);
assertElement(el, HTMLElement);
return el;
}
export function getGridLabelContainer(layerId?: number): HTMLElement {
const id = layerId ? `grid-${layerId}-labels` : DEFAULT_GRID_LABEL_LAYER_ID;
const el = document.querySelector(`#${GRID_LABEL_CONTAINER_ID} #${CSS.escape(id)}`);
assertElement(el, HTMLElement);
return el;
}
export function getGridLineNumberLabelContainer(layerId?: number): HTMLElement {
const id = layerId ? `grid-${layerId}-labels` : DEFAULT_GRID_LABEL_LAYER_ID;
const el = document.querySelector(
`#${GRID_LABEL_CONTAINER_ID} #${CSS.escape(id)} .${GRID_LINE_NUMBER_LABEL_CONTAINER_CLASS}`);
assertElement(el, HTMLElement);
return el;
}
export function getGridLineNameLabelContainer(layerId?: number): HTMLElement {
const id = layerId ? `grid-${layerId}-labels` : DEFAULT_GRID_LABEL_LAYER_ID;
const el =
document.querySelector(`#${GRID_LABEL_CONTAINER_ID} #${CSS.escape(id)} .${GRID_LINE_NAME_LABEL_CONTAINER_CLASS}`);
assertElement(el, HTMLElement);
return el;
}
export function getGridTrackSizesLabelContainer(layerId?: number): HTMLElement {
const id = layerId ? `grid-${layerId}-labels` : DEFAULT_GRID_LABEL_LAYER_ID;
const el = document.querySelector(
`#${GRID_LABEL_CONTAINER_ID} #${CSS.escape(id)} .${GRID_TRACK_SIZES_LABEL_CONTAINER_CLASS}`);
assertElement(el, HTMLElement);
return el;
}
export function getGridAreaNameLabelContainer(layerId?: number): HTMLElement {
const id = layerId ? `grid-${layerId}-labels` : DEFAULT_GRID_LABEL_LAYER_ID;
const el =
document.querySelector(`#${GRID_LABEL_CONTAINER_ID} #${CSS.escape(id)} .${GRID_LINE_AREA_LABEL_CONTAINER_CLASS}`);
assertElement(el, HTMLElement);
return el;
}
interface ExpectedLayerLabel {
layerId: number;
expectedLabels: ExpectedLineNumberLabel[];
}
interface ExpectedLineNumberLabel {
className: string;
count: number;
}
interface ExpectedLineNameLabel {
type: string;
textContent: string;
x?: number;
y?: number;
}
interface ExpectedAreaNameLabel {
textContent: string;
left?: string;
top?: string;
}
export function drawGridLineNumbersAndAssertLabels(
config: NormalizePositionDataConfig&{writingMode?: string}, bounds: Bounds, canvasSize: CanvasSize, layerId: number,
expectedLabels: ExpectedLineNumberLabel[]) {
const el = getGridLineNumberLabelContainer(layerId);
const data = normalizePositionData(config, bounds);
// Note that this test helper is focused on testing the number and orientation of the labels, not their exact position
// so we pass the identity matrix here in all cases, even when a different writing mode is provided.
drawGridLineNumbers(el, data, canvasSize, 1, new DOMMatrix(), config.writingMode);
let totalLabelCount = 0;
for (const {className, count} of expectedLabels) {
const labels =
el.querySelectorAll(`.${GRID_LINE_NUMBER_LABEL_CONTAINER_CLASS} .grid-label-content.${CSS.escape(className)}`);
assert.strictEqual(labels.length, count, `Expected ${count} labels to be displayed for ${className}`);
totalLabelCount += count;
}
assert.strictEqual(
el.querySelectorAll(`.${GRID_LINE_NUMBER_LABEL_CONTAINER_CLASS} .grid-label-content`).length, totalLabelCount,
'The right total number of line number labels were displayed');
}
export function drawGridLineNamesAndAssertLabels(
config: NormalizePositionDataConfig, bounds: Bounds, canvasSize: CanvasSize, layerId: number,
deviceEmulationFactor: number, expectedLabels: ExpectedLineNameLabel[]) {
const el = getGridLineNameLabelContainer(layerId);
const data = normalizePositionData(config, bounds);
drawGridLineNames(el, data as GridPositionNormalizedDataWithNames, canvasSize, deviceEmulationFactor);
const labels = el.querySelectorAll(`.${GRID_LINE_NAME_LABEL_CONTAINER_CLASS} .grid-label-content`);
assert.strictEqual(labels.length, expectedLabels.length, 'The right total number of line name labels were displayed');
assertElements(labels, HTMLElement);
const foundLabels: {textContent: string, x: number, y: number}[] = [];
labels.forEach(el => {
const width = el.offsetWidth;
const height = el.offsetHeight;
const top = parseInt(el.style.top, 10);
const left = parseInt(el.style.left, 10);
let rowOffset = height / 2;
if (el.classList.contains('right-top')) {
rowOffset = 0;
} else if (el.classList.contains('right-bottom')) {
rowOffset = height;
}
let columnOffset = width / 2;
if (el.classList.contains('bottom-left')) {
columnOffset = 0;
} else if (el.classList.contains('bottom-right')) {
columnOffset = width;
}
foundLabels.push({
textContent: el.textContent || '',
x: left + columnOffset,
y: top + rowOffset,
});
});
for (const expected of expectedLabels) {
const foundLabel = foundLabels.find(({textContent}) => textContent === expected.textContent);
if (!foundLabel) {
assert.fail(`Expected line name label with text content ${expected.textContent} not found`);
return;
}
if (expected.type === 'column' && typeof expected.x !== 'undefined') {
assert.strictEqual(
foundLabel.x, expected.x,
`Expected column line name label ${expected.textContent} to be positioned at ${expected.x}px`);
}
if (expected.type === 'row' && typeof expected.y !== 'undefined') {
assert.strictEqual(
foundLabel.y, expected.y,
`Expected row line name label ${expected.textContent} to be positioned at ${expected.y}px`);
}
}
}
export function drawGridAreaNamesAndAssertLabels(
areaNames: AreaBounds[], writingModeMatrix: DOMMatrix|undefined, writingMode: string|undefined,
expectedLabels: ExpectedAreaNameLabel[]) {
const el = getGridAreaNameLabelContainer();
drawGridAreaNames(el, areaNames, writingModeMatrix, writingMode);
const labels = el.querySelectorAll(`.${GRID_LINE_AREA_LABEL_CONTAINER_CLASS} .grid-label-content`);
assert.strictEqual(labels.length, expectedLabels.length, 'The right total number of area name labels were displayed');
assertElements(labels, HTMLElement);
const foundLabels: ExpectedAreaNameLabel[] = [];
labels.forEach(label => {
foundLabels.push({
textContent: label.textContent || '',
top: label.style.top,
left: label.style.left,
});
});
for (const expected of expectedLabels) {
const foundLabel = foundLabels.find(({textContent}) => textContent === expected.textContent);
if (!foundLabel) {
assert.fail(`Expected area label with text content ${expected.textContent} not found`);
return;
}
if (typeof expected.left !== 'undefined') {
assert.strictEqual(
foundLabel.left, expected.left,
`Expected label ${expected.textContent} to be left positioned to ${expected.left}`);
}
if (typeof expected.top !== 'undefined') {
assert.strictEqual(
foundLabel.top, expected.top,
`Expected label ${expected.textContent} to be top positioned to ${expected.top}`);
}
}
}
export function drawMultipleGridLineNumbersAndAssertLabels(
configs: Array<{config: NormalizePositionDataConfig, layerId: number}>, bounds: Bounds, canvasSize: CanvasSize,
expectedLabelList: ExpectedLayerLabel[]) {
for (const item of configs) {
const el = getGridLineNumberLabelContainer(item.layerId);
const data = normalizePositionData(item.config, bounds);
drawGridLineNumbers(el, data, canvasSize, 1);
}
let totalLabelCount = 0;
for (const {layerId, expectedLabels} of expectedLabelList) {
const el = getGridLineNumberLabelContainer(layerId);
for (const {className, count} of expectedLabels) {
const labels = el.querySelectorAll(
`.${GRID_LINE_NUMBER_LABEL_CONTAINER_CLASS} .grid-label-content.${CSS.escape(className)}`);
assert.strictEqual(labels.length, count, `Expected ${count} labels to be displayed for ${className}`);
totalLabelCount += count;
}
}
const mainLayerEl = getMainGridLabelContainer();
assert.strictEqual(
mainLayerEl.querySelectorAll(`.${GRID_LINE_NUMBER_LABEL_CONTAINER_CLASS} .grid-label-content`).length,
totalLabelCount, 'The right total number of line number labels were displayed');
}