React: Enzyme shallow: "Expected: 1; Received: undefined - enzyme

I am using React-typescript for my app. I am really new in testing world. I have created two components. Then I am imported the components to the App component. I am using Enzyme's shallow for testing the component. I am watching one tutorial from udemy. I followed the test code exactly as it is in video. But my test failed.
This is my app component
import React from 'react';
import CommentBox from './components/commentbox';
import CommentList from './components/commentlist'
function App() {
return (
<div className="App">
<CommentBox />
<CommentList />
</div>
);
}
export default App;
This is my test
import { cleanup } from '#testing-library/react';
import App from '../App';
import CommentBox from '../components/commentbox';
describe('whole app component', () => {
afterEach(cleanup)
it('renders Comment Box component', () => {
const wrapped = shallow(<App />);
expect(wrapped.find(CommentBox).lenght).toEqual(1) //I Received Undefined
});
});

Related

Mocha Chai vue testing a vue component : this.$notify is not a function

I'm using this component : https://github.com/euvl/vue-notification
Since then, all of my Mocha chai test units are failing .
this.$notify is not a function
This is my login spec :
// Importing The testing library
import { expect } from "chai";
import { mount } from '#vue/test-utils'
// Importing The component I need to test
import Login from "#/components/Login.vue";
// Mounting the component as in real life
const wrapper = mount(Login);
describe("Login test", () => {
it("getAuth() to be a function", () => {
expect(wrapper.vm.getAuth).to.be.a("function");
});
});
I've tried out mount, shallowMount, render with no luck .
Any workaround ?
I'm calling vue-notification in main.js like this :
import Notifications from "vue-notification";
Vue.use(Notifications);
Thank you !
EDIT :
Ive tried to add
const $notify = require('vue-notification')
To my Login.vue component with no luck
EDIT 2 : Tried to call the function like this with no luck :
this.$root.$notify({
group: 'foo',
title: 'Hello ',
text: 'Cool'
});
[Vue warn]: Error in mounted hook: "TypeError: this.$root.$notify is not a function"
*EDIT : ***** Resolved by me ****** *
I was badly importing vue . Please see my working login.spec.js testing file there :
// THE ASSERTION LIBRARY
import { expect } from "chai";
// THE TESTING LIBRARY
import { mount } from "#vue/test-utils";
// THE COMPONENT THAT I WANT TO TEST
import Login from "#/components/Login.vue";
// THE EXTERNAL COMPONENTS LINKED TO MY LOGIN COMPONENT THAT I NEED TO JOIN
import Vue from 'vue';
import Vuelidate from 'vuelidate'
Vue.use(Vuelidate)
import {
required,
minLength,
between
} from "vuelidate/lib/validators";
import Notifications from "vue-notification";
import velocity from 'velocity-animate'
Vue.use(Notifications, { velocity });
// THE WRAPPER CONTAIN MY LOGIN MOUNTED COMPONENT, JUST LIKE IN THE REAL LIFE
const wrapper = mount(Login)
describe("Login test", () => {
it("getAuth() to be a function", () => {
expect(wrapper.vm.getAuth).to.be.a("function");
});
});

Mock this.$parent.$on with jest

