Compare commits

...

1 Commits

Author SHA1 Message Date
Ashwin Bhatkal
1e887dc9c9 chore(e2eci): source Playwright browsers from official image (#11789)
Some checks are pending
build-staging / prepare (push) Waiting to run
build-staging / js-build (push) Blocked by required conditions
build-staging / go-build (push) Blocked by required conditions
build-staging / staging (push) Blocked by required conditions
Release Drafter / update_release_draft (push) Waiting to run
* chore(e2eci): source Playwright browsers from official image

Replace the runtime `pnpm playwright install` (which fetches browser
binaries from the Playwright CDN and intermittently times out) with a
copy out of the official `mcr.microsoft.com/playwright:v1.57.0-noble`
image. The job stays on ubuntu-latest so the testcontainers-based
backend bring-up is untouched; only OS deps are still installed via apt
(`install-deps`), which does not hit the flaky CDN.

Bump @playwright/test from the 1.57.0 alpha to stable 1.57.0 so the
client version matches the image tag (browser builds line up).

Closes #11772

* fix(e2e): open panel ⋮ menu via click, not hover (#11881)
2026-06-28 12:15:55 +00:00
6 changed files with 38 additions and 48 deletions

View File

@@ -70,7 +70,11 @@ jobs:
cd tests/e2e && pnpm install --frozen-lockfile
- name: playwright-browsers
run: |
cd tests/e2e && pnpm playwright install --with-deps ${{ matrix.project }}
docker create --name pw mcr.microsoft.com/playwright:v1.57.0-noble
docker cp pw:/ms-playwright "$RUNNER_TEMP/ms-playwright"
docker rm pw
echo "PLAYWRIGHT_BROWSERS_PATH=$RUNNER_TEMP/ms-playwright" >> "$GITHUB_ENV"
cd tests/e2e && pnpm playwright install-deps ${{ matrix.project }}
- name: bring-up-stack
run: |
cd tests && \

View File

@@ -32,7 +32,7 @@
"author": "",
"license": "MIT",
"devDependencies": {
"@playwright/test": "^1.57.0-alpha-2025-10-09",
"@playwright/test": "1.57.0",
"@types/node": "^20.0.0",
"dotenv": "^16.0.0",
"eslint-plugin-playwright": "^2.10.2",

View File

@@ -9,8 +9,8 @@ importers:
.:
devDependencies:
'@playwright/test':
specifier: ^1.57.0-alpha-2025-10-09
version: 1.57.0-alpha-2025-10-11
specifier: 1.57.0
version: 1.57.0
'@types/node':
specifier: ^20.0.0
version: 20.19.20
@@ -132,56 +132,48 @@ packages:
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@oxfmt/binding-linux-arm64-musl@0.41.0':
resolution: {integrity: sha512-VfVZxL0+6RU86T8F8vKiDBa+iHsr8PAjQmKGBzSCAX70b6x+UOMFl+2dNihmKmUwqkCazCPfYjt6SuAPOeQJ3g==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [linux]
libc: [musl]
'@oxfmt/binding-linux-ppc64-gnu@0.41.0':
resolution: {integrity: sha512-bwzokz2eGvdfJbc0i+zXMJ4BBjQPqg13jyWpEEZDOrBCQ91r8KeY2Mi2kUeuMTZNFXju+jcAbAbpyJxRGla0eg==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [ppc64]
os: [linux]
libc: [glibc]
'@oxfmt/binding-linux-riscv64-gnu@0.41.0':
resolution: {integrity: sha512-POLM//PCH9uqDeNDwWL3b3DkMmI3oI2cU6hwc2lnztD1o7dzrQs3R9nq555BZ6wI7t2lyhT9CS+CRaz5X0XqLA==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [riscv64]
os: [linux]
libc: [glibc]
'@oxfmt/binding-linux-riscv64-musl@0.41.0':
resolution: {integrity: sha512-NNK7PzhFqLUwx/G12Xtm6scGv7UITvyGdAR5Y+TlqsG+essnuRWR4jRNODWRjzLZod0T3SayRbnkSIWMBov33w==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [riscv64]
os: [linux]
libc: [musl]
'@oxfmt/binding-linux-s390x-gnu@0.41.0':
resolution: {integrity: sha512-qVf/zDC5cN9eKe4qI/O/m445er1IRl6swsSl7jHkqmOSVfknwCe5JXitYjZca+V/cNJSU/xPlC5EFMabMMFDpw==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [s390x]
os: [linux]
libc: [glibc]
'@oxfmt/binding-linux-x64-gnu@0.41.0':
resolution: {integrity: sha512-ojxYWu7vUb6ysYqVCPHuAPVZHAI40gfZ0PDtZAMwVmh2f0V8ExpPIKoAKr7/8sNbAXJBBpZhs2coypIo2jJX4w==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [linux]
libc: [glibc]
'@oxfmt/binding-linux-x64-musl@0.41.0':
resolution: {integrity: sha512-O2exZLBxoCMIv2vlvcbkdedazJPTdG0VSup+0QUCfYQtx751zCZNboX2ZUOiQ/gDTdhtXvSiot0h6GEGkOyalA==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [linux]
libc: [musl]
'@oxfmt/binding-openharmony-arm64@0.41.0':
resolution: {integrity: sha512-N+31/VoL+z+NNBt8viy3I4NaIdPbiYeOnB884LKqvXldaE2dRztdPv3q5ipfZYv0RwFp7JfqS4I27K/DSHCakg==}
@@ -284,56 +276,48 @@ packages:
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@oxlint/binding-linux-arm64-musl@1.61.0':
resolution: {integrity: sha512-bl1dQh8LnVqsj6oOQAcxwbuOmNJkwc4p6o//HTBZhNTzJy21TLDwAviMqUFNUxDHkPGpmdKTSN4tWTjLryP8xg==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [linux]
libc: [musl]
'@oxlint/binding-linux-ppc64-gnu@1.61.0':
resolution: {integrity: sha512-QoOX6KB2IiEpyOj/HKqaxi+NQHPnOgNgnr22n9N4ANJCzXkUlj1UmeAbFb4PpqdlHIzvGDM5xZ0OKtcLq9RhiQ==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [ppc64]
os: [linux]
libc: [glibc]
'@oxlint/binding-linux-riscv64-gnu@1.61.0':
resolution: {integrity: sha512-1TGcTerjY6p152wCof3oKElccq3xHljS/Mucp04gV/4ATpP6nO7YNnp7opEg6SHkv2a57/b4b8Ndm9znJ1/qAw==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [riscv64]
os: [linux]
libc: [glibc]
'@oxlint/binding-linux-riscv64-musl@1.61.0':
resolution: {integrity: sha512-65wXEmZIrX2ADwC8i/qFL4EWLSbeuBpAm3suuX1vu4IQkKd+wLT/HU/BOl84kp91u2SxPkPDyQgu4yrqp8vwVA==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [riscv64]
os: [linux]
libc: [musl]
'@oxlint/binding-linux-s390x-gnu@1.61.0':
resolution: {integrity: sha512-TVvhgMvor7Qa6COeXxCJ7ENOM+lcAOGsQ0iUdPSCv2hxb9qSHLQ4XF1h50S6RE1gBOJ0WV3rNukg4JJJP1LWRA==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [s390x]
os: [linux]
libc: [glibc]
'@oxlint/binding-linux-x64-gnu@1.61.0':
resolution: {integrity: sha512-SjpS5uYuFoDnDdZPwZE59ndF95AsY47R5MliuneTWR1pDm2CxGJaYXbKULI71t5TVfLQUWmrHEGRL9xvuq6dnA==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [linux]
libc: [glibc]
'@oxlint/binding-linux-x64-musl@1.61.0':
resolution: {integrity: sha512-gGfAeGD4sNJGILZbc/yKcIimO9wQnPMoYp9swAaKeEtwsSQAbU+rsdQze5SBtIP6j0QDzeYd4XSSUCRCF+LIeQ==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [linux]
libc: [musl]
'@oxlint/binding-openharmony-arm64@1.61.0':
resolution: {integrity: sha512-OlVT0LrG/ct33EVtWRyR+B/othwmDWeRxfi13wUdPeb3lAT5TgTcFDcfLfarZtzB4W1nWF/zICMgYdkggX2WmQ==}
@@ -359,8 +343,8 @@ packages:
cpu: [x64]
os: [win32]
'@playwright/test@1.57.0-alpha-2025-10-11':
resolution: {integrity: sha512-xqp2RNcLCPSUAYCrP3+rYZ4LFlESvWqjjpFegjNbun7wLcGvUt9Mh+RHBvgeZAhMxxuVde78XO9Y888UYFH9ew==}
'@playwright/test@1.57.0':
resolution: {integrity: sha512-6TyEnHgd6SArQO8UO2OMTxshln3QMWBtPGrOCgs3wVEmQmwyuNtB10IZMfmYDE0riwNR1cu4q+pPcxMVtaG3TA==}
engines: {node: '>=18'}
hasBin: true
@@ -594,13 +578,13 @@ packages:
resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
engines: {node: '>=8'}
playwright-core@1.57.0-alpha-2025-10-11:
resolution: {integrity: sha512-X6KAunryZlslAdEdlN5gIIP3sFU6Uot3vzLoGCZ9SNv0JvXd6e2g7ArjnpOQld36yKszq8J+wQJRlIvdXkIvRw==}
playwright-core@1.57.0:
resolution: {integrity: sha512-agTcKlMw/mjBWOnD6kFZttAAGHgi/Nw0CZ2o6JqWSbMlI219lAFLZZCyqByTsvVAJq5XA5H8cA6PrvBRpBWEuQ==}
engines: {node: '>=18'}
hasBin: true
playwright@1.57.0-alpha-2025-10-11:
resolution: {integrity: sha512-a80kAd59up/kURcKE7THLzx3lN6a1G9RhsgP9ZfLGL7WtnOhOdRLxbHwmjWUG11ybEDeYNpj1qwT02MT4R+rew==}
playwright@1.57.0:
resolution: {integrity: sha512-ilYQj1s8sr2ppEJ2YVadYBN0Mb3mdo9J0wQ+UuDhzYqURwSoW4n1Xs5vs7ORwgDGmyEh33tRMeS8KhdkMoLXQw==}
engines: {node: '>=18'}
hasBin: true
@@ -832,9 +816,9 @@ snapshots:
'@oxlint/binding-win32-x64-msvc@1.61.0':
optional: true
'@playwright/test@1.57.0-alpha-2025-10-11':
'@playwright/test@1.57.0':
dependencies:
playwright: 1.57.0-alpha-2025-10-11
playwright: 1.57.0
'@types/esrecurse@4.3.1': {}
@@ -1097,11 +1081,11 @@ snapshots:
path-key@3.1.1: {}
playwright-core@1.57.0-alpha-2025-10-11: {}
playwright-core@1.57.0: {}
playwright@1.57.0-alpha-2025-10-11:
playwright@1.57.0:
dependencies:
playwright-core: 1.57.0-alpha-2025-10-11
playwright-core: 1.57.0
optionalDependencies:
fsevents: 2.3.2

View File

@@ -392,17 +392,17 @@ test.describe('Dashboard Detail — Sections', () => {
page.getByText(panelName, { exact: true }).first(),
).toBeVisible();
// The panel ⋮ menu opens on HOVER (not click) — see
// `openPanelMoreMenu` in 21-panel-actions.spec.ts. Clicking the kebab
// can momentarily toggle the menu and immediately re-close it, racing
// the menuitem click on the next line. Use hover and wait for the
// menu role to be visible before clicking Delete.
// The panel ⋮ menu is a Radix `DropdownMenuSimple` — it opens on click,
// not hover (see `openPanelMoreMenu` in 21-panel-actions.spec.ts). The
// container hover only reveals the kebab (it's `visibility: hidden`
// until then); the click toggles the menu. Wait for the menu role to be
// visible before clicking Delete.
const panelTitle = page.getByText(panelName, { exact: true }).first();
await panelTitle.hover();
const panelContainer = panelTitle.locator('../..');
await panelContainer.scrollIntoViewIfNeeded();
await panelContainer.hover();
await panelContainer.getByTestId('widget-header-options').hover();
await panelContainer.getByTestId('widget-header-options').click();
const menu = page.getByRole('menu');
await menu.waitFor({ state: 'visible' });
await menu.getByRole('menuitem', { name: 'Delete', exact: true }).click();

View File

@@ -107,14 +107,15 @@ function panelContainer(page: Page, title: string, index = 0): Locator {
}
/**
* Hover the panel header (the ⋮ icon is CSS-hidden until the row is hovered)
* and open the action dropdown. Returns the opened menu locator.
* Reveal the panel header's ⋮ icon and open the action dropdown. Returns the
* opened menu locator.
*
* The antd `<Dropdown>` wrapping the ⋮ icon uses `trigger={['hover']}` (see
* `WidgetHeader/index.tsx`), so the menu opens on hover, not click —
* dispatching a click is a no-op. We hover the container first to reveal the
* icon (it's CSS-hidden until then) and then hover the icon itself to fire
* the antd Dropdown's mouseenter handler.
* The ⋮ icon is a `@signozhq/ui` `DropdownMenuSimple` (Radix
* `@radix-ui/react-dropdown-menu` under the hood — see `WidgetHeader/index.tsx`),
* so the menu opens on click, not hover. We still hover the container first
* because the icon is `visibility: hidden` until the row is hovered (see the
* `.widget-graph-component-container:hover` rule in `GridCardLayout.styles.scss`);
* then we click the revealed icon to toggle the Radix menu open.
*/
async function openPanelMoreMenu(
page: Page,
@@ -125,7 +126,7 @@ async function openPanelMoreMenu(
await container.scrollIntoViewIfNeeded();
await container.hover();
const moreOptions = container.getByTestId('widget-header-options');
await moreOptions.hover();
await moreOptions.click();
const menu = page.getByRole('menu');
await menu.waitFor({ state: 'visible' });
return menu;

View File

@@ -66,9 +66,10 @@ test.describe('Dashboard Detail — Edit Panel (entry-point only)', () => {
await container.hover();
const options = container.getByTestId('widget-header-options');
// The ⋮ uses an antd `Dropdown` with `trigger=['hover']`; firing a real
// hover (not `dispatchEvent('click')`) is what opens the menu.
await options.hover({ force: true });
// The ⋮ is a `@signozhq/ui` `DropdownMenuSimple` (Radix-based); it opens
// on click, not hover. The container hover above only reveals the icon
// (it's `visibility: hidden` until then) — the click toggles the menu.
await options.click();
await page.getByRole('menuitem', { name: 'Edit' }).click();