← Back to team overview

yellow team mailing list archive

[Merge] lp:~benji/juju-gui/bug-1081205 into lp:juju-gui

 

Benji York has proposed merging lp:~benji/juju-gui/bug-1081205 into lp:juju-gui.

Requested reviews:
  Benji York (benji): code
Related bugs:
  Bug #1081205 in juju-gui: "minification with bad "requires" param"
  https://bugs.launchpad.net/juju-gui/+bug/1081205

For more details, see:
https://code.launchpad.net/~benji/juju-gui/bug-1081205/+merge/135952

Remove "requires" properties.

The minification process does not read the "requires" parameters defined in
"all-app-debug.js". This parameter should be defined in each custom yui object
that uses some kind of internal or external requirement. The sole use of
"all-app-debug.js" is to define the fullpath of the file that defines a given
module.

This patch removes all the existing "requires" properties from
"all-app-debug.js" and add then where they are needed.

https://codereview.appspot.com/6845084/

-- 
https://code.launchpad.net/~benji/juju-gui/bug-1081205/+merge/135952
Your team Juju GUI Hackers is subscribed to branch lp:juju-gui.
=== modified file 'app/app.js'
--- app/app.js	2012-11-20 14:51:46 +0000
+++ app/app.js	2012-11-23 17:25:57 +0000
@@ -746,6 +746,7 @@
     'juju-models',
     'juju-views',
     'juju-controllers',
+    'juju-view-charm-search',
     'io',
     'json-parse',
     'app-base',

=== modified file 'app/models/charm.js'
--- app/models/charm.js	2012-10-29 11:20:31 +0000
+++ app/models/charm.js	2012-11-23 17:25:57 +0000
@@ -226,6 +226,7 @@
 }, '0.1.0', {
   requires: [
     'model',
-    'model-list'
+    'model-list',
+    'juju-charm-id'
   ]
 });

=== modified file 'app/models/models.js'
--- app/models/models.js	2012-11-16 08:25:02 +0000
+++ app/models/models.js	2012-11-23 17:25:57 +0000
@@ -487,6 +487,7 @@
     'datasource-jsonschema',
     'io-base',
     'json-parse',
+    'juju-endpoints',
     'juju-view-utils',
     'juju-charm-models'
   ]

=== modified file 'app/modules-debug.js'
--- app/modules-debug.js	2012-11-15 15:44:00 +0000
+++ app/modules-debug.js	2012-11-23 17:25:57 +0000
@@ -1,6 +1,13 @@
 // This file is used for development only. In order to use it you should call
 // the "make debug" command. This command passes the "debug" argument to the
 // "lib/server.js".
+//
+// This file declares which files implement modules, using the
+// "fullpath" property; and declares the membership of rollup modules, using
+// the "use" property to specify what the module name aliases.
+//
+// The "requires" property should not be used here because the javascript
+// minimizer will not parse it.
 var GlobalConfig = {
   filter: 'debug',
   // Set "true" for verbose logging of YUI
@@ -93,19 +100,15 @@
         },
 
         'juju-charm-models': {
-          requires: ['juju-charm-id'],
           fullpath: '/juju-ui/models/charm.js'
         },
 
         'juju-models': {
-          requires: [
-            'model', 'model-list', 'juju-endpoints', 'juju-charm-models'],
           fullpath: '/juju-ui/models/models.js'
         },
 
         // Connectivity
         'juju-env': {
-          requires: ['reconnecting-websocket'],
           fullpath: '/juju-ui/store/env.js'
         },
 
@@ -114,7 +117,6 @@
         },
 
         'juju-charm-store': {
-          requires: ['juju-charm-id'],
           fullpath: '/juju-ui/store/charm.js'
         },
 
@@ -125,13 +127,7 @@
 
         // App
         'juju-gui': {
-          fullpath: '/juju-ui/app.js',
-          requires: [
-            'juju-controllers',
-            'juju-views',
-            'juju-models',
-            'juju-view-charm-search'
-          ]
+          fullpath: '/juju-ui/app.js'
         }
       }
     }

=== modified file 'app/store/charm.js'
--- app/store/charm.js	2012-11-05 21:24:42 +0000
+++ app/store/charm.js	2012-11-23 17:25:57 +0000
@@ -114,6 +114,7 @@
 
 }, '0.1.0', {
   requires: [
+    'juju-charm-id',
     'datasource-io',
     'json-parse'
   ]

=== modified file 'test/test_app.js'
--- test/test_app.js	2012-11-14 14:34:31 +0000
+++ test/test_app.js	2012-11-23 17:25:57 +0000
@@ -31,196 +31,181 @@
   return app;
 }
 
