nuxt / nuxt/test-utils

Overriding global $fetch with `ofetch.create` will break the test run

Open
#798 3 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

pending triage
Dominant language
TypeScript
Stars
437
Forks
120
Avg merge
22h 52m
Merged PRs (30d)
23

Description

Environment

Nuxt project info:


  • Operating System: Linux
  • Node Version: v18.18.0
  • Nuxt Version: 3.11.1
  • CLI Version: 3.11.0
  • Nitro Version: 2.9.4
  • Package Manager: npm@10.2.3
  • Builder: -
  • User Config: devtools
  • Runtime Modules: -
  • Build Modules: -

@nuxt/test-utils version: 3.12.0
vitest version: 1.4.0

Reproduction

Here is a reproduce stackblitz: https://stackblitz.com/edit/github-lxyzpn?file=plugins%2Fonrequest.client.ts

Create a plugin that will override the default $fetch. This is handy when trying to inject your own headers into the HTTP requests. If you google this, you will find a helpful SO solution: https://stackoverflow.com/a/75871291/216846

import { ofetch } from 'ofetch';

export default defineNuxtPlugin((_nuxtApp) => {
  globalThis.$fetch = ofetch.create({ // <- this is the important part!
    onRequest({ request, options }) {
      options.headers = { Authorization: `Bearer token` };
      console.log('onRequest', request);
    },
    onRequestError({ error }) {
      console.log(error);
    },
  });
});

This works fine when running the dev environment or prod environment. When you now run @nuxt/test-utils based test case, the tests pass, but the run fails to this error (see the whole log in logs):

TypeError: Cannot set property request of FetchError: [GET] "/_nuxt/builds/meta/test.json": <no response> Failed to parse URL from /_nuxt/builds/meta/test.json which has only a getter
Describe the bug

The correct way to implement this kind of plugin that edits the HTTP requests is described here: https://nuxt.com/docs/examples/advanced/use-custom-fetch-composable. Instead of returning you just inject the globalThis.$fetch with the created fetch instance.

The bug is that in dev and prod environments you can as well do it like this globalThis.$fetch = ofetch.create. Everything works, except when you run unit tests with @nuxt/test-utils, you get errors described above.

So, again, the correct way is to do globalThis.$fetch = $fetch.create but I think there should be a warning or something guiding the devs to do it correctly. Or at least they find this bug issue and can fix it in their code.

Additional context

No response

Logs
~/projects/vbwirlala.github 4m 11s
❯ npm run test

> test
> vitest


 DEV  v1.4.0 /home/projects/vbwirlala.github

stdout | Object.onRequest (/home/projects/vbwirlala.github/plugins/onrequest.client.ts:8:15)
onRequest /_nuxt/builds/meta/test.json
onRequest /_nuxt/builds/meta/test.json

