Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 30 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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:
Expand All @@ -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:
Expand All @@ -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"
Expand Down
1 change: 1 addition & 0 deletions apps/api/.env.test
Original file line number Diff line number Diff line change
Expand Up @@ -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"
19 changes: 14 additions & 5 deletions playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
},
],
});
14 changes: 11 additions & 3 deletions scripts/test-bootstrap.js
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down
76 changes: 76 additions & 0 deletions tests/api/auth.spec.ts
Original file line number Diff line number Diff line change
@@ -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);
})
})