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
2 changes: 2 additions & 0 deletions .env.local.example
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@ WORKOS_API_KEY=
NEXT_PUBLIC_WORKOS_REDIRECT_URI=http://localhost:3000/callback
WORKOS_COOKIE_PASSWORD=

# When using a custom auth domain
# WORKOS_API_HOSTNAME=auth.yourapp.com
3 changes: 3 additions & 0 deletions .env.test.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
TEST_BASE_URL=http://localhost:3000
TEST_EMAIL=test-user@test-org.test
TEST_PASSWORD=
5 changes: 4 additions & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
{
"extends": "next/core-web-vitals"
"extends": "next/core-web-vitals",
"parserOptions": {
"project": "./tsconfig.dev.json"
}
}
115 changes: 115 additions & 0 deletions .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
name: E2E Tests

on:
push:
branches: [main, e2e-tests]
pull_request:
branches: [main, e2e-tests]

jobs:
playwright:
name: Playwright Tests
timeout-minutes: 60
runs-on: ubuntu-latest
container:
image: mcr.microsoft.com/playwright:v1.55.0-jammy

steps:
- uses: actions/checkout@v4

- name: Install dependencies
run: npm ci

- name: Build Next.js application
run: npm run build
env:
NEXT_PUBLIC_WORKOS_REDIRECT_URI: ${{ vars.NEXT_PUBLIC_WORKOS_REDIRECT_URI }}

- name: Run Playwright tests
run: npx playwright test
env:
# Test environment variables
WORKOS_API_KEY: ${{ secrets.WORKOS_API_KEY }}
WORKOS_CLIENT_ID: ${{ secrets.WORKOS_CLIENT_ID }}
WORKOS_COOKIE_PASSWORD: ${{ secrets.WORKOS_COOKIE_PASSWORD }}
TEST_BASE_URL: http://localhost:3000
TEST_EMAIL: ${{ secrets.TEST_EMAIL }}
TEST_PASSWORD: ${{ secrets.TEST_PASSWORD }}

- name: Upload Playwright Report
uses: actions/upload-artifact@v4
if: ${{ !cancelled() }}
with:
name: playwright-report
path: playwright-report/
retention-days: 1

- name: Upload Test Results
uses: actions/upload-artifact@v4
if: ${{ !cancelled() }}
with:
name: playwright-test-results
path: test-results/
retention-days: 1

cypress:
name: Cypress Tests
timeout-minutes: 60
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: "npm"

- name: Install dependencies
run: npm ci

- name: Build Next.js application
run: npm run build
env:
NEXT_PUBLIC_WORKOS_REDIRECT_URI: ${{ vars.NEXT_PUBLIC_WORKOS_REDIRECT_URI }}

- name: Start Next.js application
run: npm start &
env:
# Runtime environment variables for server
WORKOS_API_KEY: ${{ secrets.WORKOS_API_KEY }}
WORKOS_CLIENT_ID: ${{ secrets.WORKOS_CLIENT_ID }}
WORKOS_COOKIE_PASSWORD: ${{ secrets.WORKOS_COOKIE_PASSWORD }}
PORT: 3000

- name: Wait for application to start
run: |
timeout 30 bash -c 'until curl -s http://localhost:3000 > /dev/null; do sleep 1; done'

- name: Run Cypress tests
run: npm run test:cypress
env:
# Test environment variables
WORKOS_API_KEY: ${{ secrets.WORKOS_API_KEY }}
WORKOS_CLIENT_ID: ${{ secrets.WORKOS_CLIENT_ID }}
WORKOS_COOKIE_PASSWORD: ${{ secrets.WORKOS_COOKIE_PASSWORD }}
TEST_BASE_URL: http://localhost:3000
TEST_EMAIL: ${{ secrets.TEST_EMAIL }}
TEST_PASSWORD: ${{ secrets.TEST_PASSWORD }}

- name: Upload Cypress Screenshots
uses: actions/upload-artifact@v4
if: failure()
with:
name: cypress-screenshots
path: cypress/screenshots
retention-days: 1

