-
+
{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..98cfa89ecb
--- /dev/null
+++ b/tests/opensource-suites/dash/base/fixedHeader.test.ts
@@ -0,0 +1,157 @@
+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).toBeVisible();
+ 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 fixedHeader.toggleFixedHeaderCollapsibleState(); // collapse
+
+ await expect(collapsibleStateToggleButton).toBeVisible();
+ await expect(fixedHeader.staticFixedHeaderGroupContent).toBeHidden();
+ await expect(fixedHeader.hidableFixedHeaderGroupContent).toBeHidden();
+
+ await page.mouse.wheel(0, 500);
+
+ await expect(collapsibleStateToggleButton).toBeVisible();
+ await expect(fixedHeader.staticFixedHeaderGroupContent).toBeHidden();
+ await expect(fixedHeader.hidableFixedHeaderGroupContent).toBeHidden();
+
+ await fixedHeader.toggleFixedHeaderCollapsibleState(); // expand
+
+ await expect(fixedHeader.hidableFixedHeaderGroupContent).toBeVisible();
+
+ 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.hidableFixedHeaderGroupWrapper.boundingBox())?.y ?? 0;
+
+ await page.mouse.wheel(0, 500);
+
+ expect((await body.boundingBox())?.y).toEqual(bodyScrollPositionBeforeCollapsing);
+ expect((await fixedHeader.hidableFixedHeaderGroupWrapper.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
+ );
+ }
+}