-describe('Application basics', function() {
-  var Y, app, container;
-
-  before(function(done) {
-    Y = YUI(GlobalConfig).use(['juju-gui', 'juju-tests-utils'], function(Y) {
-      done();
-    });
-  });
-
-  beforeEach(function(done) {
-    //  XXX Apparently removing a DOM node is asynchronous (on Chrome at least)
-    //  and we occasionally lose the race if this code is in the afterEach
-    //  function, so instead we do it here, but only if one has previously been
-    //  created.
-    if (container) {
-      container.remove(true);
-    }
-    container = Y.one('#main')
-      .appendChild(Y.Node.create('<div/>'))
-        .set('id', 'test-container')
-        .addClass('container')
-        .append(Y.Node.create('<span/>')
-          .set('id', 'environment-name'))
-        .append(Y.Node.create('<span/>')
-          .set('id', 'provider-type'));
-    app = new Y.juju.App(
-        { container: container,
-          viewContainer: container});
-    injectData(app);
-    done();
-  });
-
-  it('should produce a valid index', function() {
-    var container = app.get('container');
-    app.render();
-    container.getAttribute('id').should.equal('test-container');
-    container.getAttribute('class').should.include('container');
-  });
-
-  it('should be able to route objects to internal URLs', function() {
-    // take handles to database objects and ensure we can route to the view
-    // needed to show them
-    var wordpress = app.db.services.getById('wordpress'),
-        wp0 = app.db.units.get_units_for_service(wordpress)[0],
-        wp_charm = app.db.charms.add({id: wordpress.get('charm')});
-
-    // 'service/wordpress/' is the primary and so other URL are not returned
-    app.getModelURL(wordpress).should.equal('/service/wordpress/');
-    // however passing 'intent' can force selection of another
-    app.getModelURL(wordpress, 'config').should.equal(
-        '/service/wordpress/config');
-
-    // service units use argument rewriting (thus not /u/wp/0)
-    app.getModelURL(wp0).should.equal('/unit/wordpress-0/');
-
-    // charms also require a mapping but only a name, not a function
-    app.getModelURL(wp_charm).should.equal(
-        '/charms/charms/precise/wordpress-6/json');
-  });
-
-  it('should display the configured environment name', function() {
-    var environment_name = 'This is the environment name.  Deal with it.';
-    app = new Y.juju.App(
-        { container: container,
-          viewContainer: container,
-          environment_name: environment_name});
-    assert.equal(
-        container.one('#environment-name').get('text'),
-        environment_name);
-  });
-
-  it('should show a generic environment name if none configured', function() {
-    app = new Y.juju.App(
-        { container: container,
-          viewContainer: container});
-    assert.equal(
-        container.one('#environment-name').get('text'),
-        'Environment');
-  });
-
-  it('should show the provider type, when available', function() {
-    var providerType = 'excellent provider';
-    // Since no provider type has been set yet, none is displayed.
-    assert.equal(
-        container.one('#provider-type').get('text'),
-        '');
-    app.env.set('providerType', providerType);
-    // The provider type has been displayed.
-    assert.equal(
-        container.one('#provider-type').get('text'),
-        'on ' + providerType);
-  });
-
-});
-
-
-describe('Application Connection State', function() {
-  var Y, container;
-
-  before(function(done) {
-    Y = YUI(GlobalConfig).use(['juju-gui', 'juju-tests-utils'], function(Y) {
-      container = Y.Node.create('<div id="test" class="container"></div>');
-      done();
-        });
-
-  });
-
-  it('should be able to handle env connection status changes', function() {
-    var juju = Y.namespace('juju'),
-        conn = new(Y.namespace('juju-tests.utils')).SocketStub(),
-        env = new juju.Environment({conn: conn}),
-        app = new Y.juju.App({env: env, container: container}),
-        reset_called = false,
-        noop = function() {return this;};
-
-
-    // mock the db
-    app.db = {
-      // mock out notifications
-      // so app can start normally
-      notifications: {
-        addTarget: noop,
-        after: noop,
-        filter: noop,
-        map: noop,
-        on: noop,
-        size: function() {return 0;}
-      },
-      reset: function() {
-        reset_called = true;
-               }
-    };
-    env.connect();
-    conn.open();
-    reset_called.should.equal(true);
-
-    // trigger a second time and verify
-    reset_called = false;
-    conn.open();
-    reset_called.should.equal(true);
-  });
-
-});
-
-describe('Application prefetching', function() {
-  var Y, models, conn, env, app, container, charm_store, data, juju;
-
-  before(function(done) {
-    Y = YUI(GlobalConfig).use(
-        'juju-models', 'juju-gui', 'datasource-local', 'juju-tests-utils',
-        'json-stringify',
-        function(Y) {
-          models = Y.namespace('juju.models');
-          done();
-        });
-  });
-
-  beforeEach(function() {
-    conn = new (Y.namespace('juju-tests.utils')).SocketStub(),
-    env = new Y.juju.Environment({conn: conn});
-    env.connect();
-    conn.open();
-    container = Y.Node.create('<div id="test" class="container"></div>');
-    data = [];
-    app = new Y.juju.App(
-        { container: container,
-          viewContainer: container,
-          env: env,
-          charm_store: {} });
-
-    app.updateEndpoints = function() {};
-    env.get_endpoints = function() {};
-  });
-
-  afterEach(function() {
-    container.destroy();
-    app.destroy();
-  });
-
-  it('must prefetch charm and service for service pages', function() {
-    injectData(app);
-    var _ = expect(
-        app.db.charms.getById('cs:precise/wordpress-6')).to.not.exist;
-    app.show_service({params: {id: 'wordpress'}, query: {}});
-    // The app made a request of juju for the service info.
-    conn.messages[conn.messages.length - 2].op.should.equal('get_service');
-    // The app also requested juju (not the charm store--see discussion in
-    // app/models/charm.js) for the charm info.
-    conn.last_message().op.should.equal('get_charm');
-    // Tests of the actual load machinery are in the model and env tests, and
-    // so are not repeated here.
+YUI(GlobalConfig).use(['juju-gui', 'juju-tests-utils'], function(Y) {
+  describe('Application basics', function() {
+    var app, container;
+
+    beforeEach(function() {
+      if (container) {
+        container.remove(true);
+      }
+      container = Y.one('#main')
+        .appendChild(Y.Node.create('<div/>'))
+          .set('id', 'test-container')
+          .addClass('container')
+          .append(Y.Node.create('<span/>')
+            .set('id', 'environment-name'))
+          .append(Y.Node.create('<span/>')
+            .set('id', 'provider-type'));
+      app = new Y.juju.App(
+          { container: container,
+            viewContainer: container});
+      injectData(app);
+    });
+
+    it('should produce a valid index', function() {
+      var container = app.get('container');
+      app.render();
+      container.getAttribute('id').should.equal('test-container');
+      container.getAttribute('class').should.include('container');
+    });
+
+    it('should be able to route objects to internal URLs', function() {
+      // take handles to database objects and ensure we can route to the view
+      // needed to show them
+      var wordpress = app.db.services.getById('wordpress'),
+          wp0 = app.db.units.get_units_for_service(wordpress)[0],
+          wp_charm = app.db.charms.add({id: wordpress.get('charm')});
+
+      // 'service/wordpress/' is the primary and so other URL are not returned
+      app.getModelURL(wordpress).should.equal('/service/wordpress/');
+      // however passing 'intent' can force selection of another
+      app.getModelURL(wordpress, 'config').should.equal(
+          '/service/wordpress/config');
+
+      // service units use argument rewriting (thus not /u/wp/0)
+      app.getModelURL(wp0).should.equal('/unit/wordpress-0/');
+
+      // charms also require a mapping but only a name, not a function
+      app.getModelURL(wp_charm).should.equal(
+          '/charms/charms/precise/wordpress-6/json');
+    });
+
+    it('should display the configured environment name', function() {
+      var environment_name = 'This is the environment name.  Deal with it.';
+      app = new Y.juju.App(
+          { container: container,
+            viewContainer: container,
+            environment_name: environment_name});
+      assert.equal(
+          container.one('#environment-name').get('text'),
+          environment_name);
+    });
+
+    it('should show a generic environment name if none configured', function() {
+      app = new Y.juju.App(
+          { container: container,
+            viewContainer: container});
+      assert.equal(
+          container.one('#environment-name').get('text'),
+          'Environment');
+    });
+
+    it('should show the provider type, when available', function() {
+      var providerType = 'excellent provider';
+      // Since no provider type has been set yet, none is displayed.
+      assert.equal(
+          container.one('#provider-type').get('text'),
+          '');
+      app.env.set('providerType', providerType);
+      // The provider type has been displayed.
+      assert.equal(
+          container.one('#provider-type').get('text'),
+          'on ' + providerType);
+    });
+
+  });
+});
+
+YUI(GlobalConfig).use(['juju-gui', 'juju-tests-utils'], function(Y) {
+  describe('Application Connection State', function() {
+    var container;
+
+    before(function() {
+      container = Y.Node.create('<div id="test" class="container"></div>');
+    });
+
+    it('should be able to handle env connection status changes', function() {
+      var juju = Y.namespace('juju'),
+          conn = new(Y.namespace('juju-tests.utils')).SocketStub(),
+          env = new juju.Environment({conn: conn}),
+          app = new Y.juju.App({env: env, container: container}),
+          reset_called = false,
+          noop = function() {return this;};
+
+
+      // mock the db
+      app.db = {
+        // mock out notifications
+        // so app can start normally
+        notifications: {
+          addTarget: noop,
+          after: noop,
+          filter: noop,
+          map: noop,
+          on: noop,
+          size: function() {return 0;}
+        },
+        reset: function() {
+          reset_called = true;
+                 }
+      };
+      env.connect();
+      conn.open();
+      reset_called.should.equal(true);
+
+      // trigger a second time and verify
+      reset_called = false;
+      conn.open();
+      reset_called.should.equal(true);
+    });
+
+  });
+});
+
+YUI(GlobalConfig).use(['juju-models', 'juju-gui', 'datasource-local',
+  'juju-tests-utils', 'json-stringify'], function(Y) {
+  describe('Application prefetching', function() {
+    var models, conn, env, app, container, charm_store, data, juju;
+
+    before(function() {
+      models = Y.namespace('juju.models');
+    });
+
+    beforeEach(function() {
+      conn = new (Y.namespace('juju-tests.utils')).SocketStub(),
+      env = new Y.juju.Environment({conn: conn});
+      env.connect();
+      conn.open();
+      container = Y.Node.create('<div id="test" class="container"></div>');
+      data = [];
+      app = new Y.juju.App(
+          { container: container,
+            viewContainer: container,
+            env: env,
+            charm_store: {} });
+
+      app.updateEndpoints = function() {};
+      env.get_endpoints = function() {};
+    });
+
+    afterEach(function() {
+      container.destroy();
+      app.destroy();
+    });
+
+    it('must prefetch charm and service for service pages', function() {
+      injectData(app);
+      var _ = expect(
+          app.db.charms.getById('cs:precise/wordpress-6')).to.not.exist;
+      app.show_service({params: {id: 'wordpress'}, query: {}});
+      // The app made a request of juju for the service info.
+      conn.messages[conn.messages.length - 2].op.should.equal('get_service');
+      // The app also requested juju (not the charm store--see discussion in
+      // app/models/charm.js) for the charm info.
+      conn.last_message().op.should.equal('get_charm');
+      // Tests of the actual load machinery are in the model and env tests, and
+      // so are not repeated here.
+    });
   });
 });

=== modified file 'test/test_app_hotkeys.js'
--- test/test_app_hotkeys.js	2012-11-20 15:39:46 +0000
+++ test/test_app_hotkeys.js	2012-11-23 17:25:57 +0000
@@ -1,12 +1,11 @@
 'use strict';
 
-describe('application hotkeys', function() {
-  var Y, app, container, env, conn, testUtils, windowNode;
+YUI(GlobalConfig).use(['juju-gui', 'juju-tests-utils', 'node-event-simulate'],
+    function(Y) {
+      describe('application hotkeys', function() {
+        var app, container, env, conn, testUtils, windowNode;
 
-  before(function() {
-    Y = YUI(GlobalConfig).use(
-        ['juju-gui', 'juju-tests-utils',
-          'node-event-simulate'], function(Y) {
+        before(function() {
           windowNode = Y.one(window);
           app = new Y.juju.App({
             env: env,
@@ -15,49 +14,50 @@
           });
           app.activateHotkeys();
         });
-  });
-
-  afterEach(function() {
-    container.remove(true);
-  });
-
-  beforeEach(function() {
-    container = Y.one('#main').appendChild(Y.Node.create('<div/>')).set('id',
-        'test-container').append(
-        Y.Node.create('<input />').set('id', 'charm-search-field'));
-    testUtils = Y.namespace('juju-tests.utils');
-    env = {
-      get: function() {
-      },
-      on: function() {
-      },
-      after: function() {
-      }
-    };
-  });
-
-  it('should listen for alt-S events', function() {
-    app.render();
-    windowNode.simulate('keydown', {
-      keyCode: 83, // "S" key
-      altKey: true
-    });
-    // Did charm-search-field get the focus?
-    assert.equal(Y.one('#charm-search-field'), Y.one(document.activeElement));
-  });
-
-  it('should listen for alt-E events', function() {
-    var altEtriggered = false;
-    app.on('navigateTo', function(param) {
-      if (param && param.url === '/') {
-        altEtriggered = true;
-      }
-    });
-    app.render();
-    windowNode.simulate('keydown', {
-      keyCode: 69, // "E" key
-      altKey: true
-    });
-    assert.isTrue(altEtriggered);
-  });
-});
+
+        afterEach(function() {
+          container.remove(true);
+        });
+
+        beforeEach(function() {
+          container = Y.one('#main').appendChild(Y.Node.create(
+              '<div/>')).set('id', 'test-container').append(
+              Y.Node.create('<input />').set('id', 'charm-search-field'));
+          testUtils = Y.namespace('juju-tests.utils');
+          env = {
+            get: function() {
+            },
+            on: function() {
+            },
+            after: function() {
+            }
+          };
+        });
+
+        it('should listen for alt-S events', function() {
+          app.render();
+          windowNode.simulate('keydown', {
+            keyCode: 83, // "S" key
+            altKey: true
+          });
+          // Did charm-search-field get the focus?
+          assert.equal(Y.one('#charm-search-field'),
+              Y.one(document.activeElement));
+        });
+
+        it('should listen for alt-E events', function() {
+          var altEtriggered = false;
+          app.on('navigateTo', function(param) {
+            if (param && param.url === '/') {
+              altEtriggered = true;
+            }
+          });
+          app.render();
+          windowNode.simulate('keydown', {
+            keyCode: 69, // "E" key
+            altKey: true
+          });
+          assert.isTrue(altEtriggered);
+        });
+      });
+    });

=== modified file 'test/test_model.js'
--- test/test_model.js	2012-10-23 20:02:17 +0000
+++ test/test_model.js	2012-11-23 17:25:57 +0000
@@ -1,15 +1,11 @@
 'use strict';
 
-(function() {
-
+YUI(GlobalConfig).use('juju-models', function(Y) {
   describe('charm normalization', function() {
-    var Y, models;
+    var models;
 
-    before(function(done) {
-      Y = YUI(GlobalConfig).use('juju-models', function(Y) {
-            models = Y.namespace('juju.models');
-            done();
-      });
+    before(function() {
+      models = Y.namespace('juju.models');
     });
 
     it('must create derived attributes from official charm id', function() {
@@ -31,15 +27,14 @@
     });
 
   });
+});
 
+YUI(GlobalConfig).use('juju-models', function(Y) {
   describe('juju models', function() {
-    var Y, models;
+    var models;
 
-    before(function(done) {
-      Y = YUI(GlobalConfig).use('juju-models', function(Y) {
-            models = Y.namespace('juju.models');
-            done();
-      });
+    before(function() {
+      models = Y.namespace('juju.models');
     });
 
     it('must be able to create charm', function() {
@@ -355,19 +350,17 @@
                 .should.eql(['relation-2', 'relation-3', 'relation-4']);
         });
   });
+});
 
+YUI(GlobalConfig).use(['juju-models', 'juju-gui', 'datasource-local',
+  'juju-tests-utils', 'json-stringify',
+  'juju-charm-store'], function(Y) {
   describe('juju charm load', function() {
-    var Y, models, conn, env, app, container, charm_store, data, juju;
+    var models, conn, env, app, container, charm_store, data, juju;
 
-    before(function(done) {
-      Y = YUI(GlobalConfig).use(
-          'juju-models', 'juju-gui', 'datasource-local', 'juju-tests-utils',
-          'json-stringify', 'juju-charm-store',
-          function(Y) {
-            models = Y.namespace('juju.models');
-            juju = Y.namespace('juju');
-            done();
-          });
+    before(function() {
+      models = Y.namespace('juju.models');
+      juju = Y.namespace('juju');
     });
 
     beforeEach(function() {
@@ -513,4 +506,4 @@
     });
 
   });
-})();
+});

=== modified file 'test/test_notifications.js'
--- test/test_notifications.js	2012-11-16 13:38:21 +0000
+++ test/test_notifications.js	2012-11-23 17:25:57 +0000
@@ -1,477 +1,462 @@
 'use strict';
 
-describe('notifications', function() {
-  var Y, juju, models, views;
-
-  var default_env = {
-    'result': [
-      ['service', 'add', {
-        'charm': 'cs:precise/wordpress-6',
-        'id': 'wordpress',
-        'exposed': false
-      }],
-      ['service', 'add', {
-        'charm': 'cs:precise/mediawiki-3',
-        'id': 'mediawiki',
-        'exposed': false
-      }],
-      ['service', 'add', {
-        'charm': 'cs:precise/mysql-6',
-        'id': 'mysql'
-      }],
-      ['relation', 'add', {
-        'interface': 'reversenginx',
-        'scope': 'global',
-        'endpoints':
-         [['wordpress', {'role': 'peer', 'name': 'loadbalancer'}]],
-        'id': 'relation-0000000000'
-      }],
-      ['relation', 'add', {
-        'interface': 'mysql',
-        'scope': 'global',
-        'endpoints':
-         [['mysql', {'role': 'server', 'name': 'db'}],
-          ['wordpress', {'role': 'client', 'name': 'db'}]],
-        'id': 'relation-0000000001'
-      }],
-      ['machine', 'add', {
-        'agent-state': 'running',
-        'instance-state': 'running',
-        'id': 0,
-        'instance-id': 'local',
-        'dns-name': 'localhost'
-      }],
-      ['unit', 'add', {
-        'machine': 0,
-        'agent-state': 'started',
-        'public-address': '192.168.122.113',
-        'id': 'wordpress/0'
-      }],
-      ['unit', 'add', {
-        'machine': 0,
-        'agent-state': 'error',
-        'public-address': '192.168.122.222',
-        'id': 'mysql/0'
-      }]
-    ],
-    'op': 'delta'
-  };
-
-
-  before(function(done) {
-    Y = YUI(GlobalConfig).use([
-      'juju-models',
-      'juju-views',
-      'juju-gui',
-      'juju-env',
-      'node-event-simulate',
-      'juju-tests-utils'],
-
+YUI(GlobalConfig).use(['juju-gui', 'node-event-simulate', 'juju-tests-utils'],
     function(Y) {
-      juju = Y.namespace('juju');
-      models = Y.namespace('juju.models');
-      views = Y.namespace('juju.views');
-      done();
-    });
-  });
-
-  it('must be able to make notification and lists of notifications',
-     function() {
-        var note1 = new models.Notification({
-         title: 'test1',
-         message: 'Hello'
-        }),
-            note2 = new models.Notification({
-         title: 'test2',
-         message: 'I said goodnight!'
-            }),
-            notifications = new models.NotificationList();
-
-        notifications.add([note1, note2]);
-        notifications.size().should.equal(2);
-
-        // timestamp should be generated once
-        var ts = note1.get('timestamp');
-        note1.get('timestamp').should.equal(ts);
-        // force an update so we can test ordering
-        // fast execution can result in same timestamp
-        note2.set('timestamp', ts + 1);
-        note2.get('timestamp').should.be.above(ts);
-
-        // defaults as expected
-        note1.get('level').should.equal('info');
-        note2.get('level').should.equal('info');
-        // the sort order on the list should be by
-        // timestamp
-        notifications.get('title').should.eql(['test2', 'test1']);
-     });
-
-  it('must be able to render its view with sample data',
-     function() {
-       var note1 = new models.Notification({
-         title: 'test1', message: 'Hello'}),
-           note2 = new models.Notification({
-         title: 'test2', message: 'I said goodnight!'}),
-           notifications = new models.NotificationList(),
-           container = Y.Node.create('<div id="test">'),
-           env = new juju.Environment(),
-           view = new views.NotificationsView({
-                   container: container,
-                   notifications: notifications,
-                   env: env});
-       view.render();
-       // Verify the expected elements appear in the view
-       container.one('#notify-list').should.not.equal(undefined);
-       container.destroy();
-     });
-
-  it('must be able to limit the size of notification events',
-     function() {
-       var note1 = new models.Notification({
-         title: 'test1',
-         message: 'Hello'
-       }),
-           note2 = new models.Notification({
-         title: 'test2',
-         message: 'I said goodnight!'
-       }),
-           note3 = new models.Notification({
-         title: 'test3',
-         message: 'Never remember'
-       }),
-           notifications = new models.NotificationList({
-         max_size: 2
-       });
-
-       notifications.add([note1, note2]);
-       notifications.size().should.equal(2);
-
-       // Adding a new notification should pop the oldest from the list (we
-       // exceed max_size)
-       notifications.add(note3);
-       notifications.size().should.equal(2);
-       notifications.get('title').should.eql(['test3', 'test2']);
-     });
-
-  it('must be able to get notifications for a given model',
-     function() {
-       var m = new models.Service({id: 'mediawiki'}),
-           note1 = new models.Notification({
-         title: 'test1',
-         message: 'Hello',
-         modelId: m
-       }),
-           note2 = new models.Notification({
-         title: 'test2',
-         message: 'I said goodnight!'
-       }),
-           notifications = new models.NotificationList();
-
-       notifications.add([note1, note2]);
-       notifications.size().should.equal(2);
-       notifications.getNotificationsForModel(m).should.eql(
-       [note1]);
-
-     });
-
-  it('must be able to include and show object links', function() {
-    var container = Y.Node.create('<div id="test">'),
-        conn = new(Y.namespace('juju-tests.utils')).SocketStub(),
-        env = new juju.Environment({conn: conn}),
-        app = new Y.juju.App({env: env, container: container}),
-        db = app.db,
-        mw = db.services.create({id: 'mediawiki',
-                                    name: 'mediawiki'}),
-        notifications = db.notifications,
-        view = new views.NotificationsOverview({
-                      container: container,
-                      notifications: notifications,
-                      app: app,
-                      env: env}).render();
-    // we use overview here for testing as it defaults
-    // to showing all notices
-
-    // we can use app's routing table to derive a link
-    notifications.create({title: 'Service Down',
-      message: 'Your service has an error',
-      link: app.getModelURL(mw)
-    });
-    view.render();
-    var link = container.one('.notice').one('a');
-    link.getAttribute('href').should.equal(
-        '/service/mediawiki/');
-    link.getHTML().should.contain('View Details');
-
-
-    // create a new notice passing the link_title
-    notifications.create({title: 'Service Down',
-      message: 'Your service has an error',
-      link: app.getModelURL(mw),
-      link_title: 'Resolve this'
-    });
-    view.render();
-    link = container.one('.notice').one('a');
-    link.getAttribute('href').should.equal(
-        '/service/mediawiki/');
-    link.getHTML().should.contain('Resolve this');
-  });
-
-  it('must be able to evict irrelevant notices', function() {
-    var container = Y.Node.create(
-        '<div id="test" class="container"></div>'),
-        conn = new(Y.namespace('juju-tests.utils')).SocketStub(),
-        env = new juju.Environment({conn: conn}),
-        app = new Y.juju.App({
-          env: env,
-          container: container,
-          viewContainer: container
-        });
-    var environment_delta = default_env;
-
-    var notifications = app.db.notifications,
-        view = new views.NotificationsView({
-          container: container,
-          notifications: notifications,
-          env: app.env}).render();
-
-
-    app.env.dispatch_result(environment_delta);
-
-
-    notifications.size().should.equal(7);
-    // we have one unit in error
-    view.getShowable().length.should.equal(1);
-
-    // now fire another delta event marking that node as
-    // started
-    app.env.dispatch_result({result: [['unit', 'change', {
-      'machine': 0,
-      'agent-state': 'started',
-      'public-address': '192.168.122.222',
-      'id': 'mysql/0'
-    }]], op: 'delta'});
-    notifications.size().should.equal(8);
-    // This should have evicted the prior notice from seen
-    view.getShowable().length.should.equal(0);
-  });
-
-  it('must properly construct title and message based on level from ' +
-     'event data',
-     function() {
-       var container = Y.Node.create(
-       '<div id="test" class="container"></div>'),
-       app = new Y.juju.App({
-         container: container,
-         viewContainer: container
-       });
-       var environment_delta = {
-         'result': [
-           ['service', 'add', {
-             'charm': 'cs:precise/wordpress-6',
-             'id': 'wordpress'
-           }],
-           ['service', 'add', {
-             'charm': 'cs:precise/mediawiki-3',
-             'id': 'mediawiki'
-           }],
-           ['service', 'add', {
-             'charm': 'cs:precise/mysql-6',
-             'id': 'mysql'
-           }],
-           ['unit', 'add', {
-             'agent-state': 'install-error',
-             'id': 'wordpress/0'
-           }],
-           ['unit', 'add', {
-             'agent-state': 'error',
-             'public-address': '192.168.122.222',
-             'id': 'mysql/0'
-           }],
-           ['unit', 'add', {
-             'public-address': '192.168.122.222',
-             'id': 'mysql/2'
-           }]
-         ],
-         'op': 'delta'
-       };
-
-       var notifications = app.db.notifications,
-       view = new views.NotificationsView({
-         container: container,
-         notifications: notifications,
-         app: app,
-         env: app.env}).render();
-
-       app.env.dispatch_result(environment_delta);
-
-       notifications.size().should.equal(6);
-       // we have one unit in error
-       var showable = view.getShowable();
-       showable.length.should.equal(2);
-       // The first showable notification should indicate an error.
-       showable[0].level.should.equal('error');
-       showable[0].title.should.equal('Error with mysql/0');
-       showable[0].message.should.equal('Agent-state = error.');
-       // The second showable notification should also indicate an error.
-       showable[1].level.should.equal('error');
-       showable[1].title.should.equal('Error with wordpress/0');
-       showable[1].message.should.equal('Agent-state = install-error.');
-       // The first non-error notice should have an 'info' level and less
-       // severe messaging.
-       var notice = notifications.item(0);
-       notice.get('level').should.equal('info');
-       notice.get('title').should.equal('Problem with mysql/2');
-       notice.get('message').should.equal('');
-     });
-
-
-  it('should open on click and close on clickoutside', function(done) {
-    var container = Y.Node.create(
-        '<div id="test-container" style="display: none" class="container"/>'),
-        notifications = new models.NotificationList(),
-        env = new juju.Environment(),
-        view = new views.NotificationsView({
-          container: container,
-          notifications: notifications,
-          env: env}).render(),
-        indicator;
-
-    Y.one('body').append(container);
-    notifications.add({title: 'testing', 'level': 'error'});
-    indicator = container.one('#notify-indicator');
-
-    indicator.simulate('click');
-    indicator.ancestor().hasClass('open').should.equal(true);
-
-    Y.one('body').simulate('click');
-    indicator.ancestor().hasClass('open').should.equal(false);
-
-    container.remove();
-    done();
-  });
-
-});
-
-
-describe('changing notifications to words', function() {
-  var Y, juju;
-
-  before(function(done) {
-    Y = YUI(GlobalConfig).use(
-        ['juju-notification-controller'],
-        function(Y) {
-          juju = Y.namespace('juju');
-          done();
-        });
-  });
-
-  it('should correctly translate notification operations into English',
-     function() {
-       assert.equal(juju._changeNotificationOpToWords('add'), 'created');
-       assert.equal(juju._changeNotificationOpToWords('remove'), 'removed');
-       assert.equal(juju._changeNotificationOpToWords('not-an-op'), 'changed');
-     });
-});
-
-describe('relation notifications', function() {
-  var Y, juju;
-
-  before(function(done) {
-    Y = YUI(GlobalConfig).use(
-        ['juju-notification-controller'],
-        function(Y) {
-          juju = Y.namespace('juju');
-          done();
-        });
-  });
-
-  it('should produce reasonable titles', function() {
-    assert.equal(
-        juju._relationNotifications.title(undefined, 'add'),
-        'Relation created');
-    assert.equal(
-        juju._relationNotifications.title(undefined, 'remove'),
-        'Relation removed');
-  });
-
-  it('should generate messages about two-party relations', function() {
-    var changeData =
-        { endpoints:
-              [['endpoint0', {name: 'relation0'}],
-                ['endpoint1', {name: 'relation1'}]]};
-    assert.equal(
-        juju._relationNotifications.message(undefined, 'add', changeData),
-        'Relation between endpoint0 (relation type "relation0") and ' +
-        'endpoint1 (relation type "relation1") was created');
-  });
-
-  it('should generate messages about one-party relations', function() {
-    var changeData =
-        { endpoints:
-              [['endpoint1', {name: 'relation1'}]]};
-    assert.equal(
-        juju._relationNotifications.message(undefined, 'add', changeData),
-        'Relation with endpoint1 (relation type "relation1") was created');
-  });
-});
-
-describe('notification visual feedback', function() {
-  var env, models, notifications, notificationsView, notifierBox, views, Y;
-
-  before(function(done) {
-    Y = YUI(GlobalConfig).use('juju-env', 'juju-models', 'juju-views',
-        function(Y) {
+      describe('notifications', function() {
+        var juju, models, views;
+
+        var default_env = {
+          'result': [
+            ['service', 'add', {
+              'charm': 'cs:precise/wordpress-6',
+              'id': 'wordpress',
+              'exposed': false
+            }],
+            ['service', 'add', {
+              'charm': 'cs:precise/mediawiki-3',
+              'id': 'mediawiki',
+              'exposed': false
+            }],
+            ['service', 'add', {
+              'charm': 'cs:precise/mysql-6',
+              'id': 'mysql'
+            }],
+            ['relation', 'add', {
+              'interface': 'reversenginx',
+              'scope': 'global',
+              'endpoints':
+               [['wordpress', {'role': 'peer', 'name': 'loadbalancer'}]],
+              'id': 'relation-0000000000'
+            }],
+            ['relation', 'add', {
+              'interface': 'mysql',
+              'scope': 'global',
+              'endpoints':
+               [['mysql', {'role': 'server', 'name': 'db'}],
+                ['wordpress', {'role': 'client', 'name': 'db'}]],
+              'id': 'relation-0000000001'
+            }],
+            ['machine', 'add', {
+              'agent-state': 'running',
+              'instance-state': 'running',
+              'id': 0,
+              'instance-id': 'local',
+              'dns-name': 'localhost'
+            }],
+            ['unit', 'add', {
+              'machine': 0,
+              'agent-state': 'started',
+              'public-address': '192.168.122.113',
+              'id': 'wordpress/0'
+            }],
+            ['unit', 'add', {
+              'machine': 0,
+              'agent-state': 'error',
+              'public-address': '192.168.122.222',
+              'id': 'mysql/0'
+            }]
+          ],
+          'op': 'delta'
+        };
+
+
+        before(function() {
+          juju = Y.namespace('juju');
+          models = Y.namespace('juju.models');
+          views = Y.namespace('juju.views');
+        });
+
+        it('must be able to make notification and lists of notifications',
+           function() {
+             var note1 = new models.Notification({
+               title: 'test1',
+               message: 'Hello'
+             }),
+             note2 = new models.Notification({
+               title: 'test2',
+               message: 'I said goodnight!'
+             }),
+             notifications = new models.NotificationList();
+
+             notifications.add([note1, note2]);
+             notifications.size().should.equal(2);
+
+             // timestamp should be generated once
+             var ts = note1.get('timestamp');
+             note1.get('timestamp').should.equal(ts);
+             // force an update so we can test ordering
+             // fast execution can result in same timestamp
+             note2.set('timestamp', ts + 1);
+             note2.get('timestamp').should.be.above(ts);
+
+             // defaults as expected
+             note1.get('level').should.equal('info');
+             note2.get('level').should.equal('info');
+             // the sort order on the list should be by
+             // timestamp
+             notifications.get('title').should.eql(['test2', 'test1']);
+           });
+
+        it('must be able to render its view with sample data',
+           function() {
+             var note1 = new models.Notification({
+               title: 'test1', message: 'Hello'}),
+             note2 = new models.Notification({
+               title: 'test2', message: 'I said goodnight!'}),
+             notifications = new models.NotificationList(),
+             container = Y.Node.create('<div id="test">'),
+             env = new juju.Environment(),
+             view = new views.NotificationsView({
+                     container: container,
+                     notifications: notifications,
+                     env: env});
+             view.render();
+             // Verify the expected elements appear in the view
+             container.one('#notify-list').should.not.equal(undefined);
+             container.destroy();
+           });
+
+        it('must be able to limit the size of notification events',
+           function() {
+             var note1 = new models.Notification({
+               title: 'test1',
+               message: 'Hello'
+             }),
+             note2 = new models.Notification({
+               title: 'test2',
+               message: 'I said goodnight!'
+             }),
+             note3 = new models.Notification({
+               title: 'test3',
+               message: 'Never remember'
+             }),
+             notifications = new models.NotificationList({
+               max_size: 2
+             });
+
+             notifications.add([note1, note2]);
+             notifications.size().should.equal(2);
+
+             // Adding a new notification should pop the oldest from the list
+             // (we exceed max_size)
+             notifications.add(note3);
+             notifications.size().should.equal(2);
+             notifications.get('title').should.eql(['test3', 'test2']);
+           });
+
+        it('must be able to get notifications for a given model',
+           function() {
+             var m = new models.Service({id: 'mediawiki'}),
+             note1 = new models.Notification({
+               title: 'test1',
+               message: 'Hello',
+               modelId: m
+             }),
+             note2 = new models.Notification({
+               title: 'test2',
+               message: 'I said goodnight!'
+             }),
+             notifications = new models.NotificationList();
+
+             notifications.add([note1, note2]);
+             notifications.size().should.equal(2);
+             notifications.getNotificationsForModel(m).should.eql(
+             [note1]);
+
+           });
+
+        it('must be able to include and show object links', function() {
+          var container = Y.Node.create('<div id="test">'),
+              conn = new(Y.namespace('juju-tests.utils')).SocketStub(),
+              env = new juju.Environment({conn: conn}),
+              app = new Y.juju.App({env: env, container: container}),
+              db = app.db,
+              mw = db.services.create({id: 'mediawiki',
+                                      name: 'mediawiki'}),
+              notifications = db.notifications,
+              view = new views.NotificationsOverview({
+                        container: container,
+                        notifications: notifications,
+                        app: app,
+                        env: env}).render();
+          // we use overview here for testing as it defaults
+          // to showing all notices
+
+          // we can use app's routing table to derive a link
+          notifications.create({title: 'Service Down',
+            message: 'Your service has an error',
+            link: app.getModelURL(mw)
+          });
+          view.render();
+          var link = container.one('.notice').one('a');
+          link.getAttribute('href').should.equal(
+              '/service/mediawiki/');
+          link.getHTML().should.contain('View Details');
+
+
+          // create a new notice passing the link_title
+          notifications.create({title: 'Service Down',
+            message: 'Your service has an error',
+            link: app.getModelURL(mw),
+            link_title: 'Resolve this'
+          });
+          view.render();
+          link = container.one('.notice').one('a');
+          link.getAttribute('href').should.equal(
+              '/service/mediawiki/');
+          link.getHTML().should.contain('Resolve this');
+        });
+
+        it('must be able to evict irrelevant notices', function() {
+          var container = Y.Node.create(
+              '<div id="test" class="container"></div>'),
+              conn = new(Y.namespace('juju-tests.utils')).SocketStub(),
+              env = new juju.Environment({conn: conn}),
+              app = new Y.juju.App({
+                env: env,
+                container: container,
+                viewContainer: container
+              });
+          var environment_delta = default_env;
+
+          var notifications = app.db.notifications,
+              view = new views.NotificationsView({
+                container: container,
+                notifications: notifications,
+                env: app.env}).render();
+
+
+          app.env.dispatch_result(environment_delta);
+
+
+          notifications.size().should.equal(7);
+          // we have one unit in error
+          view.getShowable().length.should.equal(1);
+
+          // now fire another delta event marking that node as
+          // started
+          app.env.dispatch_result({result: [['unit', 'change', {
+            'machine': 0,
+            'agent-state': 'started',
+            'public-address': '192.168.122.222',
+            'id': 'mysql/0'
+          }]], op: 'delta'});
+          notifications.size().should.equal(8);
+          // This should have evicted the prior notice from seen
+          view.getShowable().length.should.equal(0);
+        });
+
+        it('must properly construct title and message based on level from ' +
+           'event data',
+           function() {
+             var container = Y.Node.create(
+             '<div id="test" class="container"></div>'),
+             app = new Y.juju.App({
+               container: container,
+               viewContainer: container
+             });
+             var environment_delta = {
+               'result': [
+                 ['service', 'add', {
+                   'charm': 'cs:precise/wordpress-6',
+                   'id': 'wordpress'
+                 }],
+                 ['service', 'add', {
+                   'charm': 'cs:precise/mediawiki-3',
+                   'id': 'mediawiki'
+                 }],
+                 ['service', 'add', {
+                   'charm': 'cs:precise/mysql-6',
+                   'id': 'mysql'
+                 }],
+                 ['unit', 'add', {
+                   'agent-state': 'install-error',
+                   'id': 'wordpress/0'
+                 }],
+                 ['unit', 'add', {
+                   'agent-state': 'error',
+                   'public-address': '192.168.122.222',
+                   'id': 'mysql/0'
+                 }],
+                 ['unit', 'add', {
+                   'public-address': '192.168.122.222',
+                   'id': 'mysql/2'
+                 }]
+               ],
+               'op': 'delta'
+             };
+
+             var notifications = app.db.notifications,
+             view = new views.NotificationsView({
+               container: container,
+               notifications: notifications,
+               app: app,
+               env: app.env}).render();
+
+             app.env.dispatch_result(environment_delta);
+
+             notifications.size().should.equal(6);
+             // we have one unit in error
+             var showable = view.getShowable();
+             showable.length.should.equal(2);
+             // The first showable notification should indicate an error.
+             showable[0].level.should.equal('error');
+             showable[0].title.should.equal('Error with mysql/0');
+             showable[0].message.should.equal('Agent-state = error.');
+             // The second showable notification should also indicate an error.
+             showable[1].level.should.equal('error');
+             showable[1].title.should.equal('Error with wordpress/0');
+             showable[1].message.should.equal('Agent-state = install-error.');
+             // The first non-error notice should have an 'info' level and less
+             // severe messaging.
+             var notice = notifications.item(0);
+             notice.get('level').should.equal('info');
+             notice.get('title').should.equal('Problem with mysql/2');
+             notice.get('message').should.equal('');
+           });
+
+
+        it('should open on click and close on clickoutside', function(done) {
+          var container = Y.Node.create('<div id="test-container" ' +
+              'style="display: none" class="container"/>'),
+              notifications = new models.NotificationList(),
+              env = new juju.Environment(),
+              view = new views.NotificationsView({
+                container: container,
+                notifications: notifications,
+                env: env}).render(),
+              indicator;
+
+          Y.one('body').append(container);
+          notifications.add({title: 'testing', 'level': 'error'});
+          indicator = container.one('#notify-indicator');
+
+          indicator.simulate('click');
+          indicator.ancestor().hasClass('open').should.equal(true);
+
+          Y.one('body').simulate('click');
+          indicator.ancestor().hasClass('open').should.equal(false);
+
+          container.remove();
+          done();
+        });
+      });
+
+      describe('changing notifications to words', function() {
+        var juju;
+
+        before(function() {
+          juju = Y.namespace('juju');
+        });
+
+        it('should correctly translate notification operations into English',
+           function() {
+             assert.equal(juju._changeNotificationOpToWords('add'), 'created');
+             assert.equal(juju._changeNotificationOpToWords('remove'),
+                 'removed');
+             assert.equal(juju._changeNotificationOpToWords('not-an-op'),
+                 'changed');
+           });
+      });
+
+      describe('relation notifications', function() {
+        var juju;
+
+        before(function() {
+          juju = Y.namespace('juju');
+        });
+
+        it('should produce reasonable titles', function() {
+          assert.equal(
+              juju._relationNotifications.title(undefined, 'add'),
+              'Relation created');
+          assert.equal(
+              juju._relationNotifications.title(undefined, 'remove'),
+              'Relation removed');
+        });
+
+        it('should generate messages about two-party relations', function() {
+          var changeData =
+              { endpoints:
+                    [['endpoint0', {name: 'relation0'}],
+                     ['endpoint1', {name: 'relation1'}]]};
+          assert.equal(
+              juju._relationNotifications.message(undefined, 'add',
+                  changeData), 'Relation between endpoint0 (relation type ' +
+                  '"relation0") and endpoint1 (relation type "relation1") ' +
+                  'was created');
+        });
+
+        it('should generate messages about one-party relations', function() {
+          var changeData =
+              { endpoints:
+                    [['endpoint1', {name: 'relation1'}]]};
+          assert.equal(
+              juju._relationNotifications.message(undefined, 'add',
+                  changeData), 'Relation with endpoint1 (relation type ' +
+                  '"relation1") was created');
+        });
+      });
+
+      describe('notification visual feedback', function() {
+        var env, models, notifications, notificationsView, notifierBox, views;
+
+        before(function() {
           var juju = Y.namespace('juju');
           env = new juju.Environment();
           models = Y.namespace('juju.models');
           views = Y.namespace('juju.views');
-          done();
-        });
-  });
-
-  // Instantiate the notifications model list and view.
-  // Also create the notifier box and attach it as first element of the body.
-  beforeEach(function() {
-    notifications = new models.NotificationList();
-    notificationsView = new views.NotificationsView({
-      env: env,
-      notifications: notifications
+        });
+
+        // Instantiate the notifications model list and view.
+        // Also create the notifier box and attach it as first element of the
+        // body.
+        beforeEach(function() {
+          notifications = new models.NotificationList();
+          notificationsView = new views.NotificationsView({
+            env: env,
+            notifications: notifications
+          });
+          notifierBox = Y.Node.create('<div id="notifier-box"></div>');
+          notifierBox.setStyle('display', 'none');
+          Y.one('body').prepend(notifierBox);
+        });
+
+        // Destroy the notifier box created in beforeEach.
+        afterEach(function() {
+          notifierBox.remove();
+          notifierBox.destroy(true);
+        });
+
+        // Assert the notifier box contains the expectedNumber of notifiers.
+        var assertNumNotifiers = function(expectedNumber) {
+          assert.equal(expectedNumber, notifierBox.get('children').size());
+        };
+
+        it('should appear when a new error is notified', function() {
+          notifications.add({title: 'mytitle', level: 'error'});
+          assertNumNotifiers(1);
+        });
+
+        it('should only appear when the DOM contains the notifier box',
+            function() {
+             notifierBox.remove();
+             notifications.add({title: 'mytitle', level: 'error'});
+             assertNumNotifiers(0);
+           });
+
+        it('should not appear when the notification is not an error',
+            function() {
+             notifications.add({title: 'mytitle', level: 'info'});
+             assertNumNotifiers(0);
+           });
+
+        it('should not appear when the notification comes form delta',
+            function() {
+             notifications.add({title: 'mytitle', level: 'error', isDelta:
+               true});
+             assertNumNotifiers(0);
+           });
+
+      });
     });
-    notifierBox = Y.Node.create('<div id="notifier-box"></div>');
-    notifierBox.setStyle('display', 'none');
-    Y.one('body').prepend(notifierBox);
-  });
-
-  // Destroy the notifier box created in beforeEach.
-  afterEach(function() {
-    notifierBox.remove();
-    notifierBox.destroy(true);
-  });
-
-  // Assert the notifier box contains the expectedNumber of notifiers.
-  var assertNumNotifiers = function(expectedNumber) {
-    assert.equal(expectedNumber, notifierBox.get('children').size());
-  };
-
-  it('should appear when a new error is notified', function() {
-    notifications.add({title: 'mytitle', level: 'error'});
-    assertNumNotifiers(1);
-  });
-
-  it('should only appear when the DOM contains the notifier box', function() {
-    notifierBox.remove();
-    notifications.add({title: 'mytitle', level: 'error'});
-    assertNumNotifiers(0);
-  });
-
-  it('should not appear when the notification is not an error', function() {
-    notifications.add({title: 'mytitle', level: 'info'});
-    assertNumNotifiers(0);
-  });
-
-  it('should not appear when the notification comes form delta', function() {
-    notifications.add({title: 'mytitle', level: 'error', isDelta: true});
-    assertNumNotifiers(0);
-  });
-
-});

=== modified file 'test/test_notifier_widget.js'
--- test/test_notifier_widget.js	2012-11-16 13:37:20 +0000
+++ test/test_notifier_widget.js	2012-11-23 17:25:57 +0000
@@ -1,103 +1,101 @@
 'use strict';
 
-describe('notifier widget', function() {
-  var Notifier, notifierBox, Y;
-
-  before(function(done) {
-    Y = YUI(GlobalConfig).use('notifier', 'node-event-simulate',
-        function(Y) {
-          Notifier = Y.namespace('juju.widgets').Notifier;
-          done();
-        });
-  });
-
-  // Create the notifier box and attach it as first element of the body.
-  beforeEach(function() {
-    notifierBox = Y.Node.create('<div id="notifier-box"></div>');
-    notifierBox.setStyle('display', 'none');
-    Y.one('body').prepend(notifierBox);
-  });
-
-  // Destroy the notifier box created in beforeEach.
-  afterEach(function() {
-    notifierBox.remove();
-    notifierBox.destroy(true);
-  });
-
-  // Factory rendering and returning a notifier instance.
-  var makeNotifier = function(title, message, timeout) {
-    var notifier = new Notifier({
-      title: title || 'mytitle',
-      message: message || 'mymessage',
-      timeout: timeout || 10000
-    });
-    notifier.render(notifierBox);
-    return notifier;
-  };
-
-  // Assert the notifier box contains the expectedNumber of notifiers.
-  var assertNumNotifiers = function(expectedNumber) {
-    assert.equal(expectedNumber, notifierBox.get('children').size());
-  };
-
-  it('should be able to display a notification', function() {
-    makeNotifier();
-    assertNumNotifiers(1);
-  });
-
-  it('should display the given title and message', function() {
-    makeNotifier('mytitle', 'mymessage');
-    var notifierNode = notifierBox.one('*');
-    assert.equal('mytitle', notifierNode.one('h3').getContent());
-    assert.equal('mymessage', notifierNode.one('div').getContent());
-  });
-
-  it('should be able to display multiple notifications', function() {
-    var number = 10;
-    for (var i = 0; i < number; i += 1) {
+YUI(GlobalConfig).use(['notifier', 'node-event-simulate'], function(Y) {
+  describe('notifier widget', function() {
+    var Notifier, notifierBox;
+
+    before(function() {
+      Notifier = Y.namespace('juju.widgets').Notifier;
+    });
+
+    // Create the notifier box and attach it as first element of the body.
+    beforeEach(function() {
+      notifierBox = Y.Node.create('<div id="notifier-box"></div>');
+      notifierBox.setStyle('display', 'none');
+      Y.one('body').prepend(notifierBox);
+    });
+
+    // Destroy the notifier box created in beforeEach.
+    afterEach(function() {
+      notifierBox.remove();
+      notifierBox.destroy(true);
+    });
+
+    // Factory rendering and returning a notifier instance.
+    var makeNotifier = function(title, message, timeout) {
+      var notifier = new Notifier({
+        title: title || 'mytitle',
+        message: message || 'mymessage',
+        timeout: timeout || 10000
+      });
+      notifier.render(notifierBox);
+      return notifier;
+    };
+
+    // Assert the notifier box contains the expectedNumber of notifiers.
+    var assertNumNotifiers = function(expectedNumber) {
+      assert.equal(expectedNumber, notifierBox.get('children').size());
+    };
+
+    it('should be able to display a notification', function() {
       makeNotifier();
-    }
-    assertNumNotifiers(number);
-  });
-
-  it('should display new notifications on top', function() {
-    makeNotifier('mytitle1', 'mymessage1');
-    makeNotifier('mytitle2', 'mymessage2');
-    var notifierNode = notifierBox.one('*');
-    assert.equal('mytitle2', notifierNode.one('h3').getContent());
-    assert.equal('mymessage2', notifierNode.one('div').getContent());
-  });
-
-  it('should destroy notifications after N milliseconds', function(done) {
-    makeNotifier('mytitle', 'mymessage', 1);
-    // A timeout of 250 milliseconds is used so that we ensure the destroying
-    // animation can be completed.
-    setTimeout(function() {
-      assertNumNotifiers(0);
-      done();
-    }, 250);
-  });
-
-  it('should destroy notifications on click', function(done) {
-    makeNotifier();
-    notifierBox.one('*').simulate('click');
-    // A timeout of 250 milliseconds is used so that we ensure the destroying
-    // animation can be completed.
-    setTimeout(function() {
-      assertNumNotifiers(0);
-      done();
-    }, 250);
-  });
-
-  it('should prevent notification removal on mouse enter', function(done) {
-    makeNotifier('mytitle', 'mymessage', 1);
-    notifierBox.one('*').simulate('mouseover');
-    // A timeout of 250 milliseconds is used so that we ensure the node is not
-    // preserved by the destroying animation.
-    setTimeout(function() {
       assertNumNotifiers(1);
-      done();
-    }, 250);
+    });
+
+    it('should display the given title and message', function() {
+      makeNotifier('mytitle', 'mymessage');
+      var notifierNode = notifierBox.one('*');
+      assert.equal('mytitle', notifierNode.one('h3').getContent());
+      assert.equal('mymessage', notifierNode.one('div').getContent());
+    });
+
+    it('should be able to display multiple notifications', function() {
+      var number = 10;
+      for (var i = 0; i < number; i += 1) {
+        makeNotifier();
+      }
+      assertNumNotifiers(number);
+    });
+
+    it('should display new notifications on top', function() {
+      makeNotifier('mytitle1', 'mymessage1');
+      makeNotifier('mytitle2', 'mymessage2');
+      var notifierNode = notifierBox.one('*');
+      assert.equal('mytitle2', notifierNode.one('h3').getContent());
+      assert.equal('mymessage2', notifierNode.one('div').getContent());
+    });
+
+    it('should destroy notifications after N milliseconds', function(done) {
+      makeNotifier('mytitle', 'mymessage', 1);
+      // A timeout of 250 milliseconds is used so that we ensure the destroying
+      // animation can be completed.
+      setTimeout(function() {
+        assertNumNotifiers(0);
+        done();
+      }, 250);
+    });
+
+    it('should destroy notifications on click', function(done) {
+      makeNotifier();
+      notifierBox.one('*').simulate('click');
+      // A timeout of 250 milliseconds is used so that we ensure the destroying
+      // animation can be completed.
+      setTimeout(function() {
+        assertNumNotifiers(0);
+        done();
+      }, 250);
+    });
+
+    it('should prevent notification removal on mouse enter', function(done) {
+      makeNotifier('mytitle', 'mymessage', 1);
+      notifierBox.one('*').simulate('mouseover');
+      // A timeout of 250 milliseconds is used so that we ensure the node is not
+      // preserved by the destroying animation.
+      setTimeout(function() {
+        assertNumNotifiers(1);
+        done();
+      }, 250);
+    });
+
   });
-
 });


Follow ups