Skip to content

Instantly share code, notes, and snippets.

@jmreidy
Last active January 9, 2018 11:49
Show Gist options
  • Save jmreidy/4145809229195441d4d4 to your computer and use it in GitHub Desktop.
Save jmreidy/4145809229195441d4d4 to your computer and use it in GitHub Desktop.
Unit test React Native with Mocha
--compilers js:./test/support/compiler
--require ./test/support/init
/* eslint-env node, mocha */
import NoteEntryScreen from '../src/containers/screens/NoteEntryScreen';
import common from './support/common';
const {createRenderer, React, expect, MockComponents} = common;
function setup() {
const props = {};
const renderer = createRenderer();
renderer.render(<NoteEntryScreen {...props} />);
const output = renderer.getRenderOutput();
return {
props,
output,
renderer,
};
}
describe('NoteEntryScreen', () => {
it('should render a scrollview', () => {
const { output } = setup();
expect(output.type.displayName).to.equal(MockComponents.ScrollView.displayName);
});
});
import chai from 'chai';
import chaiAsPromised from 'chai-as-promised';
import React from 'react';
import ReactTestUtils from 'react-addons-test-utils';
import {MockComponents} from './mocks/react-native';
chai.use(chaiAsPromised);
export default {
expect: chai.expect,
createRenderer: ReactTestUtils.createRenderer,
React,
MockComponents,
};
var fs = require('fs');
var path = require('path');
var babel = require('babel-core');
var origJs = require.extensions['.js'];
require.extensions['.js'] = function (module, fileName) {
var output;
if (fileName === '/app/node_modules/react-native/Libraries/react-native/react-native.js') {
fileName = path.resolve('./test/support/mocks/react-native.js');
}
if (fileName.indexOf('node_modules/') >= 0) {
return (origJs || require.extensions['.js'])(module, fileName);
}
var src = fs.readFileSync(fileName, 'utf8');
output = babel.transform(src, {
filename: fileName,
sourceFileName: fileName,
//keep below in sync with babelrc
"retainLines": true,
"compact": true,
"comments": false,
"plugins": [
"syntax-async-functions",
"syntax-class-properties",
"syntax-trailing-function-commas",
"transform-es2015-arrow-functions",
"transform-es2015-block-scoping",
"transform-es2015-classes",
"transform-es2015-computed-properties",
"transform-es2015-constants",
"transform-es2015-destructuring",
["transform-es2015-modules-commonjs", {"strict": false, "allowTopLevelThis": true}],
"transform-es2015-parameters",
"transform-es2015-shorthand-properties",
"transform-es2015-spread",
"transform-es2015-template-literals",
"transform-class-properties",
"transform-flow-strip-types",
"transform-object-assign",
"transform-object-rest-spread",
"transform-react-display-name",
"transform-react-jsx",
"transform-regenerator"
],
"sourceMaps": false
}).code;
return module._compile(output, fileName);
};
import React from 'react';
function mockComponent(type) {
const Component = React.createClass({
displayName: type,
propTypes: { children: React.PropTypes.node },
render() { return React.createElement(React.DOM.div, this.props, this.props.children); },
});
return Component;
}
const componentsToMock = [
'View',
'Text',
'Component',
'ScrollView',
'TextInput',
];
export const MockComponents = componentsToMock.reduce((agg, type) => {
agg[type] = mockComponent(type);
return agg;
}, {});
export default {
...React,
...MockComponents,
StyleSheet: {
create: (ss) => ss,
},
PropTypes: React.PropTypes,
};
@jrichardlai
Copy link

@Andrewpk you want to make sure the path is correct in compiler.js I replaced it with fileName.match('/node_modules/react-native/Libraries/react-native/react-native.js')

@miquelbeltran
Copy link

Hi @jmreidy, any change you can upload a full repo with the working example? I am following your code examples but I am stuck with an issue I don't know how to solve when running mocha.

I'll leave here the error stack trace just in case you have any idea. Many thanks in advance!

 mocha
