Enable linting on whole src dir, fix linting errors

Update .eslintrc with additional rules, fix linting errors
This commit is contained in:
Jiri Tomasek 2015-09-25 10:24:03 +02:00
parent b05e933bce
commit 415b9b9628
19 changed files with 152 additions and 149 deletions

109
.eslintrc
View File

@ -1,58 +1,55 @@
{
"rules": {
"indent": [
2,
2
],
"quotes": [
2,
"single"
],
"linebreak-style": [
2,
"unix"
],
"semi": [
2,
"always"
],
"strict": 0,
"react/display-name": [1, { "acceptTranspilerName": true }],
"react/jsx-boolean-value": [1, "never"],
"react/jsx-curly-spacing": [1, "never"],
"react/jsx-no-duplicate-props": 1,
"react/jsx-no-undef": 1,
"react/jsx-quotes": 1,
"react/jsx-sort-prop-types": 1,
"react/jsx-sort-props": 0,
"react/jsx-uses-react": 1,
"react/jsx-uses-vars": 1,
"react/no-danger": 1,
"react/no-did-mount-set-state": 1,
"react/no-did-update-set-state": 1,
"react/no-multi-comp": 0, // reconsider this later
"react/no-unknown-property": 1,
"react/prop-types": 1,
"react/react-in-jsx-scope": 1,
"react/require-extension": 1,
"react/self-closing-comp": 1,
"react/sort-comp": 1,
"react/wrap-multilines": 1
},
"env": {
"es6": true,
"browser": true,
"jasmine": true,
'node': true,
"jest": true
},
"extends": "eslint:recommended",
"ecmaFeatures": {
"jsx": true,
"experimentalObjectRestSpread": true
},
"plugins": [
"react"
],
"parser": "babel-eslint"
"rules": {
"default-case": 0,
"indent": [ 2, 2 ],
"linebreak-style": [ 2, "unix" ],
"max-len": [1, 100, 2, { "ignoreComments": true }],
"no-cond-assign": [2, "except-parens"],
"no-else-return": 0,
"no-param-reassign": 0,
"no-unused-vars": [1, {"vars": "local", "args": "none"}],
"quotes": [ 2, "single" ],
"quote-props": [1, "consistent-as-needed"],
"radix": 0,
"react/display-name": [1, { "acceptTranspilerName": true }],
"react/jsx-boolean-value": [1, "never"],
"react/jsx-curly-spacing": [1, "never"],
"react/jsx-no-duplicate-props": 1,
"react/jsx-no-undef": 1,
"react/jsx-quotes": 1,
"react/jsx-sort-prop-types": 1,
"react/jsx-sort-props": 0,
"react/jsx-uses-react": 1,
"react/jsx-uses-vars": 1,
"react/no-danger": 1,
"react/no-did-mount-set-state": 1,
"react/no-did-update-set-state": 1,
"react/no-multi-comp": 0,
"react/no-unknown-property": 1,
"react/prop-types": 1,
"react/react-in-jsx-scope": 1,
"react/require-extension": 1,
"react/self-closing-comp": 1,
"react/sort-comp": 1,
"react/wrap-multilines": 1,
"space-infix-ops": 0,
"semi": [ 2, "always" ],
"strict": 0
},
"env": {
"es6": true,
"browser": true,
"jasmine": true,
"node": true,
"jest": true
},
"extends": "eslint:recommended",
"ecmaFeatures": {
"jsx": true,
"experimentalObjectRestSpread": true
},
"plugins": [
"react"
],
"parser": "babel-eslint"
}

View File

