-
Notifications
You must be signed in to change notification settings - Fork 3.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Issues while testing Bootstrap components. #297
Comments
Problem no. 1 explained here #202. |
Same problem with no.2, did you figure out some workaround ? |
There is an answer now: facebook/react#3151 (comment) |
I think this is a good time to state that we should add some documentation on how to test components that use react-bootstrap components. |
Setting var Input = React.createClass({
render: function(){
return Bootstrap.Input({
ref: 'input',
type: 'text'
onChange: function () {
console.log('CHANGE');
}
});
}
});
var input = TestUtils.renderIntoDocument(Input(null));
input.getInputDOMNode().value = 'foo';
expect(input.getValue()).to.eql('foo'); // all good
TestUtils.Simulate.change(input); // does nothing |
Try changing the code to:
|
Now it works fine. The prove #916 |
|
I'm having the same issues described above by @mbfisher. Any ideas as to why the following does nothing? Having no luck trying to figure this out. Thanks in advance!
|
You need to do |
Hey @mathieumg,
|
But then it's not the React-Bootstrap component, is it? |
I'm not sure @mathieumg I'm assuming that react bootstrap just adds onChange listener onto the input it creates... but maybe I'm wrong. One of those days... brick wall after brick wall trying to get these tests written. Thanks for taking the time so far though! |
But from the snippet you just showed, it seems you're not using React-Bootstrap's |
Below is my component: /*
* New Event form
*/
var React = require('react');
var Link = require('react-router').Link;
var BS = require('react-bootstrap');
var Input = BS.Input;
var Button = BS.Button;
var Col = BS.Col;
var FormStateMixin = require('../../mixins/FormState.js');
var EventActionCreator = require('../../actions/EventActionCreator.js');
var Navigation = require('react-router').Navigation;
var moment = require('moment');
var DateTimeField = require('react-bootstrap-datetimepicker');
var _ = require('lodash');
var NewEventForm =
React.createClass({
mixins: [
FormStateMixin,
Navigation
],
getInitialState: function() {
return {
title: '',
address: '',
city: '',
state: '',
postal_code: '',
country: '',
description: '',
start_time: String(Date.now()),
// Defaults to having an endtime which is 2 hours later. The below is in milliseconds
end_time: String(Date.now() + (2 * 60 * 60 * 1000)),
errors: null
};
},
handleKeyDown: function(e) {
var ENTER = 13;
if( e.keyCode == ENTER ) {
this.handleCreateEventClick();
}
},
isValidStartEndTime: function() {
if (this.state.end_time < this.state.start_time) {
alert("An event cannot end before it even starts!");
var newEndTime = parseInt(this.state.start_time) + (2 * 60 * 60 * 1000);
this.setState({
end_time: String(newEndTime)
});
} else {
return true;
}
},
handleCreateEventClick: function() {
if (this.isValidStartEndTime()) {
EventActionCreator.createEvent(this.state);
this.setState({
errors: null
});
// navigates back to home page
this.transitionTo('home');
}
},
_handleStartTimeChange: function(ev) {
var nextState = _.cloneDeep(this.state);
// Update the state of the component. By using console.dir, I was able to see that
// ev was equal to the new time data that we needed
nextState["start_time"] = ev;
// Update the component's state with the new state
this.setState(nextState);
},
_handleEndTimeChange: function(ev) {
var nextState = _.cloneDeep(this.state);
// Update the state of the component. By using console.dir, I was able to see that
// ev was equal to the new time data that we needed
nextState["end_time"] = ev;
// Update the component's state with the new state
this.setState(nextState);
},
render:function(){
/* If the colMd prop is passed, it will determine the cols to use for layout purposes. */
var colMd = this.props.colMd || null;
return (
<form onKeyDown={this.handleKeyDown} className={this.props.className}>
<Col md={colMd}>
<Input type='title'
className="form-elem-full"
name='title'
placeholder='Enter title...'
onChange={this.handleInputChange} />
</Col>
<Col md={colMd}>
<Input type='address'
className="form-elem-full"
name='address'
placeholder='Enter address...'
onChange={this.handleInputChange} />
</Col>
<Col md={colMd}>
<Input type='city'
className="form-elem-full"
name='city'
placeholder='Enter city...'
onChange={this.handleInputChange} />
</Col>
<Col md={colMd}>
<Input type='state'
className="form-elem-full"
name='state'
placeholder='Enter state...'
onChange={this.handleInputChange} />
</Col>
<Col md={colMd}>
<Input type='postal_code'
className="form-elem-full"
name='postal_code'
placeholder='Enter postal code...'
onChange={this.handleInputChange} />
</Col>
<Col md={colMd}>
<Input type='country'
className="form-elem-full"
name='country'
placeholder='Enter country...'
onChange={this.handleInputChange} />
</Col>
<Col md={colMd}>
<Input type='description'
className="form-elem-full"
name='description'
placeholder='Enter description...'
onChange={this.handleInputChange} />
</Col>
<Col md={colMd}>
<DateTimeField dateTime={this.state.start_time} onChange={this._handleStartTimeChange} inputFormat="MM/DD/YY h:mm A" />
</Col>
<Col md={colMd}>
<DateTimeField dateTime={this.state.end_time} onChange={this._handleEndTimeChange} inputFormat="MM/DD/YY h:mm A" />
</Col>
<Col md={colMd}>
<Button className='btn btn-primary event-create-btn'
onClick={this.handleCreateEventClick}>
Create Event
</Button>
</Col>
</form>
)
}
});
module.exports = NewEventForm; Following is my test jest.dontMock('object-assign');
jest.dontMock('lodash');
jest.dontMock('../NewEventForm.js');
jest.dontMock('moment');
jest.dontMock('react-bootstrap');
jest.dontMock('../../../test-utils/ReactRouterContext.js')
describe('New Event', function() {
var EventStore = require('../../../stores/EventStore.js');
var React = require('react/addons');
var TestUtils = React.addons.TestUtils;
var ReactRouterContext = require('../../../test-utils/ReactRouterContext.js');
var NewEventForm = require('../NewEventForm.js');
var BS = require('react-bootstrap');
var EventActionCreator = require('../../../actions/EventActionCreator.js');
var newEventForm;
var submitButton;
var inputs;
var textAreas;
var eventData = { "id":23, "title":"Ultron", "address":"555 batman lane", "city":"oeu", "state":"oeu", "postal_code":"oeu",
"country":"eou", "description":"oeu", "start_time":String(Date.now()), "end_time":String(Date.now() + (2 * 60 * 60 * 1000)),
};
// Mock function call
EventStore.get.mockReturnValue(eventData);
NewEventForm = ReactRouterContext(NewEventForm);
beforeEach(function() {
newEventForm = TestUtils.renderIntoDocument(
<NewEventForm />
);
inputs = TestUtils.scryRenderedDOMComponentsWithTag(newEventForm, "input");
titleInput = inputs[0];
addressInput = inputs[1];
cityInput = inputs[2];
stateInput = inputs[3];
zipInput = inputs[4];
descriptionInput = inputs[5];
});
it('sends a submit action upon clicking of submit', function() {
//Fill out the form
titleInput.getDOMNode().value = eventData.title;
titleInput.value = eventData.title;
TestUtils.Simulate.change(titleInput.getDOMNode());
TestUtils.Simulate.change(titleInput);
addressInput.getDOMNode().value = eventData.address;
TestUtils.Simulate.change(addressInput.getDOMNode());
cityInput.getDOMNode().value = eventData.city;
TestUtils.Simulate.change(cityInput.getDOMNode());
stateInput.getDOMNode().value = eventData.state;
TestUtils.Simulate.change(stateInput.getDOMNode());
zipInput.getDOMNode().value = eventData.postal_code;
TestUtils.Simulate.change(zipInput.getDOMNode());
descriptionInput.getDOMNode().value = eventData.description;
TestUtils.Simulate.change(descriptionInput.getDOMNode());
// Now handle the submission
submitButton = TestUtils.findRenderedDOMComponentWithClass(newEventForm, "event-create-btn");
TestUtils.Simulate.click(submitButton);
expect(EventActionCreator.createEvent.mock.calls[0][0]).toEqual(eventData);
});
}); |
Oh, I see what you mean. I'm guessing |
Correct, here is the handleInputChange mixin.
I'm using lodash.js for the _cloneDeep functionality. Thanks again for your help thus far. |
I've edited my previous post while you were making yours, just in case you didn't notice! Also, you can add |
Thanks! I didn't notice. |
Still no luck. Man... I may just go back to Selenium haha. |
Perhaps with I have to admit, I'm not a React testing/mocking expert. :/ |
Thanks man, I can't use findRenderedDOMComponentWithTag since I have more than one input on the page. Thanks so much for taking the time to look into this! |
I've added this test to https://github.com/react-bootstrap/react-bootstrap/blob/master/test/InputSpec.js it.only('check input change', function () {
let onChangeHandler = sinon.stub();
let instance = ReactTestUtils.renderIntoDocument(
<Input type='state' onChange={onChangeHandler} id='myComponent' />
);
let node = React.findDOMNode(ReactTestUtils.findRenderedDOMComponentWithTag(instance, 'input'));
assert.equal(node.getAttribute('id'), 'myComponent'); // check that `input` renders OK
// check that we can find input by searching multiple elements `scryRenderedDOMComponentsWithTag` method
let inputs = ReactTestUtils.scryRenderedDOMComponentsWithTag(instance, 'input');
assert.equal(React.findDOMNode(inputs[0]).getAttribute('id'), 'myComponent');
// check both ways `change` simulation. Like it is done in RB tests
ReactTestUtils.Simulate.change(node);
// and like you are trying to do
ReactTestUtils.Simulate.change(React.findDOMNode(inputs[0]));
// all works fine
onChangeHandler.should.have.been.called;
});
I hope it will help you 🍒 |
Forget to notify you @chiedojohn about #297 (comment) |
Thanks @AlexKVal, That still doesn't seem to work for my use-case though. In my use-case, I'm rendering a component that contains React-bootstrap Inputs. It could be that I need to rethink how I'm writing my tests. This is looking more and more to be a React issue and not a react-bootstrap issue. Thanks for all of your help though. |
👍 |
AHA! Figured it out. It's the darn just auto mocking. I needed to add the following to the top of my test. Now things work as expected. jest.dontMock('../../../mixins/FormState.js'); |
That's why many don't like |
Hahahahhaha. There are times like this when I am heavily considering going to |
Quick tip: if you want to disable Jest automocking, just add this line into package.json: "jest": {
"unmockedModulePathPatterns": [""]
} |
I'm trying to write tests that check conditions against the contents of a dismissable Alert component. The problem is e.g.
It works if the Alert is configured to not be dismissable. Does anyone know how I can reference this children of a dismissable Alert, it is not possible for me to make these not dismissable. Is there some ref I can get hold of? |
You're hitting https://github.com/react-bootstrap/react-bootstrap/blob/v0.25.2/src/Alert.js#L29 The Alert's child is whatever you pass in, so ultimately you can do whatever you need to get ahold of it. |
That would be the case in the trivial example I detailed, but in reality the Alert is embedded within another component. It is that component I am testing, and the contents of the alert are built based on internal state. I was attempting to look up rendered DOM components under that top level component (which just happen to be rendered inside an Alert) when I ran into this problem. |
…nput field relative to tags (react-bootstrap#491) fixes react-bootstrap#297, react-bootstrap#233
I found few issues while testing app with React.addons.TestUtils.
1. ref does not work on ModalTrigger children
code
test
2. can't change input value via TestUtils.Simulate.change
code
test
Is this expected behaviour or bug? Thank you.
The text was updated successfully, but these errors were encountered: