yellow team mailing list archive
-
yellow team
-
Mailing list archive
-
Message #01732
[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