react-webpack-generators / generator-react-webpack

Yeoman generator for ReactJS and Webpack
http://newtriks.com/2013/12/31/automating-react-with-yeoman-and-grunt/
MIT License
2.88k stars 355 forks source link

Testing default props #256

Closed dannymk closed 8 years ago

dannymk commented 8 years ago

Is there an example anywhere on how to test default properties?

'use strict';
import React from 'react';
require('styles//Dan.less');
class DanComponent extends React.Component {
  render() {
    return (
      
{this.props.name} is now here!
); } } DanComponent.displayName = 'DanComponent'; // Uncomment properties you need DanComponent.propTypes = { name: React.PropTypes.string }; DanComponent.defaultProps = { name: '==blank' }; export default DanComponent; == test 'use strict'; import createComponent from 'helpers/shallowRenderHelper'; import DanComponent from 'components//DanComponent.js'; describe('DanComponent', () => { let component; beforeEach(() => { component = createComponent(DanComponent); }); it('should have its component className as dan-component', () => { expect(component.props.className).to.equal('dan-component'); }); it('Name default property should be ==blank', () => { expect(component.defaultProps.name).to.equal('==blank'); }); });

I understand that 'react-addons-test-utils' may help in this area but I wanted to see if there was an example anywhere on here a la "out of the box".

sthzg commented 8 years ago

Hi @dannymk, the shallow render helper lets you make assertions on what your component renders, so it is already one level too deep in the tree to give you access to the outer props.

If you only want to make sure that defaultProps have a certain value you can simply assert this on the component object, without any additional helpers at all:

describe('<DanComponent />', () => {
  it('has "==blank" as a defaultProp for "name"', () => {
    expect(DanComponent.defaultProps.name).to.equal('==blank');
  });
});

If you want to assert things on the rendered component, I suggest you take a look at Enzyme, which is endorsed on the official FB docs like this

Airbnb has released a testing utility called Enzyme, which makes it easy to assert, manipulate, and traverse your React Components' output. If you're deciding on a unit testing library, it's worth checking out: http://airbnb.io/enzyme/

It is one of these packages where skimming over the api just makes you feel happy.

It is also integrated into the V4-generator, which is currently in the makings (you can already install the beta with npm i generator-react-webpack@beta). It has Enzyme setup for you, although you could also simply install it on your existing projects.

To test a (default) prop with Enzyme, you can do this:

import { mount } from 'enzyme';

describe('<DanComponent />', () => {

  let component;
  beforeEach(() => {
    component = mount(<DanComponent />);
  });

  describe('when rendering the component', () => {
    it('the defaultProp for "name" should be "==blank"', () => {
      expect(component.prop('name')).to.equal('==blank');
    });
  });
});
dannymk commented 8 years ago

Excellent, thank you. I can definitely use this on Monday.

dannymk commented 8 years ago

I wish I could just install it into my projects:

ERROR in ./~/enzyme/build/react-compat.js Module not found: Error: Cannot resolve module 'react/addons' in /home/daniel/Development/Web/Axis901/node_modules/enzyme/build @ ./~/enzyme/build/react-compat.js 40:16-39 41:46-69

Installing it from npm (This package is deprecated):

0.9.1-deprecated is the latest of 3 releases

does not look good either :-/

Even after I have confirmed that the react-addons module is installed:

