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

Errors in setup() are silent if render() throws an error #2083

Open
mikemonteith opened this issue Nov 3, 2023 · 6 comments
Open

Errors in setup() are silent if render() throws an error #2083

mikemonteith opened this issue Nov 3, 2023 · 6 comments

Comments

@mikemonteith
Copy link

Subject of the issue

Errors thrown in setup() are silently caught if the render function throws it's own error.
This can lead to confusing test error messages that seem like something is wrong in the template, when the issue is actually in the setup.

Consider the reproduction case below:

Steps to reproduce

package.json:

{
  "name": "vue-test-utils-bug",
  "version": "1.0.0",
  "description": "",
  "main": "test.js",
  "type": "module",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "@vue/test-utils": "^2.4.1"
  },
  "devDependencies": {
    "global-jsdom": "9.1.0",
    "jsdom": "22.1.0"
  }
}

test.js:

import 'global-jsdom/register'
import { mount } from '@vue/test-utils'

// The component to test
const MessageComponent = {
  template: `
    <p>{{ t('key') }}</p>
  `,
  setup: () => {
    throw Error("test error")
    return {
      t: (key) => "A translation"
    }
  },
}

// mount() returns a wrapped Vue component we can interact with
const wrapper = mount(MessageComponent)

Expected behaviour

I would expect the program to stop when setup() throws the error.

Actual behaviour

The program continues by rendering the template with an empty context, which then throws it's own error due to t being undefined.

Output:

[Vue warn]: Property "t" was accessed during render but is not defined on instance. 
  at <Anonymous ref="VTU_COMPONENT" > 
  at <VTUROOT>
undefined:9
    return (_openBlock(), _createElementBlock("p", null, _toDisplayString(t('key')), 1 /* TEXT */))
                                                                          ^

TypeError: t is not a function
    at Proxy.render (eval at compileToFunction (/Users/mike/dev/MIMO16/vue-jest-bug/node_modules/vue/dist/vue.cjs.js:66:18), <anonymous>:9:75)
    at renderComponentRoot (/Users/mike/dev/MIMO16/vue-jest-bug/node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:817:16)
    at ReactiveEffect.componentUpdateFn [as fn] (/Users/mike/dev/MIMO16/vue-jest-bug/node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:5705:46)
    at ReactiveEffect.run (/Users/mike/dev/MIMO16/vue-jest-bug/node_modules/@vue/reactivity/dist/reactivity.cjs.js:182:19)
    at instance.update (/Users/mike/dev/MIMO16/vue-jest-bug/node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:5818:51)
    at setupRenderEffect (/Users/mike/dev/MIMO16/vue-jest-bug/node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:5826:5)
    at mountComponent (/Users/mike/dev/MIMO16/vue-jest-bug/node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:5616:5)
    at processComponent (/Users/mike/dev/MIMO16/vue-jest-bug/node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:5569:9)
    at patch (/Users/mike/dev/MIMO16/vue-jest-bug/node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:5055:11)
    at ReactiveEffect.componentUpdateFn [as fn] (/Users/mike/dev/MIMO16/vue-jest-bug/node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:5712:11)
@mikemonteith
Copy link
Author

mikemonteith commented Nov 3, 2023

Is this a vue thing?

I've just found that this gives me the behaviour I want:

const wrapper = mount(MessageComponent, {
  global: {
    config: {
      errorHandler: (err) => {
        throw err;
      },
    }
  },
});

@mikemonteith
Copy link
Author

I've ended up adding this to our setup.js file to set this behaviour in all tests.

import { config } from '@vue/test-utils';

// By default, vue will attempt to continue past setup errors.
// This will cause tests to fail silently, so we make sure that
// exceptions are thrown immediately in all tests.
config.global.config.errorHandler = (err) => {
  throw err;
};

Maybe this could be more prominent in the docs?

@Bastczuak
Copy link

Bastczuak commented Mar 5, 2024

@mikemonteith dude you saved my day. I was chasing false errors.

TypeError: Cannot read properties of undefined (reading 'map')
 ❯ src/views/SubscriptionSelectSkeleton.vue:12:33
     10|       <v-card-text>
     11|         <v-select
     12|           :items="subscriptions.map(({ fqdn, id, stackName }) =>
       |                                 ^

In my case I was accessing an undefined value in useRoute in <script setup>, which let to this error. subscriptions was always a valid array.

Adding your code gave me the correct error output.

TypeError: Cannot read properties of undefined (reading '0')
 ❯ setup src/views/SubscriptionSelectSkeleton.vue:53:27
     51| const route = useRoute()
     52| const router = useRouter()
     53| const path = route.matched[0].path
                                   ^

In hindsight it makes sense, because the actual function which defines subscriptions was then never called.

@joaopedrodcf
Copy link

joaopedrodcf commented Mar 20, 2024

@mikemonteith I think from the version of your package.json it seems you opened the issue on the wrong repository:

 "@vue/test-utils": "^2.4.1"

This repository is for version 1 for the version 2: https://github.com/vuejs/test-utils/issues and the version you currently have: https://github.com/vuejs/test-utils/releases/tag/v2.4.1

@mikemonteith
Copy link
Author

@joaopedrodcf Well spotted. In that case, my issue is a duplicate of vuejs/test-utils#2319

@joaopedrodcf
Copy link

No problem glad to help ✌️

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

No branches or pull requests

3 participants