J5tester

J5tester is a stand alone JavaScript unit tester that uses gjs as it's engine. It was developed to test non-DOM JavaScript code such as that produced for use with the GNOME Shell.

Motivations

I use it to test my pure JavaScript AMQP bindings (Kamaloka-js) as it allows me to add automated testing as well as encourages me to start separating out browser specific code from the more generic JavaScript code. I also wanted to scratch an itch and learn the internals of embedding gjs and using it with GObjects.

In the future other engines could be added to both provide cross engine testing as well as facilitate drop in replacements with seed, v8, etc. in the GNOME stack.

Availability and Status

J5tester-0.2 is available but most of the development will happen in git.

Download the tarball: j5tester-0.2.tar.bz2

Git cloning

Example

This example shows some features of the J5tester by testing my Kamaloka-js bindings. Feel free to update this with a more GNOME example. For this example we change to the kamaloka-js directory to start running the tests.

kamaloka-js/test/main.js

   1 // eval_script is used similar to gjs imports except it works 
   2 // more like a script tag by evaling the module in the global context
   3 //
   4 // Note you will need the latest jsio from git
   5 eval_script('j5tester_jsio');
   6 
   7 // use the jsio importer to import the module I am testing
   8 // as is done when this is run in a browser
   9 jsio('import qpid_amqp as amqp');
  10 
  11 // use the gjs importer to import j5tester
  12 const J5tester = imports.j5tester;
  13 
  14 print('kamaloka-js unit tests');
  15 
  16 /* convenience function for checking address formats 
  17  * Params:
  18  *   t - the test object
  19  *   name - the address name we expect after it is parsed
  20  *   subject - the subject string we expect after it is parsed
  21  *   options - the options we expect after they are parsed 
  22  */
  23 let check_address = function(t, a, name, subject, options) {
  24     if(!options)
  25         options = {};
  26         
  27     t.indent(); // indent the output
  28 
  29     // check if the name and subject are what we expect, the last param is a optional comment
  30     t.assertEquals(a.name, name,"Checking if name is '" + name + "'");
  31     t.assertEquals(a.subject, subject, "Checking if subject is '" + subject + "'");
  32     
  33     // print out an info message, we also have t.warn and t.debug 
  34     t.info("Checking options");
  35   
  36     if(typeof(options) != typeof(a.options))
  37         t.fail(typeof(options) + " != " + typeof(a.options)); // you can fail your own checks and print out a custom comment
  38         
  39     if (options) {
  40         // check if the options are of type 'object'
  41         t.assertTypeOf(a.options, 'object');
  42         t.assertEquals(options.length, a.options.length, 'Checking if options has ' + options.length + ' elements');
  43        
  44         for (var o in options) {
  45             if (o == 'x-properties') {
  46                 // TODO: x-properties require more complex checking
  47             } else {
  48                 var test_val = options[o];
  49                 // check if each option equals what we expect
  50                 t.assertEquals(test_val, a.options[o], "Checking if option " + o + " == " + test_val);
  51             }
  52         }
  53     }
  54     
  55     // unindent the output
  56     t.unindent();
  57 }
  58 
  59 let address_tests = {
  60   // all object members that start with 'test' are run
  61   testValidAddresses: function() {
  62     // import our AddressParser class to test
  63     jsio('from amqp.protocol import AddressParser');
  64     
  65     var raw_addr = 'test';
  66     var a = new AddressParser(raw_addr);
  67     this.info("Checking address " + raw_addr);
  68     // 'this' is the tester object
  69     check_address(this, a, 'test', null, null);
  70     
  71     var raw_addr = 'test2/wow';
  72     a = new AddressParser(raw_addr);
  73     this.info("Checking address " + raw_addr);
  74     check_address(this, a, 'test2', 'wow');
  75     
  76     var raw_addr = 'test3/org.wow;{arg1: 1, "arg2":\'2\'}';
  77     a = new AddressParser(raw_addr);
  78     this.info("Checking address " + raw_addr);
  79     check_address(this, a, 'test3', 'org.wow', {arg1: 1, arg2:'2'});
  80     
  81     var raw_addr = "test4;{\"arg1\": 1, arg2:'2'}";
  82     a = new AddressParser(raw_addr);
  83     this.info("Checking address " + raw_addr);
  84     check_address(this, a, 'test4', null, {arg1:1, arg2:'2'});
  85   }
  86 }
  87 
  88 // create the tester object and send in the tests we want to run
  89 test = new J5tester.Test({"Address Format Tests": address_tests});
  90 // run the test
  91 test.run();

To run this test we use this on the command line:

 ../j5tester-0.2/src/j5tester -p src/ -p jsio/ test/main.js 

The -p switch tells j5tester to add a directory to the search path. In this case the kamaloka-js sources reside in the src/ directory and the jsio sources reside in the jsio/ directory. The test/ directory is automatically added to the search path.

Jsio should be fixed in git so that it no longer needs a patch to work with j5tester.

Projects/J5tester (last edited 2013-12-03 18:51:01 by WilliamJonMcCann)