From 157cc97a657896b9b9e639b8e9bbdee7faabcea9 Mon Sep 17 00:00:00 2001 From: pengx17 Date: Mon, 29 Jul 2024 11:05:24 +0000 Subject: [PATCH] test(electron): add test cases for electron tabs (#7635) fix AF-1000 --- .../app-tabs-header/views/app-tabs-header.tsx | 10 +- .../workbench/view/split-view/indicator.tsx | 1 + .../src/main/windows-manager/tab-views.ts | 2 +- tests/affine-desktop/e2e/basic.spec.ts | 40 ---- tests/affine-desktop/e2e/behavior.spec.ts | 2 +- tests/affine-desktop/e2e/tabs.spec.ts | 190 ++++++++++++++++++ tests/kit/electron.ts | 17 +- tests/kit/utils/ipc.ts | 2 + 8 files changed, 215 insertions(+), 49 deletions(-) create mode 100644 tests/affine-desktop/e2e/tabs.spec.ts diff --git a/packages/frontend/core/src/modules/app-tabs-header/views/app-tabs-header.tsx b/packages/frontend/core/src/modules/app-tabs-header/views/app-tabs-header.tsx index a21017b2a3faf..09cf0f050cce8 100644 --- a/packages/frontend/core/src/modules/app-tabs-header/views/app-tabs-header.tsx +++ b/packages/frontend/core/src/modules/app-tabs-header/views/app-tabs-header.tsx @@ -84,6 +84,7 @@ const WorkbenchTab = ({ return (
@@ -214,7 +220,7 @@ export const AppTabsHeader = ({ /> ); })} - + diff --git a/packages/frontend/core/src/modules/workbench/view/split-view/indicator.tsx b/packages/frontend/core/src/modules/workbench/view/split-view/indicator.tsx index e8aa96a64a01a..29425e878fb30 100644 --- a/packages/frontend/core/src/modules/workbench/view/split-view/indicator.tsx +++ b/packages/frontend/core/src/modules/workbench/view/split-view/indicator.tsx @@ -47,6 +47,7 @@ export const SplitViewMenuIndicator = memo(
{ unsub = helperProcessManager.connectRenderer(view.webContents); }); - view.webContents.on('did-start-loading', () => { + view.webContents.on('will-navigate', () => { // means the view is reloaded this.appTabsUIReady$.next( new Set([...this.appTabsUIReady$.value].filter(key => key !== viewId)) diff --git a/tests/affine-desktop/e2e/basic.spec.ts b/tests/affine-desktop/e2e/basic.spec.ts index b4f559fff2a71..cf356925a98fd 100644 --- a/tests/affine-desktop/e2e/basic.spec.ts +++ b/tests/affine-desktop/e2e/basic.spec.ts @@ -1,7 +1,6 @@ import { test } from '@affine-test/kit/electron'; import { clickNewPageButton, - createLinkedPage, getBlockSuiteEditorTitle, } from '@affine-test/kit/utils/page-logic'; import { @@ -143,42 +142,3 @@ test('delete workspace', async ({ page }) => { 'Demo Workspace' ); }); - -// temporary way to enable split view -async function enableSplitView(page: Page) { - await page.evaluate(() => { - const settingKey = 'affine-settings'; - window.localStorage.setItem( - settingKey, - JSON.stringify({ - clientBorder: false, - fullWidthLayout: false, - windowFrameStyle: 'frameless', - fontStyle: 'Serif', - dateFormat: 'MM/dd/YYYY', - startWeekOnMonday: false, - enableBlurBackground: true, - enableNoisyBackground: true, - autoCheckUpdate: true, - autoDownloadUpdate: true, - enableMultiView: true, - editorFlags: {}, - }) - ); - }); - await page.reload(); -} - -test('open split view', async ({ page }) => { - await enableSplitView(page); - await clickNewPageButton(page); - await page.waitForTimeout(500); - await page.keyboard.press('Enter'); - await createLinkedPage(page, 'hi from another page'); - await page - .locator('.affine-reference-title:has-text("hi from another page")') - .click({ - modifiers: ['ControlOrMeta', 'Alt'], - }); - await expect(page.locator('.doc-title-container')).toHaveCount(2); -}); diff --git a/tests/affine-desktop/e2e/behavior.spec.ts b/tests/affine-desktop/e2e/behavior.spec.ts index a060608cbfc04..7231b5a5431f4 100644 --- a/tests/affine-desktop/e2e/behavior.spec.ts +++ b/tests/affine-desktop/e2e/behavior.spec.ts @@ -3,7 +3,7 @@ import os from 'node:os'; import { test } from '@affine-test/kit/electron'; import { shouldCallIpcRendererHandler } from '@affine-test/kit/utils/ipc'; -test.describe('behavior test', () => { +test.describe.skip('behavior test', () => { if (os.platform() === 'darwin') { test('system button should hidden correctly', async ({ page, diff --git a/tests/affine-desktop/e2e/tabs.spec.ts b/tests/affine-desktop/e2e/tabs.spec.ts new file mode 100644 index 0000000000000..fba462a85598f --- /dev/null +++ b/tests/affine-desktop/e2e/tabs.spec.ts @@ -0,0 +1,190 @@ +import { test } from '@affine-test/kit/electron'; +import { + clickNewPageButton, + createLinkedPage, +} from '@affine-test/kit/utils/page-logic'; +import { expect, type Page } from '@playwright/test'; + +test('create new tab', async ({ views }) => { + let page = await views.getActive(); + + await page.getByTestId('add-tab-view-button').click(); + await expect(page.getByTestId('workbench-tab')).toHaveCount(2); + // new tab title should be All docs + await expect(page.getByTestId('workbench-tab').nth(1)).toContainText( + 'All docs' + ); + page = await views.getActive(); + // page content should be at all docs page + await expect(page.getByTestId('virtualized-page-list')).toContainText( + 'All Docs' + ); +}); + +test('can switch & close tab by clicking', async ({ page }) => { + await page.getByTestId('add-tab-view-button').click(); + + await expect(page.getByTestId('workbench-tab').nth(1)).toHaveAttribute( + 'data-active', + 'true' + ); + // switch to the previous tab by clicking on it + await page.getByTestId('workbench-tab').nth(0).click(); + await expect(page.getByTestId('workbench-tab').nth(0)).toHaveAttribute( + 'data-active', + 'true' + ); + + // switch to the next tab by clicking on it + await page.getByTestId('workbench-tab').nth(1).click(); + await expect(page.getByTestId('workbench-tab').nth(1)).toHaveAttribute( + 'data-active', + 'true' + ); + + // close the current tab + await page + .getByTestId('workbench-tab') + .nth(1) + .getByTestId('close-tab-button') + .click(); + + // the first tab should be active + await expect(page.getByTestId('workbench-tab').nth(0)).toHaveAttribute( + 'data-active', + 'true' + ); +}); + +test('can switch tab by CTRL+number', async ({ page }) => { + test.fixme(); // the shortcut can be only captured by the main process + await page.keyboard.down('ControlOrMeta+T'); + await expect(page.getByTestId('workbench-tab')).toHaveCount(2); + await expect(page.getByTestId('workbench-tab').nth(1)).toHaveAttribute( + 'data-active', + 'true' + ); + // switch to the previous tab by pressing CTRL+1 + await page.locator('body').press('ControlOrMeta+1'); + await expect(page.getByTestId('workbench-tab').nth(0)).toHaveAttribute( + 'data-active', + 'true' + ); + // switch to the next tab by pressing CTRL+2 + await page.locator('body').press('ControlOrMeta+2'); + await expect(page.getByTestId('workbench-tab').nth(1)).toHaveAttribute( + 'data-active', + 'true' + ); +}); + +test('Collapse Sidebar', async ({ page }) => { + await page + .locator('[data-testid=app-sidebar-arrow-button-collapse][data-show=true]') + .click(); + const sliderBarArea = page.getByTestId('app-sidebar'); + await expect(sliderBarArea).not.toBeInViewport(); +}); + +test('Expand Sidebar', async ({ page }) => { + await page + .locator('[data-testid=app-sidebar-arrow-button-collapse][data-show=true]') + .click(); + const sliderBarArea = page.getByTestId('sliderBar-inner'); + await expect(sliderBarArea).not.toBeInViewport(); + + await page + .locator('[data-testid=app-sidebar-arrow-button-expand][data-show=true]') + .click(); + await expect(sliderBarArea).toBeInViewport(); +}); + +test('tab title will change when navigating', async ({ page }) => { + await expect(page.getByTestId('workbench-tab')).toContainText( + 'Write, Draw, Plan all at Once' + ); + + // create new page + await clickNewPageButton(page); + await expect(page.getByTestId('workbench-tab')).toContainText('Untitled'); + + // go to all page + await page.getByTestId('all-pages').click(); + await expect(page.getByTestId('workbench-tab')).toContainText('All docs'); + + // go to today's journal + await page.getByTestId('slider-bar-journals-button').click(); + await expect(page.locator('.doc-title-container')).toContainText('Today'); + const dateString = await page + .locator('.doc-title-container > span:first-of-type') + .textContent(); + + if (dateString) { + await expect(page.getByTestId('workbench-tab')).toContainText(dateString); + } +}); + +// temporary way to enable split view +async function enableSplitView(page: Page) { + await page.evaluate(() => { + const settingKey = 'affine-settings'; + window.localStorage.setItem( + settingKey, + JSON.stringify({ + clientBorder: false, + fullWidthLayout: false, + windowFrameStyle: 'frameless', + fontStyle: 'Serif', + dateFormat: 'MM/dd/YYYY', + startWeekOnMonday: false, + enableBlurBackground: true, + enableNoisyBackground: true, + autoCheckUpdate: true, + autoDownloadUpdate: true, + enableMultiView: true, + editorFlags: {}, + }) + ); + }); + await page.reload(); +} + +test('open split view', async ({ page }) => { + await enableSplitView(page); + await clickNewPageButton(page); + await page.waitForTimeout(500); + await page.keyboard.press('Enter'); + await createLinkedPage(page, 'hi from another page'); + await page + .locator('.affine-reference-title:has-text("hi from another page")') + .click({ + modifiers: ['ControlOrMeta', 'Alt'], + }); + await expect(page.locator('.doc-title-container')).toHaveCount(2); + + // check tab title + await expect(page.getByTestId('split-view-label')).toHaveCount(2); + await expect(page.getByTestId('split-view-label').nth(0)).toContainText( + 'Untitled' + ); + await expect(page.getByTestId('split-view-label').nth(1)).toContainText( + 'hi from another page' + ); + + // the second split view should be active + await expect(page.getByTestId('split-view-label').nth(1)).toHaveAttribute( + 'data-active', + 'true' + ); + + // by clicking the first split view label, the first split view should be active + await page.getByTestId('split-view-label').nth(0).click(); + await expect(page.getByTestId('split-view-label').nth(0)).toHaveAttribute( + 'data-active', + 'true' + ); + await expect(page.getByTestId('split-view-indicator').nth(0)).toHaveAttribute( + 'data-active', + 'true' + ); +}); diff --git a/tests/kit/electron.ts b/tests/kit/electron.ts index da293ac465c5c..1707cfee78d86 100644 --- a/tests/kit/electron.ts +++ b/tests/kit/electron.ts @@ -47,6 +47,9 @@ export const test = base.extend<{ appData: string; sessionData: string; }; + views: { + getActive: () => Promise; + }; router: { goto: (path: RoutePath) => Promise; }; @@ -88,6 +91,15 @@ export const test = base.extend<{ await use(page as Page); }, + views: async ({ electronApp, page }, use) => { + void page; // makes sure page is a dependency + await use({ + getActive: async () => { + const view = await getActivePage(electronApp.windows()); + return view || page; + }, + }); + }, // eslint-disable-next-line no-empty-pattern electronApp: async ({}, use) => { try { @@ -150,8 +162,3 @@ export const test = base.extend<{ await use(appInfo); }, }); - -// eslint-disable-next-line no-empty-pattern -test.afterEach(({}, testInfo) => { - console.log('cleaning up for ' + testInfo); -}); diff --git a/tests/kit/utils/ipc.ts b/tests/kit/utils/ipc.ts index 27a1f09618800..e5f5544694a46 100644 --- a/tests/kit/utils/ipc.ts +++ b/tests/kit/utils/ipc.ts @@ -1,3 +1,5 @@ +// TODO(@pengx17): remove + import type { affine } from '@affine/electron-api'; // Credit: https://github.com/spaceagetv/electron-playwright-helpers/blob/main/src/ipc_helpers.ts import type { Page } from '@playwright/test';