Experimenting with TypeScript Single File Component to test vue3's computed properties

Currently, I am in the process of creating a test using vitest to validate a computed property within a vue3 component that is implemented with script setup.

Let's consider a straightforward component:

// simple.vue
<script lang="ts" setup>
import { computed } from 'vue';

const hello = computed((): string => {
  return 'Hello';
});
</script>

<template>
  {{ hello }}
</template>

The test I have written looks like this:

describe('Hello', () => {
  it('should compute hello', () => {
    const wrapper = mount(Hello);
    expect(wrapper.vm.hello).toBe('Hello');
  });
});

This test functions correctly when executed with vitest, indicating that things are working as intended.

However, Visual Studio Code does not recognize the computed properties on the vm object:

https://i.stack.imgur.com/WZe83.png

While normal properties (e.g., those defined with the defineProps macro) are visible. Is this an issue specific to VSCode or is there a more efficient method for testing computed properties in vue3 components?

If the current approach is recommended, is there a way to incorporate the types of the computed properties (similar to how the types of defined props are imported)?

I have attempted the strategy outlined in the Vue Testing Handbook, but it was unsuccessful and I suspect it may only be applicable to vue2.

Answer №1

According to information found in Vue documentation:

When using <script setup>, components are initially set to be closed by default. This means that any bindings declared inside the <script setup> will not be accessible from the public instance of the component, obtained through template refs or $parent chains.

This characteristic also impacts the type of wrapper.vm in Vue Test Utils, limiting it to only include public or exposed props of the <script setup> component.

To address this, you can utilize the defineExpose() compiler macro to expose the hello property:

<script lang="ts" setup>
import { computed } from 'vue';

const hello = computed((): string => {
  return 'Hello';
});
     👇
defineExpose({ hello });
</script>

https://i.stack.imgur.com/nblfa.png

Answer №2

Assuming that you are using the mount function from the @vue/test-utils library, you can write your wrapper in a way that enables TypeScript autocompletion and eliminates errors:

import { mount, VueWrapper } from "@vue/test-utils";
import HelloWorld from "@/components/HelloWorld.vue"
import { ComponentPublicInstance } from "vue";

type MyComponentProps = any
type MyComponentVariables = {
  hello: string
}

type MyComponentWrapperType = VueWrapper<ComponentPublicInstance<MyComponentProps, MyComponentVariables>>

describe('Hello', () => {
  it('should compute hello', () => {
    const wrapper: MyComponentWrapperType = mount(HelloWorld);
    expect(wrapper.vm.hello).toBe('Hello');
  });
});


The first generic type is for the props of your component (I used any as an example), while the second generic type ({ bipbip: string }) defines the types of the properties returned by your component (usually defined in a setup function). By using <script setup>, you can directly declare all your variables within the script.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Searching for a way to access the HTTP request header using ReactJS?

Can anyone assist me in retrieving the request header's cookie? I have searched extensively but haven't found a satisfactory document. Please share with me a reliable solution. ...

Encountering difficulties while trying to access the SQLite database file through a JavaScript Axios GET request

Having trouble opening an sqlite DB file from a js axios.get request which is resulting in an exception message being outputted to the console. The request is supposed to call my PHP controller to retrieve data from the DB and return it json-encoded. On t ...

What is the solution for resolving the JavaScript runtime error '0x800a1391 - 'require' is undefined'?

As a C# developer with limited web experience, I am currently diving into learning Typescript. However, I seem to be facing a roadblock in the form of an error message. 0x800a1391 - JavaScript runtime error: 'require' is undefined To provide so ...

Storybook is pulling fonts from an incorrect location on the server

Regrettably, I am facing an issue where the fonts do not load when accessing a page with Quasar integration. In the Developer Tools, it shows a path error like this: http://localhost:6006/undefined/node_modules/@quasar/extras/roboto-font/web-font/KFOmCnqEu ...

Submit information by utilizing' content-type': 'application/x-www-form-urlencoded' and 'key': 'key'

