yellow team mailing list archive
-
yellow team
-
Mailing list archive
-
Message #02128
[Merge] lp:~hazmat/juju-gui/reliable-test into lp:juju-gui
Kapil Thangavelu has proposed merging lp:~hazmat/juju-gui/reliable-test into lp:juju-gui.
Requested reviews:
Juju GUI Hackers (juju-gui)
For more details, see:
https://code.launchpad.net/~hazmat/juju-gui/reliable-test/+merge/141197
Make tests more reliable.
- Disable async loading for yui to ensure app code is loaded before tests.
- Yank yui loader closures around tests, this is an anti-pattern.
- Any test file can be run in isolation now.
- Re-order test loading into alphabetical order to detect/correct collisions.
- Enable using firefox for tests via test loader fix.
- WIP enable using phantomjs for running tests on cli.
- Make topology-mega.js more foregiving on its (there's a event subscription leak here.)
- Fix event subscription leak in charm-panel code.
https://codereview.appspot.com/7003054/
--
https://code.launchpad.net/~hazmat/juju-gui/reliable-test/+merge/141197
Your team Juju GUI Hackers is requested to review the proposed merge of lp:~hazmat/juju-gui/reliable-test into lp:juju-gui.
=== modified file 'app/app.js'
--- app/app.js 2012-12-19 13:45:10 +0000
+++ app/app.js 2012-12-24 03:49:21 +0000
@@ -745,18 +745,23 @@
}, '0.5.2', {
requires: [
+ 'juju-charm-models',
+ 'juju-charm-panel',
+ 'juju-charm-store',
'juju-models',
- 'juju-charm-models',
+ 'juju-notifications',
+
+ // This alias doesn't seem to work, including refs by hand.
+ 'juju-controllers',
+ 'juju-notification-controller',
+ 'juju-env',
+
'juju-views',
- 'juju-controllers',
- 'juju-view-charm-search',
'io',
'json-parse',
'app-base',
'app-transitions',
'base',
'node',
- 'model',
- 'juju-charm-panel',
- 'juju-charm-store']
+ 'model']
});
=== modified file 'app/modules-debug.js'
--- app/modules-debug.js 2012-12-21 12:52:30 +0000
+++ app/modules-debug.js 2012-12-24 03:49:21 +0000
@@ -12,9 +12,10 @@
filter: 'debug',
// Set "true" for verbose logging of YUI
debug: false,
+
base: '/juju-ui/assets/javascripts/yui/',
// Use Rollups
- combine: false,
+ combine: true,
groups: {
gallery: {
@@ -80,6 +81,7 @@
'juju-topology': {
fullpath: '/juju-ui/views/topology/topology.js'
},
+
'juju-view-utils': {
fullpath: '/juju-ui/views/utils.js'
},
@@ -158,7 +160,9 @@
},
'juju-controllers': {
- use: ['juju-env', 'juju-charm-store',
+ use: [
+ 'juju-env',
+ 'juju-charm-store',
'juju-notification-controller']
},
=== modified file 'app/templates/overview.handlebars'
--- app/templates/overview.handlebars 2012-12-17 15:39:40 +0000
+++ app/templates/overview.handlebars 2012-12-24 03:49:21 +0000
@@ -1,5 +1,5 @@
<div class="topology">
- <div class="topology-canvas crosshatch-background">
+ <div class="crosshatch-background topology-canvas">
<div class="environment-menu" id="service-menu">
<div class="triangle"> </div>
<ul>
=== modified file 'app/views/charm-panel.js'
--- app/views/charm-panel.js 2012-12-14 20:25:16 +0000
+++ app/views/charm-panel.js 2012-12-24 03:49:21 +0000
@@ -1056,11 +1056,11 @@
setPanel({name: 'charms'});
// Update position if we resize the window.
- Y.on('windowresize', function(e) {
+ subscriptions.push(Y.on('windowresize', function(e) {
if (isPanelVisible) {
updatePanelPosition();
}
- });
+ }));
/**
* Hide the charm panel.
@@ -1229,6 +1229,7 @@
requires: [
'view',
'juju-view-utils',
+ 'juju-templates',
'node',
'handlebars',
'event-hover',
=== modified file 'app/views/environment.js'
--- app/views/environment.js 2012-12-19 13:45:10 +0000
+++ app/views/environment.js 2012-12-24 03:49:21 +0000
@@ -34,10 +34,10 @@
//If we need the initial HTML template
// take care of that.
- if (!this.svg) {
+ if (!this.rendered) {
EnvironmentView.superclass.render.apply(this, arguments);
container.setHTML(Templates.overview());
- this.svg = container.one('.topology');
+ this.rendered = true;
}
if (!topo) {
@@ -78,13 +78,10 @@
requires: ['juju-templates',
'juju-view-utils',
'juju-models',
- 'd3',
- 'd3-components',
+ 'juju-topology',
+ 'svg-layouts',
'base-build',
'handlebars-base',
'node',
- 'svg-layouts',
- 'event-resize',
- 'slider',
'view']
});
=== modified file 'app/views/topology/mega.js'
--- app/views/topology/mega.js 2012-12-20 13:34:43 +0000
+++ app/views/topology/mega.js 2012-12-24 03:49:21 +0000
@@ -1126,6 +1126,12 @@
svg = container.one('svg'),
canvas = container.one('.topology-canvas');
+
+ // Test band-aid due to lack of cleanup.
+ if (!canvas) {
+ return;
+ }
+
topo.fire('beforePageSizeRecalculation');
// Get the canvas out of the way so we can calculate the size
// correctly (the canvas contains the svg). We want it to be the
@@ -1566,8 +1572,6 @@
'd3',
'd3-components',
'juju-templates',
- 'node',
- 'event',
'juju-models',
'juju-env'
]
=== modified file 'app/views/topology/panzoom.js'
--- app/views/topology/panzoom.js 2012-12-20 16:23:32 +0000
+++ app/views/topology/panzoom.js 2012-12-24 03:49:21 +0000
@@ -181,10 +181,11 @@
views.PanZoomModule = PanZoomModule;
}, '0.1.0', {
requires: [
+ 'node',
+ 'event',
+ 'slider',
'd3',
'd3-components',
- 'node',
- 'event',
'juju-models',
'juju-env'
]
=== modified file 'app/views/utils.js'
--- app/views/utils.js 2012-12-20 21:59:21 +0000
+++ app/views/utils.js 2012-12-24 03:49:21 +0000
@@ -118,6 +118,8 @@
time: noop,
timeEnd: noop,
log: noop,
+ info: noop,
+ error: noop,
debug: noop
};
=== modified file 'package.json'
--- package.json 2012-12-11 04:11:39 +0000
+++ package.json 2012-12-24 03:49:21 +0000
@@ -15,8 +15,9 @@
"cryptojs": ">= 2.5.3"
},
"devDependencies": {
- "d3": ">=2.10.1",
+ "d3": "<3.0.0",
"yui": ">=3.7.0",
+ "yeti": ">=0.2.0",
"mocha": "1.5.x",
"express": "3.x",
"expect.js": "0.1.2",
=== modified file 'test/index.html'
--- test/index.html 2012-12-17 14:53:46 +0000
+++ test/index.html 2012-12-24 03:49:21 +0000
@@ -3,49 +3,64 @@
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="assets/mocha.css">
+
+
+ <!-- Load test runner/environment -->
+ <script src="assets/chai.js"></script>
+ <script src="assets/mocha.js"></script>
+ <script>
+ var assert = chai.assert,
+ expect = chai.expect;
+
+ var should = chai.should();
+ console.log('mocha setup');
+ mocha.setup({'ui': 'bdd', 'ignoreLeaks': false, 'timeout': 20000})
+ console.log('mocha setup done');
+ </script>
+
+ <!-- Load up YUI base, app modules, and test utils -->
+ <!-- Since only the tests depend on these files and the prod tests disable
+ the YUI loader, we have to include them manually here. -->
<script src="/juju-ui/assets/modules.js"></script>
<script src="/juju-ui/assets/all-yui.js"></script>
- <!-- Since only the tests depend on these files and the prod tests disable
- the YUI loader, we have to include them manually here. -->
<script src="/juju-ui/assets/event-simulate.js"></script>
<script src="/juju-ui/assets/node-event-simulate.js"></script>
- <script src="assets/chai.js"></script>
- <script src="assets/mocha.js"></script>
<script src="utils.js"></script>
- <script>
- var assert = chai.assert,
- expect = chai.expect
- should = chai.should();
- mocha.setup({'ui': 'bdd', 'ignoreLeaks': false})
- </script>
-
+
+
+ <!-- Tests (Alphabetical)-->
+ <script src="test_app.js"></script>
+ <script src="test_app_hotkeys.js"></script>
+ <script src="test_application_notifications.js"></script>
+ <script src="test_charm_collection_view.js"></script>
+ <script src="test_charm_configuration.js"></script>
+ <script src="test_charm_panel.js"></script>
+ <script src="test_charm_store.js"></script>
+ <script src="test_charm_view.js"></script>
+ <script src="test_console.js"></script>
<script src="test_d3_components.js"></script>
- <script src="test_topology.js"></script>
+ <script src="test_environment_view.js"></script>
<script src="test_env.js"></script>
+ <script src="test_endpoints.js"></script>
<script src="test_model.js"></script>
<script src="test_notifications.js"></script>
- <script src="test_app.js"></script>
- <script src="test_unit_view.js"></script>
- <script src="test_charm_collection_view.js"></script>
- <script src="test_charm_view.js"></script>
- <script src="test_environment_view.js"></script>
+ <script src="test_notifier_widget.js"></script>
+ <script src="test_topology.js"></script>
<script src="test_service_config_view.js"></script>
<script src="test_service_view.js"></script>
+ <script src="test_unit_view.js"></script>
<script src="test_utils.js"></script>
- <script src="test_charm_panel.js"></script>
- <script src="test_charm_configuration.js"></script>
- <script src="test_console.js"></script>
- <script src="test_endpoints.js"></script>
- <script src="test_application_notifications.js"></script>
- <script src="test_charm_store.js"></script>
- <script src="test_app_hotkeys.js"></script>
- <script src="test_notifier_widget.js"></script>
+
<script>
- YUI().use('node', 'event', function(Y) {
+ YUI({'async': false}).use('node', 'event', function(Y) {
Y.on('domready', function() {
var config = GlobalConfig;
+
+ config.async = false;
+ config.consoleEnabled = true;
+
for (group in config.groups) {
var group = config.groups[group];
for (m in group.modules) {
@@ -54,11 +69,12 @@
continue
}
resource.fullpath = resource.fullpath.replace(
- '/juju-ui/', '../juju-ui/', 1);
+ '/juju-ui/', '../juju-ui/');
}
}
- // Load before test runner
- mocha.run();
+ // Run the tests.
+ if (window.mochaPhantomJS) { mochaPhantomJS.run(); }
+ else { mocha.run(); }
});
});
</script>
=== modified file 'test/test_app.js'
--- test/test_app.js 2012-12-03 20:24:44 +0000
+++ test/test_app.js 2012-12-24 03:49:21 +0000
@@ -31,9 +31,18 @@
return app;
}
-YUI(GlobalConfig).use(['juju-gui', 'juju-tests-utils'], function(Y) {
+(function() {
+
describe('Application basics', function() {
- var app, container;
+ var Y, app, container;
+
+ before(function(done) {
+ Y = YUI(GlobalConfig).use(
+ ['juju-gui', 'juju-tests-utils'],
+ function(Y) {
+ done();
+ });
+ });
beforeEach(function() {
container = Y.one('#main')
@@ -116,14 +125,22 @@
});
});
-});
-
-YUI(GlobalConfig).use(['juju-gui', 'juju-tests-utils'], function(Y) {
+})();
+
+
+
+(function() {
+
describe('Application Connection State', function() {
- var container;
+ var container, Y;
- before(function() {
- container = Y.Node.create('<div id="test" class="container"></div>');
+ 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() {
@@ -134,7 +151,6 @@
reset_called = false,
noop = function() {return this;};
-
// mock the db
app.db = {
// mock out notifications
@@ -162,15 +178,23 @@
});
});
-});
-
-YUI(GlobalConfig).use(['juju-models', 'juju-gui', 'datasource-local',
- 'juju-tests-utils', 'json-stringify'], function(Y) {
+})();
+
+
+(function() {
+
describe('Application prefetching', function() {
- var models, conn, env, app, container, charm_store, data, juju;
+ var Y, models, conn, env, app, container, charm_store, data, juju;
- before(function() {
- models = Y.namespace('juju.models');
+ before(function(done) {
+ console.log('Loading App prefetch test code');
+ Y = YUI(GlobalConfig).use(
+ ['juju-gui', 'datasource-local',
+ 'juju-views', 'juju-templates',
+ 'juju-tests-utils', 'json-stringify'], function(Y) {
+ models = Y.namespace('juju.models');
+ done();
+ });
});
beforeEach(function() {
@@ -237,4 +261,4 @@
get_endpoints_count.should.equal(2);
});
});
-});
+})();
=== modified file 'test/test_app_hotkeys.js'
--- test/test_app_hotkeys.js 2012-11-27 14:25:32 +0000
+++ test/test_app_hotkeys.js 2012-12-24 03:49:21 +0000
@@ -1,11 +1,11 @@
'use strict';
-YUI(GlobalConfig).use(['juju-gui', 'juju-tests-utils', 'node-event-simulate'],
- function(Y) {
- describe('application hotkeys', function() {
- var app, container, windowNode;
+describe('application hotkeys', function() {
+ var app, container, windowNode, Y;
- before(function(done) {
+ before(function(done) {
+ Y = YUI(GlobalConfig).use(
+ ['juju-gui', 'juju-tests-utils', 'node-event-simulate'], function(Y) {
var env = {
after: function() {},
get: function() {},
@@ -21,43 +21,45 @@
done();
});
- beforeEach(function() {
- container = Y.Node.create('<div/>');
- Y.one('#main').append(container);
- app.render();
- });
-
- afterEach(function() {
- container.remove(true);
- });
-
- it('should listen for alt-S events', function() {
- var searchInput = Y.Node.create('<input/>');
- searchInput.set('id', 'charm-search-field');
- container.append(searchInput);
- windowNode.simulate('keydown', {
- keyCode: 83, // "S" key.
- altKey: true
- });
- // Did charm-search-field get the focus?
- assert.equal(searchInput, Y.one(document.activeElement));
- });
-
- it('should listen for alt-E events', function() {
- var altEtriggered = false;
- app.on('navigateTo', function(ev) {
- if (ev && ev.url === '/') {
- altEtriggered = true;
- }
- // Avoid URL change performed by additional listeners.
- ev.stopImmediatePropagation();
- });
- windowNode.simulate('keydown', {
- keyCode: 69, // "E" key.
- altKey: true
- });
- assert.isTrue(altEtriggered);
- });
-
- });
- });
+ });
+
+ beforeEach(function() {
+ container = Y.Node.create('<div/>');
+ Y.one('#main').append(container);
+ app.render();
+ });
+
+ afterEach(function() {
+ container.remove(true);
+ });
+
+ it('should listen for alt-S events', function() {
+ var searchInput = Y.Node.create('<input/>');
+ searchInput.set('id', 'charm-search-field');
+ container.append(searchInput);
+ windowNode.simulate('keydown', {
+ keyCode: 83, // "S" key.
+ altKey: true
+ });
+ // Did charm-search-field get the focus?
+ assert.equal(searchInput, Y.one(document.activeElement));
+ });
+
+ it('should listen for alt-E events', function() {
+ var altEtriggered = false;
+ app.on('navigateTo', function(ev) {
+ if (ev && ev.url === '/') {
+ altEtriggered = true;
+ }
+ // Avoid URL change performed by additional listeners.
+ ev.stopImmediatePropagation();
+ });
+ windowNode.simulate('keydown', {
+ keyCode: 69, // "E" key.
+ altKey: true
+ });
+ assert.isTrue(altEtriggered);
+ });
+
+});
+
=== modified file 'test/test_d3_components.js'
--- test/test_d3_components.js 2012-12-19 13:45:10 +0000
+++ test/test_d3_components.js 2012-12-24 03:49:21 +0000
@@ -32,7 +32,6 @@
state.cancelled = true;
}
});
-
done();
});
});
=== modified file 'test/test_notifications.js'
--- test/test_notifications.js 2012-11-23 16:21:32 +0000
+++ test/test_notifications.js 2012-12-24 03:49:21 +0000
@@ -1,462 +1,477 @@
'use strict';
-YUI(GlobalConfig).use(['juju-gui', 'node-event-simulate', 'juju-tests-utils'],
+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'],
+
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() {
+ 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) {
var juju = Y.namespace('juju');
env = new juju.Environment();
models = Y.namespace('juju.models');
views = Y.namespace('juju.views');
- });
-
- // 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);
- });
-
- });
+ 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
});
+ 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-23 16:21:32 +0000
+++ test/test_notifier_widget.js 2012-12-24 03:49:21 +0000
@@ -1,101 +1,104 @@
'use strict';
-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() {
+
+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) {
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);
- });
-
- 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);
- });
-
+ done();
+ }, 250);
});
+
});
+
Follow ups