Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Karma React Setup (drop these in /tests/karma/ )
module.exports = function(config) {
config.set({
basePath: '../../',
frameworks: ['jasmine', 'jquery-2.1.0'],
plugins: [
'karma-babel-preprocessor',
'karma-jquery',
'karma-jasmine',
'karma-mocha-reporter',
],
autoWatch: true,
reporters: ['mocha'],
// import your files the same as Meteor would, you'll need to tweak these
files: [
'tests/karma/mocks.js',
'tests/karma/node_modules/react/dist/react-with-addons.js',
'both/lib/namespaces.js',
'tests/karma/spec_helper.js',
'**/*Mixin.jsx',
'both/components/**/*.jsx',
'both/pages/**/*.jsx',
'**/*_spec.js',
],
preprocessors: {
'**/*.jsx': ['babel'],
'**/*_spec.js': ['babel']
},
babelPreprocessor: {
options: {
sourceMap: 'inline',
whitelist: [
"react",
"flow",
'es3.propertyLiterals',
'es3.memberExpressionLiterals',
'es6.arrowFunctions',
'es6.templateLiterals',
'es6.classes',
'es6.blockScoping',
"es6.properties.shorthand",
"es6.properties.computed",
"es6.parameters.rest",
"es6.parameters.default",
"es6.spread",
"es6.destructuring",
"es6.constants",
"es7.objectRestSpread",
'es7.trailingFunctionCommas',
]
},
filename: function (file) {
return file.originalPath.replace(/\.js$/, '.es5.js');
},
sourceFileName: function (file) {
return file.originalPath;
}
}
});
};
ReactMeteor = {
Mixin: {}
};
Meteor = {
_reload: {
onMigrate: function() { }
}
}
FlowRouter = {
route: function() {
}
};
log = function() {};
ReactMeteorData = {};
{
"name": "karma-unit-tests",
"version": "1.0.0",
"description": "Tests for React",
"scripts": {
"test": "./node_modules/karma/bin/karma start"
},
"devDependencies": {
"jasmine-core": "^2.3.4",
"karma": "^0.12.36",
"karma-babel-preprocessor": "^5.2.1",
"karma-chrome-launcher": "^0.1.12",
"karma-jasmine": "^0.3.5",
"karma-jquery": "^0.1.0",
"karma-mocha-reporter": "^1.0.2",
"react": "^0.13.3"
}
}
# typing reactunit + tab will scaffold out this:
snippet reactunit "React Unit Test" !b
/*global $1, renderComponent */
describe("$1 Component", function() {
var defProps, renderWithProps, component, el, $el;
beforeEach(() => {
defProps = {
label: 'Check me',
};
renderWithProps = function(props) {
component = renderComponent($1, props);
el = React.findDOMNode(component);
$el = $(el);
};
renderWithProps(defProps);
});
it("should be mounted in DOM", () => {
expect($el.length).toEqual(1);
});
});
endsnippet
TestUtils = React.addons.TestUtils;
Simulate = TestUtils.Simulate;
renderComponent = function (comp, props) {
return TestUtils.renderIntoDocument(
React.createElement(comp, props)
);
};
simulateClickOn = function(selector) {
var button = this.$el.find(selector)[0];
console.log(button);
React.addons.TestUtils.Simulate.click(button);
}
var spies = [],
componentStubs = [],
renderedComponents = [];
jasmineReact = {
render: function(component, container, callback){
if(typeof container === "undefined"){
container = this.getDefaultContainer();
}
var comp = (typeof callback === "undefined") ?
React.render(component, container) :
React.render(component, container, callback);
// keep track of the components we render, so we can unmount them later
renderedComponents.push(comp);
return comp;
},
spyOnClass: function(klass, methodName){
var klassProto = this.classPrototype(klass),
original = klassProto[methodName],
jasmineSpy = spyOn(klassProto, methodName);
// keep track of the spies, so we can clean up the __reactAutoBindMap later
// (Jasmine 2.1)
spies.push({
spy: jasmineSpy,
baseObj: klassProto,
methodName: methodName,
originalValue: original
});
// react.js will autobind `this` to the correct value and it caches that
// result on a __reactAutoBindMap for performance reasons.
if(klassProto.__reactAutoBindMap){
klassProto.__reactAutoBindMap[methodName] = jasmineSpy;
}
return jasmineSpy;
},
classComponentConstructor: function(klass){
return klass.type || // React 0.11.1
klass.componentConstructor; // React 0.8.0
},
classPrototype: function(klass){
var componentConstructor = this.classComponentConstructor(klass);
if(typeof componentConstructor === "undefined"){
throw("A component constructor could not be found for this class. Are you sure you passed in a the component definition for a React component?");
}
return componentConstructor.prototype;
},
createStubComponent: function(obj, propertyName){
// keep track of the components we stub, so we can swap them back later
componentStubs.push({obj: obj, propertyName: propertyName, originalValue: obj[propertyName]});
return obj[propertyName] = React.createClass({
render: function(){
return React.DOM.div();
}
});
},
addMethodToClass: function(klass, methodName, methodDefinition){
if(typeof methodDefinition === "undefined"){
methodDefinition = function(){};
}
this.classPrototype(klass)[methodName] = methodDefinition;
return klass;
},
resetComponentStubs: function(){
for (var i = 0; i < componentStubs.length; i++) {
var stub = componentStubs[i];
stub.obj[stub.propertyName] = stub.originalValue;
}
componentStubs = [];
},
removeAllSpies: function(){
for (var i = 0; i < spies.length; i++) {
var spy = spies[i];
if(spy.baseObj.__reactAutoBindMap){
spy.baseObj.__reactAutoBindMap[spy.methodName] = spy.originalValue;
}
spy.baseObj[spy.methodName] = spy.originalValue;
}
spies = [];
},
unmountAllRenderedComponents: function(){
for (var i = 0; i < renderedComponents.length; i++) {
var renderedComponent = renderedComponents[i];
this.unmountComponent(renderedComponent);
}
renderedComponents = [];
},
unmountComponent: function(component){
if(component.isMounted()){
return React.unmountComponentAtNode(component.getDOMNode().parentNode);
} else {
return false;
}
},
getDefaultContainer: function(){
return document.getElementById("jasmine_content");
}
};
// backwards compatability for React < 0.12
jasmineReact.renderComponent = jasmineReact.render;
// TODO: this has no automated test coverage. Add some integration tests for coverage.
afterEach(function(){
jasmineReact.removeAllSpies();
jasmineReact.resetComponentStubs();
jasmineReact.unmountAllRenderedComponents();
});
beforeEach(function() {
jasmine.addMatchers({
// jQuery selector element exists
toExist: function () {
return {
compare: function (actual) {
return { pass: $(actual).length };
}
};
}
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment