From e6bab209d68db08d28c152bd0762c1846734b43b Mon Sep 17 00:00:00 2001 From: jonghoonpark Date: Sat, 9 Mar 2024 22:14:35 +0900 Subject: [PATCH] feat(ui-mode): add key shortcuts for playwright uI test runner --- packages/trace-viewer/src/ui/uiModeView.tsx | 21 +++ .../ui-mode-test-shortcut.spec.ts | 131 ++++++++++++++++++ 2 files changed, 152 insertions(+) create mode 100644 tests/playwright-test/ui-mode-test-shortcut.spec.ts diff --git a/packages/trace-viewer/src/ui/uiModeView.tsx b/packages/trace-viewer/src/ui/uiModeView.tsx index c7406fb49f..d1bd521168 100644 --- a/packages/trace-viewer/src/ui/uiModeView.tsx +++ b/packages/trace-viewer/src/ui/uiModeView.tsx @@ -117,6 +117,27 @@ export const UIModeView: React.FC<{}> = ({ }); }, [reloadTests]); + React.useEffect(() => { + const onShortcutEvent = (e: KeyboardEvent) => { + if (e.code === 'KeyR' && (e.metaKey || e.ctrlKey)){ + e.preventDefault(); + runTests('bounce-if-busy', visibleTestIds) + } else if (e.code === 'KeyS' && (e.metaKey || e.ctrlKey)) { + e.preventDefault(); + sendMessageNoReply('stop') + } else if (e.code === 'KeyU' && (e.metaKey || e.ctrlKey)) { + e.preventDefault(); + reloadTests() + } + } + + addEventListener("keydown", onShortcutEvent); + + return () => { + removeEventListener("keydown", onShortcutEvent) + } + }, [visibleTestIds]); + updateRootSuite = React.useCallback((config: reporterTypes.FullConfig, rootSuite: reporterTypes.Suite, loadErrors: reporterTypes.TestError[], newProgress: Progress | undefined) => { const selectedProjects = config.configFile ? settings.getObject(config.configFile + ':projects', undefined) : undefined; for (const projectName of projectFilters.keys()) { diff --git a/tests/playwright-test/ui-mode-test-shortcut.spec.ts b/tests/playwright-test/ui-mode-test-shortcut.spec.ts new file mode 100644 index 0000000000..52a3256d05 --- /dev/null +++ b/tests/playwright-test/ui-mode-test-shortcut.spec.ts @@ -0,0 +1,131 @@ +/** + * Copyright (c) Microsoft Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { test, expect, retries, dumpTestTree } from './ui-mode-fixtures'; + +test.describe.configure({ mode: 'parallel', retries }); + +const basicTestTree = { + 'a.test.ts': ` + import { test, expect } from '@playwright/test'; + test('test 0', () => { test.skip(); }); + test('test 1', () => {}); + test('test 2', async () => { await new Promise(() => {}); }); + test('test 3', async () => {}); + ` +} + +test('should run on Meta(command) with R', async ({ runUITest }) => { + const { page } = await runUITest(basicTestTree); + + await expect(page.getByTitle('Run all')).toBeEnabled(); + await expect(page.getByTitle('Stop')).toBeDisabled(); + + await page.keyboard.press('Meta+r'); + + await expect(page.getByTestId('status-line')).toHaveText('Running 1/4 passed (25%)'); +}); + +test('should run on Control with R', async ({ runUITest }) => { + const { page } = await runUITest(basicTestTree); + + await expect(page.getByTitle('Run all')).toBeEnabled(); + await expect(page.getByTitle('Stop')).toBeDisabled(); + + await page.keyboard.press('Control+r'); + + await expect(page.getByTestId('status-line')).toHaveText('Running 1/4 passed (25%)'); +}); + +test('should stop on Meta(command) with S', async ({ runUITest }) => { + const { page } = await runUITest(basicTestTree); + + await expect(page.getByTitle('Run all')).toBeEnabled(); + await expect(page.getByTitle('Stop')).toBeDisabled(); + + await page.getByTitle('Run all').click(); + + await expect.poll(dumpTestTree(page)).toBe(` + ▼ ↻ a.test.ts + ⊘ test 0 + ✅ test 1 + ↻ test 2 + 🕦 test 3 + `); + + await expect(page.getByTitle('Run all')).toBeDisabled(); + await expect(page.getByTitle('Stop')).toBeEnabled(); + + await page.keyboard.press('Meta+s'); + + await expect.poll(dumpTestTree(page)).toBe(` + ▼ ◯ a.test.ts + ⊘ test 0 + ✅ test 1 + ◯ test 2 + ◯ test 3 + `); +}); + +test('should stop on Control with S', async ({ runUITest }) => { + const { page } = await runUITest(basicTestTree); + + await expect(page.getByTitle('Run all')).toBeEnabled(); + await expect(page.getByTitle('Stop')).toBeDisabled(); + + await page.getByTitle('Run all').click(); + + await expect.poll(dumpTestTree(page)).toBe(` + ▼ ↻ a.test.ts + ⊘ test 0 + ✅ test 1 + ↻ test 2 + 🕦 test 3 + `); + + await expect(page.getByTitle('Run all')).toBeDisabled(); + await expect(page.getByTitle('Stop')).toBeEnabled(); + + await page.keyboard.press('Control+s'); + + await expect.poll(dumpTestTree(page)).toBe(` + ▼ ◯ a.test.ts + ⊘ test 0 + ✅ test 1 + ◯ test 2 + ◯ test 3 + `); +}); + +test('should reload on Meta(command) with U', async ({ runUITest }) => { + const { page } = await runUITest(basicTestTree); + + await page.getByTitle('Run all').click(); + await expect(page.getByTestId('status-line')).toHaveText('Running 1/4 passed (25%)'); + + await page.keyboard.press('Meta+u'); + await expect(page.getByTestId('status-line')).toBeHidden(); +}); + +test('should reload on Control with U', async ({ runUITest }) => { + const { page } = await runUITest(basicTestTree); + + await page.getByTitle('Run all').click(); + await expect(page.getByTestId('status-line')).toHaveText('Running 1/4 passed (25%)'); + + await page.keyboard.press('Control+u'); + await expect(page.getByTestId('status-line')).toBeHidden(); +});