Writing and Testing JavaScript-heavy Web 2.0 apps with JSUnit

Post on 10-May-2015

10843 Views

Category:

Business

0 Downloads

Preview:

Click to see full reader

DESCRIPTION

With the advent of the so-called Web 2.0 platform, more and more applications are using client-side JavaScript for vital features. In fact, some applications are so JS-heavy that they redefine JavaScript as a full-fledged application development language. In this tutorial we discuss some architectural considerations of JS- and AJAX-heavy applications and present in detail our testing framework, with plenty of code examples.

Transcript

Writing and Testing JavaScript-heavy Web 2.0 apps with JSUnit

Writing and Testing JavaScript-heavy Web 2.0 apps with JSUnit

Authors:Alex Chaffee, Pivotal Labs

Edward Hieatt, Pivotal Labs

Authors:Alex Chaffee, Pivotal Labs

Edward Hieatt, Pivotal Labs

AbstractAbstract

With the advent of the so-called Web 2.0 platform, more and more applications are using client-side

JavaScript for vital features. In fact, some applications are so JS-heavy that they redefine JavaScript as a full-

fledged application development language. In this tutorial we discuss some architectural considerations

of JS- and AJAX-heavy applications and present in detail our testing framework, with plenty of code

examples and live demos.

With the advent of the so-called Web 2.0 platform, more and more applications are using client-side

JavaScript for vital features. In fact, some applications are so JS-heavy that they redefine JavaScript as a full-

fledged application development language. In this tutorial we discuss some architectural considerations

of JS- and AJAX-heavy applications and present in detail our testing framework, with plenty of code

examples and live demos.

JS Application ArchitecturesJS Application Architectures

Traditional: Minimal JS JS for validation JS for user responsiveness JS for DHTML JS for layout tweaks (where CSS falls

down)

Traditional: Minimal JS JS for validation JS for user responsiveness JS for DHTML JS for layout tweaks (where CSS falls

down)

JS Application Architectures (cont.)

JS Application Architectures (cont.)

AJAX Architecture Widgets and functions live on client Use XMLHttpRequest for immediate

or background requests to server Use JSON or XML for data transport

AJAX Architecture Widgets and functions live on client Use XMLHttpRequest for immediate

or background requests to server Use JSON or XML for data transport

JS Application Architectures (cont.)

JS Application Architectures (cont.)

Dynamic Architecture: server-generated JS RJS Google Web Toolkit Big advantage:

unified codebase -> DRY Disadvantages:

Latency Harder to test

Dynamic Architecture: server-generated JS RJS Google Web Toolkit Big advantage:

unified codebase -> DRY Disadvantages:

Latency Harder to test

Application Architectures (cont.)

Application Architectures (cont.)

Client-Server

JS MVC: Heavy JS In this architecture, the JavaScript code

takes the form of a full-fledged application. Using JSON to transfer data back and forth between the server-side API, the JavaScript application maintains its own domain objects and executes its own business rules.

Can violate DRY

Client-Server

JS MVC: Heavy JS In this architecture, the JavaScript code

takes the form of a full-fledged application. Using JSON to transfer data back and forth between the server-side API, the JavaScript application maintains its own domain objects and executes its own business rules.

Can violate DRY

Application Architectures (cont.)

Application Architectures (cont.)

Hybrid Naturally, you can mix and match the

above techniques Complicates your coding and testing Can violate DRY

Hybrid Naturally, you can mix and match the

above techniques Complicates your coding and testing Can violate DRY

Testing StrategiesTesting Strategies

Unit Testing: JSUnit

Integration Testing: Selenium WATIR

Unit Testing: JSUnit

Integration Testing: Selenium WATIR

JavaScript EssenceJavaScript Essence

Dynamic Interpreted Prototype-based OO Object = Hash

Everything (even Function) is a Hash Sort of a mutant hybrid of Java and

Ruby

Dynamic Interpreted Prototype-based OO Object = Hash

Everything (even Function) is a Hash Sort of a mutant hybrid of Java and

Ruby

JavaScript ConsJavaScript Cons Functions have loose binding

“this” isn't always correct Workaround: Use bind

(part of prototype.js) Frustrating syntax and

semantics Symbols are globally scoped

by default You must remember

“this” Too easy to make global

variables null vs. undefined vs. 0 All members are public

Functions have loose binding “this” isn't always correct Workaround: Use bind

(part of prototype.js) Frustrating syntax and

semantics Symbols are globally scoped

by default You must remember

“this” Too easy to make global

variables null vs. undefined vs. 0 All members are public

No OO inheritance Several hacks to simulate

inheritance Rely more on composition

Browser differences (esp. DOM API) and bugs

No “include” or “require” We rolled our own

Painful debugging Unreliable stack traces Two different GCs

Memory leaks via DOM Third-party libraries rarely

tested

No OO inheritance Several hacks to simulate

inheritance Rely more on composition

Browser differences (esp. DOM API) and bugs

No “include” or “require” We rolled our own

Painful debugging Unreliable stack traces Two different GCs

Memory leaks via DOM Third-party libraries rarely

tested

JavaScript Tools and Libraries

