From 2ca81f2a4758c9ce5fcc312842bcdb0985358d0d Mon Sep 17 00:00:00 2001 From: binit Date: Wed, 28 Jan 2026 23:01:31 +0530 Subject: [PATCH 1/2] feat: Add Playwright API authentication tests and configure web servers for testing. --- apps/api/.env.test | 1 + playwright.config.ts | 19 ++++++++--- tests/api/auth.spec.ts | 76 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 91 insertions(+), 5 deletions(-) create mode 100644 tests/api/auth.spec.ts diff --git a/apps/api/.env.test b/apps/api/.env.test index e71fab2..b36e8e7 100644 --- a/apps/api/.env.test +++ b/apps/api/.env.test @@ -8,4 +8,5 @@ RESEND_API_KEY="" FROM_EMAIL="" # Local URLs BETTER_AUTH_URL="http://localhost:3000" +API_URL="http://localhost:3000" CLIENT_URL="http://localhost:5173" diff --git a/playwright.config.ts b/playwright.config.ts index 03a83bf..b6aede0 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -90,9 +90,18 @@ export default defineConfig({ ], /* Run your local dev server before starting the tests */ - webServer: { - command: 'npm run dev', - url: 'http://localhost:5173', - reuseExistingServer: !process.env.CI, - }, + webServer: [ + { + command: 'npm run dev --prefix apps/api', + url: 'http://localhost:3000/api/health', + reuseExistingServer: !process.env.CI, + timeout: 30000, + }, + { + command: 'npm run dev --prefix apps/web', + url: 'http://localhost:5173', + reuseExistingServer: !process.env.CI, + timeout: 30000, + }, + ], }); diff --git a/tests/api/auth.spec.ts b/tests/api/auth.spec.ts new file mode 100644 index 0000000..ce95a7e --- /dev/null +++ b/tests/api/auth.spec.ts @@ -0,0 +1,76 @@ +import { test, expect, request } from '@playwright/test'; +import dotenv from 'dotenv'; +import path from 'path'; + +dotenv.config({ path: path.resolve(__dirname, '../../apps/api/.env.test') }); + +const getTestUser = () => { + const uniqueId = Math.floor(Math.random() * 100000); + return { + name: `Test User ${uniqueId}`, + email: `test${uniqueId}@example.com`, + password: `testpassword${uniqueId}` + } +} + +test.describe('AUTH endpoints test', ()=>{ + // Run tests serially - they depend on each other + test.describe.configure({ mode: 'serial' }); + + const API_URL = process.env.API_URL; + const user = getTestUser(); + + test('should register a new user', async({request}) =>{ + const res = await request.post(`${API_URL}/api/auth/sign-up/email`, { + headers:{ + 'Content-Type': 'application/json', + }, + data: { + name: user.name, + email: user.email, + password: user.password, + } + }) + expect(res.status()).toBe(200); + + }) + + test('should login with correct credentials', async({request}) =>{ + const res = await request.post(`${API_URL}/api/auth/sign-in/email`, { + headers:{ + 'Content-Type': 'application/json', + }, + data: { + email: user.email, + password: user.password, + } + }) + expect(res.status()).toBe(200); + }) + + test('should not register with existing email', async({request})=>{ + const res = await request.post(`${API_URL}/api/auth/sign-up/email`, { + headers:{ + 'Content-Type': 'application/json', + }, + data: { + email: user.email, + password: user.password, + } + }) + expect(res.status()).toBe(400); + }) + + test('should not login with wrong password', async({request})=>{ + const res = await request.post(`${API_URL}/api/auth/sign-in/email`, { + headers:{ + 'Content-Type': 'application/json', + }, + data: { + email: user.email, + password: 'wrongpassword', + } + }) + expect(res.status()).toBe(401); + }) +}) \ No newline at end of file From 1ab32098935061bcb8a735f3816dd2e350bfec31 Mon Sep 17 00:00:00 2001 From: binit Date: Wed, 28 Jan 2026 23:20:19 +0530 Subject: [PATCH 2/2] Fix: CI pipeline improved add tests --- .github/workflows/ci.yml | 32 ++++++++++++++++++++++++++++++-- scripts/test-bootstrap.js | 14 +++++++++++--- 2 files changed, 41 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 27e2afa..ea4539a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,6 +13,21 @@ jobs: permissions: contents: read + services: + postgres: + image: postgres:17 + env: + POSTGRES_USER: composter + POSTGRES_PASSWORD: composter + POSTGRES_DB: composter_test + ports: + - 5435:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - name: Checkout Repo uses: actions/checkout@v4 @@ -25,6 +40,15 @@ jobs: with: node-version: 22 cache: "npm" + + - name: Create .env.test + run: | + echo "DATABASE_URL=postgresql://composter:composter@localhost:5435/composter_test" >> apps/api/.env.test + echo "BETTER_AUTH_SECRET=test_secret_must_be_long_enough_for_ci_123" >> apps/api/.env.test + echo "API_URL=http://localhost:3000" >> apps/api/.env.test + echo "NODE_ENV=test" >> apps/api/.env.test + echo "CLIENT_URL=http://localhost:5173" >> apps/api/.env.test + echo "VITE_API_URL=http://localhost:3000" >> apps/api/.env.test # 2 Install Dependencies (With Dummy Env) - name: Install Dependencies @@ -34,7 +58,6 @@ jobs: BETTER_AUTH_SECRET: "dummy_secret_for_install" # 3 Generate Prisma Client (Direct Command) - # ⚠️ FIX: We run prisma directly here instead of via Turbo - name: Generate Prisma Client run: npx prisma generate --schema=apps/api/prisma/schema.prisma env: @@ -43,8 +66,14 @@ jobs: # 4 e2e Tests - name: Install Playwright Browsers run: npx playwright install --with-deps + - name: Run Playwright Tests run: npx playwright test + env: + CI: true + DATABASE_URL: "postgresql://composter:composter@localhost:5433/composter_test" + API_URL: "http://localhost:3000" + - uses: actions/upload-artifact@v4 if: ${{ !cancelled() }} with: @@ -55,7 +84,6 @@ jobs: # 5 Run Turbo Pipeline (Build & Lint only) - name: Run Turbo Pipeline - # ⚠️ FIX: Pass DATABASE_URL directly in the command line run: DATABASE_URL="postgresql://dummy:password@localhost:5432/mydb" npx turbo run build lint env: BETTER_AUTH_SECRET: "dummy_secret_for_build" diff --git a/scripts/test-bootstrap.js b/scripts/test-bootstrap.js index c3d7360..20bece2 100644 --- a/scripts/test-bootstrap.js +++ b/scripts/test-bootstrap.js @@ -42,9 +42,17 @@ async function main() { } catch(error){ //Ignore if already down } - - console.log('🐳 Starting Database...'); - run(`docker compose -f ${CONFIG.dockerFile} up -d`); + if(process.env.CI){ + console.log('🤖 Running in CI: Skipping Docker Start (Service Container is active)'); + } else { + try { + execSync(`docker compose -f ${CONFIG.dockerFile} up -d`, { stdio: 'ignore' }); + // Wait for DB to wake up locally + await new Promise(r => setTimeout(r, 3000)); + } catch (e) { + console.log('⚠️ Warning: Docker start failed. Continuing...'); + } + } console.log(`Waiting for db to be ready...`) await new Promise(r=>setTimeout(r, 5000));