diff --git a/.circleci/config.yml b/.circleci/config.yml index adb1bf6c916be..406c6b65159fa 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -199,7 +199,7 @@ jobs: test_browser: <<: *default-job docker: - - image: mcr.microsoft.com/playwright:v1.44.1-focal + - image: mcr.microsoft.com/playwright:v1.46.0-focal environment: NODE_ENV: development # Needed if playwright is in `devDependencies` steps: @@ -232,7 +232,7 @@ jobs: test_e2e: <<: *default-job docker: - - image: mcr.microsoft.com/playwright:v1.44.1-focal + - image: mcr.microsoft.com/playwright:v1.46.0-focal environment: NODE_ENV: development # Needed if playwright is in `devDependencies` steps: @@ -245,7 +245,7 @@ jobs: test_e2e_website: <<: *default-job docker: - - image: mcr.microsoft.com/playwright:v1.44.1-focal + - image: mcr.microsoft.com/playwright:v1.46.0-focal environment: NODE_ENV: development # Needed if playwright is in `devDependencies` steps: @@ -260,7 +260,7 @@ jobs: test_regressions: <<: *default-job docker: - - image: mcr.microsoft.com/playwright:v1.44.1-focal + - image: mcr.microsoft.com/playwright:v1.46.0-focal environment: NODE_ENV: development # Needed if playwright is in `devDependencies` steps: diff --git a/.eslintrc.js b/.eslintrc.js index f4762cac6c026..59aab812859c9 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -269,6 +269,12 @@ module.exports = { ], }, }, + { + files: ['packages/*/src/**/*.e2e.spec{.ts,.tsx,.js}'], + rules: { + 'react/react-in-jsx-scope': 'off', + }, + }, ...buildPackageRestrictedImports('@mui/x-charts', 'x-charts', false), ...buildPackageRestrictedImports('@mui/x-charts-pro', 'x-charts-pro', false), ...buildPackageRestrictedImports('@mui/x-codemod', 'x-codemod', false), diff --git a/.gitignore b/.gitignore index ca6bf0461cd64..79b2169dfd187 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,8 @@ performance-snapshot.json .github/styles/Google .github/styles/MUI .github/styles/.vale-config +**/test-results/ +**/playwright-report/ +**/blob-report/ +**/playwright/.cache/ + diff --git a/package.json b/package.json index 8c37f4d776b6b..d93d73b33235e 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ "test:e2e:server": "serve test/e2e -p 5001", "test:e2e-website": "npx playwright test test/e2e-website --config test/e2e-website/playwright.config.ts", "test:e2e-website:dev": "PLAYWRIGHT_TEST_BASE_URL=http://localhost:3001 npx playwright test test/e2e-website --config test/e2e-website/playwright.config.ts", + "test:e2e:charts": "playwright test -c ./test/e2e-charts/playwright-ct.config.ts", "test:regressions": "cross-env NODE_ENV=production pnpm test:regressions:build && concurrently --success first --kill-others \"pnpm test:regressions:run\" \"pnpm test:regressions:server\"", "test:regressions:build": "webpack --config test/regressions/webpack.config.js", "test:regressions:dev": "concurrently \"pnpm test:regressions:build --watch\" \"pnpm test:regressions:server\"", @@ -94,9 +95,10 @@ "@next/eslint-plugin-next": "14.2.4", "@octokit/plugin-retry": "^7.1.1", "@octokit/rest": "^21.0.0", - "@playwright/test": "^1.44.1", - "@types/babel__traverse": "^7.20.6", + "@playwright/experimental-ct-react": "1.46.0", + "@playwright/test": "1.46.0", "@types/babel__core": "^7.20.5", + "@types/babel__traverse": "^7.20.6", "@types/chai": "^4.3.16", "@types/chai-dom": "^1.11.3", "@types/fs-extra": "^11.0.4", diff --git a/packages/x-charts/src/ChartsTooltip/ChartsTooltip.e2e.spec.tsx b/packages/x-charts/src/ChartsTooltip/ChartsTooltip.e2e.spec.tsx new file mode 100644 index 0000000000000..04184aef5680e --- /dev/null +++ b/packages/x-charts/src/ChartsTooltip/ChartsTooltip.e2e.spec.tsx @@ -0,0 +1,53 @@ +import { test, expect } from '@playwright/experimental-ct-react'; +import { BarChartTest } from './ChartsTooltip.e2e.stories'; + +test.use({ viewport: { width: 500, height: 500 } }); + +test.describe('', () => { + test('should display tooltip on item hover', async ({ mount, page }) => { + const component = await mount(); + + await component.getByText('100').hover({ force: true }); + + expect(await page.getByRole('tooltip').isVisible()).toBe(true); + expect(await page.getByRole('tooltip').textContent()).toBe('100'); + }); + + test('should display tooltip when dragging over multiple items with touch', async ({ + mount, + page, + hasTouch, + }) => { + test.skip(!hasTouch, 'Test touch only on touch devices'); + + const component = await mount(); + + const first = (await component.getByText('100').boundingBox())!; + const second = (await component.getByText('200').boundingBox())!; + + const getCenter = (box: { x: number; y: number; width: number; height: number }) => ({ + x: box.x + box.width / 2, + y: box.y + box.height / 2, + }); + + // Wait for playwright v1.46.0 to land + // https://github.com/microsoft/playwright/pull/31457 + await page.touchscreen.touch('touchstart', [{ x: 0, y: 0 }]); + + expect(await page.getByRole('tooltip').isVisible()).toBe(false); + + await page.touchscreen.touch('touchmove', [getCenter(first)]); + + expect(await page.getByRole('tooltip').isVisible()).toBe(true); + expect(await page.getByRole('tooltip').textContent()).toBe('100'); + + await page.touchscreen.touch('touchmove', [getCenter(second)]); + + expect(await page.getByRole('tooltip').isVisible()).toBe(true); + expect(await page.getByRole('tooltip').textContent()).toBe('200'); + + await page.touchscreen.touch('touchend', [getCenter(second)]); + + expect(await page.getByRole('tooltip').isVisible()).toBe(false); + }); +}); diff --git a/packages/x-charts/src/ChartsTooltip/ChartsTooltip.e2e.stories.tsx b/packages/x-charts/src/ChartsTooltip/ChartsTooltip.e2e.stories.tsx new file mode 100644 index 0000000000000..4fca08fbf92a3 --- /dev/null +++ b/packages/x-charts/src/ChartsTooltip/ChartsTooltip.e2e.stories.tsx @@ -0,0 +1,22 @@ +import * as React from 'react'; +import { BarChart } from '../BarChart'; + +export function BarChartTest() { + return ( + + ); +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 131f1e9fb22eb..b6aec28cc9ff5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -104,9 +104,12 @@ importers: '@octokit/rest': specifier: ^21.0.0 version: 21.0.0 + '@playwright/experimental-ct-react': + specifier: 1.46.0 + version: 1.46.0(@types/node@18.19.39)(terser@5.27.0)(vite@5.3.2(@types/node@18.19.39)(terser@5.27.0)) '@playwright/test': - specifier: ^1.44.1 - version: 1.44.1 + specifier: 1.46.0 + version: 1.46.0 '@types/babel__core': specifier: ^7.20.5 version: 7.20.5 @@ -433,7 +436,7 @@ importers: version: 5.15.21(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@mui/material-nextjs': specifier: ^5.15.11 - version: 5.15.11(@emotion/cache@11.11.0)(@emotion/server@11.11.0)(@mui/material@5.15.21(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@types/react@18.3.3)(next@14.2.4(@babel/core@7.24.7)(@opentelemetry/api@1.8.0)(@playwright/test@1.44.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) + version: 5.15.11(@emotion/cache@11.11.0)(@emotion/server@11.11.0)(@mui/material@5.15.21(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@types/react@18.3.3)(next@14.2.4(@babel/core@7.24.7)(@opentelemetry/api@1.8.0)(@playwright/test@1.46.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) '@mui/styles': specifier: ^5.15.21 version: 5.15.21(@types/react@18.3.3)(react@18.3.1) @@ -562,7 +565,7 @@ importers: version: 0.5.45 next: specifier: ^14.2.4 - version: 14.2.4(@babel/core@7.24.7)(@opentelemetry/api@1.8.0)(@playwright/test@1.44.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 14.2.4(@babel/core@7.24.7)(@opentelemetry/api@1.8.0)(@playwright/test@1.46.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) nprogress: specifier: ^0.2.0 version: 0.2.0 @@ -1462,9 +1465,6 @@ importers: '@mui/x-license': specifier: workspace:* version: link:../packages/x-license/build - '@playwright/test': - specifier: ^1.44.1 - version: 1.44.1 '@react-spring/web': specifier: ^9.7.3 version: 9.7.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -2137,6 +2137,18 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-react-jsx-self@7.24.7': + resolution: {integrity: sha512-fOPQYbGSgH0HUp4UJO4sMBFjY6DuWq+2i8rixyUMb3CdGixs/gccURvYOAhajBdKDoGajFr3mUq5rH3phtkGzw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-jsx-source@7.24.7': + resolution: {integrity: sha512-J2z+MWzZHVOemyLweMqngXrgGC42jQ//R0KdxqkIz/OrbVIIlhFI3WigZ5fO+nwFvBlncr4MGapd8vTyc7RPNQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-react-jsx@7.24.7': resolution: {integrity: sha512-+Dj06GDZEFRYvclU6k4bme55GKBEWUmByM/eoKuqg4zTNQHiApWRhQph5fxQB2wAEFvRzL1tOEj1RJ19wJrhoA==} engines: {node: '>=6.9.0'} @@ -3361,9 +3373,18 @@ packages: resolution: {integrity: sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} - '@playwright/test@1.44.1': - resolution: {integrity: sha512-1hZ4TNvD5z9VuhNJ/walIjvMVvYkZKf71axoF/uiAqpntQJXpG64dlXhoDXE3OczPuTuvjf/M5KWFg5VAVUS3Q==} - engines: {node: '>=16'} + '@playwright/experimental-ct-core@1.46.0': + resolution: {integrity: sha512-4bHw+P0ub0A/B6tbiqLQFwvaR+wsH5fE2yt1rxWg/dtE8uGhqEeAav9TX7j4PmILM86R3Le21h94wdDIHyeJBA==} + engines: {node: '>=18'} + + '@playwright/experimental-ct-react@1.46.0': + resolution: {integrity: sha512-BSEfTBes2ljEQZxmtPpEQi8ZJns+B9F5h226Fk4/DdJbvueriEcJa4uls6KRIScSX8gd27Vg3P9T/buxW2BvjA==} + engines: {node: '>=18'} + hasBin: true + + '@playwright/test@1.46.0': + resolution: {integrity: sha512-/QYft5VArOrGRP5pgkrfKksqsKA6CEFyGQ/gjNe6q0y4tZ1aaPfq4gIjudr1s3D+pXyrPRdsy4opKDrjBabE5w==} + engines: {node: '>=18'} hasBin: true '@polka/url@1.0.0-next.24': @@ -3403,6 +3424,86 @@ packages: resolution: {integrity: sha512-es2g3dq6Nb07iFxGk5GuHN20RwBZOsuDQN7izWIisUcv9r+d2C5jQxqmgkdebXgReWfiyUabcki6Fg77mSNrig==} engines: {node: '>=14.0.0'} + '@rollup/rollup-android-arm-eabi@4.18.0': + resolution: {integrity: sha512-Tya6xypR10giZV1XzxmH5wr25VcZSncG0pZIjfePT0OVBvqNEurzValetGNarVrGiq66EBVAFn15iYX4w6FKgQ==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.18.0': + resolution: {integrity: sha512-avCea0RAP03lTsDhEyfy+hpfr85KfyTctMADqHVhLAF3MlIkq83CP8UfAHUssgXTYd+6er6PaAhx/QGv4L1EiA==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.18.0': + resolution: {integrity: sha512-IWfdwU7KDSm07Ty0PuA/W2JYoZ4iTj3TUQjkVsO/6U+4I1jN5lcR71ZEvRh52sDOERdnNhhHU57UITXz5jC1/w==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.18.0': + resolution: {integrity: sha512-n2LMsUz7Ynu7DoQrSQkBf8iNrjOGyPLrdSg802vk6XT3FtsgX6JbE8IHRvposskFm9SNxzkLYGSq9QdpLYpRNA==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-linux-arm-gnueabihf@4.18.0': + resolution: {integrity: sha512-C/zbRYRXFjWvz9Z4haRxcTdnkPt1BtCkz+7RtBSuNmKzMzp3ZxdM28Mpccn6pt28/UWUCTXa+b0Mx1k3g6NOMA==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.18.0': + resolution: {integrity: sha512-l3m9ewPgjQSXrUMHg93vt0hYCGnrMOcUpTz6FLtbwljo2HluS4zTXFy2571YQbisTnfTKPZ01u/ukJdQTLGh9A==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.18.0': + resolution: {integrity: sha512-rJ5D47d8WD7J+7STKdCUAgmQk49xuFrRi9pZkWoRD1UeSMakbcepWXPF8ycChBoAqs1pb2wzvbY6Q33WmN2ftw==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-musl@4.18.0': + resolution: {integrity: sha512-be6Yx37b24ZwxQ+wOQXXLZqpq4jTckJhtGlWGZs68TgdKXJgw54lUUoFYrg6Zs/kjzAQwEwYbp8JxZVzZLRepQ==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-powerpc64le-gnu@4.18.0': + resolution: {integrity: sha512-hNVMQK+qrA9Todu9+wqrXOHxFiD5YmdEi3paj6vP02Kx1hjd2LLYR2eaN7DsEshg09+9uzWi2W18MJDlG0cxJA==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.18.0': + resolution: {integrity: sha512-ROCM7i+m1NfdrsmvwSzoxp9HFtmKGHEqu5NNDiZWQtXLA8S5HBCkVvKAxJ8U+CVctHwV2Gb5VUaK7UAkzhDjlg==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.18.0': + resolution: {integrity: sha512-0UyyRHyDN42QL+NbqevXIIUnKA47A+45WyasO+y2bGJ1mhQrfrtXUpTxCOrfxCR4esV3/RLYyucGVPiUsO8xjg==} + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.18.0': + resolution: {integrity: sha512-xuglR2rBVHA5UsI8h8UbX4VJ470PtGCf5Vpswh7p2ukaqBGFTnsfzxUBetoWBWymHMxbIG0Cmx7Y9qDZzr648w==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-musl@4.18.0': + resolution: {integrity: sha512-LKaqQL9osY/ir2geuLVvRRs+utWUNilzdE90TpyoX0eNqPzWjRm14oMEE+YLve4k/NAqCdPkGYDaDF5Sw+xBfg==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-win32-arm64-msvc@4.18.0': + resolution: {integrity: sha512-7J6TkZQFGo9qBKH0pk2cEVSRhJbL6MtfWxth7Y5YmZs57Pi+4x6c2dStAUvaQkHQLnEQv1jzBUW43GvZW8OFqA==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.18.0': + resolution: {integrity: sha512-Txjh+IxBPbkUB9+SXZMpv+b/vnTEtFyfWZgJ6iyCmt2tdx0OF5WhFowLmnh8ENGNpfUlUZkdI//4IEmhwPieNg==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.18.0': + resolution: {integrity: sha512-UOo5FdvOL0+eIVTgS4tIdbW+TtnBLWg1YBCcU2KWM7nuNwRz9bksDX1bekJJCpu25N1DVWaCwnT39dVQxzqS8g==} + cpu: [x64] + os: [win32] + '@sec-ant/readable-stream@0.4.1': resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==} @@ -3846,6 +3947,12 @@ packages: '@ungap/structured-clone@1.2.0': resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} + '@vitejs/plugin-react@4.3.1': + resolution: {integrity: sha512-m/V2syj5CuVnaxcUJOQRel/Wr31FFXRFlnOoq1TVtkCxsY5veGMTEmpWHndrhB2U8ScHtCQB1e+4hWYExQc6Lg==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + vite: ^4.2.0 || ^5.0.0 + '@webassemblyjs/ast@1.12.1': resolution: {integrity: sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==} @@ -7901,11 +8008,21 @@ packages: engines: {node: '>=16'} hasBin: true + playwright-core@1.46.0: + resolution: {integrity: sha512-9Y/d5UIwuJk8t3+lhmMSAJyNP1BUC/DqP3cQJDQQL/oWqAiuPTLgy7Q5dzglmTLwcBRdetzgNM/gni7ckfTr6A==} + engines: {node: '>=18'} + hasBin: true + playwright@1.44.1: resolution: {integrity: sha512-qr/0UJ5CFAtloI3avF95Y0L1xQo6r3LQArLIg/z/PoGJ6xa+EwzrwO5lpNr/09STxdHuUoP2mvuELJS+hLdtgg==} engines: {node: '>=16'} hasBin: true + playwright@1.46.0: + resolution: {integrity: sha512-XYJ5WvfefWONh1uPAUAi0H2xXV5S3vrtcnXe6uAOgdGi3aSpqOSXX08IAjXW34xitfuOJsvXU5anXZxPSEQiJw==} + engines: {node: '>=18'} + hasBin: true + please-upgrade-node@3.2.0: resolution: {integrity: sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==} @@ -8103,6 +8220,10 @@ packages: react-is@18.3.1: resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} + react-refresh@0.14.2: + resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==} + engines: {node: '>=0.10.0'} + react-router-dom@6.23.1: resolution: {integrity: sha512-utP+K+aSTtEdbWpC+4gxhdlPFwuEfDKq8ZrPFU65bbRJY+l706qjR7yaidBpo3MSeA/fzwbXWbKBI6ftOnP3OQ==} engines: {node: '>=14.0.0'} @@ -8376,6 +8497,11 @@ packages: robust-predicates@3.0.2: resolution: {integrity: sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==} + rollup@4.18.0: + resolution: {integrity: sha512-QmJz14PX3rzbJCN1SG4Xe/bAAX2a6NpCP8ab2vfu2GiUr8AQcr2nCV/oEO3yneFarB67zk8ShlIyWb2LGTb3Sg==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + rrweb-cssom@0.6.0: resolution: {integrity: sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==} @@ -9226,6 +9352,34 @@ packages: vfile@4.2.1: resolution: {integrity: sha512-O6AE4OskCG5S1emQ/4gl8zK586RqA3srz3nfK/Viy0UPToBc5Trp9BVFb1u0CjsKrAWwnpr4ifM/KBXPWwJbCA==} + vite@5.3.2: + resolution: {integrity: sha512-6lA7OBHBlXUxiJxbO5aAY2fsHHzDr1q7DvXYnyZycRs2Dz+dXBWuhpWHvmljTRTpQC2uvGmUFFkSHF2vGo90MA==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.19.39 + less: '*' + lightningcss: ^1.21.0 + sass: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + void-elements@2.0.1: resolution: {integrity: sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung==} engines: {node: '>=0.10.0'} @@ -10286,6 +10440,16 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/plugin-transform-react-jsx-self@7.24.7(@babel/core@7.24.7)': + dependencies: + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 + + '@babel/plugin-transform-react-jsx-source@7.24.7(@babel/core@7.24.7)': + dependencies: + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 + '@babel/plugin-transform-react-jsx@7.24.7(@babel/core@7.24.7)': dependencies: '@babel/core': 7.24.7 @@ -11162,11 +11326,11 @@ snapshots: '@emotion/styled': 11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1) '@types/react': 18.3.3 - '@mui/material-nextjs@5.15.11(@emotion/cache@11.11.0)(@emotion/server@11.11.0)(@mui/material@5.15.21(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@types/react@18.3.3)(next@14.2.4(@babel/core@7.24.7)(@opentelemetry/api@1.8.0)(@playwright/test@1.44.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)': + '@mui/material-nextjs@5.15.11(@emotion/cache@11.11.0)(@emotion/server@11.11.0)(@mui/material@5.15.21(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@types/react@18.3.3)(next@14.2.4(@babel/core@7.24.7)(@opentelemetry/api@1.8.0)(@playwright/test@1.46.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)': dependencies: '@babel/runtime': 7.24.7 '@mui/material': 5.15.21(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - next: 14.2.4(@babel/core@7.24.7)(@opentelemetry/api@1.8.0)(@playwright/test@1.44.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + next: 14.2.4(@babel/core@7.24.7)(@opentelemetry/api@1.8.0)(@playwright/test@1.46.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: 18.3.1 optionalDependencies: '@emotion/cache': 11.11.0 @@ -11781,9 +11945,38 @@ snapshots: '@pkgr/core@0.1.1': {} - '@playwright/test@1.44.1': + '@playwright/experimental-ct-core@1.46.0(@types/node@18.19.39)(terser@5.27.0)': dependencies: - playwright: 1.44.1 + playwright: 1.46.0 + playwright-core: 1.46.0 + vite: 5.3.2(@types/node@18.19.39)(terser@5.27.0) + transitivePeerDependencies: + - '@types/node' + - less + - lightningcss + - sass + - stylus + - sugarss + - terser + + '@playwright/experimental-ct-react@1.46.0(@types/node@18.19.39)(terser@5.27.0)(vite@5.3.2(@types/node@18.19.39)(terser@5.27.0))': + dependencies: + '@playwright/experimental-ct-core': 1.46.0(@types/node@18.19.39)(terser@5.27.0) + '@vitejs/plugin-react': 4.3.1(vite@5.3.2(@types/node@18.19.39)(terser@5.27.0)) + transitivePeerDependencies: + - '@types/node' + - less + - lightningcss + - sass + - stylus + - sugarss + - supports-color + - terser + - vite + + '@playwright/test@1.46.0': + dependencies: + playwright: 1.46.0 '@polka/url@1.0.0-next.24': {} @@ -11822,6 +12015,54 @@ snapshots: '@remix-run/router@1.16.1': {} + '@rollup/rollup-android-arm-eabi@4.18.0': + optional: true + + '@rollup/rollup-android-arm64@4.18.0': + optional: true + + '@rollup/rollup-darwin-arm64@4.18.0': + optional: true + + '@rollup/rollup-darwin-x64@4.18.0': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.18.0': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.18.0': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.18.0': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.18.0': + optional: true + + '@rollup/rollup-linux-powerpc64le-gnu@4.18.0': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.18.0': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.18.0': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.18.0': + optional: true + + '@rollup/rollup-linux-x64-musl@4.18.0': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.18.0': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.18.0': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.18.0': + optional: true + '@sec-ant/readable-stream@0.4.1': {} '@sigstore/bundle@1.1.0': @@ -12376,6 +12617,17 @@ snapshots: '@ungap/structured-clone@1.2.0': {} + '@vitejs/plugin-react@4.3.1(vite@5.3.2(@types/node@18.19.39)(terser@5.27.0))': + dependencies: + '@babel/core': 7.24.7 + '@babel/plugin-transform-react-jsx-self': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-react-jsx-source': 7.24.7(@babel/core@7.24.7) + '@types/babel__core': 7.20.5 + react-refresh: 0.14.2 + vite: 5.3.2(@types/node@18.19.39)(terser@5.27.0) + transitivePeerDependencies: + - supports-color + '@webassemblyjs/ast@1.12.1': dependencies: '@webassemblyjs/helper-numbers': 1.11.6 @@ -16586,7 +16838,7 @@ snapshots: nested-error-stacks@2.1.1: {} - next@14.2.4(@babel/core@7.24.7)(@opentelemetry/api@1.8.0)(@playwright/test@1.44.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + next@14.2.4(@babel/core@7.24.7)(@opentelemetry/api@1.8.0)(@playwright/test@1.46.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: '@next/env': 14.2.4 '@swc/helpers': 0.5.5 @@ -16608,7 +16860,7 @@ snapshots: '@next/swc-win32-ia32-msvc': 14.2.4 '@next/swc-win32-x64-msvc': 14.2.4 '@opentelemetry/api': 1.8.0 - '@playwright/test': 1.44.1 + '@playwright/test': 1.46.0 transitivePeerDependencies: - '@babel/core' - babel-plugin-macros @@ -17300,12 +17552,20 @@ snapshots: playwright-core@1.44.1: {} + playwright-core@1.46.0: {} + playwright@1.44.1: dependencies: playwright-core: 1.44.1 optionalDependencies: fsevents: 2.3.2 + playwright@1.46.0: + dependencies: + playwright-core: 1.46.0 + optionalDependencies: + fsevents: 2.3.2 + please-upgrade-node@3.2.0: dependencies: semver-compare: 1.0.0 @@ -17504,6 +17764,8 @@ snapshots: react-is@18.3.1: {} + react-refresh@0.14.2: {} + react-router-dom@6.23.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: '@remix-run/router': 1.16.1 @@ -17814,6 +18076,28 @@ snapshots: robust-predicates@3.0.2: {} + rollup@4.18.0: + dependencies: + '@types/estree': 1.0.5 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.18.0 + '@rollup/rollup-android-arm64': 4.18.0 + '@rollup/rollup-darwin-arm64': 4.18.0 + '@rollup/rollup-darwin-x64': 4.18.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.18.0 + '@rollup/rollup-linux-arm-musleabihf': 4.18.0 + '@rollup/rollup-linux-arm64-gnu': 4.18.0 + '@rollup/rollup-linux-arm64-musl': 4.18.0 + '@rollup/rollup-linux-powerpc64le-gnu': 4.18.0 + '@rollup/rollup-linux-riscv64-gnu': 4.18.0 + '@rollup/rollup-linux-s390x-gnu': 4.18.0 + '@rollup/rollup-linux-x64-gnu': 4.18.0 + '@rollup/rollup-linux-x64-musl': 4.18.0 + '@rollup/rollup-win32-arm64-msvc': 4.18.0 + '@rollup/rollup-win32-ia32-msvc': 4.18.0 + '@rollup/rollup-win32-x64-msvc': 4.18.0 + fsevents: 2.3.3 + rrweb-cssom@0.6.0: {} rrweb-cssom@0.7.0: {} @@ -18800,6 +19084,16 @@ snapshots: unist-util-stringify-position: 2.0.3 vfile-message: 2.0.4 + vite@5.3.2(@types/node@18.19.39)(terser@5.27.0): + dependencies: + esbuild: 0.21.5 + postcss: 8.4.38 + rollup: 4.18.0 + optionalDependencies: + '@types/node': 18.19.39 + fsevents: 2.3.3 + terser: 5.27.0 + void-elements@2.0.1: {} w3c-xmlserializer@5.0.0: diff --git a/renovate.json b/renovate.json index 5c6bf29584a6b..1940bc6efe6a5 100644 --- a/renovate.json +++ b/renovate.json @@ -30,6 +30,10 @@ "groupName": "Emotion", "matchPackagePatterns": "@emotion/*" }, + { + "groupName": "Playwright", + "matchPackagePatterns": "@playwright/*" + }, { "groupName": "core-js", "matchPackageNames": ["core-js"], diff --git a/test/e2e-charts/README.md b/test/e2e-charts/README.md new file mode 100644 index 0000000000000..2fde60fedb507 --- /dev/null +++ b/test/e2e-charts/README.md @@ -0,0 +1,35 @@ +# Testing Charts E2E + +This directory contains the end-to-end tests for the x-charts project. + +## Running the tests + +Basic tests can be run with the following command: + +```bash +pnpm test:e2e:charts +``` + +We use the playwright test runner to run the tests. You can find more information about playwright [here](https://playwright.dev/). + +An useful command to run the tests with the browser UI is: + +```bash +pnpm test:e2e:charts --ui +``` + +## Writing tests + +The tests are written in TypeScript and can be written in any of the x-charts(-\*) packages. Simply create a new file with the `.e2e.spec.tsx?` extension and write your tests. + +We use playwright in [component testing mode](https://playwright.dev/docs/test-components), which is **experimental**. But allows us to test the components in isolation. It has some caveats, so be sure to read the documentation. + +Mainly, you can't pass a synchronous function as a prop to a component, because it will be executed in the test environment, not in the browser. You can define your component's "story" in a different file and import it in the test file. + +For that we use a `*.e2e.stories.tsx` file, where we define the stories for the components we want to test. + +## Reasoning vs RTL + +Some of our features use SVG apis that are not available in the JSDOM environment. This is why we use playwright to run the tests in a real browser. + +An alternative would be to use [svgdom](https://www.npmjs.com/package/svgdom) or polyfill everything ourselves. diff --git a/test/e2e-charts/playwright-ct.config.ts b/test/e2e-charts/playwright-ct.config.ts new file mode 100644 index 0000000000000..7567a413167a0 --- /dev/null +++ b/test/e2e-charts/playwright-ct.config.ts @@ -0,0 +1,55 @@ +import { defineConfig, devices } from '@playwright/experimental-ct-react'; + +/** + * See https://playwright.dev/docs/test-configuration. + */ +export default defineConfig({ + testDir: '../../packages/', + testMatch: '**/x-charts?(-pro)/**/*.e2e.spec.tsx', + /* The base directory, relative to the config file, for snapshot files created with toMatchSnapshot and toHaveScreenshot. */ + snapshotDir: './__snapshots__', + /* Maximum time one test can run for. */ + timeout: 10 * 1000, + /* Run tests in files in parallel */ + fullyParallel: true, + /* Fail the build on CI if you accidentally left test.only in the source code. */ + forbidOnly: !!process.env.CI, + /* Retry on CI only */ + retries: process.env.CI ? 2 : 0, + /* Opt out of parallel tests on CI. */ + workers: process.env.CI ? 1 : undefined, + /* Reporter to use. See https://playwright.dev/docs/test-reporters */ + reporter: 'html', + /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ + use: { + /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ + trace: 'on-first-retry', + + /* Port to use for Playwright component endpoint. */ + ctPort: 3100, + }, + + /* Configure projects for major browsers */ + projects: [ + { + name: 'chromium', + use: { ...devices['Desktop Chrome'] }, + }, + { + name: 'chrome-mobile', + use: { ...devices['Pixel 5'] }, + }, + { + name: 'firefox', + use: { ...devices['Desktop Firefox'] }, + }, + { + name: 'webkit', + use: { ...devices['Desktop Safari'] }, + }, + { + name: 'webkit-mobile', + use: { ...devices['iPhone 13'] }, + }, + ], +}); diff --git a/test/e2e-charts/playwright/index.html b/test/e2e-charts/playwright/index.html new file mode 100644 index 0000000000000..2032be5972c7e --- /dev/null +++ b/test/e2e-charts/playwright/index.html @@ -0,0 +1,12 @@ + + + + + + Testing Page + + +
+ + + diff --git a/test/e2e-charts/playwright/index.tsx b/test/e2e-charts/playwright/index.tsx new file mode 100644 index 0000000000000..78b9c5d6ac0ad --- /dev/null +++ b/test/e2e-charts/playwright/index.tsx @@ -0,0 +1,2 @@ +// This file is required somehow. Test will fail if we remove the