/home/miquel/dev/github/react-app-test-2/AppTest2/app/scroller-item.js:1
(function (exports, require, module, __filename, __dirname) { 'use strict';Object.defineProperty(exports,"__esModule",{value:true});var _createClass=function(){function defineProperties(target,props){for(var i=0;i<props.length;i++){var descriptor=props[i];descriptor.enumerable=descriptor.enumerable||false;descriptor.configurable=true;if("value" in descriptor)descriptor.writable=true;Object.defineProperty(target,descriptor.key,descriptor);}}return function(Constructor,protoProps,staticProps){if(protoProps)defineProperties(Constructor.prototype,protoProps);if(staticProps)defineProperties(Constructor,staticProps);return Constructor;};}();var _reactNative=require('react-native');var _reactNative2=_interopRequireDefault(_reactNative);function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj};}function _classCallCheck(instance,Constructor){if(!(instance instanceof Constructor)){throw new TypeError("Cannot call a class 

TypeError: Super expression must either be null or a function, not undefined
    at _inherits (/home/miquel/dev/github/react-app-test-2/AppTest2/app/scroller-item.js:1:1287)
    at /home/miquel/dev/github/react-app-test-2/AppTest2/app/scroller-item.js:11:35
    at Object.<anonymous> (/home/miquel/dev/github/react-app-test-2/AppTest2/app/scroller-item.js:21:75)
    at Module._compile (module.js:413:34)
    at Object.require.extensions..js (/home/miquel/dev/github/react-app-test-2/AppTest2/test/support/compiler.js:51:17)
    at Module.load (module.js:357:32)
    at Function.Module._load (module.js:314:12)
    at Module.require (module.js:367:17)
    at require (internal/module.js:16:19)
    at Object.<anonymous> (/home/miquel/dev/github/react-app-test-2/AppTest2/test/scroller.test.js:1:81)
    at Module._compile (module.js:413:34)
    at Object.require.extensions..js (/home/miquel/dev/github/react-app-test-2/AppTest2/test/support/compiler.js:51:17)
    at Module.load (module.js:357:32)
    at Function.Module._load (module.js:314:12)
    at Module.require (module.js:367:17)
    at require (internal/module.js:16:19)
    at /usr/lib/node_modules/mocha/lib/mocha.js:219:27
    at Array.forEach (native)
    at Mocha.loadFiles (/usr/lib/node_modules/mocha/lib/mocha.js:216:14)
    at Mocha.run (/usr/lib/node_modules/mocha/lib/mocha.js:468:10)
    at Object.<anonymous> (/usr/lib/node_modules/mocha/bin/_mocha:403:18)
    at Module._compile (module.js:413:34)
    at Object.Module._extensions..js (module.js:422:10)
    at Module.load (module.js:357:32)
    at Function.Module._load (module.js:314:12)
    at Function.Module.runMain (module.js:447:10)
    at startup (node.js:141:18)
    at node.js:933:3

@larubbio
Copy link

@miquelbeltran I'm running into the same issue you are. Also is there anyway to use the existing .bablerc instead of duplicating it in code?

@larubbio
Copy link

@miquelbeltran I had to modify the mock to get passed the TypeError

var ReactNative = {
  ...React,
  ...MockComponents,
  StyleSheet: {
    create: (ss) => ss,
  },
  PropTypes: React.PropTypes,
};

module.exports = ReactNative;

I think the error had to do with Component not being defined so when babel tried to transpile a module that extends it you get the error. We might be on a new version of some package that requires the different export syntax.

http://stackoverflow.com/questions/30116430/reactjs-giving-error-uncaught-typeerror-super-expression-must-either-be-null-or

I've also had to add mocks for at least one other module (react-native-router-flux) to get my tests to "run".

@sstur
Copy link

sstur commented Mar 2, 2016

I also got this working with some effort and modifications to the above files. Will post my solution...

@cornedor
Copy link

You could use the react-native preset so you won't have to keep the transforms in sync
https://gist.github.com/cornedor/37ab65a3a505797b01c2e78156d5cf12/revisions

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment