Skip to content

aron/lazy.js

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

16 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Lazy.js
=======

Lazily evaluated properties. Useful for tests.

About
-----

Sometimes it is desirable to have variables that are only evaluated at the
moment they are used. This is often the case with nested test suites, where
later tests may need to create objects with slightly different properties.

    var options, view;

    before(function () {
      options = {enabled: false};
      view = new View(this.options);
    });

    it('does not render if enabled is false', function () {
      assert(view.canRender() === false);
    });

    it('can render if enabled is true', function () {
      options.enabled = true;
      view = new View(options); // We have to recreate the view.
      assert(view.canRender() === true);
    });

Using lazy properties we can update the options object before the view is
created.

    var ctx = lazy();

    before(function () {
      ctx.set('options', function () { return {enabled: false}; };
      ctx.set('view', function () { return new View(ctx.options); });
    });

    it('does not render if enabled is false', function () {
      // View is created now when ctx.view is accessed.
      assert(ctx.view.canRender() === false);
    });

    it('can render if enabled is true', function () {
      // View has not been created yet.
      ctx.options.enabled = true;
      // View will be created now, with the above options.
      assert(ctx.view.canRender() === true);
    });

Usage
-----

A context is required to instantiate the object. By default this is a plain
JavaScript object but you can pass anything into it you like.

    var ctx = lazy();
    ctx.set('myProperty', function () { return 'hello'; });
    ctx.myProperty //=> 'hello;

Use the set method to define properties on the object, or just use normal
assignment. If set is passed a function, this will be evaluated the first
time the property is accessed, this happens only once, after that the
property will be set as normal.

    ctx.set('number', Math.random);
    ctx.number //=> 0.43455677
    ctx.number //=> 0.43455677

If you want to set the same properties for every test, you can pass a wrapper
into the lazy() function, this allows you to hook into a test suites before
calls.

    before(function () {
      ctx.set('foo', 'bar'); // This can create messy before blocks.
    });

    // Alternatively pass a wrapper as the third argument to lazy().
    var ctx = lazy({}, 'set', before);

    // This will still be called in each before block and keeps your
    // definitions seperate from the setup.
    ctx.set('foo', 'bar');

    before(function () {
      ctx.foo; //=> "bar"
    });

Some test frameworks provide a shared context between before and after blocks
you can pass this into lazy() to use it instead.

    before(function () {
      lazy(this); // Some test frameworks share context between tests.
      this.set('myProperty', function () { return 'hello'; });
      this.myProperty //=> 'hello;
    });

The scope inside the lazy function will always be the context, allowing easy
access to other properties. This is useful if you use the above style.

    this.set('options', function () { return {model: this.model}; });
    this.set('model', function () { return new Model; });
    this.set('view', function () { return new View(this.options); });
    this.view; // First view will be evaluated, then options, then model.

A clean() function is provided to reset the properies back between each
test run. This is useful if you're sharing the context with the test runner,
otherwise it's unlikely to be needed.

    var ctx = lazy();
    ctx.set('foo', 'bar');
    ctx.set.clean();
    ctx.hasOwnProperty('foo'); //=> false

If you use CoffeeScript or ES6 arrow functions you get a much cleaner syntax.

    ctx.set 'model', -> new Model();
    ctx.model

    before ->
      lazy(this)
      @set 'model', -> new Model();
      @model

Installation
------------

The script works in both the browser and on the server although Internet
Explorer 8 and under will not work due to lack of defineProperty support.

For AMD users the script is registered under the "lazy" namespace.

Testing
-------

The test suite can be run from the command line assuming you have node[1]
installed:

    $ node lazy-test.js

You should see a line output saying the tests were a success, or a list of
the currently failing tests. The suite uses the node assertion library[2]
and a simple test runner included at the bottom of the file.

The tests are also run on each commit via Travis CI you can check out the
current state by visiting:

https://travis-ci.org/aron/lazy.js

[1]: http://nodejs.org
[2]: http://nodejs.org/api/assert.html

License
-------

Available under the MIT licence.

About

Deferred initialisation of object properties for unit tests

Resources

License

Stars

Watchers

Forks

Packages

No packages published