SlideShare a Scribd company logo
1 of 112
Download to read offline
back to the front
javascript tdd is between us
Who are we?
Marco Cedaro                  Luca Lischetti
javascript pirate, arr        8-bit lover and super hero

Spreaker Frontend Developer   (almost) Shazam Frontend Developer
Who are we?
Marco Cedaro                                  Luca Lischetti
javascript pirate, arr                        8-bit lover and super hero

Spreaker Frontend Developer                   (almost) Shazam Frontend Developer




 The content of this workshop do not necessarily reflect the opinion of authors employers
Who are we?
Marco Cedaro                                      Luca Lischetti
javascript pirate, arr                            8-bit lover and super hero

Spreaker Frontend Developer                       (almost) Shazam Frontend Developer




 The content of this workshop do not necessarily reflect the opinion of authors employers
 Authors employers are not responsible in any way of authors bad coding and funny spoken english
I believe I can fly
Fearless & Unconscious
Fearless & Unconscious
But Life Goes On
TDD is about control
and about DESIGN too
The curious case of JavaScript unit testing
Unit Test and Functional Test
Pro/Cons
     test                consistency
               control
interaction                against     execution       test
                over
  between                 external       time      integration
              codebase
  libraries                changes
That's the browsers,
               baby
Unit testing is
supposed to test a
single atomic “unit”
   of functionality
       without
 dependencies on
   anything else
Unit testing is
                         This is where you
supposed to test a
                          start to run into
single atomic “unit”
                       serious dependency
   of functionality
                       problems due to the
       without
                        interrelation HTML
 dependencies on
                             and CSS
   anything else
Unit testing is
                         This is where you     What do you test?
supposed to test a
                          start to run into   Usually how the user
single atomic “unit”
                       serious dependency      interface responds
   of functionality
                       problems due to the        to user input.
       without
                        interrelation HTML    Actually, the realm of
 dependencies on
                             and CSS            functional testing
   anything else
How does it work?
have you seen LOST?
Write a new test
Write a new test

Run test & let it fail
Write a new test

Run test & let it fail

Write the code
Write a new test

Run test & let it fail

Write the code

Run test & let it succeed
Write a new test

Run test & let it fail

Write the code

Run test & let it succeed

Refactor your code
Coding
_$ = (function() {
   var registered = {};

    return {

!   !   notify: function(event, memo) {
!   !   ! if (registered[event] instanceof Array){
!   !   ! ! var handlers = [].concat(registered[event]);

!   !   ! ! for (var i=0, handler; (handler = handlers[i]); i++){
!   !   ! ! ! handler.call(this, memo);
!   !   ! ! }
!   !   ! }
!   !   },
!   !   !
!   !   watch: function(event, handler) {
!   !   ! if (typeof registered[event] === "undefined"){
!   !   ! ! registered[event] = [];
!   !   ! }
!   !   ! registered[event].push(handler);
!   !   }

   };
})();
pub.. What?
_$ = (function() {
   var registered = {};

    return {

!   !   notify: function(event, memo) {
!   !   ! if (registered[event] instanceof Array){
!   !   ! ! var handlers = [].concat(registered[event]);

!   !   ! ! for (var i=0, handler; (handler = handlers[i]); i++){
!   !   ! ! ! handler.call(this, memo);
!   !   ! ! }
!   !   ! }
!   !   },
!   !   !
!   !   watch: function(event, handler) {
!   !   ! if (typeof registered[event] === "undefined"){
!   !   ! ! registered[event] = [];
!   !   ! }
!   !   ! registered[event].push(handler);
!   !   }

   };
})();
_$.watch("customEvent", function(obj) {
! //DO STUFF
});

_$.notify("customEvent");
_$.notify("customEvent", { prop : "value" });
_$.watch("customEvent", function(obj) {
! //DO STUFF
});

_$.notify("customEvent");
_$.notify("customEvent", { prop : "value" });
_$ = (function() {
   var registered = {};

    return {

!   !   notify: function(event, memo) {
!   !   ! if (registered[event] instanceof Array){
!   !   ! ! var handlers = [].concat(registered[event]);

!   !   ! ! for (var i=0, handler; (handler = handlers[i]); i++){
!   !   ! ! ! handler.call(this, memo);
!   !   ! ! }
!   !   ! }
!   !   },
!   !   !
!   !   watch: function(event, handler) {
!   !   ! if (typeof registered[event] === "undefined"){
!   !   ! ! registered[event] = [];
!   !   ! }
!   !   ! registered[event].push(handler);
!   !   }

   };
})();
_$ = (function() {
   var registered = {};

    return {

!   !   notify: function(event, memo) {
!   !   ! if (registered[event] instanceof Array){
!   !   ! ! var handlers = [].concat(registered[event]);

!   !   ! ! for (var i=0, handler; (handler = handlers[i]); i++){
!   !   ! ! ! handler.call(this, memo);
!   !   ! ! }
!   !   ! }
!   !   },
!   !   !
!   !   watch: function(event, handler) {
!   !   ! if (typeof registered[event] === "undefined"){
!   !   ! ! registered[event] = [];
!   !   ! }
!   !   ! registered[event].push(handler);
!   !   }

   };
})();
_$ = (function() {
   var registered = {};

    return {

!   !   notify: function(event, memo) {
!   !   ! if (registered[event] instanceof Array){
!   !   ! ! var handlers = [].concat(registered[event]);

!   !   ! ! for (var i=0, handler; (handler = handlers[i]); i++){
!   !   ! ! ! handler.call(this, memo);
!   !   ! ! }
!   !   ! }
!   !   },
!   !   !
!   !   watch: function(event, handler) {
!   !   ! if (typeof registered[event] === "undefined"){
!   !   ! ! registered[event] = [];
!   !   ! }
!   !   ! registered[event].push(handler);
!   !   }

   };
})();
_$ = (function() {
   var registered = {};

    return {

!   !   notify: function(event, memo) {
!   !   ! if (registered[event] instanceof Array){
!   !   ! ! var handlers = [].concat(registered[event]);

!   !   ! ! for (var i=0, handler; (handler = handlers[i]); i++){
!   !   ! ! ! handler.call(this, memo);
!   !   ! ! }
!   !   ! }
!   !   },
!   !   !
!   !   watch: function(event, handler) {
!   !   ! if (typeof registered[event] === "undefined"){
!   !   ! ! registered[event] = [];
!   !   ! }
!   !   ! registered[event].push(handler);
!   !   }

   };
})();
_$ = (function() {
   var registered = {};

    return {

!   !   notify: function(event, memo) {
!   !   ! if (registered[event] instanceof Array){
!   !   ! ! var handlers = [].concat(registered[event]);

!   !   ! ! for (var i=0, handler; (handler = handlers[i]); i++){
!   !   ! ! ! handler.call(this, memo);
!   !   ! ! }
!   !   ! }
!   !   },
!   !   !
!   !   watch: function(event, handler) {
!   !   ! if (typeof registered[event] === "undefined"){
!   !   ! ! registered[event] = [];
!   !   ! }
!   !   ! registered[event].push(handler);
!   !   }

   };
})();
_$ = (function() {
   var registered = {};

    return {

!   !   notify: function(event, memo) {
!   !   ! if (registered[event] instanceof Array){
!   !   ! ! var handlers = [].concat(registered[event]);

!   !   ! ! for (var i=0, handler; (handler = handlers[i]); i++){
!   !   ! ! ! handler.call(this, memo);
!   !   ! ! }
!   !   ! }
!   !   },
!   !   !
!   !   watch: function(event, handler) {
!   !   ! if (typeof registered[event] === "undefined"){
!   !   ! ! registered[event] = [];
!   !   ! }
!   !   ! registered[event].push(handler);
!   !   }

   };
})();
_$.watch("customEvent", function(obj) {
! //DO STUFF
});

