* 
* 
* Who Am I?
* State of the Room?
* CF API
* Ways to test your API?
* Overview of Testing Tools
* Using Testing in your Workflow
* Installing Jasmine
* Installing Testbox
* Live Demo
* 
* Gavin Pickin – developing Web Apps since late 90s
* New Addition to Ortus Solutions
* ContentBox Evangelist
* What else do you need to know?
* Blog - http://www.gpickin.com
* Twitter – http://twitter.com/gpickin
* Github - https://github.com/gpickin
* Lets get on with the show.
* 
* A few questions for you guys
* If you have arms, use them.
* 
* Most CF Apps are moving towards
providing an API for multiple consumers
* CF has many REST API Solutions and
even more with CF 12 coming soon
* Built in CF
* Built in Railo/Lucee
* Coldbox API
* Taffy
* 
* Click around in the browser yourself
* Setup Selenium / Web Driver to click
around for you
* Structured Programmatic Tests
* 
* Black/White Box
* Unit Testing
* Integration Testing
* Functional Tests
* System Tests
* End to End Tests
* Sanity Testing
* Regression Test
* Acceptance Tests
* Load Testing
* Stress Test
* Performance Tests
* Usability Tests
* + More
* 
* 
* Integration Tests several of the
pieces together
* Most of the types of tests are
variations of an Integration Test
* Can include mocks but can full end
to end tests including DB / APIs
* 
“unit testing is a software verification
and validation method in which a
programmer tests if individual units of
source code are fit for use. A unit is the
smallest testable part of an application”
- wikipedia
* 
* Can improve code quality -> quick error
discovery
* Code confidence via immediate
verification
* Can expose high coupling
* Will encourage refactoring to produce >
testable code
* Remember: Testing is all about behavior
and expectations
* 
* TDD = Test Driven Development
* Write Tests
* Run them and they Fail
* Write Functions to Fulfill the Tests
* Tests should pass
* Refactor in confidence
* Test focus on Functionality
* 
* BDD = Behavior Driven Development
Actually similar to TDD except:
* Focuses on Behavior and Specifications
* Specs (tests) are fluent and readable
* Readability makes them great for all levels of
testing in the organization
* Hard to find TDD examples in JS that are not
using BDD describe and it blocks
* 
Test( ‘Email address must not be
blank’, function(){
notEqual(email, “”, "failed");
});
* 
Describe( ‘Email Address’,
function(){
It(‘should not be blank’, function(){
expect(email).not.toBe(“”);
});
});
* 
expect(true).toBe(true);
expect(true).toBe(true);
expect(true).toBe(true);
expect(true).toBe(true);
* 
expect(true).not.toBe(true);
expect(true).not.toBe(true);
expect(true).not.toBe(true);
expect(true).not.toBe(true);
expect(true).not.toBe(true);
* 
expect(true).toBe(true);
expect(a).not.toBe(null);
expect(a).toEqual(12);
expect(message).toMatch(/bar/);
expect(message).toMatch("bar");
expect(message).not.toMatch(/quux/);
expect(a.foo).toBeDefined();
expect(a.bar).not.toBeDefined();
* 
NodeJS - CLI In the Browser
* 
* MxUnit was the standard
* TestBox is the new standard
* Other options
* 
TestBox is a next generation testing
framework for ColdFusion (CFML) that is
based on BDD (Behavior Driven
Development) for providing a clean obvious
syntax for writing tests.
It contains not only a testing framework,
runner, assertions and expectations library
but also ships with MockBox, A Mocking &
Stubbing Framework,.
It also supports xUnit style of testing and
MXUnit compatibilities.
* 
function testHelloWorld(){
          $assert.includes( helloWorld(), ”world" );
     }
* 
describe("Hello world function", function() {
it(”contains the word world", function() {
expect(helloWorld()).toContain("world");
});
});
* 
feature( "Box Size", function(){
 
    describe( "In order to know what size box I need
              As a distribution manager
              I want to know the volume of the box", function(){
 
        scenario( "Get box volume", function(){
            given( "I have entered a width of 20
                And a height of 30
                And a depth of 40", function(){
                when( "I run the calculation", function(){
                      then( "the result should be 24000", function(){
                          // call the method with the arguments and test the outcome
                          expect( myObject.myFunction(20,30,40) ).toBe( 24000 );
                      });
                 });
* 
* There are a few choices
* 
* Jasmine, Mocha and QUnit
* 
* Jasmine comes ready to go out of the box
* Fluent Syntax – BDD Style
* Includes lots of matchers
* Has spies included
* Very popular, lots of support
* Angular uses Jasmine with Karma (CLI)
* Headless running and plays well with CI
servers
* 
* Async testing in 1.3 can be a
headache
* Async testing in 2.0 is hard to find
blog posts on (I need to write one)
* Expects *spec.js suffix for test files
* This can be modified depending on
how you are running the tests
* 
describe("Hello world function", function() {
it(”contains the word world", function() {
expect(helloWorld()).toContain("world");
});
});
* 
* Simple Setup
* Simple Async testing
* Works great with other Assertion
libraries like Chai ( not included )
* Solid Support with CI Servers, with
Plugins for others
* Opinion says Mocha blazing the trail for
new features
* 
* Requires other Libraries for key features
* No Assertion Library included
* No Mocking / Spied included
* Need to create the runner manually
* Newer to the game so not as popular or
supported as others but gaining traction.
* 
var expect = require('chai').expect;
describe(’Hello World Function', function(){
it('should contain the word world', function(){
expect(helloWorld()).to.contain(’world');
})
})
* 
* The oldest of the main testing frameworks
* Is popular due to use in jQuery and age
* Ember’s default Unit testing Framework
* 
* Development slowed down since
2013 (but still under development)
* Syntax – No BDD style
* Assertion libraries – limited
matchers
* 
QUnit.test( "ok test", function( assert ) {
assert.ok( true, "true succeeds" );
assert.ok( "non-empty", "non-empty string
succeeds" );
assert.ok( false, "false fails" );
assert.ok( 0, "0 fails" );
assert.ok( NaN, "NaN fails" );
assert.ok( "", "empty string fails" );
assert.ok( null, "null fails" );
assert.ok( undefined, "undefined fails" );
});
* 
Photo Credit – Kombination
http://www.kombination.co.za/wp-content/uploads/2012/10/baby_w_spaghetti_mess_4987941.jpg
* 
* 
* 
* Things to refactor to make your code testable
* Code should not be one big chunk of
Javascript in onReady()
* Deep nested callbacks & Anon functions
cannot easily be singled out and tested
* Remove Tight Coupling – DOM access for
example
* 
* Lets look at some code
* This isn’t BEST PRACTICE, its BETTER
PRACTICE than you were doing
* Its not really refactoring if you don’t have
tests, its
“moving code and asking for trouble”
Kev McCabe
* 
var personObjLit = {
ssn: ’xxxxxxxx',
age: '35',
name: 'Gavin Pickin',
getAge: function(){
return this.age;
},
getName: function() {
return this.name;
}
};
* 
var personObjLit2 = function() {
ssn = ’xxxxxxx';
age = '35';
name = 'Gavin Pickin’;
return {
getAge: function(){
return age;
},
getName: function() {
return name;
}
};
};
* 
* Using HTML Test Runners
* Keep a Browser open
* F5 refresh tests
* 
* Run Jasmine – manual
* Run tests at the end of each section of work
* Run Grunt-Watch – automatic
* Runs Jasmine on every file change
* Grunt can run other tasks as well,
minification etc
* 
* Browser Views
* Eclipse allows you to open files in
web view – uses HTML Runner
* Run Jasmine / Grunt / Karma in IDE
Console
* Fairly Easy to setup
* See Demo– Sublime Text 2 (if we have
time)
* 
* Install / Run Jasmine Standalone for Browser
* Install / Run Jasmine with NodeJs
* Install / Run Jasmine with Grunt Watch
* Install / Run Testbox in Browser
* Install / Run Testbox with Grunt Watch
* Install / Run Grunt Watch inside Sublime Text 2
* 
Download standalone package from Github (I have 2.1.3)
https://github.com/jasmine/jasmine/tree/master/dist
Unzip into your /tests folder
Run /tests/SpecRunner.html to see example tests
* 
* 
http://www.testableapi.local.com:8504/tests/SpecRunner.html
* 
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Jasmine Spec Runner v2.1.3</title>
<link rel="shortcut icon" type="image/png" href="lib/jasmine-2.1.3/jasmine_favicon.png">
<link rel="stylesheet" href="lib/jasmine-2.1.3/jasmine.css”>
<script src="lib/jasmine-2.1.3/jasmine.js"></script>
<script src="lib/jasmine-2.1.3/jasmine-html.js"></script>
<script src="lib/jasmine-2.1.3/boot.js"></script>
<!-- include source files here... -->
<script src="../js/services/loginService.js"></script>
<!-- include spec files here... -->
<script src="spec/loginServiceSpec.js"></script>
</head>
<body>
</body>
</html>
* 
Assuming you have NodeJs Installed… install Jasmine
$ npm install jasmine
jasmine@2.2.1 node_modules/jasmine
├── exit@0.1.2
├── jasmine-core@2.2.0
└── glob@3.2.11 (inherits@2.0.1, minimatch@0.3.0)
* 
Once Jasmine is installed in your project
$ Jasmine init
* 
Edit Jasmine.json to update Locations for Spec Files and Helper Files
{
"spec_dir": "spec",
"spec_files": [
"**/*[sS]pec.js"
],
"helpers": [
"helpers/**/*.js"
]
}
* 
$ Jasmine
Started
F
Failures:
1) A suite contains spec with an expectation
Message:
Expected true to be false.
Stack:
Error: Expected true to be false.
at Object.<anonymous> (/Users/gavinpickin/Dropbox/Apps/
testApp/www/spec/test_spec.js:3:18)
1 spec, 1 failure
Finished in 0.009 seconds
* 
* Jasmine-Node is great for Node
* Jasmine Node doesn’t have a headless browser
* Hard to test Browser code
* So what should I use?
* 
* Install Grunt
npm install grunt
* Install Grunt – Jasmine
npm install grunt-contrib-jasmine
* Install Grunt – Watch
npm install grunt-contrib-watch
* Note: On Mac, I also needed to install Grunt CLI
npm install –g grunt-cli
* 
// gruntfile.js - https://gist.github.com/gpickin/1e1e7902d1d3676d23c5
module.exports = function (grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON('node_modules/grunt/package.json'),
jasmine: {
all: {
src: ['js/*.js' ],
options: {
//'vendor': ['path/to/vendor/libs/*.js'],
'specs': ['specs/*.js' ], '--web-security': false
}
}
},
* 
// gruntfile.js part 2
watch: {
js: {
files: [
'js/*.js',
'specs/*.js',
],
tasks: ['jasmine:all']
}
}
});
* 
// gruntfile.js part 3
grunt.loadNpmTasks('grunt-contrib-jasmine');
grunt.loadNpmTasks('grunt-contrib-watch');
};
* 
describe("Forgotten Password Form", function() {
it("should warn you if the email is invalid before making Ajax Call",
function() {
expect( isEmailInputInvalid('') ).toBe(true);
expect( isEmailInputInvalid('dddddddddd') ).toBe(true);
expect( isEmailInputInvalid('dddddd@') ).toBe(true);
expect( isEmailInputInvalid('dddddd@ddddd') ).toBe(true);
expect( isEmailInputInvalid('dddddd@ddddddd.') ).toBe(true);
expect( isEmailInputInvalid('dddddd@ddddddd.com') ).toBe(false);
});
});
* 
describe("Login Form", function() {
it("should set status correct status message with successful Ajax
Response", function() {
spyOn( window, "setStatusMessage");
processLoginAjaxDone('{"RESULT":"200"}');
expect(setStatusMessage).toHaveBeenCalled();
expect(setStatusMessage).toHaveBeenCalledWith(
‘TARDIS Access Granted - Please wait for the Doctor to take you for
a spin');
});
});
* 
describe("Login API", function() {
it("should return a failing Ajax Response", function() {
spyOn( window, "processLoginAjaxDone");
loginButtonEventHandlerProcess( 'gavin@gavin.co.nz',
'password');
expect(processLoginAjaxDone).toHaveBeenCalled();
expect(processLoginAjaxDone).toHaveBeenCalledWith(
‘{"RESULT":400}');
expect(processLoginAjaxFail).not.toHaveBeenCalled();
});
});
* 
describe("Login API", function() {
it("should return a failing Ajax Response", function() {
spyOn( window, "processLoginAjaxDone");
loginButtonEventHandlerProcess( 'gavin@gavin.co.nz',
'password');
expect(processLoginAjaxDone).toHaveBeenCalled();
expect(processLoginAjaxDone).toHaveBeenCalledWith(
‘{"RESULT":400}');
expect(processLoginAjaxFail).not.toHaveBeenCalled();
});
});
* 
* You want Unit Tests to test the unit and not it’s
dependencies
* You want Unit Tests to run quick
* You should mock the API in the Ajax call
* But we want to test the API
* So essentially, we’re writing an integration test.
* 
describe("Login API", function() {
beforeEach(function( done ) {
spyOn( window, "processLoginAjaxDone").and.callFake(
function(){ done(); });
spyOn( window, "processLoginAjaxFail").and.callFake(
function(){ done(); });
loginButtonEventHandlerProcess('gavin@gavin.co.nz', 'password');
});
it("should return a failing Ajax Response", function() { });
});
* 
describe("Login API", function() {
beforeEach(function( done ) {
…
});
it("should return a failing Ajax Response", function() {
expect(processLoginAjaxDone).toHaveBeenCalled();
expect(processLoginAjaxDone).toHaveBeenCalledWith(
'{"RESULT":400}');
expect(processLoginAjaxFail).not.toHaveBeenCalled();
});
});
* 
* 
* 
* Install Testbox – Thanks to Commandbox
* box install testbox
* Decide how you want to run Testbox
* 
* <cfsetting showDebugOutput="false">
* <!--- Executes all tests in the 'specs' folder with simple reporter by
default --->
* <cfparam name="url.reporter" default="simple">
* <cfparam name="url.directory" default="tests.specs">
* <cfparam name="url.recurse" default="true" type="boolean">
* <cfparam name="url.bundles" default="">
* <cfparam name="url.labels" default="">
* <!--- Include the TestBox HTML Runner --->
* <cfinclude template="/testbox/system/runners/HTMLRunner.cfm" >
* 
// tests/specs/CFCTest.cfc
component extends="testbox.system.BaseSpec" {
function run() {
it( "will error with incorrect login", function(){
var oTest = new cfcs.userServiceRemote();
expect( oTest.login( 'gavin@gavin.com',
'topsecret').result ).toBe('400');
});
}
}
* 
// tests/specs/APITest.cfc
component extends="testbox.system.BaseSpec" {
function run() {
describe("userService API Login", function(){
it( "will error with incorrect login", function(){
var email = "gavin@gavin.com";
var password = "topsecret”;
var result = "";
http url="http://www.testableapi.local.com:8504/cfcs/
userServiceRemote.cfc?method=login&email=#email#&password=#password#"
result="result”;
expect( DeserializeJSON(result.filecontent).result ).toBe('400');
});
});
}
}
* 
* Install Testbox Runner – Thanks Sean Coyne
* npm install testbox-runner
* Install Grunt Shell
* npm install grunt-shell
* Add Grunt Configuration
* 
* Install Testbox Runner – Thanks Sean Coyne
* npm install testbox-runner
* Install Grunt Shell
* npm install grunt-shell
* Add Grunt Configuration
* 
module.exports = function (grunt) {
grunt.loadNpmTasks('grunt-shell');
grunt.initConfig({ … })
}
* 
Watch: {
…
cfml: {
files: [ "cfcs/*.cfc"],
tasks: [ "testbox" ]
}
}
* 
shell: {
testbox: {
command: "./node_modules/testbox-
runner/index.js --colors --runner http://
www.testableapi.local.com:8504/tests/
runner.cfm --directory /tests/specs --recurse
true”
}
}
* 
grunt.registerTask("testbox", [ "shell:testbox" ]);
grunt.loadNpmTasks('grunt-contrib-jasmine');
grunt.loadNpmTasks('grunt-contrib-watch');
* 
js: {
files: [
'js/*.js',
'specs/*.js',
"cfcs/*.cfc”
],
tasks: ['jasmine:all']
},
* 
Jasmine
https://gist.github.com/gpickin/
1e1e7902d1d3676d23c5
Jasmine + Testbox
https://gist.github.com/gpickin/
9fc82df3667eeb63c7e7
* 
* 
* Testbox has several runners, you have seen the
HTML one, this Runner uses the JSON runner and
then formats it.
* http://www.testableapi.local.com:8504/tests/
runner.cfm?reporter=JSON&directory=%2Ftests
%2Fspecs&recurse=true
* 
* Install PackageControl into Sublime Text
* Install Grunt from PackageControl
* https://packagecontrol.io/packages/Grunt
* Update Grunt Sublime Settings for paths
{
"exec_args": { "path": "/bin:/usr/bin:/usr/local/bin” }
}
* Then Command Shift P – grunt
* 
* 
* Any questions?
* Interesting Link:
https://medium.com/@Zyklus/beautiful-seamless-
javascript-testing-in-10-minutes-2a743637035b
* 
https://www.ortussolutions.com/odw
FREE ONLINE

How do I Write Testable Javascript so I can Test my CF API on Server and Client

  • 1.
  • 2.
    *  * Who Am I? * Stateof the Room? * CF API * Ways to test your API? * Overview of Testing Tools * Using Testing in your Workflow * Installing Jasmine * Installing Testbox * Live Demo
  • 3.
    *  * Gavin Pickin –developing Web Apps since late 90s * New Addition to Ortus Solutions * ContentBox Evangelist * What else do you need to know? * Blog - http://www.gpickin.com * Twitter – http://twitter.com/gpickin * Github - https://github.com/gpickin * Lets get on with the show.
  • 4.
    *  * A few questionsfor you guys * If you have arms, use them.
  • 5.
    *  * Most CF Appsare moving towards providing an API for multiple consumers * CF has many REST API Solutions and even more with CF 12 coming soon * Built in CF * Built in Railo/Lucee * Coldbox API * Taffy
  • 6.
    *  * Click around inthe browser yourself * Setup Selenium / Web Driver to click around for you * Structured Programmatic Tests
  • 7.
    *  * Black/White Box * Unit Testing * IntegrationTesting * Functional Tests * System Tests * End to End Tests * Sanity Testing * Regression Test * Acceptance Tests * Load Testing * Stress Test * Performance Tests * Usability Tests * + More
  • 8.
  • 9.
    *  * Integration Tests severalof the pieces together * Most of the types of tests are variations of an Integration Test * Can include mocks but can full end to end tests including DB / APIs
  • 10.
    *  “unit testing isa software verification and validation method in which a programmer tests if individual units of source code are fit for use. A unit is the smallest testable part of an application” - wikipedia
  • 11.
    *  * Can improve codequality -> quick error discovery * Code confidence via immediate verification * Can expose high coupling * Will encourage refactoring to produce > testable code * Remember: Testing is all about behavior and expectations
  • 12.
    *  * TDD = TestDriven Development * Write Tests * Run them and they Fail * Write Functions to Fulfill the Tests * Tests should pass * Refactor in confidence * Test focus on Functionality
  • 13.
    *  * BDD = BehaviorDriven Development Actually similar to TDD except: * Focuses on Behavior and Specifications * Specs (tests) are fluent and readable * Readability makes them great for all levels of testing in the organization * Hard to find TDD examples in JS that are not using BDD describe and it blocks
  • 14.
    *  Test( ‘Email addressmust not be blank’, function(){ notEqual(email, “”, "failed"); });
  • 15.
    *  Describe( ‘Email Address’, function(){ It(‘shouldnot be blank’, function(){ expect(email).not.toBe(“”); }); });
  • 16.
  • 17.
  • 18.
  • 19.
    *  NodeJS - CLIIn the Browser
  • 20.
    *  * MxUnit was thestandard * TestBox is the new standard * Other options
  • 21.
    *  TestBox is anext generation testing framework for ColdFusion (CFML) that is based on BDD (Behavior Driven Development) for providing a clean obvious syntax for writing tests. It contains not only a testing framework, runner, assertions and expectations library but also ships with MockBox, A Mocking & Stubbing Framework,. It also supports xUnit style of testing and MXUnit compatibilities.
  • 22.
  • 23.
    *  describe("Hello world function",function() { it(”contains the word world", function() { expect(helloWorld()).toContain("world"); }); });
  • 24.
    *  feature( "Box Size",function(){       describe( "In order to know what size box I need               As a distribution manager               I want to know the volume of the box", function(){           scenario( "Get box volume", function(){             given( "I have entered a width of 20                 And a height of 30                 And a depth of 40", function(){                 when( "I run the calculation", function(){                       then( "the result should be 24000", function(){                           // call the method with the arguments and test the outcome                           expect( myObject.myFunction(20,30,40) ).toBe( 24000 );                       });                  });
  • 25.
  • 26.
  • 27.
    *  * Jasmine comes readyto go out of the box * Fluent Syntax – BDD Style * Includes lots of matchers * Has spies included * Very popular, lots of support * Angular uses Jasmine with Karma (CLI) * Headless running and plays well with CI servers
  • 28.
    *  * Async testing in1.3 can be a headache * Async testing in 2.0 is hard to find blog posts on (I need to write one) * Expects *spec.js suffix for test files * This can be modified depending on how you are running the tests
  • 29.
    *  describe("Hello world function",function() { it(”contains the word world", function() { expect(helloWorld()).toContain("world"); }); });
  • 30.
    *  * Simple Setup * Simple Asynctesting * Works great with other Assertion libraries like Chai ( not included ) * Solid Support with CI Servers, with Plugins for others * Opinion says Mocha blazing the trail for new features
  • 31.
    *  * Requires other Librariesfor key features * No Assertion Library included * No Mocking / Spied included * Need to create the runner manually * Newer to the game so not as popular or supported as others but gaining traction.
  • 32.
    *  var expect =require('chai').expect; describe(’Hello World Function', function(){ it('should contain the word world', function(){ expect(helloWorld()).to.contain(’world'); }) })
  • 33.
    *  * The oldest ofthe main testing frameworks * Is popular due to use in jQuery and age * Ember’s default Unit testing Framework
  • 34.
    *  * Development slowed downsince 2013 (but still under development) * Syntax – No BDD style * Assertion libraries – limited matchers
  • 35.
    *  QUnit.test( "ok test",function( assert ) { assert.ok( true, "true succeeds" ); assert.ok( "non-empty", "non-empty string succeeds" ); assert.ok( false, "false fails" ); assert.ok( 0, "0 fails" ); assert.ok( NaN, "NaN fails" ); assert.ok( "", "empty string fails" ); assert.ok( null, "null fails" ); assert.ok( undefined, "undefined fails" ); });
  • 36.
    *  Photo Credit –Kombination http://www.kombination.co.za/wp-content/uploads/2012/10/baby_w_spaghetti_mess_4987941.jpg
  • 37.
  • 38.
  • 39.
    *  * Things to refactorto make your code testable * Code should not be one big chunk of Javascript in onReady() * Deep nested callbacks & Anon functions cannot easily be singled out and tested * Remove Tight Coupling – DOM access for example
  • 40.
    *  * Lets look atsome code * This isn’t BEST PRACTICE, its BETTER PRACTICE than you were doing * Its not really refactoring if you don’t have tests, its “moving code and asking for trouble” Kev McCabe
  • 41.
    *  var personObjLit ={ ssn: ’xxxxxxxx', age: '35', name: 'Gavin Pickin', getAge: function(){ return this.age; }, getName: function() { return this.name; } };
  • 42.
    *  var personObjLit2 =function() { ssn = ’xxxxxxx'; age = '35'; name = 'Gavin Pickin’; return { getAge: function(){ return age; }, getName: function() { return name; } }; };
  • 43.
    *  * Using HTML TestRunners * Keep a Browser open * F5 refresh tests
  • 44.
    *  * Run Jasmine –manual * Run tests at the end of each section of work * Run Grunt-Watch – automatic * Runs Jasmine on every file change * Grunt can run other tasks as well, minification etc
  • 45.
    *  * Browser Views * Eclipse allowsyou to open files in web view – uses HTML Runner * Run Jasmine / Grunt / Karma in IDE Console * Fairly Easy to setup * See Demo– Sublime Text 2 (if we have time)
  • 46.
    *  * Install / RunJasmine Standalone for Browser * Install / Run Jasmine with NodeJs * Install / Run Jasmine with Grunt Watch * Install / Run Testbox in Browser * Install / Run Testbox with Grunt Watch * Install / Run Grunt Watch inside Sublime Text 2
  • 47.
    *  Download standalone packagefrom Github (I have 2.1.3) https://github.com/jasmine/jasmine/tree/master/dist Unzip into your /tests folder Run /tests/SpecRunner.html to see example tests
  • 48.
  • 49.
  • 50.
    *  <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>JasmineSpec Runner v2.1.3</title> <link rel="shortcut icon" type="image/png" href="lib/jasmine-2.1.3/jasmine_favicon.png"> <link rel="stylesheet" href="lib/jasmine-2.1.3/jasmine.css”> <script src="lib/jasmine-2.1.3/jasmine.js"></script> <script src="lib/jasmine-2.1.3/jasmine-html.js"></script> <script src="lib/jasmine-2.1.3/boot.js"></script> <!-- include source files here... --> <script src="../js/services/loginService.js"></script> <!-- include spec files here... --> <script src="spec/loginServiceSpec.js"></script> </head> <body> </body> </html>
  • 51.
    *  Assuming you haveNodeJs Installed… install Jasmine $ npm install jasmine jasmine@2.2.1 node_modules/jasmine ├── exit@0.1.2 ├── jasmine-core@2.2.0 └── glob@3.2.11 (inherits@2.0.1, minimatch@0.3.0)
  • 52.
    *  Once Jasmine isinstalled in your project $ Jasmine init
  • 53.
    *  Edit Jasmine.json toupdate Locations for Spec Files and Helper Files { "spec_dir": "spec", "spec_files": [ "**/*[sS]pec.js" ], "helpers": [ "helpers/**/*.js" ] }
  • 54.
    *  $ Jasmine Started F Failures: 1) Asuite contains spec with an expectation Message: Expected true to be false. Stack: Error: Expected true to be false. at Object.<anonymous> (/Users/gavinpickin/Dropbox/Apps/ testApp/www/spec/test_spec.js:3:18) 1 spec, 1 failure Finished in 0.009 seconds
  • 55.
    *  * Jasmine-Node is greatfor Node * Jasmine Node doesn’t have a headless browser * Hard to test Browser code * So what should I use?
  • 56.
    *  * Install Grunt npm installgrunt * Install Grunt – Jasmine npm install grunt-contrib-jasmine * Install Grunt – Watch npm install grunt-contrib-watch * Note: On Mac, I also needed to install Grunt CLI npm install –g grunt-cli
  • 57.
    *  // gruntfile.js -https://gist.github.com/gpickin/1e1e7902d1d3676d23c5 module.exports = function (grunt) { grunt.initConfig({ pkg: grunt.file.readJSON('node_modules/grunt/package.json'), jasmine: { all: { src: ['js/*.js' ], options: { //'vendor': ['path/to/vendor/libs/*.js'], 'specs': ['specs/*.js' ], '--web-security': false } } },
  • 58.
    *  // gruntfile.js part2 watch: { js: { files: [ 'js/*.js', 'specs/*.js', ], tasks: ['jasmine:all'] } } });
  • 59.
    *  // gruntfile.js part3 grunt.loadNpmTasks('grunt-contrib-jasmine'); grunt.loadNpmTasks('grunt-contrib-watch'); };
  • 60.
    *  describe("Forgotten Password Form",function() { it("should warn you if the email is invalid before making Ajax Call", function() { expect( isEmailInputInvalid('') ).toBe(true); expect( isEmailInputInvalid('dddddddddd') ).toBe(true); expect( isEmailInputInvalid('dddddd@') ).toBe(true); expect( isEmailInputInvalid('dddddd@ddddd') ).toBe(true); expect( isEmailInputInvalid('dddddd@ddddddd.') ).toBe(true); expect( isEmailInputInvalid('dddddd@ddddddd.com') ).toBe(false); }); });
  • 61.
    *  describe("Login Form", function(){ it("should set status correct status message with successful Ajax Response", function() { spyOn( window, "setStatusMessage"); processLoginAjaxDone('{"RESULT":"200"}'); expect(setStatusMessage).toHaveBeenCalled(); expect(setStatusMessage).toHaveBeenCalledWith( ‘TARDIS Access Granted - Please wait for the Doctor to take you for a spin'); }); });
  • 62.
    *  describe("Login API", function(){ it("should return a failing Ajax Response", function() { spyOn( window, "processLoginAjaxDone"); loginButtonEventHandlerProcess( 'gavin@gavin.co.nz', 'password'); expect(processLoginAjaxDone).toHaveBeenCalled(); expect(processLoginAjaxDone).toHaveBeenCalledWith( ‘{"RESULT":400}'); expect(processLoginAjaxFail).not.toHaveBeenCalled(); }); });
  • 63.
    *  describe("Login API", function(){ it("should return a failing Ajax Response", function() { spyOn( window, "processLoginAjaxDone"); loginButtonEventHandlerProcess( 'gavin@gavin.co.nz', 'password'); expect(processLoginAjaxDone).toHaveBeenCalled(); expect(processLoginAjaxDone).toHaveBeenCalledWith( ‘{"RESULT":400}'); expect(processLoginAjaxFail).not.toHaveBeenCalled(); }); });
  • 64.
    *  * You want UnitTests to test the unit and not it’s dependencies * You want Unit Tests to run quick * You should mock the API in the Ajax call * But we want to test the API * So essentially, we’re writing an integration test.
  • 65.
    *  describe("Login API", function(){ beforeEach(function( done ) { spyOn( window, "processLoginAjaxDone").and.callFake( function(){ done(); }); spyOn( window, "processLoginAjaxFail").and.callFake( function(){ done(); }); loginButtonEventHandlerProcess('gavin@gavin.co.nz', 'password'); }); it("should return a failing Ajax Response", function() { }); });
  • 66.
    *  describe("Login API", function(){ beforeEach(function( done ) { … }); it("should return a failing Ajax Response", function() { expect(processLoginAjaxDone).toHaveBeenCalled(); expect(processLoginAjaxDone).toHaveBeenCalledWith( '{"RESULT":400}'); expect(processLoginAjaxFail).not.toHaveBeenCalled(); }); });
  • 67.
  • 68.
  • 69.
    *  * Install Testbox –Thanks to Commandbox * box install testbox * Decide how you want to run Testbox
  • 70.
    *  * <cfsetting showDebugOutput="false"> * <!--- Executesall tests in the 'specs' folder with simple reporter by default ---> * <cfparam name="url.reporter" default="simple"> * <cfparam name="url.directory" default="tests.specs"> * <cfparam name="url.recurse" default="true" type="boolean"> * <cfparam name="url.bundles" default=""> * <cfparam name="url.labels" default=""> * <!--- Include the TestBox HTML Runner ---> * <cfinclude template="/testbox/system/runners/HTMLRunner.cfm" >
  • 71.
    *  // tests/specs/CFCTest.cfc component extends="testbox.system.BaseSpec"{ function run() { it( "will error with incorrect login", function(){ var oTest = new cfcs.userServiceRemote(); expect( oTest.login( 'gavin@gavin.com', 'topsecret').result ).toBe('400'); }); } }
  • 72.
    *  // tests/specs/APITest.cfc component extends="testbox.system.BaseSpec"{ function run() { describe("userService API Login", function(){ it( "will error with incorrect login", function(){ var email = "gavin@gavin.com"; var password = "topsecret”; var result = ""; http url="http://www.testableapi.local.com:8504/cfcs/ userServiceRemote.cfc?method=login&email=#email#&password=#password#" result="result”; expect( DeserializeJSON(result.filecontent).result ).toBe('400'); }); }); } }
  • 73.
    *  * Install Testbox Runner– Thanks Sean Coyne * npm install testbox-runner * Install Grunt Shell * npm install grunt-shell * Add Grunt Configuration
  • 74.
    *  * Install Testbox Runner– Thanks Sean Coyne * npm install testbox-runner * Install Grunt Shell * npm install grunt-shell * Add Grunt Configuration
  • 75.
    *  module.exports = function(grunt) { grunt.loadNpmTasks('grunt-shell'); grunt.initConfig({ … }) }
  • 76.
    *  Watch: { … cfml: { files:[ "cfcs/*.cfc"], tasks: [ "testbox" ] } }
  • 77.
    *  shell: { testbox: { command:"./node_modules/testbox- runner/index.js --colors --runner http:// www.testableapi.local.com:8504/tests/ runner.cfm --directory /tests/specs --recurse true” } }
  • 78.
    *  grunt.registerTask("testbox", [ "shell:testbox"]); grunt.loadNpmTasks('grunt-contrib-jasmine'); grunt.loadNpmTasks('grunt-contrib-watch');
  • 79.
  • 80.
  • 81.
  • 82.
    *  * Testbox has severalrunners, you have seen the HTML one, this Runner uses the JSON runner and then formats it. * http://www.testableapi.local.com:8504/tests/ runner.cfm?reporter=JSON&directory=%2Ftests %2Fspecs&recurse=true
  • 83.
    *  * Install PackageControl intoSublime Text * Install Grunt from PackageControl * https://packagecontrol.io/packages/Grunt * Update Grunt Sublime Settings for paths { "exec_args": { "path": "/bin:/usr/bin:/usr/local/bin” } } * Then Command Shift P – grunt
  • 84.
  • 85.
  • 86.