utilizando que ejemplo con bootstrap autocompletar jquery reactjs babeljs semantic-ui jestjs

ejemplo - ¿Cómo me burlo de las bibliotecas de terceros(como jQuery y UI semántica) utilizando Jest?



jquery ui widget (2)

He estado aprendiendo React, Babel, UI semántica y Jest en las últimas semanas. Realmente no me he encontrado con demasiados problemas con mis componentes que no se renderizan en el navegador, pero me he encontrado con problemas con el renderizado al escribir pruebas de unidad con Jest.

El SUT es el siguiente:

EditUser.jsx

var React = require(''react''); var { browserHistory, Link } = require(''react-router''); var $ = require(''jquery''); import Navigation from ''../Common/Navigation''; const apiUrl = process.env.API_URL; const phoneRegex = /^[(]{0,1}[0-9]{3}[)]{0,1}[-/s/.]{0,1}[0-9]{3}[-/s/.]{0,1}[0-9]{4}$/; var EditUser = React.createClass({ getInitialState: function() { return { email: '''', firstName: '''', lastName: '''', phone: '''', role: '''' }; }, handleSubmit: function(e) { e.preventDefault(); var data = { "email": this.state.email, "firstName": this.state.firstName, "lastName": this.state.lastName, "phone": this.state.phone, "role": this.state.role }; if($(''.ui.form'').form(''is valid'')) { $.ajax({ url: apiUrl + ''/api/users/'' + this.props.params.userId, dataType: ''json'', contentType: ''application/json'', type: ''PUT'', data: JSON.stringify(data), success: function(data) { this.setState({data: data}); browserHistory.push(''/Users''); $(''.toast'').addClass(''happy''); $(''.toast'').html(data["firstName"] + '' '' + data["lastName"] + '' was updated successfully.''); $(''.toast'').transition(''fade up'', ''500ms''); setTimeout(function(){ $(''.toast'').transition(''fade up'', ''500ms'').onComplete(function() { $(''.toast'').removeClass(''happy''); }); }, 3000); }.bind(this), error: function(xhr, status, err) { console.error(this.props.url, status, err.toString()); $(''.toast'').addClass(''sad''); $(''.toast'').html("Something bad happened: " + err.toString()); $(''.toast'').transition(''fade up'', ''500ms''); setTimeout(function(){ $(''.toast'').transition(''fade up'', ''500ms'').onComplete(function() { $(''.toast'').removeClass(''sad''); }); }, 3000); }.bind(this) }); } }, handleChange: function(e) { var nextState = {}; nextState[e.target.name] = e.target.value; this.setState(nextState); }, componentDidMount: function() { $(''.dropdown'').dropdown(); $(''.ui.form'').form({ fields: { firstName: { identifier: ''firstName'', rules: [ { type: ''empty'', prompt: ''Please enter a first name.'' }, { type: ''doesntContain[<script>]'', prompt: ''Please enter a valid first name.'' } ] }, lastName: { identifier: ''lastName'', rules: [ { type: ''empty'', prompt: ''Please enter a last name.'' }, { type: ''doesntContain[<script>]'', prompt: ''Please enter a valid last name.'' } ] }, email: { identifier: ''email'', rules: [ { type: ''email'', prompt: ''Please enter a valid email address.'' }, { type: ''empty'', prompt: ''Please enter an email address.'' }, { type: ''doesntContain[<script>]'', prompt: ''Please enter a valid email address.'' } ] }, role: { identifier: ''role'', rules: [ { type: ''empty'', prompt: ''Please select a role.'' } ] }, phone: { identifier: ''phone'', optional: true, rules: [ { type: ''minLength[10]'', prompt: ''Please enter a valid phone number of at least {ruleValue} digits.'' }, { type: ''regExp'', value: phoneRegex, prompt: ''Please enter a valid phone number.'' } ] } } }); $.ajax({ url: apiUrl + ''/api/users/'' + this.props.params.userId, dataType:''json'', cache: false, success: function(data) { this.setState({data: data}); this.setState({email: data.email}); this.setState({firstName: data.firstName}); this.setState({lastName: data.lastName}); this.setState({phone: data.phone}); this.setState({role: data.role}); }.bind(this), error: function(xhr, status, err) { console.error(this.props.url, status, err.toString()); }.bind(this) }); }, render: function () { return ( <div className="container"> <Navigation active="Users"/> <div className="ui segment"> <h2>Edit User</h2> <div className="required warning"> <span className="red text">*</span><span> Required</span> </div> <form className="ui form" onSubmit={this.handleSubmit} data={this.state}> <h4 className="ui dividing header">User Information</h4> <div className="ui three column grid field"> <div className="row fields"> <div className="column field required"> <label>First Name</label> <input type="text" name="firstName" value={this.state.firstName} onChange={this.handleChange}/> </div> <div className="column field required"> <label>Last Name</label> <input type="text" name="lastName" value={this.state.lastName} onChange={this.handleChange}/> </div> <div className="column field required"> <label>Email</label> <input type="text" name="email" value={this.state.email} onChange={this.handleChange}/> </div> </div> </div> <div className="ui three column grid field"> <div className="row fields"> <div className="column field required"> <label>User Role</label> <select className="ui dropdown" name="role" onChange={this.handleChange} value={this.state.role}> <option value="SuperAdmin">Super Admin</option> </select> </div> <div className="column field"> <label>Phone</label> <input name="phone" value={this.state.phone} onChange={this.handleChange}/> </div> </div> </div> <div className="ui three column grid"> <div className="row"> <div className="right floated column"> <div className="right floated large ui buttons"> <Link to="/Users" className="ui button">Cancel</Link> <button className="ui button primary" type="submit">Save</button> </div> </div> </div> </div> <div className="ui error message"></div> </form> </div> </div> ); } }); module.exports = EditUser;

El archivo de prueba asociado es el siguiente:

EditUser.test.js

var React = require(''react''); var Renderer = require(''react-test-renderer''); var jQuery = require(''jquery''); require(''../../../semantic/dist/components/dropdown''); import EditUser from ''../../../app/components/Users/EditUser''; it(''renders correctly'', () => { const component = Renderer.create( <EditUser /> ).toJSON(); expect(component).toMatchSnapshot(); });

El problema que estoy viendo cuando corro jest :

FAIL test/components/Users/EditUser.test.js ● Test suite failed to run ReferenceError: jQuery is not defined at Object.<anonymous> (semantic/dist/components/dropdown.min.js:11:21523) at Object.<anonymous> (test/components/Users/EditUser.test.js:6:370) at process._tickCallback (node.js:369:9)


Lo estás haciendo de manera correcta, pero un simple error.

Tienes que decir broma para no burlarse de jquery

Para ser claro,

de https://www.phpied.com/jest-jquery-testing-vanilla-app/ under 4th subtitle Testing Vanilla

[Habla de probar una aplicación de Vainilla, pero describe perfectamente acerca de Jest ]

Lo que pasa con Jest es que se burla de todo. Lo cual no tiene precio para las pruebas unitarias. Pero también significa que debes declarar cuando no quieres algo burlado.

Es decir

jest.unmock(moduleName)

De la documentación de Facebook
unmock Indica que el sistema del módulo nunca debe devolver una versión unmock del módulo especificado de require () (p. ej., que siempre debe devolver el módulo real).

El uso más común de esta API es para especificar el módulo que una prueba determinada tiene la intención de probar (y por lo tanto no desea burlarse automáticamente).

Devuelve el objeto de broma para encadenar.

Nota: Anteriormente no se dontMock .

Al usar babel-jest, las llamadas para desbloquear se elevarán automáticamente a la parte superior del bloque de código. Use dontMock si quiere evitar explícitamente este comportamiento.
Puede ver la documentación completa aquí Página de documentación de Facebook en Github .

También use const lugar de var in require. Es decir

const $ = require(''jquery'');

Entonces el código parece

jest.unmock(''jquery''); // unmock it. In previous versions, use dontMock instead var React = require(''react''); var { browserHistory, Link } = require(''react-router''); const $ = require(''jquery''); import Navigation from ''../Common/Navigation''; const apiUrl = process.env.API_URL; const phoneRegex = /^[(]{0,1}[0-9]{3}[)]{0,1}[-/s/.]{0,1}[0-9]{3}[-/s/.]{0,1}[0-9]{4}$/; var EditUser = React.createClass({ getInitialState: function() { return { email: '''', firstName: '''', lastName: '''', phone: '''', role: '''' }; }, handleSubmit: function(e) { e.preventDefault(); var data = { "email": this.state.email, "firstName": this.state.firstName, "lastName": this.state.lastName, "phone": this.state.phone, "role": this.state.role }; if($(''.ui.form'').form(''is valid'')) { $.ajax({ url: apiUrl + ''/api/users/'' + this.props.params.userId, dataType: ''json'', contentType: ''application/json'', type: ''PUT'', data: JSON.stringify(data), success: function(data) { this.setState({data: data}); browserHistory.push(''/Users''); $(''.toast'').addClass(''happy''); $(''.toast'').html(data["firstName"] + '' '' + data["lastName"] + '' was updated successfully.''); $(''.toast'').transition(''fade up'', ''500ms''); setTimeout(function(){ $(''.toast'').transition(''fade up'', ''500ms'').onComplete(function() { $(''.toast'').removeClass(''happy''); }); }, 3000); }.bind(this), error: function(xhr, status, err) { console.error(this.props.url, status, err.toString()); $(''.toast'').addClass(''sad''); $(''.toast'').html("Something bad happened: " + err.toString()); $(''.toast'').transition(''fade up'', ''500ms''); setTimeout(function(){ $(''.toast'').transition(''fade up'', ''500ms'').onComplete(function() { $(''.toast'').removeClass(''sad''); }); }, 3000); }.bind(this) }); } }, handleChange: function(e) { var nextState = {}; nextState[e.target.name] = e.target.value; this.setState(nextState); }, componentDidMount: function() { $(''.dropdown'').dropdown(); $(''.ui.form'').form({ fields: { firstName: { identifier: ''firstName'', rules: [ { type: ''empty'', prompt: ''Please enter a first name.'' }, { type: ''doesntContain[<script>]'', prompt: ''Please enter a valid first name.'' } ] }, lastName: { identifier: ''lastName'', rules: [ { type: ''empty'', prompt: ''Please enter a last name.'' }, { type: ''doesntContain[<script>]'', prompt: ''Please enter a valid last name.'' } ] }, email: { identifier: ''email'', rules: [ { type: ''email'', prompt: ''Please enter a valid email address.'' }, { type: ''empty'', prompt: ''Please enter an email address.'' }, { type: ''doesntContain[<script>]'', prompt: ''Please enter a valid email address.'' } ] }, role: { identifier: ''role'', rules: [ { type: ''empty'', prompt: ''Please select a role.'' } ] }, phone: { identifier: ''phone'', optional: true, rules: [ { type: ''minLength[10]'', prompt: ''Please enter a valid phone number of at least {ruleValue} digits.'' }, { type: ''regExp'', value: phoneRegex, prompt: ''Please enter a valid phone number.'' } ] } } }); $.ajax({ url: apiUrl + ''/api/users/'' + this.props.params.userId, dataType:''json'', cache: false, success: function(data) { this.setState({data: data}); this.setState({email: data.email}); this.setState({firstName: data.firstName}); this.setState({lastName: data.lastName}); this.setState({phone: data.phone}); this.setState({role: data.role}); }.bind(this), error: function(xhr, status, err) { console.error(this.props.url, status, err.toString()); }.bind(this) }); }, render: function () { return ( <div className="container"> <Navigation active="Users"/> <div className="ui segment"> <h2>Edit User</h2> <div className="required warning"> <span className="red text">*</span><span> Required</span> </div> <form className="ui form" onSubmit={this.handleSubmit} data={this.state}> <h4 className="ui dividing header">User Information</h4> <div className="ui three column grid field"> <div className="row fields"> <div className="column field required"> <label>First Name</label> <input type="text" name="firstName" value={this.state.firstName} onChange={this.handleChange}/> </div> <div className="column field required"> <label>Last Name</label> <input type="text" name="lastName" value={this.state.lastName} onChange={this.handleChange}/> </div> <div className="column field required"> <label>Email</label> <input type="text" name="email" value={this.state.email} onChange={this.handleChange}/> </div> </div> </div> <div className="ui three column grid field"> <div className="row fields"> <div className="column field required"> <label>User Role</label> <select className="ui dropdown" name="role" onChange={this.handleChange} value={this.state.role}> <option value="SuperAdmin">Super Admin</option> </select> </div> <div className="column field"> <label>Phone</label> <input name="phone" value={this.state.phone} onChange={this.handleChange}/> </div> </div> </div> <div className="ui three column grid"> <div className="row"> <div className="right floated column"> <div className="right floated large ui buttons"> <Link to="/Users" className="ui button">Cancel</Link> <button className="ui button primary" type="submit">Save</button> </div> </div> </div> </div> <div className="ui error message"></div> </form> </div> </div> ); } }); module.exports = EditUser;


En tu configuración de broma, pon ..

"setupFiles": ["./jestsetup.js"]

En jestsetup.js necesitas agregar $ y jQuery como globales ...

import $ from ''jquery''; global.$ = $; global.jQuery = $;