Curso de React.js 2017

Toma las primeras clases gratis

COMPARTE ESTE ARTÍCULO Y MUESTRA LO QUE APRENDISTE

<h1>Testear los componentes de React?¿?¿</h1>

Hoy en día el Frontend es una de las partes con mayor responsabilidad en el desarrollo web por lo que es de mucha importancia poder automatizar nuestras pruebas para tener mayor control del código, crear componentes más robustos y responder a errores de una manera más rápida. Así que por favor no hagan caso a Eddie Murphy!!

Quisiera darles una pequeña idea de como crear un entorno de test con Jest y Enzyme testeando uno de los componentes del curso de React, el componente Media. Pero para ello vamos a definir primero que son estos dos términos.

Jest: Es un framework de test unitarios y será el encargado de correr nuestros test. Jest website

Enzyme: Es una librería creada por AirBnb con utilidades especificas para el trabajo con componentes hechos con React. Enzyme repository

<h1>Setup</h1>

En primer lugar, les recomiendo que tomen el curso de React de Platzi por si no están familiarizados con lo que es un componente y porque lo que vamos a testear es uno de los componentes de ese curso, el component Media.js

Las dependencias que vamos a necesitar instalar son las siguientes:

npm install --save-dev babel-jest babel-preset-env babel-preset-react jest enzyme react-test-renderer enzyme-adapter-react-16

Para que nuestro entorno de testing con jest funcione correctamente para la versión de React del curso tendremos que crear el siguiente archivo de configuración src/setupTests.js y .babelrc:

/* 
Script necesario para realizar test con enzyme y la
versión 16 de React si utilizas otra versión puedes consultar
en el siguiente enlace:

https://github.com/airbnb/enzyme/tree/master/packages/enzyme-adapter-react-16#upgrading-from-enzyme-2x-or-react--16

*/
import { configure } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
 
configure({ adapter: new Adapter() });

// stub para ignorar cuando incluimos css con css loader en nuestros componentes

const stubCSS = '';

export default stubCSS;

{
  "presets": ["env", "react", "stage-2"]
}

Después en nuestro package.json tenemos que añadir lo siguiente:

