with event
- <DOMElement> with (event|events) <array|object|string> <assertion?>
An assertion that will issue one or more events on the given element and forward
it to the next assertion.
You can either provide a single event or an array of events that should be
triggers on the component. An event have the following form:
{
type: 'change', // The event type
value: 'My value', // will be set on target when specified
target: 'input', // an optional CSS selector specifying the target
}
You can also specify event data for
Simulate:
{
type: "keyDown",
target: "input",
data: {
keyCode: 13
}
}
If you don't specify a target, the event will be issued on the root element of
the given component.
I case you just want to specify the type, you can just give a string instead of
an event object:
const React = require("react");
expect = unexpected.use(require("unexpected-sinon"));
const sinon = require("sinon");
let onClick = sinon.spy();
expect(
<button onClick={onClick}>Click me!</button>,
'when mounted',
'with event', 'click'
);
expect(onClick, 'to have calls satisfying', () => {
onClick(expect.it('to satisfy', {type: 'click'}))
});
Let's use a sign-up form for the example:
class SignUpForm extends React.Component {
constructor(props) {
super();
this.state = {
username: "",
password: "",
showValidation: false
};
this.onUsernameChange = e => {
this.setState({ username: e.target.value, showValidation: false });
};
this.onPasswordChange = e => {
this.setState({ password: e.target.value, showValidation: false });
};
this.onSubmit = () => {
const { username, password } = this.state;
if (username && password.length >= 8) {
props.onSubmit({ username, password });
} else {
this.setState({ showValidation: true });
}
};
}
render() {
const { password, showValidation, username } = this.state;
return (
<form data-test-id="login">
<fieldset>
<label htmlFor="username">Username:</label>
<input
name="username"
onChange={this.onUsernameChange}
value={username}
/>
{showValidation &&
!username && (
<span className="validation">Username is required.</span>
)}
</fieldset>
<fieldset>
<label htmlFor="password">Password:</label>
<input
name="password"
type="password"
onChange={this.onPasswordChange}
value={password}
/>
{showValidation &&
password.length < 8 && (
<span className="validation">
Password must be at least 8 characters.
</span>
)}
</fieldset>
<button onClick={this.onSubmit}>Sign up</button>
</form>
);
}
}
Let's start by checking that we can successfully submit the form.
We will use sinon and
unexpected-sinon to spy on the
submit function.
Then we will use the with events
assertion to fill out the username and
password and click on the submit button.
Finally we will check that the onSubmit
function was called with the expected
values.
let onSubmit = sinon.spy();
expect(
<SignUpForm onSubmit={onSubmit} />,
"when mounted",
"with events", [
{
type: "change",
target: "[name=username]",
value: "Sune Simonsen"
},
{
type: "change",
target: "[name=password]",
value: "Secret..."
},
{
type: "click",
target: "button"
}
]
);
expect(onSubmit, "to have calls satisfying", () => {
onSubmit({ username: 'Sune Simonsen', password: 'Secret...' });
});
For a case where we don't assert anything on the rendered structure after
issuing the events, it is probably more natural to use the
simulate function
from react-dom-testing
instead. This function is exported by unexpected-reaction as a convenience:
const { simulate } = require('unexpected-reaction');
Let's see that we get a validations messages if we submit the form without
entering any data:
onSubmit = sinon.spy()
expect(
<SignUpForm onSubmit={onSubmit} />,
"when mounted",
"with event", {
type: "click",
target: "button"
},
'queried for', '.validation',
'to satisfy', [
<span>Username is required.</span>,
<span>Password must be at least 8 characters.</span>
]
);
expect(onSubmit, "was not called");