diff --git a/package.json b/package.json
index 1241658bac3..8fa680545c0 100644
--- a/package.json
+++ b/package.json
@@ -18,7 +18,7 @@
"test": "yarn test:prepare && cypress run --component --browser chrome --spec packages",
"test:pw": "playwright test -c playwright-ct.config.ts",
"test:pw:open": "playwright test -c playwright-ct.config.ts --ui",
- "test:pw:ci": "playwright test -c playwright-ct.config.ts playwright/test/ packages/main/src/components/SelectDialog/test/ --project chromium",
+ "test:pw:ci": "playwright test -c playwright-ct.config.ts --project chromium",
"clean": "tsc --build --clean && tsc --build tsconfig.build.json --clean && rimraf temp .out test-results playwright-report playwright-ct && lerna run clean",
"clean:remove-modules": "yarn clean && rimraf node_modules",
"prettier:all": "prettier --write --config ./prettier.config.js \"**/*\"",
diff --git a/packages/main/src/components/SplitterLayout/SplitterLayout.cy.tsx b/packages/main/src/components/SplitterLayout/SplitterLayout.cy.tsx
deleted file mode 100644
index 637b1caa587..00000000000
--- a/packages/main/src/components/SplitterLayout/SplitterLayout.cy.tsx
+++ /dev/null
@@ -1,261 +0,0 @@
-import { useState } from 'react';
-import type { SplitterLayoutPropTypes } from '../..';
-import { FlexBox, Text, Button, Label, SplitterElement, SplitterLayout } from '../..';
-import { cypressPassThroughTestsFactory } from '@/cypress/support/utils';
-
-function TestComp({ vertical, dir }: { vertical: SplitterLayoutPropTypes['vertical']; dir: string }) {
- const [mount, setMount] = useState(false);
- const [dep, setDep] = useState(false);
- return (
-
-
-
-
-
-
-
-
-
- {mount && (
-
- Additional Child
-
- )}
-
- );
-}
-
-function moveSpacer(dir: string, vertical: boolean) {
- cy.findAllByRole('separator').eq(0).click();
- cy.wait(50);
- const rtlSafeLeft = `Arrow${dir === 'rtl' && !vertical ? 'Right' : 'Left'}`;
- const rtlSafeUp = `Arrow${dir === 'rtl' && !vertical ? 'Down' : 'Up'}`;
- for (let i = 0; i < 5; i++) {
- cy.findAllByRole('separator').eq(0).trigger('keydown', { code: rtlSafeLeft, force: true });
- cy.findAllByRole('separator').eq(0).trigger('keyup', { code: rtlSafeLeft, force: true });
- cy.wait(50);
- cy.findAllByRole('separator').eq(0).trigger('keydown', { code: rtlSafeUp, force: true });
- cy.findAllByRole('separator').eq(0).trigger('keyup', { code: rtlSafeUp, force: true });
- cy.wait(50);
- }
-}
-
-describe('SplitterLayout', () => {
- ['ltr', 'rtl'].forEach((dir) => {
- [false, true].forEach((vertical) => {
- it(`Splitter Move & Reset - ${dir} - vertical: ${vertical}`, () => {
- cy.viewport(2000, 2000);
- cy.mount();
-
- cy.findByTestId('se1').should('have.css', 'flex', '0 1 calc(70% - 16px)');
- cy.findByTestId('se2').should('have.css', 'flex', '0 1 30%');
-
- moveSpacer(dir, vertical);
- cy.findByTestId('se1').should('have.css', 'flex', '0 0 1184px');
- cy.findByTestId('se2').should('have.css', 'flex', '0 0 800px');
-
- cy.findByText('Trigger dep').click({ force: true });
-
- cy.findByTestId('se1').should('have.css', 'flex', '0 1 calc(70% - 16px)');
- cy.findByTestId('se2').should('have.css', 'flex', '0 1 30%');
-
- moveSpacer(dir, vertical);
- cy.findByTestId('se1').should('have.css', 'flex', '0 0 1184px');
- cy.findByTestId('se2').should('have.css', 'flex', '0 0 800px');
-
- cy.findByText('Add child').click({ force: true });
- cy.findByTestId('se1').should('have.css', 'flex', '0 1 calc(70% - 16px)');
- cy.findByTestId('se2').should('have.css', 'flex', '0 1 calc(25% - 16px)');
- cy.findByTestId('se3').should('have.css', 'flex', '0 1 5%');
-
- moveSpacer(dir, vertical);
-
- cy.viewport(1000, 1000);
-
- cy.findByTestId('se1').should('have.css', 'flex', '0 1 calc(70% - 16px)');
- cy.findByTestId('se2').should('have.css', 'flex', '0 1 calc(25% - 16px)');
- cy.findByTestId('se3').should('have.css', 'flex', '0 1 5%');
- });
- });
- });
-
- it('SplitterLayout w/ multiple SplitterElements', () => {
- const click = cy.spy().as('click');
- [true, false].forEach((vertical) => {
- cy.mount(
-
-
-
-
-
-
-
-
-
-
- ,
- );
- cy.findByTestId('btn').click();
- cy.get('[role="separator"]').first().click();
- // fallback click to prevent flakyness
- cy.get('[role="separator"]')
- .first()
- .click()
- .should('have.length', 1)
- .should('have.css', 'border', '2px solid rgb(0, 50, 165)');
- cy.findByTestId('sl').should('have.css', 'width', '800px').should('have.css', 'height', '800px');
- cy.findByTestId('se2')
- .should('have.css', 'flex', '0 1 400px')
- .should('have.css', vertical ? 'min-height' : 'min-width', '300px');
- cy.findByTestId('se3')
- .should('have.css', 'flex', '0 0 200px')
- .should('have.css', vertical ? 'min-height' : 'min-width', '0px');
- });
- cy.get('@click').should('have.been.calledTwice');
- });
-
- it('empty content', () => {
- cy.mount();
- cy.findByTestId('sl').should('not.be.visible').should('exist');
- });
-
- [true, false].forEach((vertical) => {
- it(`controlled width (${vertical ? 'vertical' : 'horizontal'})`, () => {
- function getMouseMoveArgs(amount: number): [number, number] {
- return vertical ? [0, amount] : [amount, 0];
- }
- const resize = cy.spy().as('resize');
- const TestComp = () => {
- const [size0, setSize0] = useState('200px');
- const [size1, setSize1] = useState(200);
- const [size2, setSize2] = useState('auto');
- const [size3, setSize3] = useState('200px');
- const setter = [setSize0, setSize1, setSize2, setSize3];
- return (
- <>
- {
- resize(e);
- e.areas.forEach((item) => {
- if (item.area.dataset.index === '1') {
- setter[Number(item.area.dataset.index)](item.size);
- } else {
- //@ts-expect-error: supported
- setter[Number(item.area.dataset.index)](item.size + 'px');
- }
- });
- }}
- >
-
-
- Content 1
-
-
-
-
- {`Content 2
- with
- multi
- lines`}
-
-
-
-
-
- Content 3 with long text: Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy
- eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et
- accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est
- Lorem ipsum dolor sit amet.
-
-
-
-
-
- Content 4
-
-
-
- {size0}
-
- {size1}
-
- {size2}
-
- {size3}
- >
- );
- };
-
- cy.mount();
-
- cy.wait(100);
-
- cy.get('@resize').should('not.have.been.called');
-
- cy.findAllByRole('separator').eq(0).realMouseDown({ position: 'center' });
- cy.wait(50);
- cy.findAllByRole('separator')
- .eq(0)
- .realMouseMove(...getMouseMoveArgs(-100), {
- position: 'center',
- scrollBehavior: false,
- })
- .realMouseUp({ position: 'center' });
-
- cy.get('@resize').should('have.been.called');
-
- cy.findByTestId('0').should(($el) => {
- expect(parseInt($el.text(), 10)).to.be.within(99, 101);
- });
- cy.findByTestId('1').should(($el) => {
- expect(parseInt($el.text(), 10)).to.be.within(299, 301);
- });
- cy.findByTestId('2').should('have.text', 'auto');
- cy.findByTestId('3').invoke('text').should('equal', '200px');
-
- cy.findAllByRole('separator').eq(0).realMouseDown({ position: 'center' });
- cy.wait(50);
- // drag across bounding box
- cy.get('body')
- .realMouseMove(...getMouseMoveArgs(300), {
- position: 'center',
- scrollBehavior: false,
- })
- .realMouseUp({ position: 'center' });
-
- cy.findByTestId('0').should(($el) => {
- expect(parseInt($el.text(), 10)).to.be.within(383, 385);
- });
- cy.findByTestId('1').should(($el) => {
- expect(parseInt($el.text(), 10)).to.be.within(15, 17);
- });
- cy.findByTestId('2').should('have.text', 'auto');
- cy.findByTestId('3').invoke('text').should('equal', '200px');
-
- cy.findAllByRole('separator').eq(2).click().realPress('ArrowDown').realPress('ArrowDown').realPress('ArrowDown');
-
- cy.findByTestId('0').should(($el) => {
- expect(parseInt($el.text(), 10)).to.be.within(383, 385);
- });
- cy.findByTestId('1').should(($el) => {
- expect(parseInt($el.text(), 10)).to.be.within(15, 17);
- });
- cy.findByTestId('2').should('have.text', '360px');
- cy.findByTestId('3').should('have.text', '140px');
- });
- });
-
- cypressPassThroughTestsFactory(SplitterLayout, { children: Content });
-});
diff --git a/packages/main/src/components/SplitterLayout/test/SplitterLayout.spec.tsx b/packages/main/src/components/SplitterLayout/test/SplitterLayout.spec.tsx
new file mode 100644
index 00000000000..b8a29e124b6
--- /dev/null
+++ b/packages/main/src/components/SplitterLayout/test/SplitterLayout.spec.tsx
@@ -0,0 +1,184 @@
+import { expect, test } from '../../../../../../playwright/fixtures/main-fixtures.js';
+import type { Page } from '@playwright/test';
+import {
+ SplitterMoveResetTestComp,
+ SplitterMultipleElementsTestComp,
+ SplitterEmptyTestComp,
+ SplitterControlledTestComp,
+} from './SplitterLayoutTestComponents.js';
+
+/**
+ * Move first separator 10 times via ArrowUp/ArrowLeft (RTL aware)
+ */
+async function moveSpacer(page: Page, dir: string, vertical: boolean) {
+ const separator = page.locator('[role="separator"]').first();
+ await separator.click();
+ await page.waitForTimeout(50);
+
+ const rtlSafeLeft = `Arrow${dir === 'rtl' && !vertical ? 'Right' : 'Left'}`;
+ const rtlSafeUp = `Arrow${dir === 'rtl' && !vertical ? 'Down' : 'Up'}`;
+
+ for (let i = 0; i < 5; i++) {
+ await page.keyboard.press(rtlSafeLeft);
+ await page.waitForTimeout(50);
+ await page.keyboard.press(rtlSafeUp);
+ await page.waitForTimeout(50);
+ }
+}
+
+test.describe('SplitterLayout', () => {
+ for (const dir of ['ltr', 'rtl']) {
+ for (const vertical of [false, true]) {
+ test(`Splitter Move & Reset - ${dir} - vertical: ${vertical}`, async ({ mount, page }) => {
+ await page.setViewportSize({ width: 2000, height: 2000 });
+ await mount();
+
+ const se1 = page.getByTestId('se1');
+ const se2 = page.getByTestId('se2');
+
+ await expect(se1).toHaveCSS('flex', '0 1 calc(70% - 16px)');
+ await expect(se2).toHaveCSS('flex', '0 1 30%');
+
+ await moveSpacer(page, dir, vertical);
+ await expect(se1).toHaveCSS('flex', '0 0 1184px');
+ await expect(se2).toHaveCSS('flex', '0 0 800px');
+
+ await page.getByText('Trigger dep').click({ force: true });
+ await expect(se1).toHaveCSS('flex', '0 1 calc(70% - 16px)');
+ await expect(se2).toHaveCSS('flex', '0 1 30%');
+
+ await moveSpacer(page, dir, vertical);
+ await expect(se1).toHaveCSS('flex', '0 0 1184px');
+ await expect(se2).toHaveCSS('flex', '0 0 800px');
+
+ await page.getByText('Add child').click({ force: true });
+ await expect(se1).toHaveCSS('flex', '0 1 calc(70% - 16px)');
+ await expect(se2).toHaveCSS('flex', '0 1 calc(25% - 16px)');
+ const se3 = page.getByTestId('se3');
+ await expect(se3).toHaveCSS('flex', '0 1 5%');
+
+ // resetOnSizeChange
+ await moveSpacer(page, dir, vertical);
+ await page.setViewportSize({ width: 1000, height: 1000 });
+ await expect(se1).toHaveCSS('flex', '0 1 calc(70% - 16px)');
+ await expect(se2).toHaveCSS('flex', '0 1 calc(25% - 16px)');
+ await expect(se3).toHaveCSS('flex', '0 1 5%');
+ });
+ }
+ }
+
+ for (const vertical of [false, true]) {
+ test(`SplitterLayout w/ multiple SplitterElements - vertical: ${vertical}`, async ({ mount, page }) => {
+ let clickCount = 0;
+ await mount(
+ {
+ clickCount++;
+ }}
+ />,
+ );
+
+ await page.getByTestId('btn').click();
+ expect(clickCount).toBe(1);
+
+ // only one separator (resizable=false for #2)
+ const separators = page.locator('[role="separator"]');
+ await separators.click();
+ await expect(separators).toHaveCount(1);
+ await expect(separators).toHaveCSS('border', '2px solid rgb(0, 50, 165)');
+
+ await expect(page.getByTestId('sl')).toHaveCSS('width', '800px');
+ await expect(page.getByTestId('sl')).toHaveCSS('height', '800px');
+
+ const se2 = page.getByTestId('se2');
+ await expect(se2).toHaveCSS('flex', '0 1 400px');
+ await expect(se2).toHaveCSS(vertical ? 'min-height' : 'min-width', '300px');
+
+ // Non-resizable element
+ const se3 = page.getByTestId('se3');
+ await expect(se3).toHaveCSS('flex', '0 0 200px');
+ await expect(se3).toHaveCSS(vertical ? 'min-height' : 'min-width', '0px');
+ });
+ }
+
+ test('empty content', async ({ mount, page }) => {
+ await mount();
+ const sl = page.getByTestId('sl');
+ await expect(sl).toBeAttached();
+ await expect(sl).not.toBeVisible();
+ });
+
+ for (const vertical of [true, false]) {
+ test(`controlled width (${vertical ? 'vertical' : 'horizontal'})`, async ({ mount, page }) => {
+ await mount();
+
+ await expect(page.getByTestId('resize-count')).toHaveText('0');
+ await expect(page.getByTestId('0')).toHaveText('200px');
+ await expect(page.getByTestId('1')).toHaveText('200');
+ await expect(page.getByTestId('2')).toHaveText('auto');
+ await expect(page.getByTestId('3')).toHaveText('200px');
+
+ const sep0 = page.locator('[role="separator"]').nth(0);
+ const box0 = await sep0.boundingBox();
+ const startX0 = box0.x + box0.width / 2;
+ const startY0 = box0.y + box0.height / 2;
+
+ // move mouse to first separator, drag left/up by 100px, release
+ await page.mouse.move(startX0, startY0);
+ await page.mouse.down();
+ await page.waitForTimeout(100);
+ if (vertical) {
+ await page.mouse.move(startX0, startY0 - 100);
+ } else {
+ await page.mouse.move(startX0 - 100, startY0);
+ }
+ await page.mouse.up();
+
+ await expect(page.getByTestId('resize-count')).toHaveText('1');
+
+ await expect(page.getByTestId('0')).toHaveText('100px');
+ await expect(page.getByTestId('1')).toHaveText('300');
+ await expect(page.getByTestId('2')).toHaveText('auto');
+ await expect(page.getByTestId('3')).toHaveText('200px');
+
+ // move mouse to first separator, drag right/down by 100px (across bounding box), release
+ const box0b = await sep0.boundingBox();
+ const startX0b = box0b.x + box0b.width / 2;
+ const startY0b = box0b.y + box0b.height / 2;
+
+ await page.mouse.move(startX0b, startY0b);
+ await page.mouse.down();
+ await page.waitForTimeout(100);
+ if (vertical) {
+ await page.mouse.move(startX0b, startY0b + 300);
+ } else {
+ await page.mouse.move(startX0b + 300, startY0b);
+ }
+ await page.mouse.up();
+
+ await expect(page.getByTestId('resize-count')).toHaveText('2');
+
+ await expect(page.getByTestId('0')).toHaveText('384px');
+ await expect(page.getByTestId('1')).toHaveText('16');
+ await expect(page.getByTestId('2')).toHaveText('auto');
+ await expect(page.getByTestId('3')).toHaveText('200px');
+
+ // keyboard resize on third separator
+ const sep2 = page.locator('[role="separator"]').nth(2);
+ await sep2.click();
+ await page.keyboard.press('ArrowDown');
+ await expect(page.getByTestId('resize-count')).toHaveText('3');
+ await page.keyboard.press('ArrowDown');
+ await expect(page.getByTestId('resize-count')).toHaveText('4');
+ await page.keyboard.press('ArrowDown');
+
+ await expect(page.getByTestId('resize-count')).toHaveText('5');
+
+ await expect(page.getByTestId('0')).toHaveText('384px');
+ await expect(page.getByTestId('1')).toHaveText('16');
+ await expect(page.getByTestId('2')).toHaveText('360px');
+ await expect(page.getByTestId('3')).toHaveText('140px');
+ });
+ }
+});
diff --git a/packages/main/src/components/SplitterLayout/test/SplitterLayoutTestComponents.tsx b/packages/main/src/components/SplitterLayout/test/SplitterLayoutTestComponents.tsx
new file mode 100644
index 00000000000..d9a80f9a899
--- /dev/null
+++ b/packages/main/src/components/SplitterLayout/test/SplitterLayoutTestComponents.tsx
@@ -0,0 +1,135 @@
+import { useState } from 'react';
+import { Button } from '../../../webComponents/Button/index.js';
+import { Label } from '../../../webComponents/Label/index.js';
+import { Text } from '../../../webComponents/Text/index.js';
+import { FlexBox } from '../../FlexBox/index.js';
+import { SplitterElement } from '../../SplitterElement/index.js';
+import { SplitterLayout } from '../index.js';
+import type { SplitterLayoutPropTypes } from '../types.js';
+
+export const SplitterMoveResetTestComp = ({
+ vertical,
+ dir,
+}: {
+ vertical: SplitterLayoutPropTypes['vertical'];
+ dir: string;
+}) => {
+ const [mount, setMount] = useState(false);
+ const [dep, setDep] = useState(false);
+ return (
+
+
+
+
+
+
+
+
+
+ {mount && (
+
+ Additional Child
+
+ )}
+
+ );
+};
+
+export const SplitterMultipleElementsTestComp = ({
+ vertical,
+ onBtnClick,
+}: {
+ vertical: boolean;
+ onBtnClick?: () => void;
+}) => {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export const SplitterEmptyTestComp = () => {
+ return ;
+};
+
+export const SplitterControlledTestComp = ({ vertical }: { vertical: boolean }) => {
+ const [size0, setSize0] = useState('200px');
+ const [size1, setSize1] = useState(200);
+ const [size2, setSize2] = useState('auto');
+ const [size3, setSize3] = useState('200px');
+ const [resizeCount, setResizeCount] = useState(0);
+ const setter = [setSize0, setSize1, setSize2, setSize3];
+ return (
+ <>
+ {
+ setResizeCount((c) => c + 1);
+ e.areas.forEach((item) => {
+ if (item.area.dataset.index === '1') {
+ setter[Number(item.area.dataset.index)](item.size);
+ } else {
+ // @ts-expect-error: supported
+ setter[Number(item.area.dataset.index)](item.size + 'px');
+ }
+ });
+ }}
+ >
+
+
+ Content 1
+
+
+
+
+ {`Content 2
+ with
+ multi
+ lines`}
+
+
+
+
+
+ Content 3 with long text: Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod
+ tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et
+ justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor
+ sit amet.
+
+
+
+
+
+ Content 4
+
+
+
+ {size0}
+
+ {size1}
+
+ {size2}
+
+ {size3}
+
+ {resizeCount}
+ >
+ );
+};
diff --git a/playwright-ct.config.ts b/playwright-ct.config.ts
index 124e92c18a8..35ddd9f819d 100644
--- a/playwright-ct.config.ts
+++ b/playwright-ct.config.ts
@@ -14,6 +14,7 @@ export default defineConfig({
// https://github.com/microsoft/playwright/issues/14511#issuecomment-1552589959
reporter: process.env.CI
? [
+ ['list'],
['github'],
[
'monocart-reporter',
@@ -22,7 +23,8 @@ export default defineConfig({
outputFile: 'temp/playwright-coverage/report.html',
coverage: {
sourceFilter: (sourcePath: string) =>
- sourcePath.includes('packages/main/src/components/SelectDialog') &&
+ (sourcePath.includes('packages/main/src/components/SelectDialog') ||
+ sourcePath.includes('packages/main/src/components/Splitter')) &&
!sourcePath.includes('node_modules') &&
!sourcePath.includes('/test/'),
reports: ['lcovonly'],