diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml new file mode 100644 index 000000000..6b815b4a9 --- /dev/null +++ b/.github/workflows/playwright.yml @@ -0,0 +1,44 @@ +name: Playwright Tests +on: + push: + branches: [pathfinder] + pull_request: + branches: [pathfinder] +jobs: + test: + timeout-minutes: 60 + runs-on: self-hosted + + steps: + - uses: actions/checkout@v3 + + - uses: pnpm/action-setup@v2 + with: + version: 'latest' + + - uses: actions/setup-node@v3 + with: + node-version: 16 + registry-url: https://npm.pkg.github.com + scope: '@toeverything' + cache: 'pnpm' + + - run: node scripts/module-resolve/ci.js + + - name: Install dependencies + run: pnpm install --no-frozen-lockfile + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_GITHUB_AUTH_TOKEN }} + + - name: Install Playwright Browsers + run: npx playwright install --with-deps + + - name: Run Playwright tests + run: pnpm dlx playwright test + + - uses: actions/upload-artifact@v3 + if: always() + with: + name: playwright-report + path: playwright-report/ + retention-days: 30 diff --git a/.gitignore b/.gitignore index 924094754..2d049c3c6 100644 --- a/.gitignore +++ b/.gitignore @@ -48,3 +48,6 @@ Thumbs.db out/ module-resolve.js +/test-results/ +/playwright-report/ +/playwright/.cache/ diff --git a/.vscode/settings.json b/.vscode/settings.json index 784f0f182..df31aeb4b 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,5 +2,6 @@ "eslint.packageManager": "pnpm", "editor.defaultFormatter": "esbenp.prettier-vscode", "editor.formatOnSave": true, - "editor.formatOnSaveMode": "file" + "editor.formatOnSaveMode": "file", + "cSpell.words": ["testid"] } diff --git a/package.json b/package.json index 40bce5546..84342f92f 100644 --- a/package.json +++ b/package.json @@ -7,14 +7,16 @@ "build": "pnpm -r build", "export": "pnpm --filter @pathfinder/app export", "start": "pnpm --filter @pathfinder/app start", - "lint": "pnpm --filter @pathfinder/app lint" + "lint": "pnpm --filter @pathfinder/app lint", + "test:e2e": "playwright test" }, - "dependencies": {}, "devDependencies": { - "prettier": "^2.7.1", + "@playwright/test": "^1.27.1", + "@types/node": "18.7.18", "eslint": "8.22.0", "eslint-config-next": "12.3.1", "eslint-config-prettier": "^8.5.0", - "eslint-plugin-prettier": "^4.2.1" + "eslint-plugin-prettier": "^4.2.1", + "prettier": "^2.7.1" } } diff --git a/packages/app/src/components/theme-mode-switch/index.tsx b/packages/app/src/components/theme-mode-switch/index.tsx index 324a3cfda..ad3c32dd3 100644 --- a/packages/app/src/components/theme-mode-switch/index.tsx +++ b/packages/app/src/components/theme-mode-switch/index.tsx @@ -9,6 +9,7 @@ export const ThemeModeSwitch = () => { const [firstTrigger, setFirstTrigger] = useState(false); return ( { setIsHover(true); if (!firstTrigger) { @@ -20,6 +21,7 @@ export const ThemeModeSwitch = () => { }} > { =14'} + hasBin: true + dependencies: + '@types/node': 18.7.18 + playwright-core: 1.27.1 + dev: true + /@popperjs/core/2.11.6: resolution: {integrity: sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==} dev: false @@ -2577,6 +2590,12 @@ packages: engines: {node: '>=8.6'} dev: true + /playwright-core/1.27.1: + resolution: {integrity: sha512-9EmeXDncC2Pmp/z+teoVYlvmPWUC6ejSSYZUln7YaP89Z6lpAaiaAnqroUt/BoLo8tn7WYShcfaCh+xofZa44Q==} + engines: {node: '>=14'} + hasBin: true + dev: true + /postcss/8.4.14: resolution: {integrity: sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==} engines: {node: ^10 || ^12 || >=14} diff --git a/tests/theme.spec.ts b/tests/theme.spec.ts new file mode 100644 index 000000000..c2a5b1332 --- /dev/null +++ b/tests/theme.spec.ts @@ -0,0 +1,48 @@ +import { test, expect, type Page } from '@playwright/test'; + +test.beforeEach(async ({ page }) => { + await page.goto('http://localhost:3000'); +}); + +test.describe('Change Theme', () => { + test('default white', async ({ page }) => { + const root = page.locator('html'); + const themeMode = await root.evaluate(element => + window.getComputedStyle(element).getPropertyValue('--affine-theme-mode') + ); + + await expect(themeMode).toBe('light'); + + const lightButton = page.locator('[data-testid=change-theme-light]'); + const buttonPositionTop = await lightButton.evaluate( + element => window.getComputedStyle(element).top + ); + await expect(buttonPositionTop).toBe('0px'); + }); + + test('change theme to dark', async ({ page }) => { + const changeThemeContainer = page.locator( + '[data-testid=change-theme-container]' + ); + const box = await changeThemeContainer.boundingBox(); + await expect(box?.x).not.toBeUndefined(); + await page.mouse.move((box?.x ?? 0) + 5, (box?.y ?? 0) + 5); + + await page.waitForTimeout(3000); + + const darkButton = page.locator('[data-testid=change-theme-dark]'); + const darkButtonPositionTop = await darkButton.evaluate( + element => element.getBoundingClientRect().y + ); + await expect(darkButtonPositionTop).toBe(box?.y); + + await page.mouse.click((box?.x ?? 0) + 5, (box?.y ?? 0) + 5); + + const root = page.locator('html'); + const themeMode = await root.evaluate(element => + window.getComputedStyle(element).getPropertyValue('--affine-theme-mode') + ); + + await expect(themeMode).toBe('dark'); + }); +});