Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ jobs:
run: pnpm install

- name: 🏗️ Build project
run: pnpm build
run: NODE_ENV=test pnpm build

- name: ♿ Accessibility audit (Lighthouse - ${{ matrix.mode }} mode)
run: ./scripts/lighthouse-a11y.sh
Expand Down
64 changes: 64 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ We want to create 'a fast, modern browser for the npm registry.' This means, amo
- [Unit tests](#unit-tests)
- [Component accessibility tests](#component-accessibility-tests)
- [End to end tests](#end-to-end-tests)
- [Test fixtures (mocking external APIs)](#test-fixtures-mocking-external-apis)
- [Submitting changes](#submitting-changes)
- [Before submitting](#before-submitting)
- [Pull request process](#pull-request-process)
Expand Down Expand Up @@ -482,6 +483,69 @@ pnpm test:browser:ui # Run with Playwright UI

Make sure to read about [Playwright best practices](https://playwright.dev/docs/best-practices) and don't rely on classes/IDs but try to follow user-replicable behaviour (like selecting an element based on text content instead).

### Test fixtures (mocking external APIs)

E2E tests use a fixture system to mock external API requests, ensuring tests are deterministic and don't hit real APIs. This is handled at two levels:

**Server-side mocking** (`modules/fixtures.ts` + `modules/runtime/server/cache.ts`):

- Intercepts all `$fetch` calls during SSR
- Serves pre-recorded fixture data from `test/fixtures/`
- Enabled via `NUXT_TEST_FIXTURES=true` or Nuxt test mode

**Client-side mocking** (`test/e2e/test-utils.ts`):

- Uses Playwright's route interception to mock browser requests
- All test files import from `./test-utils` instead of `@nuxt/test-utils/playwright`
- Throws a clear error if an unmocked external request is detected

#### Fixture files

Fixtures are stored in `test/fixtures/` with this structure:

```
test/fixtures/
├── npm-registry/
│ ├── packuments/ # Package metadata (vue.json, @nuxt/kit.json)
│ ├── search/ # Search results (vue.json, nuxt.json)
│ └── orgs/ # Org package lists (nuxt.json)
├── npm-api/
│ └── downloads/ # Download stats
└── users/ # User package lists
```

#### Adding new fixtures

1. **Generate fixtures** using the script:

```bash
pnpm generate:fixtures vue lodash @nuxt/kit
```

2. **Or manually create** a JSON file in the appropriate directory

#### Environment variables

| Variable | Purpose |
| --------------------------------- | ---------------------------------- |
| `NUXT_TEST_FIXTURES=true` | Enable server-side fixture mocking |
| `NUXT_TEST_FIXTURES_VERBOSE=true` | Enable detailed fixture logging |

#### When tests fail due to missing fixtures

If a test fails with an error like:

```
UNMOCKED EXTERNAL API REQUEST DETECTED
API: npm registry
URL: https://registry.npmjs.org/some-package
```

You need to either:

1. Add a fixture file for that package/endpoint
2. Update the mock handlers in `test/e2e/test-utils.ts` (client) or `modules/runtime/server/cache.ts` (server)

## Submitting changes

### Before submitting
Expand Down
40 changes: 40 additions & 0 deletions modules/fixtures.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import process from 'node:process'
import { addServerPlugin, createResolver, defineNuxtModule, useNuxt } from 'nuxt/kit'

/**
* Test fixtures module for mocking external API requests.
*
* This module intercepts server-side requests to external APIs (npm registry, etc.)
* and serves pre-recorded fixture data instead. This ensures tests are deterministic
* and don't depend on external API availability.
*
* Enabled when:
* - `nuxt.options.test` is true (Nuxt test mode), OR
* - `NUXT_TEST_FIXTURES=true` environment variable is set
*
* Set `NUXT_TEST_FIXTURES_VERBOSE=true` for detailed logging.
*
* Note: This only mocks server-side requests. For client-side mocking in
* Playwright tests, see test/e2e/test-utils.ts.
*/
export default defineNuxtModule({
meta: {
name: 'fixtures',
},
setup() {
const nuxt = useNuxt()
const resolver = createResolver(import.meta.url)

if (nuxt.options.test || process.env.NUXT_TEST_FIXTURES === 'true') {
addServerPlugin(resolver.resolve('./runtime/server/cache.ts'))

nuxt.hook('nitro:config', nitroConfig => {
nitroConfig.storage ||= {}
nitroConfig.storage['fixtures'] = {
driver: 'fsLite',
base: resolver.resolve('../test/fixtures'),
}
})
}
},
})
Loading
Loading