We are using vuejs, typescript, vuex and jest. We are currently using test-utils to mock the store.
But I cannot find out how to mock a call to this.$parent.$on
Here is one of our components (very simplified):
AnalysisList.ts:
import Component from 'vue-class-component'
import {Getter} from 'vuex-class'
import {UserVO} from '#/valueObjects/UserVO'
import {Vue} from 'vue-property-decorator'
#Component
export default class AnalysisList extends Vue {
#Getter('getCurrentUser') private currentUser: UserVO
private searchString = ''
public mounted() {
this.$parent.$on('resetAnalyses', this.reset)
}
public reset() {
this.searchString = ''
}
}
AnalysisList.vue:
<template lang="pug">
text test
</template>
<script lang="ts" src="./AnalysisList.ts">
</script>
AnalysisList.spec.ts:
import {shallowMount} from '#vue/test-utils'
import AnalysisList from '#/components/analysis/AnalysisList'
import Vuex from 'vuex'
import {Vue} from 'vue-property-decorator'
import VueRouter from 'vue-router'
Vue.use(Vuex)
Vue.use(VueRouter)
describe('AnalysisList.vue', () => {
const store = new Vuex.Store( {
modules: {
user: {
state: {currentUser: 'test'},
getters: {
getCurrentUser: (state: any) => state.currentUser,
},
},
},
})
it('minimum test', (done) => {
const wrapper = shallowMount(AnalysisList, {store})
done()
})
})
When I run the test, I have the following error message, because $parent is not mocked:
TypeError: Cannot read property '$on' of undefined
at VueComponent.mounted (src/components/analysis/AnalysisList/AnalysisList.vue:73:20)
at callHook (node_modules/vue/dist/vue.runtime.common.js:2919:21)
at mountComponent (node_modules/vue/dist/vue.runtime.common.js:2800:5)
at VueComponent.Object.<anonymous>.Vue.$mount (node_modules/vue/dist/vue.runtime.common.js:7997:10)
at mount (node_modules/#vue/test-utils/dist/vue-test-utils.js:5381:8)
at shallowMount (node_modules/#vue/test-utils/dist/vue-test-utils.js:5414:10)
at Object.done (tests/unit/AnalysisList.spec.ts:20:53)
If I try to add a new property to shallowMount parameter:
const wrapper = shallowMount(AnalysisList, {store, parent: {$on: ()=>{}}})
I obtain a type error:
TS2345: Argument of type 'VueConstructor<Vue>' is not assignable to parameter of type 'FunctionalComponentOptions<Record<string, any>, PropsDefinition<Record<string, any>>>'.   Property 'functional' is missing in type 'VueConstructor<Vue>'.
Do you have any clue to help me mock this.$parent.$on ? Thanks.
I got the same issue with vue-test-utils and Jest (under the Vue, Vuex and Typescript environment)
For me, createLocalVue() of vue-test-utils library fixed the issue. This function creates a local copy of Vue to use when mounting the component. Installing plugins on this copy of Vue prevents polluting the original Vue copy. (https://vue-test-utils.vuejs.org/api/options.html#localvue)
Adding this to my test file fixed the issue:
const EventBus = new Vue();
const GlobalPlugins = {
install(v) {
// Event bus
v.prototype.$bus = EventBus;
},
};
// create a local instance of the global bus
const localVue = createLocalVue();
localVue.use(GlobalPlugins);
Hope this helps others, thanks :)

Testing Angular 2 service with mocha

I am trying to implement unit tests for an Angular 2 app. But I can't get it it to work.
As test runner mocha is used and executed like this:
mocha -r ts-node/register -t 10000 ./**/*.unit.ts
Consider the following test file where I define two test cases which basically should do the same thing, but neither one is working.
shared.service.unit.ts
import { TestBed, async, inject } from '#angular/core/testing';
import { SharedService } from './shared.service';
import * as Chai from 'chai';
import 'mocha';
const expect = Chai.expect;
describe('SharedService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [SharedService],
providers: [SharedService]
});
});
it('should be an object',
inject([SharedService], (service: SharedService) => {
expect(service).to.be.an('object');
})
);
});
describe('SharedService without the TestBed', () => {
let service: SharedService;
beforeEach(() => {
service = new SharedService();
});
it('should be an object', () => {
expect(service).to.be.an('object');
});
});
The first one 'SharedService' uses the Angular Testing Utility. Running it gives:
ReferenceError: Zone is not defined
The second one 'SharedService without TestBed'does not use any Angular code (similar to this example from Angular 2 Testing guide). Running it gives:
TypeError: Reflect.getMetadata is not a function
After adding these lines to the test file:
import 'core-js/es6';
import 'core-js/es7/reflect';
import 'zone.js/dist/zone';
Both test cases give the same error (from zone.js\dist\zone.js):
TypeError: Cannot read property 'prototype' of undefined
What am I doing wrong?
Got it, just needed to import 'core-js/es7/reflect':
import 'core-js/es7/reflect';
import 'mocha';
import * as Chai from 'chai';
let expect = Chai.expect;
import { SharedService } from './shared.service';
describe('SharedService', () => {
let service: SharedService;
beforeEach(() => {
service = new SharedService();
})
it('should be an object', () => {
expect(service).to.be.an('object');
})
});
You need to load all that stuff - angular, ngzone, metadata, es shims, etc. - statically in the mocha's - or systemjs or whatever you use for setting this stuff up - configuration.

Jest with React - How do you render an entire component and test it?

