Skip to content
Open
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
66 changes: 66 additions & 0 deletions .github/workflows/bdd.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
name: BDD E2E

on:
push:
branches: ["**"]
pull_request:
branches: ["**"]

permissions:
contents: read

jobs:
e2e:
name: Run BDD (Cucumber + Playwright)
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- name: Checkout
uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1

- name: Setup
uses: ./.github/actions/setup

- name: Install Playwright browsers
run: pnpm exec playwright install --with-deps

- name: Start dev stack (Next + OIDC + Mock)
env:
API_BASE_URL: http://localhost:9090
OIDC_ISSUER_URL: http://localhost:4000
OIDC_CLIENT_ID: better-auth-dev
OIDC_CLIENT_SECRET: dev-secret-change-in-production
NEXT_PUBLIC_OIDC_PROVIDER_ID: okta
BETTER_AUTH_URL: http://localhost:3000
BETTER_AUTH_SECRET: ci-test-secret-not-for-production
run: |
pnpm dev &
echo $! > dev.pid
# Wait for Next (3000), OIDC (4000 - use discovery endpoint), and Mock API (9090 - use health endpoint)
for url in http://localhost:3000 http://localhost:4000/.well-known/openid-configuration http://localhost:9090/health; do
echo "Waiting for $url..."
up=false
for i in {1..60}; do
if curl -sf "$url" >/dev/null; then
echo "$url is up"
up=true
break
fi
sleep 2
done
if [ "$up" = false ]; then
echo "ERROR: $url failed to start"
exit 1
fi
done

- name: Run BDD tests
env:
BASE_URL: http://localhost:3000
run: pnpm run test:bdd

- name: Cleanup dev
if: always()
run: |
if [ -f dev.pid ]; then kill $(cat dev.pid) || true; fi

4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@

# testing
/coverage
# Playwright/Cucumber E2E artifacts
test-results/
playwright-report/
blob-report/

# next.js
/.next/
Expand Down
24 changes: 20 additions & 4 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ pnpm generate-client:nofetch # Regenerate without fetching

### Backend API

- **Base URL**: Configured via `NEXT_PUBLIC_API_URL`
- **Base URL**: Configured via `API_BASE_URL` (server-side only)
- **Format**: Official MCP Registry API (upstream compatible)
- **Endpoints**:
- `GET /api/v0/servers` - List all MCP servers
Expand All @@ -178,7 +178,7 @@ pnpm generate-client:nofetch # Regenerate without fetching
### Production

1. User accesses protected route
2. Redirected to `/sign-in`
2. Redirected to `/signin`
3. Better Auth initiates OIDC flow with configured provider
4. Provider redirects back with authorization code
5. Better Auth exchanges code for tokens
Expand Down Expand Up @@ -218,6 +218,19 @@ pnpm generate-client:nofetch # Regenerate without fetching
- **Testing Library** - Component testing
- **jsdom** - DOM simulation

### BDD E2E (Cucumber + Playwright)

- End-to-end scenarios live under `tests/bdd` and run against a live dev stack.
- Commands:
- `pnpm dev` – starts Next.js (3000), mock OIDC (4000), and MSW mock API (9090)
- `pnpm run test:bdd` – runs Cucumber scenarios with Playwright (headless)
- `pnpm run test:bdd:debug` – runs with Playwright Inspector (headed, pauses on start)
- `pnpm run test:bdd:trace` – runs with Playwright tracing, artifacts in `test-results/traces/*.zip`
- CI runs BDD tests via `.github/workflows/bdd.yml` and installs Playwright browsers.
- Install browsers locally once: `pnpm exec playwright install`

Scaffolded global steps include navigation, clicking buttons by accessible name, URL assertions, and text/heading checks. Prefer reusing global steps; add domain-specific ones only when needed for clarity.

### Example Test

```typescript
Expand Down Expand Up @@ -274,7 +287,10 @@ git push origin v0.x.x

### Authentication Not Working

- **Development**: Ensure OIDC mock is running (`pnpm oidc`)
- **Development**:
- Ensure OIDC mock is running (`pnpm oidc`) or start the full stack with `pnpm dev`
- Dev provider issues refresh tokens unconditionally and uses a short AccessToken TTL (15s) to exercise the refresh flow
- If you see origin errors (403), ensure `BETTER_AUTH_URL` matches the port you use (default `http://localhost:3000`) or include it in `TRUSTED_ORIGINS`
- **Production**: Check environment variables:
- `OIDC_ISSUER_URL` - OIDC provider URL
- `OIDC_CLIENT_ID` - OAuth2 client ID
Expand All @@ -285,7 +301,7 @@ git push origin v0.x.x

### API Calls Failing

- Check `NEXT_PUBLIC_API_URL` environment variable
- Check `API_BASE_URL` environment variable
- Verify backend API is running
- Check browser console for CORS errors