_$.notify("customEvent");
_$.notify("customEvent", { prop : "value" });
_$ = (function() {
   var registered = {};

    return {

!   !   notify: function(event, memo) {
!   !   ! if (registered[event] instanceof Array){
!   !   ! ! var handlers = [].concat(registered[event]);

!   !   ! ! for (var i=0, handler; (handler = handlers[i]); i++){
!   !   ! ! ! handler.call(this, memo);
!   !   ! ! }
!   !   ! }
!   !   },
!   !   !
!   !   watch: function(event, handler) {
!   !   ! if (typeof registered[event] === "undefined"){
!   !   ! ! registered[event] = [];
!   !   ! }
!   !   ! registered[event].push(handler);
!   !   }

   };
})();
_$ = (function() {
   var registered = {};

    return {

!   !   notify: function(event, memo) {
!   !   ! if (registered[event] instanceof Array){
!   !   ! ! var handlers = [].concat(registered[event]);

!   !   ! ! for (var i=0, handler; (handler = handlers[i]); i++){
!   !   ! ! ! handler.call(this, memo);
!   !   ! ! }
!   !   ! }
!   !   },
!   !   !
!   !   watch: function(event, handler) {
!   !   ! if (typeof registered[event] === "undefined"){
!   !   ! ! registered[event] = [];
!   !   ! }
!   !   ! registered[event].push(handler);
!   !   }

   };
})();
_$ = (function() {
   var registered = {};

    return {

!   !   notify: function(event, memo) {
!   !   ! if (registered[event] instanceof Array){
!   !   ! ! var handlers = [].concat(registered[event]);

!   !   ! ! for (var i=0, handler; (handler = handlers[i]); i++){
!   !   ! ! ! handler.call(this, memo);
!   !   ! ! }
!   !   ! }
!   !   },
!   !   !
!   !   watch: function(event, handler) {
!   !   ! if (typeof registered[event] === "undefined"){
!   !   ! ! registered[event] = [];
!   !   ! }
!   !   ! registered[event].push(handler);
!   !   }

   };
})();
_$ = (function() {
   var registered = {};

    return {

!   !   notify: function(event, memo) {
!   !   ! if (registered[event] instanceof Array){
!   !   ! ! var handlers = [].concat(registered[event]);

!   !   ! ! for (var i=0, handler; (handler = handlers[i]); i++){
!   !   ! ! ! handler.call(this, memo);
!   !   ! ! }
!   !   ! }
!   !   },
!   !   !
!   !   watch: function(event, handler) {
!   !   ! if (typeof registered[event] === "undefined"){
!   !   ! ! registered[event] = [];
!   !   ! }
!   !   ! registered[event].push(handler);
!   !   }

   };
})();
_$ = (function() {
   var registered = {};

    return {

!   !   notify: function(event, memo) {
!   !   ! if (registered[event] instanceof Array){
!   !   ! ! var handlers = [].concat(registered[event]);

!   !   ! ! for (var i=0, handler; (handler = handlers[i]); i++){
!   !   ! ! ! handler.call(this, memo);
!   !   ! ! }
!   !   ! }
!   !   },
!   !   !
!   !   watch: function(event, handler) {
!   !   ! if (typeof registered[event] === "undefined"){
!   !   ! ! registered[event] = [];
!   !   ! }
!   !   ! registered[event].push(handler);
!   !   }

   };
})();
_$ = (function() {
   var registered = {};

    return {

!   !   notify: function(event, memo) {
!   !   ! if (registered[event] instanceof Array){
!   !   ! ! var handlers = [].concat(registered[event]);

!   !   ! ! for (var i=0, handler; (handler = handlers[i]); i++){
!   !   ! ! ! handler.call(this, memo);
!   !   ! ! }
!   !   ! }
!   !   },
!   !   !
!   !   watch: function(event, handler) {
!   !   ! if (typeof registered[event] === "undefined"){
!   !   ! ! registered[event] = [];
!   !   ! }
!   !   ! registered[event].push(handler);
!   !   }

   };
})();
_$ = (function() {
   var registered = {};

    return {

!   !   notify: function(event, memo) {
!   !   ! if (registered[event] instanceof Array){
!   !   ! ! var handlers = [].concat(registered[event]);

!   !   ! ! for (var i=0, handler; (handler = handlers[i]); i++){
!   !   ! ! ! handler.call(this, memo);
!   !   ! ! }
!   !   ! }
!   !   },
!   !   !
!   !   watch: function(event, handler) {
!   !   ! if (typeof registered[event] === "undefined"){
!   !   ! ! registered[event] = [];
!   !   ! }
!   !   ! registered[event].push(handler);
!   !   }

   };
})();
_$ = (function (_) {

   return {

       notify: function (a, b, c, d) {
          for (d = -1, c = [].concat(_[a]); c[++d];) c[d](b);
       },

       watch: function (a, b) {
          (_[a] || (_[a] = [])).push(b);
       }

   }

})({});
[...]
    testNotify: function(){!
                           !
!   ! var a = 0;!
!   ! _$.watch('testNotify', function(){ a = 1; });
!   ! _$.notify('testNotify');

!   ! assertEquals(1, a);
!   },
!   ! !
!   testNotifyWithMemo: function(){! !
!   ! var a = 0 ;!
!   ! _$.watch('testNotify', function(memo){ a = memo.test; });
!   ! _$.notify('testNotify', {test: 1});

!   ! assertEquals(1, a);
!   },
[...]
[...]
    testNotify: function(){!
                           !
!   ! var a = 0;!
!   ! _$.watch('testNotify', function(){ a = 1; });
!   ! _$.notify('testNotify');

!   ! assertEquals(1, a);
!   },
!   ! !
!   testNotifyWithMemo: function(){! !
!   ! var a = 0 ;!
!   ! _$.watch('testNotify', function(memo){ a = memo.test; });
!   ! _$.notify('testNotify', {test: 1});

!   ! assertEquals(1, a);
!   },
[...]
[...]
    testNotify: function(){!
                           !
!   ! var a = 0;!
!   ! _$.watch('testNotify', function(){ a = 1; });
!   ! _$.notify('testNotify');

!   ! assertEquals(1, a);
!   },
!   ! !
!   testNotifyWithMemo: function(){! !
!   ! var a = 0 ;!
!   ! _$.watch('testNotify', function(memo){ a = memo.test; });
!   ! _$.notify('testNotify', {test: 1});

!   ! assertEquals(1, a);
!   },
[...]
[...]
    testNotify: function(){!
                           !
!   ! var a = 0;!
!   ! _$.watch('testNotify', function(){ a = 1; });
!   ! _$.notify('testNotify');

!   ! assertEquals(1, a);
!   },
!   ! !
!   testNotifyWithMemo: function(){! !
!   ! var a = 0 ;!
!   ! _$.watch('testNotify', function(memo){ a = memo.test; });
!   ! _$.notify('testNotify', {test: 1});

!   ! assertEquals(1, a);
!   },
[...]
[...]
    testNotify: function(){!
                           !
!   ! var a = 0;!
!   ! _$.watch('testNotify', function(){ a = 1; });
!   ! _$.notify('testNotify');

!   ! assertEquals(1, a);
!   },
!   ! !
!   testNotifyWithMemo: function(){! !
!   ! var a = 0 ;!
!   ! _$.watch('testNotify', function(memo){ a = memo.test; });
!   ! _$.notify('testNotify', {test: 1});

!   ! assertEquals(1, a);
!   },
[...]
[...]
    testNotify: function(){!
                           !
!   ! var a = 0;!
!   ! _$.watch('testNotify', function(){ a = 1; });
!   ! _$.notify('testNotify');

!   ! assertEquals(1, a);
!   },
!   ! !
!   testNotifyWithMemo: function(){! !
!   ! var a = 0 ;!
!   ! _$.watch('testNotify', function(memo){ a = memo.test; });
!   ! _$.notify('testNotify', {test: 1});

!   ! assertEquals(1, a);
!   },
[...]
[...]
    testNotify: function(){!
                           !
!   ! var a = 0;!
!   ! _$.watch('testNotify', function(){ a = 1; });
!   ! _$.notify('testNotify');

!   ! assertEquals(1, a);
!   },
!   ! !
!   testNotifyWithMemo: function(){! !
!   ! var a = 0 ;!
!   ! _$.watch('testNotify', function(memo){ a = memo.test; });
!   ! _$.notify('testNotify', {test: 1});

!   ! assertEquals(1, a);
!   },
[...]
[...]
!   testNotifyWithMultipleWhatches: function(){!
                                               !
!   ! var a = 0, b = 0;!
!   ! _$.watch('testNotify', function(memo){ a = memo.test; });
!   ! _$.watch('testNotify', function(memo){ b = memo.test; });
!   ! _$.notify('testNotify', {test: 1});

!   ! assertEquals(1, a);
!   ! assertEquals(1, b);
!   },
[...]
[...]
!   testNotifyWithMultipleWhatches: function(){!
                                               !
!   ! var a = 0, b = 0;!
!   ! _$.watch('testNotify', function(memo){ a = memo.test; });
!   ! _$.watch('testNotify', function(memo){ b = memo.test; });
!   ! _$.notify('testNotify', {test: 1});

!   ! assertEquals(1, a);
!   ! assertEquals(1, b);
!   },
[...]
[...]
!   testNotifyWithMultipleWhatches: function(){!
                                               !
!   ! var a = 0, b = 0;!
!   ! _$.watch('testNotify', function(memo){ a = memo.test; });
!   ! _$.watch('testNotify', function(memo){ b = memo.test; });
!   ! _$.notify('testNotify', {test: 1});

!   ! assertEquals(1, a);
!   ! assertEquals(1, b);
!   },
[...]
[...]
    testNotifyWithMultipleWhatchesNested: function(){!!
!   ! var a = 0, b = 0, c=0;!
!   ! _$.watch('testNotify', function(memo){
           a = memo.test;
!   ! ! _$.watch('testNotify', function(memo){
!   ! ! ! if (b<2){ b = memo.test; }
              else { c = memo.test; }
!   ! ! });
!   ! });
!   !
!   ! _$.notify('testNotify', {test: 1});
!   ! assertEquals(1, a);
!   ! assertEquals(0, b);
!   ! assertEquals(0, c);
!   !
!   ! _$.notify('testNotify', {test: 2});
!   ! assertEquals(2, a);
!   ! assertEquals(2, b);
!   ! assertEquals(0, c);
!   !
!   ! _$.notify('testNotify', {test: 3});
!   ! assertEquals(3, a);
!   ! assertEquals(2, b);
!   ! assertEquals(3, c);
!   },
[...]
[...]
    testNotifyWithMultipleWhatchesNested: function(){!!
!   ! var a = 0, b = 0, c=0;!
!   ! _$.watch('testNotify', function(memo){
           a = memo.test;
!   ! ! _$.watch('testNotify', function(memo){
!   ! ! ! if (b<2){ b = memo.test; }
              else { c = memo.test; }
!   ! ! });
!   ! });
!   !
!   ! _$.notify('testNotify', {test: 1});
!   ! assertEquals(1, a);
!   ! assertEquals(0, b);
!   ! assertEquals(0, c);
!   !
!   ! _$.notify('testNotify', {test: 2});
!   ! assertEquals(2, a);
!   ! assertEquals(2, b);
!   ! assertEquals(0, c);
!   !
!   ! _$.notify('testNotify', {test: 3});
!   ! assertEquals(3, a);
!   ! assertEquals(2, b);
!   ! assertEquals(3, c);
!   },
[...]
[...]
    testNotifyWithMultipleWhatchesNested: function(){!!
!   ! var a = 0, b = 0, c=0;!
!   ! _$.watch('testNotify', function(memo){
           a = memo.test;
!   ! ! _$.watch('testNotify', function(memo){
!   ! ! ! if (b<2){ b = memo.test; }
              else { c = memo.test; }
!   ! ! });
!   ! });
!   !
!   ! _$.notify('testNotify', {test: 1});
!   ! assertEquals(1, a);
!   ! assertEquals(0, b);
!   ! assertEquals(0, c);
!   !
!   ! _$.notify('testNotify', {test: 2});
!   ! assertEquals(2, a);
!   ! assertEquals(2, b);
!   ! assertEquals(0, c);
!   !
!   ! _$.notify('testNotify', {test: 3});
!   ! assertEquals(3, a);
!   ! assertEquals(2, b);
!   ! assertEquals(3, c);
!   },
[...]
[...]
    testNotifyWithMultipleWhatchesNested: function(){!!
!   ! var a = 0, b = 0, c=0;!
!   ! _$.watch('testNotify', function(memo){
           a = memo.test;
!   ! ! _$.watch('testNotify', function(memo){
!   ! ! ! if (b<2){ b = memo.test; }
              else { c = memo.test; }
!   ! ! });
!   ! });
!   !
!   ! _$.notify('testNotify', {test: 1});
!   ! assertEquals(1, a);
!   ! assertEquals(0, b);
!   ! assertEquals(0, c);
!   !
!   ! _$.notify('testNotify', {test: 2});
!   ! assertEquals(2, a);
!   ! assertEquals(2, b);
!   ! assertEquals(0, c);
!   !
!   ! _$.notify('testNotify', {test: 3});
!   ! assertEquals(3, a);
!   ! assertEquals(2, b);
!   ! assertEquals(3, c);
!   },
[...]
[...]
    testNotifyWithMultipleWhatchesNested: function(){!!
!   ! var a = 0, b = 0, c=0;!
!   ! _$.watch('testNotify', function(memo){
           a = memo.test;
!   ! ! _$.watch('testNotify', function(memo){
!   ! ! ! if (b<2){ b = memo.test; }
!   ! ! ! else { c = memo.test; }
!   ! ! });
!   ! });
!   !
!   ! _$.notify('testNotify', {test: 1});
!   ! assertEquals(1, a);
!   ! assertEquals(0, b);
!   ! assertEquals(0, c);
!   !
!   ! _$.notify('testNotify', {test: 2});
!   ! assertEquals(2, a);
!   ! assertEquals(2, b);
!   ! assertEquals(0, c);
!   !
!   ! _$.notify('testNotify', {test: 3});
!   ! assertEquals(3, a);
!   ! assertEquals(2, b);
!   ! assertEquals(3, c);
!   },
[...]
[...]
    testNotifyWithMultipleWhatchesNested: function(){!!
!   ! var a = 0, b = 0, c=0;!
!   ! _$.watch('testNotify', function(memo){
           a = memo.test;
!   ! ! _$.watch('testNotify', function(memo){
!   ! ! ! if (b<2){ b = memo.test; }
              else { c = memo.test; }
!   ! ! });
!   ! });
!   !
!   ! _$.notify('testNotify', {test: 1});
!   ! assertEquals(1, a);
!   ! assertEquals(0, b);
!   ! assertEquals(0, c);
!   !
!   ! _$.notify('testNotify', {test: 2});
!   ! assertEquals(2, a);
!   ! assertEquals(2, b);
!   ! assertEquals(0, c);
!   !
!   ! _$.notify('testNotify', {test: 3});
!   ! assertEquals(3, a);
!   ! assertEquals(2, b);
!   ! assertEquals(3, c);
!   },
[...]
[...]
    testNotifyWithMultipleWhatchesNested: function(){!!
!   ! var a = 0, b = 0, c=0;!
!   ! _$.watch('testNotify', function(memo){
           a = memo.test;
!   ! ! _$.watch('testNotify', function(memo){
!   ! ! ! if (b<2){ b = memo.test; }
              else { c = memo.test; }
!   ! ! });
!   ! });
!   !
!   ! _$.notify('testNotify', {test: 1});
!   ! assertEquals(1, a);
!   ! assertEquals(0, b);
!   ! assertEquals(0, c);
!   !
!   ! _$.notify('testNotify', {test: 2});
!   ! assertEquals(2, a);
!   ! assertEquals(2, b);
!   ! assertEquals(0, c);
!   !
!   ! _$.notify('testNotify', {test: 3});
!   ! assertEquals(3, a);
!   ! assertEquals(2, b);
!   ! assertEquals(3, c);
!   },
[...]
[...]
    testNotifyWithMultipleWhatchesNested: function(){!!
!   ! var a = 0, b = 0, c=0;!
!   ! _$.watch('testNotify', function(memo){
           a = memo.test;
!   ! ! _$.watch('testNotify', function(memo){
!   ! ! ! if (b<2){ b = memo.test; }
              else { c = memo.test; }
!   ! ! });
!   ! });
!   !
!   ! _$.notify('testNotify', {test: 1});
!   ! assertEquals(1, a);
!   ! assertEquals(0, b);
!   ! assertEquals(0, c);
!   !
!   ! _$.notify('testNotify', {test: 2});
!   ! assertEquals(2, a);
!   ! assertEquals(2, b);
!   ! assertEquals(0, c);
!   !
!   ! _$.notify('testNotify', {test: 3});
!   ! assertEquals(3, a);
!   ! assertEquals(2, b);
!   ! assertEquals(3, c);
!   },
[...]
[...]
    testNotifyWithMultipleWhatchesNested: function(){!!
!   ! var a = 0, b = 0, c=0;!
!   ! _$.watch('testNotify', function(memo){
           a = memo.test;
!   ! ! _$.watch('testNotify', function(memo){
!   ! ! ! if (b<2){ b = memo.test; }
              else { c = memo.test; }
!   ! ! });
!   ! });
!   !
!   ! _$.notify('testNotify', {test: 1});
!   ! assertEquals(1, a);
!   ! assertEquals(0, b);
!   ! assertEquals(0, c);
!   !
!   ! _$.notify('testNotify', {test: 2});
!   ! assertEquals(2, a);
!   ! assertEquals(2, b);
!   ! assertEquals(0, c);
!   !
!   ! _$.notify('testNotify', {test: 3});
!   ! assertEquals(3, a);
!   ! assertEquals(2, b);
!   ! assertEquals(3, c);
!   },
[...]
[...]
    testNotifyWithMultipleWhatchesNested: function(){!!
!   ! var a = 0, b = 0, c=0;!
!   ! _$.watch('testNotify', function(memo){
           a = memo.test;
!   ! ! _$.watch('testNotify', function(memo){
!   ! ! ! if (b<2){ b = memo.test; }
              else { c = memo.test; }
!   ! ! });
!   ! });
!   !
!   ! _$.notify('testNotify', {test: 1});
!   ! assertEquals(1, a);
!   ! assertEquals(0, b);
!   ! assertEquals(0, c);
!   !
!   ! _$.notify('testNotify', {test: 2});
!   ! assertEquals(2, a);
!   ! assertEquals(2, b);
!   ! assertEquals(0, c);
!   !
!   ! _$.notify('testNotify', {test: 3});
!   ! assertEquals(3, a);
!   ! assertEquals(2, b);
!   ! assertEquals(3, c);
!   },
[...]
There's no parachute



 There's a major bug, let's take
 another look at the code...
