Skip to content

Commit c295d19

Browse files
authored
test: use fixtures for server side api fetches (#828)
1 parent b85af80 commit c295d19

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+39529
-64
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ jobs:
117117
run: pnpm install
118118

119119
- name: 🏗️ Build project
120-
run: pnpm build
120+
run: NODE_ENV=test pnpm build
121121

122122
- name: ♿ Accessibility audit (Lighthouse - ${{ matrix.mode }} mode)
123123
run: ./scripts/lighthouse-a11y.sh

CONTRIBUTING.md

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ We want to create 'a fast, modern browser for the npm registry.' This means, amo
4242
- [Unit tests](#unit-tests)
4343
- [Component accessibility tests](#component-accessibility-tests)
4444
- [End to end tests](#end-to-end-tests)
45+
- [Test fixtures (mocking external APIs)](#test-fixtures-mocking-external-apis)
4546
- [Submitting changes](#submitting-changes)
4647
- [Before submitting](#before-submitting)
4748
- [Pull request process](#pull-request-process)
@@ -482,6 +483,69 @@ pnpm test:browser:ui # Run with Playwright UI
482483

483484
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).
484485

486+
### Test fixtures (mocking external APIs)
487+
488+
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:
489+
490+
**Server-side mocking** (`modules/fixtures.ts` + `modules/runtime/server/cache.ts`):
491+
492+
- Intercepts all `$fetch` calls during SSR
493+
- Serves pre-recorded fixture data from `test/fixtures/`
494+
- Enabled via `NUXT_TEST_FIXTURES=true` or Nuxt test mode
495+
496+
**Client-side mocking** (`test/e2e/test-utils.ts`):
497+
498+
- Uses Playwright's route interception to mock browser requests
499+
- All test files import from `./test-utils` instead of `@nuxt/test-utils/playwright`
500+
- Throws a clear error if an unmocked external request is detected
501+
502+
#### Fixture files
503+
504+
Fixtures are stored in `test/fixtures/` with this structure:
505+
506+
```
507+
test/fixtures/
508+
├── npm-registry/
509+
│ ├── packuments/ # Package metadata (vue.json, @nuxt/kit.json)
510+
│ ├── search/ # Search results (vue.json, nuxt.json)
511+
│ └── orgs/ # Org package lists (nuxt.json)
512+
├── npm-api/
513+
│ └── downloads/ # Download stats
514+
└── users/ # User package lists
515+
```
516+
517+
#### Adding new fixtures
518+
519+
1. **Generate fixtures** using the script:
520+
521+
```bash
522+
pnpm generate:fixtures vue lodash @nuxt/kit
523+
```
524+
525+
2. **Or manually create** a JSON file in the appropriate directory
526+
527+
#### Environment variables
528+
529+
| Variable | Purpose |
530+
| --------------------------------- | ---------------------------------- |
531+
| `NUXT_TEST_FIXTURES=true` | Enable server-side fixture mocking |
532+
| `NUXT_TEST_FIXTURES_VERBOSE=true` | Enable detailed fixture logging |
533+
534+
#### When tests fail due to missing fixtures
535+
536+
If a test fails with an error like:
537+
538+
```
539+
UNMOCKED EXTERNAL API REQUEST DETECTED
540+
API: npm registry
541+
URL: https://registry.npmjs.org/some-package
542+
```
543+
544+
You need to either:
545+
546+
1. Add a fixture file for that package/endpoint
547+
2. Update the mock handlers in `test/e2e/test-utils.ts` (client) or `modules/runtime/server/cache.ts` (server)
548+
485549
## Submitting changes
486550

487551
### Before submitting

knip.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ const config: KnipConfig = {
2626
'scripts/**/*.ts',
2727
],
2828
project: ['**/*.{ts,vue,cjs,mjs}'],
29+
ignore: ['test/fixtures/**'],
2930
ignoreDependencies: [
3031
'@iconify-json/*',
3132
'@vercel/kv',

modules/fixtures.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import process from 'node:process'
2+
import { addServerPlugin, createResolver, defineNuxtModule, useNuxt } from 'nuxt/kit'
3+
4+
/**
5+
* Test fixtures module for mocking external API requests.
6+
*
7+
* This module intercepts server-side requests to external APIs (npm registry, etc.)
8+
* and serves pre-recorded fixture data instead. This ensures tests are deterministic
9+
* and don't depend on external API availability.
10+
*
11+
* Enabled when:
12+
* - `nuxt.options.test` is true (Nuxt test mode), OR
13+
* - `NUXT_TEST_FIXTURES=true` environment variable is set
14+
*
15+
* Set `NUXT_TEST_FIXTURES_VERBOSE=true` for detailed logging.
16+
*
17+
* Note: This only mocks server-side requests. For client-side mocking in
18+
* Playwright tests, see test/e2e/test-utils.ts.
19+
*/
20+
export default defineNuxtModule({
21+
meta: {
22+
name: 'fixtures',
23+
},
24+
setup() {
25+
const nuxt = useNuxt()
26+
const resolver = createResolver(import.meta.url)
27+
28+
if (nuxt.options.test || process.env.NUXT_TEST_FIXTURES === 'true') {
29+
addServerPlugin(resolver.resolve('./runtime/server/cache.ts'))
30+
31+
nuxt.hook('nitro:config', nitroConfig => {
32+
nitroConfig.storage ||= {}
33+
nitroConfig.storage['fixtures'] = {
34+
driver: 'fsLite',
35+
base: resolver.resolve('../test/fixtures'),
36+
}
37+
})
38+
}
39+
},
40+
})

0 commit comments

Comments
 (0)