Skip to content

Commit 68e7a32

Browse files
author
vinogradov
committed
1) add Jest+Webpack infrastructure, 2) refactor eslint: migrate to airbnb config, add special eslint config for tests
1 parent 53a8d52 commit 68e7a32

22 files changed

+731
-739
lines changed

.babelrc

+16-14
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
11
{
2-
"presets": [
3-
[
4-
"es2015",
5-
{
6-
"modules": false
7-
}
8-
],
9-
"es2016",
10-
"es2017",
11-
"react"
2+
"presets": [
3+
[
4+
"es2015", {"modules": false}
125
],
13-
"plugins": [
14-
"transform-object-rest-spread"
15-
]
16-
}
6+
"es2016",
7+
"es2017",
8+
"react"
9+
],
10+
"plugins": [
11+
"transform-object-rest-spread"
12+
],
13+
"env": {
14+
"test": {
15+
"plugins": ["transform-es2015-modules-commonjs"]
16+
}
17+
}
18+
}

.editorconfig

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[*]
22
end_of_line = lf
3-
insert_final_newline = false
3+
insert_final_newline = true
44
indent_style = space
5-
indent_size = 4
5+
indent_size = 2

.eslintignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
dist
2+
__tests__

.eslintrc-test.js

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
module.exports = {
2+
extends: [
3+
'./.eslintrc.js',
4+
'plugin:jest/recommended'
5+
],
6+
plugins: [
7+
'jest'
8+
],
9+
env: {
10+
jest: true
11+
},
12+
rules: {
13+
'no-magic-numbers': ['off']
14+
}
15+
};

.eslintrc.js

