From a4e2242b8dfa3241a9836911bce07771faa42db2 Mon Sep 17 00:00:00 2001 From: DarkSky <25152247+darkskygit@users.noreply.github.com> Date: Fri, 27 Feb 2026 22:56:43 +0800 Subject: [PATCH] chore: bump playwright (#13947) ## Summary by CodeRabbit * **Chores** * Updated Playwright test tooling to 1.58.2 across the repository and test packages. * **Tests** * Improved end-to-end robustness: replaced fragile timing/coordinate logic with element-based interactions, added polling/retry checks for flaky asserts and async state, and simplified input/rename flows to reduce test flakiness. --- package.json | 2 +- tests/affine-cloud-copilot/package.json | 2 +- tests/affine-cloud/package.json | 2 +- tests/affine-desktop-cloud/package.json | 2 +- tests/affine-desktop/package.json | 4 +- tests/affine-local/e2e/quick-search.spec.ts | 13 +++- tests/affine-local/package.json | 2 +- tests/affine-mobile/package.json | 2 +- tests/blocksuite/e2e/attachment.spec.ts | 17 ++-- .../inline/inline-editor.spec.ts | 35 +++++---- .../blocksuite/e2e/utils/actions/edgeless.ts | 8 +- tests/blocksuite/e2e/utils/actions/misc.ts | 78 +++++++++++++------ tests/blocksuite/e2e/utils/asserts.ts | 70 ++++++++++------- tests/blocksuite/package.json | 2 +- tests/kit/package.json | 2 +- yarn.lock | 48 ++++++------ 16 files changed, 170 insertions(+), 119 deletions(-) diff --git a/package.json b/package.json index 71ffb21f79..e89c8b981c 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,7 @@ "@faker-js/faker": "^10.1.0", "@istanbuljs/schema": "^0.1.3", "@magic-works/i18n-codegen": "^0.6.1", - "@playwright/test": "=1.52.0", + "@playwright/test": "=1.58.2", "@smarttools/eslint-plugin-rxjs": "^1.0.8", "@taplo/cli": "^0.7.0", "@toeverything/infra": "workspace:*", diff --git a/tests/affine-cloud-copilot/package.json b/tests/affine-cloud-copilot/package.json index 8aac7e2ed1..a81b2af191 100644 --- a/tests/affine-cloud-copilot/package.json +++ b/tests/affine-cloud-copilot/package.json @@ -7,7 +7,7 @@ }, "devDependencies": { "@affine-test/kit": "workspace:*", - "@playwright/test": "=1.52.0" + "@playwright/test": "=1.58.2" }, "version": "0.26.3" } diff --git a/tests/affine-cloud/package.json b/tests/affine-cloud/package.json index 3be53c02c1..afb50235bb 100644 --- a/tests/affine-cloud/package.json +++ b/tests/affine-cloud/package.json @@ -7,7 +7,7 @@ }, "devDependencies": { "@affine-test/kit": "workspace:*", - "@playwright/test": "=1.52.0" + "@playwright/test": "=1.58.2" }, "version": "0.26.3" } diff --git a/tests/affine-desktop-cloud/package.json b/tests/affine-desktop-cloud/package.json index 4a8ca27b84..c0ed9e39dd 100644 --- a/tests/affine-desktop-cloud/package.json +++ b/tests/affine-desktop-cloud/package.json @@ -7,7 +7,7 @@ }, "devDependencies": { "@affine-test/kit": "workspace:*", - "@playwright/test": "=1.52.0" + "@playwright/test": "=1.58.2" }, "version": "0.26.3" } diff --git a/tests/affine-desktop/package.json b/tests/affine-desktop/package.json index e8da361308..653a2f6327 100644 --- a/tests/affine-desktop/package.json +++ b/tests/affine-desktop/package.json @@ -8,10 +8,10 @@ "devDependencies": { "@affine-test/kit": "workspace:*", "@affine/electron-api": "workspace:*", - "@playwright/test": "=1.52.0", + "@playwright/test": "=1.58.2", "@types/fs-extra": "^11.0.4", "fs-extra": "^11.2.0", - "playwright": "=1.52.0" + "playwright": "=1.58.2" }, "version": "0.26.3" } diff --git a/tests/affine-local/e2e/quick-search.spec.ts b/tests/affine-local/e2e/quick-search.spec.ts index a3a77d5442..a6e4935d3f 100644 --- a/tests/affine-local/e2e/quick-search.spec.ts +++ b/tests/affine-local/e2e/quick-search.spec.ts @@ -417,12 +417,19 @@ test('Create a new page with special characters in the title and search for this await clickNewPageButton(page); await getBlockSuiteEditorTitle(page).click(); await getBlockSuiteEditorTitle(page).fill(specialTitle); + await page.keyboard.press('Enter'); + await expect(getBlockSuiteEditorTitle(page)).toContainText(specialTitle); await openQuickSearchByShortcut(page); await insertInputText(page, specialTitle); - await page.waitForTimeout(1000); - - await assertResultList(page, [specialTitle, specialTitle]); + await expect + .poll(async () => { + const labels = await page + .locator('[cmdk-item] [data-testid=cmdk-label]') + .allInnerTexts(); + return labels.some(label => label.split('\n').includes(specialTitle)); + }) + .toBe(true); await page.keyboard.press('Enter'); await page.waitForTimeout(1000); await assertTitle(page, specialTitle); diff --git a/tests/affine-local/package.json b/tests/affine-local/package.json index f0ddadfb4b..c4e8a75aaf 100644 --- a/tests/affine-local/package.json +++ b/tests/affine-local/package.json @@ -9,7 +9,7 @@ "@affine-test/kit": "workspace:*", "@affine-tools/cli": "workspace:*", "@affine-tools/utils": "workspace:*", - "@playwright/test": "=1.52.0", + "@playwright/test": "=1.58.2", "webpack": "^5.102.1" }, "version": "0.26.3" diff --git a/tests/affine-mobile/package.json b/tests/affine-mobile/package.json index bf87587b03..bfcf167055 100644 --- a/tests/affine-mobile/package.json +++ b/tests/affine-mobile/package.json @@ -7,7 +7,7 @@ }, "devDependencies": { "@affine-test/kit": "workspace:*", - "@playwright/test": "=1.52.0" + "@playwright/test": "=1.58.2" }, "version": "0.26.3" } diff --git a/tests/blocksuite/e2e/attachment.spec.ts b/tests/blocksuite/e2e/attachment.spec.ts index d6d81fa044..5f633aeb04 100644 --- a/tests/blocksuite/e2e/attachment.spec.ts +++ b/tests/blocksuite/e2e/attachment.spec.ts @@ -15,7 +15,6 @@ import { pressShiftTab, pressTab, redoByKeyboard, - SHORT_KEY, type, undoByKeyboard, } from './utils/actions/keyboard.js'; @@ -113,11 +112,13 @@ function getAttachment(page: Page) { await attachment.click(); await expect(toolbar).toBeVisible(); await renameBtn.click(); - await page.keyboard.press(`${SHORT_KEY}+a`, { delay: 50 }); - await pressBackspace(page); - await type(page, newName); + await expect(renameInput).toBeVisible(); + await renameInput.fill(newName); await pressEnter(page); - expect(await getName()).toContain(newName); + await expect(renameInput).not.toBeVisible(); + if (newName.length > 0) { + await expect.poll(getName).toContain(newName); + } }, // external @@ -215,11 +216,11 @@ test('should rename attachment works', async ({ page }) => { await expect(renameInput).not.toBeVisible(); await rename('new-name'); - expect(await getName()).toBe('new-name.png'); + await expect.poll(getName).toBe('new-name.png'); await rename(''); - expect(await getName()).toBe('.png'); + await expect.poll(getName).toBe('.png'); await rename('abc'); - expect(await getName()).toBe('abc'); + await expect.poll(getName).toBe('abc'); }); test('should turn attachment to image works', async ({ page }, testInfo) => { diff --git a/tests/blocksuite/e2e/cross-platform/inline/inline-editor.spec.ts b/tests/blocksuite/e2e/cross-platform/inline/inline-editor.spec.ts index 090699cee5..6ee037d35d 100644 --- a/tests/blocksuite/e2e/cross-platform/inline/inline-editor.spec.ts +++ b/tests/blocksuite/e2e/cross-platform/inline/inline-editor.spec.ts @@ -143,17 +143,20 @@ async function assertSelection( rangeIndex: number, rangeLength = 0 ) { - const actual = await page.evaluate( - ([richTextIndex]) => { - const richText = - document?.querySelectorAll('test-rich-text')[richTextIndex]; - // @ts-expect-error getInlineRange - const inlineEditor = richText.inlineEditor; - return inlineEditor?.getInlineRange(); - }, - [richTextIndex] - ); - expect(actual).toEqual({ index: rangeIndex, length: rangeLength }); + await expect + .poll(async () => { + return page.evaluate( + ([richTextIndex]) => { + const richText = + document?.querySelectorAll('test-rich-text')[richTextIndex]; + // @ts-expect-error getInlineRange + const inlineEditor = richText.inlineEditor; + return inlineEditor?.getInlineRange(); + }, + [richTextIndex] + ); + }) + .toEqual({ index: rangeIndex, length: rangeLength }); } test('basic input', async ({ page, browserName }) => { @@ -1113,16 +1116,14 @@ test('embed', async ({ page }) => { await assertSelection(page, 0, 3, 1); // try to update cursor position and select embed element by clicking embed element - let rect = await getInlineRangeIndexRect(page, [0, 1]); - await page.mouse.click(rect.x + 3, rect.y); + const embeds = page.locator('[data-v-embed="true"]'); + await embeds.nth(0).click(); await assertSelection(page, 0, 1, 1); - rect = await getInlineRangeIndexRect(page, [0, 2]); - await page.mouse.click(rect.x + 3, rect.y); + await embeds.nth(1).click(); await assertSelection(page, 0, 2, 1); - rect = await getInlineRangeIndexRect(page, [0, 3]); - await page.mouse.click(rect.x + 3, rect.y); + await embeds.nth(2).click(); await assertSelection(page, 0, 3, 1); }); diff --git a/tests/blocksuite/e2e/utils/actions/edgeless.ts b/tests/blocksuite/e2e/utils/actions/edgeless.ts index 7aa505c47f..3828fc8d85 100644 --- a/tests/blocksuite/e2e/utils/actions/edgeless.ts +++ b/tests/blocksuite/e2e/utils/actions/edgeless.ts @@ -820,10 +820,10 @@ export async function updateExistedBrushElementSize( page: Page, nthSizeButton: 1 | 2 | 3 | 4 | 5 | 6 ) { - // get the nth brush size button - const btn = page.locator( - `edgeless-line-width-panel .point-button:nth-child(${nthSizeButton})` - ); + // pick from the visible panel to avoid strict-mode collisions from hidden/duplicate toolbars + const btn = page + .locator('edgeless-line-width-panel:visible .point-button') + .nth(nthSizeButton - 1); await btn.click(); } diff --git a/tests/blocksuite/e2e/utils/actions/misc.ts b/tests/blocksuite/e2e/utils/actions/misc.ts index 9cb928da79..f2d37644f6 100644 --- a/tests/blocksuite/e2e/utils/actions/misc.ts +++ b/tests/blocksuite/e2e/utils/actions/misc.ts @@ -1015,31 +1015,63 @@ export async function getIndexCoordinate( [richTextIndex, vIndex]: [number, number], coordOffSet: { x: number; y: number } = { x: 0, y: 0 } ) { - const coord = await page.evaluate( - ({ richTextIndex, vIndex, coordOffSet, currentEditorIndex }) => { - const editorHost = - document.querySelectorAll('editor-host')[currentEditorIndex]; - const richText = editorHost.querySelectorAll('rich-text')[ - richTextIndex - ] as any; - const domRange = richText.inlineEditor.toDomRange({ - index: vIndex, - length: 0, - }); - const pointBound = domRange.getBoundingClientRect(); - return { - x: pointBound.left + coordOffSet.x, - y: pointBound.top + pointBound.height / 2 + coordOffSet.y, - }; - }, - { - richTextIndex, - vIndex, - coordOffSet, - currentEditorIndex, + for (let attempt = 0; attempt < 20; attempt++) { + const coord = await page.evaluate( + ({ richTextIndex, vIndex, coordOffSet, currentEditorIndex }) => { + const editorHost = + document.querySelectorAll('editor-host')[currentEditorIndex]; + const richTexts = Array.from( + editorHost?.querySelectorAll('rich-text') ?? [] + ); + if (!richTexts.length) { + return null; + } + const richText = richTexts[ + Math.min(richTextIndex, richTexts.length - 1) + ] as any; + const inlineEditor = richText?.inlineEditor; + if (!inlineEditor) { + return null; + } + const clampedIndex = Math.max( + 0, + Math.min(vIndex, inlineEditor.yTextLength ?? vIndex) + ); + const domRange = inlineEditor.toDomRange({ + index: clampedIndex, + length: 0, + }); + if (!domRange) { + return null; + } + const pointBound = domRange.getBoundingClientRect(); + if ( + !Number.isFinite(pointBound.left) || + !Number.isFinite(pointBound.top) + ) { + return null; + } + return { + x: pointBound.left + coordOffSet.x, + y: pointBound.top + pointBound.height / 2 + coordOffSet.y, + }; + }, + { + richTextIndex, + vIndex, + coordOffSet, + currentEditorIndex, + } + ); + if (coord) { + return coord; } + await page.waitForTimeout(50); + } + + throw new Error( + `Failed to get index coordinate: richTextIndex=${richTextIndex}, vIndex=${vIndex}` ); - return coord; } export function inlineEditorInnerTextToString(innerText: string): string { diff --git a/tests/blocksuite/e2e/utils/asserts.ts b/tests/blocksuite/e2e/utils/asserts.ts index 61471815a4..fbc4160d80 100644 --- a/tests/blocksuite/e2e/utils/asserts.ts +++ b/tests/blocksuite/e2e/utils/asserts.ts @@ -159,17 +159,20 @@ export async function assertTextContain(page: Page, text: string, i = 0) { } export async function assertRichTexts(page: Page, texts: string[]) { - const actualTexts = await page.evaluate(() => { - const editorHost = document.querySelector('editor-host'); - const richTexts = Array.from( - editorHost?.querySelectorAll('rich-text') ?? [] - ); - return richTexts.map(richText => { - const editor = richText.inlineEditor as AffineInlineEditor; - return editor.yText.toString(); - }); - }); - expect(actualTexts).toEqual(texts); + await expect + .poll(async () => { + return page.evaluate(() => { + const editorHost = document.querySelector('editor-host'); + const richTexts = Array.from( + editorHost?.querySelectorAll('rich-text') ?? [] + ); + return richTexts.map(richText => { + const editor = richText.inlineEditor as AffineInlineEditor; + return editor.yText.toString(); + }); + }); + }) + .toEqual(texts); } export async function assertEdgelessCanvasText(page: Page, text: string) { @@ -274,16 +277,20 @@ export async function assertRichTextInlineRange( rangeIndex: number, rangeLength = 0 ) { - const actual = await page.evaluate( - ([richTextIndex]) => { - const editorHost = document.querySelector('editor-host'); - const richText = editorHost?.querySelectorAll('rich-text')[richTextIndex]; - const inlineEditor = richText?.inlineEditor; - return inlineEditor?.getInlineRange(); - }, - [richTextIndex] - ); - expect(actual).toEqual({ index: rangeIndex, length: rangeLength }); + await expect + .poll(async () => { + return page.evaluate( + ([richTextIndex]) => { + const editorHost = document.querySelector('editor-host'); + const richText = + editorHost?.querySelectorAll('rich-text')[richTextIndex]; + const inlineEditor = richText?.inlineEditor; + return inlineEditor?.getInlineRange(); + }, + [richTextIndex] + ); + }) + .toEqual({ index: rangeIndex, length: rangeLength }); } export async function assertNativeSelectionRangeCount( @@ -1137,15 +1144,18 @@ export async function assertNoteSequence(page: Page, expected: string) { } export async function assertBlockSelections(page: Page, paths: string[]) { - const selections = await page.evaluate(() => { - const host = document.querySelector('editor-host'); - if (!host) { - throw new Error('editor-host host not found'); - } - return host.selection.value.filter(b => b.type === 'block'); - }); - const actualPaths = selections.map(selection => selection.blockId); - expect(actualPaths).toEqual(paths); + await expect + .poll(async () => { + const selections = await page.evaluate(() => { + const host = document.querySelector('editor-host'); + if (!host) { + throw new Error('editor-host host not found'); + } + return host.selection.value.filter(b => b.type === 'block'); + }); + return selections.map(selection => selection.blockId); + }) + .toEqual(paths); } export async function assertTextSelection( diff --git a/tests/blocksuite/package.json b/tests/blocksuite/package.json index 461a235430..af474a2fbf 100644 --- a/tests/blocksuite/package.json +++ b/tests/blocksuite/package.json @@ -9,7 +9,7 @@ "@affine-test/kit": "workspace:*", "@blocksuite/affine": "workspace:*", "@blocksuite/integration-test": "workspace:*", - "@playwright/test": "=1.52.0", + "@playwright/test": "=1.58.2", "@toeverything/theme": "^1.1.23", "json-stable-stringify": "^1.2.1", "rxjs": "^7.8.2" diff --git a/tests/kit/package.json b/tests/kit/package.json index 1a97b4c9f0..f91ac9e861 100644 --- a/tests/kit/package.json +++ b/tests/kit/package.json @@ -14,7 +14,7 @@ "@affine-tools/utils": "workspace:*", "@blocksuite/affine": "workspace:*", "@node-rs/argon2": "^2.0.2", - "@playwright/test": "=1.52.0", + "@playwright/test": "=1.58.2", "@toeverything/infra": "workspace:*", "express": "^5.0.0", "http-proxy-middleware": "^3.0.3" diff --git a/yarn.lock b/yarn.lock index a00e9bb446..7d8eb17994 100644 --- a/yarn.lock +++ b/yarn.lock @@ -24,7 +24,7 @@ __metadata: resolution: "@affine-test/affine-cloud-copilot@workspace:tests/affine-cloud-copilot" dependencies: "@affine-test/kit": "workspace:*" - "@playwright/test": "npm:=1.52.0" + "@playwright/test": "npm:=1.58.2" languageName: unknown linkType: soft @@ -33,7 +33,7 @@ __metadata: resolution: "@affine-test/affine-cloud@workspace:tests/affine-cloud" dependencies: "@affine-test/kit": "workspace:*" - "@playwright/test": "npm:=1.52.0" + "@playwright/test": "npm:=1.58.2" languageName: unknown linkType: soft @@ -42,7 +42,7 @@ __metadata: resolution: "@affine-test/affine-desktop-cloud@workspace:tests/affine-desktop-cloud" dependencies: "@affine-test/kit": "workspace:*" - "@playwright/test": "npm:=1.52.0" + "@playwright/test": "npm:=1.58.2" languageName: unknown linkType: soft @@ -52,10 +52,10 @@ __metadata: dependencies: "@affine-test/kit": "workspace:*" "@affine/electron-api": "workspace:*" - "@playwright/test": "npm:=1.52.0" + "@playwright/test": "npm:=1.58.2" "@types/fs-extra": "npm:^11.0.4" fs-extra: "npm:^11.2.0" - playwright: "npm:=1.52.0" + playwright: "npm:=1.58.2" languageName: unknown linkType: soft @@ -66,7 +66,7 @@ __metadata: "@affine-test/kit": "workspace:*" "@affine-tools/cli": "workspace:*" "@affine-tools/utils": "workspace:*" - "@playwright/test": "npm:=1.52.0" + "@playwright/test": "npm:=1.58.2" webpack: "npm:^5.102.1" languageName: unknown linkType: soft @@ -76,7 +76,7 @@ __metadata: resolution: "@affine-test/affine-mobile@workspace:tests/affine-mobile" dependencies: "@affine-test/kit": "workspace:*" - "@playwright/test": "npm:=1.52.0" + "@playwright/test": "npm:=1.58.2" languageName: unknown linkType: soft @@ -87,7 +87,7 @@ __metadata: "@affine-test/kit": "workspace:*" "@blocksuite/affine": "workspace:*" "@blocksuite/integration-test": "workspace:*" - "@playwright/test": "npm:=1.52.0" + "@playwright/test": "npm:=1.58.2" "@toeverything/theme": "npm:^1.1.23" json-stable-stringify: "npm:^1.2.1" rxjs: "npm:^7.8.2" @@ -101,7 +101,7 @@ __metadata: "@affine-tools/utils": "workspace:*" "@blocksuite/affine": "workspace:*" "@node-rs/argon2": "npm:^2.0.2" - "@playwright/test": "npm:=1.52.0" + "@playwright/test": "npm:=1.58.2" "@toeverything/infra": "workspace:*" express: "npm:^5.0.0" http-proxy-middleware: "npm:^3.0.3" @@ -809,7 +809,7 @@ __metadata: "@faker-js/faker": "npm:^10.1.0" "@istanbuljs/schema": "npm:^0.1.3" "@magic-works/i18n-codegen": "npm:^0.6.1" - "@playwright/test": "npm:=1.52.0" + "@playwright/test": "npm:=1.58.2" "@smarttools/eslint-plugin-rxjs": "npm:^1.0.8" "@taplo/cli": "npm:^0.7.0" "@toeverything/infra": "workspace:*" @@ -10900,14 +10900,14 @@ __metadata: languageName: node linkType: hard -"@playwright/test@npm:=1.52.0": - version: 1.52.0 - resolution: "@playwright/test@npm:1.52.0" +"@playwright/test@npm:=1.58.2": + version: 1.58.2 + resolution: "@playwright/test@npm:1.58.2" dependencies: - playwright: "npm:1.52.0" + playwright: "npm:1.58.2" bin: playwright: cli.js - checksum: 10/e18a4eb626c7bc6cba212ff2e197cf9ae2e4da1c91bfdf08a744d62e27222751173e4b220fa27da72286a89a3b4dea7c09daf384d23708f284b64f98e9a63a88 + checksum: 10/58bf90139280a0235eeeb6049e9fb4db6425e98be1bf0cc17913b068eef616cf67be57bfb36dc4cb56bcf116f498ffd0225c4916e85db404b343ea6c5efdae13 languageName: node linkType: hard @@ -31101,27 +31101,27 @@ __metadata: languageName: node linkType: hard -"playwright-core@npm:1.52.0": - version: 1.52.0 - resolution: "playwright-core@npm:1.52.0" +"playwright-core@npm:1.58.2": + version: 1.58.2 + resolution: "playwright-core@npm:1.58.2" bin: playwright-core: cli.js - checksum: 10/42e13f5f98dc25ebc95525fb338a215b9097b2ba39d41e99972a190bf75d79979f163f5bc07b1ca06847ee07acb2c9b487d070fab67e9cd55e33310fc05aca3c + checksum: 10/8a98fcf122167e8703d525db2252de0e3da4ab9110ab6ea9951247e52d846310eb25ea2c805e1b7ccb54b4010c44e5adc3a76aae6da02f34324ccc3e76683bb1 languageName: node linkType: hard -"playwright@npm:1.52.0, playwright@npm:=1.52.0": - version: 1.52.0 - resolution: "playwright@npm:1.52.0" +"playwright@npm:1.58.2, playwright@npm:=1.58.2": + version: 1.58.2 + resolution: "playwright@npm:1.58.2" dependencies: fsevents: "npm:2.3.2" - playwright-core: "npm:1.52.0" + playwright-core: "npm:1.58.2" dependenciesMeta: fsevents: optional: true bin: playwright: cli.js - checksum: 10/214175446089000c2ac997b925063b95f7d86d129c5d7c74caa5ddcb05bcad598dfd569d2133a10dc82d288bf67e7858877dcd099274b0b928b9c63db7d6ecec + checksum: 10/d89d6c8a32388911b9aff9ee0f1a90076219f15c804f2b287db048b9e9cde182aea3131fac1959051d25189ed4218ec4272b137c83cd7f9cd24781cbc77edd86 languageName: node linkType: hard