JavaScript Tools and Libraries

Firefox ExtensionsFirefox Extensions

Web Developer Firebug ROCKS

Web Developer Firebug ROCKS

Development EnvironmentsDevelopment Environments

IDEA Eclipse TextMate ?

IDEA Eclipse TextMate ?

prototype.js Libraryprototype.js Library

bind $ $H, $A, each, etc. extend Ajax.Request Element.hide Other useful stuff

bind $ $H, $A, each, etc. extend Ajax.Request Element.hide Other useful stuff

JS UI librariesJS UI libraries

script.aculo.us Very Good Popular (easy to find help)

Yahoo UI Excellent Drag and drop, animation, calendar,

etc.

script.aculo.us Very Good Popular (easy to find help)

Yahoo UI Excellent Drag and drop, animation, calendar,

etc.

Asset PackagerAsset Packager

Combines multiple JS files into one Also CSS

Reduces Latency Also Steve Conover’s inline merger

looks promising

Combines multiple JS files into one Also CSS

Reduces Latency Also Steve Conover’s inline merger

looks promising

JSUnitJSUnit

“Controlling The Insanity”

Unit Testing is essential for all but the most trivial JavaScript

“Controlling The Insanity”

Unit Testing is essential for all but the most trivial JavaScript

Pivotal AssertionsPivotal Assertions

clock.jsclock.js

Testing utility class we wrote Overrides setTimeout Allows unit testing of time-based

operations without sleeping

Testing utility class we wrote Overrides setTimeout Allows unit testing of time-based

operations without sleeping

ajax.jsajax.js

AjaxUnit Overrides Prototype AJAX classes Stubs out the network interface Allows unit testing of AJAX calls

AjaxUnit Overrides Prototype AJAX classes Stubs out the network interface Allows unit testing of AJAX calls

Mock Objects in JSMock Objects in JS

We don’t know of any real mocking framework for JS

We use stubs, spies, object mothers and mock methods

We don’t know of any real mocking framework for JS

We use stubs, spies, object mothers and mock methods

Client-Server Communication

Client-Server Communication

Client-Server Communication: Let me

count the ways

Client-Server Communication: Let me

count the ways HTTP

Including GET, POST, cookies, etc.

CGI AJAX+XML AJAX+JSON AJAX+HTML AJAX+JS RJS

HTTP Including GET, POST, cookies, etc.

CGI AJAX+XML AJAX+JSON AJAX+HTML AJAX+JS RJS

AJAXAJAX

“Asynchronous JavaScript And XML”

Client calls server with CGI GET or POST via XMLHttpRequest API

Server responds Client does something without

redrawing entire page

“Asynchronous JavaScript And XML”

Client calls server with CGI GET or POST via XMLHttpRequest API

Server responds Client does something without

redrawing entire page

AJAX+XMLAJAX+XML

Response contains XML Original implementation of AJAX Not used much now (?) I've heard of doing XSL but that's

mostly on IE-only apps

Response contains XML Original implementation of AJAX Not used much now (?) I've heard of doing XSL but that's

mostly on IE-only apps

JSONJSON

Evaluates to JS values (hashes and arrays) Example:

{ "Image": { "Width": 800, "Height": 600, "Title": "View from 15th Floor", "Thumbnail": { "Url": "http: //scd.mmb1.com/image/481989943", "Height": 125, "Width": "100" }, "IDs": [116, 943, 234, 38793] }}

Evaluates to JS values (hashes and arrays) Example:

{ "Image": { "Width": 800, "Height": 600, "Title": "View from 15th Floor", "Thumbnail": { "Url": "http: //scd.mmb1.com/image/481989943", "Height": 125, "Width": "100" }, "IDs": [116, 943, 234, 38793] }}

AJAX+JSON (AJAJ?)AJAX+JSON (AJAJ?)

Proper client-server communication Client sends requests in CGI, gets

responses as pure data Client evaluates data, actively

performs response Interacts with DOM Creates/removes/modifies/copies

HTML elements

Proper client-server communication Client sends requests in CGI, gets

responses as pure data Client evaluates data, actively

performs response Interacts with DOM Creates/removes/modifies/copies

HTML elements

AJAX+HTMLAJAX+HTML

Server executes RHTML/JSP/etc. AJAX response contains HTML Client splats it onto the page

Server executes RHTML/JSP/etc. AJAX response contains HTML Client splats it onto the page

AJAX+JSAJAX+JS

AJAX response contains JavaScript code

Client calls eval() on it Powerful and a little scary Hard to test

AJAX response contains JavaScript code

Client calls eval() on it Powerful and a little scary Hard to test

RJSRJS

Part of Ruby on Rails Generates JS via Ruby methods Not as scary as raw JS since it’s

coming from a tested library

Part of Ruby on Rails Generates JS via Ruby methods Not as scary as raw JS since it’s

coming from a tested library

Latency: The AJAX killerLatency: The AJAX killer

This AJAX stuff really is client-server communication

If the server is slow, your app crawls to a halt -- and inside a page, not just between pages

Less user feedback for a hung AJAX call Can lead to multiple clicks, reloads,

confusion, etc.

