From b9cc3405d5364ae6740e23427c8e87eaf7152f91 Mon Sep 17 00:00:00 2001 From: Daria Larionova Date: Fri, 29 Nov 2024 18:07:14 +0300 Subject: [PATCH] Tests on fixed header --- src/i18n-keysets/dash.main.view/en.json | 2 + src/i18n-keysets/dash.main.view/ru.json | 2 + src/shared/constants/qa/dash.ts | 8 + src/ui/units/dash/containers/Body/Body.tsx | 6 + .../containers/FixedHeader/FixedHeader.scss | 10 +- .../containers/FixedHeader/FixedHeader.tsx | 15 +- .../dash/base/fixedHeader.test.ts | 146 ++++++++++++++++++ tests/page-objects/dashboard/DashboardPage.ts | 3 + tests/page-objects/dashboard/FixedHeader.ts | 63 ++++++++ 9 files changed, 247 insertions(+), 8 deletions(-) create mode 100644 tests/opensource-suites/dash/base/fixedHeader.test.ts create mode 100644 tests/page-objects/dashboard/FixedHeader.ts diff --git a/src/i18n-keysets/dash.main.view/en.json b/src/i18n-keysets/dash.main.view/en.json index ebd6391a5e..aa45fc5db0 100644 --- a/src/i18n-keysets/dash.main.view/en.json +++ b/src/i18n-keysets/dash.main.view/en.json @@ -16,5 +16,7 @@ "label_updating": "Updating", "toast_paste-invalid-workbook-entry": "Pasting widgets linked to objects from another workbook is forbidden", "toast_unsaved": "There are unsaved changes on the page. Are you sure?", + "tooltip_collapse-fixed-group": "Collapse pinned group", + "tooltip_expand-fixed-group": "Expand pinned group", "warning_paste-invalid-workbook-entry": "To work with this object within another workbook, please migrate all linked objects from the source workbook. Migrating objects to workbooks" } diff --git a/src/i18n-keysets/dash.main.view/ru.json b/src/i18n-keysets/dash.main.view/ru.json index 43a4eee1c5..8cc697c477 100644 --- a/src/i18n-keysets/dash.main.view/ru.json +++ b/src/i18n-keysets/dash.main.view/ru.json @@ -16,5 +16,7 @@ "label_updating": "Обновление", "toast_paste-invalid-workbook-entry": "Не допускается вставка виджетов, у которых есть связи с объектами из другого воркбука", "toast_unsaved": "На странице есть несохраненные изменения. Вы уверены?", + "tooltip_collapse-fixed-group": "Свернуть закрепленную группу", + "tooltip_expand-fixed-group": "Развернуть закрепленную группу", "warning_paste-invalid-workbook-entry": "Чтобы работать с объектом в рамках другого воркбука, пожалуйста, перенесите в этот воркбук все связанные объекты из исходного воркбука. Миграция объектов в воркбук" } diff --git a/src/shared/constants/qa/dash.ts b/src/shared/constants/qa/dash.ts index 5b3973da62..bbaf87576f 100644 --- a/src/shared/constants/qa/dash.ts +++ b/src/shared/constants/qa/dash.ts @@ -84,6 +84,14 @@ export enum DashCommonQa { RelationsRowPopover = 'dialog-relations-row-popover', } +export enum FixedHeaderQa { + ExpandCollapseFixedHeaderButton = 'expand-collapse-fixed-header-button', + StaticFixedHeaderGroupWrapper = 'static-fixed-header-group-wrapper', + StaticFixedHeaderGroupContent = 'static-fixed-header-group-content', + HidableFixedHeaderGroupWrapper = 'hidable-fixed-header-group-wrapper', + HidableFixedHeaderGroupContent = 'hidable-fixed-header-group-content', +} + export enum DashRelationTypes { output = 'relation-type-option-output', input = 'relation-type-option-input', diff --git a/src/ui/units/dash/containers/Body/Body.tsx b/src/ui/units/dash/containers/Body/Body.tsx index 6be2a8ccc3..04448b6a80 100644 --- a/src/ui/units/dash/containers/Body/Body.tsx +++ b/src/ui/units/dash/containers/Body/Body.tsx @@ -47,6 +47,7 @@ import { DashKitOverlayMenuQa, DashTabItemType, Feature, + FixedHeaderQa, LOADED_DASH_CLASS, UPDATE_STATE_DEBOUNCE_TIME, } from 'shared'; @@ -635,6 +636,11 @@ class Body extends React.PureComponent { size="xl" width="max" pin="brick-round" + title={i18n( + 'dash.main.view', + isCollapsed ? 'tooltip_expand-fixed-group' : 'tooltip_collapse-fixed-group', + )} + qa={FixedHeaderQa.ExpandCollapseFixedHeaderButton} > diff --git a/src/ui/units/dash/containers/FixedHeader/FixedHeader.scss b/src/ui/units/dash/containers/FixedHeader/FixedHeader.scss index cc8e3505fd..94f3887cb4 100644 --- a/src/ui/units/dash/containers/FixedHeader/FixedHeader.scss +++ b/src/ui/units/dash/containers/FixedHeader/FixedHeader.scss @@ -73,14 +73,15 @@ $fixedSectionOffset: 8px; &_edit-mode { border-bottom: 1px solid var(--g-color-line-generic); + padding-bottom: $fixedSectionOffset; } } &__container-wrapper { display: flex; - padding-bottom: $fixedSectionOffset; flex-direction: row; flex: 1; + position: relative; @include flexReactGridLayout; } @@ -89,6 +90,7 @@ $fixedSectionOffset: 8px; display: flex; flex-direction: row; min-height: 52px; + padding-bottom: $fixedSectionOffset; @include dndHighlight; @@ -112,6 +114,7 @@ $fixedSectionOffset: 8px; overflow: clip; min-height: 0; max-height: 0; + padding: 0; } } @@ -124,10 +127,5 @@ $fixedSectionOffset: 8px; pointer-events: none; color: var(--g-color-text-hint); text-align: center; - - &.with-offset { - top: calc(50% - #{$fixedSectionOffset}); - transform: translateY(calc(-1 * calc(50% - calc(#{$fixedSectionOffset}) / 2))); - } } } diff --git a/src/ui/units/dash/containers/FixedHeader/FixedHeader.tsx b/src/ui/units/dash/containers/FixedHeader/FixedHeader.tsx index 2090d4e8df..0bb277aa03 100644 --- a/src/ui/units/dash/containers/FixedHeader/FixedHeader.tsx +++ b/src/ui/units/dash/containers/FixedHeader/FixedHeader.tsx @@ -3,6 +3,7 @@ import React from 'react'; import {useBodyScrollLock, useForkRef} from '@gravity-ui/uikit'; import block from 'bem-cn-lite'; import {I18n} from 'i18n'; +import {FixedHeaderQa} from 'shared'; import './FixedHeader.scss'; @@ -125,13 +126,17 @@ export const FixedHeaderControls: React.FC = (props) = return (
-
+
{content}
{props.controls}
@@ -204,6 +209,7 @@ export const FixedHeaderContainer: React.FC = (props) style={{height: containerHeight}} >
= (props) 'edit-mode': editMode, })} > -
{content}
+
+ {content} +
); diff --git a/tests/opensource-suites/dash/base/fixedHeader.test.ts b/tests/opensource-suites/dash/base/fixedHeader.test.ts new file mode 100644 index 0000000000..86c7fb9911 --- /dev/null +++ b/tests/opensource-suites/dash/base/fixedHeader.test.ts @@ -0,0 +1,146 @@ +import {Page, expect} from '@playwright/test'; + +import DashboardPage from '../../../page-objects/dashboard/DashboardPage'; +import {openTestPage, slct} from '../../../utils'; +import datalensTest from '../../../utils/playwright/globalTestDefinition'; +import {ActionPanelQA} from '../../../../src/shared'; + +const dashboardKey = 'at6wshbewj36x-fixed-header-tests'; +const tabsIds = { + twoGroups: 'X5', + onlySecondGroup: 'Ja', + overflownSecondGroup: 'vJ', +}; + +function getTabUrl(tabName: string) { + return `/${dashboardKey}?tab=${tabName}`; +} + +datalensTest.describe('Fixed header', () => { + datalensTest('Header with 2 groups', async ({page}: {page: Page}) => { + await openTestPage(page, getTabUrl(tabsIds.twoGroups)); + const dashboardPage = new DashboardPage({page}); + const fixedHeader = dashboardPage.fixedHeader; + const actionPanelHeight = + (await dashboardPage.page.locator(slct(ActionPanelQA.ActionPanel)).boundingBox()) + ?.height ?? 0; + + const collapsibleStateToggleButton = fixedHeader.expandCollapseButton; + + await expect(collapsibleStateToggleButton).toBeVisible(); + await expect(fixedHeader.staticFixedHeaderGroupContent).toBeVisible(); + await expect(fixedHeader.hidableFixedHeaderGroupContent).toBeVisible(); + + const initialStaticFixedHeaderGroupVerticalOffset = + await fixedHeader.getStaticFixedHeaderGroupVerticalOffset(); + + // check that "fixed" header is not fixed without scrolling + expect(initialStaticFixedHeaderGroupVerticalOffset).toBeGreaterThan(actionPanelHeight); + expect(await fixedHeader.getHidableFixedHeaderGroupVerticalOffset()).toBeGreaterThan( + initialStaticFixedHeaderGroupVerticalOffset + actionPanelHeight, + ); + + await fixedHeader.toggleFixedHeaderCollapsibleState(); // collapse + + await expect(collapsibleStateToggleButton).toBeVisible(); + await expect(fixedHeader.staticFixedHeaderGroupContent).toBeVisible(); + await expect(fixedHeader.hidableFixedHeaderGroupContent).toBeHidden(); + + await page.mouse.wheel(0, 500); + + await expect(collapsibleStateToggleButton).toBeVisible(); + await expect(fixedHeader.staticFixedHeaderGroupContent).toBeVisible(); + await expect(fixedHeader.hidableFixedHeaderGroupContent).toBeHidden(); + + expect(await fixedHeader.getStaticFixedHeaderGroupVerticalOffset()).toEqual( + actionPanelHeight, + ); + + await fixedHeader.toggleFixedHeaderCollapsibleState(); // expand + + await expect(fixedHeader.hidableFixedHeaderGroupContent).toBeVisible(); + + const staticFixedHeaderHeight = + (await fixedHeader.staticFixedHeaderGroupWrapper.boundingBox())?.height ?? 0; + expect(await fixedHeader.getHidableFixedHeaderGroupVerticalOffset()).toEqual( + actionPanelHeight + staticFixedHeaderHeight, + ); + }); + + datalensTest('With second group only', async ({page}: {page: Page}) => { + await openTestPage(page, getTabUrl(tabsIds.onlySecondGroup)); + const dashboardPage = new DashboardPage({page}); + const fixedHeader = dashboardPage.fixedHeader; + const actionPanelHeight = + (await dashboardPage.page.locator(slct(ActionPanelQA.ActionPanel)).boundingBox()) + ?.height ?? 0; + + const collapsibleStateToggleButton = fixedHeader.expandCollapseButton; + + await expect(collapsibleStateToggleButton).toBeHidden(); + await expect(fixedHeader.staticFixedHeaderGroupContent).toBeHidden(); + await expect(fixedHeader.hidableFixedHeaderGroupContent).toBeVisible(); + + const initialStaticHidableHeaderGroupVerticalOffset = + await fixedHeader.getHidableFixedHeaderGroupVerticalOffset(); + + // check that "fixed" header is not fixed without scrolling + expect(initialStaticHidableHeaderGroupVerticalOffset).toBeGreaterThan(actionPanelHeight); + + await page.mouse.wheel(0, 500); + + await expect(fixedHeader.staticFixedHeaderGroupContent).toBeHidden(); + + expect(await fixedHeader.getHidableFixedHeaderGroupVerticalOffset()).toEqual( + actionPanelHeight, + ); + }); + datalensTest('Header with overflown second group', async ({page}: {page: Page}) => { + await openTestPage(page, getTabUrl(tabsIds.overflownSecondGroup)); + const dashboardPage = new DashboardPage({page}); + const fixedHeader = dashboardPage.fixedHeader; + const actionPanelHeight = + (await dashboardPage.page.locator(slct(ActionPanelQA.ActionPanel)).boundingBox()) + ?.height ?? 0; + + const collapsibleStateToggleButton = fixedHeader.expandCollapseButton; + + await expect(collapsibleStateToggleButton).toBeVisible(); + await expect(fixedHeader.staticFixedHeaderGroupContent).toBeVisible(); + await expect(fixedHeader.hidableFixedHeaderGroupContent).toBeVisible(); + + const body = page.locator('body'); + + const initialStaticFixedHeaderGroupVerticalOffset = + await fixedHeader.getStaticFixedHeaderGroupVerticalOffset(); + + // check that "fixed" header is not fixed without scrolling + expect(initialStaticFixedHeaderGroupVerticalOffset).toBeGreaterThan(actionPanelHeight); + expect(await fixedHeader.getHidableFixedHeaderGroupVerticalOffset()).toBeGreaterThan( + initialStaticFixedHeaderGroupVerticalOffset + actionPanelHeight, + ); + + await page.mouse.wheel(0, 500); + + const bodyScrollPositionBeforeCollapsing = (await body.boundingBox())?.y ?? 0; + const fixedHeaderScrollPositionBeforeCollapsing = + (await fixedHeader.hidableFixedHeaderGroupContent.boundingBox())?.y ?? 0; + + await fixedHeader.hidableFixedHeaderGroupContent.hover(); + await page.mouse.wheel(0, 500); + + expect((await body.boundingBox())?.y).toEqual(bodyScrollPositionBeforeCollapsing); + expect((await fixedHeader.hidableFixedHeaderGroupContent.boundingBox())?.y).toEqual( + fixedHeaderScrollPositionBeforeCollapsing - 500, + ); + + await fixedHeader.toggleFixedHeaderCollapsibleState(); // collapse + + await expect(collapsibleStateToggleButton).toBeVisible(); + await expect(fixedHeader.staticFixedHeaderGroupContent).toBeVisible(); + await expect(fixedHeader.hidableFixedHeaderGroupContent).toBeHidden(); + + await page.mouse.wheel(0, 500); + expect((await body.boundingBox())?.y).toEqual(bodyScrollPositionBeforeCollapsing - 500); + }); +}); diff --git a/tests/page-objects/dashboard/DashboardPage.ts b/tests/page-objects/dashboard/DashboardPage.ts index a050126035..5bdbc6edb1 100644 --- a/tests/page-objects/dashboard/DashboardPage.ts +++ b/tests/page-objects/dashboard/DashboardPage.ts @@ -66,6 +66,7 @@ import {CommonUrls} from '../constants/common-urls'; import {EditEntityButton} from '../workbook/EditEntityButton'; import ControlActions from './ControlActions'; import {getUrlStateParam} from '../../suites/dash/helpers'; +import {FixedHeader} from './FixedHeader'; export const BUTTON_CHECK_TIMEOUT = 3000; export const RENDER_TIMEOUT = 4000; @@ -112,6 +113,7 @@ class DashboardPage extends BasePage { dialogCreateEntry: DialogCreateEntry; editEntityButton: EditEntityButton; controlActions: ControlActions; + fixedHeader: FixedHeader; constructor({page}: DashboardPageProps) { super({page}); @@ -123,6 +125,7 @@ class DashboardPage extends BasePage { this.dialogCreateEntry = new DialogCreateEntry(page); this.editEntityButton = new EditEntityButton(page); this.controlActions = new ControlActions(page); + this.fixedHeader = new FixedHeader(page); } async waitForResponses(url: string, timeout = API_TIMEOUT): Promise> { diff --git a/tests/page-objects/dashboard/FixedHeader.ts b/tests/page-objects/dashboard/FixedHeader.ts new file mode 100644 index 0000000000..c8129d5cba --- /dev/null +++ b/tests/page-objects/dashboard/FixedHeader.ts @@ -0,0 +1,63 @@ +import {Page} from '@playwright/test'; +import {slct} from '../../utils'; +import {FixedHeaderQa} from '../../../src/shared'; + +export class FixedHeader { + static selectors = { + expandCollapseButton: slct(FixedHeaderQa.ExpandCollapseFixedHeaderButton), + staticFixedHeaderGroupWrapper: slct(FixedHeaderQa.StaticFixedHeaderGroupWrapper), + staticFixedHeaderGroupContent: slct(FixedHeaderQa.StaticFixedHeaderGroupContent), + hidableFixedHeaderGroupWrapper: slct(FixedHeaderQa.HidableFixedHeaderGroupWrapper), + hidableFixedHeaderGroupContent: slct(FixedHeaderQa.HidableFixedHeaderGroupContent), + }; + + protected page: Page; + + constructor(page: Page) { + this.page = page; + } + + get expandCollapseButton() { + return this.page.locator(FixedHeader.selectors.expandCollapseButton); + } + + toggleFixedHeaderCollapsibleState() { + return this.page.locator(FixedHeader.selectors.expandCollapseButton).click(); + } + + get staticFixedHeaderGroupContent() { + return this.page.locator(FixedHeader.selectors.staticFixedHeaderGroupContent); + } + + get hidableFixedHeaderGroupContent() { + return this.page.locator(FixedHeader.selectors.hidableFixedHeaderGroupContent); + } + + get staticFixedHeaderGroupWrapper() { + return this.page.locator(FixedHeader.selectors.staticFixedHeaderGroupWrapper); + } + + get hidableFixedHeaderGroupWrapper() { + return this.page.locator(FixedHeader.selectors.hidableFixedHeaderGroupWrapper); + } + + async getStaticFixedHeaderGroupVerticalOffset() { + return ( + ( + await this.page + .locator(FixedHeader.selectors.staticFixedHeaderGroupWrapper) + .boundingBox() + )?.y ?? 0 + ); + } + + async getHidableFixedHeaderGroupVerticalOffset() { + return ( + ( + await this.page + .locator(FixedHeader.selectors.hidableFixedHeaderGroupWrapper) + .boundingBox() + )?.y ?? 0 + ); + } +}