nuxt / test-utils

🧪 Test utilities for Nuxt
http://nuxt.com/docs/getting-started/testing
MIT License
287 stars 74 forks source link

Using `throw` in component causes unit test to timeout #875

Open palmer-rm opened 4 days ago

palmer-rm commented 4 days ago

Environment

Reproduction

https://stackblitz.com/edit/github-jk1bg9?file=package.json,app.nuxt.test.ts

Command: npm run test

Describe the bug

I am using Nuxt's createError to handle errors from within Vue components.

When using the throw keyword inside a component, a unit test that mounts that component fails due to a timeout.

This happens regardless of whether the component throws Nuxt's createError, newError, or anything else, e.g:

throw createError();
throw new Error();
throw () => null;

Results in:

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.

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Unhandled Rejection ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯
Unknown Error: This is an error
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯
Serialized Error: { statusCode: 500 }
This error originated in "app.nuxt.test.ts" test file. It doesn't mean the error was thrown inside the file itself, but while it was running.
The latest test that might've caused the error is "calls createError with correct error". It might mean one of the following:
- The error was thrown, while Vitest was running this test.
- If the error occurred after the test had been completed, this was the last documented test before it was thrown.

When mounting the component using mount in @vue/test-utils (which mountSuspended wraps IIRC), using throw in a component does not result in a failed test due to timeout.

Using a try catch in the component still causes the test to timeout, i.e:

try {
  // Do something
} catch (e) {
  throw new Error();
}
dosubot[bot] commented 4 days ago

@palmer-rm Hello there! I'm a bot here to help you with bugs, questions, and becoming a contributor. Let's squash those bugs together!

To resolve the issue where using the throw keyword in a Vue component causes a unit test to timeout in a Nuxt 3 project, you should handle the error properly within the component. Instead of letting the error propagate and cause the test to timeout, you can catch the error and handle it gracefully. Here is an example of how you can modify the component to catch the error:

<template>
  <div>
    This should not display.
  </div>
</template>

<script lang="ts">
export default defineComponent({
  data () {
    try {
      throw new Error('💀')
    } catch (error) {
      console.error(error)
      // Handle the error appropriately, e.g., set an error state
    }
  },
})
</script>

By catching the error within the data method, you prevent the error from causing the unit test to timeout. Instead, the error is logged, and you can handle it as needed within the component.

Additionally, ensure you have set up your testing environment correctly using @nuxt/test-utils and vitest as described in the Nuxt documentation. This includes configuring your vitest.config.ts to use the Nuxt environment:

import { defineVitestConfig } from '@nuxt/test-utils/config'

export default defineVitestConfig({
  test: {
    environment: 'nuxt',
    // you can optionally set Nuxt-specific environment options
    // environmentOptions: {
    //   nuxt: {
    //     rootDir: fileURLToPath(new URL('./playground', import.meta.url)),
    //     domEnvironment: 'happy-dom', // 'happy-dom' (default) or 'jsdom'
    //     overrides: {
    //       // other Nuxt config you want to pass
    //     }
    //   }
    // }
  }
})

This setup ensures that your tests run in a proper Nuxt environment, which can help prevent issues like timeouts due to unhandled errors [1][2][3].

To continue talking to Dosu, mention @dosu.