Undefined is not a constructor Jasmine Enzyme Karma - javascript

Hey I have been working in the configuration of karma + jasmine + enzyme to start working in the unit tests of my project, then at exec my first test I got this error
TypeError: undefined is not a constructor (evaluating '(0, _jasmine.expect)(addLoan.length)') in src/app/modules/Login/LoginComponent.spec.js (line 80581)
src/app/modules/Login/LoginComponent.spec.js:80581:29
loaded#http://localhost:9876/context.js:151:17
then here is my test code:
import React from 'react';
import { expect } from 'jasmine';
import { shallow } from 'enzyme';
import ServicerComponent from './LoginComponent';
function setup() {
const props = {
error: {},
onClick: () => {},
emailOnChange: () => {},
passwordOnChange: () => {},
};
return shallow(<ServicerComponent{...props} />);
}
describe('<ServicerComponent />', () => {
const displayNames = {
login: 'login',
};
let wrapper;
beforeEach(() => {
wrapper = setup();
});
it('should have a Login button', () => {
const addLoan = wrapper.find({ name: displayNames.login });
expect(addLoan.length).toBe(1);
});
});
also I am using :
jasmine: 2.5.3
enzyme: 2.7.1

You need to create setup instance of the class
beforeEach(() => {
wrapper = new setup();
});

I already found the answer of the question, I just remove the jasmine importer and add a global variable in the .eslintrc.json named expect equal true

Related

TS/Vue 3: Can't access mocked global property in component

I am using the v3-tour plugin for a Vue 3 frontend, and I access the global $tours property injected by the plugin in my component like so
<script setup lang="ts">
import { ComponentPublicInstance, computed, getCurrentInstance, onMounted } from 'vue';
import { useI18n } from 'vue-i18n';
const app = getCurrentInstance();
const proxy = app?.appContext.config.globalProperties;
...
const startTour = () => {
proxy?.$tours['homeTour'].start();
};
...
This works but a problem occurs in my unit tests when I try to mock $tours like so:
const wrapper = shallowMount(Tour, {
global: {
stubs: ['v-tour', 'v-step'],
mocks: {
$tours: {
homeTour: {
start: jest.fn(),
currentStep: 0,
nextStep: jest.fn(),
},
},
},
plugins: [i18n],
},
});
When I try to test the help tour
it('startTour should start tour', () => {
wrapper.find("#start-tour").trigger("click");
expect(wrapper.vm.$tours['homeTour'].start).toHaveBeenCalled();
});
it fails because $tours in undefined in my component:
Cannot read properties of undefined (reading 'homeTour')
How can should I mount or access $tours so that I can access it in my unit tests ?

Unable to mock react hooks with jest

I'm using Jest to test a file written in react, I'm trying to mock the hooks but for some reason I still fail. I've tried to follow several suggestions (included stackoverflow answers) but nothing is working. I've tried to simplify the code to find my mistake but it still failing.
// myFileToTest.js
import { useContext, useState } from 'react';
export const returnsUseContext = () => {
return useContext;
};
export const returnsUseState = () => {
return useState;
};
// myFileToTest.test.js
import React from 'react';
import { returnsUseContext, returnsUseState } from './myFileToTest';
describe('test 1', () => {
let realUseContext;
let useContextMock;
beforeEach(() => {
realUseContext = React.useContext;
useContextMock = React.useContext = jest.fn();
});
// Cleanup mock
afterEach(() => {
React.useContext = realUseContext;
});
it('first try', () => {
expect(returnsUseContext()).toBe(useContextMock);
});
});
describe('test 2', () => {
beforeEach(() => {
jest.spyOn(React, 'useState').mockReturnValue({
name: 'hello'
});
});
it('second try', () => {
const useStateMock = jest.spyOn(React, 'useState');
expect(returnsUseState()).toBe(useStateMock);
});
});
and are both failing. Am I making any silly mistakes?

Jest throws error about missing global function (vue.prototype)