_$ = (function() {
   var registered = {};

    return {

!   !   notify: function(event, memo) {
!   !   ! if (registered[event] instanceof Array){
!   !   ! ! var handlers = [].concat(registered[event]);

!   !   ! ! for (var i=0, handler; (handler = handlers[i]); i++){
!   !   ! ! ! handler.call(this, memo);
!   !   ! ! }
!   !   ! }
!   !   },
!   !   !
!   !   watch: function(event, handler) {
!   !   ! if (typeof registered[event] === "undefined"){
!   !   ! ! registered[event] = [];
!   !   ! }
!   !   ! registered[event].push(handler);
!   !   }

   };
})();
_$ = (function() {
   var registered = {};

    return {

!   !   notify: function(event, memo) {
!   !   ! if (registered[event] instanceof Array){
!   !   ! ! var handlers = [].concat(registered[event]);

!   !   ! ! for (var i=0, handler; (handler = handlers[i]); i++){
!   !   ! ! ! handler.call(this, memo);
!   !   ! ! }
!   !   ! }
!   !   },
!   !   !
!   !   watch: function(event, handler) {
!   !   ! if (typeof registered[event] === "undefined"){
!   !   ! ! registered[event] = [];
!   !   ! }
!   !   ! registered[event].push(handler);
!   !   }

   };
})();
There's no parachute



 How would you write a test to
 check it?
[...]
!   testNotifyWithMultipleWhatches: function(){!
                                               !
!   ! var a = 0, b = 0;!
!   ! _$.watch('testNotify', function(memo){ a = memo.test; });
!   ! _$.watch('testNotify', function(memo){ b = memo.test; });
!   ! _$.notify('testNotify', {test: 1});

!   ! assertEquals(1, a);
!   ! assertEquals(1, b);
!   },
[...]
[...]
!   testWhatchWithoutHandler: function(){! !
!   ! var a = 0, b = 0;!
!   ! _$.watch('testNotify', function(memo){ a = memo.test; });
!   ! _$.watch('testNotify');
!   ! _$.watch('testNotify', function(memo){ b = memo.test; });
!   ! _$.notify('testNotify', {test: 1});

!   ! assertEquals(1, a);
!   ! assertEquals(1, b);
!   },
[...]
_$ = (function() {
   var registered = {};

    return {

!   !   notify: function(event, memo) {
!   !   ! if (registered[event] instanceof Array){
!   !   ! ! var handlers = [].concat(registered[event]);

!   !   ! ! for (var i=0, handler; (handler = handlers[i]); i++){
!   !   ! ! ! handler.call(this, memo);
!   !   ! ! }
!   !   ! }
!   !   },
!   !   !
!   !   watch: function(event, handler) {
!   !   ! if (handler) {
               if (typeof registered[event] === "undefined"){
    !   ! ! ! registered[event] = [];
    !   ! ! }

    !   !   !   registered[event].push(handler);
            }
!   !   }

   };
})();
_$    = (function (_) {

     return {

         notify: function (a, b, c, d) {
             for (d = -1, c = [].concat(_[a]); c[++d];) c[d](b);
         },

         watch: function (a, b) {
            if(b)(_[a] || (_[a] = [])).push(b);
         }

     }

})({});
Spy, Stub & Mock
Fake objects & methods
Sinon.js
Spies
   a function that
records arguments,
  return value, the
  value of this and
exception thrown (if
 any) for all its calls.
Spies                       Stub
   a function that         functions (spies) with
records arguments,           pre-programmed
  return value, the              behavior.
  value of this and
exception thrown (if
 any) for all its calls.
Spies                       Stub                    Mock
   a function that         functions (spies) with   functions (spies) with
records arguments,           pre-programmed           pre-programmed
  return value, the              behavior.           behavior (stubs) as
  value of this and                                      well as pre-
exception thrown (if                                    programmed
 any) for all its calls.                                expectations.
[...]
    testMyLibRegistersToSystemOnEvent: function(){!!
!   ! var spy = sinon.spy(_$, 'watch');!
!   ! //DO STUFF TO INIT YOUR LIB
!   ! assertTrue(spy.calledWith('SysyemOn'));
!   },
!   ! !
!   testMyLibLoggedNotLogged: function(){! !
!   ! var stub = sinon.stub(User, 'isLogged');!
!   ! stub.returns(true);
!   ! //DO STUFF && ASSERTIONS

!   !    stub.returns(false);
!   !    //DO STUFF && ASSERTIONS

!   },
[...]
[...]
    testMyLibRegistersToSystemOnEvent: function(){!!
!   ! var spy = sinon.spy(_$, 'watch');!
!   ! //DO STUFF TO INIT YOUR LIB
!   ! assertTrue(spy.calledWith('SystemOn'));
!   },
!   ! !
!   testMyLibLoggedNotLogged: function(){! !
!   ! var stub = sinon.stub(User, 'isLogged');!
!   ! stub.returns(true);
!   ! //DO STUFF && ASSERTIONS

!   !    stub.returns(false);
!   !    //DO STUFF && ASSERTIONS

!   },
[...]
[...]
    "test MyLib Registers To 'SystemOn' Event": function(){! !
!   ! var spy = sinon.spy(_$, 'watch');!
!   ! //DO STUFF TO INIT YOUR LIB
!   ! assertTrue(spy.calledWith('SystemOn'));
!   },
!   ! !
!   testMyLibLoggedNotLogged: function(){! !
!   ! var stub = sinon.stub(User, 'isLogged');!
!   ! stub.returns(true);
!   ! //DO STUFF && ASSERTIONS

!   !    stub.returns(false);
!   !    //DO STUFF && ASSERTIONS

!   },
[...]
[...]
    testMyLibRegistersToSystemOnEvent: function(){!!
!   ! var spy = sinon.spy(_$, 'watch');!
!   ! //DO STUFF TO INIT YOUR LIB
!   ! assertTrue(spy.calledWith('SystemOn'));
!   },
!   ! !
!   testMyLibLoggedNotLogged: function(){! !
!   ! var stub = sinon.stub(User, 'isLogged');!
!   ! stub.returns(true);
!   ! //DO STUFF && ASSERTIONS

!   !    stub.returns(false);
!   !    //DO STUFF && ASSERTIONS

!   },
[...]
[...]
    testMyLibRegistersToSystemOnEvent: function(){!!
!   ! var spy = sinon.spy(_$, 'watch');!
!   ! //DO STUFF TO INIT YOUR LIB
!   ! assertTrue(spy.calledWith('SystemOn'));
!   },
!   ! !
!   testMyLibLoggedNotLogged: function(){! !
!   ! var stub = sinon.stub(User, 'isLogged');!
!   ! stub.returns(true);
!   ! //DO STUFF && ASSERTIONS

!   !    stub.returns(false);
!   !    //DO STUFF && ASSERTIONS

!   },
[...]
[...]
    testMyLibRegistersToSystemOnEvent: function(){!!
!   ! var spy = sinon.spy(_$, 'watch');!
!   ! //DO STUFF TO INIT YOUR LIB
!   ! assertTrue(spy.calledWith('SystemOn'));
!   },
!   ! !
!   testMyLibLoggedNotLogged: function(){! !
!   ! var stub = sinon.stub(User, 'isLogged');!
!   ! stub.returns(true);
!   ! //DO STUFF && ASSERTIONS

!   !    stub.returns(false);
!   !    //DO STUFF && ASSERTIONS

!   },
[...]
[...]
    testMyLibRegistersToSystemOnEvent: function(){!!
!   ! var spy = sinon.spy(_$, 'watch');!
!   ! //DO STUFF TO INIT YOUR LIB
!   ! assertTrue(spy.calledWith('SystemOn'));
!   },
!   ! !
!   testMyLibLoggedNotLogged: function(){! !
!   ! var stub = sinon.stub(User, 'isLogged');!
!   ! stub.returns(true);
!   ! //DO STUFF && ASSERTIONS

!   !    stub.returns(false);
!   !    //DO STUFF && ASSERTIONS

!   },
[...]
[...]
    testMyLibRegistersToSystemOnEvent: function(){!!
!   ! var spy = sinon.spy(_$, 'watch');!
!   ! //DO STUFF TO INIT YOUR LIB
!   ! assertTrue(spy.calledWith('SystemOn'));
!   },
!   ! !
!   testMyLibLoggedNotLogged: function(){! !
!   ! var stub = sinon.stub(User, 'isLogged');!
!   ! stub.returns(true);
!   ! //DO STUFF && ASSERTIONS

!   !    stub.returns(false);
!   !    //DO STUFF && ASSERTIONS

!   },
[...]
[...]
    testMyLibRegistersToSystemOnEvent: function(){!!
!   ! var spy = sinon.spy(_$, 'watch');!
!   ! //DO STUFF TO INIT YOUR LIB
!   ! assertTrue(spy.calledWith('SystemOn'));
!   },
!   ! !
!   testMyLibLoggedNotLogged: function(){! !
!   ! var stub = sinon.stub(User, 'isLogged');!
!   ! stub.returns(true);
!   ! //DO STUFF && ASSERTIONS

!   !    stub.returns(false);
!   !    //DO STUFF && ASSERTIONS

!   },
[...]
[...]
    testMyLibRegistersToSystemOnEvent: function(){!!
!   ! var spy = sinon.spy(_$, 'watch');!
!   ! //DO STUFF TO INIT YOUR LIB
!   ! assertTrue(spy.calledWith('SystemOn'));
!   },
!   ! !
!   testMyLibLoggedNotLogged: function(){! !
!   ! var stub = sinon.stub(User, 'isLogged');!
!   ! stub.returns(true);
!   ! //DO STUFF && ASSERTIONS

!   !    stub.returns(false);
!   !    //DO STUFF && ASSERTIONS

!   },
[...]
[...]
    testMyLibRegistersToSystemOnEvent: function(){!!
!   ! var spy = sinon.spy(_$, 'watch');!
!   ! //DO STUFF TO INIT YOUR LIB
!   ! assertTrue(spy.calledWith('SystemOn'));
!   },
[...]
[...]
    //testMyLibRegistersToSystemOnEvent: function(){! !
