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

Transferring Files from Bower to Library Directory in ASP.Net Core Web Application

Exploring ASP.Net Core + NPM for the first time, I have been trying out different online tutorials. However, most of them don't seem to work completely as expected, including the current one that I am working on. I'm facing an issue where Bower ...

Retrieve data from REST call to populate Material dropdown menu

I am looking to dynamically populate a dropdown menu with data retrieved from a Rest API. I attempted the following code: <Select id="country-helper"> {array.map((element) => ( <MenuItem value={element.code}>{element.country}& ...

I want my Angular 2 application to redirect to the appropriate page when a user who is logged out attempts to access a page that requires them to be logged in

When a user is logged out in Angular 2 router and they try to navigate to a page that requires them to be logged in, I need the app.ts file to redirect them. I am utilizing typescript along with angular 2. Oddly enough, the redirection works for certain ...

access search input value in Vuetify combobox on blur event

In my v-combobox, I can easily select or deselect multiple items from a list of objects. <div id="app"> <v-app> <v-layout column> <v-form v-model="valid"> <v-combobox v-model="selectedItems" ...

Finding the route name in VueJS

I am currently working on a VueJS script to control the visibility of the navbar based on whether the user is on a login or register page. However, I am facing an issue where the console returns undefined when I try to access this.$route.name. To address t ...

Vue JS is unable to interpret CSS codes within components

Currently, I am working on a project using Vue.js in combination with Laravel. However, I encountered a problem when trying to execute the npm run watch command. Vue.js is throwing the following error and preventing the project from being built: ERROR in ...

Guidelines for sending data to child components using Vue Router

I'm currently working on a Vue component that includes Navigation and layout features and relies on a bus to communicate with its sub-components. The bus is passed down as a prop to the sub components, which then utilize $emit for communication. expo ...

Guide on utilizing a provider's variable in another provider within Ionic 2/3

In my code, I have a boolean variable called isConnection that is used to monitor network connection status. This variable is defined in a provider named 'network' and can be set to either true or false in different functions. Now, I need to acc ...

Loop through the tabs in a for loop until reaching the specified length

I have a switch case function inside a modal in Vue. My goal is to create tabs or screens for different components. <div v-switch="tabnumber"> <div v-case="1"> <form-component> ...

The most accurate type to determine after verifying that `typeof a === 'object' && a !== null` is the following

Within my codebase, there exists an assertion function that verifies a given value is an object (using the typeof operator), with the exception of null: export function assertIsJavaScriptObjectExceptNull(value: unknown) { if (typeof value !== 'obj ...

Decoding enum interface attribute from response object in Angular 4 using typescript

From an API response, I am receiving an enum value represented as a string. This enum value is part of a typescript interface. Issue: Upon receiving the response, the TypeScript interface stores the value as a string, making it unusable directly as an en ...

TypeScript issue encountered with parseInt() function when used with a numeric value

The functionality of the JavaScript function parseInt allows for the coercion of a specified parameter into an integer, regardless of whether that parameter is originally a string, float number, or another type. While in JavaScript, performing parseInt(1. ...

Is it possible to utilize the maximum value from the store in Vuelidate while implementing Vue?

Utilizing VUE and Vuelidate for form input validation, specifically within a modal popup that retrieves data through ...mapGetters from the store. When static values are set like this, it functions correctly : validations: { refundAmount: { ...

Checkbox in Angular FormGroup not triggering touched state

There seems to be an issue with the Angular form when checking if the form is touched, especially in relation to a checkbox element. Despite the value of the checkbox changing on click, I am seeing !newDeviceGroup.touched = true. I'm not quite sure wh ...

The argument passed cannot be assigned to the parameter required

Currently, I am in the process of transitioning an existing React project from JavaScript to TypeScript. One function in particular that I am working on is shown below: const isSad = async (value: string) => { return await fetch(process.env.REACT_AP ...

Steps for utilizing a Get() method to view a response within Angular

I am having trouble with implementing an API call on a page and I'm unsure about what's wrong with the Subscribe/Observe method. Currently, this is the code that I have: import { Component, OnInit } from '@angular/core'; import { Ro ...

Tips for incorporating Angular2 into Eclipse using TypeScript

Recently, I delved into the world of Angular 2 and noticed that TypeScript is highly recommended over JavaScript. Intrigued by this recommendation, I decided to make the switch as well. I came across a helpful guide for setting up everything in Eclipse - f ...

Why isn't my prop available in the child component of Vue.js parent-child components yet?

Within the parent component Member.vue, I retrieve user and account data from the Vuex store using getters. <script> import { mapGetters } from 'vuex' import Profile from '@/components/Member/Profile.vue' export default { name: ...

Why is it that when I try to create a table using the "Create Table" statement, I keep getting an error saying "Near '(': syntax error"?

Error : There seems to be a syntax error near "(". Here is the SQL statement causing the issue: CREATE TABLE IF NOT EXISTS tickets ( numero INTEGER PRIMARY KEY AUTOINCREMENT, identifier VARCHAR(4) NOT NULL, subject VARCHAR(150) NOT NULL, ...