N
Nuxt2mo ago
CFHxKai

How can I know how much times a method inside the mocked composable was called in a test?

Hi. 😄 I'm trying to learn about tests in Nuxt but is a little hard to find content/courses about it. I have something like this:
import { describe, it, expect, vi } from 'vitest';
import {
mountSuspended,
mockNuxtImport,
} from '@nuxt/test-utils/runtime';
import { CustomBtn } from '#components';

const { useMyComposableMock } =
vi.hoisted(() => {
return {
useMyComposableMock : vi.fn(() => ({
myMethod: vi.fn(),
})),
};
});

describe('Component CustomBtn', async () => {
it('should call 4 times myMethod', async () => {
const component = await mountSuspended(CustomBtn);

const button = component.find('button');

await button.trigger('click');
await button.trigger('click');
await button.trigger('click');
await button.trigger('click');

expect(useMyComposableMock).toHaveBeenCalledTimes(4);
});
});
import { describe, it, expect, vi } from 'vitest';
import {
mountSuspended,
mockNuxtImport,
} from '@nuxt/test-utils/runtime';
import { CustomBtn } from '#components';

const { useMyComposableMock } =
vi.hoisted(() => {
return {
useMyComposableMock : vi.fn(() => ({
myMethod: vi.fn(),
})),
};
});

describe('Component CustomBtn', async () => {
it('should call 4 times myMethod', async () => {
const component = await mountSuspended(CustomBtn);

const button = component.find('button');

await button.trigger('click');
await button.trigger('click');
await button.trigger('click');
await button.trigger('click');

expect(useMyComposableMock).toHaveBeenCalledTimes(4);
});
});
This is called one time, and I think this is right because composable is instantiated one time, but how can I get how much times the method myMethod is called. For example inside the component file I have something like this:
<script setup lang="ts">
const { myMethod } = useMyComposable();

const handleMyBtnClick = async () => {
myMethod(someParams);
}
</script>

<template>
<button @click="hadleMyBtnClick">Click Here</button>
</template>
<script setup lang="ts">
const { myMethod } = useMyComposable();

const handleMyBtnClick = async () => {
myMethod(someParams);
}
</script>

<template>
<button @click="hadleMyBtnClick">Click Here</button>
</template>
And how can I get how much times method (handleMyBtnClick) inside de component who is handle this clicks are called? Thank you so much... 😉
5 Replies
kapa.ai
kapa.ai2mo ago
Hi @CFHxKai. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- To check how many times myMethod inside your mocked composable was called in a test, you can modify your test setup and assertions slightly. Here's how you can do it: 1. First, let's adjust the mock setup:
const myMethodMock = vi.fn();
const { useMyComposableMock } = vi.hoisted(() => {
return {
useMyComposableMock: vi.fn(() => ({
myMethod: myMethodMock,
})),
};
});

mockNuxtImport('useMyComposable', () => useMyComposableMock);
const myMethodMock = vi.fn();
const { useMyComposableMock } = vi.hoisted(() => {
return {
useMyComposableMock: vi.fn(() => ({
myMethod: myMethodMock,
})),
};
});

mockNuxtImport('useMyComposable', () => useMyComposableMock);
2. Then, in your test, you can assert on myMethodMock:
describe('Component CustomBtn', async () => {
it('should call myMethod 4 times', async () => {
const component = await mountSuspended(CustomBtn);

const button = component.find('button');

await button.trigger('click');
await button.trigger('click');
await button.trigger('click');
await button.trigger('click');

expect(myMethodMock).toHaveBeenCalledTimes(4);
});
});
describe('Component CustomBtn', async () => {
it('should call myMethod 4 times', async () => {
const component = await mountSuspended(CustomBtn);

const button = component.find('button');

await button.trigger('click');
await button.trigger('click');
await button.trigger('click');
await button.trigger('click');

expect(myMethodMock).toHaveBeenCalledTimes(4);
});
});
This approach allows you to check how many times myMethod was called. As for checking how many times handleMyBtnClick was called, since it's a method defined within the component, you can spy on it using Vue Test Utils' spyOn method:
describe('Component CustomBtn', async () => {
it('should call handleMyBtnClick 4 times', async () => {
const component = await mountSuspended(CustomBtn);
const handleMyBtnClickSpy = vi.spyOn(component.vm, 'handleMyBtnClick');

const button = component.find('button');

await button.trigger('click');
await button.trigger('click');
await button.trigger('click');
await button.trigger('click');

expect(handleMyBtnClickSpy).toHaveBeenCalledTimes(4);
});
});
describe('Component CustomBtn', async () => {
it('should call handleMyBtnClick 4 times', async () => {
const component = await mountSuspended(CustomBtn);
const handleMyBtnClickSpy = vi.spyOn(component.vm, 'handleMyBtnClick');

const button = component.find('button');

await button.trigger('click');
await button.trigger('click');
await button.trigger('click');
await button.trigger('click');

expect(handleMyBtnClickSpy).toHaveBeenCalledTimes(4);
});
});
These approaches should allow you to verify both the number of times your mocked composable method is called and the number of times the component's click handler is called. For more information on testing in Nuxt, you can refer to the Nuxt Testing documentation (https://nuxt.com/docs/getting-started/testing) and the mockNuxtImport helper documentation (https://nuxt.com/docs/getting-started/testing#mocknuxtimport). ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai2mo ago
<@206534948952342529> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
CFHxKai
CFHxKaiOP2mo ago
For the composable method worked... xD @kapa.ai for the method handleMyBtnClick in the component not work. AssertionError: expected "handleMyBtnClick" to be called 4 times, but got 0 times
kapa.ai
kapa.ai2mo ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- I apologize for the confusion in my previous answer. You're right that the method handleMyBtnClick is not directly accessible in the way I suggested. Let me provide a more accurate approach to test the click handler in a Nuxt component. In Nuxt 3 with Vue 3, methods defined in the <script setup> are not exposed on the component instance, which is why we can't spy on them directly. Instead, we need to focus on the behavior that the click handler triggers. Here's a better way to test this: 1. First, ensure that your component is properly set up with the mocked composable:
import { describe, it, expect, vi } from 'vitest';
import { mountSuspended, mockNuxtImport } from '@nuxt/test-utils/runtime';
import CustomBtn from './CustomBtn.vue';

