Code Quality despite of JavaScript
Niko Köbler (@dasniko)
Heiko Spindler (@brainbrix)
Qualitects Group
WTFJS
http://wtfjs.com/
It's all(most)
about scope!
var that = this;
'use strict'
ECMA standards
code conventions
&
styleguides
Douglas Crockford
Google
and many more...
modules
RequireJS
CommonJS
static code analysis
JSLint
JSHint
SidekickJS
Sonar Qube
ESLint
The pluggable linting utility for JavaScript
installation
on node.js
npm i -g eslint
run it
eslint [options] [file|dir]*
configuration
eslint -c myconfig.json model.js
sample
{
"env": {
"browser": true
},
"rules": {
// Override our default settings just for this directory
"eqeqeq": 1,
"strict": 1,
"quotes": 0,
"no-extra-semi": 1
}
}
output
38:13 error 'require' is not defined no-undef
41:18 error 'Java' is not defined no-undef
43:11 error 'require' is not defined no-undef
515:69 error 'serviceContainer' is not defined no-undef
710:0 error 'exports' is not defined no-undef
36:0 error Use the function form of "use strict" no-global-strict
36:0 warning Strings must use doublequote quotes
152:36 error It's not necessary to initialize 'cb' to undefined no-undef-init
173:63 warning Strings must use doublequote quotes
193:36 error It's not necessary to initialize 'cb' to undefined no-undef-init
389:43 warning Strings must use doublequote quotes
491:15 warning Expected '!==' and instead saw '!=' eqeqeq
568:13 warning Unnecessary semicolon no-extra-semi
203:93 error args is defined but never used no-unused-vars
define your own rules
module.exports = function(context) {
return {
"BinaryExpression": function(node) {
var operator = node.operator;
...
if (context.options[0] === "smart" && (isTypeOf(node) ||
bothAreSameTypeLiterals(node)) || isNullCheck(node))
{ return; }
if (operator === "==") {
context.report(node, "Expected '===' and instead saw '=='.");
} else if (operator === "!=") {
context.report(node, "Expected '!==' and instead saw '!='.");
}
}
}; };
Sonar Qube (tm)
-
Open Source
-
Multi language support
-
Integrates 20+ languages
-
Based on well known tools (e.g. Findbugs)
-
Web ui with navigation down to the code
-
Definition of Quality Gates
- Online demo project NEMO
- Link: http://www.sonarqube.org/
static typing
???
TypeScript = ES6
types, interfaces, classes,
inheritence, modules, generics
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet() {
return "Hello, " + this.greeting;
}
}
var greeter = new Greeter("world");
alert(greeter.greet());
transpiles to native JavaScript/ES5
DefinitelyTyped
test driven development
e.g. Jasmine
Mocha
Jasmine
Behaviour-driven development
describe("A spec", function() {
it("is just a function, so it can contain any code", function() {
var foo = 0;
foo += 1;
expect(foo).toEqual(1);
});
it("can have more than one expectation", function() {
var foo = 0;
foo += 1;
expect(foo).toEqual(1);
expect(true).toEqual(true);
expect(true).not.toBe(false);
});
});
Mocha
describe('Array', function () {
describe('#indexOf()', function () {
it('should return -1 when the value is not present', function () {
assert.equal(-1, [1, 2, 3].indexOf(5));
assert.equal(-1, [1, 2, 3].indexOf(0));
// same as above, other assertion notation
[1,2,3].indexOf(5).should.equal(-1);
[1,2,3].indexOf(0).should.equal(-1);
});
});
});
PhantomJS
Headless WebKit Browser
Scriptable with JS
Supports: CSS Selectors, XPath, Canvas, SVG, ...
Some drawbacks: e.g. Alert dialogs don't work
CasperJS
Navigation scripting &
testing utility for PhantomJS.
testing utility for PhantomJS.
casper.start('http://www.someurl.com', function() {
casper.assertHttpStatus(200, 'Testlab is up');
casper.capture('LoginScreen.png', {
top: 0, left: 0, width: 1000, height: 900
});
casper.waitForSelector('#logonForm', function() {
casper.fill('form#logonForm', {
'user': 'heiko.spindler@hirnsport.de',
'password': 'xxx' }, true);
});
casper.wait(1000, function() { ... });
casper.test.assertExists('Filterform(click to hide)', "Form found");
});
casper.run();
resurrectio
CasperJS test recorder Chrome extension
casperbox (alpha)
Run CasperJS scripts in the cloud
with simple REST API
-
Scripts are limited to 10 KB and 30 seconds
-
One request per second per IP address
casperbox sample
$ curl --data-binary @hello-world.js http://api.casperbox.com/scripts -H 'Content-Type:text/plain'
{
"id": "430638dd-046a-4d1c-95cd-f510b752de32",
"status": "QUEUED"
}
$ curl http://api.casperbox.com/scripts/ 430638dd-046a-4d1c-95cd-f510b752de32
{
"id": "430638dd-046a-4d1c-95cd-f510b752de32",
"source": "var casper = require('casper').create();\ncasper.start('http://casperjs.org', function() {\n\tcasper.echo('Hello, world!');\n});\ncasper.run();\n",
"status": "RUN",
"output": "Hello, world!"
}
IDE usage
e.g. WebStorm
documentation
JSDoc
/**
* Creates an instance of Circle.
*
* @constructor
* @param {number} r The desired radius of the circle.
*/
function Circle(r) {
/** @private */ this.radius = r;
/** @private */ this.circumference = 2 * Math.PI * r;
}
/**
* Creates a new Circle from a diameter.
*
* @param {number} d The desired diameter of the circle.
* @return {Circle} The new Circle object.
*/
Circle.fromDiameter = function (d) {
return new Circle(d / 2);
};
Thank you!
Code Quality despite of JavaScript
By Niko Köbler
Code Quality despite of JavaScript
- 4,616