This AJAX stuff really is client-server communication

If the server is slow, your app crawls to a halt -- and inside a page, not just between pages

Less user feedback for a hung AJAX call Can lead to multiple clicks, reloads,

confusion, etc.

Solving LatencySolving Latency

The Easy Way: Use a spinny icon Still requires UI/UE design

The Easy Way: Use a spinny icon Still requires UI/UE design

Solving LatencySolving Latency

The Hard Way: To solve, you must write a lot of code on the

client to react immediately to user actions, then queue up requests and deal gracefully once the server reponds

Error handling Command queue Undo Dynamic/incremental data updates This leads naturally to true MVC in JS

The Hard Way: To solve, you must write a lot of code on the

client to react immediately to user actions, then queue up requests and deal gracefully once the server reponds

Error handling Command queue Undo Dynamic/incremental data updates This leads naturally to true MVC in JS

JS MVC ArchitectureJS MVC ArchitectureJSON

ModelObjects

Notify

ViewComponents

Render

DOMUser Events

Enqueue

CommandObjectsExecute / undo

AJAX (CGI)

Integration Testing with Selenium

Integration Testing with Selenium

Selenium… Runs in the browser Executes your app in a frame Simulates user actions via JavaScript Goes all the way to the server and back

Complementary to JSUnit JSUnit tests JS pages and libraries only, not interaction

with server Selenium is fun to watch Integrated into Continuous Integration like JSUnit Catch our talks on Wednesday (Selenium) and

Thursday (CI)

Selenium… Runs in the browser Executes your app in a frame Simulates user actions via JavaScript Goes all the way to the server and back

Complementary to JSUnit JSUnit tests JS pages and libraries only, not interaction

with server Selenium is fun to watch Integrated into Continuous Integration like JSUnit Catch our talks on Wednesday (Selenium) and

Thursday (CI)

Q&AQ&A

More ExamplesMore Examples

ClockClock

We wrote our JS “Mock Clock” test-first Actually, it’s a stub, not a mock :-)

Illustrates a true (isolated) unit test of a utility class

We wrote our JS “Mock Clock” test-first Actually, it’s a stub, not a mock :-)

Illustrates a true (isolated) unit test of a utility class

WeaverWeaver

The Weaver takes two arrays and returns the set of changes required to transform one into the other

Used by Tracker’s list widgets Illustrates use of roll-your-own test

spies

The Weaver takes two arrays and returns the set of changes required to transform one into the other

Used by Tracker’s list widgets Illustrates use of roll-your-own test

spies

DateWidgetDateWidget

We wrapped Yahoo’s YUI Calendar widget to add a text field with validation and pop-up-on-activate

Illustrates Testing with UI events Using a “demo.html” page Wrapping a third-party widget with

tests

We wrapped Yahoo’s YUI Calendar widget to add a text field with validation and pop-up-on-activate

Illustrates Testing with UI events Using a “demo.html” page Wrapping a third-party widget with

tests

Server ProxyServer Proxy

Illustrates AjaxUnit (ajax.js) mocking out the networking layer

Illustrates AjaxUnit (ajax.js) mocking out the networking layer

Add Note CommandAdd Note Command

Tests the command which adds a note (comment) to a story Does not test the networking layer,

just the command object Demonstrates use of stubs and

object mother (JsonFactory)

Tests the command which adds a note (comment) to a story Does not test the networking layer,

just the command object Demonstrates use of stubs and

object mother (JsonFactory)

Login WidgetLogin Widget

PeerToPatent uses page caching, so we have to render the “you’re logged in / please log in” area of the screen in JavaScript

PeerToPatent uses page caching, so we have to render the “you’re logged in / please log in” area of the screen in JavaScript

Cacheable FlashCacheable Flash

Not that kind of Flash… “Flash” is Rails for “Message Box”

In order for dynamic information to be rendered inside of a statically cached page, we put it into a cookie, and render the cookie’s contents with JavaScript

Not that kind of Flash… “Flash” is Rails for “Message Box”

In order for dynamic information to be rendered inside of a statically cached page, we put it into a cookie, and render the cookie’s contents with JavaScript

Cookie LibraryCookie Library

Illustrates testing a third-party library

We found bugs in it, esp. IE 7 We had to patch it

Illustrates testing a third-party library

We found bugs in it, esp. IE 7 We had to patch it

JS PaginatorJS Paginator

Illustrates receiving JSON with data Download (actually render) entire

data set on page load, then render some at a time Doesn’t scale to large datasets, like

Rico LiveGrid does

Illustrates receiving JSON with data Download (actually render) entire

data set on page load, then render some at a time Doesn’t scale to large datasets, like

Rico LiveGrid does

ExperimentationExperimentation

Since this is an agile conference, if there's time and interest, we can get volunteers from the audience to come up and pair program with the presenters on stage. solving problems posed by the audience.

Since this is an agile conference, if there's time and interest, we can get volunteers from the audience to come up and pair program with the presenters on stage. solving problems posed by the audience.

Where to find more info?Where to find more info?

http://jsunit.net http://pivotallabs.com

http://jsunit.net http://pivotallabs.com

top related