Attempting to send data to the server with a content-type of 'application/xwww-form-urlencode' is resulting in a failure due to the content type being changed to application/json. var headers= { 'content-type': 'applica ...

Issue with sending multiple files using FormData and axios in Vuex with Laravel. Server side consistently receiving null. Need help troubleshooting the problem

After trying the solution from my previous question Vuex + Laravel. Why axios sends any values but only not that one, which come's with method's parameter?, I realized that it only works when passing a single argument in axios. I managed to succe ...

Creating dynamic child components in Vue.js version 2

I am currently developing a facet search system using VueJS. The concept is fairly straightforward: Within a FilterGroup component lies the overarching filter logic. This component allows for several child components, such as AttributeXYZFilter, to provid ...

Looping through dynamic image sources using v-for

I have 10 images in the resources/images directory that I want to display using the vue3-carousel library. The image files are named 1.jfif, 2.jfif, and so on. However, when trying to bind the image source attribute with a variable, it results in an error: ...

Utilizing the array.map method to access the key of an object within an array of arrays in TypeScript

Can I utilize array.map in TypeScript to apply a function with the parameter being the key of an object within an array? I have an array containing objects which have keys 'min' and 'max'. I am looking to use something like someArrayFun ...

How come accessing the superclass's property with a getter in TypeScript is not working as expected?

class A { protected _value:number; get value() { return this._value; } } class B extends A { set value(v:number) { this._value = v; } } var b = new B(); b.value = 2; console.log(b.value);//undefined Coding Pla ...

Vue: passing parameters between application and component through computed properties

I apologize for the basic question as I am new to Vue and struggling to find the right terminology to search for answers. I recently started learning Vue through this course (). The lesson involves a critical app-level data parameter named cart, which is a ...

Is error propagation from nested Promise to parent Promise not working properly in Node.js?

I'm currently working on a Node.js/TypeScript API with Express. Below is a snippet from my get method where I encountered an error in the format function. The error is caught by the promise, but it doesn't propagate to the parent promise after th ...

Tips for adding a time increment of 24 hours to a date variable in Angular 6

My goal is to update a date variable called EndDate stored in localStorage by adding exactly 24 hours to it. The current value in the localStorage is Sun Jun 09 2019 20:39:44 GMT+0530 (India Standard Time). var endDate = new Date(); endDate.setDat ...

Efficiently process and handle the responses from Promise.all for every API call, then save the retrieved data

Currently, I am passing three API calls to Promise.all. Each API call requires a separate error handler and data storage in its own corresponding object. If I pass test4 to Promise.all, how can I automatically generate its own error and store the data in ...

Optimal data structure for storage in a Next.js project with TypeScript

What is the appropriate data type for store in export let store: any; other than any? I have used @ts-igore to suppress TypeScript errors on the last line. How can I address the TypeScript error for that as well? I mentioned the boilerplates utilized in ...

Is there a navigation feature in VueJS that functions similarly to React Router?

I am currently working on enhancing the navigation experience of an existing vueJS application that utilizes Vue Router. When working with React, I typically structure breadcrumbs in the following manner: <Breadcrumbs> <Route path="/users&q ...

Detecting when users stop scrolling in Angular 5

Is there a way to toggle visibility of a div based on user scrolling behavior? I'd like the div to hide when the user scrolls and reappear once they stop. I've attempted to achieve this effect using @HostListener, but it only seems to trigger wh ...

Using i18next to efficiently map an array of objects in TypeScript

I am currently converting a React project to TypeScript and using Packages like Next.js, next-i18next, and styled-components. EDIT: The information provided here may be outdated due to current versions of next-i18next. Please check out: Typescript i18ne ...

Conceal the header on signup and login pages using Material UI

I am working on a project with three pages: SignUp, Login, and Lists, along with a header component. My goal is to hide the header on the SignUp and Login pages, and only show it on the List page. Any suggestions on how I can achieve this? Here is my cod ...

I am working on developing a CRUD application using Vue.Js, but I'm facing difficulties in adding new users to

I encountered an error while attempting to insert data into the database. The error message states that "Property or method 'saveUser' is not defined on the instance but referenced during render." Below is the code snippet: <script> impor ...