test: add mutex to clipboard copy & paste operation to reduce flaky (#11884)
This commit is contained in:
@@ -7,7 +7,6 @@ import {
|
|||||||
} from '@affine-test/kit/utils/editor';
|
} from '@affine-test/kit/utils/editor';
|
||||||
import { importImage } from '@affine-test/kit/utils/image';
|
import { importImage } from '@affine-test/kit/utils/image';
|
||||||
import {
|
import {
|
||||||
pasteByKeyboard,
|
|
||||||
selectAllByKeyboard,
|
selectAllByKeyboard,
|
||||||
writeTextToClipboard,
|
writeTextToClipboard,
|
||||||
} from '@affine-test/kit/utils/keyboard';
|
} from '@affine-test/kit/utils/keyboard';
|
||||||
@@ -253,7 +252,6 @@ test('should show toolbar when inline link is preceded by image or surface-ref',
|
|||||||
const url = new URL(page.url());
|
const url = new URL(page.url());
|
||||||
|
|
||||||
await writeTextToClipboard(page, url.toString());
|
await writeTextToClipboard(page, url.toString());
|
||||||
await pasteByKeyboard(page);
|
|
||||||
|
|
||||||
const toolbar = locateToolbar(page);
|
const toolbar = locateToolbar(page);
|
||||||
|
|
||||||
|
|||||||
@@ -64,7 +64,6 @@ test('not allowed to switch to embed view when linking to the same document', as
|
|||||||
const url0 = new URL(page.url());
|
const url0 = new URL(page.url());
|
||||||
|
|
||||||
await writeTextToClipboard(page, url0.toString());
|
await writeTextToClipboard(page, url0.toString());
|
||||||
await pasteByKeyboard(page);
|
|
||||||
|
|
||||||
const { toolbar, switchViewBtn, inlineViewBtn, cardViewBtn, embedViewBtn } =
|
const { toolbar, switchViewBtn, inlineViewBtn, cardViewBtn, embedViewBtn } =
|
||||||
toolbarButtons(page);
|
toolbarButtons(page);
|
||||||
@@ -296,7 +295,6 @@ test('allow switching to embed view when linking to the other document with mode
|
|||||||
await page.keyboard.press('Enter');
|
await page.keyboard.press('Enter');
|
||||||
|
|
||||||
await writeTextToClipboard(page, url.toString());
|
await writeTextToClipboard(page, url.toString());
|
||||||
await pasteByKeyboard(page);
|
|
||||||
|
|
||||||
// Inline
|
// Inline
|
||||||
await inlineLink.hover();
|
await inlineLink.hover();
|
||||||
@@ -516,9 +514,8 @@ test('the viewport should be fit when the linked document is with edgeless mode'
|
|||||||
|
|
||||||
// move viewport
|
// move viewport
|
||||||
const { x, y } = noteBoundingBox;
|
const { x, y } = noteBoundingBox;
|
||||||
await page.mouse.click(x - 10, y - 10);
|
await page.mouse.click(x - 10, y + 100);
|
||||||
await page.keyboard.down('Space');
|
await page.keyboard.down('Space');
|
||||||
await page.waitForTimeout(50);
|
|
||||||
await page.mouse.down();
|
await page.mouse.down();
|
||||||
await page.mouse.move(x + 1000, y);
|
await page.mouse.move(x + 1000, y);
|
||||||
await page.mouse.up();
|
await page.mouse.up();
|
||||||
@@ -538,7 +535,6 @@ test('the viewport should be fit when the linked document is with edgeless mode'
|
|||||||
await page.keyboard.press('Enter');
|
await page.keyboard.press('Enter');
|
||||||
|
|
||||||
await writeTextToClipboard(page, url.toString());
|
await writeTextToClipboard(page, url.toString());
|
||||||
await pasteByKeyboard(page);
|
|
||||||
|
|
||||||
// Inline
|
// Inline
|
||||||
await page.locator('affine-reference').hover();
|
await page.locator('affine-reference').hover();
|
||||||
@@ -608,7 +604,7 @@ test('should show edgeless content when switching card view of linked mode doc i
|
|||||||
await clickEdgelessModeButton(page);
|
await clickEdgelessModeButton(page);
|
||||||
|
|
||||||
await page.mouse.move(x, y);
|
await page.mouse.move(x, y);
|
||||||
await writeTextToClipboard(page, url.toString());
|
await writeTextToClipboard(page, url.toString(), false);
|
||||||
|
|
||||||
// Inline
|
// Inline
|
||||||
const embed = page.locator('affine-embed-edgeless-linked-doc-block');
|
const embed = page.locator('affine-embed-edgeless-linked-doc-block');
|
||||||
@@ -1116,7 +1112,6 @@ test('should show full email address', async ({ page }) => {
|
|||||||
await page.keyboard.press('Enter');
|
await page.keyboard.press('Enter');
|
||||||
|
|
||||||
await writeTextToClipboard(page, 'dev@affine.pro');
|
await writeTextToClipboard(page, 'dev@affine.pro');
|
||||||
await pasteByKeyboard(page);
|
|
||||||
|
|
||||||
const inlineLink = page.locator('affine-link');
|
const inlineLink = page.locator('affine-link');
|
||||||
|
|
||||||
@@ -1140,7 +1135,6 @@ test('should not show view toggle button when protocol of link is not http(s)',
|
|||||||
await page.keyboard.press('Enter');
|
await page.keyboard.press('Enter');
|
||||||
|
|
||||||
await writeTextToClipboard(page, 'ftp://affine.pro/blocksuite.pdf');
|
await writeTextToClipboard(page, 'ftp://affine.pro/blocksuite.pdf');
|
||||||
await pasteByKeyboard(page);
|
|
||||||
|
|
||||||
const inlineLink = page.locator('affine-link');
|
const inlineLink = page.locator('affine-link');
|
||||||
|
|
||||||
|
|||||||
@@ -515,8 +515,6 @@ test('can paste a doc link to create link reference', async ({ page }) => {
|
|||||||
// paste the url
|
// paste the url
|
||||||
await writeTextToClipboard(page, url);
|
await writeTextToClipboard(page, url);
|
||||||
|
|
||||||
// check the link reference
|
|
||||||
await page.waitForTimeout(500);
|
|
||||||
await expect(
|
await expect(
|
||||||
page.locator('affine-reference:has-text("Getting Started")')
|
page.locator('affine-reference:has-text("Getting Started")')
|
||||||
).toBeVisible();
|
).toBeVisible();
|
||||||
@@ -524,8 +522,6 @@ test('can paste a doc link to create link reference', async ({ page }) => {
|
|||||||
// can ctrl-z to revert to normal link
|
// can ctrl-z to revert to normal link
|
||||||
await page.keyboard.press('ControlOrMeta+z');
|
await page.keyboard.press('ControlOrMeta+z');
|
||||||
|
|
||||||
// check the normal link
|
|
||||||
await page.waitForTimeout(500);
|
|
||||||
await expect(page.locator(`affine-link:has-text("${url}")`)).toBeVisible();
|
await expect(page.locator(`affine-link:has-text("${url}")`)).toBeVisible();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
"@blocksuite/affine": "workspace:*",
|
"@blocksuite/affine": "workspace:*",
|
||||||
"@node-rs/argon2": "^2.0.2",
|
"@node-rs/argon2": "^2.0.2",
|
||||||
"@playwright/test": "=1.51.1",
|
"@playwright/test": "=1.51.1",
|
||||||
|
"@toeverything/infra": "workspace:*",
|
||||||
"express": "^5.0.0",
|
"express": "^5.0.0",
|
||||||
"http-proxy-middleware": "^3.0.3"
|
"http-proxy-middleware": "^3.0.3"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import type { Page } from '@playwright/test';
|
import { type Page } from '@playwright/test';
|
||||||
|
import { AsyncLock } from '@toeverything/infra/utils';
|
||||||
|
|
||||||
const IS_MAC = process.platform === 'darwin';
|
const IS_MAC = process.platform === 'darwin';
|
||||||
|
|
||||||
@@ -102,13 +103,18 @@ export async function undoByKeyboard(page: Page) {
|
|||||||
await keyUpCtrlOrMeta(page);
|
await keyUpCtrlOrMeta(page);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function writeTextToClipboard(page: Page, text: string) {
|
const clipboardMutex = new AsyncLock();
|
||||||
|
|
||||||
|
export async function writeTextToClipboard(
|
||||||
|
page: Page,
|
||||||
|
text: string,
|
||||||
|
paste = true
|
||||||
|
) {
|
||||||
|
using _release = await clipboardMutex.acquire();
|
||||||
// paste the url
|
// paste the url
|
||||||
await page.evaluate(
|
await page.evaluate(
|
||||||
async ([text]) => {
|
async ([text]) => {
|
||||||
const clipData = {
|
navigator.clipboard.writeText('');
|
||||||
'text/plain': text,
|
|
||||||
};
|
|
||||||
const e = new ClipboardEvent('paste', {
|
const e = new ClipboardEvent('paste', {
|
||||||
clipboardData: new DataTransfer(),
|
clipboardData: new DataTransfer(),
|
||||||
});
|
});
|
||||||
@@ -116,11 +122,14 @@ export async function writeTextToClipboard(page: Page, text: string) {
|
|||||||
writable: false,
|
writable: false,
|
||||||
value: document,
|
value: document,
|
||||||
});
|
});
|
||||||
Object.entries(clipData).forEach(([key, value]) => {
|
e.clipboardData!.setData('text/plain', text);
|
||||||
e.clipboardData?.setData(key, value);
|
|
||||||
});
|
|
||||||
document.dispatchEvent(e);
|
document.dispatchEvent(e);
|
||||||
},
|
},
|
||||||
[text]
|
[text]
|
||||||
);
|
);
|
||||||
|
if (paste) {
|
||||||
|
await keyDownCtrlOrMeta(page);
|
||||||
|
await page.keyboard.press('v', { delay: 50 });
|
||||||
|
await keyUpCtrlOrMeta(page);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,8 +60,7 @@ export async function type(page: Page, content: string, delay = 50) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const createLinkedPage = async (page: Page, pageName?: string) => {
|
export const createLinkedPage = async (page: Page, pageName?: string) => {
|
||||||
// fixme: workaround for @ popover not showing up when editor is not ready
|
await waitForEditorLoad(page);
|
||||||
await page.waitForTimeout(500);
|
|
||||||
await page.keyboard.type('@', { delay: 50 });
|
await page.keyboard.type('@', { delay: 50 });
|
||||||
const linkedPagePopover = page.locator('.linked-doc-popover');
|
const linkedPagePopover = page.locator('.linked-doc-popover');
|
||||||
await expect(linkedPagePopover).toBeVisible();
|
await expect(linkedPagePopover).toBeVisible();
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
"include": ["./src"],
|
"include": ["./src"],
|
||||||
"references": [
|
"references": [
|
||||||
{ "path": "../../tools/utils" },
|
{ "path": "../../tools/utils" },
|
||||||
{ "path": "../../blocksuite/affine/all" }
|
{ "path": "../../blocksuite/affine/all" },
|
||||||
|
{ "path": "../../packages/common/infra" }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -85,11 +85,12 @@ function getBundleConfigs(pkg: Package) {
|
|||||||
const IN_CI = !!process.env.CI;
|
const IN_CI = !!process.env.CI;
|
||||||
const httpProxyMiddlewareLogLevel = IN_CI ? 'silent' : 'error';
|
const httpProxyMiddlewareLogLevel = IN_CI ? 'silent' : 'error';
|
||||||
|
|
||||||
const defaultDevServerConfig = {
|
const defaultDevServerConfig: DevServerConfiguration = {
|
||||||
host: '0.0.0.0',
|
host: '0.0.0.0',
|
||||||
allowedHosts: 'all',
|
allowedHosts: 'all',
|
||||||
hot: false,
|
hot: false,
|
||||||
liveReload: true,
|
liveReload: true,
|
||||||
|
compress: !process.env.CI,
|
||||||
client: {
|
client: {
|
||||||
overlay: process.env.DISABLE_DEV_OVERLAY === 'true' ? false : undefined,
|
overlay: process.env.DISABLE_DEV_OVERLAY === 'true' ? false : undefined,
|
||||||
logging: process.env.CI ? 'none' : 'error',
|
logging: process.env.CI ? 'none' : 'error',
|
||||||
@@ -124,7 +125,7 @@ const defaultDevServerConfig = {
|
|||||||
logLevel: httpProxyMiddlewareLogLevel,
|
logLevel: httpProxyMiddlewareLogLevel,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
} as DevServerConfiguration;
|
};
|
||||||
|
|
||||||
export class BundleCommand extends PackageCommand {
|
export class BundleCommand extends PackageCommand {
|
||||||
static override paths = [['bundle'], ['webpack'], ['pack'], ['bun']];
|
static override paths = [['bundle'], ['webpack'], ['pack'], ['bun']];
|
||||||
|
|||||||
@@ -1209,7 +1209,11 @@ export const PackageList = [
|
|||||||
{
|
{
|
||||||
location: 'tests/kit',
|
location: 'tests/kit',
|
||||||
name: '@affine-test/kit',
|
name: '@affine-test/kit',
|
||||||
workspaceDependencies: ['tools/utils', 'blocksuite/affine/all'],
|
workspaceDependencies: [
|
||||||
|
'tools/utils',
|
||||||
|
'blocksuite/affine/all',
|
||||||
|
'packages/common/infra',
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
location: 'tools/@types/build-config',
|
location: 'tools/@types/build-config',
|
||||||
|
|||||||
@@ -101,6 +101,7 @@ __metadata:
|
|||||||
"@blocksuite/affine": "workspace:*"
|
"@blocksuite/affine": "workspace:*"
|
||||||
"@node-rs/argon2": "npm:^2.0.2"
|
"@node-rs/argon2": "npm:^2.0.2"
|
||||||
"@playwright/test": "npm:=1.51.1"
|
"@playwright/test": "npm:=1.51.1"
|
||||||
|
"@toeverything/infra": "workspace:*"
|
||||||
express: "npm:^5.0.0"
|
express: "npm:^5.0.0"
|
||||||
http-proxy-middleware: "npm:^3.0.3"
|
http-proxy-middleware: "npm:^3.0.3"
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
|||||||
Reference in New Issue
Block a user