const myMethodMock = vi.fn();
const useMyComposableMock = vi.fn(() => ({
myMethod: myMethodMock,
}));

mockNuxtImport('useMyComposable', () => useMyComposableMock);
import { describe, it, expect, vi } from 'vitest';
import { mountSuspended, mockNuxtImport } from '@nuxt/test-utils/runtime';
import CustomBtn from './CustomBtn.vue';

const myMethodMock = vi.fn();
const useMyComposableMock = vi.fn(() => ({
myMethod: myMethodMock,
}));

mockNuxtImport('useMyComposable', () => useMyComposableMock);
2. Then, in your test, focus on the behavior of myMethod being called when the button is clicked:
describe('Component CustomBtn', async () => {
it('should call myMethod 4 times when button is clicked 4 times', async () => {
const wrapper = await mountSuspended(CustomBtn);
const button = wrapper.find('button');

await button.trigger('click');
await button.trigger('click');
await button.trigger('click');
await button.trigger('click');

expect(myMethodMock).toHaveBeenCalledTimes(4);
});
});
describe('Component CustomBtn', async () => {
it('should call myMethod 4 times when button is clicked 4 times', async () => {
const wrapper = await mountSuspended(CustomBtn);
const button = wrapper.find('button');

await button.trigger('click');
await button.trigger('click');
await button.trigger('click');
await button.trigger('click');

expect(myMethodMock).toHaveBeenCalledTimes(4);
});
});
This approach tests the actual behavior you're interested in - that clicking the button results in myMethod being called the correct number of times. If you specifically need to test that handleMyBtnClick is being called, you would need to refactor your component to make it testable. One way to do this is by using a methods option instead of defining the function directly in <script setup>:
<script setup lang="ts">
import { defineComponent } from 'vue'

export default defineComponent({
setup() {
const { myMethod } = useMyComposable();
return { myMethod }
},
methods: {
handleMyBtnClick() {
this.myMethod(someParams);
}
}
})
</script>

<template>
<button @click="handleMyBtnClick">Click Here</button>
</template>
<script setup lang="ts">
import { defineComponent } from 'vue'

export default defineComponent({
setup() {
const { myMethod } = useMyComposable();
return { myMethod }
},
methods: {
handleMyBtnClick() {
this.myMethod(someParams);
}
}
})
</script>

<template>
<button @click="handleMyBtnClick">Click Here</button>
</template>
Then you could test it like this:
describe('Component CustomBtn', async () => {
it('should call handleMyBtnClick 4 times', async () => {
const wrapper = await mountSuspended(CustomBtn);
const handleMyBtnClickSpy = vi.spyOn(wrapper.vm, 'handleMyBtnClick');

const button = wrapper.find('button');

await button.trigger('click');
await button.trigger('click');
await button.trigger('click');
await button.trigger('click');

expect(handleMyBtnClickSpy).toHaveBeenCalledTimes(4);
});
});
describe('Component CustomBtn', async () => {
it('should call handleMyBtnClick 4 times', async () => {
const wrapper = await mountSuspended(CustomBtn);
const handleMyBtnClickSpy = vi.spyOn(wrapper.vm, 'handleMyBtnClick');

const button = wrapper.find('button');

await button.trigger('click');
await button.trigger('click');
await button.trigger('click');
await button.trigger('click');

expect(handleMyBtnClickSpy).toHaveBeenCalledTimes(4);
});
});
However, this approach is less idiomatic in Vue 3 and Nuxt 3, where the Composition API with <script setup> is preferred. In most cases, testing the end result (like myMethod being called) is a more robust approach. For more details on testing in Nuxt, you can refer to the Nuxt Testing documentation (https://nuxt.com/docs/getting-started/testing). ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai2mo ago
<@206534948952342529> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Want results from more Discord servers?
Add your server