"scripts": {
    "test": "jest --watch",
    "build:dev": "webpack-dev-server --config ./webpack.dev.config.js",

y

  "jest": {
    "moduleNameMapper": {
      "\\.(css|jpg|png)$": "<rootDir>/src/setupTests.js"
    }
  },
  "dependencies": {

lo primero es un script para correr nuestro test runner (Jest) y que se ejecuten nuestros test y lo segundo es configuración, para ignorar ciertos archivos que no queremos testear o que afecten a nuestros test como los que importamos de tipo .css

Ahora ejecutamos nuestro script de test en una terminal o linea de comandos:

npm test

Y debería devolvernos alguno de los siguientes mensajes:

No tests found
In /home/kevinccbsg/Platzi/pull-request-repos/platzi-video
  42 files checked.
  testMatch: **/__tests__/**/*.js?(x),**/?(*.)(spec|test).js?(x) - 0 matches
  testPathIgnorePatterns: /node_modules/ - 42 matches
Pattern:  - 0 matches

Watch Usage: Press w to show more.
No tests found related to files changed since last commit.
Press `a` to run all tests, or run Jest with `--watchAll`.

Watch Usage
 › Press a to run all tests.
 › Press f to run only failed tests.
 › Press p to filter by a filename regex pattern.
 › Press t to filter by a test name regex pattern.
 › Press q to quit watch mode.
 › Press Enter to trigger a test run.

Perfecto!! ya tenemos nuestro entorno listo ahora tenemos que testear nuestro componente.

<h1>Testing time</h1>

Lo primer será crear nuestro archivo de testing *src/playlist/components/media.test.js

Una vez esto si vemos en nuestra linea de comandos donde lanzamos el script npm test veremos que tenemos un error pero es básicamente porque no tenemos ningún test escrito:

 FAIL  src/playlist/components/media.test.js
  ● Test suite failed to run

    Your test suite must contain at least one test.
      
      at node_modules/jest/node_modules/jest-cli/build/test_scheduler.js:157:22

Test Suites: 1 failed, 1 total
Tests:       0 total
Snapshots:   0 total
Time:        0.31s
Ran all test suites related to changed files.

Watch Usage: Press w to show more.

Como se trata de un componente presentacional y no de un componente de tipo contenedor solo nos va a interesar testear su renderizado, por lo que nuestro test se podría ver de la siguiente forma:

// importamos react para poder usar componentes
import React from 'react';
// importamos el metodo shallow para renderizar el componente
import { shallow } from 'enzyme';
// importamos el componente que queremos testear
import Media from './media';

// props se testing
const props = {
  title: 'title test',
};

const newProps = {
  title: 'new title test',
};

describe('Media', () => {
  it('should have an image', () => {
    // creamos un wrapper que tenga nuestro componente
    const wrapper = shallow(<Media {...props} />);
    // esperamos que ese wrapper que es nuestro componente tenga una imagen
    expect(wrapper.find('img')).toHaveLength(1);
  });

  it('should have title with value `title test`', () => {
    const wrapper = shallow(<Media {...props} />);
    // esperamos que ese wrapper que es nuestro componente tenga un h3 con el titulo
    expect(wrapper.find('h3.Media-title').text()).toEqual(props.title);
  });

  it('should have title with new value `title test`', () => {
    const wrapper = shallow(<Media {...props} />);
    // modificamos las props con las nuevas
    wrapper.setProps(newProps);
    // esperamos que ese wrapper que es nuestro componente tenga un h3 con el titulo nuevo
    expect(wrapper.find('h3.Media-title').text()).toEqual(newProps.title);
  });
});

Este es un test sencillo lo cual nos ayuda un poco a ver el comportamiento de nuestro componente. Esto podría abarcar mucho más, desde simular eventos del DOM a hacer servidores fake que nos proporcionen los datos a nuestros componentes. Pero solo quería mostrarles un ejemplo básico.

En el output de nuestra terminal veremos como todos nuestros test pasan correctamente.

 PASS  src/playlist/components/media.test.js
  Media
    ✓ should have an image (5ms)
    ✓ should have title with value `title test` (3ms)
    ✓ should have title with new value `new title test` (3ms)

Test Suites: 1 passed, 1 total
Tests:       3 passed, 3 total
Snapshots:   0 total
Time:        0.638s, estimated 1s
Ran all test suites related to changed files.

Watch Usage: Press w to show more.

Lo cool de esto, es que ahora podríamos modificar el componente de Leonidas, por uno funcional, ya que el estado no se esta utilizando y pasariamos de:

import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import './media.css';

class Media extends PureComponent {
  state = {
    author: 'Leonidas Esteban'
  }
  // constructor(props) {
  //   super(props)
  //   this.state = {
  //     author: props.author
  //   }
  // //   this.handleClick = this.handleClick.bind(this);
  // }
  handleClick = (event) => {
    // console.log(this.props.image)
    // this.setState({
    //   author: 'Ricardo Celis',
    // })
    this.props.openModal(this.props);
  }
  render() {
    const styles = {
      container: {
        color: '#44546b',
        cursor: 'pointer',
        width: 260,
        border: '1px solid red'
      }
    }
    return (
      <div className="Media" onClick={this.handleClick}>
        <div className="Media-cover">
          <img
            src={this.props.cover}
            alt=""
            width={260}
            height={160}
            className="Media-image"
          />
          <h3 className="Media-title">{this.props.title}</h3>
          <p className="Media-author">{this.props.author}</p>
        </div>
      </div>
    )
  }
}

Media.propTypes = {
  cover: PropTypes.string,
  title: PropTypes.string.isRequired,
  author: PropTypes.string,
  type: PropTypes.oneOf(['video', 'audio']),
}

export default Media;

a algo así:

import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import './media.css';

const styles = {
  container: {
    color: '#44546b',
    cursor: 'pointer',
    width: 260,
    border: '1px solid red'
  }
};

const Media = (props) => (
  <div className="Media" onClick={props.openModal(props)}>
    <div className="Media-cover">
      <img
        src={props.cover}
        alt=""
        width={260}
        height={160}
        className="Media-image"
      />
      <h3 className="Media-title">{props.title}</h3>
      <p className="Media-author">{props.author}</p>
    </div>
  </div>
);

Media.propTypes = {
  cover: PropTypes.string,
  title: PropTypes.string.isRequired,
  author: PropTypes.string,
  type: PropTypes.oneOf(['video', 'audio']),
  openModal: PropTypes.func,
}

Media.defaultProps = {
  openModal: () => 0,
};

export default Media;

Y nuestros test continuarían pasando asegurandonos que el renderizado es correcto.

 PASS  src/playlist/components/media.test.js
  Media
    ✓ should have an image (5ms)
    ✓ should have title with value `title test` (3ms)
    ✓ should have title with new value `new title test` (3ms)

Test Suites: 1 passed, 1 total
Tests:       3 passed, 3 total
Snapshots:   0 total
Time:        0.638s, estimated 1s
Ran all test suites related to changed files.

Watch Usage: Press w to show more.
<h1>Conclusión</h1>

Al principio puede parecer complicado, pero es muy recomendable crear test a nuestros componentes. Para comprovar su renderizado en cambios de estado, simular eventos del dom y ver como se comporta el componente o incluso los lifecycle methods de React. En este tutorial era imposible mostrar todo pero les invito a que consulten la documentación de Jest y Enzyme.

El código lo pueden encontrar en mi repositorio que es un fork del repo del curso.

Curso de React.js 2017

Toma las primeras clases gratis

COMPARTE ESTE ARTÍCULO Y MUESTRA LO QUE APRENDISTE

0 Comentarios

para escribir tu comentario

Artículos relacionados