By: Victor Mejia
Does this describe your current front-end dev workflow?
https://angular.io/docs/ts/latest/guide/testing.html
(function(context) {
var SuperAwesomeModule = {
featureA: function() {
...
},
featureB: function() {
...
}
};
context.SuperAwesomeModule = SuperAwesomeModule;
})(window);
describe('SuperAwesomeModule', function() {
describe('featureA', function() {
});
describe('featureB', function() {
});
});
it(<string>, <fn>)
describe('SuperAwesomeModule', function() {
describe('featureA', function() {
it('should calculate some super awesome calculation', function() {
...
});
it('should also do this correctly', function() {
...
});
});
});
expect(<actual>).<matcher(expectedValue)>
describe('SuperAwesomeModule', function() {
describe('featureA', function() {
it('should calculate some super awesome calculation', function() {
expect(SuperAwesomeModule.featureA([1, 2, 4]).toEqual(7);
});
it('should also do this correctly', function() {
expect(SuperAwesomeModule.featureB('...').toBe(true);
});
});
});
expect(foo).toBe(true); // uses JS strict equality
expect(foo).not.toBe(true);
expect(foo).toEqual(482); // uses deep equality, recursive search through objects
expect(foo).toBeDefined();
expect(foo).not.toBeDefined();
expect(foo).toBeUndefined();
expect(foo).toBeTruthy(); // boolean cast testing
expect(foo).toBeFalsy();
expect(foo).toContain('student'); // find item in array
expect(e).toBeLessThan(pi);
expect(pi).toBeGreaterThan(e);
expect(a).toBeCloseTo(b, 2); // a to be close to b by 2 decimal points
expect(function() {
foo(1, '2')
}).toThrowError();
expect(function() {
foo(1, '2')
}).toThrow(new Error('Invalid parameter type.')
describe("A spec using beforeEach and afterEach", function() {
var foo = 0;
beforeEach(function() {
foo += 1;
});
afterEach(function() {
foo = 0;
});
it("is just a function, so it can contain any code", function() {
expect(foo).toEqual(1);
});
it("can have more than one expectation", function() {
expect(foo).toEqual(1);
expect(true).toEqual(true);
});
});
describe("A spec using beforeAll and afterAll", function() {
var foo;
beforeAll(function() {
foo = 1;
});
afterAll(function() {
foo = 0;
});
it("sets the initial value of foo before specs run", function() {
expect(foo).toEqual(1);
foo += 1;
});
it("does not reset foo between specs", function() {
expect(foo).toEqual(2);
});
});
describe('SuperAwesomeModule', function() {
xdescribe('featureA', function() {
it('should ...', function() {
});
it('should ...', function() {
});
});
describe('featureB', function() {
xit('should ...', function() {
});
it('should ...', function() {
});
});
});
describe('SuperAwesomeModule', function() {
beforeEach(function() {
// track all calls to SuperAwesomeModule.coolHelperFunction()
// and also delegate to the actual implementation
spyOn(SuperAwesomeModule, 'coolHelperFunction').and.callThrough();
});
describe('featureA', function() {
it('should ...', function() {
expect(SuperAwesomeModule.featureA(2)).toBe(5);
// matchers for spies
expect(SuperAwesomeModule.coolHelperFunction).toHaveBeenCalled();
expect(SuperAwesomeModule.coolHelperFunction).toHaveBeenCalledTimes(1);
});
});
});
describe('SuperAwesomeModule', function() {
beforeEach(function() {
spyOn(SuperAwesomeModule, 'coolHelperFunction').and.returnValue('myValue');
});
});
describe("Manually ticking the Jasmine Clock", function() {
var timerCallback;
beforeEach(function() {
timerCallback = jasmine.createSpy("timerCallback");
jasmine.clock().install();
});
afterEach(function() {
jasmine.clock().uninstall();
});
it("causes a timeout to be called synchronously", function() {
setTimeout(function() {
timerCallback();
}, 100);
expect(timerCallback).not.toHaveBeenCalled();
jasmine.clock().tick(101);
expect(timerCallback).toHaveBeenCalled();
});
});
describe("long asynchronous specs", function() {
beforeEach(function(done) {
done();
}, 1000);
it("takes a long time", function(done) {
setTimeout(function() {
done();
}, 9000);
}, 10000);
afterEach(function(done) {
done();
}, 1000);
});
Default timeout is 5 seconds, can override: jasmine.DEFAULT_TIMEOUT_INTERVAL
# init package.json
npm init
# install karma cli globally
npm install karma-cli -g
# Install plugins that your project needs:
npm install jasmine-core karma karma-jasmine karma-phantomjs-launcher \
karma-spec-reporter phantomjs-prebuilt --save-dev
# init karma.conf.js
karma init
// list of files / patterns to load in the browser
files: [
'src/*.js',
'spec/*.js'
],
browsers: ['PhantomJS'], // run your tests in a headless browser!
update karma.conf.js:
plugins: [
require("karma-jasmine"),
require("karma-phantomjs-launcher"),
require("karma-spec-reporter")
],
...
reporters: ['spec'],
npm install gulp-karma --save-dev
var karma = require('karma');
function handleError(error) {
console.log(error);
process.exit(1);
}
/**
* Run test once and exit
*/
gulp.task('test', function (done) {
var Server = require('karma').Server;
new karma.Server({
configFile: __dirname + '/karma.conf.js',
singleRun: true
}, done).start({}, function(exitStatus) {
if (exitStatus) {
handleError();
}
});
});
npm install gulp-karma --save-dev
var karma = require('karma');
function handleError(error) {
console.log(error);
process.exit(1);
}
/**
* Watch for file changes and re-run tests on each change
*/
gulp.task('tdd', function (done) {
new karma.Server({
configFile: __dirname + '/karma.conf.js'
}, done).start();
});
npm install husky --save-dev
// package.json
{
"scripts": {
"precommit": "gulp test",
"prepush": "gulp test",
"...": "..."
}
}
On npm install, that will install git commit hooks for you, and enable them by adding npm scripts