Hone logo
Hone
Problems

Mastering Vue Unit Testing with Vue Test Utils

This challenge focuses on building a robust testing suite for a Vue.js application using Vue Test Utils. You will learn to effectively mount Vue components, interact with them, and assert their behavior, which is crucial for ensuring the stability and maintainability of your Vue applications.

Problem Description

Your task is to write unit tests for a simple Vue.js component using TypeScript and Vue Test Utils. The component, UserProfile.vue, displays a user's name and email, and has a button to toggle the visibility of the user's email.

Component: UserProfile.vue

<template>
  <div>
    <h2>User Profile</h2>
    <p>Name: {{ name }}</p>
    <button @click="toggleEmailVisibility">
      {{ emailVisible ? 'Hide Email' : 'Show Email' }}
    </button>
    <p v-if="emailVisible">Email: {{ email }}</p>
  </div>
</template>

<script lang="ts">
import { defineComponent, ref } from 'vue';

export default defineComponent({
  name: 'UserProfile',
  props: {
    name: {
      type: String,
      required: true,
    },
    email: {
      type: String,
      required: true,
    },
  },
  setup(props) {
    const emailVisible = ref(false);

    const toggleEmailVisibility = () => {
      emailVisible.value = !emailVisible.value;
    };

    return {
      emailVisible,
      toggleEmailVisibility,
    };
  },
});
</script>

What needs to be achieved:

You need to create a test file (e.g., UserProfile.spec.ts) that contains the following unit tests:

  1. Initial Render Test: Verify that the component renders correctly with the provided name prop. The email should not be visible initially.
  2. Email Visibility Toggle Test:
    • Click the "Show Email" button. Assert that the email is now visible and the button text changes to "Hide Email".
    • Click the "Hide Email" button. Assert that the email is no longer visible and the button text changes back to "Show Email".
  3. Prop Rendering Test: Ensure that both the name and email props are correctly rendered when the email is visible.

Key requirements:

  • Use vue-test-utils for mounting and interacting with the component.
  • Write tests in TypeScript.
  • Mock any necessary dependencies if the component were more complex (though for this simple component, direct prop passing is sufficient).

Expected behavior:

  • When the component is mounted with name="John Doe" and email="john.doe@example.com", it should display "Name: John Doe" and a button with the text "Show Email". The email itself should not be displayed.
  • Clicking the "Show Email" button should display "Email: john.doe@example.com" and change the button text to "Hide Email".
  • Clicking the "Hide Email" button should hide the email again and change the button text back to "Show Email".

Edge cases to consider:

  • What happens if the name or email props are empty strings? (For this challenge, assume valid string inputs as per required: true.)

Examples

Example 1: Initial Render

// Assuming UserProfile.vue is imported and mounted correctly
const wrapper = mount(UserProfile, {
  props: {
    name: 'Jane Smith',
    email: 'jane.smith@example.com',
  },
});

// Assertions:
expect(wrapper.find('h2').text()).toBe('User Profile');
expect(wrapper.find('p:first-of-type').text()).toBe('Name: Jane Smith');
expect(wrapper.find('button').text()).toBe('Show Email');
expect(wrapper.find('p:last-of-type').exists()).toBe(false); // Email should not be visible

Example 2: Toggling Email Visibility

// Assuming component is mounted as in Example 1

// Click to show email
await wrapper.find('button').trigger('click');

// Assertions after showing
expect(wrapper.find('button').text()).toBe('Hide Email');
expect(wrapper.find('p:last-of-type').text()).toBe('Email: jane.smith@example.com');
expect(wrapper.find('p:last-of-type').exists()).toBe(true);

// Click to hide email
await wrapper.find('button').trigger('click');

// Assertions after hiding
expect(wrapper.find('button').text()).toBe('Show Email');
expect(wrapper.find('p:last-of-type').exists()).toBe(false);

Constraints

  • All tests must be written in TypeScript.
  • You must use the vue-test-utils library.
  • The tests should be self-contained and runnable with a standard Vue testing setup (e.g., using Vitest or Jest).
  • Assume the component's internal logic (setup function) remains as provided.

Notes

  • You'll need to install vue-test-utils and any necessary testing framework (like Vitest or Jest) and their TypeScript types.
  • Consider using await when triggering events, as DOM updates might be asynchronous.
  • Familiarize yourself with vue-test-utils's mount function and the methods available on the wrapper object (e.g., find, text, trigger, exists).
  • The name and email props are crucial for testing the initial state and verifying content.
  • The button's text dynamically changes, which is a good indicator to test the state change.
Loading editor...
typescript