Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Javascript Test Driven Development is between us (Workshop)

3ca63d4e2f2be0ef47b841e63b564d18?s=47 Marco Cedaro
September 29, 2011

Javascript Test Driven Development is between us (Workshop)

Javascript & browsers have been for years a complex and unsafe environment for a web developer, now we have the right tools to gain control on what we are distributing in our web applications. During the workshop you will learn first-hand basic Javascript Test Driven Development practices including testing, refactoring and related agile practices such as continuous integration and pair programming.

From The Front, Back To The Front (Cesena, Sept 29th, 2011)
@cedmax
http://cedmax.com

3ca63d4e2f2be0ef47b841e63b564d18?s=128

Marco Cedaro

September 29, 2011
Tweet

Transcript

  1. back to the front javascript tdd is between us

  2. Who are we? Marco Cedaro javascript pirate, arr Spreaker Frontend

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

    Developer Luca Lischetti 8-bit lover and super hero (almost) Shazam Frontend Developer The content of this workshop do not necessarily reflect the opinion of authors employers
  4. Who are we? Marco Cedaro javascript pirate, arr Spreaker Frontend

    Developer Luca Lischetti 8-bit lover and super hero (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

  6. Fearless & Unconscious

  7. Fearless & Unconscious

  8. But Life Goes On

  9. TDD is about control

  10. and about DESIGN too

  11. The curious case of JavaScript unit testing

  12. Unit Test and Functional Test

  13. Pro/Cons test interaction between libraries control over codebase consistency against

    external changes execution time test integration
  14. That's the browsers, baby

  15. None
  16. Unit testing is supposed to test a single atomic “unit”

    of functionality without dependencies on anything else
  17. This is where you start to run into serious dependency

    problems due to the interrelation HTML and CSS Unit testing is supposed to test a single atomic “unit” of functionality without dependencies on anything else
  18. This is where you start to run into serious dependency

    problems due to the interrelation HTML and CSS Unit testing is supposed to test a single atomic “unit” of functionality without dependencies on anything else What do you test? Usually how the user interface responds to user input. Actually, the realm of functional testing
  19. How does it work?

  20. have you seen LOST?

  21. None
  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 Refactor your code Run test &

    let it fail Write the code Run test & let it succeed
  27. Coding

  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); ! ! } }; })();
  29. pub.. What?

  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 (_) { 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 (_) { 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

  78. Sinon.js

  79. None
  80. a function that records arguments, return value, the value of

    this and exception thrown (if any) for all its calls. Spies
  81. functions (spies) with pre-programmed behavior. Stub a function that records

    arguments, return value, the value of this and exception thrown (if any) for all its calls. Spies
  82. functions (spies) with pre-programmed behavior. Stub a function that records

    arguments, return value, the value of this and exception thrown (if any) for all its calls. Spies functions (spies) with pre-programmed behavior (stubs) as well as pre- programmed expectations. Mock
  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

  97. cheat config dist libs tools workshop build.sh build.bat readme.txt svn

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

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

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

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

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

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

    build.bat readme.txt /tools/ ant browser jslint JsTestDriver /workshop/ append find syntax /append/ src append.js test append.test.js jsTestDriver.conf /config/ browsers.prop build.xml default.prop svn co https://svn.dsgn.it/jstdd 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?

  109. Costs of change

  110. I Build So Consistently

  111. I Build So Consistently Identify Build Share make it Continuous

  112. None