How do I test Vue method? - unit-testing

I am using Vue-js-modal.
On my template I have this:
<modal name="hello-world">
hello, world!
</modal>
On my Vue, I have a method like this:
showModal() {
this.$modal.show('hello-world');
}
How can I test this method (showModal)?

In general in Vue you would use refs to access the DOM like so:
<modal ref="$myModal" name="hello-world">
hello, world!
</modal>
...
methods: {
testModal(){
this.$refs.$myModal.show()
}
}
Then if your modal pops up it works!

Related

Nativescript vue remove zoom button on WebView

I'm new in NativeScript.
I can't remove the zoom button from webView. Usually, I didn't find any way of resolving this problem.
<Page id="webViewID" class="page" #loaded="onWebViewLoaded($event)">
export default {
methods: {
onWebViewLoaded(event) {
console.log("Hi can I hendle to event for remove zoom");
}
}
}
You can not do it on as in your case. You need to have #loadFinished on webview
<WebView src="url"
#loadFinished="finished"
/>
and in your methods
methods: {
finished(args) {
args.object.android.getSettings().setBuiltInZoomControls(false);
}
}

Why do I get method is not a function in my jesttest?

My jest unittest looks like this:
import React from 'react';
import renderer from 'react-test-renderer';
import ReactTestUtils from 'react-dom/test-utils'
import Calculator from "./calculator";
test('test that calculator', () => {
const component = renderer.create(
<Calculator></Calculator>
);
let tree = component.toJSON();
expect(tree).toMatchSnapshot();
console.log('component=',component.refs);
// Simulate click on button -> trigger sumCalc()
ReactTestUtils.Simulate.click(component.refs.button);
});
When I run the test I get:
TypeError: Cannot read property 'button' of undefined
My react component looks like this:
import React, {Component} from 'react';
export default class Calculator extends Component {
constructor(props) {
super(props);
this.calcSum = this.calcSum.bind(this);
this.state = {sum: 0};
}
calcSum() {
console.log('this.refs.one=', this.refs.one);
let s = Number(this.refs.one.value) + Number(this.refs.two.value);
this.setState({sum: s});
}
render() {
return (<div>
<input type="text" placeholder="number 1" ref="one"/>
<input type="text" placeholder="number 2" ref="two"/>
<button ref="button" onClick={this.calcSum}>sum</button>
sum: {this.state.sum}
</div>
);
}
}
How can I avoid this error? what am I missing?
The component works when rendered into the DOM but the unit test has issues.
component.toJSON() returns a JSON not a JavaScript object. Moreover calcSum is not a prop, instead it is a method defined on your component class.
Hence you could use getInstance() method to manually invoke calcSum.
Try this:
const component = renderer.create(<Calculator />);
component.getInstance().calcSum();
Now you can see that console.log output from calcSum.

How to unit test a Redux action in a component inside a connected Redux component with Jest

I'm using jest and enzyme to unit test my React application and I'm struggling with testing connected components.
I do have a simple component which the following logic:
class LoginPage extends React.Component {
componentDidMount() {
if (!this.props.reduxReducer.appBootstrapped) {
this.props.dispatch(ReduxActions.fadeOutAndRemoveSplashScreen(500));
}
}
render() {
return (
<div data-page="login-page" >
<div>This is the login page.</div>
</div>
);
}
}
const mapStateToProps = (state) => {
return {
reduxReducer: state.reduxReducer
}
};
export default connect(mapStateToProps, null)(LoginPage);
So, this is a component which displays a <div /> element containing some text, but the important part that I want to test is that when the component is mounted, an action is dispatched to hide the splash screen.
I want this only to happen when the application is not bootstrapped.
I do have a simple unit test to test that the component is rendered:
describe("[LoginPage Component]", () => {
it("Renders without a problem.", () => {
// Act.
const wrapper = mount(
<LoginPage store={ reduxStore } />
);
// Assert.
expect(wrapper.find("div[data-page=\"login-page\"]").length).toBe(1);
});
});
The reduxStore property is my actual redux store, created with the following code:
const reduxStore = createStore(
combineReducers(
{
reduxReducer
}
)
);
Now, how can I test the componentDidMount() method, and more in special, test that the redux action fadeOutAndRemoveSplashScreen() is only called when the application is not bootstrapped yet.
I do think that I need to mock my redux store, however, I'm a newbie on this and don't now how to get started, so an example will be highly appreciated.
If any other thoughts on my implementation, feel free to provide some advice.
Kind regards
I wouldn't use the raw dispatch method to send off an action. I would use mapDispatchToProps. This makes your action directly available in your component props - here we use ES6 destructing as a short hand in the connect method.
Then instead of mocking the redux store I would just test your component without it. Try adding an export to your class (first line). For example:
export class LoginPage extends React.Component {
componentDidMount() {
if (!this.props.reduxReducer.appBootstrapped) {
// make sure that you are using this.props.action() not
// just the action(), which is not connected to redux
this.props.fadeOutAndRemoveSplashScreen(500);
}
}
render() {
return (
<div data-page="login-page" >
<div>This is the login page.</div>
</div>
);
}
}
const mapStateToProps = (state) => {
return {
reduxReducer: state.reduxReducer
}
};
export default connect(mapStateToProps, {
fadeOutAndRemoveSplashScreen: ReduxActions.fadeOutAndRemoveSplashScreen
})(LoginPage);
Then in your test instead of importing the connected component, import the class:
import ConnectedLoginPage, { LoginPage } from '/path/to/component';
Then simply pass the LoginPage whatever props you want to test with. So we will set your appBooststrapped to false, and then pass the action as a sinon spy:
const spy = sinon.spy();
const reduxReducer = {
appBootstrapped: false, // or true
}
const wrapper = mount(
<LoginPage reduxReducer={reduxReducer} fadeOutAndRemoveSplashScreen={spy} />
);
// test that the spy was called
expect(spy.callCount).to.equal(1);
This makes the test much simpler, and more importantly you are testing the component behavior - not Redux.

