diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml new file mode 100644 index 0000000..d8c5e3f --- /dev/null +++ b/.github/workflows/playwright.yml @@ -0,0 +1,47 @@ +name: Playwright Tests +on: + push: + branches: [main, master] + pull_request: + branches: [main, master] +jobs: + test: + timeout-minutes: 60 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: lts/* + - uses: actions/setup-python@v5 + with: + python-version: "3.12" + - name: List repo structure + run: ls -R + #backend setup and start + - name: Install backend dependencies + working-directory: backend + run: pip install -r requirements.txt + + #frontend setup and run + - name: Setup pnpm + run: npm install -g pnpm + + - name: Install frontend dependencies + working-directory: frontend + run: pnpm install + + #Playwright setup and run tests + - name: Install Playwright Browsers + working-directory: frontend + run: pnpm exec playwright install --with-deps + + - name: Run Playwright tests + working-directory: frontend + run: pnpm exec playwright test + - uses: actions/upload-artifact@v4 + if: ${{ !cancelled() }} + with: + name: playwright-report + path: frontend/playwright-report/ + retention-days: 30 diff --git a/README.md b/README.md index 99aff3d..5e09968 100644 --- a/README.md +++ b/README.md @@ -16,10 +16,14 @@ cd fastapi-vue-spa-boilerplate # Backend cd backend && source .venv/bin/activate && uvicorn app.main:app --reload -# Frontend +# Frontend cd frontend && pnpm dev + +# E2E testing +cd frontend && pnpm test:e2e + ``` - Frontend: http://localhost:3000 - Backend: http://localhost:8000 -- API Docs: http://localhost:8000/docs \ No newline at end of file +- API Docs: http://localhost:8000/docs diff --git a/frontend/.gitignore b/frontend/.gitignore index a547bf3..2e5968d 100644 --- a/frontend/.gitignore +++ b/frontend/.gitignore @@ -22,3 +22,10 @@ dist-ssr *.njsproj *.sln *.sw? + +# Playwright +/test-results/ +/playwright-report/ +/blob-report/ +/playwright/.cache/ +/playwright/.auth/ diff --git a/frontend/e2e/homepage.spec.ts b/frontend/e2e/homepage.spec.ts new file mode 100644 index 0000000..cf6eeba --- /dev/null +++ b/frontend/e2e/homepage.spec.ts @@ -0,0 +1,16 @@ +import { test, expect } from "@playwright/test"; + +test("should display the correct page title", async ({ page }) => { + await page.goto("/"); + + await expect(page).toHaveTitle("Vite + Vue + TS"); +}); + +test("should display backend health status", async ({ page }) => { + await page.goto("/"); + + const healthStatus = page.getByRole("paragraph"); + await expect(healthStatus).toHaveText( + 'Health: {"status":"healthy","message":"FastAPI backend is running","environment":"development","version":"1.0.0"}', + ); +}); diff --git a/frontend/package.json b/frontend/package.json index 50413a9..3160739 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -3,12 +3,14 @@ "version": "0.0.0", "scripts": { "dev": "vite", - "build": "vite build" + "build": "vite build", + "test:e2e": "pnpm exec playwright test" }, "dependencies": { "vue": "^3.4.0" }, "devDependencies": { + "@playwright/test": "^1.59.1", "@types/node": "^24.3.0", "@vitejs/plugin-vue": "^4.5.0", "@vue/tsconfig": "^0.8.1", diff --git a/frontend/playwright.config.ts b/frontend/playwright.config.ts new file mode 100644 index 0000000..adc65c4 --- /dev/null +++ b/frontend/playwright.config.ts @@ -0,0 +1,46 @@ +import { defineConfig, devices } from "@playwright/test"; +import path from "path"; + +const absolutePathBackend = path.resolve(__dirname, "../backend"); + +export default defineConfig({ + testDir: "./e2e", + + fullyParallel: true, + forbidOnly: !!process.env.CI, + retries: process.env.CI ? 2 : 0, + workers: process.env.CI ? 1 : undefined, + reporter: "html", + use: { + baseURL: "http://127.0.0.1:5173", + }, + + projects: [ + { + name: "chromium", + use: { ...devices["Desktop Chrome"] }, + }, + + { + name: "firefox", + use: { ...devices["Desktop Firefox"] }, + }, + + { + name: "webkit", + use: { ...devices["Desktop Safari"] }, + }, + ], + + /* Run your local dev server before starting the tests*/ + webServer: [ + { + command: `cd ${absolutePathBackend} && uvicorn app.main:app --host 127.0.0.1 --port 8000`, + url: "http://127.0.0.1:8000", + }, + { + command: "pnpm dev --host 0.0.0.0", + url: "http://127.0.0.1:5173", + }, + ], +}); diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index 82d4331..fffbf73 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -12,6 +12,9 @@ importers: specifier: ^3.4.0 version: 3.5.20(typescript@5.9.2) devDependencies: + '@playwright/test': + specifier: ^1.59.1 + version: 1.59.1 '@types/node': specifier: ^24.3.0 version: 24.3.0 @@ -185,6 +188,11 @@ packages: '@jridgewell/sourcemap-codec@1.5.5': resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + '@playwright/test@1.59.1': + resolution: {integrity: sha512-PG6q63nQg5c9rIi4/Z5lR5IVF7yU5MqmKaPOe0HSc0O2cX1fPi96sUQu5j7eo4gKCkB2AnNGoWt7y4/Xx3Kcqg==} + engines: {node: '>=18'} + hasBin: true + '@types/node@24.3.0': resolution: {integrity: sha512-aPTXCrfwnDLj4VvXrm+UUCQjNEvJgNA8s5F1cvwQU+3KNltTOkBm1j30uNLyqqPNe7gE3KFzImYoZEfLhp4Yow==} @@ -250,6 +258,11 @@ packages: estree-walker@2.0.2: resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + fsevents@2.3.2: + resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -266,6 +279,16 @@ packages: picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + playwright-core@1.59.1: + resolution: {integrity: sha512-HBV/RJg81z5BiiZ9yPzIiClYV/QMsDCKUyogwH9p3MCP6IYjUFu/MActgYAvK0oWyV9NlwM3GLBjADyWgydVyg==} + engines: {node: '>=18'} + hasBin: true + + playwright@1.59.1: + resolution: {integrity: sha512-C8oWjPR3F81yljW9o5OxcWzfh6avkVwDD2VYdwIGqTkl+OGFISgypqzfu7dOe4QNLL2aqcWBmI3PMtLIK233lw==} + engines: {node: '>=18'} + hasBin: true + postcss@8.5.6: resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} engines: {node: ^10 || ^12 || >=14} @@ -406,6 +429,10 @@ snapshots: '@jridgewell/sourcemap-codec@1.5.5': {} + '@playwright/test@1.59.1': + dependencies: + playwright: 1.59.1 + '@types/node@24.3.0': dependencies: undici-types: 7.10.0 @@ -505,6 +532,9 @@ snapshots: estree-walker@2.0.2: {} + fsevents@2.3.2: + optional: true + fsevents@2.3.3: optional: true @@ -516,6 +546,14 @@ snapshots: picocolors@1.1.1: {} + playwright-core@1.59.1: {} + + playwright@1.59.1: + dependencies: + playwright-core: 1.59.1 + optionalDependencies: + fsevents: 2.3.2 + postcss@8.5.6: dependencies: nanoid: 3.3.11 diff --git a/frontend/pnpm-workspace.yaml b/frontend/pnpm-workspace.yaml new file mode 100644 index 0000000..5ed0b5a --- /dev/null +++ b/frontend/pnpm-workspace.yaml @@ -0,0 +1,2 @@ +allowBuilds: + esbuild: true diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..85d7848 --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,43 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + playwright: + specifier: ^1.59.1 + version: 1.59.1 + +packages: + + fsevents@2.3.2: + resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + playwright-core@1.59.1: + resolution: {integrity: sha512-HBV/RJg81z5BiiZ9yPzIiClYV/QMsDCKUyogwH9p3MCP6IYjUFu/MActgYAvK0oWyV9NlwM3GLBjADyWgydVyg==} + engines: {node: '>=18'} + hasBin: true + + playwright@1.59.1: + resolution: {integrity: sha512-C8oWjPR3F81yljW9o5OxcWzfh6avkVwDD2VYdwIGqTkl+OGFISgypqzfu7dOe4QNLL2aqcWBmI3PMtLIK233lw==} + engines: {node: '>=18'} + hasBin: true + +snapshots: + + fsevents@2.3.2: + optional: true + + playwright-core@1.59.1: {} + + playwright@1.59.1: + dependencies: + playwright-core: 1.59.1 + optionalDependencies: + fsevents: 2.3.2