Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
jrutila opened this issue Mar 20, 2024 · 2 comments
Open

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

jrutila opened this issue Mar 20, 2024 · 2 comments

Comments

@jrutila
Copy link
Sponsor Contributor

jrutila commented Mar 20, 2024

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
@mathiasrando
Copy link

If you don't actually need the plugin for the test I would assume you could add an early return in your defineNuxtPlugin based on the environment. Maybe you can useimport.meta.test or pass a variable yourself and check for that using import.meta.env.YOUR_VARIABLE and your script in package.json being YOUR_VARIABLE=true vitest.

https://nuxt.com/docs/api/advanced/import-meta

@jrutila
Copy link
Sponsor Contributor Author

jrutila commented Mar 22, 2024

If you don't actually need the plugin for the test I would assume you could add an early return in your defineNuxtPlugin based on the environment.

This is a good tip if you don't need the plugin. Still, cluttering the plugin code with that kind of a check is also little smelly. I investigated and I don't think there is a way to disable, say in vitest.config, certain autoloaded plugins in tests run by test-utils? That is totally different topic, though.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants