This directory contains end-to-end and API tests for Berkeleytime using Playwright.
tests/
├── sanity/ # Fast smoke tests (run on every PR)
├── api/ # GraphQL API unit tests
├── e2e/ # Comprehensive end-to-end user flows
├── fixtures/ # Shared test data and fixtures
└── utils/ # Test utilities and helpers
-
Ensure you have docker-compose running with all services:
docker compose up
-
Install Playwright browsers (first time only):
npx playwright install
# Run all test suites
npx playwright test
# Run only sanity tests (fast)
npx playwright test --project=sanity
# Run only API tests
npx playwright test --project=api
# Run only e2e tests (all browsers)
npx playwright test --grep e2e# Run a specific test file
npx playwright test tests/sanity/smoke.spec.ts
# Run tests in UI mode (interactive)
npx playwright test --ui
# Run tests in headed mode (see the browser)
npx playwright test --headed
# Debug a specific test
npx playwright test --debug tests/sanity/smoke.spec.ts- Purpose: Verify critical functionality works
- Speed: Must complete in < 2-3 minutes total
- Coverage: Homepage loads, API responds, core navigation works
- Browser: Chromium only (for speed)
- When to run: Every PR
Example:
test('homepage loads successfully', async ({ page }) => {
await page.goto('/');
await expect(page).toHaveTitle(/Berkeleytime/i);
});- Purpose: Test GraphQL API endpoints directly
- Speed: Very fast (no browser overhead)
- Coverage: Queries, mutations, input validation, error handling
- When to run: Every PR
Example:
test('can query courses', async ({ request }) => {
const response = await request.post('/api/graphql', {
data: {
query: `{ courses { id title } }`,
},
});
expect(response.ok()).toBeTruthy();
const data = await response.json();
expect(data.data.courses).toBeDefined();
});- Purpose: Test complete user flows from frontend to backend
- Speed: Slower (5-10 minutes)
- Coverage: Search courses, view ratings, create schedule, authentication, etc.
- Browsers: Chromium, Firefox, Safari, Mobile (iPhone 12)
- When to run: Can run on PR or separately
Example:
test('can search and view course details', async ({ page }) => {
await page.goto('/');
await page.getByPlaceholder(/search/i).fill('CS 61A');
await page.getByTestId('course-result').first().click();
await expect(page).toHaveURL(/course/);
});When you open a PR, GitHub Actions automatically:
- Checks out your code
- Runs
docker compose up --buildto build your changes - Runs sanity tests against the built code
- Reports results in the PR
See .github/workflows/playwright.yml
- Local Development: Tests run against your running
docker composeinstance - CI (Pull Requests): Tests run against the code in the PR (built fresh via docker-compose)
The TEST_ENV environment variable controls this:
TEST_ENV=local(default): Uses your existing docker-composeTEST_ENV=ci: Starts fresh docker-compose in CI
For tests that need specific data (courses, users, ratings), add fixtures in tests/fixtures/:
// tests/fixtures/test-data.ts
export const sampleCourses = [
{ code: 'CS 61A', name: 'Structure and Interpretation of Computer Programs' },
{ code: 'CS 61B', name: 'Data Structures' },
];- Use data-testid attributes: Add
data-testidto important UI elements for stable selectors - Avoid hardcoded waits: Use
waitForSelectorinstead ofwaitForTimeout - Keep sanity tests fast: Only test critical paths
- Test APIs directly: Use API tests for backend logic, E2E for user workflows
- Use descriptive test names:
test('can search for course by name')nottest('test 1') - Independent tests: Each test should work in isolation
# View last test run report
npx playwright show-report
# Run with verbose logging
DEBUG=pw:api npx playwright test
# Record a test (generates test code)
npx playwright codegen http://localhost:3000- Ensure
docker compose upis running - Check that frontend is accessible at http://localhost:3000
- Check if the endpoint requires authentication
- Add test auth tokens or mock authentication in
tests/fixtures/
- Increase timeout in test:
test.setTimeout(60000) - Or in config: Update
timeoutinplaywright.config.ts