├── README.md
├── ch1
└── enerjy.pdf
├── ch2
├── pg14
├── pg15
├── pg15.1
├── pg16
├── pg16.1
├── pg17
├── pg17.1
├── pg18
├── pg18.1
├── pg19
├── pg19.1
├── pg31
├── pg32
├── pg32.1
├── pg33
├── pg34
├── pg35
├── pg36
├── pg37
├── pg37.1
├── pg43
├── pg43.1
├── pg44
├── pg46
├── pg46.1
├── pg46.2
├── pg47
├── pg49
├── pg51
└── pg53
├── ch3
├── pg61
├── pg62
├── pg62.1
├── pg63
├── pg64
├── pg64.1
├── pg64.2
├── pg66
├── pg66.1
├── pg69
├── pg70
├── pg71
├── pg72
├── pg73
├── pg73.1
├── pg75
├── pg75.1
├── pg76
├── pg77
├── pg77.1
└── pg78
├── ch4
├── pg100
├── pg102
├── pg103
├── pg103.1
├── pg104
├── pg105
├── pg109
├── pg110
├── pg111
├── pg112
├── pg112.1
├── pg85
├── pg85.1
├── pg91
├── pg92
├── pg92.1
├── pg93
├── pg94
├── pg94.1
├── pg96
├── pg96.1
├── pg97
├── pg98
└── pg99
├── ch5
├── pg115
├── pg116
├── pg117
├── pg117.1
├── pg121
├── pg122
├── pg123
├── pg124
├── pg125
├── pg126
├── pg127
├── pg130
├── pg131
└── pg132
├── ch6
├── pg140
├── pg140.1
├── pg142
├── pg144
├── pg145
├── pg146
├── pg149
├── pg149.1
├── pg151
├── pg161
├── pg161.1
├── pg161.2
├── pg162
└── pg163
├── ch7
├── pg179
├── pg180
├── pg188
├── pg190
├── pg191
├── pg192
└── pg196
└── ch8
├── Makefile
├── hudson_jslint.pl
├── pg224
└── pg225
/README.md:
--------------------------------------------------------------------------------
1 | Code Examples and Snippets from [Testable JavaScript](http://shop.oreilly.com/product/0636920024699.do)
2 |
--------------------------------------------------------------------------------
/ch1/enerjy.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zzo/TestableJS/cc8a0172c0812c7a8d226952aab2a1c93264ccf0/ch1/enerjy.pdf
--------------------------------------------------------------------------------
/ch2/pg14:
--------------------------------------------------------------------------------
1 | function configure(values) {
2 | var fs = require('fs')
3 | , config = { docRoot: '/somewhere' }
4 | , key
5 | , stat
6 | ;
7 | for (key in values) {
8 | config[key] = values[key];
9 | }
10 | try {
11 | stat = fs.statSync(config.docRoot);
12 | if (!stat.isDirectory()) {
13 | throw new Error('Is not valid');
14 | }
15 | } catch(e) {
16 | console.log("** " + config.docRoot +
17 | " does not exist or is not a directory!! **");
18 | return;
19 | }
20 | // ... check other values ...
21 | return config;
22 | }
23 |
--------------------------------------------------------------------------------
/ch2/pg15:
--------------------------------------------------------------------------------
1 | describe("configure tests", function() {
2 | it("undef if docRoot does not exist", function() {
3 | expect(configure({ docRoot: '/xxx' })).toBeUndefined();
4 | });
5 | it("not undef if docRoot does exist", function() {
6 | expect(configure({ docRoot: '/tmp' })).not.toBeUndefined();
7 | });
8 | it("adds values to config hash", function() {
9 | var config = configure({ docRoot: '/tmp', zany: 'crazy' });
10 | expect(config).not.toBeUndefined();
11 | expect(config.zany).toEqual('crazy');
12 | expect(config.docRoot).toEqual('/tmp');
13 | });
14 | it("verifies value1 good...", function() {
15 | });
16 | it("verifies value1 bad...", function() {
17 | });
18 | // ...
19 | });
20 |
--------------------------------------------------------------------------------
/ch2/pg15.1:
--------------------------------------------------------------------------------
1 | function configure(values) {
2 | var config = { docRoot: '/somewhere' }
3 | , key
4 | ;
5 |
6 | for (key in values) {
7 | config[key] = values[key];
8 | }
9 |
10 | return config;
11 | }
12 |
13 | function validateDocRoot(config) {
14 | var fs = require('fs')
15 | , stat
16 | ;
17 |
18 | stat = fs.statSync(config.docRoot);
19 | if (!stat.isDirectory()) {
20 | throw new Error('Is not valid');
21 | }
22 | }
23 |
24 | function validateSomethingElse(config) { ... }
25 |
--------------------------------------------------------------------------------
/ch2/pg16:
--------------------------------------------------------------------------------
1 | describe("validate value1", function() {
2 | it("accepts the correct value", function() {
3 | // some expects
4 | });
5 |
6 | it("rejects the incorrect value", function() {
7 | // some expects
8 | });
9 | });
10 |
--------------------------------------------------------------------------------
/ch2/pg16.1:
--------------------------------------------------------------------------------
1 | function configure(values) {
2 | var config = { docRoot: '/somewhere' };
3 | for (var key in values) {
4 | config[key] = values[key];
5 | }
6 |
7 | validateDocRoot(config);
8 | validateSomethingElse(config);
9 | //...
10 | return config;
11 | }
12 |
--------------------------------------------------------------------------------
/ch2/pg17:
--------------------------------------------------------------------------------
1 | var fields {
2 | docRoot: { validator: validateDocRoot, default: '/somewhere' }
3 | , somethingElse: { validator: validateSomethingElse }
4 | };
5 |
6 | function configure(values) {
7 | var config = {};
8 | for (var key in fields) {
9 | if (typeof values[key] !== 'undefined') {
10 | fields[key].validator(values[key]);
11 | config[key] = values[key];
12 | } else {
13 | config[key] = fields[key].default;
14 | }
15 | }
16 | return config;
17 | }
18 |
--------------------------------------------------------------------------------
/ch2/pg17.1:
--------------------------------------------------------------------------------
1 | var obj = { realRoot : '/somewhere' };
2 | Object.defineProperty(obj, 'docRoot', {
3 | enumerable: true
4 | , set: function(value) {
5 | validateDocRoot(value); this.realRoot = value; }
6 | }
7 | );
8 |
--------------------------------------------------------------------------------
/ch2/pg18:
--------------------------------------------------------------------------------
1 | var Obj = (function() {
2 | return function() {
3 | var docRoot = '/somewhere';
4 | this.validateDocRoot = function(val) {
5 | // validation logic - throw Error if not OK
6 | };
7 |
8 | this.setDocRoot = function(val) {
9 | this.validateDocRoot(val);
10 | docRoot = val;
11 | };
12 |
13 | this.getDocRoot = function() {
14 | return docRoot;
15 | };
16 | };
17 | }());
18 |
--------------------------------------------------------------------------------
/ch2/pg18.1:
--------------------------------------------------------------------------------
1 | var myObject = new Obj();
2 | try {
3 | myObject.setDocRoot('/somewhere/else');
4 | } catch(e) {
5 | // something wrong with my new doc root
6 | // old value of docRoot still there
7 | }
8 | // all is OK
9 | console.log(myObject.getDocRoot());
10 |
--------------------------------------------------------------------------------
/ch2/pg19:
--------------------------------------------------------------------------------
1 | var Obj = (function() {
2 | return function() {
3 | var docRoot = '/somewhere';
4 | this.validateDocRoot = function(val) {
5 | // validation logic - throw Exception if not OK
6 | };
7 |
8 | this.setDocRoot = function(val) {
9 | this.validateDocRoot(val);
10 | docRoot = val;
11 | };
12 |
13 | this.getDocRoot = function() {
14 | return docRoot;
15 | };
16 | Object.preventExtensions(this)
17 | };
18 | }());
19 |
--------------------------------------------------------------------------------
/ch2/pg19.1:
--------------------------------------------------------------------------------
1 | describe("validate docRoot", function() {
2 | var config = new Obj();
3 | it("throw if docRoot does not exist", function() {
4 | expect(config.validateDocRoot.bind(config, '/xxx')).toThrow();
5 | });
6 | it("not throw if docRoot does exist", function() {
7 | expect(config.validateDocRoot.bind(config, '/tmp')).not.toThrow();
8 | });
9 | });
10 |
--------------------------------------------------------------------------------
/ch2/pg31:
--------------------------------------------------------------------------------
1 | YUI.use('myModule', function(Y) {
2 | var myModule = function() {
3 | this.a = new Y.A();
4 | this.b = new Y.B();
5 | this.c = new Y.C();
6 | };
7 |
8 | Y.MyModule = myModule;
9 | }, { requires: [ 'a', 'b', 'c' ] });
10 |
--------------------------------------------------------------------------------
/ch2/pg32:
--------------------------------------------------------------------------------
1 | YUI.use('myModule', function(Y) {
2 | var myModule = function() {
3 | this.a = new Y.A();
4 | this.b = new Y.B();
5 | this.c = new Y.C();
6 | this.d = new Y.D();
7 | this.e = new Y.E();
8 | this.f = new Y.F();
9 | this.g = new Y.G();
10 | this.h = new Y.H();
11 | };
12 | Y.MyModule = myModule;
13 | }, { requires: [ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h' ] });
14 |
--------------------------------------------------------------------------------
/ch2/pg32.1:
--------------------------------------------------------------------------------
1 | YUI.use('mySubModule', function(Y) {
2 | var mySubModule = function() {
3 | this.a = new Y.A();
4 | this.b = new Y.B();
5 | this.c = new Y.C();
6 | this.d = new Y.D();
7 | };
8 |
9 | mySubModule.prototype.getA = function() { return this.a; };
10 | mySubModule.prototype.getB = function() { return this.b; };
11 | mySubModule.prototype.getC = function() { return this.c; };
12 | mySubModule.prototype.getD = function() { return this.d; };
13 | Y.MySubModule = mySubModule;
14 | }, { requires: [ 'a', 'b', 'c', 'd'] });
15 |
16 | YUI.use('myModule', function(Y) {
17 | var myModule = function() {
18 | var sub = new Y.MySubModule();
19 | this.a = sub.getA();
20 | this.b = sub.getB();
21 | this.c = sub.getC();
22 | this.d = sub.getD();
23 | this.e = new Y.E();
24 | this.f = new Y.F();
25 | this.g = new Y.G();
26 | this.h = new Y.H();
27 | };
28 | Y.MyModule = myModule;
29 | }, { requires: [ 'mySubModule', 'e', 'f', 'g', 'h' ] });
30 |
--------------------------------------------------------------------------------
/ch2/pg33:
--------------------------------------------------------------------------------
1 | function makeChickenDinner(ingredients) {
2 | var chicken = new ChickenBreast()
3 | , oven = new ConventionalOven()
4 | , mixer = new Mixer()
5 | , dish = mixer.mix(chicken, ingredients)
6 | ;
7 |
8 | return oven.bake(dish, new FDegrees(350), new Timer("50 minutes"));
9 | }
10 | var dinner = makeChickenDinner(ingredients);
11 |
--------------------------------------------------------------------------------
/ch2/pg34:
--------------------------------------------------------------------------------
1 | describe("test make dinner", function() {
2 | // Mocks
3 | Food = function(obj) {};
4 | Food.prototype.attr = {};
5 | MixedFood = function(args) {
6 | var obj = Object.create(Food.prototype);
7 | obj.attr.isMixed = true; return obj;
8 | };
9 |
10 | CookedFood = function(dish) {
11 | var obj = Object.create(Food.prototype);
12 | obj.attr.isCooked = true; return obj;
13 | };
14 |
15 | FDegrees = function(temp) { this.temp = temp };
16 | Meal = function(dish) { this.dish = dish };
17 | Timer = function(timeSpec) { this.timeSpec = timeSpec; };
18 | ChickenBreast = function() {
19 | var obj = Object.create(Food.prototype);
20 | obj.attr.isChicken = true; return obj;
21 | };
22 | ConventionalOven = function() {
23 | this.bake = function(dish, degrees, timer) {
24 | return new CookedFood(dish, degrees, timer);
25 | };
26 | };
27 | Mixer = function() {
28 | this.mix = function(chicken, ingredients) {
29 | return new MixedFood(chicken, ingredients);
30 | };
31 | };
32 | Ingredients = function(ings) { this.ings = ings; };
33 | // end Mocks
34 |
35 | it("cooked dinner", function() {
36 | this.addMatchers({
37 | toBeYummy: function(expected) {
38 | return this.actual.attr.isCooked && this.actual.attr.isMixed;
39 | }
40 | });
41 |
42 | var ingredients = new Ingredients('parsley', 'salt')
43 | , dinner = makeChickenDinner(ingredients)
44 | ;
45 | expect(dinner).toBeYummy();
46 | });
47 | });
48 |
--------------------------------------------------------------------------------
/ch2/pg35:
--------------------------------------------------------------------------------
1 | function Cooker(oven) {
2 | this.oven = oven;
3 | }
4 |
5 | Cooker.prototype.bake = function(dish, deg, timer) {
6 | return this.oven.bake(dish, deg, timer);
7 | };
8 |
9 | Cooker.prototype.degrees_f = function(deg) {
10 | return new FDegrees(deg);
11 | };
12 |
13 | Cooker.prototype.timer = function(time) {
14 | return new Timer(time);
15 | };
16 |
17 | function makeChickenDinner(ingredients, cooker) {
18 | var chicken = new ChickenBreast()
19 | , mixer = new Mixer()
20 | , dish = mixer.mix(chicken, ingredients)
21 | ;
22 | return cooker.bake(dish , cooker.degrees_f(350) , cooker.timer("50 minutes"));
23 | }
24 |
25 | var cooker = new Cooker(new ConventionalOven())
26 | , dinner = makeChickenDinner(ingredients, cooker);
27 |
--------------------------------------------------------------------------------
/ch2/pg36:
--------------------------------------------------------------------------------
1 | describe("test make dinner refactored", function() {
2 | // Mocks
3 | Food = function() {};
4 | Food.prototype.attr = {};
5 | MixedFood = function(args) {
6 | var obj = Object.create(Food.prototype);
7 | obj.attr.isMixed = true;
8 | return obj;
9 | };
10 | CookedFood = function(dish) {
11 | var obj = Object.create(Food.prototype);
12 | obj.attr.isCooked = true;
13 | return obj;
14 | };
15 | ChickenBreast = function() {
16 | var obj = Object.create(Food.prototype);
17 | obj.attr.isChicken = true;
18 | return obj;
19 | };
20 | Meal = function(dish) { this.dish = dish };
21 | Mixer = function() {
22 | this.mix = function(chicken, ingredients) {
23 | return new MixedFood(chicken, ingredients);
24 | };
25 | };
26 | Ingredients = function(ings) { this.ings = ings; };
27 | // end Mocks
28 |
29 | it("cooked dinner", function() {
30 | this.addMatchers({
31 | toBeYummy: function(expected) {
32 | return this.actual.attr.isCooked && this.actual.attr.isMixed;
33 | }
34 | });
35 | var ingredients = new Ingredients('parsley', 'salt')
36 | , MockedCooker = function() {};
37 | // Local (to this test) mocked Cooker object that can actually
38 | // do testing!
39 | MockedCooker.prototype = {
40 | bake: function(food, deg, timer) {
41 | expect(food.attr.isMixed).toBeTruthy();
42 | food.attr.isCooked = true;
43 | return food
44 | }
45 | , degrees_f: function(temp) { expect(temp).toEqual(350); }
46 | , timer: function(time) {
47 | expect(time).toEqual('50 minutes');
48 | }
49 | };
50 | var cooker = new MockedCooker()
51 | , dinner = makeChickenDinner(ingredients, cooker)
52 | ;
53 | expect(dinner).toBeYummy();
54 | });
55 | });
56 |
--------------------------------------------------------------------------------
/ch2/pg37:
--------------------------------------------------------------------------------
1 | function makeChickenDinner(ingredients, cooker, chicken, mixer) {
2 | var dish = mixer.mix(chicken, ingredients);
3 | return cooker.bake(dish
4 | , cooker.degrees_f(350)
5 | , cooker.timer('50 minutes')
6 | );
7 | }
8 |
--------------------------------------------------------------------------------
/ch2/pg37.1:
--------------------------------------------------------------------------------
1 | describe("test make dinner injected", function() {
2 | it("cooked dinner", function() {
3 | this.addMatchers({
4 | toBeYummy: function(expected) {
5 | return this.actual.attr.isCooked && this.actual.attr.isMixed;
6 | }
7 | });
8 |
9 | var ingredients = ['parsley', 'salt']
10 | , chicken = {}
11 | , mixer = {
12 | mix: function(chick, ings) {
13 | expect(ingredients).toBe(ings);
14 | expect(chicken).toBe(chick);
15 | return { attr: { isMixed: true } };
16 | }
17 | }
18 | , MockedCooker = function() {}
19 | ;
20 | MockedCooker.prototype = {
21 | bake: function(food, deg, timer) {
22 | expect(food.attr.isMixed).toBeTruthy();
23 | food.attr.isCooked = true;
24 | return food
25 | }
26 | , degrees_f: function(temp) { expect(temp).toEqual(350); }
27 | , timer: function(time) {
28 | expect(time).toEqual('50 minutes');
29 | }
30 | };
31 | var cooker = new MockedCooker()
32 | , dinner = makeChickenDinner(ingredients, cooker , chicken, mixer)
33 | ;
34 | expect(dinner).toBeYummy();
35 | })
36 | });
37 |
--------------------------------------------------------------------------------
/ch2/pg43:
--------------------------------------------------------------------------------
1 | function dinnerParty(guests) {
2 | var table = new Table()
3 | , invitations = new Invitations()
4 | , food = new Ingredients()
5 | , chef = new Chef()
6 | , staff = new Staff()
7 | , cloth = new FancyTableClothWithFringes()
8 | , dishes = new ChinaWithBlueBorders()
9 | , dinner
10 | ;
11 |
12 | invitations.invite(guests);
13 | table.setTable(cloth, dishes);
14 | dinner = chef.cook(ingredients);
15 | staff.serve(dinner);
16 | }
17 |
--------------------------------------------------------------------------------
/ch2/pg43.1:
--------------------------------------------------------------------------------
1 | var TableClothFactory = {
2 | getTableCloth: function(color) {
3 | return Object.create(TableCloth, { color: { value: color }});
4 | }
5 | };
6 |
--------------------------------------------------------------------------------
/ch2/pg44:
--------------------------------------------------------------------------------
1 | var AbstractTableClothFactory = {
2 | getFactory: function(kind) {
3 | if (kind !== 'TEST') {
4 | return TableClothFactory;
5 | } else {
6 | return TableClothTestFactory;
7 | }
8 | }
9 | };
10 |
--------------------------------------------------------------------------------
/ch2/pg46:
--------------------------------------------------------------------------------
1 | var SpaceShuttle = function() {
2 | this.mainEngine = new SpaceShuttleMainEngine();
3 | this.boosterEngine1 = new SpaceShuttleSolidRocketBooster();
4 | this.boosterEngine2 = new SpaceShuttleSolidRocketBooster();
5 | this.arm = new ShuttleRemoteManipulatorSystem();
6 | };
7 |
--------------------------------------------------------------------------------
/ch2/pg46.1:
--------------------------------------------------------------------------------
1 | var SpaceShuttle = function(mainEngine, b1, b2, arm) {
2 | this.mainEngine = mainEngine;
3 | this.boosterEngine1 = b1;
4 | this.boosterEngine2 = b2;
5 | this.arm = arm;
6 | };
7 |
--------------------------------------------------------------------------------
/ch2/pg46.2:
--------------------------------------------------------------------------------
1 | knit = require('knit');
2 | knit.config(function (bind) {
3 | bind('MainEngine').to(SpaceShuttleMainEngine).is("construtor");
4 | bind('BoosterEngine1').to(SpaceShuttleSolidRocketBooster).is("constructor");
5 | bind('BoosterEngine2').to(SpaceShuttleSolidRocketBooster).is("constructor");
6 | bind('Arm').to(ShuttleRemoteManipulatorSystem).is("constructor");
7 | bind('ShuttleDiscovery').to(SpaceShuttle).is("constructor");
8 | bind('ShuttleEndeavor').to(SpaceShuttle).is("constructor");
9 | bind('Pad').to(new LaunchPad()).is("singleton");
10 | });
11 |
--------------------------------------------------------------------------------
/ch2/pg47:
--------------------------------------------------------------------------------
1 | knit.inject(function(ShuttleDiscovery, ShuttleEndeavor, Pad) {
2 | ShuttleDiscovery.blastOff(Pad);
3 | ShuttleEndeavor.blastOff(Pad);
4 | });
5 |
--------------------------------------------------------------------------------
/ch2/pg49:
--------------------------------------------------------------------------------
1 | /**
2 | * Provides some mathematical functions
3 | *
4 | * @class Math
5 | **/
6 | /**
7 | * This function accepts two operands, 'a' and 'b' and returns
8 | * their sum (or concatenation if they are strings)
9 | *
10 | * @method sum
11 | * @param {Number or String} a first operand
12 | * @param {Number or String} b second operand
13 | * @return {Number or String} The 'summed' value
14 | */
15 | exports.sum = function(a, b) { return a + b };
16 | /**
17 | * This function accepts two operands, 'a' and 'b' and returns
18 | * their product
19 | *
20 | * @method product
21 | * @param {Number} a first operand
22 | * @param {Number} b second operand
23 | * @return {Number} The product
24 | */
25 | exports.mult = function(a, b) { return a * b };
26 |
--------------------------------------------------------------------------------
/ch2/pg51:
--------------------------------------------------------------------------------
1 | /**
2 | * This function accepts two operands, 'a' and 'b' and returns
3 | * their sum (or concatenation if they are strings)
4 | *
5 | * @name sum
6 | * @function
7 | * @param {Number or String} a first operand
8 | * @param {Number or String} b second operand
9 | * @returns {Number or String} The 'summed' value
10 | */
11 | exports.sum = function(a, b) { return a + b };
12 | /**
13 | * This function accepts two operands, 'a' and 'b' and returns
14 | * their product
15 | *
16 | * @name product
17 | * @function
18 | * @param {Number} a first operand
19 | * @param {Number} b second operand
20 | * @returns {Number} The product
21 | */
22 | exports.mult = function(a, b) { return a * b };
23 |
--------------------------------------------------------------------------------
/ch2/pg53:
--------------------------------------------------------------------------------
1 | /**
2 | * This function accepts two operands, 'a' and 'b' and returns their
3 | * sum (or concatenation if they are strings)
4 | */
5 | exports.sum = function(a, b) { return a + b };
6 | /**
7 | * This function accepts two operands, 'a' and 'b' and
8 | * returns their product
9 | */
10 | exports.mult = function(a, b) { return a * b };
11 |
--------------------------------------------------------------------------------
/ch3/pg61:
--------------------------------------------------------------------------------
1 | YUI().add('login', function(Y) {
2 | Y.one('#submitButton').on('click', logIn);
3 | function logIn(e) {
4 | var username = Y.one('#username').get('value')
5 | , password = Y.one('#password').get('value')
6 | , cfg = {
7 | data: JSON.stringify({username: username, password: password })
8 | , method: 'POST'
9 | , on: {
10 | complete: function(tid, resp, args) {
11 | if (resp.status === 200) {
12 | var response = JSON.parse(resp.responseText);
13 | if (response.loginOk) {
14 | userLoggedIn(username);
15 | } else {
16 | failedLogin(username);
17 | }
18 | } else {
19 | networkError(resp);
20 | }
21 | }
22 | }
23 | }
24 | , request = Y.io('/login', cfg)
25 | ;
26 | }
27 | }, '1.0', { requires: [ 'node', 'io-base' ] });
28 |
--------------------------------------------------------------------------------
/ch3/pg62:
--------------------------------------------------------------------------------
1 | YUI().add('login', function(Y) {
2 | Y.one('#submitButton').on('click', logIn);
3 | function logIn(e) {
4 | var username = Y.one('#username').get('value')
5 | , password = Y.one('#password').get('value')
6 | ;
7 |
8 | eventHub.fire('logIn'
9 | , { username: username, password: password }
10 | , function(err, resp) {
11 | if (!err) {
12 | if (resp.loginOk) {
13 | userLoggedIn(username);
14 | } else {
15 | failedLogin(username);
16 | }
17 | } else {
18 | networkError(err);
19 | }
20 | });
21 | }
22 | }, '1.0', { requires: [ 'node', 'EventHub' ] });
23 |
--------------------------------------------------------------------------------
/ch3/pg62.1:
--------------------------------------------------------------------------------
1 | YUI().use('test', 'console', 'node-event-simulate' , 'login', function(Y) {
2 | // Factory for mocking Y.io
3 | var getFakeIO = function(args) {
4 | return function(url, config) {
5 | Y.Assert.areEqual(url, args.url);
6 | Y.Assert.areEqual(config.data, args.data);
7 | Y.Assert.areEqual(config.method, args.method);
8 | Y.Assert.isFunction(config.on.complete);
9 | config.on.complete(1, args.responseArg);
10 | };
11 | }
12 | , realIO = Y.io
13 | ;
14 |
--------------------------------------------------------------------------------
/ch3/pg63:
--------------------------------------------------------------------------------
1 | var testCase = new Y.Test.Case({
2 | name: "test ajax login"
3 | , tearDown: function() {
4 | Y.io = realIO;
5 | }
6 | , testLogin : function () {
7 | var username = 'mark'
8 | , password = 'rox'
9 | ;
10 |
11 | Y.io = getFakeIO({
12 | url: '/login'
13 | , data: JSON.stringify({
14 | username: username
15 | , password: password
16 | })
17 | , method: 'POST'
18 | , responseArg: {
19 | status: 200
20 | , responseText: JSON.stringify({ loginOk: true })
21 | }
22 | });
23 |
24 | userLoggedIn = function(user) {
25 | Y.Assert.areEqual(user, username);
26 | };
27 |
28 | failedLogin = function() {
29 | Y.Assert.fail('login should have succeeded!');
30 | };
31 |
32 | networkError = function() {
33 | Y.Assert.fail('login should have succeeded!');
34 | };
35 |
36 | Y.one('#username').set('value', username);
37 | Y.one('#password').set('value', password);
38 | Y.one('#submitButton').simulate('click');
39 | }
40 | });
41 |
--------------------------------------------------------------------------------
/ch3/pg64:
--------------------------------------------------------------------------------
1 | var suite = new Y.Test.Suite('login');
2 | suite.add(testCase);
3 | Y.Test.Runner.add(suite);
4 | //Initialize the console
5 | new Y.Console({
6 | newestOnTop: false
7 | }).render('#log');
8 | Y.Test.Runner.run();
9 |
--------------------------------------------------------------------------------
/ch3/pg64.1:
--------------------------------------------------------------------------------
1 | YUI().use('test', 'console', 'node-event-simulate' , 'login', function(Y) {
2 |
3 | // Factory for mocking EH
4 | var getFakeEH = function(args) {
5 | return {
6 | fire: function(event, eventArgs, cb) {
7 | Y.Assert.areEqual(event, args.event);
8 | Y.Assert.areEqual(JSON.stringify(eventArgs),
9 | JSON.stringify(args.data));
10 | Y.Assert.isFunction(cb);
11 | cb(args.err, args.responseArg);
12 | }
13 | };
14 | };
15 | });
16 |
--------------------------------------------------------------------------------
/ch3/pg64.2:
--------------------------------------------------------------------------------
1 | var testCase = new Y.Test.Case({
2 | name: "test eh login"
3 | , testLogin : function () {
4 | var username = 'mark'
5 | , password = 'rox'
6 | ;
7 |
8 | eventHub = getFakeEH({
9 | event: 'logIn'
10 | , data: {
11 | username: username
12 | , password: password
13 | }
14 | , responseArg: { loginOk: true }
15 | });
16 |
17 | userLoggedIn = function(user) {
18 | Y.Assert.areEqual(user, username);
19 | };
20 |
21 | failedLogin = function() {
22 | Y.Assert.fail('login should have succeeded!');
23 | };
24 |
25 | networkError = function() {
26 | Y.Assert.fail('login should have succeeded!');
27 | };
28 |
29 | Y.one('#username').set('value', username);
30 | Y.one('#password').set('value', password);
31 | Y.one('#submitButton').simulate('click');
32 | }
33 | }
34 | );
35 |
--------------------------------------------------------------------------------
/ch3/pg66:
--------------------------------------------------------------------------------
1 | // somewhere on server
2 | eventHub.on('REGISTER_USER', function(obj) {
3 | // stick obj.name into user DB
4 | eventHub.fire('USER_REGISTERED', { name: obj.name });
5 | });
6 | // somewhere global
7 | eventHub.on('USER_REGISTERED', function(user) {
8 | console.log(user.name + ' registered!');
9 | });
10 | // somewhere specific
11 | eventHub.fire('REGISTER_USER', { name: 'mark' });
12 |
--------------------------------------------------------------------------------
/ch3/pg66.1:
--------------------------------------------------------------------------------
1 | // Somewhere on the server
2 | eventHub.on('ADD_TO_CART'
3 | , function(userId, itemId, callback) {
4 | d.cart.push(itemId);
5 | callback(null, { items: userId.cart.length });
6 | }
7 | );
8 |
9 | // Meanwhile, somewhere else (in the browser, probably)
10 | function addItemToCart(userId, itemId) {
11 | eventHub.fire('ADD_TO_CART'
12 | , { user_id: userId, item_id: itemId }
13 | , function(err, result) {
14 | if (!err) {
15 | console.log('Cart now has: ' + result.cart.items + ' items');
16 | }
17 | }
18 | );
19 | }
20 |
--------------------------------------------------------------------------------
/ch3/pg69:
--------------------------------------------------------------------------------
1 | // Some handle to a datastore
2 | function DB(eventHub, dbHandle) {
3 | // Add user function
4 | eventHub.on('CREATE_USER', createAddUserHandler(eventHub, dbHandle));
5 | }
6 |
7 | function createAddUserHandler(eventHub, dbHandle) {
8 | return function addUser(user) {
9 | var result = dbHandle.addRow('user', user);
10 | eventHub.fire('USER_CREATED', {
11 | success: result.success
12 | , message: result.message
13 | , user: user
14 | });
15 | }
16 | }
17 |
18 |
19 |
--------------------------------------------------------------------------------
/ch3/pg70:
--------------------------------------------------------------------------------
1 | YUI().use('test', function(Y) {
2 | var eventHub = Y.Mock()
3 | , addUserTests = new Y.Test.Case({
4 | name: 'add user'
5 | , testAddOne: function() {
6 | var user = { user_id: 'mark' }
7 | , dbHandle = { // DB stub
8 | addRow: function(user) {
9 | return { user: user
10 | , success: true
11 | , message: 'ok' };
12 | }
13 | }
14 | , addUser = createAddUserHandler(eventHub, dbHandle)
15 | ;
16 |
17 | Y.Mock.expect(
18 | eventHub
19 | , 'fire'
20 | , [
21 | 'USER_CREATED'
22 | , { success: true, message: 'ok', user: user }
23 | ]
24 | );
25 | DB(eventHub, dbHandle); // Inject test versions
26 | addUser(user);
27 | Y.Mock.verify(eventHub);
28 | }
29 | });
30 |
31 | eventHub.on = function(event, func) {};
32 | eventHub.fire = function(event, data) {};
33 | Y.Test.Runner.add(addUserTests);
34 | Y.Test.Runner.run();
35 | });
36 |
--------------------------------------------------------------------------------
/ch3/pg71:
--------------------------------------------------------------------------------
1 | var DB = function(dbHandle) {
2 | this.handle = dbHandle;
3 | };
4 |
5 | DB.prototype.addUser = function(user) {
6 | var result = dbHandle.addRow('user', user);
7 | return {
8 | success: result.success
9 | , message: result.message
10 | , user: user
11 | };
12 | };
13 |
--------------------------------------------------------------------------------
/ch3/pg72:
--------------------------------------------------------------------------------
1 | YUI().use('test', function(Y) {
2 | var addUserTests = new Y.Test.Case({
3 | name: 'add user'
4 | , addOne: function() {
5 | var user = { user_id: 'mark' }
6 | , dbHandle = { // DB stub
7 | addRow: function(user) {
8 | return { user: user
9 | , success: true
10 | , message: 'ok' };
11 | }
12 | }
13 | , result
14 | ;
15 |
16 | DB(dbHandle); // Inject test versions
17 | result = addUser(user);
18 | Y.Assert.areSame(result.user, user.user);
19 | Y.Assert.isTrue(result.success);
20 | Y.Assert.areSame(result.message, 'ok');
21 | }
22 | });
23 |
24 | Y.Test.Runner.add(addUserTests);
25 | Y.Test.Runner.run();
26 | });
27 |
--------------------------------------------------------------------------------
/ch3/pg73:
--------------------------------------------------------------------------------
1 | // Return an object with 'on' and 'fire' functions for the specified
2 | // eventName
3 | hub.addEvent = function(eventName) {
4 | var _this = this;
5 | this.events[eventName] = {
6 | on: function(callback) {
7 | _this.on.call(_this, eventName, callback);
8 | }
9 | , fire: function() {
10 | Array.prototype.unshift.call(arguments, eventName);
11 | this.fire.apply(_this, arguments);
12 | }
13 | };
14 | return this.events[eventName];
15 | };
16 |
--------------------------------------------------------------------------------
/ch3/pg73.1:
--------------------------------------------------------------------------------
1 | var clickEvent = hub.addEvent('click');
2 | clickEvent.on(function(data) { /* got a click event! */ });
3 | clickEvent.fire({ button: 'clicked' }); // fired a click event!
4 |
--------------------------------------------------------------------------------
/ch3/pg75:
--------------------------------------------------------------------------------
1 | eventSwitch.on('depositMoney', function(data) {
2 | cash += data.depositAmount;
3 | eventSwitch.emit('depositedMoney', cash);
4 | }, { type: 'unicast' });
5 |
--------------------------------------------------------------------------------
/ch3/pg75.1:
--------------------------------------------------------------------------------
1 | eventHub.on('eventClient:done', function(event) {
2 | console.log('DONE LISTENING FOR ' + event);
3 | // finish handling any outstanding events & then safely:
4 | process.exit(0);
5 | });
6 |
--------------------------------------------------------------------------------
/ch3/pg76:
--------------------------------------------------------------------------------
1 | eventHub.on('eventClient:done', function(event) {
2 | console.log('I have been advised to stop listening for event: ' + event);
3 | eventHub.removeAllListeners(event);
4 | });
5 |
--------------------------------------------------------------------------------
/ch3/pg77:
--------------------------------------------------------------------------------
1 | var EventHub = require('EventHub/clients/server/eventClient.js');
2 | , eventHub = EventHub.getClientHub('http://localhost:5883');
3 |
4 | eventHub.on('ADD_USER', function(user) {
5 | // Add user logic
6 | eventHub.fire('ADD_USER_DONE', { success: true, user: user });
7 | });
8 |
--------------------------------------------------------------------------------
/ch3/pg77.1:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
14 |
--------------------------------------------------------------------------------
/ch3/pg78:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 |
--------------------------------------------------------------------------------
/ch4/pg100:
--------------------------------------------------------------------------------
1 | page.onConsoleMessage = function(msg) {
2 | var obj = JSON.parse(msg);
3 | if (obj.results) {
4 | window.setTimeout(function () {
5 | console.log(obj.results);
6 | page.render('output.png');
7 | phantom.exit();
8 | }, 200);
9 | } else {
10 | console.log(msg);
11 | }
12 | };
13 |
--------------------------------------------------------------------------------
/ch4/pg102:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | User View Tests
6 |
7 |
8 | Test User View
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/ch4/pg103:
--------------------------------------------------------------------------------
1 | var webdriverjs = require("webdriverjs")
2 | , url = '...'
3 | ;
4 |
5 | browser = webdriverjs.remote({
6 | host: 'localhost'
7 | , port: 4444
8 | , desiredCapabilities: { browserName: 'firefox' }
9 | });
10 |
11 | browser.init().url(url).end();
12 |
--------------------------------------------------------------------------------
/ch4/pg103.1:
--------------------------------------------------------------------------------
1 | YUI().add('selenium', function(Y) {
2 | var messages = [];
3 | , yconsole = new Y.Console()
4 | ;
5 |
6 | yconsole.on('entry', function(obj) { messages.push(obj.message); });
7 | var TR = Y.Test.Runner;
8 | TR.subscribe(TR.COMPLETE_EVENT, function(obj) {
9 | // Data to dump
10 | var data = escape(JSON.stringify(
11 | {
12 | messages: messages
13 | , results: Y.Test.Format.JUnitXML(obj.results)
14 | }
15 | ));
16 |
17 | // Create a new Node
18 | var item = Y.Node.create('');
19 | item.setContent(data);
20 | // Append to document
21 | Y.one('body').append(item);
22 | });
23 | }, '1.0', { requires: [ 'console', 'node' ] });
24 |
--------------------------------------------------------------------------------
/ch4/pg104:
--------------------------------------------------------------------------------
1 | var webdriverjs = require("webdriverjs")
2 | , url = '...'
3 | , browser = webdriverjs.remote({
4 | host: 'localhost'
5 | , port: 4444
6 | , desiredCapabilities: { browserName: 'firefox' }
7 | })
8 | ;
9 |
10 | browser.init().url(url).waitFor('#testresults', 10000, function(found) {
11 | var res;
12 | if (found) {
13 | res = browser.getText('#testresults',
14 | function(text) {
15 | // Do something smarter than console.log!
16 | console.log(JSON.parse(unescape(text.value)));
17 | });
18 | } else {
19 | console.log('TEST RESULTS NOT FOUND');
20 | }
21 | }).end();
22 |
--------------------------------------------------------------------------------
/ch4/pg105:
--------------------------------------------------------------------------------
1 | var webdriverjs = require("webdriverjs")
2 | , url
3 | , browser = webdriverjs.remote({
4 | host: 'localhost'
5 | , port: 4444
6 | , desiredCapabilities: { browserName: 'firefox' }
7 | })
8 | ;
9 |
10 | browser.init().url(url).waitFor('#testresults', 10000, function(found) {
11 | if (found) {
12 | var res = browser.getText('#testresults'
13 | , function(text) {
14 | // Get log messages and JUnit XML results
15 | console.log(JSON.parse(unescape(text.value)));
16 | // Now take the snapshot
17 | browser.screenshot(
18 | function(screenshot) {
19 | var fs = require('fs')
20 | , filename = 'snapshot.png'
21 | , imageData
22 | ;
23 |
24 | try {
25 | imageData = new Buffer(screenshot.value , 'base64');
26 | fs.writeFileSync(filename, imageData);
27 | } catch(e) {
28 | console.log('Error getting snapshot: ' + e);
29 | }
30 | }
31 | );
32 | });
33 | } else {
34 | console.log('TEST RESULTS NOT FOUND');
35 | }
36 | }).end();
37 |
--------------------------------------------------------------------------------
/ch4/pg109:
--------------------------------------------------------------------------------
1 | var mockery = require('mockery');
2 |
3 | mockery.enable();
4 |
5 | describe("Sum suite File", function() {
6 | beforeEach(function() {
7 | mockery.registerAllowable('./mySumFS', true);
8 | });
9 |
10 | afterEach(function() {
11 | mockery.deregisterAllowable('./mySumFS');
12 | });
13 |
14 | it("Adds Integers!", function() {
15 | var filename = "numbers"
16 | , fsMock = {
17 | readFileSync: function (path, encoding) {
18 | expect(path).toEqual(filename);
19 | expect(encoding).toEqual('utf8');
20 | return JSON.stringify({ a: 9, b: 3 });
21 | }
22 | }
23 | ;
24 |
25 | mockery.registerMock('fs', fsMock);
26 | var mySum = require('./mySumFS');
27 | expect(mySum.sum(filename)).toEqual(12);
28 | mockery.deregisterMock('fs');
29 | });
30 | });
31 |
--------------------------------------------------------------------------------
/ch4/pg110:
--------------------------------------------------------------------------------
1 | it("Adds Strings!", function() {
2 | var filename = "strings"
3 | , fsMock = {
4 | readFileSync: function (path, encoding) {
5 | expect(path).toEqual(filename);
6 | expect(encoding).toEqual('utf8');
7 | return JSON.stringify({ a: 'testable' , b: 'JavaScript' });
8 | }
9 | }
10 | ;
11 |
12 | mockery.registerMock('fs', fsMock);
13 | var mySum = require('./mySumFS');
14 | expect(mySum.sum(filename)).toEqual('testableJavaScript');
15 | mockery.deregisterMock('fs');
16 | });
17 |
--------------------------------------------------------------------------------
/ch4/pg111:
--------------------------------------------------------------------------------
1 | exports.sum = function(func, data) {
2 | var data = JSON.parse(func.apply(this, data));
3 | return data.a + data.b;
4 | };
5 |
6 | exports.getByFile = function(file) {
7 | var fs = require('fs');
8 | return fs.readFileSync(file, 'utf8');
9 | };
10 |
11 | exports.getByParam = function(a, b) {
12 | return JSON.stringify({a: a, b: b});
13 | };
14 |
--------------------------------------------------------------------------------
/ch4/pg112:
--------------------------------------------------------------------------------
1 | mySum = require('./mySumFunc');
2 | describe("Sum suite Functions", function() {
3 | it("Adds By Param!", function() {
4 | var sum = mySum.sum(mySum.getByParam, [6,6]);
5 | expect(sum).toEqual(12);
6 | });
7 |
8 | it("Adds By File!", function() {
9 | var sum = mySum.sum(mySum.getByFile, ["strings"]);
10 | expect(sum).toEqual("testableJavaScript");
11 | });
12 | });
13 |
--------------------------------------------------------------------------------
/ch4/pg112.1:
--------------------------------------------------------------------------------
1 | it("Adds By Param!", function() {
2 |
3 | var params = [ 8, 4 ]
4 | , expected = 12
5 | ;
6 |
7 | spyOn(mySum, 'getByParam').andCallThrough();
8 | expect(mySum.sum(mySum.getByParam, params)).toEqual(expected);
9 | expect(mySum.getByParam).toHaveBeenCalled();
10 | expect(mySum.getByParam.mostRecentCall.args).toEqual(params);
11 | });
12 |
--------------------------------------------------------------------------------
/ch4/pg85:
--------------------------------------------------------------------------------
1 | YUI({ logInclude: { TestRunner: true } }).use('test', 'test-console' , function(Y) {
2 | var testCase = new Y.Test.Case(
3 | {
4 | name: 'Sum Test'
5 | , testSimple: function () {
6 | Y.Assert.areSame(sum(2, 2), 4 , '2 + 2 does not equal 4?');
7 | }
8 | }
9 | );
10 |
11 | // Load it up
12 | Y.Test.Runner.add(testCase);
13 | (new Y.Test.Console({
14 | newestOnTop: false
15 | })).render('#log');
16 |
17 | // Run it
18 | Y.Test.Runner.run();
19 | });
20 |
--------------------------------------------------------------------------------
/ch4/pg85.1:
--------------------------------------------------------------------------------
1 |
2 |
3 | Sum Tests
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/ch4/pg91:
--------------------------------------------------------------------------------
1 | // actual production code:
2 | function buyNowClicked(event) {
3 | hub.fire('addToShoppingCart', { item: event.target.id });
4 | }
5 | Y.one('#products').delegate('click', buyNowClicked, '.buy-now-button');
6 |
7 | /* ... and in your test code: */
8 | testAddToShoppingCart: function() {
9 | var hub = Y.Mock();
10 | Y.Mock.expect(hub,
11 | {
12 | method: "fire"
13 | , args: [ "addToShoppingCart" , Y.Mock.Value.String]
14 | }
15 | );
16 | }
17 | Y.one('.buy-now-button').simulate('click');
18 | Y.Mock.verify(hub);
19 |
--------------------------------------------------------------------------------
/ch4/pg92:
--------------------------------------------------------------------------------
1 | function addToShoppingCart(item) {
2 | if (item.inStock()) {
3 | this.cart.push(item);
4 | return item;
5 | } else {
6 | return null;
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/ch4/pg92.1:
--------------------------------------------------------------------------------
1 | testAddOk: function() {
2 | var shoppingCart = new ShoppingCart()
3 | , item = { inStock: function() { return true; } }
4 | , back = shoppingCart.addToShoppingCart(item)
5 | ;
6 |
7 | Y.Assert.areSame(back, item, "Item not returned");
8 | Y.ArrayAssert.contains(item, "Item not pushed into cart!");
9 | }
10 | , testAddNok: function() {
11 | var shoppingCart = new ShoppingCart()
12 | , item = { inStock: function() { return false; } }
13 | , back = shoppingCart.addToShoppingCart(item)
14 | ;
15 |
16 | Y.Assert.isNull(back, "Item returned is not null");
17 | Y.ArrayAssert.isEmpty(shoppingCart.cart, "Cart not empty!");
18 | }
19 |
--------------------------------------------------------------------------------
/ch4/pg93:
--------------------------------------------------------------------------------
1 | , testWithSpy: function() {
2 | var origSum = sum
3 | , sumSpy = function(a, b) {
4 | Y.Assert.areSame(a, 2, 'first arg is 2!');
5 | Y.Assert.areSame(a, 9, 'second arg is 9!');
6 | return origSum(a, b);
7 | }
8 | ;
9 |
10 | sum = sumSpy;
11 | Y.Assert.areSame(sum(2, 9), 11 , '2 + 9 does not equal 11?');
12 | sum = origSum; // reset it (or use teardown)
13 | }
14 |
--------------------------------------------------------------------------------
/ch4/pg94:
--------------------------------------------------------------------------------
1 | testAsync: function () {
2 | var test = this, myButton = Y.one('#button');
3 | myButton.on('click', function() {
4 | this.resume(function() {
5 | Y.Assert.isTrue(true, 'You sunk my battleship!');
6 | });
7 | }
8 |
9 | myButton.simulate('click');
10 | this.wait(2000);
11 | }
12 |
--------------------------------------------------------------------------------
/ch4/pg94.1:
--------------------------------------------------------------------------------
1 | console = Y.Mock();
2 | testLogHandler: function () {
3 | var sev = 'DEBUG', message = 'TEST';
4 | Y.Mock.expect(console, { method: log
5 | , arguments: [ sev, message ] });
6 | hub.fire('log', sev, message);
7 |
8 | this.wait(function() {
9 | Y.Mock.verify(console);
10 | }, 1000);
11 | }
12 |
--------------------------------------------------------------------------------
/ch4/pg96:
--------------------------------------------------------------------------------
1 | YUI().add('phantomjs', function(Y) {
2 | var TR;
3 | if (typeof(console) !== 'undefined') {
4 | TR = Y.Test.Runner;
5 | TR.subscribe(TR.COMPLETE_EVENT, function(obj) {
6 | console.log(Y.Test.Format.JUnitXML(obj.results));
7 | });
8 | }
9 | });
10 |
--------------------------------------------------------------------------------
/ch4/pg96.1:
--------------------------------------------------------------------------------
1 | YUI({
2 | logInclude: { TestRunner: true },
3 | }).use('test', 'sum', 'console', 'phantomjs', function(Y) {
4 | var suite = new Y.Test.Suite('sum');
5 | suite.add(new Y.Test.Case({
6 | name:'simple test',
7 | testIntAdd : function () {
8 | Y.log('testIntAdd');
9 | Y.Assert.areEqual(Y.MySum(2 ,2), 4);
10 | }
11 | , testStringAdd : function () {
12 | Y.log('testStringAdd');
13 | Y.Assert.areEqual(Y.MySum('my', 'sum'), 'mysum');
14 | }
15 | }));
16 |
17 | Y.Test.Runner.add(suite);
18 | //Initialize the console
19 | var yconsole = new Y.Console({
20 | newestOnTop: false
21 | });
22 | yconsole.render('#log');
23 | Y.Test.Runner.run();
24 | });
25 |
--------------------------------------------------------------------------------
/ch4/pg97:
--------------------------------------------------------------------------------
1 | var page = new WebPage();
2 | page.onConsoleMessage = function(msg) {
3 | console.log(msg);
4 | phantom.exit(0);
5 | };
6 | page.open(phantom.args[0], function (status) {
7 | // Check for page load success
8 | if (status !== "success") {
9 | console.log("Unable to load file");
10 | phantom.exit(1);
11 | }
12 | });
13 |
--------------------------------------------------------------------------------
/ch4/pg98:
--------------------------------------------------------------------------------
1 | var page = new WebPage();
2 | page.viewportSize = { width: 1024, height: 768 };
3 | page.onConsoleMessage = function(msg) {
4 | console.log(msg);
5 | setTimeout(function() {
6 | page.render('output.png');
7 | phantom.exit();
8 | }, 500);
9 | };
10 |
11 | page.open(phantom.args[0], function (status) {
12 | // Check for page load success
13 | if (status !== "success") {
14 | console.log("Unable to load file");
15 | phantom.exit(1);
16 | }
17 | });
18 |
--------------------------------------------------------------------------------
/ch4/pg99:
--------------------------------------------------------------------------------
1 | YUI().add('phantomjs', function(Y) {
2 | var yconsole = new Y.Console();
3 | yconsole.on('entry',
4 | function(obj) {
5 | console.log(JSON.stringify(obj.message));
6 | }
7 | );
8 |
9 | if (typeof(console) !== 'undefined') {
10 | var TR = Y.Test.Runner;
11 | TR.subscribe(TR.COMPLETE_EVENT, function(obj) {
12 | console.log(JSON.stringify(
13 | { results: Y.Test.Format.JUnitXML(obj.results) }));
14 | }
15 | );
16 | }
17 | }, '1.0', { requires: [ 'console' ] });
18 |
--------------------------------------------------------------------------------
/ch5/pg115:
--------------------------------------------------------------------------------
1 | /**
2 | * Return current stock price for given symbol
3 | * in the callback
4 | *
5 | * @method getPrice
6 | * @param symbol the ticker symbol
7 | * @param cb callback with results cb(error, value)
8 | * @param httpObj Optional HTTP object for injection
9 | * @return nothing
10 | **/
11 | function getPrice(symbol, cb, httpObj) {
12 | var http = httpObj || require('http')
13 | , options = {
14 | host: 'download.finance.yahoo.com' // Thanks Yahoo!
15 | , path: '/d/quotes.csv?s=' + symbol + '&f=l1'
16 | }
17 | ;
18 |
19 | http.get(options, function(res) {
20 | res.on('data', function(d) {
21 | cb(null, d);
22 | });
23 | }).on('error', function(e) {
24 | cb(e.message);
25 | });
26 | }
27 |
28 |
--------------------------------------------------------------------------------
/ch5/pg116:
--------------------------------------------------------------------------------
1 | /**
2 | * A simple stub for HTTP object
3 | */
4 | var events = require('events').EventEmitter
5 | , util = require('util')
6 | , myhttp = function() { // Dummy up NodeJS's 'http' object
7 | var _this = this ;
8 | events.call(this);
9 | this.get = function(options, cb) {
10 | cb(_this);
11 | return _this;
12 | };
13 | }
14 | ;
15 | util.inherits(myhttp, events);
16 |
--------------------------------------------------------------------------------
/ch5/pg117:
--------------------------------------------------------------------------------
1 | testPrice: function() {
2 | var symbol = 'YHOO'
3 | , stockPrice = 50 // Wishful thinking??
4 | , _this = this
5 | , http = new myhttp()
6 | ;
7 |
8 | getPrice(symbol, function(err, price) {
9 | _this.resume(function() {
10 | Y.Assert.areEqual(stockPrice, price, "Prices not equal!");
11 | }, http); // Inject our 'http' object
12 | http.fire('data', stockPrice); // Our mock data
13 | this.wait(1000);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/ch5/pg117.1:
--------------------------------------------------------------------------------
1 | testPriceError: function() {
2 | var symbol = 'YHOO'
3 | , _this = this
4 | , http = new myhttp()
5 | ;
6 |
7 | getPrice(symbol, function(err, price) {
8 | _this.resume(function() {
9 | Y.Assert.areEqual(err, 'an error', "Did not get error!"); }, http);
10 | http.fire('error', { message: 'an error'} );
11 | this.wait(1000);
12 | }
13 | }
14 |
15 |
--------------------------------------------------------------------------------
/ch5/pg121:
--------------------------------------------------------------------------------
1 | RewriteEngine On
2 | RewriteCond %{QUERY_STRING} coverage=1
3 | RewriteRule ^(.*)$ make_coverage.pl?file=%{DOCUMENT_ROOT}/$1 [L]
4 |
--------------------------------------------------------------------------------
/ch5/pg122:
--------------------------------------------------------------------------------
1 | #!/usr/bin/perl
2 | use CGI;
3 | my $q = CGI->new;
4 | my $file = $q->param('file');
5 | system("java -jar /path/to/yuitest_coverage.jar -o /tmp/$$.js $file");
6 | print $q->header('application/JavaScript');
7 | open(C, "/tmp/$$.js");
8 | print ;
9 |
--------------------------------------------------------------------------------
/ch5/pg123:
--------------------------------------------------------------------------------
1 | var Module = require('module')
2 | , path = require('path')
3 | , originalLoader = Module._load
4 | , coverageBase = '/tmp'
5 | , COVERAGE_ME = []
6 | ;
7 |
8 | Module._load = coverageLoader;
9 |
10 | // Figure out what files to generate code coverage for
11 | // & put into COVERAGE_ME
12 | // And run those JS files thru yuitest-coverage.jar
13 | // and dump the output into coverageBase
14 | // Then execute tests
15 | // All calls to 'require' will filter thru this:
16 | function coverageLoader(request, parent, isMain) {
17 | if (COVERAGE_ME[request]) {
18 | request = PATH.join(coverageBase, path.basename(request));
19 | }
20 | return originalLoader(request, parent, isMain);
21 | }
22 | // At the end dump the global _yuitest_coverage variable
23 |
--------------------------------------------------------------------------------
/ch5/pg124:
--------------------------------------------------------------------------------
1 | var tempFile = PATH.join(coverageBase, PATH.basename(file));
2 | , realFile = require.resolve(file)
3 | ;
4 | exec('java -jar ' + coverageJar + " -o " + tempFile + " " + realFile
5 | , function(err) {
6 | COVERAGE_ME[file] = 1;
7 | });
8 |
--------------------------------------------------------------------------------
/ch5/pg125:
--------------------------------------------------------------------------------
1 | var realFile = require.resolve(file)
2 | , coverFile = realFile.replace('.js', '.cover');
3 | ;
4 | exec('java -jar ' + coverageJar + " -o " + coverFile + " " + realFile, function(err) {});
5 |
--------------------------------------------------------------------------------
/ch5/pg126:
--------------------------------------------------------------------------------
1 | var TestRunner = Y.Test.Runner;
2 | TestRunner.subscribe(TestRunner. TEST_SUITE_COMPLETE_EVENT, getResults);
3 | TestRunner.run();
4 | function getResults(data) {
5 | var reporter = new Y.Test.Reporter(
6 | "http://www.yourserver.com/path/to/target"
7 | , Y.Test.Format.JUnitXML);
8 | reporter.report(results);
9 | }
10 |
--------------------------------------------------------------------------------
/ch5/pg127:
--------------------------------------------------------------------------------
1 | function getResults(data) {
2 | // Use JUnitXML format for unit test results
3 | var reporter = new Y.Test.Reporter(
4 | "http://www.yourserver.com/path/to/target"
5 | , Y.Test.Format.JUnitXML);
6 |
7 | // Toss in coverage results
8 | reporter.addField("coverageResults", Y.Test.Runner.getCoverage(Y.Coverage.Format.JSON));
9 | // Ship it
10 | reporter.report(results);
11 | }
12 |
--------------------------------------------------------------------------------
/ch5/pg130:
--------------------------------------------------------------------------------
1 | my $old = '/a/b/c';
2 | my $new = '/d/e/f';
3 | open(F, "wrong.lcov");
4 | open(G, ">right.lcov");
5 | while() {
6 | s#^$old#$new#;
7 | print G;
8 | }
9 | close(G);
10 | close(F);
11 |
--------------------------------------------------------------------------------
/ch5/pg131:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Running dummy unit test for APP_FILE
5 |
6 |
7 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/ch5/pg132:
--------------------------------------------------------------------------------
1 | #!/usr/local/bin/perl
2 | use Getopt::Long;
3 | use File::Find;
4 | use File::Basename;
5 |
6 | my($debug, $test_dir, @src_dir, $src_base);
7 | my $src_key = 'src'; // root of source tree
8 |
9 | GetOptions (
10 | "test_dir=s" => \$test_dir,
11 | 132 | Chapter 5: Code Coverage
12 | "src_dir=s" => \@src_dir,
13 | "src_base=s" => \$src_base,
14 | ) || die "Bad Options!\n";;
15 |
16 | my $src_files = {};
17 | find(\&all_src_files, @src_dir);
18 | find(\&all_tested_files, $test_dir);
19 |
20 | sub all_src_files {
21 | return unless (/\.js$/);
22 | foreach my $src_dir (@src_dir) {
23 | $File::Find::name =~ s/^\Q$src_base\E//;
24 | }
25 | $src_files->{$File::Find::name}++;
26 | }
27 |
28 | sub all_tested_files {
29 | return unless (/\.html?$/);
30 | open(F, $_) || die "Can't open $_: $!\n";
31 | while(my $line = ) {
32 | if ($line =~ /["']([^"]+?\/($src_key\/[^"]+?\.js))["']/) {
33 | my($full_file_path) = $2;
34 | print "Test file $File::Find::name is coveraging
35 | $full_file_path\n" if ($debug);
36 | delete $src_files->{$full_file_path};
37 | }.
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/ch6/pg140:
--------------------------------------------------------------------------------
1 | var webdriverjs = require("webdriverjs")
2 | , browser = webdriverjs.remote({
3 | host: 'localhost'
4 | , port: 4444
5 | , desiredCapabilities: { browserName: 'firefox' }
6 | })
7 | ;
8 |
9 | browser
10 | .testMode()
11 | .init()
12 | .url("http://search.yahoo.com")
13 | .setValue("#yschsp", "JavaScript")
14 | .submitForm("#sf")
15 | .tests.visible('#resultCount', true, 'Got result count')
16 | .end();
17 |
--------------------------------------------------------------------------------
/ch6/pg140.1:
--------------------------------------------------------------------------------
1 | var webdriverjs = require("webdriverjs")
2 | , browser = webdriverjs.remote({
3 | host: 'localhost'
4 | , port: 4444
5 | , desiredCapabilities: { browserName: 'firefox' }
6 | })
7 | ;
8 |
9 | browser
10 | .testMode()
11 | .init()
12 | .url("http://search.yahoo.com")
13 | .setValue("#yschsp", "javascript")
14 | .submitForm("#sf")
15 | .tests.visible('#resultCount', true, 'Got result count')
16 | .saveScreenshot('results.png')
17 | .end();
18 |
--------------------------------------------------------------------------------
/ch6/pg142:
--------------------------------------------------------------------------------
1 | var soda = require('soda')
2 | , browser = soda.createClient({
3 | url: 'http://search.yahoo.com'
4 | , host: 'localhost'
5 | , browser: 'safari'
6 | })
7 | ;
8 |
9 | browser
10 | .chain
11 | .session()
12 | .open('/')
13 | .type('yschsp', 'JavaScript')
14 | .submit('sf')
15 | .waitForPageToLoad(5000)
16 | .assertElementPresent('resultCount')
17 | .end(function(err) {
18 | browser.testComplete(function() {
19 | if (err) {
20 | console.log('Test failures: ' + err);
21 | } else {
22 | console.log('success!');
23 | }
24 | })
25 |
--------------------------------------------------------------------------------
/ch6/pg144:
--------------------------------------------------------------------------------
1 | var casper = require('casper').create();
2 | casper.start('http://search.yahoo.com/', function() {
3 | this.fill('form#sf', { "p": 'JavaScript' }, false);
4 | this.click('#yschbt');
5 | });
6 | casper.then(function() {
7 | this.test.assertExists('#resultCount', 'Got result count');
8 | });
9 | casper.run(function() {
10 | this.exit();
11 | });
12 |
--------------------------------------------------------------------------------
/ch6/pg145:
--------------------------------------------------------------------------------
1 | var casper = require('casper').create();
2 | casper.start('http://search.yahoo.com/', function() {
3 | this.fill('form#sf', { "p": 'JavaScript' }, false);
4 | this.click('#yschbt');
5 | });
6 |
7 | casper.then(function() {
8 | this.capture('results.png', {
9 | top: 0,
10 | left: 0,
11 | width: 1024,
12 | height: 768
13 | });
14 |
15 | this.test.assertExists('#resultCount', 'Got result count');
16 | });
17 |
18 | casper.run(function() {
19 | this.exit();
20 | });
21 |
--------------------------------------------------------------------------------
/ch6/pg146:
--------------------------------------------------------------------------------
1 | var casper = require('casper').create();
2 | casper.start('http://search.yahoo.com/', function() {
3 | this.fill('form#sf', { "p": 'JavaScript' }, false);
4 | this.click('#yschbt');
5 | });
6 | casper.then(function() {
7 | this.capture('results.png', {
8 | top: 0,
9 | left: 0,
10 | width: 1024,
11 | height: 768
12 | });
13 |
14 | this.test.assertExists('#resultCount', 'Got result count');
15 | });
16 |
17 | casper.run(function() {
18 | this.test.renderResults(true, 0, 'test-results.xml');
19 | });
20 |
--------------------------------------------------------------------------------
/ch6/pg149:
--------------------------------------------------------------------------------
1 | var Proxy = require('browsermob-proxy').Proxy
2 | , fs = require('fs')
3 | , proxy = new Proxy()
4 | ;
5 |
6 | proxy.doHAR('http://yahoo.com', function(err, data) {
7 | if (err) {
8 | console.error('ERROR: ' + err);
9 | } else {
10 | fs.writeFileSync('yahoo.com.har', data, 'utf8');
11 | }
12 | });
13 |
--------------------------------------------------------------------------------
/ch6/pg149.1:
--------------------------------------------------------------------------------
1 | var Proxy = require('browsermob-proxy').Proxy
2 | , webdriverjs = require("webdriverjs")
3 | , fs = require('fs')
4 | , proxy = new Proxy()
5 | ;
6 |
7 | /*
8 | * Call into the proxy with a 'name' for this session, a Selenium
9 | * function to run the interaction we want to capture, and
10 | * finally a callback that will contain either the HAR data or
11 | * an error
12 | */
13 | proxy.cbHAR('search.yahoo.com', doSeleniumStuff, function(err, data) {
14 | if (err) {
15 | console.error('Error capturing HAR: ' + err);
16 | } else {
17 | fs.writeFileSync('search.yahoo.com.har', data, 'utf8');
18 | }
19 | });
20 |
21 | /*
22 | * This is the Selenium function that gets passed the proxy webdriverjs
23 | * should use and a callback to call when the interaction is done
24 | */
25 | function doSeleniumStuff(proxy, cb) {
26 | var browser = webdriverjs.remote({
27 | host: 'localhost'
28 | , port: 4444
29 | , desiredCapabilities: {
30 | browserName: 'firefox'
31 | , seleniumProtocol: 'WebDriver'
32 | , proxy: { httpProxy: proxy }
33 | }
34 | });
35 |
36 | // Just run our regular Selenium stuff - note this can just
37 | // be your regular test code or something special you want
38 | // to capture with a HAR
39 | // Just pass the browsermob-proxy callback to 'end()'
40 | browser
41 | .testMode()
42 | .init()
43 | .url("http://search.yahoo.com")
44 | .setValue("#yschsp", "JavaScript")
45 | .submitForm("#sf")
46 | .tests.visible('#resultCount', true, 'Got result count')
47 | .saveScreenshot('results.png')
48 | .end(cb);
49 | }
50 |
--------------------------------------------------------------------------------
/ch6/pg151:
--------------------------------------------------------------------------------
1 | var Proxy = require('browsermob-proxy').Proxy
2 | , spawn = require('child_process').spawn
3 | , fs = require('fs')
4 | ;
5 |
6 | var proxy = new Proxy();
7 | proxy.cbHAR('MyCoolHARFile', doCasperJSStuff, function(err, data) {
8 | if (err) {
9 | console.error('ERR: ' + err);
10 | } else {
11 | fs.writeFileSync('casper.har', data, 'utf8');
12 | }
13 | });
14 |
15 | function doCasperJSStuff(proxy, cb) {
16 | casperjs = spawn('bin/casperjs' , [ '--proxy=' + proxy, process.argv[2] ]);
17 | casperjs.on('exit', cb);
18 | }
19 |
--------------------------------------------------------------------------------
/ch6/pg161:
--------------------------------------------------------------------------------
1 | var myLoop = new loop.Loop(
2 | function(finished, args) {
3 | getMemory();
4 | getCPU();
5 | finished();
6 | }
7 | , [] // No args
8 | , [] // No conditions
9 | , .2 // Once every 5 seconds
10 | );
11 |
12 | myLoop.start();
13 |
--------------------------------------------------------------------------------
/ch6/pg161.1:
--------------------------------------------------------------------------------
1 | var reporting = require('nodeload/lib/reporting')
2 | , report = reporting.REPORT_MANAGER.getReport('System Usage')
3 | , memChart = report.getChart('Memory Usage')
4 | , cpuChart = report.getChart('CPU Usage')
5 | , loop = require('nodeload/lib/loop')
6 | , fs = require('fs')
7 | ;
8 |
--------------------------------------------------------------------------------
/ch6/pg161.2:
--------------------------------------------------------------------------------
1 | function getMemory() {
2 | var memData = getProc('meminfo', /\s*kb/i);
3 | memChart.put({ 'Free Memory': memData['MemFree'] , 'Free Swap': memData['SwapFree'] });
4 | report.summary['Total Memory'] = memData['MemTotal'];
5 | report.summary['Total Swap'] = memData['SwapTotal'];
6 | }
7 |
--------------------------------------------------------------------------------
/ch6/pg162:
--------------------------------------------------------------------------------
1 | function getCPU() {
2 | var meminfo = fs.readFileSync('/proc/loadavg', 'utf8')
3 | , vals = meminfo.split(/\s+/)
4 | , cpuInfo = getProc('cpuinfo')
5 | ;
6 |
7 | cpuChart.put( {
8 | '1 Min': vals[0]
9 | , '5 Min': vals[1]
10 | , '15 Min': vals[2]
11 | });
12 | report.summary['CPU'] = cpuInfo['model name'];
13 | }
14 |
--------------------------------------------------------------------------------
/ch6/pg163:
--------------------------------------------------------------------------------
1 | function createClosure() {
2 | var bigHairyVariable = { ... }, wow = 'wow';
3 | return {
4 | a: bigHairyVariable
5 | , b: wow
6 | , c: 87
7 | , d: function() { return bigHairyVariable; }
8 | };
9 | }
10 | // never use global.a - wasted a lot of memory - a leak?
11 | var global = createClosure();
12 |
--------------------------------------------------------------------------------
/ch7/pg179:
--------------------------------------------------------------------------------
1 | function getIterator(countBy, startAt, upTill) {
2 | countBy = countBy || 1;
3 | startAt = startAt || 0;
4 | upTill = upTill || 100;
5 | var current = startAt;
6 | return function() {
7 | current += countBy;
8 | return (current > upTill) ? NaN : current;
9 | };
10 | }
11 |
--------------------------------------------------------------------------------
/ch7/pg180:
--------------------------------------------------------------------------------
1 | function getIterator(countBy, startAt, upTill) {
2 | countBy = countBy || 1;
3 | startAt = startAt || 0;
4 | upTill = upTill || 100;
5 | var current = startAt
6 | , ret = function() {
7 | current += countBy;
8 | return (current > upTill) ? NaN : current;
9 | }
10 | ;
11 |
12 | ret.displayName = "Iterator from " + startAt + " until " + upTill + " by " countBy;
13 | return ret;
14 | }
15 |
--------------------------------------------------------------------------------
/ch7/pg188:
--------------------------------------------------------------------------------
1 | var pDebug = require('pDebug').pDebug
2 | , debug = new pDebug({ eventHandler: function(event) {
3 | console.log('Event'); console.log(event); } }
4 | )
5 | ;
6 |
7 | debug.connect(function() {
8 | var msg = { command: 'continue' };
9 | debug.send(msg, function(req, resp) {
10 | console.log('REQ: ');
11 | console.log(req);
12 | console.log('RES: ');
13 | console.log(resp);
14 | });
15 | });
16 |
--------------------------------------------------------------------------------
/ch7/pg190:
--------------------------------------------------------------------------------
1 | var webdriverjs = require("webdriverjs")
2 | , browser = webdriverjs.remote({
3 | host: 'localhost'
4 | , port: 4444
5 | , desiredCapabilities: {
6 | browserName: 'chrome'
7 | , seleniumProtocol: 'WebDriver'
8 | , 'chrome.switches': [
9 | '--remote-debugging-port=9222'
10 | , '--user-data-dir=remote-profile'
11 | ]
12 | }
13 | })
14 | ;
15 |
16 | browser.addCommand("startCapture", startCapture);
17 | browser
18 | .init()
19 | .url('http://search.yahoo.com')
20 | .startCapture()
21 | .setValue("#yschsp", "JavaScript")
22 | .submitForm("#sf")
23 | .saveScreenshot('results.png')
24 | .end();
25 |
--------------------------------------------------------------------------------
/ch7/pg191:
--------------------------------------------------------------------------------
1 | function startCapture(ready) {
2 | var http = require('http')
3 | , options = {
4 | host: 'localhost'
5 | , port: 9222
6 | , path: '/json'
7 | }
8 | ;
9 |
10 | http.get(options, function(res) {
11 | res.on('data', function (chunk) {
12 | var resObj = JSON.parse(chunk);
13 | connectToDebugger(resObj[0], ready);
14 | });
15 | }).on('error', function(e) {
16 | console.log("Got error: " + e.message);
17 | }
18 |
--------------------------------------------------------------------------------
/ch7/pg192:
--------------------------------------------------------------------------------
1 | function connectToDebugger(obj, ready) {
2 | var fs = require('fs')
3 | , WebSocket = require('faye-websocket')
4 | , ws = new WebSocket.Client(obj.webSocketDebuggerUrl)
5 | , msg = {
6 | id: 777
7 | , method: "Timeline.start"
8 | , params: {
9 | maxCallStackDepth: 10
10 | }
11 | }
12 | , messages = ''
13 | ;
14 |
15 | ws.onopen = function(event) {
16 | ws.send(JSON.stringify(msg));
17 | ready();
18 | };
19 |
20 | ws.onmessage = function(event) {
21 | var obj = JSON.parse(event.data);
22 | if (obj.method && obj.method === 'Timeline.eventRecorded') {
23 | obj.record = obj.params.record; // Zany little hack
24 | messages += JSON.stringify(obj) + '\n';
25 | }
26 | };
27 |
28 | ws.onclose = function(event) {
29 | var header = '\n'
30 | + '\n'
31 | , footer = '
'
32 | ;
33 |
34 | ws = null;
35 | fs.writeFileSync('DUMP.speedtracer.html', header + messages + footer, 'utf8');
36 | };
37 |
--------------------------------------------------------------------------------
/ch7/pg196:
--------------------------------------------------------------------------------
1 | // Open page from the command line in PhantomJS
2 | var page = new WebPage();
3 | page.onError = function (msg, trace) {
4 | console.log(msg);
5 | trace.forEach(function(item) {
6 | console.log(' ', item.file, ':', item.line);
7 | })
8 | }
9 |
10 | page.open(phantom.args[0], function (status) {
11 | // Check for page load success
12 | if (status !== "success") {
13 | console.log("Unable to access network");
14 | } else {
15 | setInterval(function() {}, 200000);
16 | }
17 | });
18 |
--------------------------------------------------------------------------------
/ch8/Makefile:
--------------------------------------------------------------------------------
1 | DO_COVERAGE=1
2 | RELEASE=release
3 | UGLIFY=uglifyjs
4 |
5 | SRC := $(shell find src -name '*.js')
6 | OBJS := $(patsubst %.js,%.jc,$(SRC))
7 |
8 | %.jc : %.js
9 | -mkdir -p $(RELEASE)/$(@D)
10 | $(UGLIFY) -o $(RELEASE)/$(*D)/$(*F).js $<
11 |
12 | CHECKSTYLE=checkstyle
13 | STYLE := $(patsubst %.js,%.xml,$(SRC))
14 | %.xml : %.js
15 | -mkdir -p $(CHECKSTYLE)/$(@D)
16 | -jscheckstyle --checkstyle $< > $(CHECKSTYLE)/$(*D)/$(*F).xml
17 |
18 | JSLINT=jslint
19 | JSL := $(patsubst %.js,%.jslint,$(SRC))
20 | %.jslint : %.js
21 | -mkdir -p $(JSLINT)/$(@D)
22 | ./hudson_jslint.pl $< > $(JSLINT)/$(*D)/$(*F).jslint
23 |
24 | prod: unit_tests $(OBJS) $(STYLE) $(JSL)
25 |
26 | jslint: $(JSL)
27 |
28 | pre:
29 | ifdef WORKSPACE
30 | npm config set jute:docRoot '$(WORKSPACE)'
31 | npm restart jute
32 | npm config list jute
33 | endif
34 |
35 | server_side_unit_tests: pre
36 | cd test && find server_side -name '*.js' -exec echo "{}?do_coverage=$(DO_COVERAGE)" \; | jute_submit_test --v8 --test -
37 |
38 | client_side_unit_tests: pre
39 | cd test && find client_side -name '*.html' -exec echo "{}?do_coverage=$(DO_COVERAGE)" \; | jute_submit_test --v8 --test -
40 |
41 | unit_tests: server_side_unit_tests client_side_unit_tests make_total_lcov
42 |
43 | OUTPUT_DIR=output
44 | TOTAL_LCOV_FILE=$(OUTPUT_DIR)/lcov.info
45 | make_total_lcov:
46 | @echo "OUTPUT DIR: ${OUTPUT_DIR}"
47 | @echo "TOTAL LCOV FILE: ${TOTAL_LCOV_FILE}"
48 | /bin/rm -f /tmp/lcov.info ${TOTAL_LCOV_FILE}
49 | find $(OUTPUT_DIR) -name lcov.info -exec echo '-a {}' \; | xargs lcov > /tmp/lcov.info
50 | cp /tmp/lcov.info ${TOTAL_LCOV_FILE}
51 | /bin/rm -rf $(OUTPUT_DIR)/lcov-report
52 | genhtml -o $(OUTPUT_DIR)/lcov-report $(TOTAL_LCOV_FILE)
53 | python ./conv.py $(TOTAL_LCOV_FILE) -b . -o output/cob.xml
54 |
55 | .PHONY: server_side_unit_tests client_side_unit_tests unit_tests pre make_total_lcov
56 |
--------------------------------------------------------------------------------
/ch8/hudson_jslint.pl:
--------------------------------------------------------------------------------
1 | #!/usr/bin/perl
2 |
3 | use JSON;
4 | use Cwd qw(abs_path);
5 | use XML::Writer;
6 |
7 | my $f = abs_path(shift);
8 |
9 | my @back = `jslint --json $f`;
10 | my $res = decode_json(join '', @back);
11 | my @errors;
12 | foreach my $error (@{$res->[1]}) {
13 | if ($error->{id}) {
14 | push @errors, $error;
15 | }
16 | }
17 |
18 | my $xml = new XML::Writer();
19 | $xml->startTag('jslint');
20 | $xml->startTag('file', name => $res->[0]);
21 | foreach my $error (@errors)
22 | {
23 | $xml->emptyTag('issue',
24 | line => $error->{line},
25 | reason => $error->{reason},
26 | evidence => $error->{evidence}
27 | );
28 | }
29 | $xml->endTag('file');
30 | $xml->endTag('jslint');
31 | $xml->end;
32 |
33 | exit(0);
34 |
35 |
--------------------------------------------------------------------------------
/ch8/pg224:
--------------------------------------------------------------------------------
1 | #!/usr/bin/perl
2 |
3 | # Passed from SVN
4 | my $REPO = shift;
5 | my $TXN = shift;
6 |
7 | # Set up PATH
8 | $ENV{PATH} = "$ENV{PATH}:/usr/bin:/usr/local/bin";
9 |
10 | # The log message
11 | my @logmsg = `svnlook log -t "$TXN" "$REPO"`;
12 | #print STDERR @logmsg;
13 |
14 | # Get file changeset
15 | my @changes = `svnlook changed --transaction "$TXN" "$REPO"`;
16 | my $failed = 0;
17 | #print STDERR @changes;
18 |
19 | # Find JS files
20 | foreach (@changes) {
21 | my($cmd, $file) = split(/\s+/);
22 | # Only JSLint *.js files that haven't been deleted!
23 | if ($file =~ /\.js$/ && $cmd ne 'D') {
24 | # Text of changed file:
25 | # my @cat = `svnlook cat "$REPO" --transaction "$TXN" $file`;
26 | # OR just grab the pre-committed file itself directly
27 | # This script runs from the directory of the commit itself so
28 | # these relative paths are the uncommitted versions
29 | my @jslint = `/usr/local/bin/jslint $file`;
30 | if ($?) {
31 | print STDERR '-' x 20, "\n";
32 | print STDERR "JSLint errors in $file:\n";
33 | print STDERR '-' x 20;
34 | print STDERR @jslint;
35 | $failed++;
36 | }
37 | }
38 | }
39 |
40 | # STDERR goes back to client if failed
41 | exit $failed;
42 |
--------------------------------------------------------------------------------
/ch8/pg225:
--------------------------------------------------------------------------------
1 | #!/usr/bin/perl
2 |
3 | # Get file list
4 | my @files = `git diff --cached --name-only HEAD`;
5 | my $failed = 0;
6 | foreach (@files) {
7 | # Check *.js files only
8 | if (/\.js$/) {
9 | my @style = `jscheckstyle --violations $_`;
10 | if ($?) {
11 | # Send pretty error output to client
12 | print @style;
13 | $failed++;
14 | }
15 | }
16 | }
17 | exit $failed;
18 |
--------------------------------------------------------------------------------