Jest Vue, test trigger click button, Expected 1, received: 0 - unit-testing

I have a problem with unit test to trigger click. Error: Expected: 1, Received: 0
I'm using Vue, Jest and Vue test utils. I wanna test if the button is triggered
Search.vue
<v-btn id="searchBtn" #click="searchItem"></v-btn>
methods: {
searchItem() {}
...
}
test.spec.js
import Search from '...'
describle(Search, () => {
it('trigger button', () => {
const wrapper = shallowMount(Search)
const clickMethodStub = jest.fn()
wrapper.setMethods({ searchItem: clickMethodStub })
wrapper.find('#searchBtn').trigger('click')
expect(clickMethodStub.mock.calls.length).toBe(1)
})
})
}
Error:
Expected: 1
Received: 0

Because it is vuetify button, you need to use to shallowMount to mount.
import Search from '...'
describle(Search, () => {
it('trigger button', () => {
const wrapper = mount(Search)
const clickMethodStub = jest.fn()
wrapper.setMethods({ searchItem: clickMethodStub })
wrapper.find('#searchBtn').trigger('click')
expect(clickMethodStub.mock.calls.length).toBe(1)
})
})
}

Related

vitest failed to mock quasar

I am having vue3 app with vite and vitest and trying to mock the Quasar useQuasar composable which I am using in my custom Composable like:
// useLoginRequestBuilder.ts
import { makeUserAuthentication } from "#/main/factories"
import { useQuasar } from "quasar"
export function useLoginRequestBuilder() {
const $q = useQuasar()
async function login() {
try {
$q.loading.show()
const auth = makeUserAuthentication()
return await auth.signinRedirect()
} catch (e) {
console.log(e)
$q.loading.hide()
$q.notify({
color: "red-4",
textColor: "white",
icon: "o_warning",
message: "Login Failed!",
})
}
}
return {
login,
}
}
and I am trying to mock quasar in tests like:
// useLoginRequestBuilder.spec.ts
import { useLoginRequestBuilder } from "#/main/builders"
vi.mock("quasar", () => ({ // <--- this is not really mocking quasar
useQuasar: () => ({
loading: {
show: () => true,
hide: () => true,
},
}),
}))
const spyAuth = vi.fn(() => Promise.resolve(true))
vi.mock("#/main/factories", () => ({
makeUserAuthentication: () => ({
signinRedirect: () => spyAuth(),
}),
}))
describe("test useLoginRequestBuilder", () => {
test("should call signinRedirect", async () => {
const { login } = useLoginRequestBuilder()
const sut = await login()
expect(sut).toBe(true)
})
})
vi.mock("quasar"... is failing to mock quasar and I am getting below error. That means, it failed to mock and failed to get the $q.loading.... object.
TypeError: Cannot read properties of undefined (reading 'loading')
I understand that there is a separate testing lib for quasar, here but I think this is not really the case here.
Bordering on a necro-post, but I had a similar issue that the mocking factory wasn't creating the plugins being used in non-Vue components, and had to mock each call individually in the end.
Though I'd add it here for anyone else
vitest.mock("quasar", () => vi.fn()); // this doesn't mock out calls
// use individual mocks as below
import { Loading } from "quasar";
vi.spyOn(Loading, "show").mockImplementation(() => vi.fn());
vi.spyOn(Loading, "hide").mockImplementation(() => vi.fn());

Vitest gives no output

I'm new to testing and im trying to write some unit tests for my Vue app. The problem is that vitest givesno output and I cant figure out what is wrong. Any help would be apriciated.
describe('UserForm', () => {
it('renders component properly', async () => {
const viewId = "123"
render(UserForm, {
props: {
open: true
}
})
const view = await screen.findByText('Kontrahent')
expect(view.id).toBe(viewId)
})
})
I run the test with this command
vitest --environment jsdom
Have you tried to do something like:
import { mount } from "#vue/test-utils";
// in the describe
const wrapper = mount(Login, {
props: {
open: true
},
});
it("mounts the component", () => {
expect(wrapper.html()).toContain("Kontrahent");
});

React & React Native Testing Library wait for async state update caused by useEffect on mount

I can't seem to get this simple test to work in react-testing-library & react-native-testing-library. I've tried various combinations of wrapping the render function in act, or using waitFor and other async utils, but the test never waits for the component to re-render after useEffect causes the async api call to set the new state.
Also worth noting I receive the warning: An update to TestComponent inside a test was not wrapped in act(...).`. I'm aware of this issue but no method that I've seen solved it for me.
import React, { useEffect, useState } from 'react'
import { View, Text } from 'react-native'
import { render, waitFor } from 'test-utils'
import { rest } from 'msw'
import { setupServer } from 'msw/node'
import { useApi } from './index'
const server = setupServer(
rest.get('http://localhost/MOCK_VAR/some-endpoint', (req, res, ctx) => {
return res(ctx.json({ greeting: 'hello there' }))
})
)
beforeAll(() => server.listen())
afterEach(() => server.resetHandlers())
afterAll(() => server.close())
function TestComponent() {
const { apiRequest } = useApi()
const [result, setResult] = useState(null)
useEffect(() => {
makeApiCall()
})
const makeApiCall = async () => {
const apiResult = await apiRequest({ url: '/some-endpoint' })
console.log(apiResult.greeting) // <-- 'hello there'
setResult(apiResult.greeting)
}
return (
<View>
<Text>{result}</Text>
</View>
)
}
describe('Test useApi hook', () => {
test('test post request', async () => {
const { findByText } = render(<TestComponent />)
const greeting = await findByText('hello there')
await waitFor(() => { // <-- never waits
expect(greeting).toBeTruthy()
})
})
})
My issue was awaiting the findBy function. From the docs it says findBy* methods have waitFor already built in. So simply removing the await solved the issue.
What worked for me:
test('test post request', async () => {
const { findByText } = render(<TestComponent />)
const greeting = findByText('hello there')
waitFor(() => expect(greeting).toBeTruthy())
})

Testing that a method is called when component is mounted

I'm trying to test that a method gets called when a component is mounted but it keeps failing with
Expected mock function to have been called one time, but it was called zero times.
Here is the component:
<template>
<b-form-input
class="mr-2 rounded-0"
placeholder="Enter Search term..."
id="input-keyword"
/>
</template>
<script>
export default {
name: 'job-search-test',
methods: {
async searchJobs () {
console.log('Calling Search Jobs from JobsSearchTest')
}
},
mounted () {
this.searchJobs()
}
}
</script>
Here is the test:
import { shallowMount, createLocalVue } from '#vue/test-utils'
import BootstrapVue from 'bootstrap-vue'
import JobSearchTest from '#/components/jobs/JobSearchTest'
const localVue = createLocalVue()
localVue.use(BootstrapVue)
describe('JobsSearchTest.vue', () => {
it('should call searchJobs method when component is mounted', () => {
const methods = {
searchJobs: jest.fn()
}
shallowMount(JobSearchTest, {
mocks: {
methods
},
localVue })
expect(methods.searchJobs).toHaveBeenCalledTimes(1)
})
})
However, the following test passes
import { shallowMount, createLocalVue } from '#vue/test-utils'
import BootstrapVue from 'bootstrap-vue'
import JobSearchTest from '#/components/jobs/JobSearchTest'
const localVue = createLocalVue()
localVue.use(BootstrapVue)
describe('JobsSearchTest.vue', () => {
it('should call searchJobs method when component is mounted', () => {
let searchJobs = jest.fn()
shallowMount(JobSearchTest, {
methods: {
searchJobs
},
localVue })
expect(searchJobs).toHaveBeenCalledTimes(1)
})
})
According to Testing VueJs Applications by Edd Yerburgh one tests a function by stubbing it with a Jest mock the following way
it('should call $bar.start on load', () => {
const $bar = {
start: jest.fn(),
finish: () => {}
}
shallowMount(ItemList, { mocks: $bar })
expect($bar.start).toHaveBeenCalledTimes(1)
})
In my eyes, this is essentially what I am doing in the first test, which fails.
Any help with why this could be happening will be appreciated.
mocks option mocks instance properties. mocks: { methods } assumes that there's methods property in Vue component. Since this.methods.searchJobs() isn't called, the test fails.
It's searchJobs method, the test should be as the working snippet shows:
shallowMount(JobSearchTest, {
methods: {
searchJobs
},
localVue })

How do you test Collection.allow( ) functions that rely on the user ID?

Given the following collection and access control defintion
class TasksCollection extends Mongo.Collection {
insert (task, callback) {
const doc = _.extend({}, task, {
createdOn: new Date(),
owner: this.userId
})
super.insert(doc, callback)
}
}
export const Tasks = new TasksCollection('tasks')
// Simple checks to ensure that the user is logged in before making changes.
Tasks.allow({
insert: (userId, doc) =>=> !!userId,
update: (userId, doc, fields, modifier) => !!userId,
remove: (userId, doc) => !!userId
})
How would you test to ensure that it works using Mocha/Chai/Sinon? This is what I have tried.
import { Meteor } from 'meteor/meteor'
import { resetDatabase } from 'meteor/xolvio:cleaner';
import { assert, expect } from 'chai'
import { Tasks } from '/imports/api/tasks'
import sinon from 'sinon'
describe('collection test', () => {
beforeEach(() => {
resetDatabase()
})
it('can see a collection', () => {
assert(Tasks, 'unable to see sample collection')
})
it('can query an empty collection', () => {
expect(Tasks.find({}).fetch()).to.be.empty
})
it('fails to add to a collection when the user is not logged in', (done) => {
expect(Tasks.find({}).fetch()).to.be.empty
Tasks.insert({
text: 'hello world'
}, (error) => {
console.log('expected', error) // this is also a 404
assert(error)
done()
})
})
describe('logged in', () => {
let sandbox
beforeEach(() => {
sandbox = sinon.sandbox.create()
sandbox.stub(Meteor, 'userId').returns(42)
})
afterEach(() => {
sandbox.restore()
})
it('can add to a collection', (done) => {
expect(Tasks.find({}).fetch()).to.be.empty
Tasks.insert({
text: 'hello world'
}, (error, _id) => {
console.log(error)
assert(!error)
const results = Tasks.find({}).fetch()
expect(results).to.have.lengthOf(1)
expect(results[0].defaultValue).to.equal(42)
expect(results[0]._id).to.equal(_id)
expect(results[0].createdOn).to.not.be.undefined
done()
})
})
})
})
UPDATE: But I get a 404 error when calling the server.
The insecure package is already removed.
UPDATE: I am only testing on the client for now as the authorization can only be done from a client call.