+11-178
Original file line numberDiff line numberDiff line change
@@ -1,179 +1,12 @@
11
module.exports = {
2-
'parserOptions': {
3-
'ecmaVersion': 8,
4-
'sourceType': 'module',
5-
'ecmaFeatures': {
6-
'jsx': true,
7-
'experimentalObjectRestSpread': true
8-
}
9-
},
10-
'rules': {
11-
// Possible Errors (http://eslint.org/docs/rules/#possible-errors):
12-
'valid-jsdoc': ['warn', {
13-
'prefer': {
14-
'return': 'returns'
15-
}
16-
}],
17-
18-
19-
// Best Practices (http://eslint.org/docs/rules/#best-practices):
20-
'consistent-return': ['warn'],
21-
'curly': ['warn'],
22-
'dot-location': ['warn', 'property'],
23-
'dot-notation': ['warn'],
24-
'eqeqeq': ['warn'],
25-
'no-alert': ['warn'],
26-
'no-caller': ['warn'],
27-
'no-else-return': ['warn'],
28-
'no-empty-function': ['warn'],
29-
'no-empty-pattern': ['warn'],
30-
'no-eq-null': ['warn'],
31-
'no-eval': ['warn'],
32-
'no-extend-native': ['warn'],
33-
'no-extra-bind': ['warn'],
34-
'no-extra-label': ['warn'],
35-
'no-fallthrough': ['warn'],
36-
'no-floating-decimal': ['warn'],
37-
'no-implicit-coercion': ['warn', {
38-
'boolean': false
39-
}],
40-
'no-implicit-globals': ['warn'],
41-
'no-implied-eval': ['warn'],
42-
'no-invalid-this': ['warn'],
43-
'no-iterator': ['warn'],
44-
'no-labels': ['warn'],
45-
'no-lone-blocks': ['warn'],
46-
'no-loop-func': ['warn'],
47-
'no-magic-numbers': ['warn'],
48-
'no-multi-spaces': ['warn'],
49-
'no-native-reassign': ['warn'],
50-
'no-new-func': ['warn'],
51-
'no-new-wrappers': ['warn'],
52-
'no-proto': ['warn'],
53-
'no-redeclare': ['warn'],
54-
'no-return-assign': ['warn'],
55-
'no-script-url': ['warn'],
56-
'no-self-assign': ['warn'],
57-
'no-self-compare': ['warn'],
58-
'no-sequences': ['warn'],
59-
'no-unmodified-loop-condition': ['warn'],
60-
'no-unused-expressions': ['warn'],
61-
'no-unused-labels': ['warn'],
62-
'no-useless-call': ['warn'],
63-
'no-useless-concat': ['warn'],
64-
'no-useless-escape': ['warn'],
65-
'no-with': ['warn'],
66-
'require-await': ['warn'],
67-
'wrap-iife': ['warn'],
68-
'yoda': ['warn'],
69-
70-
71-
// Strict Mode (http://eslint.org/docs/rules/#strict-mode):
72-
'strict': ['warn'],
73-
74-
75-
// Variables (http://eslint.org/docs/rules/#variables):
76-
'no-catch-shadow': ['warn'],
77-
'no-delete-var': ['warn'],
78-
'no-label-var': ['warn'],
79-
'no-shadow': ['warn'],
80-
'no-shadow-restricted-names': ['warn'],
81-
'no-undef-init': ['warn'],
82-
'no-use-before-define': ['warn'],
83-
84-
85-
// Node.js and CommonJS (http://eslint.org/docs/rules/#nodejs-and-commonjs):
86-
'global-require': ['warn'],
87-
'no-mixed-requires': ['warn'],
88-
'no-path-concat': ['warn'],
89-
'no-sync': ['warn'],
90-
91-
92-
// Stylistic Issues (http://eslint.org/docs/rules/#stylistic-issues):
93-
'array-bracket-spacing': ['warn'],
94-
'block-spacing': ['warn'],
95-
'brace-style': ['warn', '1tbs', {'allowSingleLine': true}],
96-
'camelcase': ['warn', {'properties': 'never'}],
97-
'comma-dangle': ['warn', 'never'],
98-
'comma-spacing': ['warn', {'before': false, 'after': true}],
99-
'comma-style': ['warn', 'last'],
100-
'computed-property-spacing': ['warn', 'never'],
101-
'consistent-this': ['warn', 'that'],
102-
'func-style': ['warn', 'declaration'],
103-
'indent': ['warn', 4, {'SwitchCase': 1}],
104-
'key-spacing': ['warn'],
105-
'keyword-spacing': ['warn'],
106-
'linebreak-style': ['warn', 'unix'],
107-
'max-depth': ['warn', 10],
108-
'max-len': ['warn', {'code': 140, 'ignoreUrls': true}],
109-
'max-nested-callbacks': ['warn', 5],
110-
'max-params': ['warn', 5],
111-
'max-statements-per-line': ['warn', {'max': 10}],
112-
'new-cap': ['warn'],
113-
'new-parens': ['warn'],
114-
'no-lonely-if': ['warn'],
115-
'no-mixed-spaces-and-tabs': ['warn'],
116-
'no-nested-ternary': ['warn'],
117-
'no-new-object': ['warn'],
118-
'no-spaced-func': ['warn'],
119-
'no-trailing-spaces': ['warn'],
120-
'no-underscore-dangle': ['warn', {'allowAfterThis': true}],
121-
'no-unneeded-ternary': ['warn'],
122-
'no-whitespace-before-property': ['warn'],
123-
'object-curly-spacing': ['warn', 'never'],
124-
'one-var-declaration-per-line': ['warn'],
125-
'operator-assignment': ['warn'],
126-
'operator-linebreak': ['warn', 'after'],
127-
'padded-blocks': ['warn', {'blocks': 'never', 'switches': 'never', 'classes': 'never'}],
128-
'quote-props': ['warn', 'as-needed'],
129-
'quotes': ['warn', 'single'],
130-
'semi': ['warn', 'always'],
131-
'semi-spacing': ['warn', {'before': false, 'after': true}],
132-
'space-before-blocks': ['warn'],
133-
'space-before-function-paren': ['warn', 'never'],
134-
'space-in-parens': ['warn', 'never'],
135-
'space-infix-ops': ['warn'],
136-
'space-unary-ops': ['warn', {'words': true, 'nonwords': false}],
137-
'spaced-comment': ['warn', 'always'],
138-
139-
140-
// ECMAScript2015 (http://eslint.org/docs/rules/#ecmascript-6):
141-
'arrow-body-style': ['warn', 'as-needed'],
142-
'arrow-parens': ['warn'],
143-
'arrow-spacing': ['warn', {'before': true, 'after': true}],
144-
'constructor-super': ['warn'],
145-
146-
'generator-star-spacing': ['warn', {'before': true, 'after': true}],
147-
'yield-star-spacing': ['warn', {'before': true, 'after': true}],
148-
149-
'no-class-assign': ['warn'],
150-
'no-confusing-arrow': ['warn', {'allowParens': true}],
151-
'no-const-assign': ['warn'],
152-
'no-dupe-class-members': ['warn'],
153-
'no-duplicate-imports': ['warn'],
154-
'no-new-symbol': ['warn'],
155-
'no-this-before-super': ['warn'],
156-
'no-useless-constructor': ['warn'],
157-
'no-var': ['warn'],
158-
'object-shorthand': ['warn', 'always'],
159-
'prefer-arrow-callback': ['warn'],
160-
'prefer-const': ['warn'],
161-
'prefer-reflect': ['warn'],
162-
'prefer-rest-params': ['warn'],
163-
'prefer-spread': ['warn'],
164-
'prefer-template': ['warn'],
165-
'require-yield': ['warn'],
166-
'template-curly-spacing': ['warn', 'never']
167-
},
168-
'env': {
169-
'browser': true,
170-
'commonjs': true
171-
},
172-
'extends': [
173-
'eslint:recommended',
174-
'plugin:react/recommended'
175-
],
176-
'plugins': [
177-
'react'
178-
]
179-
};
2+
rules: {
3+
'object-curly-spacing': ['warn', 'never'],
4+
'comma-dangle': ['warn', 'never'],
5+
'max-len': ['warn', 120],
6+
'react/jsx-filename-extension': ['off']
7+
},
8+
env: {
9+
browser: true
10+
},
11+
extends: 'airbnb'
12+
};

README.md

+8-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
Includes only the latest and greatest web technologies. Use it for your next heroic SPA project because you can't go wrong with it. Contains minimal viable "hello, world" code just to proof it works. Remove hello world and write your own great project.
22

