Search This Blog

Thursday, 30 April 2015

Using the Jasmine testing framework in an Adobe Designer LiveCycle Form

Jasmine is a popular testing framework for JavaScript applications.  There's lots of tutorials on using Jasmine so I wont go into a lot of detail but as an example if we had a form that has a item price field, a quantity field and a total field with Jasmine we can write a test something like;

 describe("Total Calculation: ", function()
 {
  beforeEach(function ()
  {
   TotalPriceCalculation.ItemPrice.rawValue = 1.75;
   TotalPriceCalculation.Quantity = 5000;
   TotalPriceCalculation.Total.execCalculate();
  });

  it("Equals ItemPrice * Quantity", function()
  {
   expect(TotalPriceCalculation.Total.rawValue).toEqual(8750);
  });
  it("Formatted in Australian Dollars ", function()
  {
   expect(TotalPriceCalculation.Total.formattedValue).toEqual("$8,750.00");
  });
 });

This is JavaScript code, describe, is a Jasmine function that takes a description and function as arguments. beforeEach is another function that is executed before every it  function which performs the actual test.  The above test will hopefully give us a result like;


The toEqual function after the expect is one of the standard Jasmine matches, the complete list is;

toBe( null | true | false )
toEqual( value )
toMatch( regex | string )
toBeDefined()
toBeUndefined()
toBeNull()
toBeTruthy()
toBeFalsy()
toContain( string )
toBeLessThan( number )
toBeGreaterThan( number )
toBeNaN()
toBeCloseTo( number, precision )


And the Jasmine framework allows us to add our own matches, so for the XFA environment I have added;

toBeVisible()
toBeInvisible()
toBeHidden()
toBeMandatory()
toBeProtected()
toBeOpen()
toBeValid()
toBeXFANull()
toHaveItemCount( number )
toHaveError( string )
toHaveFontColor ( "r,g,b" )


These are just helper functions target.toBeVisible() is the same as target.presence.toEqual("visible").

Other helper functions added for the XFA environment are

 /**
  * Raises the change event for a specified field
  * @param {XFA object}  field     The target field of the change event
  * @param {string}   newText    The value of the field after the change is applied
  * @param {string}   [change=newText] The value typed or pasted into the field that raises the change event
  * @param {boolean}  [keyDown=false]  The user is using an arrow key (listbox and dropdown only)
  * @param {boolean}  [modifier=false] The user is holding the Ctrl key down
  * @param {boolean}  [shift=false]  The user is holding the shift key down
  */

function execChangeEvent(field, newText, change, keyDown, modifier, shift) {


 /**
  * Raises the exit event for a specified field
  * @param {XFA object}  field     The target field of the exit event
  * @param {various}  rawValue    The value of the field before the exit event called, undefined doesn't update the field
  * @param {string}   [commitKey=3]  How the current value of the field was set: 0 - not set, escape key pressed, 1 - mouse click, 2 - enter key, 3 - tabbing
  * @param {boolean}  [modifier=false] The user is holding the Ctrl key down
  * @param {boolean}  [shift=false]  The user is holding the shift key down
  */

function execExitEvent(field, rawValue, commitKey, modifier, shift) {


 /**
  * Reset fields to their default values
  */

function resetData(/*arguments*/) {


In this sample Jasmine.xdp is a script object which is the standalone Jasmine code download with a fairly small modification to cater for the differences in the Adobe JavaScript environment.  The changes are commented at the start of the code but relate to the app.setTimeOut() function taking a string instead of a JavaScript statement.

Hopefully this sample will give you enough to get you going JasmineSample.pdf.  All the tests in this sample pass but when you get some that fail an exception will be thrown, you may want to set "When exception is thrown" to ignore in Acrobat JavaScript options.

The XFA bootstrap is in JasmineXFA.xdp and the Jasmine test are in JasmineSpec.xdp, all zipped in JasmineXDP.zip with the XDP of the sample.

The JasmineSpec.xdp is a form fragment, the tests are run as part of a click event of the "Run Jasmine Specs" button, the results are displayed in a text object in the same fragment.  The click event must start with the statement;

var jasmine = JasmineXFA.Bootstrap({environment:this})

this, adds the Jasmine functions and the XFA helpers and ends with the statement;

jasmine.getEnv().execute(); 

Which starts the actual tests.

The sample by default generates a pass/fail log to the console log as well. If you find generating output to the console log is getting in the way of your own debug statements you can turn the Jasmine output off by passing the includeConsoleReporter:false option.

var jasmine = JasmineXFA.Bootstrap({environment:this, includeConsoleReporter:false})

I tend to develop the tests as an embedded script object which allows me to use the control-click method of referencing fields, then when ready to be released change the script to a fragment and comment it out.  The XDP file being an XML file allows XML comments <!-- -->.  So in the XML Source view will look like;

<!--subform usehref=".\JasmineSpec.xdp#som($template.#subform.JasmineSpec)"></subform-->

I am using the Jasmine framework version 2.0, the latest is 2.2 but I have not been successful in getting later version to run in the Acrobat environment, again because of the differences in the app.setTimeOut() function.  I'm not sure what I am missing but 2.0 has provided enough functionality for me so far.




1 comment: