YUI3 Yogi – Module Creation and Tests

In my previous post about the YUI3 Shifter tool, I mentioned that we needed a certain directory structure to create a new module. This is where the YUI3 yogi tool comes in to save the day (more like time). Instead of creating a module’s directory structure from scratch or copying the structure from a previous module, yogi will enable us to create a module from scratch with a couple of commands.

In Anthony Pipkin’s talk, he explains how to integrate a new custom module with the YUI3 gallery. I would recommend watching this video for a good overview of yogi.

Installing the Tools
Before we can run the yogi tool, please install git scm and Node.js on your local machine. These are required in order to run yogi. Since YUI uses Github to host the source code for its YUI3 gallery modules, it is assumed that developers will also use git as the scm.

Before continuing, it may be good to know that yogi will use PhantomJS to drive the module tests. I would recommend installing this for smooth sailing later.

Now that we have the require tools installed, let us install the latest version of yogi. As of this writing, yogi 0.0.75 is available.

npm -g install yogi
yogi --version

Creating our Module Repository and its First Module
First create a git repository that will hold the module repository’s source. Then create the module directory structure and files with yogi using the following commands:

git init test-repository
yogi init test-module --type js

This will create a directory structure that looks like this:
yogi-dir-structure

Developing our First Module
Here is an example of a module.

/*jslint vars: true*/
/**
 * Defines our TestModule object.
 * 
 * @author Bret K. Ikehara
 * @constructor
 * @version 1.0.0 
 */
var TestModule = function () {
  TestModule.superclass.constructor.apply(this, arguments);
};
/**
 * Define our TestModule in the Y.com.bikehara package.
 */
Y.namespace('com.bikehara').TestModule = Y.extend(TestModule, Y.Base,
/**
 * Override the superclass attributes.
 */
{
  /**
   * Initializes this module.
   * 
   * @private 
   */
  "initializer" : function () {
    // TODO implement module.
  },
  /**
   * Destroys this module.
   * 
   * @private 
   */
  "destructor" : function () {
    // TODO destroy module.
  }
},
/**
 * Static content.
 */
{
  /**
   * This name.
   */
  NAME : "test-module",
  /**
   * This attributes.
   */
  ATTRS : {
    "message" : {
      "value" : "hello"
    }
  }
});

After creating our first module, yogi can build the script by invoking inside the module repository directory:

yogi build --walk --recursive

This build command is really a wrapper for YUI3 shifter tool that I previously wrote about. Please look at the shifter tool on how to add options to a .shifter.json file to easily build your modules.

Setup the Test
Before I begin the testing portion of this post, let me preface this portion by saying that our module is not defined in the YUI loader yet, whether that be the gallery, an edited loader, or applied configs. The other assumption is the script build directory will be a sibling of the src directory, just like the YUI project directory.

Inside the ./src/test-module/tests/unit/index.html file, the test runner is defined for our module, but our module will not be loaded with the index.html in its current state. Since the module is not defined in the YUI loader, we need to add a reference to this module file. Now add this line to load our module on index.html page load.

<script src="../../../../build/test-module/test-module-min.js"></script>

This will occur if the original script is used instead of the built module script.
yogi-build-non-built-module

With our test-module available in the index.html page, let us fix up our test dependency. On the bottom of our ./src/test-module/tests/unit/js/test.js file, there is an array of required modules. Ensure that the name of the module, in this case ‘test-module’, has been added to this array. This is the same name used to create the module using the yogi init [module name] command.

This ‘undefined’ error will occur if the module is not reference correctly.
yogi-build-module-undefined

Define the Test
Now that the test files have been configured, the module unit tests can be defined.

/**
 * Adds the module for testing.
 */
YUI.add('module-tests', function (Y) {
  // create our suite runner.
  var suite = new Y.Test.Suite ('test-module');
  suite.add(new Y.Test.Case ({
    name : 'Automated Tests',
    'test is empty' : function () {
      // create our module.
      var module = new Y.com.bikehara.TestModule({
        'message' : 'hello world'
      });
      // run our tests.
      Y.Assert.areEqual('hello world', module.get('message'), "Message has been set.");
    }
  }));
  Y.Test.Runner.add(suite);
}, '', {
  requires : ['test-module', 'test']
});

Although this is not a very exciting test (rather it just test the Attribute functionality), let us run the test command to see the results.

cd ./src/test-module/
yogi test

If the test went well, we should see an output similar to this:
yogi-build-successful

After Thoughts
Yogi broke down all the frustration that I had creating a module only using the shifter tool. Module creation using yogi is a breeze. Now we can get on to more coding and less fiddling with the project structure.