Expand Down
54 changes: 40 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ pnpm dev
# Application will be available at http://localhost:3000
```

Authentication: the dev stack also starts a local OIDC provider (on :4000) and MSW mock API (on :9090). The `/signin` page initiates the OIDC flow and redirects back to `/catalog` on success.

### Available Commands

#### Development Commands (pnpm)
Expand Down Expand Up @@ -260,26 +262,26 @@ BETTER_AUTH_URL=http://localhost:3000

### Testing

#### Unit/Component Tests

```bash
# Run all tests
pnpm test
pnpm test # Run all tests
pnpm test --watch # Watch mode
pnpm test --coverage # With coverage
```

# Run tests in watch mode
pnpm test --watch
Uses Vitest + Testing Library + MSW.

# Run tests with coverage
pnpm test --coverage
#### BDD E2E Tests (Cucumber + Playwright)

# Run specific test file
pnpm test src/components/navbar.test.tsx
```bash
pnpm exec playwright install # One-time browser install
pnpm dev # Start dev stack
pnpm run test:bdd # Run scenarios (headless)
pnpm run test:bdd:debug # With Playwright Inspector
pnpm run test:bdd:trace # Capture traces
```

Tests use:

- **Vitest** - Test runner
- **Testing Library** - React component testing
- **MSW** - API mocking

### Mock Server

The project includes a standalone MSW mock server for development:
Expand Down Expand Up @@ -454,6 +456,30 @@ For detailed information about the project:
- [shadcn/ui Components](https://ui.shadcn.com)
- [MCP Registry Official](https://github.com/modelcontextprotocol/registry)

## Testing

### Unit/Component

```bash
pnpm test # Vitest
pnpm type-check # TypeScript
pnpm lint # Biome
```

### BDD E2E (Cucumber + Playwright)

Run the app and E2E tests locally:

```bash
pnpm exec playwright install # one-time browser install
pnpm dev # start Next (3000) + OIDC (4000) + Mock API (9090)
pnpm run test:bdd # run Cucumber scenarios (headless)
pnpm run test:bdd:debug # headed with Playwright Inspector (PWDEBUG=1)
pnpm run test:bdd:trace # capture Playwright traces (PWTRACE=1)
```

CI runs the E2E suite via `.github/workflows/bdd.yml`.

## Deploy on Vercel

The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
Expand Down
16 changes: 16 additions & 0 deletions cucumber.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
module.exports = {
default: {
requireModule: ["ts-node/register/transpile-only"],
require: [
"tests/bdd/support/world.ts",
"tests/bdd/support/hooks.ts",
"tests/bdd/support/roles.ts",
"tests/bdd/support/parameter-types.ts",
"tests/bdd/support/auth.ts",
"tests/bdd/steps/**/*.ts",
],
paths: ["tests/bdd/features/**/*.feature"],
publishQuiet: true,
format: ["progress"],
},
};
Comment on lines +1 to +16
Copy link
Collaborator

@peppescg peppescg Nov 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: why we need cucumber? we cannot handle everything within playwright? cucumber is not so common in UI as a testing framework

8 changes: 8 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
"lint": "biome check",
"format": "biome format --write",
"test": "vitest",
"test:bdd": "cucumber-js",
"test:bdd:trace": "PWTRACE=1 cucumber-js",
"test:bdd:debug": "PWDEBUG=1 cucumber-js",
"type-check": "tsc --noEmit",
"prepare": "husky",
"oidc": "node dev-auth/oidc-provider.mjs",
Expand Down Expand Up @@ -47,9 +50,12 @@
},
"devDependencies": {
"@biomejs/biome": "2.3.7",
"@cucumber/cucumber": "^12.2.0",
"@cucumber/messages": "^31.0.0",
"@hey-api/client-next": "0.5.1",
"@hey-api/openapi-ts": "0.87.5",
"@mswjs/http-middleware": "^0.10.2",
"@playwright/test": "^1.56.1",
"@tailwindcss/postcss": "^4",
"@testing-library/dom": "^10.4.1",
"@testing-library/jest-dom": "^6.9.1",
Expand All @@ -59,6 +65,7 @@
"@types/react": "^19",
"@types/react-dom": "^19",
"@vitejs/plugin-react": "^5.1.1",
"aria-query": "^5.3.2",
"babel-plugin-react-compiler": "1.0.0",
"concurrently": "^9.2.1",
"dotenv": "^17.2.3",
Expand All @@ -67,6 +74,7 @@
"lint-staged": "^16.0.0",
"oidc-provider": "^9.5.2",
"tailwindcss": "^4",
"ts-node": "^10.9.2",
"tsx": "4.20.6",
"typescript": "^5",
"vite": "^7.2.2",
Expand Down
Loading