Let's say I have a simple App component and I am running a test for it to see if it simply returns a div that prints Hello World to the screen. What is the function helper in order to render App inside my testing file? Furthermore, what is the function to call in the expect call in order to test the HTML being rendered?
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
describe("App", () => {
it('prints "HELLO WORLD" to the screen', () => {
expect(**App??**).**toRENDER??**("HELLO WORLD")
}
}
Thanks
It's a good practice to use enzyme library from airbnb.
There is an example of using both together
Your code can looks like the next:
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
import {shallow} from 'enzyme'
describe("App", () => {
it('prints "HELLO WORLD" to the screen', () => {
const wrapper = shallow(<App />)
expect(wrapper.text()).toBe("HELLO WORLD")
}
}
You would want to look at Jest's snapshot testing for this. This is as simple as calling:
import renderer from 'react-test-renderer';
describe('snapshot testing', () => {
it('should render App', () => {
const component = renderer.create(<App />);
const tree = component.toJSON();
expect(component).toMatchSnapshot();
});
});
A snapshot file will be stored in a __tests__/__snapshots__ folder. Make sure you commit these snapshot files into your Git repository so other contributors can have a snapshot to their components against.
For more information on how to setup Jest snapshot testing with React, refer to this docs here as you will need to install some npm dependencies.

TypeError: Cannot read property 'contextTypes' of undefined

I'm trying to test a React-app with Jest. I use Enzyme's shallow to render my App.js component in App-test-js but I'm getting this error: TypeError: Cannot read property 'contextTypes' of undefined
This is my App.js:
/* global google */
import React, { Component } from 'react';
import Geosuggest from 'react-geosuggest';
import { getAirQuality } from './Client'
import DataTable from './DataTable'
import Errors from 'react-errors'
class App extends Component {
.
.
.
render() {
return (
<div className="App">
<form onSubmit={this.searchAirQuality.bind(this)}>
<Geosuggest
placeholder="Type a location and press SEARCH button!"
onSuggestSelect={this.onSuggestSelect.bind(this)}
initialValue={this.state.place}
location={new google.maps.LatLng(53.558572, 9.9278215)}
radius="20"/>
<button className="my-button" type="submit" disabled={!this.state.place}>Button</button>
</form>
<DataTable items={this.state.items} />
<Errors
errors={this.state.errors}
onErrorClose={this.handleErrorClose}
/>
</div>
)
}
}
export default App;
and this is my App-test.js:
import React from 'react'
import { shallow } from 'enzyme'
import App from '../components/App.js'
describe( '<App />', () => {
it('Button disable when input is empty', () => {
const App = shallow(<App />);
expect(App.find('.my-button').hasClass('disabled')).to.equal(true);
});
});
And this the error when I run npm test:
Terminal screenshot
This is my first time with testing in jest, please could someone help me with any idea about this error?
This would be the same error TypeError: Cannot read property 'contextTypes' of undefined when you are importing something that does not exist.
Here is an example:
AccountFormComponent.jsx (incorrect class name):
export class FoeFormComponent extends React.Component { .... }
AccountFormComponent.test.jsx:
import { shallow } from 'enzyme'
import { expect, assert } from 'chai'
import { AccountFormComponent } from '../../src/components/AccountFormComponent';
describe('', function () {
it('', function () {
const enzymeWrapper = shallow(<AccountFormComponent {...props} />);
});
});
Just add the following to your test file to be sure the component exists:
it('should exists', function () {
assert.isDefined(AccountFormComponent);
});
which prints AssertionError: expected undefined to not equal undefined instead
The problem here is that you are redefining the the app component with the result of the shallow call
// Redefining
// ↓
const App = shallow(<App />);
The solution would be to use a different name:
// Use a different name
// ↓
const app = shallow(<App />);
In my case the error occurred when imported a module that has only one default export, but I was using single import.
So instead of:
import { Foo } from './Foo'
use:
import Foo from './Foo'
where Foo has default export:
class Foo extends Component {
render() {
return (<div>foo</div>)
}
}
export default Foo;
As #Ser mentioned could be a import issue.
If you are using eslint rules this could give you a hint if any of the imports might fail
"import/no-unresolved": 1,
I got that error on trying to import a component from a jsx file
import {Header} from './Header';
this fixed it
import {Header} from './Header.jsx';
Also because I used webpack I realised that I should have added '.jsx' to resolve.extensions option. This way I can ignore the extensions when importing.
In my case I was importing a default component with named component syntax.
For example, something like:
import {TestComponent} from "../../components/TestComponent";
instead of
import TestComponent from "../../components/TestComponent";
Updating the import to use the right syntax fixed the issue. Silly one though.