I'm trying to set up unit testing for my Vue application.
I'm using Jest. I have mounted a component and I want to run tests on it. This component uses a global function (Vue.prototype), called aao, which fails to run in my tests.
Error message:
console.error node_modules/vue/dist/vue.runtime.common.dev.js:621
[Vue warn]: Error in beforeMount hook: "TypeError: this.$aao is not a function"
found in
---> <MyProfile>
<Root>
example.spec.ts:
import editUser from '#/components/forms/editUser.vue';
import TestComponent from '#/pages/user/UserMyProfile.vue';
import { shallowMount } from '#vue/test-utils';
import { expect } from 'chai';
import 'jest';
describe('AppLoadingScreen', () => {
let component;
beforeEach(() => {
component = shallowMount(TestComponent);
});
it('should render Spinner on mount', () => {
expect(component.find(editUser).exists()).to.be.true;
});
});
AAO function:
export function dbRequest(
method: 'get' | 'put' | 'post' | 'delete',
endpoint: string,
data: any,
headers?: any,
responseType?: 'blob' | 'json'
) {
return new Promise<any>((resolve, reject) => {
...
});
}
Vue.prototype.$aao = dbRequest;
How can I make sure that the test utils knows about this.$aao?
SOLVED!
Changed my .spec.ts file to .spec.js, and changed the content to something like this:
import { mount, createLocalVue, shallowMount } from '#vue/test-utils';
import * as All from 'quasar';
import dbRequest from 'src/boot/aao';
const { Quasar, date } = All;
const components = Object.keys(All).reduce((object, key) => {
const val = All[key];
if (val && val.component && val.component.name != null) {
object[key] = val;
}
return object;
}, {});
describe('Mount Quasar', () => {
const localVue = createLocalVue();
localVue.use(Quasar, { components });
// Here's the solution, the global functions need to be used by the local vue component
localVue.use(dbRequest);
const wrapper = mount(UserMyProfile, {
localVue,
});
const vm = wrapper.vm;
// Tests here
}
Read more here:
https://vue-test-utils.vuejs.org/guides/common-tips.html#applying-global-plugins-and-mixins

running mount() in react native Not Possible?

This post follows up with my previous question:
previous question
I have come across a test which requires me to run mount in react native. I have gone through the documentation in jest and have found that before running the test suite you specifically need to setup a test environment capable of running jsdom for mount to work:
The link to docs is:
testEnvironment
Because of it's horrible documentation. I can't figure out how to create the customEnvironment class and what after that? what do I do with the global object? How to use it in my test file which currently looks like:
describe('Estimate', () => {
test('Estimate component Exists', () => {
const onPressFunction = jest.fn()
const obj = shallow(
<Estimate onPress={onPressFunction} />
)
expect(obj.find('TextInput').exists()).toBe(true)
})
test('Estimate returns value on button press', () => {
const onPressFunction = jest.fn()
const obj = shallow(
<Estimate onPress={onPressFunction} />
)
obj.find('TextInput').first().simulate('keypress', { key: '1' })
obj.find('Button').first().props().onPress()
expect(onPressFunction.toHaveBeenCalledWith('1'))
})
})
I just made it work had to import three packages from npm:
jsdom
react-native-mock-renderer
jest-environment-jsdom
Also my setup.mjs file looks like:
// #note can't import shallow or ShallowWrapper specifically
import Enzyme from 'enzyme'
import Adapter from 'enzyme-adapter-react-16'
// eslint-disable-next-line
import { format } from 'prettier'
Enzyme.configure({ adapter: new Adapter() })
// Make Enzyme functions available in all test files without importing
global.shallow = Enzyme.shallow
Enzyme.ShallowWrapper.prototype.jsx = function jsx () {
const placeholder = '{ something: null }'
const obj = this.debug({ ignoreProps: false, verbose: true }).replace(/{\.\.\.}/g, placeholder)
return format(obj, {
parser: 'babylon',
filepath: 'test/setup.mjs',
trailingComma: 'all',
semi: false,
arrowParens: 'always',
})
.replace(new RegExp(placeholder, 'g'), '{...}')
.replace(';<', '<')
}
// the html function just throws errors so it's just reset to be the jsx function
Enzyme.ShallowWrapper.prototype.html = Enzyme.ShallowWrapper.prototype.jsx
jest.mock('react-native-device-info', () => {
return {
getDeviceLocale: () => 'en',
getDeviceCountry: () => 'US',
}
})
jest.mock('react-native-custom-tabs', () => ({
CustomTabs: {
openURL: jest.fn(),
},
}))
jest.mock('react-native-safari-view', () => ({
isAvailable: jest.fn(),
show: jest.fn(),
}))
const { JSDOM } = require('jsdom')
const jsdom = new JSDOM()
const { window } = jsdom
function copyProps (src, target) {
const props = Object.getOwnPropertyNames(src)
.filter((prop) => typeof target[prop] === 'undefined')
.map((prop) => Object.getOwnPropertyDescriptor(src, prop))
Object.defineProperties(target, props)
}
global.window = window
global.document = window.document
global.navigator = {
userAgent: 'node.js',
}
copyProps(window, global)
Enzyme.configure({ adapter: new Adapter() })
// Ignore React Web errors when using React Native
// allow other errors to propagate if they're relevant
const suppressedErrors = /(React does not recognize the.*prop on a DOM element|Unknown event handler property|is using uppercase HTML|Received `true` for a non-boolean attribute `accessible`|The tag.*is unrecognized in this browser)/
const realConsoleError = console.error
console.error = (message) => {
if (message.match(suppressedErrors)) {
return
}
realConsoleError(message)
}
require('react-native-mock-render/mock')
Test looks like:
test('Estimate returns value on button press', () => {
const onPressFunction = jest.fn()
const tree = mount(
<Estimate onPress={onPressFunction} />
)
console.log(tree.children().first().html())
})
Works like a charm!

how to mock module when using jest

I'm using Jest for unit test in a vuejs2 project but got stuck in mocking howler.js, a library imported in my component.
Suppose I have a component named Player.vue
<template>
<div class="player">
<button class="player-button" #click="play">Player</button>
</div>
</template>
<script>
import { Howl } from 'howler';
export default {
name: 'audioplayer',
methods: {
play() {
console.log('player button clicked');
new Howl({
src: [ 'whatever.wav' ],
}).play();
}
}
}
</script>
then I have its test file named Player.spec.js. Test code was written based on the answer here, but the test failed since called wasn't set as true. It seems that mocked constructor won't be called when running this test.
import Player from './Player';
import Vue from 'vue';
describe('Player', () => {
let called = false;
jest.mock('howler', () => ({
Howl({ src }) {
this.play = () => {
called = true;
console.log(`playing ${src[0]} now`);
};
},
}));
test('should work', () => {
const Constructor = Vue.extend(Player);
const vm = new Constructor().$mount();
vm.$el.querySelector('.player-button').click();
expect(called).toBeTruthy(); // => will fail
})
})
Though I'm using Vuejs here, I considered it as a more general question related to the usage of Jest's mock API, but I'm not able to get further.
The SO you linked to only works for react components. Here is a way to mock the module with a spy on the play function that can be tested with toBeHaveCalled
//import the mocked module
import { Howl } from 'howler';
// mock the module so it returns an object with the spy
jest.mock('howler', () => ({Howl: jest.fn()}));
const HowlMock ={play: jest.fn()}
// set the actual implementation of the spy so it returns the object with the play function
Howl.mockImplementation(()=> HowlMock)
describe('Player', () => {
test('should work', () => {
const Constructor = Vue.extend(Player);
const vm = new Constructor().$mount();
vm.$el.querySelector('.player-button').click();
expect(Howl).toBeHaveCalledWith({src:[ 'whatever.wav' ]})
expect(HowlMock.play).toBeHaveCalled()
})
})

Categories