Skip to content

Karma + Jasmine test runner #38

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Oct 7, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"stage": 0,
"plugins": [
"react-transform"
],
"extra": {
"react-transform": [{
"target": "react-transform-webpack-hmr",
"imports": ["react"],
// this is important for Webpack HMR:
"locals": ["module"]
},
{
"target": "react-transform-catch-errors",
// the second import is the React component to render error
// (it can be a local path too, like "./src/ErrorReporter")
"imports": ["react", "redbox-react"]
}]
}
}
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
# meteor-webpack-react

THis is a Meteor project skeleton where the client (in React) and server get built by Webpack. In dev mode,
webpack-dev-server is used with react-hot-loader. There are a bunch of run and build scripts to make things more
webpack-dev-server is used with [react-transform](https://github.com/gaearon/babel-plugin-react-transform). There are a bunch of run and build scripts to make things more
convenient.

There is a port of the Meteor simple-todos tutorial to this stack on the `simple-todos` branch.

## Advantages of packaging with Webpack instead of Meteor

* `require`/ES6 `import` let you avoid Meteor global variables/load order issues
* `react-hot-loader` reloads React components without reloading the entire page
* `react-transform` reloads React components without reloading the entire page
when you make changes
* If you `require` your styles with Webpack, it will also reload them without
reloading the entire page when you make changes to them
Expand Down Expand Up @@ -39,10 +39,10 @@ In dev mode, both `webpack-dev-server` and `meteor_core` run simultaneously on d

This is where it gets tricky, but there is an experimental solution in the `react-commons` branch.

`react-hot-loader` requires many internal React modules, thus it doesn't work with components
`react-transform` requires many internal React modules, thus it doesn't work with components
created by an instance of React loaded from `react-runtime-dev`.

But if React is loaded by Webpack, then the the modules required by `react-hot-loader`
But if React is loaded by Webpack, then the the modules required by `react-transform`
will be the same as in that instance of React.

This poses a problem if you want to use any Meteor packages that depend on the `react` package,
Expand Down Expand Up @@ -107,9 +107,9 @@ Put your settings in `settings/devel.json` & `settings/prod.json` and they will

## Running Meteor Commands

As a convenince you can run `./met` in the root directory to run the `meteor` command. However you can still `cd meteor_core` and then run `meteor` from that directory as well.
As a convenience you can run `./met` in the root directory to run the `meteor` command. However you can still `cd meteor_core` and then run `meteor` from that directory as well.

```
./met --version
./met search moment
```
./met search simple-schema
```
74 changes: 74 additions & 0 deletions app/components/tests/app_spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// See this for some tips with Meteor: https://medium.com/all-about-meteorjs/unit-test-react-components-in-meteor-a19d96684d7d

// If you import ../App you'll have to stub out Meteor, this is
// why it's important to use controller-views that just setup
// data and then the children can be very easily tested with
// just props and state. We'll use a local component for an example

import React from 'react/addons';
//import App from '../App';
//import $ from 'jquery'; // you could use jq to make life easier
const TestUtils = React.addons.TestUtils;
const Simulate = TestUtils.Simulate;

// these should go into a spec helper module

function renderComponent(comp, props) {
return TestUtils.renderIntoDocument(
React.createElement(comp, props)
);
}

function simulateClickOn(selector) {
var button = this.$el.find(selector)[0];
React.addons.TestUtils.Simulate.click(button);
}


const Post = React.createClass({
getDefaultProps() {
return {title: "Default Post Name"};
},
getInitialState() {
return { isVisible: true };
},
handleHide() {
this.setState({isVisible: false});
},
render() {
let visibleClass = (this.state.isVisible) ? 'block' : 'hidden';
return (
<div className='Post' style={{display: visibleClass }}>
<h1>{this.props.title}</h1>
<article>
How now brown cow
</article>
<button onClick={this.handleHide}>Hide</button>
</div>
);
}
});

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, any way we could make the test have something to do with what's actually in the App stub instead of this?


describe('Sample post component', () => {
it('renders default post name without props', () => {
let comp = renderComponent(Post, {});
expect(comp.props.title).toEqual('Default Post Name');
});

it('renders correct post name with a name prop', () => {
let comp = renderComponent(Post, {title: "Webpack is awesome!"});
expect(comp.props.title).toEqual("Webpack is awesome!");
});

it("should have a default state of visible", () => {
let comp = renderComponent(Post, {});
expect(comp.state.isVisible).toEqual(true);
});

it("should hide when hide button is clicked", () => {
let comp = renderComponent(Post, {});
comp.handleHide();
expect(comp.state.isVisible).toEqual(false);
});
});
37 changes: 37 additions & 0 deletions karma.conf.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
var path = require('path');
var webpackConfig = require('./webpack/webpack.config.client.js');

module.exports = function (config) {
config.set({
//singleRun: true,
reporters: [ 'dots' ],
browsers: [ 'Chrome' ],
files: [ './test/karma.bundle.js' ],
frameworks: [ 'jasmine' ],
plugins: [
'karma-chrome-launcher',
//'karma-firefox-launcher',
'karma-jasmine',
//'karma-mocha',
'karma-sourcemap-loader',
'karma-webpack',
],
// run the bundle through the webpack and sourcemap plugins
preprocessors: {
'./test/karma.bundle.js': [ 'webpack', 'sourcemap' ]
},
// use our own webpack config to mirror test setup
webpack: {
entry: [
'./lib/core-js-no-number',
'regenerator/runtime',
],
devtool: 'eval-source-map',
resolve: webpackConfig.resolve,
module: { loaders: webpackConfig.module.loaders },
},
webpackMiddleware: {
noInfo: true,
}
});
};
10 changes: 9 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,21 @@
"devDependencies": {
"babel-eslint": "^4.0.5",
"babel-loader": "^5.1.2",
"babel-plugin-react-transform": "^1.0.3",
"css-loader": "^0.15.3",
"eslint-config-airbnb": "0.0.7",
"eslint-plugin-react": "^3.2.2",
"grunt": "^0.4.5",
"grunt-cli": "^0.1.13",
"karma": "^0.13.9",
"karma-chrome-launcher": "^0.2.0",
"karma-jasmine": "^0.2.2",
"karma-sourcemap-loader": "^0.3.5",
"karma-webpack": "^1.7.0",
"node-libs-browser": "^0.5.2",
"react-hot-loader": "^1.2.7",
"react-transform-catch-errors": "^0.1.1",
"react-transform-webpack-hmr": "^0.1.4",
"redbox-react": "^1.0.1",
"style-loader": "^0.12.3",
"webpack": "^1.10.1",
"webpack-dev-server": "^1.10.1"
Expand Down
4 changes: 4 additions & 0 deletions test/karma.bundle.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// require all foo_spec.js, bar_spec.jsx files in the app directory
var context = require.context('../app', true, /.+_spec\.jsx?$/);
context.keys().forEach(context);
module.exports = context;
12 changes: 0 additions & 12 deletions webpack/webpack.config.client.dev.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
var webpack = require('webpack');
var config = require('./webpack.config.client');
var _ = require('lodash');

var devProps = require('./devProps');

var config = module.exports = _.assign(_.cloneDeep(config), {
Expand Down Expand Up @@ -31,14 +30,3 @@ var config = module.exports = _.assign(_.cloneDeep(config), {
port: devProps.webpackPort,
}
});

// inject react-hot loader

var jsLoader = _.find(config.module.loaders, function(loader) {
return loader.test.test('.js');
});

if (jsLoader) {
jsLoader.loader = 'react-hot!' + jsLoader.loader;
}

2 changes: 1 addition & 1 deletion webpack/webpack.config.client.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ module.exports = {
loaders: [
{
test: /\.jsx?$/,
loader: 'babel?stage=0',
loader: 'babel',
exclude: /node_modules|lib/,
},
{
Expand Down