diff --git a/.gitignore b/.gitignore index 162e443..3ab6773 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ web/dist/ web/node_modules/ +web/test-results/ diff --git a/web/package-lock.json b/web/package-lock.json index ee46446..d33a312 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -22,6 +22,7 @@ "react-router-dom": "7.18.2" }, "devDependencies": { + "@playwright/test": "1.62.1", "@testing-library/dom": "10.4.1", "@testing-library/react": "16.3.2", "@vitejs/plugin-react": "6.1.0", @@ -768,6 +769,22 @@ "url": "https://github.com/sponsors/Boshen" } }, + "node_modules/@playwright/test": { + "version": "1.62.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.62.1.tgz", + "integrity": "sha512-DTcUc8qii+cpHvtOwggMtBRMjKZHXYWdw8syRYu2vtzuq4Wxphqq4NfCs5Zt44L6mA8rfDfj+PHnxFc/FeK6mQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright": "1.62.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=20" + } + }, "node_modules/@popperjs/core": { "version": "2.11.8", "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", @@ -2712,6 +2729,53 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/playwright": { + "version": "1.62.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.62.1.tgz", + "integrity": "sha512-0M+L3LAD8/nm554LOla9Ayx0j0tmFZ0FBcoQ7F1VuVHpM/XpiC8RcDzBQB8W5+hA8L22THxELzeF+2WcUzvcLg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.62.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=20" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.62.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.62.1.tgz", + "integrity": "sha512-wPYSwEBJY9GHraISXqyqtx0na0LpO3XEX7jNDhntbex7tzUS7kLnZsOlFruFJB4Hi/rhDMjXGqHewDZ68nYZVw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/playwright/node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/postcss": { "version": "8.5.26", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.26.tgz", diff --git a/web/package.json b/web/package.json index dd0d8e7..5fb3096 100644 --- a/web/package.json +++ b/web/package.json @@ -6,7 +6,8 @@ "scripts": { "build": "vite build", "dev": "vite", - "test": "vitest run" + "test": "vitest run", + "test:responsive": "playwright test" }, "dependencies": { "@emotion/react": "11.14.0", @@ -23,6 +24,7 @@ "react-router-dom": "7.18.2" }, "devDependencies": { + "@playwright/test": "1.62.1", "@testing-library/dom": "10.4.1", "@testing-library/react": "16.3.2", "@vitejs/plugin-react": "6.1.0", diff --git a/web/playwright.config.js b/web/playwright.config.js new file mode 100644 index 0000000..bc455fa --- /dev/null +++ b/web/playwright.config.js @@ -0,0 +1,12 @@ +import { defineConfig } from '@playwright/test' + +export default defineConfig({ + testDir: './tests', + testMatch: '*.e2e.js', + use: { baseURL: 'http://127.0.0.1:4173', channel: 'chrome' }, + webServer: { + command: 'npm run dev -- --host 127.0.0.1 --port 4173', + url: 'http://127.0.0.1:4173', + reuseExistingServer: true, + }, +}) diff --git a/web/src/BrowserList.jsx b/web/src/BrowserList.jsx index 0000dbf..0ef4f2a 100644 --- a/web/src/BrowserList.jsx +++ b/web/src/BrowserList.jsx @@ -116,7 +116,7 @@ export function BrowserList() { <> 运行环境启动、停止并回收隔离的浏览器 Profile - + 环境名称 setName(event.target.value)} placeholder="例如:account-a" /> @@ -125,7 +125,7 @@ export function BrowserList() { Fingerprint Seed setSeed(event.target.value)} /> - + {message ? { setLocalError(''); refetch() }}>重试} sx={{ mb: 2.5 }}>{message} : null} diff --git a/web/src/layout.jsx b/web/src/layout.jsx index 786e7fc..8ba70ff 100644 --- a/web/src/layout.jsx +++ b/web/src/layout.jsx @@ -66,7 +66,7 @@ export function CreatorHubLayout({ children }) { {desktop ? setCollapsed(value => !value)} sx={{ position: 'absolute', right: 16, bottom: 24, color: '#a9b7cc', border: '1px solid #35506f' }}>{collapsed ? : } : null} - + {children} diff --git a/web/tests/responsive.e2e.js b/web/tests/responsive.e2e.js new file mode 100644 index 0000000..4035319 --- /dev/null +++ b/web/tests/responsive.e2e.js @@ -0,0 +1,15 @@ +import { expect, test } from '@playwright/test' + +test('keeps the create form inside a 900px viewport', async ({ page }) => { + await page.route('**/api/browsers', route => route.fulfill({ json: [] })) + await page.setViewportSize({ width: 900, height: 800 }) + await page.goto('/') + + await expect(page.getByRole('button', { name: '收起导航' }).first()).toBeVisible() + const createButton = page.getByRole('button', { name: '创建环境' }) + await expect(createButton).toBeVisible() + expect(await page.evaluate(() => document.documentElement.scrollWidth)).toBeLessThanOrEqual(900) + const box = await createButton.boundingBox() + expect(box).not.toBeNull() + expect(box.x + box.width).toBeLessThanOrEqual(900) +})