User:Cnbrown4/sandbox

Jasmine is an open source development framework for testing a JavaScript code. It is run independently and is behavior driven. It doesn’t require any DOM. It is favored because of its clean, easy to read and obvious syntax.

History
The developers at Pivotal Labs for Jasmine previously developed a similar unit testing framework called JsUnit before active development of Jasmine.

Installation
The latest standalone download version is available at https://github.com/jasmine/jasmine The resulting directory has the following structure



Folders and their meanings

 * lib-Contains Jasmine Framework files
 * src-Contains the actual Javascript code we want to test
 * spec-Contains the Javascript test code
 * SpecRunner.html-File that runs the tests in the browser

Key terms

 * Suit:Starts with a global Jasmine function describe, which takes two parameters (Name of the suite as string & spec function)
 * Spec:Function consists of the it block describing the setup code the test needs to do.
 * Matcher:Spec function takes this function as parameter. Matcher compares the result of the code with the expected result.

The spec .js file, which tests the JavaScript code consists of suites of test cases. Basic structure of a spec .js file is as follows: describe(“Name of Suite”, function {  it(“what it does”, function { expect(yourJsFunction).toEqual(“Your expected result”); }); });

Running the test

 * Place the .js file to be tested in the src folder
 * Place the spec file in the spec folder
 * Edit SpecRunner.html and include the file names in the "src" tags
 * Run SpecRunner in browser to see the results

Before & After
If in situations where a few lines of setup code needs to be performed for every test, Jasmine provides  &   functions which allows to run the setup code before and after each test. It eliminates the pain of writing redundant code for every  call.

Example: describe("MyObject", function {    var obj = new MyObject;

beforeEach(function {        obj.setValue("null");    });

it("changes value", function {        obj.setValue("xyz");        expect(obj.getValue).toEqual("xyz");    }) it("adds value", function {        obj.addValue("pqr");        expect(obj.getValue).toEqual(["null", "pqr"]);    }) }); In the above example, before each test is run, the value of the object is set to null. This is to ensure every test starts with a fresh copy of the object without the previous values persisting.

Predefined Matchers (v.2.3.4)

 * 'toBe'
 * 'toBeCloseTo'
 * 'toBeDefined'
 * 'toBeFalsy'
 * 'toBeGreaterThan',
 * 'toBeLessThan'
 * 'toBeNaN'
 * 'toBeNull'
 * 'toBeTruthy'
 * 'toBeUndefined'
 * 'toContain'
 * 'toEqual'
 * 'toHaveBeenCalled'
 * 'toHaveBeenCalledWith'
 * 'toHaveBeenCalledTimes'
 * 'toMatch'
 * 'toThrow'
 * 'toThrowError'

Custom Matchers
Sometimes building your own matchers are helpful. A custom matcher can be added in a  call or within the   call. describe(“Name of Suite”, function {  beforeEach(function  { jasmine.addMatchers({	   toBeCustomMatcher: function{		return {                    compare: function (actual, expected) {                        return {                            pass: (actual + someCalculation) === expectedResult                        };                    }                 };	     }	}); });

it(“what it does”, function {      expect(yourJsFunction).toBeCustomMatcher;    }); });

Spies
A spy is a way to test if a function has been called and in the way it is supposed to be called describe(“Name of Spy”, function{    it(“calls the [name of] function”, function{ spyOn(class, "methodToSpyOn"); class.aDifferentMethod(input); expect(class.methodToSpyOn).toHaveBeenCalledWith(input); }); });

Hello World!
function helloWorld { return "Hello world!"; } describe("Hello world", function { it("says hello", function { expect(helloWorld).toEqual("Hello world!"); }); });
 * JavaScript file that needs to be tested Hello.js (Place it in /src directory)
 * JavaScript file with the test case HelloSpec.js (Place it in /spec directory)
 * SpecRunner.html




 * Run SpecRunner.html in browser



Shapes
function rectangleArea(width, height){ return width * height; }
 * JavaScript file that needs to be tested Shapes.js (Place it in /src directory)

var Shape = function{};

Shape.prototype.circleCircumference = function(radius){ this.checkInvalidNumber(radius); return 2 * radius * 3.14; }

Shape.prototype.checkInvalidNumber = function(num){ if(num <= 0){ throw new Error("Invalid Number"); } } describe ("Rectangle Area", function{	beforeEach(function { jasmine.addMatchers({			toBeDividedByThree: function{				return {                   compare: function (actual, expected) {                        return {                            pass: (actual/3) === 4                        };                    }                };			}		}); });	it('check rectangle area', function{ expect(rectangleArea(2, 4)).toBe(8); expect(rectangleArea(2,3)).toBeLessThan(8); expect(rectangleArea(3,'a')).toBeNaN; expect(rectangleArea(3, 4)).toBeDividedByThree; }); });
 * JavaScript file with the test case ShapeSpec.js (Place it in /spec directory)

describe("Circle Circumference", function{	it( 'check circle circumference has valid number', function { var newShape = new Shape; spyOn(newShape, "checkInvalidNumber"); newShape.circleCircumference(3); expect(newShape.checkInvalidNumber).toHaveBeenCalledWith(3); });	it( 'check circle circumference', function { var newShape = new Shape; expect(newShape.circleCircumference(3)).toBeCloseTo(19, 0); expect(newShape.circleCircumference(3)).not.toBeCloseTo(18.8, 1); expect(newShape.checkInvalidNumber.bind(null, -3)).toThrow; expect(newShape.checkInvalidNumber.bind(null, 7)).not.toThrow; }); });
 * SpecRunner.html





In this example there are 2 suites. The first suite is called “Rectangle Area”. It contains 1 specs: “check rectangle area”. Within this spec is 4 matchers. The beforeEach call at the top of the method is used to create the matcher "toBeDividedByThree". The first matcher is “toBe” which checks if the value returned from the method within expect is equal to the argument given to "toBe". The second matcher is “toBeLessThan” which checks if the returned value is less than the argument given to "toBeLessThan". The third matcher, "toBeNaN", checks if the value returned is 'NaN'. The fourth matcher is "toBeDividedByThree" uses the matcher created at the top of the suite. The second suite, "Circle Circumference", has two specs. The first spec uses a spy to see if we indirectly call checkInvalidNumber with a 3 using the matcher “toHaveBeenCalledWith”. The second spec uses the “toBeCloseTo” matcher. This first matcher is used to check if circleCircumference(3) is close to 19 without the decimal place. circleCircumference(3) is 18.84 so 19 is close to 18.84 without the decimal. The second matcher is used to check if circleCircumference(3) is close to 18.8 checking within one decimal place. The third matcher tests the toThrow matcher. Because -3 throws an error within the checkInvalidNumber method this test will return true. The second matcher within this suite checks to see if 7 does not throw an error within the checkInvalidNumber method. The .not operator can be used on all matchers.