!   ! //var spy = sinon.spy(_$, 'watch');!
!   ! //DO STUFF TO INIT YOUR LIB
!   ! //assertTrue(spy.calledWith('SysyemOn'));
!   //},
!
!   testMyLibRegistersToSystemOnEvent: function(){!!
!   ! var mock = sinon.mock(_$);
!   ! mock.expect('watch').calledWith('SysyemOn');
!   ! //DO STUFF TO INIT YOUR LIB
!   ! mock.verify();
!   },
[...]
[...]
    //testMyLibRegistersToSystemOnEvent: function(){! !
!   ! //var spy = sinon.spy(_$, 'watch');!
!   ! //DO STUFF TO INIT YOUR LIB
!   ! //assertTrue(spy.calledWith('SysyemOn'));
!   //},
!
!   testMyLibRegistersToSystemOnEvent: function(){!!
!   ! var mock = sinon.mock(_$);
!   ! mock.expect('watch').calledWith('SysyemOn');
!   ! //DO STUFF TO INIT YOUR LIB
!   ! mock.verify();
!   },
[...]
What are we going to do
svn co https://svn.dsgn.it/jstdd

cheat
config
dist
libs
tools
workshop
build.sh
build.bat
readme.txt
svn co https://svn.dsgn.it/jstdd

cheat                                           /config/
config                                            browsers.prop
dist                                             build.xml
libs                                             default.prop
tools
workshop
build.sh
build.bat
readme.txt
svn co https://svn.dsgn.it/jstdd

cheat                                             /config/
config                                              browsers.prop
dist                                 /libs/        build.xml
libs                                   base.js     default.prop
tools                                  sinon.js
workshop
build.sh
build.bat
readme.txt
svn co https://svn.dsgn.it/jstdd

cheat                                                /config/
config                                                 browsers.prop
dist                                    /libs/        build.xml
libs                                      base.js     default.prop
tools                  /tools/            sinon.js
workshop                 ant
build.sh                 browser
build.bat                jslint
readme.txt               JsTestDriver
svn co https://svn.dsgn.it/jstdd

cheat                                                /config/
config                                                 browsers.prop
dist                                    /libs/        build.xml
libs                                      base.js     default.prop
tools                  /tools/            sinon.js
workshop                 ant
build.sh                 browser
build.bat                jslint
readme.txt               JsTestDriver

                     /workshop/
                      append
                      find
                      syntax
svn co https://svn.dsgn.it/jstdd

cheat                                                        /config/
config                                                           browsers.prop
dist                                    /libs/                  build.xml
libs                                      base.js               default.prop
tools                  /tools/            sinon.js
workshop                 ant
build.sh                 browser
build.bat                jslint                      /append/
readme.txt               JsTestDriver                 src
                                                          append.js
                     /workshop/                       test
                      append                              append.test.js
                      find                             jsTestDriver.conf
                      syntax
svn co https://svn.dsgn.it/jstdd

cheat                                                        /config/
config                                                           browsers.prop
dist                                    /libs/                  build.xml
libs                                      base.js               default.prop
tools                  /tools/            sinon.js
workshop                 ant
build.sh                 browser
build.bat                jslint                      /append/
readme.txt               JsTestDriver                 src
                                                          append.js
                     /workshop/                       test
                      append                              append.test.js
                      find                             jsTestDriver.conf
                      syntax
                                         build append | sh build.sh append
A simple modular event driven app
  a javascript code highlighter with 3 components:


         syntax highlighter
         selected word highlighter
         finder
First step - syntax
  watch a SRC_LOADED event with the memo {file:'{{FILE_SRC}}'}
  highlight (wrap in a span with the keyword itself as classname)
     function => <span class="function">function</span>
     var, if ... else, for, return, ...
  notify SRC_READY with the memo {file:'{{EDITED_SRC}}'}
Second step - append
 watch previous SRC_READY
 create a div[id="src_container"] and fill it with the source
 append to document
 llisten dblclick event and notify SRC_HIGHLIGHT with this memo:
 {keyword:'{{HIGHLIGHTED_WORD}}'}
 manage the SRC_HIGHLIGHT notification
 <span class="highlight">{{HIGHLIGHTED_KEYWORKD}}</span>
Third step - find
  watch to SRC_READY
  create a div[id=form] and append inside of it
       input[type=text][id=search]
       input[type=button][id=submitBtn][value=Search]
  append the div to the document
  on click on submit notify a SRC_HIGHLIGHT event with memo
  {keyword:"{{SEARCHED_TEXT}}"}
Where are we now?
Costs of change
I Build So Consistently
Identify                         Build




           I Build So Consistently




Share               make it Continuous
Back To The Front - Javascript Test Driven Development is between us (workshop)

More Related Content

What's hot

JavascriptMVC
JavascriptMVCJavascriptMVC
JavascriptMVC4lb0
 
A slew of AACM 50th anniversary celebrations this weekend
A slew of AACM 50th anniversary celebrations this weekendA slew of AACM 50th anniversary celebrations this weekend
A slew of AACM 50th anniversary celebrations this weekendchicagonewsyesterday
 
QCON SP 2014: 10 dicas de desempenho para apps mobile hibridas
QCON SP 2014: 10 dicas de desempenho para apps mobile hibridasQCON SP 2014: 10 dicas de desempenho para apps mobile hibridas
QCON SP 2014: 10 dicas de desempenho para apps mobile hibridasLoiane Groner
 
Apresentação jQuery 1
Apresentação jQuery 1Apresentação jQuery 1
Apresentação jQuery 1douglasgrava
 
Here's the Downtown Sound lineup for 2015
Here's the Downtown Sound lineup for 2015Here's the Downtown Sound lineup for 2015
Here's the Downtown Sound lineup for 2015chicagonewsyesterday
 
Pianist and composer Jeff Kowalkowski releases strong new trio album
Pianist and composer Jeff Kowalkowski releases strong new trio albumPianist and composer Jeff Kowalkowski releases strong new trio album
Pianist and composer Jeff Kowalkowski releases strong new trio albumirwinvifxcfesre
 
JavaScript de qualidade: hoje, amanhã e sempre!
JavaScript de qualidade: hoje, amanhã e sempre!JavaScript de qualidade: hoje, amanhã e sempre!
JavaScript de qualidade: hoje, amanhã e sempre!Thiago de Oliveira Pires
 
Chief Keef's hologram can't catch a break, and it's a win for Keef
Chief Keef's hologram can't catch a break, and it's a win for KeefChief Keef's hologram can't catch a break, and it's a win for Keef
Chief Keef's hologram can't catch a break, and it's a win for Keefchicagonewsonlineradio
 
Javascript and jQuery for Mobile
Javascript and jQuery for MobileJavascript and jQuery for Mobile
Javascript and jQuery for MobileIvano Malavolta
 
2015 Key Ingredient Cook-Off
2015 Key Ingredient Cook-Off2015 Key Ingredient Cook-Off
2015 Key Ingredient Cook-Offirwinvifxcfesre
 
Practical JavaScript Programming - Session 2/8
Practical JavaScript Programming - Session 2/8Practical JavaScript Programming - Session 2/8
Practical JavaScript Programming - Session 2/8Wilson Su
 
アプリ設定の保存をシンプルに
アプリ設定の保存をシンプルにアプリ設定の保存をシンプルに
アプリ設定の保存をシンプルにsusan335
 

What's hot (20)

JavascriptMVC
JavascriptMVCJavascriptMVC
JavascriptMVC
 
A slew of AACM 50th anniversary celebrations this weekend
A slew of AACM 50th anniversary celebrations this weekendA slew of AACM 50th anniversary celebrations this weekend
A slew of AACM 50th anniversary celebrations this weekend
 
QCON SP 2014: 10 dicas de desempenho para apps mobile hibridas
QCON SP 2014: 10 dicas de desempenho para apps mobile hibridasQCON SP 2014: 10 dicas de desempenho para apps mobile hibridas
QCON SP 2014: 10 dicas de desempenho para apps mobile hibridas
 
Poetry in the age of hip-hop
Poetry in the age of hip-hopPoetry in the age of hip-hop
Poetry in the age of hip-hop
 
Apresentação jQuery 1
Apresentação jQuery 1Apresentação jQuery 1
Apresentação jQuery 1
 
Jquery Framework
Jquery FrameworkJquery Framework
Jquery Framework
 
Here's the Downtown Sound lineup for 2015
Here's the Downtown Sound lineup for 2015Here's the Downtown Sound lineup for 2015
Here's the Downtown Sound lineup for 2015
 
Pianist and composer Jeff Kowalkowski releases strong new trio album
Pianist and composer Jeff Kowalkowski releases strong new trio albumPianist and composer Jeff Kowalkowski releases strong new trio album
Pianist and composer Jeff Kowalkowski releases strong new trio album
 
Best Fried Chicken
Best Fried ChickenBest Fried Chicken
Best Fried Chicken
 
