SlideShare uma empresa Scribd logo
1 de 72
JavaScript Is Not a ToyIt’s Time it was Tested Developers James Hatton : salesforce.com Alexis Williams: salesforce.com
Safe Harbor Safe harbor statement under the Private Securities Litigation Reform Act of 1995: This presentation may contain forward-looking statements that involve risks, uncertainties, and assumptions. If any such uncertainties materialize or if any of the assumptions proves incorrect, the results of salesforce.com, inc. could differ materially from the results expressed or implied by the forward-looking statements we make. All statements other than statements of historical fact could be deemed forward-looking, including any projections of subscriber growth, earnings, revenues, or other financial items and any statements regarding strategies or plans of management for future operations, statements of belief, any statements concerning new, planned, or upgraded services or technology developments and customer contracts or use of our services. The risks and uncertainties referred to above include – but are not limited to – risks associated with developing and delivering new functionality for our service, our new business model, our past operating losses, possible fluctuations in our operating results and rate of growth, interruptions or delays in our Web hosting, breach of our security measures, the outcome of intellectual property and other litigation, risks associated with possible mergers and acquisitions, the immature market in which we operate, our relatively limited operating history, our ability to expand, retain, and motivate our employees and manage our growth, new releases of our service and successful customer deployment, our limited history reselling non-salesforce.com products, and utilization and selling to larger enterprise customers. Further information on potential factors that could affect the financial results of salesforce.com, inc. is included in our annual report on Form 10-K for the most recent fiscal year ended January 31, 2010.  This documents and others are available on the SEC Filings section of the Investor Information section of our Web site.  Any unreleased services or features referenced in this or other press releases or public statements are not currently available and may not be delivered on time or at all. Customers who purchase our services should make the purchase decisions based upon features that are currently available. Salesforce.com, inc. assumes no obligation and does not intend to update these forward-looking statements.
Our session’s Chatter feed
Agenda The evolution of JavaScript Tools to help you test: Jasmine by Pivotal Labs  YUI Test by Yahoo! Demos.  How to use these tools with the force.com platform Questions & Answers
Session Objective By the end of this session you will be ready to get started with Jasmine and YUI Test inside your force.com environment.
It’s not the ‘90s anymore In the past only trivial tasks were delegated to JavaScript Today’s applications have a growing dependency on JavaScript and asynchronous services
It’s not the ‘90s anymore
JavaScript is no longer a toy language
JavaScript is no longer a toy language
We’ve come a long way…
JavaScript breaks!
We have tools now Jasmine test framework by Pivotal Labs YUI test framework by Yahoo
Jasmine Jasmine is a behavior-driven development framework for testing your JavaScript code.  It does not depend on any other JavaScript frameworks.  It has a clean, obvious syntax so that you can easily write tests.
What is BDD? Behavior Driven Development “BDD is a second-generation, outside-in, pull-based, multiple-stakeholder, multiple-scale, high-automation, agile methodology.” Huh?
Hold on what is BDD? “A practice of writing test cases in a natural language that non-programmers can read.”
Example function helloWorld() { 	return "Hello, World!"; } describe('helloWorld()', function() { it('says hello', function() { expect(helloWorld()).toEqual("Hello, World!"); 	}); });
Another Example function copyToDiv() { var source = document.getElementById(‘source’); var content = document.getElementById(‘content’); content.innerHTML = source.innerHTML; } describe(’copyToDiv()', function() { it(’copies input data to content', function() { copyToDiv(); var content = document.getElementById(‘content’).innerHTML expect(content).toEqual(‘source data’); 	}); });
Tests are called “Specs” ,[object Object]
The string is a description of a behavior that you want your production code to exhibit; it should be meaningful to you when reading a report.it('should increment a variable', function () {  varfoo = 0;  foo++;  });
Expectations Within your spec you will express expectations about the behavior of your application code. This is done using the expect() function. function increment(foo) { 	returnfoo++; } describe('increment()', function() { 	it('should increment a variable', function() { varfoo = 0;  expect(increment(foo)).toEqual(1); 	}); });
Suites Specs are grouped in Suites. Suites are defined using the global describe() function. describe('Calculator', function () {  it('can add a number', function() { 	 ...  	});  it(’multiply some numbers', function() { 	 ...  	});  });
Expectation Matchers Jasmine has several built-in matchers.  For example: expect(x).toEqual(y);  expect(x).toBeNull();  expect(x).toContain(y);  expect(x).toBeLessThan(y);  expect(x).toBeGreaterThan(y);  expect(fn).toThrow(e);  Each matcher’s criteria can be inverted by prepending .not
Custom Matchers Jasmine includes a small set of matchers that cover many common situations.  However you can write custom matchers when you want to assert a more specific sort of expectation.  Custom matchers help to document the intent of your specs, and can help to remove code duplication in your specs.
Custom Matchers – An Example To add the matcher to your suite, call this.addMatchers() from within a  beforeEach or block.  beforeEach(function() {  this.addMatchers({  toBeVisible: function() {return this.actual.isVisible();} 	 });  });
Custom Matchers beforeEach(function() { this.addMatchers({ toBeACar: function() {       return this.actual.hasWheels() &&     	  		this.actual.hasEngine() && 			this.actual.hasSteeringWheel();     }   }); }); describe(‘car’, function() { it(‘is a car’, function() { expect(car).toBeACar();    }); });
beforeEach A suite can have a beforeEach() declaration. It takes a function that is run before each spec. For example: describe('some suite', function () {  varsuiteWideFoo;  beforeEach(function () {  suiteWideFoo = 1;     });  it('should equal bar', function () {        expect(suiteWideFoo).toEqual(1);    });  });
beforeEach Runner beforeEach() functions are executed before every spec in all suites, and execute BEFORE suite beforeEach() functions. For example: varrunnerWideFoo = [];  beforeEach(function () {  runnerWideFoo.push('runner');   }); describe('some suite', function () { beforeEach(function () {  runnerWideFoo.push('suite');    });  it('should equal bar', function () {  expect(runnerWideFoo).toEqual(['runner', 'suite']);   });  });
afterEach Similarly, there is an afterEach() declaration. It takes a function that is run after each spec. For example: describe('some suite', function () {  varsuiteWideFoo = 1;  afterEach(function () {  suiteWideFoo = 0;     });  it('should equal 1', function() {      expect(suiteWideFoo).toEqual(1);    });  it('should equal 0 after', function(){       expect (suiteWideFoo).toEqual(0);     }; });
afterEach varrunnerWideFoo = []; afterEach(function () { runnerWideFoo.push('runner'); }); describe('some suite', function () { afterEach(function () { runnerWideFoo.push('suite');   }); it('should be empty', function () { expect(runnerWideFoo).toEqual([]);   }); it('should be populated after', function () { expect(runnerWideFoo).toEqual(['suite', 'runner']);   }; });
Spies! Spies allow you to “spy” on the function being called granting far more visibility into its behavior then can be achieved by inspecting the return value.
How to spy on your code function Hostess(name) { this.name = name; this.getName = function() { return name; }; this.greetParty = function() {     return “My name is “ + this.getName() + “ please follow me”  }; //.. it(‘uses the name’, function() { var hostess = new Hostess(‘Janet’);  spyOn(hostess, ‘getName’); expect(hostess.greetParty()).toMatch(‘My name is Janet please follow me’); expect(hostess.getName).toHaveBeenCalled(); });
Spy-Specific Matchers There are spy-specific matchers that are very handy. expect(x).toHaveBeenCalled() expect(x).toHaveBeenCalledWith(arguments) expect(x).not.toHaveBeenCalled() expect(x).not.toHaveBeenCalledWith(arguments)
Useful Properties Spies have some useful properties: callCount mostRecentCall.args argsForCall[i] Spies are automatically removed after each spec. They may be set in the beforeEach function.
Spy Example 2 varKlass = function () { };  Klass.staticMethod = function (arg) {  	return arg;  };  Klass.prototype.method = function (arg) {  	return arg;  }; Klass.prototype.methodWithCallback = function (callback) {  	return callback('foo');  };
Spy Example 2 Continued… it('should spy on a static method of Klass',    function() {  spyOn(Klass, 'staticMethod');  Klass.staticMethod('foo argument');  expect(Klass.staticMethod).toHaveBeenCalledWith('foo   	argument');  });
Spy Example 2 Continued… it('should spy on an instance method of a Klass', 	function() {  varobj = new Klass();  spyOn(obj, 'method');  obj.method('foo argument');  expect(obj.method).toHaveBeenCalledWith('foo 	  argument');  var obj2 = new Klass();  	  spyOn(obj2, 'method');  	  expect(obj2.method).not.toHaveBeenCalled();     });
Spy Example 2 Continued… it('should spy on Klass.methodWithCallback', function() {  var callback = jasmine.createSpy();  	new Klass().methodWithCallback(callback); expect(callback).toHaveBeenCalledWith('foo'); });
Spy Example 3 varKlass = function () { };  varKlass.prototype.asyncMethod = function (callback) {   someAsyncCall(callback);  };
Spy Example 3 Continued… it('should test async call') { spyOn(Klass, 'asyncMethod'); var callback = jasmine.createSpy(); Klass.asyncMethod(callback); expect(callback).not.toHaveBeenCalled(); varsomeResponseData = 'foo';   Klass.asyncMethod.mostRecentCall.args[0](someResponseData); expect(callback).toHaveBeenCalledWith(someResponseData); });
Asynchronous Specs Imagine you need to make a call that is asynchronous - an AJAX API, event callback, or some other JavaScript library.  That is, the call returns immediately, yet you want to make expectations ‘at some point in the future’ after some magic happens in the background. Jasmine allows you to do this with runs(), waits() and waitsFor() blocks.
Asynchronous Specs describe('Spreadsheet', function() {  it('should calculate the total asynchronously', function () {  var spreadsheet = new Spreadsheet();        spreadsheet.fillWith(lotsOfFixureDataValues()); spreadsheet.asynchronouslyCalculateTotal(); waitsFor(function() { return spreadsheet.calculationIsComplete(); }, "Spreadsheet calculation never completed", 10000);  runs(function () {      expect(spreadsheet.total).toEqual(123456);  });  }); });
Jasmine Demo
Alexis Williams salesforce.com
YUI Test – What is it? YUI Test is a test driven development framework for testing your JavaScript code.  It does not depend on any other JavaScript frameworks.  It allows you to plug into any other frameworks: Dojo, jQuery, Prototype… It has a clean JSON like syntax many of us are familiar with already
YUI Test – What are the Benefits? Reduces overall ramp up time Familiar JSON like syntax Tests cases are easy to create Provides setup and tear down functionality Writing tests (unit) is easy Explicitly indicates test outcomes Groups together test case statistics
Getting Started with YUI Test Create HTML page Include required resources: Java script and CSS Create test case Add unit tests Add test cases to test suite Open in web browser to run test suite and view results
Test Cases and Unit Tests {Test Methods} Test Case is comprised of unit tests Unit tests exercise small, isolated units of code Unit tests have expected input and outputs The test case will present the number of passed and failed unit tests
Creating a Test Case and Test Methods Pt. 1 Create a new instance of the TestCase Any method prefixed with lower case test is considered a unit test to run Any method not defined already or prefixed with test is considered a helper method Built in methods: Set up: set up data that will be consumed in test methods Tear down: construct to tear down data setup for test methods
Creating a Test Case and Test Methods Pt. 2
Test Method Assertions Pt. 1 Equality Assertions areEqual() and areNotEqual(): both accept 3 arguments: expected value, actual value, and optional failure message Assert.areEqual(5, 5);     //passes Assert.areEqual(5, "5");     //passes Assert.areEqual(5, 6, "Five was expected."); //fails Sameness Assertions areSame() and areNotSame(): same argument structure like equals, but uses different comparison operator (===) Assert.areSame(5, "5");    //fails Assert.areNotSame(5, 6);   //passes Assert.areSame(5, 6, "Five was expected."); //fails
Test Method Assertions Pt. 2 Data Type Assertions test the data type of variables: accepts 2 arguments, the variable to test, and an optional error message.  Assert.isString("Hello world");     //passes Assert.isNumber(1);                 //passes Assert.isArray([]);                 //passes Assert.isObject([]);                //passes Assert.isFunction(function(){});    //passes Assert.isBoolean(true);             //passes Assert.isObject(function(){});      //passes
Test Method Assertions Pt. 3 Special Value Assertions designed to test for the following special values: true, false, NaN, null, and undefined. Accepts 2 arguments again: the variable to test, and an optional error message. Assert.isFalse(false);      //passes             Assert.isNaN(5 / "5");      //passes Assert.isNull(null);        //passes Assert.isUndefined(undefined);  //passes Forced Failures Forced failure you can optionally pass a message into
Getting Test Cases Ready to Run Pt. 1 Create new instance of TestSuite Add testCases to TestSuite Create new instance of TestLogger Add the test suite to TestLogger Run the test suite with TestRunner when the DOM is ready
Getting Test Cases Ready to Run Pt. 2
Enter The Complexities – Browser Environment Dependencies upon page events Execution types: Synchronous Asynchronous Different behaviors exhibited per browser
Simulating User Actions {Mouse & Keyboard} Each event is fired by a corresponding method on UserAction that accepts two arguments: the target of the event and an optional object specifying additional information for the event YAHOO.util.UserAction object provides methods to simulate basic user events involving the keyboard and mouse
Simulating Mouse Actions Seven mouse events that can be simulated: click, dblclick, mousedown, mouseup, mouseover, mouseout, mousemove var element = document.getElementById("myDiv"); //simulate a click Alt key down YAHOO.util.UserAction.click(element, { altKey: true}); //simulate a double click with Ctrl key down YAHOO.util.UserAction.dblclick(element, { ctrlKey: true });
Simulating Keyboard Actions Three key events that can be simulated: keyup, keydown, keypress Key events also support the ctrlKey, altKey, shiftKey, and metaKey event properties var element = document.getElementById("myDiv"); //simulate a keydown on the A key YAHOO.util.UserAction.keydown(element, { keyCode: 97 }); //simulate a keyup on the A key YAHOO.util.UserAction.keyup(element, { keyCode: 97 });
Asynchronous Testing – Wait Pt. 1 YUI Test allows you to pause a currently running test and resume either after a set amount of time or at another designated time The TestCase object has a method called wait(). When wait() is called, the test immediately exits (meaning that any code after that point will be ignored) and waits for a signal to resume the test.
Asynchronous Testing – Wait Pt. 2 A test may be resumed after a certain amount of time by passing in two arguments to wait(): a function to execute and the number of milliseconds to wait before executing the function (similar to using setTimeout()).  The function passed in as the first argument will be executed as part of the current test (in the same scope) after the specified amount of time.
Asynchronous Testing – Wait Pt. 3  Example of using wait with a timer
Real Life Example {Ghost Text} Pt. 1 Need: when user loads a VF page they are presented ghost text (grey) in description field. The text should disappear when they click in the field, text color should be black, and reappear if they don’t add any text with text color back to grey Translation: create function to populate text and erase text Function:  Add ghost text to field Remove ghost text from field Add ghost text to field if needed
Real Life Example {Ghost Text} Pt. 2 Render ghost text when Description field is null
Real Life Example {Ghost Text} Pt. 3 Remove ghost text when clicking in Description field
Real Life Example {Ghost Text} Pt. 4
Working with the Results Test Logger Use the test logger to output the results varoLogger = new YAHOO.tool.TestLogger(); YAHOO.tool.TestRunner.run();
Working with the Results Test Reporter Pt. 1 Use the test reporter to create a form that posts the results to a specific URL:  results - the serialized results object. useragent - the user-agent string of the browser. timestamp - the date and time that the report was sent. One way direction – no return processed from server Does not cause you to navigate away from page varoReporter = new YAHOO.tool.TestReporter("http://www.yourserver.com/path/to/target"); oReporter.report(results);
Working with the Results Test Reporter Pt. 2 Custom fields Custom fields can be added to the results report using the addField() method Custom fields are appended to the standard fields posted oReporter.addField("User_Story_c", "a0lB00000004IkV"); oReporter.addField("Test_Case__c", "a07B0000000DlSEIA0");
Working with the Results Test Reporter Pt. 3 Two serialization formats for the results objects: XML and JSON XML is the default format varoReporter = new YAHOO.tool.TestReporter("https://na1.salesforce.com/apex/processYIUTest", YAHOO.tool.TestFormat.JSON);
Which one should I use?
ResourcesJasmine: http://pivotal.github.com/jasmine/YUI Test: http://developer.yahoo.com/yui/yuitest/
Questions?

Mais conteúdo relacionado

Semelhante a Java Script Isn\'t a Toy Anymore

S-Controls for Dummies
S-Controls for DummiesS-Controls for Dummies
S-Controls for Dummiesdreamforce2006
 
S-Controls for Dummies
S-Controls for DummiesS-Controls for Dummies
S-Controls for Dummiesdreamforce2006
 
How We Built the Private AppExchange App (Apex, Visualforce, RWD)
How We Built the Private AppExchange App (Apex, Visualforce, RWD)How We Built the Private AppExchange App (Apex, Visualforce, RWD)
How We Built the Private AppExchange App (Apex, Visualforce, RWD)Salesforce Developers
 
Introduction to the Wave Platform API
Introduction to the Wave Platform APIIntroduction to the Wave Platform API
Introduction to the Wave Platform APISalesforce Developers
 
Connect Your Clouds with Force.com
Connect Your Clouds with Force.comConnect Your Clouds with Force.com
Connect Your Clouds with Force.comJeff Douglas
 
Visualforce Hack for Junction Objects
Visualforce Hack for Junction ObjectsVisualforce Hack for Junction Objects
Visualforce Hack for Junction ObjectsRitesh Aswaney
 
Salesforce1 Platform for programmers
Salesforce1 Platform for programmersSalesforce1 Platform for programmers
Salesforce1 Platform for programmersSalesforce Developers
 
Dive Deep into Apex: Advanced Apex!
Dive Deep into Apex: Advanced Apex! Dive Deep into Apex: Advanced Apex!
Dive Deep into Apex: Advanced Apex! Salesforce Developers
 
Integrating Force.com with Heroku
Integrating Force.com with HerokuIntegrating Force.com with Heroku
Integrating Force.com with HerokuPat Patterson
 
Introduction to Developing Android Apps With the Salesforce Mobile SDK
Introduction to Developing Android Apps With the Salesforce Mobile SDKIntroduction to Developing Android Apps With the Salesforce Mobile SDK
Introduction to Developing Android Apps With the Salesforce Mobile SDKSalesforce Developers
 
Advanced Apex Webinar
Advanced Apex WebinarAdvanced Apex Webinar
Advanced Apex Webinarpbattisson
 
Lightning web components episode 2- work with salesforce data
Lightning web components   episode 2- work with salesforce dataLightning web components   episode 2- work with salesforce data
Lightning web components episode 2- work with salesforce dataSalesforce Developers
 
February 2020 Salesforce API Review
February 2020 Salesforce API ReviewFebruary 2020 Salesforce API Review
February 2020 Salesforce API ReviewLydon Bergin
 
Spring '14 Release Developer Preview Webinar
Spring '14 Release Developer Preview WebinarSpring '14 Release Developer Preview Webinar
Spring '14 Release Developer Preview WebinarSalesforce Developers
 

Semelhante a Java Script Isn\'t a Toy Anymore (20)

S-Controls for Dummies
S-Controls for DummiesS-Controls for Dummies
S-Controls for Dummies
 
S-Controls for Dummies
S-Controls for DummiesS-Controls for Dummies
S-Controls for Dummies
 
ELEVATE Paris
ELEVATE ParisELEVATE Paris
ELEVATE Paris
 
How We Built the Private AppExchange App (Apex, Visualforce, RWD)
How We Built the Private AppExchange App (Apex, Visualforce, RWD)How We Built the Private AppExchange App (Apex, Visualforce, RWD)
How We Built the Private AppExchange App (Apex, Visualforce, RWD)
 
Intro to Apex Programmers
Intro to Apex ProgrammersIntro to Apex Programmers
Intro to Apex Programmers
 
Introduction to the Wave Platform API
Introduction to the Wave Platform APIIntroduction to the Wave Platform API
Introduction to the Wave Platform API
 
Connect Your Clouds with Force.com
Connect Your Clouds with Force.comConnect Your Clouds with Force.com
Connect Your Clouds with Force.com
 
Introduction to Apex for Developers
Introduction to Apex for DevelopersIntroduction to Apex for Developers
Introduction to Apex for Developers
 
Speed of Lightning
Speed of LightningSpeed of Lightning
Speed of Lightning
 
Finding Security Issues Fast!
Finding Security Issues Fast!Finding Security Issues Fast!
Finding Security Issues Fast!
 
Visualforce Hack for Junction Objects
Visualforce Hack for Junction ObjectsVisualforce Hack for Junction Objects
Visualforce Hack for Junction Objects
 
Salesforce1 Platform for programmers
Salesforce1 Platform for programmersSalesforce1 Platform for programmers
Salesforce1 Platform for programmers
 
Dive Deep into Apex: Advanced Apex!
Dive Deep into Apex: Advanced Apex! Dive Deep into Apex: Advanced Apex!
Dive Deep into Apex: Advanced Apex!
 
Integrating Force.com with Heroku
Integrating Force.com with HerokuIntegrating Force.com with Heroku
Integrating Force.com with Heroku
 
Force.com Friday : Intro to Apex
Force.com Friday : Intro to Apex Force.com Friday : Intro to Apex
Force.com Friday : Intro to Apex
 
Introduction to Developing Android Apps With the Salesforce Mobile SDK
Introduction to Developing Android Apps With the Salesforce Mobile SDKIntroduction to Developing Android Apps With the Salesforce Mobile SDK
Introduction to Developing Android Apps With the Salesforce Mobile SDK
 
Advanced Apex Webinar
Advanced Apex WebinarAdvanced Apex Webinar
Advanced Apex Webinar
 
Lightning web components episode 2- work with salesforce data
Lightning web components   episode 2- work with salesforce dataLightning web components   episode 2- work with salesforce data
Lightning web components episode 2- work with salesforce data
 
February 2020 Salesforce API Review
February 2020 Salesforce API ReviewFebruary 2020 Salesforce API Review
February 2020 Salesforce API Review
 
Spring '14 Release Developer Preview Webinar
Spring '14 Release Developer Preview WebinarSpring '14 Release Developer Preview Webinar
Spring '14 Release Developer Preview Webinar
 

Java Script Isn\'t a Toy Anymore

  • 1. JavaScript Is Not a ToyIt’s Time it was Tested Developers James Hatton : salesforce.com Alexis Williams: salesforce.com
  • 2. Safe Harbor Safe harbor statement under the Private Securities Litigation Reform Act of 1995: This presentation may contain forward-looking statements that involve risks, uncertainties, and assumptions. If any such uncertainties materialize or if any of the assumptions proves incorrect, the results of salesforce.com, inc. could differ materially from the results expressed or implied by the forward-looking statements we make. All statements other than statements of historical fact could be deemed forward-looking, including any projections of subscriber growth, earnings, revenues, or other financial items and any statements regarding strategies or plans of management for future operations, statements of belief, any statements concerning new, planned, or upgraded services or technology developments and customer contracts or use of our services. The risks and uncertainties referred to above include – but are not limited to – risks associated with developing and delivering new functionality for our service, our new business model, our past operating losses, possible fluctuations in our operating results and rate of growth, interruptions or delays in our Web hosting, breach of our security measures, the outcome of intellectual property and other litigation, risks associated with possible mergers and acquisitions, the immature market in which we operate, our relatively limited operating history, our ability to expand, retain, and motivate our employees and manage our growth, new releases of our service and successful customer deployment, our limited history reselling non-salesforce.com products, and utilization and selling to larger enterprise customers. Further information on potential factors that could affect the financial results of salesforce.com, inc. is included in our annual report on Form 10-K for the most recent fiscal year ended January 31, 2010. This documents and others are available on the SEC Filings section of the Investor Information section of our Web site. Any unreleased services or features referenced in this or other press releases or public statements are not currently available and may not be delivered on time or at all. Customers who purchase our services should make the purchase decisions based upon features that are currently available. Salesforce.com, inc. assumes no obligation and does not intend to update these forward-looking statements.
  • 4. Agenda The evolution of JavaScript Tools to help you test: Jasmine by Pivotal Labs YUI Test by Yahoo! Demos. How to use these tools with the force.com platform Questions & Answers
  • 5. Session Objective By the end of this session you will be ready to get started with Jasmine and YUI Test inside your force.com environment.
  • 6. It’s not the ‘90s anymore In the past only trivial tasks were delegated to JavaScript Today’s applications have a growing dependency on JavaScript and asynchronous services
  • 7. It’s not the ‘90s anymore
  • 8. JavaScript is no longer a toy language
  • 9. JavaScript is no longer a toy language
  • 10. We’ve come a long way…
  • 12. We have tools now Jasmine test framework by Pivotal Labs YUI test framework by Yahoo
  • 13. Jasmine Jasmine is a behavior-driven development framework for testing your JavaScript code. It does not depend on any other JavaScript frameworks. It has a clean, obvious syntax so that you can easily write tests.
  • 14. What is BDD? Behavior Driven Development “BDD is a second-generation, outside-in, pull-based, multiple-stakeholder, multiple-scale, high-automation, agile methodology.” Huh?
  • 15. Hold on what is BDD? “A practice of writing test cases in a natural language that non-programmers can read.”
  • 16. Example function helloWorld() { return "Hello, World!"; } describe('helloWorld()', function() { it('says hello', function() { expect(helloWorld()).toEqual("Hello, World!"); }); });
  • 17. Another Example function copyToDiv() { var source = document.getElementById(‘source’); var content = document.getElementById(‘content’); content.innerHTML = source.innerHTML; } describe(’copyToDiv()', function() { it(’copies input data to content', function() { copyToDiv(); var content = document.getElementById(‘content’).innerHTML expect(content).toEqual(‘source data’); }); });
  • 18.
  • 19. The string is a description of a behavior that you want your production code to exhibit; it should be meaningful to you when reading a report.it('should increment a variable', function () { varfoo = 0; foo++; });
  • 20. Expectations Within your spec you will express expectations about the behavior of your application code. This is done using the expect() function. function increment(foo) { returnfoo++; } describe('increment()', function() { it('should increment a variable', function() { varfoo = 0; expect(increment(foo)).toEqual(1); }); });
  • 21. Suites Specs are grouped in Suites. Suites are defined using the global describe() function. describe('Calculator', function () { it('can add a number', function() { ... }); it(’multiply some numbers', function() { ... }); });
  • 22. Expectation Matchers Jasmine has several built-in matchers. For example: expect(x).toEqual(y); expect(x).toBeNull(); expect(x).toContain(y); expect(x).toBeLessThan(y); expect(x).toBeGreaterThan(y); expect(fn).toThrow(e); Each matcher’s criteria can be inverted by prepending .not
  • 23. Custom Matchers Jasmine includes a small set of matchers that cover many common situations. However you can write custom matchers when you want to assert a more specific sort of expectation. Custom matchers help to document the intent of your specs, and can help to remove code duplication in your specs.
  • 24. Custom Matchers – An Example To add the matcher to your suite, call this.addMatchers() from within a beforeEach or block. beforeEach(function() { this.addMatchers({ toBeVisible: function() {return this.actual.isVisible();} }); });
  • 25. Custom Matchers beforeEach(function() { this.addMatchers({ toBeACar: function() { return this.actual.hasWheels() && this.actual.hasEngine() && this.actual.hasSteeringWheel(); } }); }); describe(‘car’, function() { it(‘is a car’, function() { expect(car).toBeACar(); }); });
  • 26. beforeEach A suite can have a beforeEach() declaration. It takes a function that is run before each spec. For example: describe('some suite', function () { varsuiteWideFoo; beforeEach(function () { suiteWideFoo = 1; }); it('should equal bar', function () { expect(suiteWideFoo).toEqual(1); }); });
  • 27. beforeEach Runner beforeEach() functions are executed before every spec in all suites, and execute BEFORE suite beforeEach() functions. For example: varrunnerWideFoo = []; beforeEach(function () { runnerWideFoo.push('runner'); }); describe('some suite', function () { beforeEach(function () { runnerWideFoo.push('suite'); }); it('should equal bar', function () { expect(runnerWideFoo).toEqual(['runner', 'suite']); }); });
  • 28. afterEach Similarly, there is an afterEach() declaration. It takes a function that is run after each spec. For example: describe('some suite', function () { varsuiteWideFoo = 1; afterEach(function () { suiteWideFoo = 0; }); it('should equal 1', function() { expect(suiteWideFoo).toEqual(1); }); it('should equal 0 after', function(){ expect (suiteWideFoo).toEqual(0); }; });
  • 29. afterEach varrunnerWideFoo = []; afterEach(function () { runnerWideFoo.push('runner'); }); describe('some suite', function () { afterEach(function () { runnerWideFoo.push('suite'); }); it('should be empty', function () { expect(runnerWideFoo).toEqual([]); }); it('should be populated after', function () { expect(runnerWideFoo).toEqual(['suite', 'runner']); }; });
  • 30. Spies! Spies allow you to “spy” on the function being called granting far more visibility into its behavior then can be achieved by inspecting the return value.
  • 31. How to spy on your code function Hostess(name) { this.name = name; this.getName = function() { return name; }; this.greetParty = function() { return “My name is “ + this.getName() + “ please follow me” }; //.. it(‘uses the name’, function() { var hostess = new Hostess(‘Janet’); spyOn(hostess, ‘getName’); expect(hostess.greetParty()).toMatch(‘My name is Janet please follow me’); expect(hostess.getName).toHaveBeenCalled(); });
  • 32. Spy-Specific Matchers There are spy-specific matchers that are very handy. expect(x).toHaveBeenCalled() expect(x).toHaveBeenCalledWith(arguments) expect(x).not.toHaveBeenCalled() expect(x).not.toHaveBeenCalledWith(arguments)
  • 33. Useful Properties Spies have some useful properties: callCount mostRecentCall.args argsForCall[i] Spies are automatically removed after each spec. They may be set in the beforeEach function.
  • 34. Spy Example 2 varKlass = function () { }; Klass.staticMethod = function (arg) { return arg; }; Klass.prototype.method = function (arg) { return arg; }; Klass.prototype.methodWithCallback = function (callback) { return callback('foo'); };
  • 35. Spy Example 2 Continued… it('should spy on a static method of Klass', function() { spyOn(Klass, 'staticMethod'); Klass.staticMethod('foo argument'); expect(Klass.staticMethod).toHaveBeenCalledWith('foo argument'); });
  • 36. Spy Example 2 Continued… it('should spy on an instance method of a Klass', function() { varobj = new Klass(); spyOn(obj, 'method'); obj.method('foo argument'); expect(obj.method).toHaveBeenCalledWith('foo argument'); var obj2 = new Klass(); spyOn(obj2, 'method'); expect(obj2.method).not.toHaveBeenCalled(); });
  • 37. Spy Example 2 Continued… it('should spy on Klass.methodWithCallback', function() { var callback = jasmine.createSpy(); new Klass().methodWithCallback(callback); expect(callback).toHaveBeenCalledWith('foo'); });
  • 38. Spy Example 3 varKlass = function () { }; varKlass.prototype.asyncMethod = function (callback) { someAsyncCall(callback); };
  • 39. Spy Example 3 Continued… it('should test async call') { spyOn(Klass, 'asyncMethod'); var callback = jasmine.createSpy(); Klass.asyncMethod(callback); expect(callback).not.toHaveBeenCalled(); varsomeResponseData = 'foo'; Klass.asyncMethod.mostRecentCall.args[0](someResponseData); expect(callback).toHaveBeenCalledWith(someResponseData); });
  • 40. Asynchronous Specs Imagine you need to make a call that is asynchronous - an AJAX API, event callback, or some other JavaScript library. That is, the call returns immediately, yet you want to make expectations ‘at some point in the future’ after some magic happens in the background. Jasmine allows you to do this with runs(), waits() and waitsFor() blocks.
  • 41. Asynchronous Specs describe('Spreadsheet', function() { it('should calculate the total asynchronously', function () { var spreadsheet = new Spreadsheet(); spreadsheet.fillWith(lotsOfFixureDataValues()); spreadsheet.asynchronouslyCalculateTotal(); waitsFor(function() { return spreadsheet.calculationIsComplete(); }, "Spreadsheet calculation never completed", 10000); runs(function () { expect(spreadsheet.total).toEqual(123456); }); }); });
  • 44. YUI Test – What is it? YUI Test is a test driven development framework for testing your JavaScript code. It does not depend on any other JavaScript frameworks. It allows you to plug into any other frameworks: Dojo, jQuery, Prototype… It has a clean JSON like syntax many of us are familiar with already
  • 45. YUI Test – What are the Benefits? Reduces overall ramp up time Familiar JSON like syntax Tests cases are easy to create Provides setup and tear down functionality Writing tests (unit) is easy Explicitly indicates test outcomes Groups together test case statistics
  • 46. Getting Started with YUI Test Create HTML page Include required resources: Java script and CSS Create test case Add unit tests Add test cases to test suite Open in web browser to run test suite and view results
  • 47. Test Cases and Unit Tests {Test Methods} Test Case is comprised of unit tests Unit tests exercise small, isolated units of code Unit tests have expected input and outputs The test case will present the number of passed and failed unit tests
  • 48. Creating a Test Case and Test Methods Pt. 1 Create a new instance of the TestCase Any method prefixed with lower case test is considered a unit test to run Any method not defined already or prefixed with test is considered a helper method Built in methods: Set up: set up data that will be consumed in test methods Tear down: construct to tear down data setup for test methods
  • 49. Creating a Test Case and Test Methods Pt. 2
  • 50. Test Method Assertions Pt. 1 Equality Assertions areEqual() and areNotEqual(): both accept 3 arguments: expected value, actual value, and optional failure message Assert.areEqual(5, 5); //passes Assert.areEqual(5, "5"); //passes Assert.areEqual(5, 6, "Five was expected."); //fails Sameness Assertions areSame() and areNotSame(): same argument structure like equals, but uses different comparison operator (===) Assert.areSame(5, "5"); //fails Assert.areNotSame(5, 6); //passes Assert.areSame(5, 6, "Five was expected."); //fails
  • 51. Test Method Assertions Pt. 2 Data Type Assertions test the data type of variables: accepts 2 arguments, the variable to test, and an optional error message. Assert.isString("Hello world"); //passes Assert.isNumber(1); //passes Assert.isArray([]); //passes Assert.isObject([]); //passes Assert.isFunction(function(){}); //passes Assert.isBoolean(true); //passes Assert.isObject(function(){}); //passes
  • 52. Test Method Assertions Pt. 3 Special Value Assertions designed to test for the following special values: true, false, NaN, null, and undefined. Accepts 2 arguments again: the variable to test, and an optional error message. Assert.isFalse(false); //passes Assert.isNaN(5 / "5"); //passes Assert.isNull(null); //passes Assert.isUndefined(undefined); //passes Forced Failures Forced failure you can optionally pass a message into
  • 53. Getting Test Cases Ready to Run Pt. 1 Create new instance of TestSuite Add testCases to TestSuite Create new instance of TestLogger Add the test suite to TestLogger Run the test suite with TestRunner when the DOM is ready
  • 54. Getting Test Cases Ready to Run Pt. 2
  • 55. Enter The Complexities – Browser Environment Dependencies upon page events Execution types: Synchronous Asynchronous Different behaviors exhibited per browser
  • 56. Simulating User Actions {Mouse & Keyboard} Each event is fired by a corresponding method on UserAction that accepts two arguments: the target of the event and an optional object specifying additional information for the event YAHOO.util.UserAction object provides methods to simulate basic user events involving the keyboard and mouse
  • 57. Simulating Mouse Actions Seven mouse events that can be simulated: click, dblclick, mousedown, mouseup, mouseover, mouseout, mousemove var element = document.getElementById("myDiv"); //simulate a click Alt key down YAHOO.util.UserAction.click(element, { altKey: true}); //simulate a double click with Ctrl key down YAHOO.util.UserAction.dblclick(element, { ctrlKey: true });
  • 58. Simulating Keyboard Actions Three key events that can be simulated: keyup, keydown, keypress Key events also support the ctrlKey, altKey, shiftKey, and metaKey event properties var element = document.getElementById("myDiv"); //simulate a keydown on the A key YAHOO.util.UserAction.keydown(element, { keyCode: 97 }); //simulate a keyup on the A key YAHOO.util.UserAction.keyup(element, { keyCode: 97 });
  • 59. Asynchronous Testing – Wait Pt. 1 YUI Test allows you to pause a currently running test and resume either after a set amount of time or at another designated time The TestCase object has a method called wait(). When wait() is called, the test immediately exits (meaning that any code after that point will be ignored) and waits for a signal to resume the test.
  • 60. Asynchronous Testing – Wait Pt. 2 A test may be resumed after a certain amount of time by passing in two arguments to wait(): a function to execute and the number of milliseconds to wait before executing the function (similar to using setTimeout()). The function passed in as the first argument will be executed as part of the current test (in the same scope) after the specified amount of time.
  • 61. Asynchronous Testing – Wait Pt. 3 Example of using wait with a timer
  • 62. Real Life Example {Ghost Text} Pt. 1 Need: when user loads a VF page they are presented ghost text (grey) in description field. The text should disappear when they click in the field, text color should be black, and reappear if they don’t add any text with text color back to grey Translation: create function to populate text and erase text Function: Add ghost text to field Remove ghost text from field Add ghost text to field if needed
  • 63. Real Life Example {Ghost Text} Pt. 2 Render ghost text when Description field is null
  • 64. Real Life Example {Ghost Text} Pt. 3 Remove ghost text when clicking in Description field
  • 65. Real Life Example {Ghost Text} Pt. 4
  • 66. Working with the Results Test Logger Use the test logger to output the results varoLogger = new YAHOO.tool.TestLogger(); YAHOO.tool.TestRunner.run();
  • 67. Working with the Results Test Reporter Pt. 1 Use the test reporter to create a form that posts the results to a specific URL: results - the serialized results object. useragent - the user-agent string of the browser. timestamp - the date and time that the report was sent. One way direction – no return processed from server Does not cause you to navigate away from page varoReporter = new YAHOO.tool.TestReporter("http://www.yourserver.com/path/to/target"); oReporter.report(results);
  • 68. Working with the Results Test Reporter Pt. 2 Custom fields Custom fields can be added to the results report using the addField() method Custom fields are appended to the standard fields posted oReporter.addField("User_Story_c", "a0lB00000004IkV"); oReporter.addField("Test_Case__c", "a07B0000000DlSEIA0");
  • 69. Working with the Results Test Reporter Pt. 3 Two serialization formats for the results objects: XML and JSON XML is the default format varoReporter = new YAHOO.tool.TestReporter("https://na1.salesforce.com/apex/processYIUTest", YAHOO.tool.TestFormat.JSON);
  • 71. ResourcesJasmine: http://pivotal.github.com/jasmine/YUI Test: http://developer.yahoo.com/yui/yuitest/
  • 73. How Could Dreamforce Be Better? Tell Us! Log in to the Dreamforce app to submit surveys for the sessions you attended Use the Dreamforce Mobile app to submit surveys OR Every session survey you submit is a chance to win an iPod nano!

Notas do Editor

  1. expect(x).toEqual(y); compares objects or primitives x and y and passes if they are equivalentexpect(x).toBeNull(); passes if x is nullexpect(x).toContain(y); passes if array or string x contains yexpect(x).toBeLessThan(y); passes if x is less than yexpect(x).toBeGreaterThan(y); passes if x is greater than yexpect(fn).toThrow(e); passes if function fn throws exception e when executed
  2. expect(x).toHaveBeenCalled() passes if x is a spy and was calledexpect(x).toHaveBeenCalledWith(arguments) passes if x is a spy and was called with the specified argumentsexpect(x).not.toHaveBeenCalled() passes if x is a spy and was not calledexpect(x).not.toHaveBeenCalledWith(arguments) passes if x is a spy and was not called with the specified arguments
  3. Spies have some useful properties:callCount: returns number of times spy was calledmostRecentCall.args: returns argument array from last call to spy.argsForCall[i] returns arguments array for call i to spy.Spies are automatically removed after each spec. They may be set in the beforeEach function.
  4. The callBack() is not actually called by the asyncMethod() it is only used as a method parameterHowever we do call it ourselves and we access it by inspecting the arguments used by the most recent callThen we verify our expected that the callBack() has now been called
  5. waitsFor() provides a better interface for pausing your spec until some other work has completed. Jasmine will wait until the provided function returns true before continuing with the next block. This may mean waiting an arbitrary period of time, or you may specify a maxiumum period in milliseconds before timing out:In this example, we create a spreadsheet and fill it with some sample data. We then ask the spreadsheet to start calculating its total, which presumably is a slow operation and therefore happens asynchronously. We ask Jasmine to wait until the spreadsheet’s calculation work is complete (or up to 10 seconds, whichever comes first) before continuing with the rest of the spec. If the calculation finishes within the allotted 10 seconds, Jasmine continues on to the final runs() block, where it validates the calculation. If the spreadsheet hasn’t finished calculations within 10 seconds, the spec stops and reports a spec failure with the message given in the waitsFor() block.In this example, we create a spreadsheet and fill it with some sample data. We then ask the spreadsheet to start calculating its total, which presumably is a slow operation and therefore happens asynchronously. We ask Jasmine to wait until the spreadsheet’s calculation work is complete (or up to 10 seconds, whichever comes first) before continuing with the rest of the spec. If the calculation finishes within the allotted 10 seconds, Jasmine continues on to the final runs() block, where it validates the calculation. If the spreadsheet hasn’t finished calculations within 10 seconds, the spec stops and reports a spec failure with the message given in the waitsFor() block.
  6. Force failures are exactly what they sound like. You want to force a failure. You are able to pass along a specific error message to be output.
  7. Some of the benefits of YUI testSome things you still need to deal with…
  8. Nice thing is standardized way to mimic user inputs that works everywhere
  9. Update your tests to run correctly in each browserYAHOO.env.ua.{browser}YAHOO.env.ua.gecko
  10. I like the approach because we can save the data into a custom object for reporting purposes
  11. Obvious benefits include creating new test executions relating user story record to test case