3+
# Principles
4+
1. Use plain ES2015/16/17. Minimize use of experimental Stage-* Javascript features
5+
1. Use tests (by [jest](https://github.com/facebook/jest))
6+
1. Use linting (by [airbnb eslint config](https://github.com/airbnb/javascript))
7+
38
Suitable for:
49
1. Education
5-
2. Small pet projects/protorypes
6-
3. Production
10+
1. Small pet projects/protorypes
11+
1. Production
712

813
# 🎁 What’s Inside?
914

@@ -43,4 +48,4 @@ If you have problems with running it please [file an issue](https://github.com/v
4348
# Examples
4449

4550
1. [examples/react](https://github.com/vinogradov/react-starter-kit/tree/master/src/examples/react) - trivial hello world using React
46-
1. [examples/redux](https://github.com/vinogradov/react-starter-kit/tree/master/src/examples/redux) - counter example with `redux` and `redux-saga`
51+
1. [examples/redux](https://github.com/vinogradov/react-starter-kit/tree/master/src/examples/redux) - counter example with `redux` and `redux-saga`

__mocks__/fileMock.js

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module.exports = 'path-to-file';

__mocks__/styleMock.js

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module.exports = {};

package.json

+20-8
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,13 @@
66
"scripts": {
77
"start": "webpack-dev-server",
88
"dist": "webpack --display-error-details --env.dist",
9-
"test": "echo \"Error: no test specified\" && exit 1"
9+
"test": "jest src",
10+
"lint": "eslint .; eslint --no-ignore --config .eslintrc.js --config .eslintrc-test.js --ext test.js ."
1011
},
1112
"license": "MIT",
1213
"dependencies": {
1314
"babel-core": "6.24.1",
14-
"babel-jest": "19.0.0",
15+
"babel-jest": "20.0.1",
1516
"babel-loader": "7.0.0",
1617
"babel-plugin-transform-object-rest-spread": "6.23.0",
1718
"babel-preset-es2015": "6.24.1",
@@ -21,31 +22,42 @@
2122
"clean-webpack-plugin": "0.1.16",
2223
"css-loader": "0.28.1",
2324
"eslint": "3.19.0",
25+
"eslint-config-airbnb": "14.1.0",
2426
"eslint-loader": "1.7.1",
25-
"eslint-plugin-react": "6.10.3",
27+
"eslint-plugin-import": "2.2.0",
28+
"eslint-plugin-jest": "20.0.1",
29+
"eslint-plugin-jsx-a11y": "4.0.0",
30+
"eslint-plugin-react": "7.0.1",
2631
"extract-text-webpack-plugin": "2.1.0",
2732
"file-loader": "0.11.1",
2833
"html-webpack-plugin": "2.28.0",
2934
"isomorphic-fetch": "2.2.1",
30-
"jest": "19.0.2",
35+
"jest": "20.0.1",
3136
"node-sass": "4.5.2",
32-
"prop-types": "15.5.8",
37+
"prop-types": "15.5.10",
3338
"react": "15.5.4",
3439
"react-dom": "15.5.4",
3540
"react-redux": "5.0.4",
3641
"react-router-dom": "4.1.1",
42+
"react-test-renderer": "15.5.4",
3743
"redux": "3.6.0",
3844
"redux-logger": "3.0.1",
39-
"redux-saga": "0.15.1",
45+
"redux-saga": "0.15.3",
4046
"redux-thunk": "2.2.0",
41-
"sass-loader": "6.0.3",
47+
"sass-loader": "6.0.5",
4248
"style-loader": "0.17.0",
43-
"webpack": "2.5.0"
49+
"webpack": "2.5.1"
4450
},
4551
"devDependencies": {
4652
"webpack-dev-server": "2.4.5"
4753
},
4854
"engines": {
4955
"node": ">=7.5.0"
56+
},
57+
"jest": {
58+
"moduleNameMapper": {
59+
"\\.(scss)$": "<rootDir>/__mocks__/styleMock.js",
60+
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|ico)$": "<rootDir>/__mocks__/fileMock.js"
61+
}
5062
}
5163
}

src/entry.js

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1+
/* eslint-disable */
12
import 'file-loader?name=[name].[ext]!./favicon.ico';
3+
/* eslint-enable */
24

3-
import './examples/react';
4-
// import './examples/redux';
5-
5+
// import './examples/react/index';
6+
import './examples/redux';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`renders correctly 1`] = `
4+
<div
5+
className="hello-message"
6+
>
7+
<div>
8+
Hello
9+
<span
10+
className="name"
11+
>
12+
John
13+
</span>
14+
</div>
15+
<button
16+
onClick={[Function]}
17+
>
18+
toggle:
19+
ON
20+
</button>
21+
</div>
22+
`;
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import * as React from 'react';
2+
import renderer from 'react-test-renderer';
3+
import Hello from '../hello';
4+
5+
test('renders correctly', () => {
6+
const tree = renderer.create(
7+
<Hello name="John" />
8+
).toJSON();
9+
10+
expect(tree).toMatchSnapshot();
11+
});

0 commit comments

Comments
 (0)