- name: Upload Cypress Videos
uses: actions/upload-artifact@v4
if: failure()
with:
name: cypress-videos
path: cypress/videos
retention-days: 1
10 changes: 10 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,14 @@
/node_modules
/.pnp
.pnp.js
.yarn/install-state.gz

# testing
/coverage
/test-results/
/playwright-report/
/blob-report/
/playwright/.auth

# next.js
/.next/
Expand All @@ -26,10 +31,15 @@ yarn-error.log*

# local env files
.env*.local
.env.test

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts

# cypress
cypress/videos
cypress/screenshots
36 changes: 36 additions & 0 deletions cypress.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { defineConfig } from "cypress";
import dotenv from "dotenv";
import path from "path";
import { registerWorkOSTasks } from "./cypress/plugins/workos";

// Load environment variables from .env files
dotenv.config({ path: path.resolve(__dirname, ".env.local") });
dotenv.config({ path: path.resolve(__dirname, ".env.test") });

export default defineConfig({
e2e: {
baseUrl: process.env.TEST_BASE_URL,
supportFile: "cypress/support/e2e.ts",
specPattern: "cypress/e2e/**/*.cy.{js,jsx,ts,tsx}",
viewportWidth: 1280,
viewportHeight: 720,
video: false,
screenshotOnRunFailure: true,

setupNodeEvents(on, config) {
// Register WorkOS authentication tasks
registerWorkOSTasks(on, config);

// Pass through environment variables to Cypress
config.env = {
...config.env,
WORKOS_CLIENT_ID: process.env.WORKOS_CLIENT_ID,
WORKOS_API_KEY: process.env.WORKOS_API_KEY,
TEST_BASE_URL: process.env.TEST_BASE_URL,
TEST_EMAIL: process.env.TEST_EMAIL,
TEST_PASSWORD: process.env.TEST_PASSWORD,
};
return config;
},
},
});
87 changes: 87 additions & 0 deletions cypress/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# E2E Testing with Cypress and WorkOS AuthKit

This directory contains Cypress tests for WorkOS AuthKit authentication using programmatic authentication.

## Setup

1. **Environment Variables** (same as Playwright tests)

```bash
# WorkOS Configuration
WORKOS_CLIENT_ID=your_client_id
WORKOS_API_KEY=your_api_key
WORKOS_COOKIE_PASSWORD=your_cookie_password

# Test Configuration
TEST_BASE_URL=http://localhost:3000
```

2. **Run Tests**

```bash
npm run test:cypress # Headless
npm run test:cypress:open # Interactive
```

## Authentication

### **Custom Command**

```typescript
// Authenticate as specific user
cy.login(Cypress.env("TEST_EMAIL"), Cypress.env("TEST_PASSWORD"));
```

### **Session Caching**

- First use: API authentication + session creation
- Subsequent uses: Cached session (faster)
- Auto-validation: Ensures session is still valid

## Usage

**Authenticated Tests:**

```typescript
describe("Admin Features", () => {
beforeEach(() => {
cy.login(Cypress.env("TEST_EMAIL"), Cypress.env("TEST_PASSWORD"));
});

it("can access admin panel", () => {
cy.visit("/admin"); // Already authenticated
});
});
```

**Unauthenticated Tests:**

```typescript
describe("Public Features", () => {
// No beforeEach = unauthenticated

it("shows login page", () => {
cy.visit("/");
});
});
```

## Test Endpoint

The tests use the following API endpoint for programmatic authentication and session creation:

**Endpoint:** `POST /api/test/set-session`

- **Purpose:** Create session from authentication tokens
- **Body:** `{ user, accessToken, refreshToken }`
- **Response:** Uses WorkOS AuthKit's `saveSession` method to create encrypted session cookie

The endpoint is to be used for testing purposes only and is recommended to be disabled in production environments.

## Files

- `plugins/workos.ts` - WorkOS authentication plugin
- `support/commands.ts` - Authentication command
- `support/e2e.ts` - Test configuration
- `e2e/authenticated-flows.cy.ts` - Tests for logged-in users
- `e2e/unauthenticated-flows.cy.ts` - Tests for anonymous users
Loading