JavaScript de qualidade: hoje, amanhã e sempre!
JavaScript de qualidade: hoje, amanhã e sempre!JavaScript de qualidade: hoje, amanhã e sempre!
JavaScript de qualidade: hoje, amanhã e sempre!
 
Chief Keef's hologram can't catch a break, and it's a win for Keef
Chief Keef's hologram can't catch a break, and it's a win for KeefChief Keef's hologram can't catch a break, and it's a win for Keef
Chief Keef's hologram can't catch a break, and it's a win for Keef
 
Javascript and jQuery for Mobile
Javascript and jQuery for MobileJavascript and jQuery for Mobile
Javascript and jQuery for Mobile
 
Service Workers
Service WorkersService Workers
Service Workers
 
2015 Key Ingredient Cook-Off
2015 Key Ingredient Cook-Off2015 Key Ingredient Cook-Off
2015 Key Ingredient Cook-Off
 
Best hotel
Best hotelBest hotel
Best hotel
 
Practical JavaScript Programming - Session 2/8
Practical JavaScript Programming - Session 2/8Practical JavaScript Programming - Session 2/8
Practical JavaScript Programming - Session 2/8
 
Index2
Index2Index2
Index2
 
Get more votes!
Get more votes!Get more votes!
Get more votes!
 
Best gourmet market
Best gourmet marketBest gourmet market
Best gourmet market
 
アプリ設定の保存をシンプルに
アプリ設定の保存をシンプルにアプリ設定の保存をシンプルに
アプリ設定の保存をシンプルに
 

Viewers also liked

The Spirit of Testing
The Spirit of TestingThe Spirit of Testing
The Spirit of TestingMarco Cedaro
 
jsDay - Javascript as a programming language
jsDay - Javascript as a programming languagejsDay - Javascript as a programming language
jsDay - Javascript as a programming languageMarco Cedaro
 
