Kann jemand bitte sagen Sie mir, wie ein Test Reagieren Komponente Event-Handler, der so aussieht ...Testing Event-Handler
handleChange(e) {
this.setObjectState(e.target.getAttribute("for").toCamelCase(), e.target.value);
}
setObjectState(propertyName, value) {
let obj = this.state.registrationData;
obj[propertyName] = value;
this.setState({registrationData: obj});
}
Ich habe einen Test geschrieben Enzym mit dem Rendering zu testen und können Ich simuliere die Ereignisse, um zu testen, dass die Handler tatsächlich aufgerufen werden, aber das ist der einfache Teil. Ich möchte testen, was passiert, wenn der Ereigniscode ausgeführt wird. Ich kann diese manuell auslösen, aber ich weiß nicht, was ich an den 'e' Parameter im Test weitergeben soll. Wenn ich Enzym verwende, fällt der Test um, es sei denn, ich stub den Event-Handler, da 'e' nicht definiert ist.
Hier ist der Enzymtest Bits ...
describe("uses internal state to",() => {
let stateStub = null;
let formWrapper = null;
beforeEach(() => {
wrapper = shallow(<RegistrationForm />);
instance = wrapper.instance();
stateStub = sinon.stub(instance, 'setState');
formWrapper = wrapper.find(Form.Wrapper);
});
afterEach(() => {
stateStub.restore();
});
it("handle changing an email address",() => {
formWrapper.find("[name='Email']").simulate('change')
sinon.called(stateStub);
})
});
ich mit ‚Mount‘ anstelle von ‚flachen‘ kurz sah, aber ich konnte sie nicht auf Anhieb funktioniert bekommen. Das hat viele viele Probleme, wie zum Beispiel nicht in der Lage zu sein, Dinge wie die Datenlast für die Look-Up-Drop-Downs auszugeben, bevor es versucht, es auszuführen.
Hier ist, was ich bin versucht (im Idealfall) zu tun ...
describe("ALT uses internal state to",() => {
let stateStub = null;
let formWrapper = null;
beforeEach(() => {
wrapper = shallow(<RegistrationForm />);
instance = wrapper.instance();
stateStub = sinon.stub(instance, 'setState');
});
afterEach(() => {
stateStub.restore();
});
it("handle changing an email address",() => {
let e = 'some fake data - what IS this object?';
instance.handleChange(e);
sinon.called(stateStub);
sinon.calledWith({registrationData: errr.. what?});
})
});
Auf Wunsch ist hier die vollständige Komponentencode ...
import ErrorProcessor from "./error-processor";
import Form from "../../../../SharedJs/components/form/index.jsx"
import HiddenState from "../../data/hidden-state"
import LookupRestServiceGateway from "../../../../SharedJs/data/lookup-rest-service-gateway"
import React from "react";
import RegistrationRestServiceGateway from "../../data/registration-rest-service-gateway"
export default class RegistrationForm extends React.Component {
constructor(props) {
super(props);
this.state = props.defaultState || {
registrationData: {
email: "",
password: "",
confirmPassword: "",
firstName: "",
lastName: "",
employerID: null
},
registered: false,
employersLookupData: []
};
this.formId = "registration-form";
this.errorProcessor = new ErrorProcessor();
this.employersDataSource = new LookupRestServiceGateway(`/api/lookups/employers/${HiddenState.getServiceOperatorCode()}`);
this.registrationGateway = new RegistrationRestServiceGateway();
this.handleChange = this.handleChange.bind(this);
this.handleEmployerChange = this.handleEmployerChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(e) {
this.setObjectState(e.target.getAttribute("for").toCamelCase(), e.target.value);
}
handleEmployerChange(e) {
this.setObjectState("EmployerID", e.target.value);
}
handleSubmit() {
this.submitRegistration();
}
componentDidMount() {
this.loadLookupData();
}
loadLookupData() {
this.employersDataSource.getListItems({ successCallback: (data) => {
this.setState({ employersLookupData: data ? data.items : [] });
}});
}
setObjectState(propertyName, value) {
let obj = this.state.registrationData;
obj[propertyName] = value;
this.setState({registrationData: obj});
}
submitRegistration() {
this.registrationGateway.register({
data: this.state.registrationData,
successCallback: (data, status, xhr) => {
this.setState({registered: true});
if (data.errors && data.errors.length) {
this.errorProcessor.processErrorObject(this.formId, xhr);
}
},
errorCallback: (xhr) => {
this.errorProcessor.processErrorObject(this.formId, xhr);
}
});
}
render() {
return (this.state.registered ? this.renderConfirmation() : this.renderForm());
}
renderConfirmation() {
return (
<div className = "registration-form">
<p>Your registration has been submitted. An email will be sent to you to confirm your registration details before you can log in.</p>
<Form.ErrorDisplay />
</div>
);
}
renderForm() {
return (
<Form.Wrapper formId = {this.formId}
className = "registration-form form-horizontal"
onSubmit = {this.handleSubmit}>
<h4>Create a new account.</h4>
<hr/>
<Form.ErrorDisplay />
<Form.Line name = "Email"
label = "Email"
type = "email"
inputClassName = "col-md-10 col-sm-9" labelClassName = "col-md-2 col-sm-3"
value = {this.state.registrationData.email}
onChange = {this.handleChange} />
<Form.Line name = "Password"
label = "Password"
type = "password"
inputClassName = "col-md-10 col-sm-9" labelClassName = "col-md-2 col-sm-3"
value = {this.state.registrationData.password}
onChange = {this.handleChange} />
<Form.Line name = "ConfirmPassword"
label = "Confirm Password"
type = "password"
inputClassName = "col-md-10 col-sm-9" labelClassName = "col-md-2 col-sm-3"
value = {this.state.registrationData.confirmPassword}
onChange = {this.handleChange} />
<Form.Line name = "FirstName"
label = "First Name"
inputClassName = "col-md-10 col-sm-9" labelClassName = "col-md-2 col-sm-3"
value = {this.state.registrationData.firstName}
onChange = {this.handleChange} />
<Form.Line name = "LastName"
label = "Last Name"
inputClassName = "col-md-10 col-sm-9" labelClassName = "col-md-2 col-sm-3"
value = {this.state.registrationData.lastName}
onChange = {this.handleChange} />
<Form.DropDownLine name = "EmployerID"
label = "Employer"
inputClassName = "col-md-10 col-sm-9" labelClassName = "col-md-2 col-sm-3"
emptySelection = "Please select an employer…"
onChange = {this.handleEmployerChange}
selectedValue = {this.state.registrationData.employerID}
items = {this.state.employersLookupData}/>
<Form.Buttons.Wrapper className="col-sm-offset-3 col-md-offset-2 col-md-10 col-sm-9">
<Form.Buttons.Submit text = "Register"
icon = "fa-user-plus" />
</Form.Buttons.Wrapper>
</Form.Wrapper>
);
}
}
RegistrationForm.PropTypes = {
defaultState: React.PropTypes.object
}
Ich habe es geschafft, diese Funktion zu erhalten so wie jetzt, aber das fühlt sich sehr sehr bescheuert an - Es bringt mich dazu zu denken, dass Enzyms Mount der Weg ist, aber das bringt so viele Probleme mit sich und meine Spec-Datei ist schon 10 mal so groß wie meine Komponente und alles scheint ziemlich sinnlos auf dieser Ebene ...
describe("uses internal state to",() => {
let stateStub = null;
let formWrapper = null;
beforeEach(() => {
wrapper = shallow(<RegistrationForm />);
instance = wrapper.instance();
formWrapper = wrapper.find(Form.Wrapper);
stateStub = sinon.stub(instance, 'setState');
});
afterEach(() => {
stateStub.restore();
});
it("handle changing an email address",() => {
$("body").append(`<input type="email" for="Email" id="field" class="form-control form-control " maxlength="10000" value="">`);
let node = $("#field")[0];
node.value = "[email protected]";
instance.handleChange({target: node});
sinon.assert.called(stateStub);
})
});
React stellt Testprogramme zur Verfügung, um den Click-Handler zu simulieren: https://facebook.github.io/react/docs/test-utils.html#simulate – chrisjlee
Enzym tut das - ich benutze keinen Jest. Ich versuche auch nicht zu klicken. Die Jest Docs haben mir vielleicht eine Idee gegeben. Danke für den Link. –