React.js and Jasmine Spies

Using basic test-utils and jasmine for unit testing.
How do you spy on a function inside a react component?
test.js:
class Test extends React.Component {
handleClick() {
// Do something
}
render() {
return (
<div className="test-class" onClick={this.handleClick}>Test</div>
);
}
}
const React = require('react-with-addons');
const RequireJsTest = require('requirejs-test');
const Utils = React.addons.TestUtils;
const Test = require('./test');
describe('test', () => {
it('should test', function() {
const test = Utils.renderIntoDocument(<Test/>);
const el = Utils.findRenderedDOMComponentWithClass(test, 'test-class');
spyOn(test, 'handleClick');
Utils.Simulate.click(el);
expect(test.handleClick).toHaveBeenCalled();
});
});
I'm getting the following error:
Expected spy handleClick to have been called. (1)
Any ideas? Thanks!
To be honest, I haven't tested react apps yet, but try the method (the last test in describe block), which I've just found in enzyme readme doc.
I think you should spy on component class prototype method before rendering component:
spyOn(Test.prototype, 'handleClick');
// and then
expect(Test.prototype.handleClick).toHaveBeenCalled();

How to mock e.preventDefault in react component's child

Hy, I don't know how to mock an inline function in React component's child
My stack: sinon, chai, enzyme;
Component usage:
<ListItem onClick={() => someFn()} />
Component's render:
render() {
return (
<li>
<a href="#" onClick={e => {
e.preventDefault();
this.props.onClick();
}}
> whatever </a>
</li>
);
}
Here we have onClick function that calls e.preventDefault(). How to tell to <a href>(link) to not to call e.preventDefault()? How can I mock an onClick?
Below is what I have tried in tests:
Shallow copy setup
function setup() {
const someFn = sinon.stub();
const component = shallow(
<ListItem
onClick={() => {
someFn();
}}
/>
);
return {
component: component,
actions: someFn,
link: component.find('a'),
listItem: component.find('li'),
}
}
And the test
it('simulates click events', () => {
const { link, actions } = setup();
link.simulate('click'); //Click on <a href>
expect(actions).to.have.property('callCount', 1); //will be fine if we remove e.preventDefault()
});
Test's output error:
TypeError: Cannot read property 'preventDefault' of undefined
Try this
link.simulate('click', {
preventDefault: () => {
}
});
test('simulates click events', () => {
const e = { stopPropagation: jest.fn() };
const component = shallow(<ListItem{...props} />);
const li = component.find('li').at(0).childAt(0)
li.props().onClick(e)
expect();
});
For those using Jest and #testing-library or react-testing-librarys fireEvent, you need to provide an initialised event object, otherwise the event can't be dispatched via your element.
One can then assert on e.preventDefault being called by assigning a property to that initialised event:
test('prevents default on click', () => {
const {getByText} = render(<MyComponent />);
const button = getByText(/click me/);
// initialise an event, and assign your own preventDefault
const clickEvent = new MouseEvent('click');
Object.assign(clickEvent, {preventDefault: jest.fn()});
fireEvent(button, clickEvent);
expect(clickEvent.preventDefault).toHaveBeenCalledTimes(1);
});
Similarly for stopPropagation.
Anton Karpenko's answer for Jest was useful.
Just to note that this is an issue only when using shallow enzyme renderer. In case of full DOM renderer mount, the event object contains the preventDefault method, therefore you don't have to mock it.
You can define an object with regarding function you will mock via some testing tool, for example look at Jest and Enzyme
describe('Form component', () => {
test('deos not reload page after submition', () => {
const wrapper = shallow(<TodosForm />)
// an object with some function
const event = { preventDefault: () => {} }
// mocks for this function
jest.spyOn(event, 'preventDefault')
wrapper.find('form').simulate('submit', event)
// how would you know that function is called
expect(event.preventDefault).toBeCalled()
})
})
I would suggest to create new object based on jest.fn() with
const event = Object.assign(jest.fn(), {preventDefault: () => {}})
then use it:
element.simulate('click', event);
I am using Web Components and this works for me -
const callback = jest.fn();
MouseEvent.prototype.stopPropagation = callback;
const element = createElement({});
element.shadowRoot.querySelector('ul').click();
expect(callback).toHaveBeenCalledTimes(1);