fix(editor): ci stability (#14704)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Chores**
* Improved Electron shutdown, diagnostics and tab teardown for more
reliable exits and forced cleanup on stubborn processes.
* **Tests**
* Added polling-based test helpers, stronger scroll/page readiness,
timeout-tolerant page selection, and async cleanup/worker teardown;
updated many tests to wait for UI/model updates and rendering frames.
* **Bug Fixes**
* Reduced flakiness by awaiting paragraph visibility, nested counts,
selection/navigation stability, tab counts, post-action renders, and
safer element interactions.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
DarkSky
2026-03-23 16:25:15 +08:00
committed by GitHub
parent 8ba02ed6fb
commit dcf041a3f2
17 changed files with 619 additions and 256 deletions

View File

@@ -14,7 +14,7 @@ import {
waitForEditorLoad,
} from '@affine-test/kit/utils/page-logic';
import type { ParagraphBlockComponent } from '@blocksuite/affine-block-paragraph';
import { expect } from '@playwright/test';
import { expect, type Locator } from '@playwright/test';
test.beforeEach(async ({ page }) => {
await openHomePage(page);
@@ -22,6 +22,44 @@ test.beforeEach(async ({ page }) => {
await waitForEditorLoad(page);
});
async function expectParagraphState(
paragraphs: Locator,
index: number,
expectedType: string,
expectedText: string
) {
await expect
.poll(async () => {
return await paragraphs
.nth(index)
.evaluate(
(
block: ParagraphBlockComponent,
expected: { type: string; text: string }
) =>
block.model.props.type === expected.type &&
block.model.props.text.toString() === expected.text,
{
type: expectedType,
text: expectedText,
}
);
})
.toBeTruthy();
}
async function expectParagraphVisibility(
paragraphs: Locator,
index: number,
visible: boolean
) {
await expect
.poll(async () => {
return await paragraphs.nth(index).isVisible();
})
.toBe(visible);
}
test('heading icon should be updated after change heading level', async ({
page,
}) => {
@@ -320,26 +358,9 @@ test('also move children when dedent collapsed heading', async ({ page }) => {
await subParagraph.nth(0).click();
await pressShiftTab(page);
expect(await subParagraph.count()).toBe(0);
expect(
await paragraph
.nth(1)
.evaluate(
(block: ParagraphBlockComponent) =>
block.model.props.type === 'h1' &&
block.model.props.text.toString() === 'bbb'
)
).toBeTruthy();
expect(
await paragraph
.nth(2)
.evaluate(
(block: ParagraphBlockComponent) =>
block.model.props.type === 'text' &&
block.model.props.text.toString() === 'ccc'
)
).toBeTruthy();
expect(await paragraph.nth(2).isVisible()).toBeFalsy();
await expectParagraphState(paragraph, 1, 'h1', 'bbb');
await expectParagraphState(paragraph, 2, 'text', 'ccc');
await expectParagraphVisibility(paragraph, 2, false);
await paragraph
.nth(1)
.locator('blocksuite-toggle-button .toggle-icon')
@@ -349,7 +370,7 @@ test('also move children when dedent collapsed heading', async ({ page }) => {
y: 5,
},
});
expect(await paragraph.nth(2).isVisible()).toBeTruthy();
await expectParagraphVisibility(paragraph, 2, true);
});
test('also move collapsed siblings when indent collapsed heading', async ({
@@ -433,23 +454,19 @@ test('unfold collapsed heading when its other blocks indented to be its sibling'
*/
const paragraph = page.locator('affine-note affine-paragraph');
expect(await paragraph.nth(2).isVisible()).toBeTruthy();
expect(
await paragraph
.nth(2)
.evaluate(
(block: ParagraphBlockComponent) =>
block.model.props.type === 'text' &&
block.model.props.text.toString() === 'ccc'
)
).toBeTruthy();
await expectParagraphVisibility(paragraph, 2, true);
await expectParagraphState(paragraph, 2, 'text', 'ccc');
await paragraph.locator('blocksuite-toggle-button .toggle-icon').click();
expect(await paragraph.nth(2).isVisible()).toBeFalsy();
await expectParagraphVisibility(paragraph, 2, false);
await paragraph.nth(3).click(); // ddd
expect(await paragraph.nth(2).isVisible()).toBeFalsy();
expect(await paragraph.nth(0).locator('affine-paragraph').count()).toBe(2);
await expectParagraphVisibility(paragraph, 2, false);
await expect
.poll(() => paragraph.nth(0).locator('affine-paragraph').count())
.toBe(2);
await pressTab(page);
expect(await paragraph.nth(0).locator('affine-paragraph').count()).toBe(3);
expect(await paragraph.nth(2).isVisible()).toBeTruthy();
await expect
.poll(() => paragraph.nth(0).locator('affine-paragraph').count())
.toBe(3);
await expectParagraphVisibility(paragraph, 2, true);
});