stdout | Object.onRequestError (/home/projects/vbwirlala.github/plugins/onrequest.client.ts:11:15)
TypeError: Failed to parse URL from /_nuxt/builds/meta/test.json
    at _0x88e3f9 (https://vbwirlalagithub-bvqi.w-credentialless-staticblitz.com/blitz.810981ba.js:352:614955)
    at _0x303d3a._0x5ec96b (https://vbwirlalagithub-bvqi.w-credentialless-staticblitz.com/blitz.810981ba.js:352:625681)
    at Object.t.exports.fetch (node:internal/deps/undici/undici:194:308109)
    at $fetchRaw2 (/home/projects/vbwirlala.github/node_modules/ofetch/dist/shared/ofetch.00501375.mjs:236:26)
    at $fetch2 (/home/projects/vbwirlala.github/node_modules/ofetch/dist/shared/ofetch.00501375.mjs:278:15) {
  [cause]: TypeError [ERR_INVALID_URL]: Invalid URL
      at __node_internal_ (node:internal/errors:36:5406)
      at new <anonymous> (node:internal/errors:36:4168)
      at new URL (node:internal/url:48:8018)
      at new URL (/home/projects/vbwirlala.github/node_modules/happy-dom/lib/url/URL.js:25:1)
      at new oe (node:internal/deps/undici/undici:194:83653)
      at fetch (node:internal/deps/undici/undici:194:307099)
      at Object.t.exports.fetch (node:internal/deps/undici/undici:194:308078)
      at node:internal/process/pre_execution:56:2507
      at $fetchRaw2 (/home/projects/vbwirlala.github/node_modules/ofetch/dist/shared/ofetch.00501375.mjs:236:32)
      at $fetch2 (/home/projects/vbwirlala.github/node_modules/ofetch/dist/shared/ofetch.00501375.mjs:278:15) {
    input: '/_nuxt/builds/meta/test.json',
    code: 'ERR_INVALID_URL'
  }
}
TypeError: Failed to parse URL from /_nuxt/builds/meta/test.json
    at _0x88e3f9 (https://vbwirlalagithub-bvqi.w-credentialless-staticblitz.com/blitz.810981ba.js:352:614955)
    at _0x303d3a._0x5ec96b (https://vbwirlalagithub-bvqi.w-credentialless-staticblitz.com/blitz.810981ba.js:352:625681)
    at Object.t.exports.fetch (node:internal/deps/undici/undici:194:308109)
    at $fetchRaw2 (/home/projects/vbwirlala.github/node_modules/ofetch/dist/shared/ofetch.00501375.mjs:236:26)
    at $fetchRaw2 (/home/projects/vbwirlala.github/node_modules/ofetch/dist/shared/ofetch.00501375.mjs:245:14)
    at $fetch2 (/home/projects/vbwirlala.github/node_modules/ofetch/dist/shared/ofetch.00501375.mjs:278:15) {
  [cause]: TypeError [ERR_INVALID_URL]: Invalid URL
      at __node_internal_ (node:internal/errors:36:5406)
      at new <anonymous> (node:internal/errors:36:4168)
      at new URL (node:internal/url:48:8018)
      at new URL (/home/projects/vbwirlala.github/node_modules/happy-dom/lib/url/URL.js:25:1)
      at new oe (node:internal/deps/undici/undici:194:83653)
      at fetch (node:internal/deps/undici/undici:194:307099)
      at Object.t.exports.fetch (node:internal/deps/undici/undici:194:308078)
      at node:internal/process/pre_execution:56:2507
      at $fetchRaw2 (/home/projects/vbwirlala.github/node_modules/ofetch/dist/shared/ofetch.00501375.mjs:236:32) {
    input: '/_nuxt/builds/meta/test.json',
    code: 'ERR_INVALID_URL'
  }
}

stdout | createSuspenseBoundary (/home/projects/vbwirlala.github/node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:1442:43)
<Suspense> is an experimental feature and its API will likely change.

 ✓ test/my.spec.ts (1)
   ✓ abba (1)
     ✓ should be abba

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Unhandled Errors ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯

Vitest caught 1 unhandled error during the test run.
This might cause false positive tests. Resolve unhandled errors to make sure your tests are not affected.

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Uncaught Exception ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯
TypeError: Cannot set property request of FetchError: [GET] "/_nuxt/builds/meta/test.json": <no response> Failed to parse URL from /_nuxt/builds/meta/test.json which has only a getter
 ❯ _0x46d1e6 ../../../blitz.810981ba.js:352:617597
 ❯ _0x1eee56 ../../../blitz.810981ba.js:352:615189
 ❯ FetchError.get ../../../blitz.810981ba.js:352:615388
 ❯ Module.processError node_modules/@vitest/utils/dist/error.js:95:11
 ❯ catchError node_modules/vitest/dist/vendor/execute.2_yoIC01.js:396:39
 ❯ process.unhandledRejection node_modules/vitest/dist/vendor/execute.2_yoIC01.js:406:37
 ❯ EventEmitter.emit node:events:42:9202
 ❯ emit node:internal/process/promises:230:1176
 ❯ processPromiseRejections node:internal/process/promises:230:3782
 ❯ processTicksAndRejections node:internal/process/task_queues:107:1089

This error originated in "test/my.spec.ts" test file. It doesn't mean the error was thrown inside the file itself, but while it was running.
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯

 Test Files  1 passed (1)
      Tests  1 passed (1)
     Errors  1 error
   Start at  08:55:23
   Duration  4.31s (transform 467ms, setup 535ms, collect 11ms, tests 2ms, environment 800ms, prepare 1.37s)


 FAIL  Tests failed. Watching for file changes...
       press h to show help, press q to quit

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the StackBlitz reproduction, especially plugins/onrequest.client.ts and test/my.spec.ts, and trace how @nuxt/test-utils handles an overridden globalThis.$fetch during its metadata request. Reproduce the unhandled error with the reported Nuxt and Vitest versions, then establish a regression check and the supported outcome for this configuration.

Written by the indexing model from the issue text.

Assessment

Tech stack
nuxt, typescript
Domain
testing-qa
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
32/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.