Upload
marco-cedaro
View
101.421
Download
0
Embed Size (px)
Citation preview
Javascript As A Programming Language
Javascript As A Programming Language
Versioning, Test Driven Development & Continuous Integration
IS
Javascript As A Programming Language
Versioning, Test Driven Development & Continuous Integration
IS
Hello, who’s speaking?
Hello, who’s speaking?
Marco Cedaro @cedmax
They said I am a...
Frontend Cowboy Nicola Vitto Jr.
Javascript PervertRoberto Felter
Perfect Strangerbasically anyone else
Hello, who’s speaking?
Marco Cedaro @cedmax
Actually I am:
a Frontend Developer at Spreaker.com
Hello, who’s speaking?
Marco Cedaro @cedmax
Actually I am:
a Frontend Developer at Spreaker.com
a conference organizer with From The Front
Hello, who’s speaking?
Marco Cedaro @cedmax
Actually I am:
a Frontend Developer at Spreaker.com
a conference organizer with From The Front
and a javascript pervert
Hello, who’s speaking?
Marco Cedaro @cedmax
Bologna, Italy
something in common with Robert Nyman
something in common with Robert Nyman
I believe I can fly
I believe I can fly
I believe I can fly
Be brave. Take risks. Nothing can substitute
experience. Paulo Coelho
once upon a time
we had no control
once upon a time
we had no control
javascript was the land of the brave
once upon a time
we had no control
javascript was the land of the brave
we were fearless and unconscious
once upon a time
we had no control
javascript was the land of the brave
we were fearless and unconscious
we were proud of being like that
once upon a time
just like them
kitty hawk
but life goes on
web engineer
had a very bad
opinion of us
once upon a time
but it wasn't fair
we didn't have IDEs & tools they did
but it wasn't fair
we didn't have IDEs & tools they did
actually it was our own fault
but it wasn't fair
we didn't have IDEs & tools they did
actually it was our own fault
we were not ready
but it wasn't fair
we didn't have IDEs & tools they did
actually it was our own fault
we were not ready
and javascript was neither
but it wasn't fair
but, again, life goes on...
...and on...
and on..
it's not about the language itself
GREAT POWERS...
Frontend developers have to claim their rolein development roadmap and
business strategy
Javascript is a serious business
how serious?
something we can achieve
less bandwidth and server load loading
resources and content when needed
something we can achieve
less bandwidth and server load loading
resources and content when needed
performance boosts that can lead to better
conversion rates
something we can achieve
less bandwidth and server load loading
resources and content when needed
performance boosts that can lead to better
conversion rates
cross platform development: less maintenance costs
less bandwidth and server load loading
resources and content when needed
performance boosts that can lead to better
conversion rates
cross platform development: less maintenance costs
money
how serious?
this serious
what's missing?
what's missing?
what's missing?
If I had nine of my fingers missing I wouldn't type any
slower.Mitch Hedberg
IDEs & Tools
the attitude
a strategy
the small web agency
The designer introduces a slider on
some websites: ”it’s cool on apple store”.
The developer gets a jQuery plugin online
the small web agency
The designer introduces a slider on
some websites: ”it’s cool on apple store”.
The developer gets a jQuery plugin online
Major release of the most used browser.
A small fix has been released, they have to change 5 files in 5 different projects.
the small web agency
The designer introduces a slider on
some websites: ”it’s cool on apple store”.
The developer gets a jQuery plugin online
Major release of the most used browser.
A small fix has been released, they have to change 5 files in 5 different projects.
Oh damn! There’s no mouse wheel integration!
should they ask for support or should they change the
library by themself?
am I the only one or there’s something wrong?
the big corp
The client-side architecture has been
built on the most known and supported
framework
2006
the big corp
The client-side architecture has been
built on the most known and supported
framework
2006
Everything seems to be fine, except that the
well known framework was being replaced by a
powerful new one
2008 - 2010
the big corp
The client-side architecture has been
built on the most known and supported
framework
2006
Everything seems to be fine, except that the
well known framework was being replaced by a
powerful new one
2008 - 2010
They were forced to change the whole
codebase at once to reduce maintenance
and development costs
2011
here we are again
attitude, strategy...
...and foresight
WARNING!
continuous integration
continuous integration
continuous integration
A software development practice where members of a
team integrate their work frequently [...] to detect
integration errors as quickly as possible.
Martin Fowler
I Build So Consistently
I Build So Consistently
identify
I Build So Consistently
identify
write a build script
I Build So Consistently
share
identify
write a build script
I Build So Consistently
share
identify
write a build script
make it continuous
How can we take advantages from a
continuous integration process?
rationalize your workflow
deploy stable versions
Separate the codebase
unit test your code
basically
basically
basically
ie7
choose your tools
choose your tools
choose your tools
A man cannot be too careful in the choice of his enemies
Oscar Wilde
JSHINT
a code quality tool
like Douglas Crockford's JSLint
a code quality tool
like Douglas Crockford's JSLint
but
a code quality tool
like Douglas Crockford's JSLint
but
customizable
a code quality tool
a tool for stupid?
JS HINT
JS TEST DRIVER
JS HINT
once upon a time
jsTestDriver
jsTestDriver
works from console
jsTestDriver
works from console
runs a server
jsTestDriver
works from console
runs a server
opens browsers
jsTestDriver
works from console
runs a server
opens browsers
runs test suites
jsTestDriver
works from console
runs a server
opens browsers
runs test suites
retrieves results in console
build server
build server
build server
how does testing works?
have you seen Lost?
how does it work?
how does it work?
write a test
how does it work?
write a test let it fail
how does it work?
write a test let it fail write the code
how does it work?
write a test let it fail write the code
run the test again
how does it work?
write a test let it fail write the code
run the test again
refactor
the environment
It's the browser, baby
It's the browser, baby
The curious case of Javascript unit testing
Unit testing is supposed to test a
single atomic “unit” of functionality without
dependencies on anything else
The curious case of Javascript unit testing
Unit testing is supposed to test a
single atomic “unit” of functionality without
dependencies on anything else
This is where you start to run into serious
dependency problems due to the interrelation
with HTML and CSS
The curious case of Javascript unit testing
Unit testing is supposed to test a
single atomic “unit” of functionality without
dependencies on anything else
This is where you start to run into serious
dependency problems due to the interrelation
with HTML and CSS
What do you test? Usually how the user interface responds to
user input. Actually, the realm of
functional testing
keep it real
keep it real
keep it real
To all my homies working on the 9 to 5
Shaggy
#140bytes
I used to work with these guys
_$ = (function() {var registered = {};return {
! ! pub: function(event, memo) {! ! ! if (registered[event] instanceof Array){! ! ! ! var handlers = [].concat(registered[event]);! ! ! ! for (var i=0, h; (h = handlers[i]); i++){! ! ! ! ! h.call(this, memo);! ! ! ! }! ! ! }! ! },! ! sub: function(event, handler) {! ! ! if (typeof registered[event] === "undefined"){! ! ! ! registered[event] = [];! ! ! }! ! ! registered[event].push(handler);! ! }};
})();
_$ = (function() {var registered = {};return {
! ! pub: function(event, memo) {! ! ! if (registered[event] instanceof Array){! ! ! ! var handlers = [].concat(registered[event]);! ! ! ! for (var i=0, h; (h = handlers[i]); i++){! ! ! ! ! h.call(this, memo);! ! ! ! }! ! ! }! ! },! ! sub: function(event, handler) {! ! ! if (typeof registered[event] === "undefined"){! ! ! ! registered[event] = [];! ! ! }! ! ! registered[event].push(handler);! ! }};
})();
_$.sub("customEvent", function(obj) {! //DO STUFF});
_$.pub("customEvent");_$.pub("customEvent", { prop : "value" });
_$.sub("customEvent", function(obj) {! //DO STUFF});
_$.pub("customEvent");_$.pub("customEvent", { prop : "value" });
_$.sub("customEvent", function(obj) {! //DO STUFF});
_$.pub("customEvent");_$.pub("customEvent", { prop : "value" });
_$ = (function() {var registered = {};return {
! ! pub: function(event, memo) {! ! ! if (registered[event] instanceof Array){! ! ! ! var handlers = [].concat(registered[event]);! ! ! ! for (var i=0, h; (h = handlers[i]); i++){! ! ! ! ! h.call(this, memo);! ! ! ! }! ! ! }! ! },! ! sub: function(event, handler) {! ! ! if (typeof registered[event] === "undefined"){! ! ! ! registered[event] = [];! ! ! }! ! ! registered[event].push(handler);! ! }};
})();
_$ = (function (_) {! return {! ! pub: function(a, b, c, d) {! ! ! for (d=-1, c=[].concat(_[a]); c[++d];) c[d](b)! ! },! ! sub: function(a, b) {! ! ! (_[a] || (_[a] = [])).push(b)! ! }! }})({})
_$ = (function (_) {! return {! ! pub: function(a, b, c, d) {! ! ! for (d=-1, c=[].concat(_[a]); c[++d];) c[d](b)! ! },! ! sub: function(a, b) {! ! ! (_[a] || (_[a] = [])).push(b)! ! }! }})({})
#140bytes
_$ = (function() {var registered = {};return {
! ! pub: function(event, memo) {! ! ! if (registered[event] instanceof Array){! ! ! ! var handlers = [].concat(registered[event]);! ! ! ! for (var i=0, h; (h = handlers[i]); i++){! ! ! ! ! h.call(this, memo);! ! ! ! }! ! ! }! ! },! ! sub: function(event, handler) {! ! ! if (typeof registered[event] === "undefined"){! ! ! ! registered[event] = [];! ! ! }! ! ! registered[event].push(handler);! ! }};
})();
_$ = (function (_) {! return {! ! pub: function(a, b, c, d) {! ! ! for (d=-1, c=[].concat(_[a]); c[++d];) c[d](b)! ! },! ! sub: function(a, b) {! ! ! (_[a] || (_[a] = [])).push(b)! ! }! }})({})
#140bytes
_$ = (function() {var registered = {};return {
! ! pub: function(event, memo) {! ! ! if (registered[event] instanceof Array){! ! ! ! var handlers = [].concat(registered[event]);! ! ! ! for (var i=0, h; (h = handlers[i]); i++){! ! ! ! ! h.call(this, memo);! ! ! ! }! ! ! }! ! },! ! sub: function(event, handler) {! ! ! if (typeof registered[event] === "undefined"){! ! ! ! registered[event] = [];! ! ! }! ! ! registered[event].push(handler);! ! }};
})();
_$ = (function (_) {! return {! ! pub: function(a, b, c, d) {! ! ! for (d=-1, c=[].concat(_[a]); c[++d];) c[d](b)! ! },! ! sub: function(a, b) {! ! ! (_[a] || (_[a] = [])).push(b)! ! }! }})({})
#140bytes
_$ = (function (_) {! return {! ! pub: function(a, b, c, d) {! ! ! for (d=-1, c=[].concat(_[a]); c[++d];) c[d](b)! ! },! ! sub: function(a, b) {! ! ! (_[a] || (_[a] = [])).push(b)! ! }! }})({})
#140bytes
[...]testPub: function(){! !
! ! var a = 0;!! ! _$.sub('testNotify', function(){ a = 1; });! ! _$.pub('testNotify');
! ! assertEquals(1, a);! },! ! !! testNotifyWithMemo: function(){!!! ! var a = 0 ;!! ! _$.sub('testNotify', function(memo){ ! ! ! ! a = memo.test;! ! });! ! _$.pub('testNotify', {test: 1});
! ! assertEquals(1, a);! },[...]
[...]testPub: function(){! !
! ! var a = 0;!! ! _$.sub('testNotify', function(){ a = 1; });! ! _$.pub('testNotify');
! ! assertEquals(1, a);! },! ! !! testNotifyWithMemo: function(){!!! ! var a = 0 ;!! ! _$.sub('testNotify', function(memo){ ! ! ! ! a = memo.test;! ! });! ! _$.pub('testNotify', {test: 1});
! ! assertEquals(1, a);! },[...]
[...]testPub: function(){! !
! ! var a = 0;!! ! _$.sub('testNotify', function(){ a = 1; });! ! _$.pub('testNotify');
! ! assertEquals(1, a);! },! ! !! testNotifyWithMemo: function(){!!! ! var a = 0 ;!! ! _$.sub('testNotify', function(memo){ ! ! ! ! a = memo.test;! ! });! ! _$.pub('testNotify', {test: 1});
! ! assertEquals(1, a);! },[...]
[...]testPub: function(){! !
! ! var a = 0;!! ! _$.sub('testNotify', function(){ a = 1; });! ! _$.pub('testNotify');
! ! assertEquals(1, a);! },! ! !! testNotifyWithMemo: function(){!!! ! var a = 0 ;!! ! _$.sub('testNotify', function(memo){ ! ! ! ! a = memo.test;! ! });! ! _$.pub('testNotify', {test: 1});
! ! assertEquals(1, a);! },[...]
[...]testPub: function(){! !
! ! var a = 0;!! ! _$.sub('testNotify', function(){ a = 1; });! ! _$.pub('testNotify');
! ! assertEquals(1, a);! },! ! !! testNotifyWithMemo: function(){!!! ! var a = 0 ;!! ! _$.sub('testNotify', function(memo){ ! ! ! ! a = memo.test;! ! });! ! _$.pub('testNotify', {test: 1});
! ! assertEquals(1, a);! },[...]
[...]testPub: function(){! !
! ! var a = 0;!! ! _$.sub('testNotify', function(){ a = 1; });! ! _$.pub('testNotify');
! ! assertEquals(1, a);! },! ! !! testNotifyWithMemo: function(){!!! ! var a = 0 ;! ! _$.sub('testNotify', function(memo){ ! ! ! ! a = memo.test;! ! });! ! _$.pub('testNotify', {test: 1});
! ! assertEquals(1, a);! },[...]
[...]testPub: function(){! !
! ! var a = 0;!! ! _$.sub('testNotify', function(){ a = 1; });! ! _$.pub('testNotify');
! ! assertEquals(1, a);! },! ! !! testNotifyWithMemo: function(){!!! ! var a = 0 ;!! ! _$.sub('testNotify', function(memo){ ! ! ! ! a = memo.test;! ! });! ! _$.pub('testNotify', {test: 1});
! ! assertEquals(1, a);! },[...]
easy, uh?
you will, eventually
JS TEST DRIVER
JS HINT
JS TEST DRIVERSINON.JS
JS HINT
a mock library
a mock library
SPIESa function that records
arguments, return value, the value of this and exception thrown (if any) for all its calls.
a mock library
SPIESa function that records
arguments, return value, the value of this and exception thrown (if any) for all its calls.
STUBSfunctions (spies) with
pre-programmed behavior.
a mock library
SPIESa function that records
arguments, return value, the value of this and exception thrown (if any) for all its calls.
STUBSfunctions (spies) with
pre-programmed behavior.
MOCKSfunctions (spies) with
pre-programmed behavior (stubs) as well
as pre-programmed 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
! },[...]
SPY
[...]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
! },[...]
SPY
[...]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
! },[...]
SPY
[...]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
! },[...]
SPY
[...]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
! },[...]
STUB
[...]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
! },[...]
STUB
[...]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
! },[...]
STUB
[...]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
! },[...]
STUB
[...]testMyLibRegistersToSystemOnEvent: function(){! !
! ! var spy = sinon.spy(_$, 'watch');!! ! //DO STUFF TO INIT YOUR LIB! ! assertTrue(spy.calledWith('SystemOn'));! },[...]
MOCK
[...]//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();! },[...]
MOCK
[...]//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();! },[...]
MOCK
[...]//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();! },[...]
MOCK
[...]testOnSuccessCallback: function(){! !var server = sinon.useFakeServer();
server.respondWith("GET", "/art/12/comments.json", [200, {"Content-Type":"application/json"},
"[{ id:12, text:'Hello'}]"]);
! ! var spy = sinon.spy();! ! myLib.getCommentsFor("/art/12", spy);
! ! server.respond();
! ! assert(spy.calledWith([{ id:12, text:"Hello"}]));! },[...]
AJAX CALL
[...]testOnSuccessCallback: function(){! !var server = sinon.useFakeServer();
server.respondWith("GET", "/art/12/comments.json", [200, {"Content-Type":"application/json"},
"[{ id:12, text:'Hello'}]"]);
! ! var spy = sinon.spy();! ! myLib.getCommentsFor("/art/12", spy);
! ! server.respond();
! ! assert(spy.calledWith([{ id:12, text:"Hello"}]));! },[...]
AJAX CALL
[...]testOnSuccessCallback: function(){! !var server = sinon.useFakeServer();
server.respondWith("GET", "/art/12/comments.json", [200, {"Content-Type":"application/json"},
"[{ id:12, text:'Hello'}]"]);
! ! var spy = sinon.spy();! ! myLib.getCommentsFor("/art/12", spy);
! ! server.respond();
! ! assert(spy.calledWith([{ id:12, text:"Hello"}]));! },[...]
AJAX CALL
[...]testOnSuccessCallback: function(){! !var server = sinon.useFakeServer();
server.respondWith("GET", "/art/12/comments.json", [200, {"Content-Type":"application/json"},
"[{ id:12, text:'Hello'}]"]);
! ! var spy = sinon.spy();! ! myLib.getCommentsFor("/art/12", spy);
! ! server.respond();
! ! assert(spy.calledWith([{ id:12, text:"Hello"}]));! },[...]
AJAX CALL
[...]testOnSuccessCallback: function(){! !var server = sinon.useFakeServer();
server.respondWith("GET", "/art/12/comments.json", [200, {"Content-Type":"application/json"},
"[{ id:12, text:'Hello'}]"]);
! ! var spy = sinon.spy();! ! myLib.getCommentsFor("/art/12", spy);
! ! server.respond();
! ! assert(spy.calledWith([{ id:12, text:"Hello"}]));! },[...]
AJAX CALL
[...]testOnSuccessCallback: function(){! !var server = sinon.useFakeServer();
server.respondWith("GET", "/art/12/comments.json", [200, {"Content-Type":"application/json"},
"[{ id:12, text:'Hello'}]"]);
! ! var spy = sinon.spy();! ! myLib.getCommentsFor("/art/12", spy);
! ! server.respond();
! ! assert(spy.calledWith([{ id:12, text:"Hello"}]));! },[...]
AJAX CALL
[...]testOnSuccessCallback: function(){! !var server = sinon.useFakeServer();
server.respondWith("GET", "/art/12/comments.json", [200, {"Content-Type":"application/json"},
"[{ id:12, text:'Hello'}]"]);
! ! var spy = sinon.spy();! ! myLib.getCommentsFor("/art/12", spy);
! ! server.respond();
! ! assert(spy.calledWith([{ id:12, text:"Hello"}]));! },[...]
AJAX CALL
[...]testOnSuccessCallback: function(){! !var server = sinon.useFakeServer();
server.respondWith("GET", "/art/12/comments.json", [200, {"Content-Type":"application/json"},
"[{ id:12, text:'Hello'}]"]);
! ! var spy = sinon.spy();! ! myLib.getCommentsFor("/art/12", spy);
! ! server.respond();
! ! assert(spy.calledWith([{ id:12, text:"Hello"}]));! },[...]
AJAX CALL
[...]testOnSuccessCallback: function(){! !var server = sinon.useFakeServer();
server.respondWith("GET", "/art/12/comments.json", [200, {"Content-Type":"application/json"},
"[{ id:12, text:'Hello'}]"]);
! ! var spy = sinon.spy();! ! myLib.getCommentsFor("/art/12", spy);
! ! server.respond();
! ! assert(spy.calledWith([{ id:12, text:"Hello"}]));! },[...]
AJAX CALL
[...]testOnSuccessCallback: function(){! !var server = sinon.useFakeServer();
server.respondWith("GET", "/art/12/comments.json", [200, {"Content-Type":"application/json"},
"[{ id:12, text:'Hello'}]"]);
! ! var spy = sinon.spy();! ! myLib.getCommentsFor("/art/12", spy);
! ! server.respond();
! ! assert(spy.calledWith([{ id:12, text:"Hello"}]));! },[...]
AJAX CALL
[...]testOnSuccessCallback: function(){! !var server = sinon.useFakeServer();
server.respondWith("GET", "/art/12/comments.json", [200, {"Content-Type":"application/json"},
"[{ id:12, text:'Hello'}]"]);
! ! var spy = sinon.spy();! ! myLib.getCommentsFor("/art/12", spy);
! ! server.respond();
! ! assert(spy.calledWith([{ id:12, text:"Hello"}]));! },[...]
AJAX CALL
JS TEST DRIVERSINON.JS
JS HINT
JS TEST DRIVERSINON.JS
JS HINT
YUI COMPRESSOR
Everyone should be happy
in the wild
in the wild
IN THE WILD
In the wild, there is no health care.
Dwight Schrute (the office)
drawbacks
at the beginning
cost of change
LOOKING FORWARD
LOOKING FORWARD
LOOKING FORWARD
LOOKING FORWARD
LOOKING FORWARD
the further we look at,the more control we need
LOOKING FORWARD
the further we look at,the more control we need
LOOKING FORWARD
the further we look at,the more control we need
LOOKING FORWARD
let's get ready
the further we look at,the more control we need
LOOKING FORWARD
let's get ready
javascript is a programming language
the further we look at,the more control we need
LOOKING FORWARD
let's get ready
javascript is a programming language
javascript is a serious business.
the further we look at,the more control we need
LOOKING FORWARD
let's get ready
javascript is a programming language
javascript is a serious business. and, most of all...
javascript kicks asses
javascript kicks asses
http://spkr8.com/t/8718http://cedmax.com@cedmax
any question?