@ -30,7 +30,10 @@ In case of errors during ```npm install```, remove node_modules dir and clean np
- ```npm run lint``` to run ESLint
- ```npm test && npm run lint``` to run Tests and ESLint
(Info on Linting setup here: https://medium.com/@dan_abramov/lint-like-it-s-2015-6987d44c5b48)
(Info on Linting setup here: https://medium.com/@dan_abramov/lint-like-it-s-2015-6987d44c5b48,
.eslintrc rules tweaks here: http://blog.javascripting.com/2015/09/07/fine-tuning-airbnbs-eslint-config/)
Style guide: https://github.com/airbnb/javascript
#### Tests during development:

View File

@ -44,10 +44,10 @@ gulp.task('fonts', function() {
});
gulp.task('webpack-token-worker', function() {
return gulp.src('./src/js/workers/TokenWorker.js')
.pipe(webpack(tokenWorkerConfig))
.pipe(gulp.dest('./dist/js'))
.pipe(browserSync.stream());
return gulp.src('./src/js/workers/TokenWorker.js')
.pipe(webpack(tokenWorkerConfig))
.pipe(gulp.dest('./dist/js'))
.pipe(browserSync.stream());
});
// Start test server, run tests once, then quit.

View File

@ -14,7 +14,7 @@ module.exports = function(config) {
files: ['webpack.tests.js'],
preprocessors: {
// Run this through webpack, and enable inline sourcemaps
'webpack.tests.js': ['webpack', 'sourcemap'],
'webpack.tests.js': ['webpack', 'sourcemap']
},
webpack: webpackConfig,
@ -32,8 +32,7 @@ module.exports = function(config) {
// Webpack takes a little while to compile -- this manifests as a really
// long load time while webpack blocks on serving the request.
browserNoActivityTimeout: 60000, // 60 seconds
browserNoActivityTimeout: 60000 // 60 seconds
});
};

View File

@ -44,7 +44,7 @@
},
"scripts": {
"test": "karma start --single-run",
"lint": "eslint src/js"
"lint": "eslint src"
},
"repository": {
"type": "git",

View File

@ -24,20 +24,20 @@ let notLoggedInState = {};
describe('Login component', () => {
describe('When user is not logged in', () => {
beforeEach(() => {
spyOn(LoginStore, 'getState').and.returnValue(notLoggedInState);
spyOn(LoginStore, 'isLoggedIn').and.returnValue(false);
loginInstance = TestUtils.renderIntoDocument(<Login/>);
spyOn(LoginStore, 'getState').and.returnValue(notLoggedInState);
spyOn(LoginStore, 'isLoggedIn').and.returnValue(false);
loginInstance = TestUtils.renderIntoDocument(<Login/>);
});
it('should check for redirection prior to mounting', () => {
spyOn(loginInstance, '_shouldRedirect').and.callThrough();
loginInstance.componentWillMount();
expect(loginInstance._shouldRedirect).toHaveBeenCalled();
spyOn(loginInstance, '_shouldRedirect').and.callThrough();
loginInstance.componentWillMount();
expect(loginInstance._shouldRedirect).toHaveBeenCalled();
});
it('should check if User is logged in when testing for redirection', () => {
loginInstance._shouldRedirect();
expect(LoginStore.isLoggedIn).toHaveBeenCalled();
loginInstance._shouldRedirect();
expect(LoginStore.isLoggedIn).toHaveBeenCalled();
});
it('should render with expected markup', () => {

View File

@ -2,47 +2,40 @@ const AuthTokenStorage = require('../../js/services/AuthTokenStorage.js');
const LoginActions = require('../../js/actions/LoginActions');
describe('AuthTokenStorage.', () => {
describe('```AuthTokenStorage.getTokenId```', () => {
let cbObj = { cb: (token) => {} };
describe('```AuthTokenStorage.getTokenId```', () => {
let cbObj = { cb: (token) => {} };
beforeEach(() => {
spyOn(cbObj, 'cb');
});
it('calls the given callback with the token if one has been set.',
(done) => {
LoginActions.loginUser({
token: 'token-from-login',
user: null,
serviceCatalog: null,
metadata: null
});
// unset the sessionStorage value to make sure
// the value is retreived from the worker.
spyOn(sessionStorage, 'getItem').and.returnValue(null);
AuthTokenStorage.getTokenId(cbObj.cb);
done();
expect(cbObj.cb).toHaveBeenCalledWith('token-from-login');
});
it('gives precedence to the token in sessionStorage if one is set', () => {
spyOn(sessionStorage, 'getItem').and.returnValue('token-from-session-storage');
AuthTokenStorage.getTokenId(cbObj.cb);
expect(cbObj.cb).toHaveBeenCalledWith('token-from-session-storage');
});
beforeEach(() => {
spyOn(cbObj, 'cb');
});
describe('```AuthTokenStorage.onLogoutUser```', () => {
it('removes the token from sessionStorage', () => {
spyOn(sessionStorage, 'removeItem');
AuthTokenStorage.removeTokenId();
expect(sessionStorage.removeItem).toHaveBeenCalledWith('keystoneAuthTokenId');
});
it('calls the given callback with the token if one has been set.', (done) => {
LoginActions.loginUser({
token: 'token-from-login',
user: null,
serviceCatalog: null,
metadata: null
});
// unset the sessionStorage value to make sure
// the value is retreived from the worker.
spyOn(sessionStorage, 'getItem').and.returnValue(null);
AuthTokenStorage.getTokenId(cbObj.cb);
done();
expect(cbObj.cb).toHaveBeenCalledWith('token-from-login');
});
it('gives precedence to the token in sessionStorage if one is set', () => {
spyOn(sessionStorage, 'getItem').and.returnValue('token-from-session-storage');
AuthTokenStorage.getTokenId(cbObj.cb);
expect(cbObj.cb).toHaveBeenCalledWith('token-from-session-storage');
});
});
describe('```AuthTokenStorage.onLogoutUser```', () => {
it('removes the token from sessionStorage', () => {
spyOn(sessionStorage, 'removeItem');
AuthTokenStorage.removeTokenId();
expect(sessionStorage.removeItem).toHaveBeenCalledWith('keystoneAuthTokenId');
});
});
});

View File

@ -27,7 +27,7 @@ describe('KeystoneApiService', () => {
// let wrongApiRequest = jest.genMockFunction().mockImplementation(() => {
// return when.reject(expectedError);
// });
KeystoneApiService.handleAuth(when(wrongApiRequest()));
// KeystoneApiService.handleAuth(when(wrongApiRequest()));
// jest.runAllTicks();
expect(console.error).toBeCalledWith('Error in handleAuth', expectedError);
});

View File

@ -73,7 +73,7 @@ export default class Login extends React.Component {
render() {
return (
<div className="row">
<div className="col-md-6 col-xs-8 col-md-offset-3 col-xs-offset-2">
<div className="col-md-6 col-sm-8 col-xs-12 col-md-offset-3 col-sm-offset-2">
<div className="panel panel-default panel-login">
<div className="panel-heading">
<h1 className="panel-title">TripleO UI Login</h1>

View File

@ -11,9 +11,11 @@ export default class NodePicker extends React.Component {
render() {
return (
<div className="node-picker">
<PickerArrow direction="left" increment={this.props.onIncrement.bind(this, -this.props.incrementValue)}/>
<PickerArrow direction="left"
increment={this.props.onIncrement.bind(this, -this.props.incrementValue)}/>
<NodeStack count={this.props.nodeCount}/>
<PickerArrow direction="right" increment={this.props.onIncrement.bind(this, this.props.incrementValue)}/>
<PickerArrow direction="right"
increment={this.props.onIncrement.bind(this, this.props.incrementValue)}/>
</div>
);
}
@ -30,7 +32,8 @@ export class PickerArrow extends React.Component {
render() {
return (
<button className="picker-arrow" onClick={this.props.increment}>
<span className={'glyphicon glyphicon-chevron-' + this.props.direction} aria-hidden="true"></span>
<span className={'glyphicon glyphicon-chevron-' + this.props.direction}
aria-hidden="true"></span>
</button>
);
}

View File

@ -70,7 +70,7 @@ export class FlavorPanelList extends React.Component {
}
}
FlavorPanelList.propTypes = {
'flavors': React.PropTypes.array.isRequired
flavors: React.PropTypes.array.isRequired
};
@ -100,7 +100,7 @@ export class FlavorPanel extends React.Component {
}
}
FlavorPanel.propTypes = {
'flavor': React.PropTypes.object.isRequired
flavor: React.PropTypes.object.isRequired
};
@ -121,7 +121,7 @@ export class RoleList extends React.Component {
}
}
RoleList.propTypes = {
'roles': React.PropTypes.array.isRequired
roles: React.PropTypes.array.isRequired
};
@ -140,7 +140,7 @@ export class FreeNodesPanel extends React.Component {
}
}
FreeNodesPanel.propTypes = {
'nodeCount': React.PropTypes.number.isRequired
nodeCount: React.PropTypes.number.isRequired
};
@ -174,12 +174,13 @@ export class RolePanel extends React.Component {
<h3 className="panel-title">{this.props.role.name}</h3>
</div>
<div className="panel-body clearfix">
<NodePicker nodeCount={this.props.role.nodeCount} onIncrement={this.updateCount.bind(this)}/>
<NodePicker nodeCount={this.props.role.nodeCount}
onIncrement={this.updateCount.bind(this)}/>
</div>
</div>
);
}
}
RolePanel.propTypes = {
'role': React.PropTypes.object.isRequired
role: React.PropTypes.object.isRequired
};

View File

@ -13,7 +13,10 @@ export default class Notification extends React.Component {
});
return (
<div className={classes} role="alert">
<button type="button" className="close" aria-label="Close" onClick={this.props.removeNotification}>
<button type="button"
className="close"
aria-label="Close"
onClick={this.props.removeNotification}>
<span aria-hidden="true">&times;</span>
</button>
<strong>{this.props.title}</strong><br/>

View File

@ -43,7 +43,8 @@ export default class NotificationList extends React.Component {
return (
<div className="container-fluid">
<div className="row">
<div className="col-lg-3 col-lg-offset-9 col-md-4 col-md-offset-8 col-sm-6 col-sm-offset-6">
<div className="col-lg-3 col-lg-offset-9 col-md-4
col-md-offset-8 col-sm-6 col-sm-offset-6">
<div className="notification-list">
{notifications}
</div>

View File

@ -11,5 +11,5 @@ export class PageHeader extends React.Component {
}
}
PageHeader.propTypes = {
'children': React.PropTypes.node
children: React.PropTypes.node
};

View File

@ -35,7 +35,7 @@ export default (ComposedComponent) => {
static willTransitionTo(transition) {
if (!LoginStore.isLoggedIn()) {
transition.redirect('/login', {}, {'nextPath' : transition.path});
transition.redirect('/login', {}, { nextPath: transition.path });
}
}

View File

@ -7,7 +7,8 @@ export default class BaseHttpRequestErrorHandler{
this.xmlHttpRequestError = xmlHttpRequestError;
this.formInputFieldNames = formInputFieldNames || [];
this._errors = this._generateErrors(this.xmlHttpRequestError);
this._formFieldErrors = this._generateFormFieldErrors(this.xmlHttpRequestError, this.formInputFieldNames);
this._formFieldErrors = this._generateFormFieldErrors(this.xmlHttpRequestError,
this.formInputFieldNames);
}
/**
@ -15,7 +16,7 @@ export default class BaseHttpRequestErrorHandler{
@param {object} xmlHttpRequestError - The Error object
@returns {array} array of error objects with type, title and message properties
*/
_generateErrors() {
_generateErrors(xmlHttpRequestError) {
return [];
}
@ -26,7 +27,7 @@ export default class BaseHttpRequestErrorHandler{
@returns {object} object with with form field names as keys and error messages as
values. e.g. {'username': 'Username does not exist'}
*/
_generateFormFieldErrors() {
_generateFormFieldErrors(xmlHttpRequestError, formInputFieldNames) {
return {};
}

View File

@ -33,7 +33,9 @@ class FlavorStore extends BaseStore {
}
getState() {
this.state.flavors.forEach((flavor) => { flavor.freeNodeCount = this._calculateFreeNodes(flavor); });
this.state.flavors.forEach((flavor) => {
flavor.freeNodeCount = this._calculateFreeNodes(flavor);
});
return this.state;
}
}

View File

@ -1,17 +1,17 @@
module.exports = {
devtool: 'source-map',
output: {
filename: 'tripleo_ui_token_worker.js',
sourceMapFilename: 'tripleo_ui_token_worker.js.map'
},
module: {
loaders: [
{ test: /\.js$/, include: /src\/js\/workers/, loader: 'babel-loader' }//,
]
},
node: {
fs: 'empty',
net: 'empty',
tls: 'empty'
}
devtool: 'source-map',
output: {
filename: 'tripleo_ui_token_worker.js',
sourceMapFilename: 'tripleo_ui_token_worker.js.map'
},
module: {
loaders: [
{ test: /\.js$/, include: /src\/js\/workers/, loader: 'babel-loader' }//,
]
},
node: {
fs: 'empty',
net: 'empty',
tls: 'empty'
}
};

View File

@ -6,8 +6,8 @@ module.exports = {
},
module: {
loaders: [
{ test: /\.js$/, include: /src/, exclude: /(node_modules|src\/js\/workers)/, loader: 'babel-loader' }//,
// { test: /disqus-thread.js$/, loader: 'babel-loader' },
{ test: /\.js$/, include: /src/,
exclude: /src\/js\/workers/, loader: 'babel-loader' }
// { test: /\.json$/, loader: 'json-loader' }
]
},
@ -15,5 +15,5 @@ module.exports = {
fs: 'empty',
net: 'empty',
tls: 'empty'
},
}
};