{ name: 'react-addons', description: 'Simple packaging of react addons to avoid fiddly \'react/addons\' npm module.', 'dist-tags': { latest: '0.9.1-deprecated' }, versions: [ '0.8.0', '0.9.0', '0.9.1-deprecated' ], maintainers: [ 'strml samuel.trace.reed@gmail.com' ], time: { modified: '2015-01-27T13:49:03.165Z', created: '2014-02-06T15:14:58 ...

weblogixx commented 8 years ago

Hi @dannymk,

you should use react-addons-test-utils directly, react-addons is not an official react module. Maybe it does not provide the testutils in a current version?

It should be enough to:

'use strict';

let path = require('path');
let srcPath = path.join(__dirname, '/../src/');

let baseConfig = require('./base');

module.exports = {
  devtool: 'cheap-module-source-map',
  module: {
    preLoaders: [
      {
        test: /\.(js|jsx)$/,
        loader: 'isparta-loader',
        include: [
          path.join(__dirname, '/../src')
        ]
      }
    ],
    loaders: [
      {
        test: /\.(png|jpg|gif|woff|woff2|css|sass|scss|less|styl|mp4|ogg|svg)$/,
        loader: 'null-loader'
      },
      {
        test: /\.json$/,
        loader: 'json'
      },
      {
        test: /\.(js|jsx)$/,
        loader: 'babel-loader',
        query: {
          presets: [ 'airbnb' ]
        },
        include: [].concat(
          baseConfig.additionalPaths,
          [
            path.join(__dirname, '/../src'),
            path.join(__dirname, '/../test')
          ]
        )
      }
    ]
  },
  resolve: {
    extensions: [ '', '.js', '.jsx', '.json' ],
    alias: {
      actions: srcPath + 'actions/',
      components: srcPath + 'components/',
      sources: srcPath + 'sources/',
      stores: srcPath + 'stores/',
      styles: srcPath + 'styles/',
      config: srcPath + 'config/' + process.env.REACT_WEBPACK_ENV
    }
  },
  externals: {
    'react/lib/ExecutionEnvironment': true,
    'react/addons': true,
    'react/lib/ReactContext': 'window'
  },
  plugins: []
};

Have a look at the externals section, this is required to get it running. Also, make sure you have the json-loader configured the way you see it above. It is needed by cheerio (a dom traversing lib).

As a next step, make sure to have the following packages installed to make enzyme work correctly:

import React from 'react';
import { shallow } from 'enzyme';

import MyComponent from 'components/MyComponent';

describe('<MyComponent />', () => {

  let component;

  beforeEach(() => {
    component = shallow(<MyComponent />);
  });

  describe('when initializing the component', () => {
    it('should do something', () => {
      throw component.html(); // Debug only
    });
  });
});

Hope this helps.

dannymk commented 8 years ago

Much better. Thank you. Configuration in "cfg/test.js" helped.

ZigaVukcevicDev commented 7 years ago

@weblogixx hi,

I am getting following error:

ERROR in ./test/loadtests.js Module build failed: ReferenceError: [BABEL] /my-path/test/loadtests.js: Unknown option: /my-path/node_modules/enzyme/build/index.js.render.

I can provide content from my files, if this will help somehow.

weblogixx commented 7 years ago

Hi @be-codified,

could you please provide a link to a repo (if one exists)? Seems like there are some missing webpack deps (e.g. loaders) or there is something missing in the babel config.

ZigaVukcevicDev commented 7 years ago

Hi @weblogixx thank you for your reply.

Sorry, this is private repo. But I can copy & paste content of files, which ones would you need?

weblogixx commented 7 years ago

Hi @be-codified,

I would need:

I hope this should be enough.

ZigaVukcevicDev commented 7 years ago

Here are the files:

package.json .babelrc defaults.js loadtests.js

If you need anything else, please let me know.

weblogixx commented 7 years ago

Do you also have a config you run in unit test cases (e.g. cfg/test.js)?

weblogixx commented 7 years ago

It should look something like this:

'use strict';

const webpack = require('webpack');
let path = require('path');
let srcPath = path.join(__dirname, '/../src/');

let baseConfig = require('./base');

module.exports = {
  devtool: 'inline-source-map',
  module: {
    loaders: [
      {
        test: /\.(png|jpg|gif|mp4|ogg|svg|woff|woff2|md)$/,
        loader: 'null-loader'
      },
      {
        test: /\.json$/,
        loader: 'json'
      },
      {
        test: /\.(js|jsx)$/,
        loader: 'babel-loader',
        include: [].concat(
          baseConfig.additionalPaths,
          [
            path.join(__dirname, '/../src'),
            path.join(__dirname, '/../test')
          ]
        )
      }
    ]
  },
  resolve: {
    extensions: [ '', '.js', '.jsx', '.json' ],
    alias: {
      actions: srcPath + 'actions/',
      components: srcPath + 'components/',
      sources: srcPath + 'sources/',
      stores: srcPath + 'stores/',
      styles: srcPath + 'styles/',
      config: srcPath + 'config/' + process.env.REACT_WEBPACK_ENV
    }
  },
  externals: {
    cheerio: 'window',
    'react/lib/ExecutionEnvironment': true,
    'react/addons': true,
    'react/lib/ReactContext': true
  },
  plugins: [
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': '"test"'
    })
  ]
};

Note the externals section. You will also have to install the json-loader (npm install --save-dev json-loader). This is needed for cheerio to work.

Maybe this helps?

ZigaVukcevicDev commented 7 years ago

I will take a look.

This is my file:

'use strict';

let path = require('path');
let srcPath = path.join(__dirname, '/../src/');

let baseConfig = require('./base');

// Add needed plugins here
let BowerWebpackPlugin = require('bower-webpack-plugin');

module.exports = {
    devtool: 'eval',
    module: {
        preLoaders: [
            {
                test: /\.(js|jsx)$/,
                loader: 'isparta-instrumenter-loader',
                include: [
                    path.join(__dirname, '/../src')
                ]
            }
        ],
        loaders: [
            {
                test: /\.(png|jpg|gif|woff|woff2|css|sass|scss|less|styl)$/,
                loader: 'null-loader'
            },
            {
                test: /\.json$/,
                loader: 'json'
            },
            {
                test: /\.(js|jsx)$/,
                loader: 'babel-loader',
                query: {
                    presets: [ 'enzyme' ]
                },
                include: [].concat(
                    baseConfig.additionalPaths,
                    [
                        path.join(__dirname, '/../src'),
                        path.join(__dirname, '/../test')
                    ]
                )
            },
            // the url-loader uses DataUrls.
            // the file-loader emits files.
            {test: /\.(woff|woff2)(\?v=\d+\.\d+\.\d+)?$/, loader: 'url?limit=10000&mimetype=application/font-woff'},
            {test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, loader: 'url?limit=10000&mimetype=application/octet-stream'},
            {test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, loader: 'file'},
            {test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: 'url?limit=10000&mimetype=image/svg+xml'}
        ]
    },
    resolve: {
        extensions: [ '', '.js', '.jsx' ],
        alias: {
            actions: srcPath + 'actions/',
            helpers: path.join(__dirname, '/../test/helpers'),
            components: srcPath + 'components/',
            sources: srcPath + 'sources/',
            stores: srcPath + 'stores/',
            styles: srcPath + 'styles/',
            config: srcPath + 'config/' + process.env.REACT_WEBPACK_ENV
        }
    },
    plugins: [
        new BowerWebpackPlugin({
            searchResolveModulesDirectories: false
        })
    ]
};
weblogixx commented 7 years ago

Your extensions should read: extensions: [ '', '.js', '.jsx', '.json' ], not [ '', '.js', '.jsx' ]. Maybe this is all it takes.