FFWD.PRO - It's not you, It's me (or how to avoid being coupled with a Javasc...
FFWD.PRO - It's not you, It's me (or how to avoid being coupled with a Javasc...FFWD.PRO - It's not you, It's me (or how to avoid being coupled with a Javasc...
FFWD.PRO - It's not you, It's me (or how to avoid being coupled with a Javasc...Marco Cedaro
 
YOOX Launch & Learn - Javascript as a programming language
 YOOX Launch & Learn - Javascript as a programming language YOOX Launch & Learn - Javascript as a programming language
YOOX Launch & Learn - Javascript as a programming languageMarco Cedaro
 
JsDay - It's not you, It's me (or how to avoid being coupled with a Javascrip...
JsDay - It's not you, It's me (or how to avoid being coupled with a Javascrip...JsDay - It's not you, It's me (or how to avoid being coupled with a Javascrip...
JsDay - It's not you, It's me (or how to avoid being coupled with a Javascrip...Marco Cedaro
 
A developers' journey into building automated tests for IT from the ground up
A developers' journey into building automated tests for IT from the ground upA developers' journey into building automated tests for IT from the ground up
A developers' journey into building automated tests for IT from the ground upstefanorago
 

Viewers also liked (6)

The Spirit of Testing
The Spirit of TestingThe Spirit of Testing
The Spirit of Testing
 
jsDay - Javascript as a programming language
jsDay - Javascript as a programming languagejsDay - Javascript as a programming language
jsDay - Javascript as a programming language
 
FFWD.PRO - It's not you, It's me (or how to avoid being coupled with a Javasc...
FFWD.PRO - It's not you, It's me (or how to avoid being coupled with a Javasc...FFWD.PRO - It's not you, It's me (or how to avoid being coupled with a Javasc...
FFWD.PRO - It's not you, It's me (or how to avoid being coupled with a Javasc...
 
YOOX Launch & Learn - Javascript as a programming language
 YOOX Launch & Learn - Javascript as a programming language YOOX Launch & Learn - Javascript as a programming language
YOOX Launch & Learn - Javascript as a programming language
 
JsDay - It's not you, It's me (or how to avoid being coupled with a Javascrip...
JsDay - It's not you, It's me (or how to avoid being coupled with a Javascrip...JsDay - It's not you, It's me (or how to avoid being coupled with a Javascrip...
JsDay - It's not you, It's me (or how to avoid being coupled with a Javascrip...
 
A developers' journey into building automated tests for IT from the ground up
A developers' journey into building automated tests for IT from the ground upA developers' journey into building automated tests for IT from the ground up
A developers' journey into building automated tests for IT from the ground up
 

Back To The Front - Javascript Test Driven Development is between us (workshop)

  • 1. back to the front javascript tdd is between us
  • 2. Who are we? Marco Cedaro Luca Lischetti javascript pirate, arr 8-bit lover and super hero Spreaker Frontend Developer (almost) Shazam Frontend Developer
  • 3. Who are we? Marco Cedaro Luca Lischetti javascript pirate, arr 8-bit lover and super hero Spreaker Frontend Developer (almost) Shazam Frontend Developer The content of this workshop do not necessarily reflect the opinion of authors employers
  • 4. Who are we? Marco Cedaro Luca Lischetti javascript pirate, arr 8-bit lover and super hero Spreaker Frontend Developer (almost) Shazam Frontend Developer The content of this workshop do not necessarily reflect the opinion of authors employers Authors employers are not responsible in any way of authors bad coding and funny spoken english
  • 5. I believe I can fly
  • 9. TDD is about control
  • 11. The curious case of JavaScript unit testing
  • 12. Unit Test and Functional Test
  • 13. Pro/Cons test consistency control interaction against execution test over between external time integration codebase libraries changes
  • 15.
  • 16. Unit testing is supposed to test a single atomic “unit” of functionality without dependencies on anything else
  • 17. Unit testing is This is where you supposed to test a start to run into single atomic “unit” serious dependency of functionality problems due to the without interrelation HTML dependencies on and CSS anything else
  • 18. Unit testing is This is where you What do you test? supposed to test a start to run into Usually how the user single atomic “unit” serious dependency interface responds of functionality problems due to the to user input. without interrelation HTML Actually, the realm of dependencies on and CSS functional testing anything else
  • 19. How does it work?
  • 20. have you seen LOST?
  • 21.
  • 22. Write a new test
  • 23. Write a new test Run test & let it fail
  • 24. Write a new test Run test & let it fail Write the code
  • 25. Write a new test Run test & let it fail Write the code Run test & let it succeed
  • 26. Write a new test Run test & let it fail Write the code Run test & let it succeed Refactor your code
  • 28. _$ = (function() { var registered = {}; return { ! ! notify: function(event, memo) { ! ! ! if (registered[event] instanceof Array){ ! ! ! ! var handlers = [].concat(registered[event]); ! ! ! ! for (var i=0, handler; (handler = handlers[i]); i++){ ! ! ! ! ! handler.call(this, memo); ! ! ! ! } ! ! ! } ! ! }, ! ! ! ! ! watch: function(event, handler) { ! ! ! if (typeof registered[event] === "undefined"){ ! ! ! ! registered[event] = []; ! ! ! } ! ! ! registered[event].push(handler); ! ! } }; })();
  • 30. _$ = (function() { var registered = {}; return { ! ! notify: function(event, memo) { ! ! ! if (registered[event] instanceof Array){ ! ! ! ! var handlers = [].concat(registered[event]); ! ! ! ! for (var i=0, handler; (handler = handlers[i]); i++){ ! ! ! ! ! handler.call(this, memo); ! ! ! ! } ! ! ! } ! ! }, ! ! ! ! ! watch: function(event, handler) { ! ! ! if (typeof registered[event] === "undefined"){ ! ! ! ! registered[event] = []; ! ! ! } ! ! ! registered[event].push(handler); ! ! } }; })();
  • 31. _$.watch("customEvent", function(obj) { ! //DO STUFF }); _$.notify("customEvent"); _$.notify("customEvent", { prop : "value" });
  • 32. _$.watch("customEvent", function(obj) { ! //DO STUFF }); _$.notify("customEvent"); _$.notify("customEvent", { prop : "value" });
  • 33. _$ = (function() { var registered = {}; return { ! ! notify: function(event, memo) { ! ! ! if (registered[event] instanceof Array){ ! ! ! ! var handlers = [].concat(registered[event]); ! ! ! ! for (var i=0, handler; (handler = handlers[i]); i++){ ! ! ! ! ! handler.call(this, memo); ! ! ! ! } ! ! ! } ! ! }, ! ! ! ! ! watch: function(event, handler) { ! ! ! if (typeof registered[event] === "undefined"){ ! ! ! ! registered[event] = []; ! ! ! } ! ! ! registered[event].push(handler); ! ! } }; })();
  • 34. _$ = (function() { var registered = {}; return { ! ! notify: function(event, memo) { ! ! ! if (registered[event] instanceof Array){ ! ! ! ! var handlers = [].concat(registered[event]); ! ! ! ! for (var i=0, handler; (handler = handlers[i]); i++){ ! ! ! ! ! handler.call(this, memo); ! ! ! ! } ! ! ! } ! ! }, ! ! ! ! ! watch: function(event, handler) { ! ! ! if (typeof registered[event] === "undefined"){ ! ! ! ! registered[event] = []; ! ! ! } ! ! ! registered[event].push(handler); ! ! } }; })();
  • 35. _$ = (function() { var registered = {}; return { ! ! notify: function(event, memo) { ! ! ! if (registered[event] instanceof Array){ ! ! ! ! var handlers = [].concat(registered[event]); ! ! ! ! for (var i=0, handler; (handler = handlers[i]); i++){ ! ! ! ! ! handler.call(this, memo); ! ! ! ! } ! ! ! } ! ! }, ! ! ! ! ! watch: function(event, handler) { ! ! ! if (typeof registered[event] === "undefined"){ ! ! ! ! registered[event] = []; ! ! ! } ! ! ! registered[event].push(handler); ! ! } }; })();
  • 36. _$ = (function() { var registered = {}; return { ! ! notify: function(event, memo) { ! ! ! if (registered[event] instanceof Array){ ! ! ! ! var handlers = [].concat(registered[event]); ! ! ! ! for (var i=0, handler; (handler = handlers[i]); i++){ ! ! ! ! ! handler.call(this, memo); ! ! ! ! } ! ! ! } ! ! }, ! ! ! ! ! watch: function(event, handler) { ! ! ! if (typeof registered[event] === "undefined"){ ! ! ! ! registered[event] = []; ! ! ! } ! ! ! registered[event].push(handler); ! ! } }; })();
  • 37. _$ = (function() { var registered = {}; return { ! ! notify: function(event, memo) { ! ! ! if (registered[event] instanceof Array){ ! ! ! ! var handlers = [].concat(registered[event]); ! ! ! ! for (var i=0, handler; (handler = handlers[i]); i++){ ! ! ! ! ! handler.call(this, memo); ! ! ! ! } ! ! ! } ! ! }, ! ! ! ! ! watch: function(event, handler) { ! ! ! if (typeof registered[event] === "undefined"){ ! ! ! ! registered[event] = []; ! ! ! } ! ! ! registered[event].push(handler); ! ! } }; })();
  • 38. _$ = (function() { var registered = {}; return { ! ! notify: function(event, memo) { ! ! ! if (registered[event] instanceof Array){ ! ! ! ! var handlers = [].concat(registered[event]); ! ! ! ! for (var i=0, handler; (handler = handlers[i]); i++){ ! ! ! ! ! handler.call(this, memo); ! ! ! ! } ! ! ! } ! ! }, ! ! ! ! ! watch: function(event, handler) { ! ! ! if (typeof registered[event] === "undefined"){ ! ! ! ! registered[event] = []; ! ! ! } ! ! ! registered[event].push(handler); ! ! } }; })();
  • 39. _$.watch("customEvent", function(obj) { ! //DO STUFF }); _$.notify("customEvent"); _$.notify("customEvent", { prop : "value" });
  • 40. _$ = (function() { var registered = {}; return { ! ! notify: function(event, memo) { ! ! ! if (registered[event] instanceof Array){ ! ! ! ! var handlers = [].concat(registered[event]); ! ! ! ! for (var i=0, handler; (handler = handlers[i]); i++){ ! ! ! ! ! handler.call(this, memo); ! ! ! ! } ! ! ! } ! ! }, ! ! ! ! ! watch: function(event, handler) { ! ! ! if (typeof registered[event] === "undefined"){ ! ! ! ! registered[event] = []; ! ! ! } ! ! ! registered[event].push(handler); ! ! } }; })();
  • 41. _$ = (function() { var registered = {}; return { ! ! notify: function(event, memo) { ! ! ! if (registered[event] instanceof Array){ ! ! ! ! var handlers = [].concat(registered[event]); ! ! ! ! for (var i=0, handler; (handler = handlers[i]); i++){ ! ! ! ! ! handler.call(this, memo); ! ! ! ! } ! ! ! } ! ! }, ! ! ! ! ! watch: function(event, handler) { ! ! ! if (typeof registered[event] === "undefined"){ ! ! ! ! registered[event] = []; ! ! ! } ! ! ! registered[event].push(handler); ! ! } }; })();
  • 42. _$ = (function() { var registered = {}; return { ! ! notify: function(event, memo) { ! ! ! if (registered[event] instanceof Array){ ! ! ! ! var handlers = [].concat(registered[event]); ! ! ! ! for (var i=0, handler; (handler = handlers[i]); i++){ ! ! ! ! ! handler.call(this, memo); ! ! ! ! } ! ! ! } ! ! }, ! ! ! ! ! watch: function(event, handler) { ! ! ! if (typeof registered[event] === "undefined"){ ! ! ! ! registered[event] = []; ! ! ! } ! ! ! registered[event].push(handler); ! ! } }; })();
  • 43. _$ = (function() { var registered = {}; return { ! ! notify: function(event, memo) { ! ! ! if (registered[event] instanceof Array){ ! ! ! ! var handlers = [].concat(registered[event]); ! ! ! ! for (var i=0, handler; (handler = handlers[i]); i++){ ! ! ! ! ! handler.call(this, memo); ! ! ! ! } ! ! ! } ! ! }, ! ! ! ! ! watch: function(event, handler) { ! ! ! if (typeof registered[event] === "undefined"){ ! ! ! ! registered[event] = []; ! ! ! } ! ! ! registered[event].push(handler); ! ! } }; })();
  • 44. _$ = (function() { var registered = {}; return { ! ! notify: function(event, memo) { ! ! ! if (registered[event] instanceof Array){ ! ! ! ! var handlers = [].concat(registered[event]); ! ! ! ! for (var i=0, handler; (handler = handlers[i]); i++){ ! ! ! ! ! handler.call(this, memo); ! ! ! ! } ! ! ! } ! ! }, ! ! ! ! ! watch: function(event, handler) { ! ! ! if (typeof registered[event] === "undefined"){ ! ! ! ! registered[event] = []; ! ! ! } ! ! ! registered[event].push(handler); ! ! } }; })();
  • 45. _$ = (function() { var registered = {}; return { ! ! notify: function(event, memo) { ! ! ! if (registered[event] instanceof Array){ ! ! ! ! var handlers = [].concat(registered[event]); ! ! ! ! for (var i=0, handler; (handler = handlers[i]); i++){ ! ! ! ! ! handler.call(this, memo); ! ! ! ! } ! ! ! } ! ! }, ! ! ! ! ! watch: function(event, handler) { ! ! ! if (typeof registered[event] === "undefined"){ ! ! ! ! registered[event] = []; ! ! ! } ! ! ! registered[event].push(handler); ! ! } }; })();
  • 46. _$ = (function() { var registered = {}; return { ! ! notify: function(event, memo) { ! ! ! if (registered[event] instanceof Array){ ! ! ! ! var handlers = [].concat(registered[event]); ! ! ! ! for (var i=0, handler; (handler = handlers[i]); i++){ ! ! ! ! ! handler.call(this, memo); ! ! ! ! } ! ! ! } ! ! }, ! ! ! ! ! watch: function(event, handler) { ! ! ! if (typeof registered[event] === "undefined"){ ! ! ! ! registered[event] = []; ! ! ! } ! ! ! registered[event].push(handler); ! ! } }; })();
  • 47. _$ = (function (_) { return { notify: function (a, b, c, d) { for (d = -1, c = [].concat(_[a]); c[++d];) c[d](b); }, watch: function (a, b) { (_[a] || (_[a] = [])).push(b); } } })({});
  • 48. [...] testNotify: function(){! ! ! ! var a = 0;! ! ! _$.watch('testNotify', function(){ a = 1; }); ! ! _$.notify('testNotify'); ! ! assertEquals(1, a); ! }, ! ! ! ! testNotifyWithMemo: function(){! ! ! ! var a = 0 ;! ! ! _$.watch('testNotify', function(memo){ a = memo.test; }); ! ! _$.notify('testNotify', {test: 1}); ! ! assertEquals(1, a); ! }, [...]
  • 49. [...] testNotify: function(){! ! ! ! var a = 0;! ! ! _$.watch('testNotify', function(){ a = 1; }); ! ! _$.notify('testNotify'); ! ! assertEquals(1, a); ! }, ! ! ! ! testNotifyWithMemo: function(){! ! ! ! var a = 0 ;! ! ! _$.watch('testNotify', function(memo){ a = memo.test; }); ! ! _$.notify('testNotify', {test: 1}); ! ! assertEquals(1, a); ! }, [...]
  • 50. [...] testNotify: function(){! ! ! ! var a = 0;! ! ! _$.watch('testNotify', function(){ a = 1; }); ! ! _$.notify('testNotify'); ! ! assertEquals(1, a); ! }, ! ! ! ! testNotifyWithMemo: function(){! ! ! ! var a = 0 ;! ! ! _$.watch('testNotify', function(memo){ a = memo.test; }); ! ! _$.notify('testNotify', {test: 1}); ! ! assertEquals(1, a); ! }, [...]
  • 51. [...] testNotify: function(){! ! ! ! var a = 0;! ! ! _$.watch('testNotify', function(){ a = 1; }); ! ! _$.notify('testNotify'); ! ! assertEquals(1, a); ! }, ! ! ! ! testNotifyWithMemo: function(){! ! ! ! var a = 0 ;! ! ! _$.watch('testNotify', function(memo){ a = memo.test; }); ! ! _$.notify('testNotify', {test: 1}); ! ! assertEquals(1, a); ! }, [...]
  • 52. [...] testNotify: function(){! ! ! ! var a = 0;! ! ! _$.watch('testNotify', function(){ a = 1; }); ! ! _$.notify('testNotify'); ! ! assertEquals(1, a); ! }, ! ! ! ! testNotifyWithMemo: function(){! ! ! ! var a = 0 ;! ! ! _$.watch('testNotify', function(memo){ a = memo.test; }); ! ! _$.notify('testNotify', {test: 1}); ! ! assertEquals(1, a); ! }, [...]
  • 53. [...] testNotify: function(){! ! ! ! var a = 0;! ! ! _$.watch('testNotify', function(){ a = 1; }); ! ! _$.notify('testNotify'); ! ! assertEquals(1, a); ! }, ! ! ! ! testNotifyWithMemo: function(){! ! ! ! var a = 0 ;! ! ! _$.watch('testNotify', function(memo){ a = memo.test; }); ! ! _$.notify('testNotify', {test: 1}); ! ! assertEquals(1, a); ! }, [...]
  • 54. [...] testNotify: function(){! ! ! ! var a = 0;! ! ! _$.watch('testNotify', function(){ a = 1; }); ! ! _$.notify('testNotify'); ! ! assertEquals(1, a); ! }, ! ! ! ! testNotifyWithMemo: function(){! ! ! ! var a = 0 ;! ! ! _$.watch('testNotify', function(memo){ a = memo.test; }); ! ! _$.notify('testNotify', {test: 1}); ! ! assertEquals(1, a); ! }, [...]
  • 55. [...] ! testNotifyWithMultipleWhatches: function(){! ! ! ! var a = 0, b = 0;! ! ! _$.watch('testNotify', function(memo){ a = memo.test; }); ! ! _$.watch('testNotify', function(memo){ b = memo.test; }); ! ! _$.notify('testNotify', {test: 1}); ! ! assertEquals(1, a); ! ! assertEquals(1, b); ! }, [...]
  • 56. [...] ! testNotifyWithMultipleWhatches: function(){! ! ! ! var a = 0, b = 0;! ! ! _$.watch('testNotify', function(memo){ a = memo.test; }); ! ! _$.watch('testNotify', function(memo){ b = memo.test; }); ! ! _$.notify('testNotify', {test: 1}); ! ! assertEquals(1, a); ! ! assertEquals(1, b); ! }, [...]
  • 57. [...] ! testNotifyWithMultipleWhatches: function(){! ! ! ! var a = 0, b = 0;! ! ! _$.watch('testNotify', function(memo){ a = memo.test; }); ! ! _$.watch('testNotify', function(memo){ b = memo.test; }); ! ! _$.notify('testNotify', {test: 1}); ! ! assertEquals(1, a); ! ! assertEquals(1, b); ! }, [...]
  • 58. [...] testNotifyWithMultipleWhatchesNested: function(){!! ! ! var a = 0, b = 0, c=0;! ! ! _$.watch('testNotify', function(memo){ a = memo.test; ! ! ! _$.watch('testNotify', function(memo){ ! ! ! ! if (b<2){ b = memo.test; } else { c = memo.test; } ! ! ! }); ! ! }); ! ! ! ! _$.notify('testNotify', {test: 1}); ! ! assertEquals(1, a); ! ! assertEquals(0, b); ! ! assertEquals(0, c); ! ! ! ! _$.notify('testNotify', {test: 2}); ! ! assertEquals(2, a); ! ! assertEquals(2, b); ! ! assertEquals(0, c); ! ! ! ! _$.notify('testNotify', {test: 3}); ! ! assertEquals(3, a); ! ! assertEquals(2, b); ! ! assertEquals(3, c); ! }, [...]
  • 59. [...] testNotifyWithMultipleWhatchesNested: function(){!! ! ! var a = 0, b = 0, c=0;! ! ! _$.watch('testNotify', function(memo){ a = memo.test; ! ! ! _$.watch('testNotify', function(memo){ ! ! ! ! if (b<2){ b = memo.test; } else { c = memo.test; } ! ! ! }); ! ! }); ! ! ! ! _$.notify('testNotify', {test: 1}); ! ! assertEquals(1, a); ! ! assertEquals(0, b); ! ! assertEquals(0, c); ! ! ! ! _$.notify('testNotify', {test: 2}); ! ! assertEquals(2, a); ! ! assertEquals(2, b); ! ! assertEquals(0, c); ! ! ! ! _$.notify('testNotify', {test: 3}); ! ! assertEquals(3, a); ! ! assertEquals(2, b); ! ! assertEquals(3, c); ! }, [...]
  • 60. [...] testNotifyWithMultipleWhatchesNested: function(){!! ! ! var a = 0, b = 0, c=0;! ! ! _$.watch('testNotify', function(memo){ a = memo.test; ! ! ! _$.watch('testNotify', function(memo){ ! ! ! ! if (b<2){ b = memo.test; } else { c = memo.test; } ! ! ! }); ! ! }); ! ! ! ! _$.notify('testNotify', {test: 1}); ! ! assertEquals(1, a); ! ! assertEquals(0, b); ! ! assertEquals(0, c); ! ! ! ! _$.notify('testNotify', {test: 2}); ! ! assertEquals(2, a); ! ! assertEquals(2, b); ! ! assertEquals(0, c); ! ! ! ! _$.notify('testNotify', {test: 3}); ! ! assertEquals(3, a); ! ! assertEquals(2, b); ! ! assertEquals(3, c); ! }, [...]
  • 61. [...] testNotifyWithMultipleWhatchesNested: function(){!! ! ! var a = 0, b = 0, c=0;! ! ! _$.watch('testNotify', function(memo){ a = memo.test; ! ! ! _$.watch('testNotify', function(memo){ ! ! ! ! if (b<2){ b = memo.test; } else { c = memo.test; } ! ! ! }); ! ! }); ! ! ! ! _$.notify('testNotify', {test: 1}); ! ! assertEquals(1, a); ! ! assertEquals(0, b); ! ! assertEquals(0, c); ! ! ! ! _$.notify('testNotify', {test: 2}); ! ! assertEquals(2, a); ! ! assertEquals(2, b); ! ! assertEquals(0, c); ! ! ! ! _$.notify('testNotify', {test: 3}); ! ! assertEquals(3, a); ! ! assertEquals(2, b); ! ! assertEquals(3, c); ! }, [...]
  • 62. [...] testNotifyWithMultipleWhatchesNested: function(){!! ! ! var a = 0, b = 0, c=0;! ! ! _$.watch('testNotify', function(memo){ a = memo.test; ! ! ! _$.watch('testNotify', function(memo){ ! ! ! ! if (b<2){ b = memo.test; } ! ! ! ! else { c = memo.test; } ! ! ! }); ! ! }); ! ! ! ! _$.notify('testNotify', {test: 1}); ! ! assertEquals(1, a); ! ! assertEquals(0, b); ! ! assertEquals(0, c); ! ! ! ! _$.notify('testNotify', {test: 2}); ! ! assertEquals(2, a); ! ! assertEquals(2, b); ! ! assertEquals(0, c); ! ! ! ! _$.notify('testNotify', {test: 3}); ! ! assertEquals(3, a); ! ! assertEquals(2, b); ! ! assertEquals(3, c); ! }, [...]
  • 63. [...] testNotifyWithMultipleWhatchesNested: function(){!! ! ! var a = 0, b = 0, c=0;! ! ! _$.watch('testNotify', function(memo){ a = memo.test; ! ! ! _$.watch('testNotify', function(memo){ ! ! ! ! if (b<2){ b = memo.test; } else { c = memo.test; } ! ! ! }); ! ! }); ! ! ! ! _$.notify('testNotify', {test: 1}); ! ! assertEquals(1, a); ! ! assertEquals(0, b); ! ! assertEquals(0, c); ! ! ! ! _$.notify('testNotify', {test: 2}); ! ! assertEquals(2, a); ! ! assertEquals(2, b); ! ! assertEquals(0, c); ! ! ! ! _$.notify('testNotify', {test: 3}); ! ! assertEquals(3, a); ! ! assertEquals(2, b); ! ! assertEquals(3, c); ! }, [...]
  • 64. [...] testNotifyWithMultipleWhatchesNested: function(){!! ! ! var a = 0, b = 0, c=0;! ! ! _$.watch('testNotify', function(memo){ a = memo.test; ! ! ! _$.watch('testNotify', function(memo){ ! ! ! ! if (b<2){ b = memo.test; } else { c = memo.test; } ! ! ! }); ! ! }); ! ! ! ! _$.notify('testNotify', {test: 1}); ! ! assertEquals(1, a); ! ! assertEquals(0, b); ! ! assertEquals(0, c); ! ! ! ! _$.notify('testNotify', {test: 2}); ! ! assertEquals(2, a); ! ! assertEquals(2, b); ! ! assertEquals(0, c); ! ! ! ! _$.notify('testNotify', {test: 3}); ! ! assertEquals(3, a); ! ! assertEquals(2, b); ! ! assertEquals(3, c); ! }, [...]
  • 65. [...] testNotifyWithMultipleWhatchesNested: function(){!! ! ! var a = 0, b = 0, c=0;! ! ! _$.watch('testNotify', function(memo){ a = memo.test; ! ! ! _$.watch('testNotify', function(memo){ ! ! ! ! if (b<2){ b = memo.test; } else { c = memo.test; } ! ! ! }); ! ! }); ! ! ! ! _$.notify('testNotify', {test: 1}); ! ! assertEquals(1, a); ! ! assertEquals(0, b); ! ! assertEquals(0, c); ! ! ! ! _$.notify('testNotify', {test: 2}); ! ! assertEquals(2, a); ! ! assertEquals(2, b); ! ! assertEquals(0, c); ! ! ! ! _$.notify('testNotify', {test: 3}); ! ! assertEquals(3, a); ! ! assertEquals(2, b); ! ! assertEquals(3, c); ! }, [...]
  • 66. [...] testNotifyWithMultipleWhatchesNested: function(){!! ! ! var a = 0, b = 0, c=0;! ! ! _$.watch('testNotify', function(memo){ a = memo.test; ! ! ! _$.watch('testNotify', function(memo){ ! ! ! ! if (b<2){ b = memo.test; } else { c = memo.test; } ! ! ! }); ! ! }); ! ! ! ! _$.notify('testNotify', {test: 1}); ! ! assertEquals(1, a); ! ! assertEquals(0, b); ! ! assertEquals(0, c); ! ! ! ! _$.notify('testNotify', {test: 2}); ! ! assertEquals(2, a); ! ! assertEquals(2, b); ! ! assertEquals(0, c); ! ! ! ! _$.notify('testNotify', {test: 3}); ! ! assertEquals(3, a); ! ! assertEquals(2, b); ! ! assertEquals(3, c); ! }, [...]
  • 67. [...] testNotifyWithMultipleWhatchesNested: function(){!! ! ! var a = 0, b = 0, c=0;! ! ! _$.watch('testNotify', function(memo){ a = memo.test; ! ! ! _$.watch('testNotify', function(memo){ ! ! ! ! if (b<2){ b = memo.test; } else { c = memo.test; } ! ! ! }); ! ! }); ! ! ! ! _$.notify('testNotify', {test: 1}); ! ! assertEquals(1, a); ! ! assertEquals(0, b); ! ! assertEquals(0, c); ! ! ! ! _$.notify('testNotify', {test: 2}); ! ! assertEquals(2, a); ! ! assertEquals(2, b); ! ! assertEquals(0, c); ! ! ! ! _$.notify('testNotify', {test: 3}); ! ! assertEquals(3, a); ! ! assertEquals(2, b); ! ! assertEquals(3, c); ! }, [...]
  • 68. There's no parachute There's a major bug, let's take another look at the code...
  • 69. _$ = (function() { var registered = {}; return { ! ! notify: function(event, memo) { ! ! ! if (registered[event] instanceof Array){ ! ! ! ! var handlers = [].concat(registered[event]); ! ! ! ! for (var i=0, handler; (handler = handlers[i]); i++){ ! ! ! ! ! handler.call(this, memo); ! ! ! ! } ! ! ! } ! ! }, ! ! ! ! ! watch: function(event, handler) { ! ! ! if (typeof registered[event] === "undefined"){ ! ! ! ! registered[event] = []; ! ! ! } ! ! ! registered[event].push(handler); ! ! } }; })();
  • 70. _$ = (function() { var registered = {}; return { ! ! notify: function(event, memo) { ! ! ! if (registered[event] instanceof Array){ ! ! ! ! var handlers = [].concat(registered[event]); ! ! ! ! for (var i=0, handler; (handler = handlers[i]); i++){ ! ! ! ! ! handler.call(this, memo); ! ! ! ! } ! ! ! } ! ! }, ! ! ! ! ! watch: function(event, handler) { ! ! ! if (typeof registered[event] === "undefined"){ ! ! ! ! registered[event] = []; ! ! ! } ! ! ! registered[event].push(handler); ! ! } }; })();
  • 71. There's no parachute How would you write a test to check it?
  • 72. [...] ! testNotifyWithMultipleWhatches: function(){! ! ! ! var a = 0, b = 0;! ! ! _$.watch('testNotify', function(memo){ a = memo.test; }); ! ! _$.watch('testNotify', function(memo){ b = memo.test; }); ! ! _$.notify('testNotify', {test: 1}); ! ! assertEquals(1, a); ! ! assertEquals(1, b); ! }, [...]
  • 73. [...] ! testWhatchWithoutHandler: function(){! ! ! ! var a = 0, b = 0;! ! ! _$.watch('testNotify', function(memo){ a = memo.test; }); ! ! _$.watch('testNotify'); ! ! _$.watch('testNotify', function(memo){ b = memo.test; }); ! ! _$.notify('testNotify', {test: 1}); ! ! assertEquals(1, a); ! ! assertEquals(1, b); ! }, [...]
  • 74. _$ = (function() { var registered = {}; return { ! ! notify: function(event, memo) { ! ! ! if (registered[event] instanceof Array){ ! ! ! ! var handlers = [].concat(registered[event]); ! ! ! ! for (var i=0, handler; (handler = handlers[i]); i++){ ! ! ! ! ! handler.call(this, memo); ! ! ! ! } ! ! ! } ! ! }, ! ! ! ! ! watch: function(event, handler) { ! ! ! if (handler) { if (typeof registered[event] === "undefined"){ ! ! ! ! registered[event] = []; ! ! ! } ! ! ! registered[event].push(handler); } ! ! } }; })();
  • 75. _$ = (function (_) { return { notify: function (a, b, c, d) { for (d = -1, c = [].concat(_[a]); c[++d];) c[d](b); }, watch: function (a, b) { if(b)(_[a] || (_[a] = [])).push(b); } } })({});
  • 76. Spy, Stub & Mock
  • 77. Fake objects & methods
  • 79.
  • 80. Spies a function that records arguments, return value, the value of this and exception thrown (if any) for all its calls.
  • 81. Spies Stub a function that functions (spies) with records arguments, pre-programmed return value, the behavior. value of this and exception thrown (if any) for all its calls.
  • 82. Spies Stub Mock a function that functions (spies) with functions (spies) with records arguments, pre-programmed pre-programmed return value, the behavior. behavior (stubs) as value of this and well as pre- exception thrown (if programmed any) for all its calls. expectations.
  • 83. [...] testMyLibRegistersToSystemOnEvent: function(){!! ! ! var spy = sinon.spy(_$, 'watch');! ! ! //DO STUFF TO INIT YOUR LIB ! ! assertTrue(spy.calledWith('SysyemOn')); ! }, ! ! ! ! testMyLibLoggedNotLogged: function(){! ! ! ! var stub = sinon.stub(User, 'isLogged');! ! ! stub.returns(true); ! ! //DO STUFF && ASSERTIONS ! ! stub.returns(false); ! ! //DO STUFF && ASSERTIONS ! }, [...]
  • 84. [...] testMyLibRegistersToSystemOnEvent: function(){!! ! ! var spy = sinon.spy(_$, 'watch');! ! ! //DO STUFF TO INIT YOUR LIB ! ! assertTrue(spy.calledWith('SystemOn')); ! }, ! ! ! ! testMyLibLoggedNotLogged: function(){! ! ! ! var stub = sinon.stub(User, 'isLogged');! ! ! stub.returns(true); ! ! //DO STUFF && ASSERTIONS ! ! stub.returns(false); ! ! //DO STUFF && ASSERTIONS ! }, [...]
  • 85. [...] "test MyLib Registers To 'SystemOn' Event": function(){! ! ! ! var spy = sinon.spy(_$, 'watch');! ! ! //DO STUFF TO INIT YOUR LIB ! ! assertTrue(spy.calledWith('SystemOn')); ! }, ! ! ! ! testMyLibLoggedNotLogged: function(){! ! ! ! var stub = sinon.stub(User, 'isLogged');! ! ! stub.returns(true); ! ! //DO STUFF && ASSERTIONS ! ! stub.returns(false); ! ! //DO STUFF && ASSERTIONS ! }, [...]
  • 86. [...] testMyLibRegistersToSystemOnEvent: function(){!! ! ! var spy = sinon.spy(_$, 'watch');! ! ! //DO STUFF TO INIT YOUR LIB ! ! assertTrue(spy.calledWith('SystemOn')); ! }, ! ! ! ! testMyLibLoggedNotLogged: function(){! ! ! ! var stub = sinon.stub(User, 'isLogged');! ! ! stub.returns(true); ! ! //DO STUFF && ASSERTIONS ! ! stub.returns(false); ! ! //DO STUFF && ASSERTIONS ! }, [...]
  • 87. [...] testMyLibRegistersToSystemOnEvent: function(){!! ! ! var spy = sinon.spy(_$, 'watch');! ! ! //DO STUFF TO INIT YOUR LIB ! ! assertTrue(spy.calledWith('SystemOn')); ! }, ! ! ! ! testMyLibLoggedNotLogged: function(){! ! ! ! var stub = sinon.stub(User, 'isLogged');! ! ! stub.returns(true); ! ! //DO STUFF && ASSERTIONS ! ! stub.returns(false); ! ! //DO STUFF && ASSERTIONS ! }, [...]
  • 88. [...] testMyLibRegistersToSystemOnEvent: function(){!! ! ! var spy = sinon.spy(_$, 'watch');! ! ! //DO STUFF TO INIT YOUR LIB ! ! assertTrue(spy.calledWith('SystemOn')); ! }, ! ! ! ! testMyLibLoggedNotLogged: function(){! ! ! ! var stub = sinon.stub(User, 'isLogged');! ! ! stub.returns(true); ! ! //DO STUFF && ASSERTIONS ! ! stub.returns(false); ! ! //DO STUFF && ASSERTIONS ! }, [...]
  • 89. [...] testMyLibRegistersToSystemOnEvent: function(){!! ! ! var spy = sinon.spy(_$, 'watch');! ! ! //DO STUFF TO INIT YOUR LIB ! ! assertTrue(spy.calledWith('SystemOn')); ! }, ! ! ! ! testMyLibLoggedNotLogged: function(){! ! ! ! var stub = sinon.stub(User, 'isLogged');! ! ! stub.returns(true); ! ! //DO STUFF && ASSERTIONS ! ! stub.returns(false); ! ! //DO STUFF && ASSERTIONS ! }, [...]
  • 90. [...] testMyLibRegistersToSystemOnEvent: function(){!! ! ! var spy = sinon.spy(_$, 'watch');! ! ! //DO STUFF TO INIT YOUR LIB ! ! assertTrue(spy.calledWith('SystemOn')); ! }, ! ! ! ! testMyLibLoggedNotLogged: function(){! ! ! ! var stub = sinon.stub(User, 'isLogged');! ! ! stub.returns(true); ! ! //DO STUFF && ASSERTIONS ! ! stub.returns(false); ! ! //DO STUFF && ASSERTIONS ! }, [...]
  • 91. [...] testMyLibRegistersToSystemOnEvent: function(){!! ! ! var spy = sinon.spy(_$, 'watch');! ! ! //DO STUFF TO INIT YOUR LIB ! ! assertTrue(spy.calledWith('SystemOn')); ! }, ! ! ! ! testMyLibLoggedNotLogged: function(){! ! ! ! var stub = sinon.stub(User, 'isLogged');! ! ! stub.returns(true); ! ! //DO STUFF && ASSERTIONS ! ! stub.returns(false); ! ! //DO STUFF && ASSERTIONS ! }, [...]
  • 92. [...] testMyLibRegistersToSystemOnEvent: function(){!! ! ! var spy = sinon.spy(_$, 'watch');! ! ! //DO STUFF TO INIT YOUR LIB ! ! assertTrue(spy.calledWith('SystemOn')); ! }, ! ! ! ! testMyLibLoggedNotLogged: function(){! ! ! ! var stub = sinon.stub(User, 'isLogged');! ! ! stub.returns(true); ! ! //DO STUFF && ASSERTIONS ! ! stub.returns(false); ! ! //DO STUFF && ASSERTIONS ! }, [...]
  • 93. [...] testMyLibRegistersToSystemOnEvent: function(){!! ! ! var spy = sinon.spy(_$, 'watch');! ! ! //DO STUFF TO INIT YOUR LIB ! ! assertTrue(spy.calledWith('SystemOn')); ! }, [...]
  • 94. [...] //testMyLibRegistersToSystemOnEvent: function(){! ! ! ! //var spy = sinon.spy(_$, 'watch');! ! ! //DO STUFF TO INIT YOUR LIB ! ! //assertTrue(spy.calledWith('SysyemOn')); ! //}, ! ! testMyLibRegistersToSystemOnEvent: function(){!! ! ! var mock = sinon.mock(_$); ! ! mock.expect('watch').calledWith('SysyemOn'); ! ! //DO STUFF TO INIT YOUR LIB ! ! mock.verify(); ! }, [...]
  • 95. [...] //testMyLibRegistersToSystemOnEvent: function(){! ! ! ! //var spy = sinon.spy(_$, 'watch');! ! ! //DO STUFF TO INIT YOUR LIB ! ! //assertTrue(spy.calledWith('SysyemOn')); ! //}, ! ! testMyLibRegistersToSystemOnEvent: function(){!! ! ! var mock = sinon.mock(_$); ! ! mock.expect('watch').calledWith('SysyemOn'); ! ! //DO STUFF TO INIT YOUR LIB ! ! mock.verify(); ! }, [...]
  • 96. What are we going to do
  • 98. svn co https://svn.dsgn.it/jstdd cheat /config/ config browsers.prop dist build.xml libs default.prop tools workshop build.sh build.bat readme.txt
  • 99. svn co https://svn.dsgn.it/jstdd cheat /config/ config browsers.prop dist /libs/ build.xml libs base.js default.prop tools sinon.js workshop build.sh build.bat readme.txt
  • 100. svn co https://svn.dsgn.it/jstdd cheat /config/ config browsers.prop dist /libs/ build.xml libs base.js default.prop tools /tools/ sinon.js workshop ant build.sh browser build.bat jslint readme.txt JsTestDriver
  • 101. svn co https://svn.dsgn.it/jstdd cheat /config/ config browsers.prop dist /libs/ build.xml libs base.js default.prop tools /tools/ sinon.js workshop ant build.sh browser build.bat jslint readme.txt JsTestDriver /workshop/ append find syntax
  • 102. svn co https://svn.dsgn.it/jstdd cheat /config/ config browsers.prop dist /libs/ build.xml libs base.js default.prop tools /tools/ sinon.js workshop ant build.sh browser build.bat jslint /append/ readme.txt JsTestDriver src append.js /workshop/ test append append.test.js find jsTestDriver.conf syntax
  • 103. svn co https://svn.dsgn.it/jstdd cheat /config/ config browsers.prop dist /libs/ build.xml libs base.js default.prop tools /tools/ sinon.js workshop ant build.sh browser build.bat jslint /append/ readme.txt JsTestDriver src append.js /workshop/ test append append.test.js find jsTestDriver.conf syntax build append | sh build.sh append
  • 104. A simple modular event driven app a javascript code highlighter with 3 components: syntax highlighter selected word highlighter finder
  • 105. First step - syntax watch a SRC_LOADED event with the memo {file:'{{FILE_SRC}}'} highlight (wrap in a span with the keyword itself as classname) function => <span class="function">function</span> var, if ... else, for, return, ... notify SRC_READY with the memo {file:'{{EDITED_SRC}}'}
  • 106. Second step - append watch previous SRC_READY create a div[id="src_container"] and fill it with the source append to document llisten dblclick event and notify SRC_HIGHLIGHT with this memo: {keyword:'{{HIGHLIGHTED_WORD}}'} manage the SRC_HIGHLIGHT notification <span class="highlight">{{HIGHLIGHTED_KEYWORKD}}</span>
  • 107. Third step - find watch to SRC_READY create a div[id=form] and append inside of it input[type=text][id=search] input[type=button][id=submitBtn][value=Search] append the div to the document on click on submit notify a SRC_HIGHLIGHT event with memo {keyword:"{{SEARCHED_TEXT}}"}
  • 108. Where are we now?
  • 110. I Build So Consistently
  • 111. Identify Build I Build So Consistently Share make it Continuous

Editor's Notes

  1. \n
  2. \n
  3. \n
  4. \n
  5. \n
  6. \n
  7. \n
  8. \n
  9. \n
  10. \n
  11. \n
  12. \n
  13. \n
  14. \n
  15. \n
  16. \n
  17. \n
  18. \n
  19. \n
  20. \n
  21. \n
  22. \n
  23. \n
  24. \n
  25. \n
  26. \n
  27. \n
  28. \n
  29. \n
  30. \n
  31. \n
  32. \n
  33. \n
  34. \n
  35. \n
  36. \n
  37. \n
  38. \n
  39. \n
  40. \n
  41. \n
  42. \n
  43. \n
  44. \n
  45. \n
  46. \n
  47. \n
  48. \n
  49. \n
  50. \n
  51. \n
  52. \n
  53. \n
  54. \n
  55. \n
  56. \n
  57. \n
  58. \n
  59. \n
  60. \n
  61. \n
  62. \n
  63. \n
  64. \n
  65. \n
  66. \n
  67. \n
  68. \n
  69. \n
  70. \n
  71. \n
  72. \n
  73. \n
  74. \n
  75. \n
  76. \n
  77. \n
  78. \n
  79. \n
  80. \n
  81. \n
  82. \n
  83. \n
  84. \n
  85. \n
  86. \n
  87. \n
  88. \n
  89. \n
  90. \n
  91. \n
  92. \n
  93. \n
  94. \n
  95. \n
  96. \n
  97. \n
  98. \n
  99. \n
  100. \n
  101. \n
  102. \n
  103. \n
  104. \n
  105. \n
  106. \n
  107. \n
  108. \n
  109. \n
  110. \n
  111. \n
  112. \n
  113. \n
  114. \n
  115. \n
  116. \n
  117. \n
  118. \n
  119. \n
  120. \n
  121. \n
  122. \n
  123. \n
  124. \n
  125. \n
  126. \n
  127. \n
  128. \n