I'm having trouble with unit testing using mocha, chai and enzyme for the following. I can't seem to understand how to unit test methods in components and how to unit test onClick methods will call those methods.
The following is what I am trying to unit test:
<Link to="/create-new-template-results" onClick={this.checkLink}>
<Button
buttonname="Next_button"
variant="primary"
label="Save"
onClickMethod={() => this.submitTemplateCreation()}
disabled={!this.disabledButtonCheck()}
/>
</Link>
.
Header: '',
Cell: value => {
return (
<div>
<img
height={34}
src="https://content.usaa.com/mcontent/static_assets/Media/icon-trash.svg"
onClick={() => this.removeAttribute(value)}
/>
</div>
);
}
.
removeAttribute = value => {
this.props.change('templateAttributeForm', value.original.name, '');
this.props.removeAttributeItem(value.index);
};
submitTemplateCreation() {
let profLvlData = Object.values(this.props.templateAttributeFormData);
let attrData = Object.keys(this.props.templateAttributeFormData);
let attributeProfLvl = attributeProfLvlUtil(attrData, profLvlData);
let templateCreationJSON = templateCreationPOSTFilter(attributeProfLvl, this.props.templateFormData);
this.props.submitTemplateCreation(templateCreationJSON);
}
Chai provides some nice tools for testing things exactly like what you are talking about.
You'll want to render your component somehow in the virtual DOM, either by using enzyme's "shallow" or "mount" functions.
Once you've done that, you can access the component using .find, and "simulate" an event using .simulate like so.
wrapper.find('Button').at(0).simulate('click');
This will find all of the 'Button' components in your wrapper, take the first one, and simulate a click. From there you can use expect() combined with any of the ways Chai provides to examine the state of the component in order to test that your button did what it was supposed to.
Since it seems like you are particularly interesting in the calling of the onClick function itself, I will add that you can specifically check to see if a function is called by doing the following with Chai.
expect(MyComponent.prototype.myOnClickFunction).to.have.property('callCount', 1);
Related
I cant seem to find a way to do a really simple thing like the below:
render() {
return (
<div className="messageDetail">
<div className="messageForm" >
Name: <input id="senderMsgName" value={this.props.nameValue} onChange={this.props.handleNameChange}/>
<br />
Body: <input id="senderMsgBody" value={this.props.bodyValue} onChange={this.props.handleBodyChange}/>
<br />
</div>
</div>
);
}
}
All I want to test is that the onChange function is called. how can I mock this out using sinon (bearing in mind it called on props)? I then will simulate it being called to test it.
I started with this: const handleBodyChangeSpy = sinon.spy();
and will expect this: expect(handleBodyChangeSpy).to.have.not.been.called();
just need some guidance on how to do that
I assume you are using ES6 and class Component extends React.Component. In that case you can create a spy by writing var spy = sinon.spy(Component.prototype, "handleBodyChange"). You can test your assertions on that spy.
More about creating spies here: http://sinonjs.org/releases/v1.17.7/spies/ (check under Creating spies: sinon.spy() Method Signatures).
I am just starting with Jest and Snapshot testing and I was wondering why all examples do "deep rendering" of React components to create snapshots.
Example
const A = () => {
return <div><B /><B /></div>
}
const B = () => {
return <div>This is B</div>
}
// TEST
describe('Test', () => {
it('renders correctly', () => {
const tree = ReactTestRenderer.create(
<A />
).toJSON();
expect(tree).toMatchSnapshot();
});
});
Snapshot:
exports[`Summary DOM rendering renders correctly 1`] = `
<div>
<div>
This is B
</div>
<div>
This is B
</div>
</div>
`;
While this is useful sometimes I think it makes far more sense to have separate tests/snapshots for A and B and to do shallow rendering so if I change B my A snapshots do not need to be updated. So I want my snapshots to look like this:
exports[`Summary DOM rendering renders correctly 1`] = `
<div>
<B />
<B />
</div>
`;
Is there any way to do this? Is this a good idea in the first place? If it is possible why is shallow rendering not the preferred way in the docs?
Update(Jan 3, 2018)
Shallowrender has been moved to react-test-renderer
import ShallowRenderer from 'react-test-renderer/shallow'
it('Matches snapshot', () => {
const renderer = new ShallowRenderer()
const result = renderer.render(<A />)
expect(result).toMatchSnapshot()
})
You can use react-test-utils Shallow Rendering with snapshot testing as well:
import ReactTestUtils from 'react-addons-test-utils';
describe('Test', () => {
it('renders correctly', () => {
const renderer = ReactTestUtils.createRenderer();
expect(renderer.render(<A />)).toMatchSnapshot();
});
});
With that you can create renderer that only renders 1 level deep, that is: it'll only render what's in your component's render() function, and not render child components.
react-test-renderer is a different renderer, it renders your component (and the whole tree) to JSON. Currently it has no option to shallow render, it will work just like in the browser and render everything, but to JSON.
They both are good for testing because they don't require a DOM environment and they have different characteristics. You can choose one that suits better your use case.
You can use enzyme to shallow-render your components.
I can't tell you for sure as to why it's not the preferred method in the docs, but my guess would be that it's because the functionality isn't built into the official react-test-renderer.
Shallow rendering is preferred for unit tests, where only a single component is being tested. In your question, shallow rendering the <A/> component is the correct approach. The it('renders correctly') test should only check that <A/> renders a certain way. That test should not depend on how <B/> renders.
To test more complex behaviors that involve multiple components, mount or render can be used. This allows for testing aspects of <A/> and <B/>.
(I use enzyme for test rendering.)
Is there a better solution to dive into props.text in Enzyme?
Component:
export function TitleText ({ text, info, required }) {
return (
<div className={style.titleText}>
<div className={style.titleText} style={{ margin: 0 }} required={required}>{text}</div>
{info ? <InfoIcon className={style.infoIcon} /> : ''}
</div>
)
}
Test:
it('renders text from its props', () => {
const wrapper = setupTitleText('Test')
expect(wrapper.find(`.${style.titleText}`).node.props.children[0].props.children).toEqual('Test')
})
You can access the props using props(). Should at least work on shallow and mounted components.
wrapper.props().text
However, I would add a data attribute for testing.
Doing so would
let anyone working on your code would know that this element is being tested
let anyone working on your code would know that this element is being tested
prevent multiple elements being returned when you're looking to test something specific
prevent others breaking your tests if they decide to change the class.
How to assert with chai that some div('.MyDive') contains text 'Some text'?
<div class="MyDive">
<div>Some text</div>
</div>
You'll want to pull in jQuery to access elements on the DOM. Once you have that, you can assert against DOM elements using vanilla Chai like so:
expect($('div.MyDive').text()).to.have.string('Some text');
If you want to visually clean up your code a bit, you could also pull in a plugin like chai-jquery and use a custom assertion, such as contain(text):
expect($('div.MyDive')).to.contain('Some text');
If you are using chai with WebdriverIO, you can do something like
expect = require('chai').expect;
client
.element('.MyDive')
.getText()
.then(function (text) {
expect(text).to.equal('Some text');
});
I prefer to use chai-dom for this:
import chai, { expect } from "chai";
import chaiDom from "chai-dom";
chai.use(chaiDom);
expect(document.querySelector(".MyDive")).to.have.text("Some text");
Im just starting on polymer. Im trying to unit test a custom element that has dependencies and I would like to fake/mock these out.
I've found Scott Miles recommendation on how to mock the core-ajax implementation. I thought I could follow that pattern easily but this only works as long as my element does not import the about to be mocked (core-ajax in this case) element.
If it does import it, then when the test tries to run I get
'Uncaught NotSupportedError: Failed to execute 'registerElement' on 'Document': Registration failed for type 'core-ajax'. A type with that name is already registered.'
If I could do something like document.unregister the core-ajax element and import it again in my test, Id be a much happier dev!!!
Polymer is awesome but if I can not unit test it, then it presents major risks (at least when building an app that will need to be maintained/changed)
How are you guys working around this? I've been digging into Polymer and PolymerLab elements repo and most of them lack tests. So far I;ve not found much reference on how to do it.
Thanks for the help!
Santiago
Scotts' recommendation was:
Instead of importing core-ajax/core-ajax.html, create your own core-ajax element.
<polymer-element name="core-ajax" attributes="response">
<script>
Polymer('core-ajax', {
attached: function() {
this.response = ['a', 'b', 'c'];
}
});
</script>
</polymer-element>
Obviously, this is just an example, the actual implementation depends on the desired mocking behavior.
This is just one way to solve it, there are many others. I'm interested to hear what you find (in)convenient.
This question is a little old. Figured I'd provide an update since this is a pretty common situation.
Polymer CLI is the recommended approach for unit testing Polymer elements. The underlying library that it uses for testing is called web-component-tester (WCT). WCT has support for stub elements. Basically, if one of your tests relies on another element to return data, you can create a stub of that element that always returns consistent data.
JS in the unit test code for specifying the stub element:
setup(function() {
replace('paper-button').with('fake-paper-button');
});
Element to be tested:
<dom-module id='x-el'>
<template>
<paper-button id="pb">button</paper-button>
</template>
</dom-module>
At test runtime, the content template would be stamped out as:
<dom-module id='x-el'>
<template>
<fake-paper-button id="pb">button</fake-paper-button>
</template>
</dom-module>
https://www.polymer-project.org/1.0/docs/tools/tests#create-stub-elements
You can try registering it imperatively with js or extend every single element you are testing and override its properties or methods you want to mock.
i think that is just about it. It's like my google-map custom element, i import the google-map and change stuff around like so:
<polymer-element name="core-gmaps" attributes="lat long mapzoom markerlat markerlong markertitle" extends="google-map">
<template>
<style>
:host{
width: 100%;
}
#vivaMap {
display: block;
height: 100%;
width: 100%;
}
</style>
<google-map id="vivaMap" latitude="0" longitude="0" zoom="18">
<google-map-marker id="vivaMarker" title="" latitude="0" longitude=""></google-map-marker>
</google-map>
</template>
<script>
Polymer("core-gmaps",{
ready: function(){
var map = this.$.vivaMap;
map.latitude = Number(this.getAttribute('lat'));
map.longitude = Number(this.getAttribute('long'));
map.zoom = Number(this.getAttribute('mapzoom'));
var mapMarker = this.$.vivaMarker;
mapMarker.latitude = Number(this.getAttribute('markerlat'));
mapMarker.longitude = Number(this.getAttribute('markerlong'));
mapMarker.title = this.getAttribute('markertitle');
/*map.addEventListener('google-map-ready', function(e) {
console.log('Map loaded!');
});*/
}
});
</script>
</polymer-element>
I am still not sure if it was worth it professionally (i may end up not using it), but was totally worth it intellectually. learned some nice stuff. since i'm extending google-map it gets registered once and only once.
EDIT:
in my case i used the ready event because i couldn't manipulate the map per se without it being at least ready. but you can choose the event callback from the lifecycle methods. The list is here.
PS.:Yes, i didn't use data binding because i couldn't. The google map api was complaining about it being NaN so i had to cast it.