diff --git a/IPython/html/static/base/js/utils.js b/IPython/html/static/base/js/utils.js
index 013389cd4..fba5baac4 100644
--- a/IPython/html/static/base/js/utils.js
+++ b/IPython/html/static/base/js/utils.js
@@ -605,7 +605,119 @@ define([
$.ajax(url, settings);
});
};
-
+
+ var WrappedError = function(message, error){
+ // Wrappable Error class
+
+ // The Error class doesn't actually act on `this`. Instead it always
+ // returns a new instance of Error. Here we capture that instance so we
+ // can apply it's properties to `this`.
+ var tmp = Error.apply(this, [message]);
+
+ // Copy the properties of the error over to this.
+ var properties = Object.getOwnPropertyNames(tmp);
+ for (var i = 0; i < properties.length; i++) {
+ this[properties[i]] = tmp[properties[i]];
+ }
+
+ // Keep a stack of the original error messages.
+ if (error instanceof WrappedError) {
+ this.error_stack = error.error_stack;
+ } else {
+ this.error_stack = [error];
+ }
+ this.error_stack.push(tmp);
+
+ return this;
+ };
+
+ WrappedError.prototype = Object.create(Error.prototype, {});
+
+
+ var load_class = function(class_name, module_name, registry) {
+ // Tries to load a class
+ //
+ // Tries to load a class from a module using require.js, if a module
+ // is specified, otherwise tries to load a class from the global
+ // registry, if the global registry is provided.
+ return new Promise(function(resolve, reject) {
+
+ // Try loading the view module using require.js
+ if (module_name) {
+ require([module_name], function(module) {
+ if (module[class_name] === undefined) {
+ reject(new Error('Class '+class_name+' not found in module '+module_name));
+ } else {
+ resolve(module[class_name]);
+ }
+ }, reject);
+ } else {
+ if (registry && registry[class_name]) {
+ resolve(registry[class_name]);
+ } else {
+ reject(new Error('Class '+class_name+' not found in registry '));
+ }
+ }
+ });
+ };
+
+ var resolve_promises_dict = function(d) {
+ // Resolve a promiseful dictionary.
+ // Returns a single Promise.
+ var keys = Object.keys(d);
+ var values = [];
+ keys.forEach(function(key) {
+ values.push(d[key]);
+ });
+ return Promise.all(values).then(function(v) {
+ d = {};
+ for(var i=0; i');
+ cell.widget_subarea.append(dummy);
+ that.create_view(model, {cell: cell}).then(function(view) {
+ that._handle_display_view(view);
+ dummy.replaceWith(view.$el);
+ view.trigger('displayed');
+ resolve(view);
+ }, function(error) {
+ reject(new utils.WrappedError('Could not display view', error));
+ });
+ }
+ });
};
WidgetManager.prototype._handle_display_view = function (view) {
@@ -70,52 +76,39 @@ define([
if (this.keyboard_manager) {
this.keyboard_manager.register_events(view.$el);
- if (view.additional_elements) {
- for (var i = 0; i < view.additional_elements.length; i++) {
+ if (view.additional_elements) {
+ for (var i = 0; i < view.additional_elements.length; i++) {
this.keyboard_manager.register_events(view.additional_elements[i]);
- }
- }
+ }
+ }
}
};
-
WidgetManager.prototype.create_view = function(model, options) {
- // Creates a view for a particular model.
-
- var view_name = model.get('_view_name');
- var view_mod = model.get('_view_module');
- var error = options.error || function(error) { console.log(error); };
+ // Creates a promise for a view of a given model
+
+ // Make sure the view creation is not out of order with
+ // any state updates.
+ model.state_change = model.state_change.then(function() {
+
+ return utils.load_class(model.get('_view_name'), model.get('_view_module'),
+ WidgetManager._view_types).then(function(ViewType) {
- var instantiate_view = function(ViewType) {
- if (ViewType) {
// If a view is passed into the method, use that view's cell as
// the cell for the view that is created.
options = options || {};
if (options.parent !== undefined) {
options.cell = options.parent.options.cell;
}
-
// Create and render the view...
var parameters = {model: model, options: options};
var view = new ViewType(parameters);
+ view.listenTo(model, 'destroy', view.remove);
view.render();
- model.on('destroy', view.remove, view);
- if (options.success) {
- options.success(view);
- }
- } else {
- error({unknown_view: true, view_name: view_name,
- view_module: view_mod});
- }
- };
-
- if (view_mod) {
- require([view_mod], function(module) {
- instantiate_view(module[view_name]);
- }, error);
- } else {
- instantiate_view(WidgetManager._view_types[view_name]);
- }
+ return view;
+ }, utils.reject("Couldn't create a view for model id '" + String(model.id) + "'"));
+ });
+ return model.state_change;
};
WidgetManager.prototype.get_msg_cell = function (msg_id) {
@@ -179,24 +172,20 @@ define([
};
WidgetManager.prototype.get_model = function (model_id) {
- // Look-up a model instance by its id.
- var model = this._models[model_id];
- if (model !== undefined && model.id == model_id) {
- return model;
- }
- return null;
+ // Get a promise for a model by model id.
+ return this._models[model_id];
};
WidgetManager.prototype._handle_comm_open = function (comm, msg) {
// Handle when a comm is opened.
- this.create_model({
+ return this.create_model({
model_name: msg.content.data.model_name,
model_module: msg.content.data.model_module,
- comm: comm});
+ comm: comm}).catch(utils.reject("Couldn't create a model."));
};
WidgetManager.prototype.create_model = function (options) {
- // Create and return a new widget model.
+ // Create and return a promise for a new widget model
//
// Minimally, one must provide the model_name and widget_class
// parameters to create a model from Javascript.
@@ -206,8 +195,9 @@ define([
// JS:
// IPython.notebook.kernel.widget_manager.create_model({
// model_name: 'WidgetModel',
- // widget_class: 'IPython.html.widgets.widget_int.IntSlider',
- // init_state_callback: function(model) { console.log('Create success!', model); }});
+ // widget_class: 'IPython.html.widgets.widget_int.IntSlider'})
+ // .then(function(model) { console.log('Create success!', model); },
+ // $.proxy(console.error, console));
//
// Parameters
// ----------
@@ -220,60 +210,33 @@ define([
// widget_class: (optional) string
// Target name of the widget in the back-end.
// comm: (optional) Comm
- // success: (optional) callback
- // Callback for when the model was created successfully.
- // error: (optional) callback
- // Callback for when the model wasn't created.
- // init_state_callback: (optional) callback
- // Called when the first state push from the back-end is
- // recieved. Allows you to modify the model after it's
- // complete state is filled and synced.
-
- // Make default callbacks if not specified.
- var error = options.error || function(error) { console.log(error); };
-
+
// Create a comm if it wasn't provided.
var comm = options.comm;
if (!comm) {
comm = this.comm_manager.new_comm('ipython.widget', {'widget_class': options.widget_class});
}
- // Create a new model that is connected to the comm.
var that = this;
- var instantiate_model = function(ModelType) {
- var model_id = comm.comm_id;
- var widget_model = new ModelType(that, model_id, comm, options.init_state_callback);
- widget_model.on('comm:close', function () {
- delete that._models[model_id];
+ var model_id = comm.comm_id;
+ var model_promise = utils.load_class(options.model_name, options.model_module, WidgetManager._model_types)
+ .then(function(ModelType) {
+ var widget_model = new ModelType(that, model_id, comm);
+ widget_model.once('comm:close', function () {
+ delete that._models[model_id];
+ });
+ return widget_model;
+
+ }, function(error) {
+ delete that._models[model_id];
+ var wrapped_error = new utils.WrappedError("Couldn't create model", error);
+ return Promise.reject(wrapped_error);
});
- that._models[model_id] = widget_model;
- if (options.success) {
- options.success(widget_model);
- }
- };
-
- // Get the model type using require or through the registry.
- var widget_type_name = options.model_name;
- var widget_module = options.model_module;
- if (widget_module) {
-
- // Load the module containing the widget model
- require([widget_module], function(mod) {
- if (mod[widget_type_name]) {
- instantiate_model(mod[widget_type_name]);
- } else {
- error("Error creating widget model: " + widget_type_name
- + " not found in " + widget_module);
- }
- }, error);
- } else {
-
- // No module specified, load from the global models registry
- instantiate_model(WidgetManager._model_types[widget_type_name]);
- }
+ this._models[model_id] = model_promise;
+ return model_promise;
};
- // Backwards compatability.
+ // Backwards compatibility.
IPython.WidgetManager = WidgetManager;
return {'WidgetManager': WidgetManager};
diff --git a/IPython/html/static/widgets/js/widget.js b/IPython/html/static/widgets/js/widget.js
index ea5c062c5..00a4ca740 100644
--- a/IPython/html/static/widgets/js/widget.js
+++ b/IPython/html/static/widgets/js/widget.js
@@ -3,13 +3,14 @@
define(["widgets/js/manager",
"underscore",
- "backbone",
- "jquery",
+ "backbone",
+ "jquery",
+ "base/js/utils",
"base/js/namespace",
-], function(widgetmanager, _, Backbone, $, IPython){
+], function(widgetmanager, _, Backbone, $, utils, IPython){
var WidgetModel = Backbone.Model.extend({
- constructor: function (widget_manager, model_id, comm, init_state_callback) {
+ constructor: function (widget_manager, model_id, comm) {
// Constructor
//
// Creates a WidgetModel instance.
@@ -20,11 +21,8 @@ define(["widgets/js/manager",
// model_id : string
// An ID unique to this model.
// comm : Comm instance (optional)
- // init_state_callback : callback (optional)
- // Called once when the first state message is recieved from
- // the back-end.
this.widget_manager = widget_manager;
- this.init_state_callback = init_state_callback;
+ this.state_change = Promise.resolve();
this._buffered_state_diff = {};
this.pending_msgs = 0;
this.msg_buffer = null;
@@ -71,13 +69,12 @@ define(["widgets/js/manager",
_handle_comm_msg: function (msg) {
// Handle incoming comm msg.
var method = msg.content.data.method;
+ var that = this;
switch (method) {
case 'update':
- this.set_state(msg.content.data.state);
- if (this.init_state_callback) {
- this.init_state_callback.apply(this, [this]);
- delete this.init_state_callback;
- }
+ this.state_change = this.state_change.then(function() {
+ return that.set_state(msg.content.data.state);
+ }).catch(utils.reject("Couldn't process update msg for model id '" + String(that.id) + "'", true));
break;
case 'custom':
this.trigger('msg:custom', msg.content.data.content);
@@ -89,17 +86,17 @@ define(["widgets/js/manager",
},
set_state: function (state) {
+ var that = this;
// Handle when a widget is updated via the python side.
- this.state_lock = state;
- try {
- var that = this;
- WidgetModel.__super__.set.apply(this, [Object.keys(state).reduce(function(obj, key) {
- obj[key] = that._unpack_models(state[key]);
- return obj;
- }, {})]);
- } finally {
- this.state_lock = null;
- }
+ return this._unpack_models(state).then(function(state) {
+ that.state_lock = state;
+ try {
+ WidgetModel.__super__.set.call(that, state);
+ } finally {
+ that.state_lock = null;
+ }
+ return Promise.resolve();
+ }, utils.reject("Couldn't set model state", true));
},
_handle_status: function (msg, callbacks) {
@@ -259,24 +256,18 @@ define(["widgets/js/manager",
_.each(value, function(sub_value, key) {
unpacked.push(that._unpack_models(sub_value));
});
- return unpacked;
-
+ return Promise.all(unpacked);
} else if (value instanceof Object) {
unpacked = {};
_.each(value, function(sub_value, key) {
unpacked[key] = that._unpack_models(sub_value);
});
- return unpacked;
-
+ return utils.resolve_promises_dict(unpacked);
} else if (typeof value === 'string' && value.slice(0,10) === "IPY_MODEL_") {
- var model = this.widget_manager.get_model(value.slice(10, value.length));
- if (model) {
- return model;
- } else {
- return value;
- }
+ // get_model returns a promise already
+ return this.widget_manager.get_model(value.slice(10, value.length));
} else {
- return value;
+ return Promise.resolve(value);
}
},
@@ -304,7 +295,7 @@ define(["widgets/js/manager",
this.options = parameters.options;
this.child_model_views = {};
this.child_views = {};
- this.id = this.id || IPython.utils.uuid();
+ this.id = this.id || utils.uuid();
this.model.views[this.id] = this;
this.on('displayed', function() {
this.is_displayed = true;
@@ -318,29 +309,19 @@ define(["widgets/js/manager",
},
create_child_view: function(child_model, options) {
- // Create and return a child view.
- //
- // -given a model and (optionally) a view name if the view name is
- // not given, it defaults to the model's default view attribute.
-
- // TODO: this is hacky, and makes the view depend on this cell attribute and widget manager behavior
- // it would be great to have the widget manager add the cell metadata
- // to the subview without having to add it here.
+ // Create and promise that resolves to a child view of a given model
var that = this;
- var old_callback = options.callback || function(view) {};
- options = $.extend({ parent: this, success: function(child_view) {
+ options = $.extend({ parent: this }, options || {});
+ return this.model.widget_manager.create_view(child_model, options).then(function(child_view) {
// Associate the view id with the model id.
if (that.child_model_views[child_model.id] === undefined) {
that.child_model_views[child_model.id] = [];
}
that.child_model_views[child_model.id].push(child_view.id);
-
// Remember the view by id.
that.child_views[child_view.id] = child_view;
- old_callback(child_view);
- }}, options || {});
-
- this.model.widget_manager.create_view(child_model, options);
+ return child_view;
+ }, utils.reject("Couldn't create child view"));
},
pop_child_view: function(child_model) {
diff --git a/IPython/html/static/widgets/js/widget_box.js b/IPython/html/static/widgets/js/widget_box.js
index 1d2edcbf0..abcc8babd 100644
--- a/IPython/html/static/widgets/js/widget_box.js
+++ b/IPython/html/static/widgets/js/widget_box.js
@@ -4,8 +4,9 @@
define([
"widgets/js/widget",
"jqueryui",
+ "base/js/utils",
"bootstrap",
-], function(widget, $){
+], function(widget, $, utils){
var BoxView = widget.DOMWidgetView.extend({
initialize: function(){
@@ -75,14 +76,17 @@ define([
add_child_model: function(model) {
// Called when a model is added to the children list.
var that = this;
- this.create_child_view(model, {callback: function(view) {
- that.$box.append(view.$el);
+ var dummy = $('
');
+ that.$box.append(dummy);
+ return this.create_child_view(model).then(function(view) {
+ dummy.replaceWith(view.el);
// Trigger the displayed event of the child view.
that.after_displayed(function() {
view.trigger('displayed');
});
- }});
+ return view;
+ }, utils.reject("Couldn't add child view to box", true));
},
});
diff --git a/IPython/html/static/widgets/js/widget_selectioncontainer.js b/IPython/html/static/widgets/js/widget_selectioncontainer.js
index 40b6e4307..f7cdd0758 100644
--- a/IPython/html/static/widgets/js/widget_selectioncontainer.js
+++ b/IPython/html/static/widgets/js/widget_selectioncontainer.js
@@ -114,9 +114,10 @@ define([
accordion_group.container_index = container_index;
this.model_containers[model.id] = accordion_group;
- this.create_child_view(model, {callback: function(view) {
- accordion_inner.append(view.$el);
-
+ var dummy = $('');
+ accordion_inner.append(dummy);
+ return this.create_child_view(model).then(function(view) {
+ dummy.replaceWith(view.$el);
that.update();
that.update_titles();
@@ -124,7 +125,8 @@ define([
that.after_displayed(function() {
view.trigger('displayed');
});
- }});
+ return view;
+ }, utils.reject("Couldn't add child view to box", true));
},
});
@@ -186,36 +188,40 @@ define([
.css('list-style-type', 'none')
.appendTo(this.$tabs);
- this.create_child_view(model, {callback: function(view) {
- view.parent_tab = tab;
- var tab_text = $('')
- .attr('href', '#' + uuid)
- .attr('data-toggle', 'tab')
- .text('Page ' + index)
- .appendTo(tab)
- .click(function (e) {
-
- // Calling model.set will trigger all of the other views of the
- // model to update.
- that.model.set("selected_index", index, {updated_view: that});
- that.touch();
- that.select_page(index);
- });
- tab.tab_text_index = that.containers.push(tab_text) - 1;
+ var tab_text = $('')
+ .attr('href', '#' + uuid)
+ .attr('data-toggle', 'tab')
+ .text('Page ' + index)
+ .appendTo(tab)
+ .click(function (e) {
+
+ // Calling model.set will trigger all of the other views of the
+ // model to update.
+ that.model.set("selected_index", index, {updated_view: that});
+ that.touch();
+ that.select_page(index);
+ });
+ tab.tab_text_index = that.containers.push(tab_text) - 1;
+
+ var dummy = $('');
+ var contents_div = $('', {id: uuid})
+ .addClass('tab-pane')
+ .addClass('fade')
+ .append(dummy)
+ .appendTo(that.$tab_contents);
- var contents_div = $('', {id: uuid})
- .addClass('tab-pane')
- .addClass('fade')
- .append(view.$el)
- .appendTo(that.$tab_contents);
+ return this.create_child_view(model).then(function(view) {
+ dummy.replaceWith(view.$el);
+ view.parent_tab = tab;
view.parent_container = contents_div;
// Trigger the displayed event of the child view.
that.after_displayed(function() {
view.trigger('displayed');
});
- }});
+ return view;
+ }, utils.reject("Couldn't add child view to box", true));
},
update: function(options) {
diff --git a/IPython/html/templates/page.html b/IPython/html/templates/page.html
index 93ba4b5f7..f024bb53e 100644
--- a/IPython/html/templates/page.html
+++ b/IPython/html/templates/page.html
@@ -27,9 +27,9 @@
bootstrap: 'components/bootstrap/js/bootstrap.min',
bootstraptour: 'components/bootstrap-tour/build/js/bootstrap-tour.min',
jqueryui: 'components/jquery-ui/ui/minified/jquery-ui.min',
- moment: "components/moment/moment",
+ moment: 'components/moment/moment',
codemirror: 'components/codemirror',
- termjs: "components/term.js/src/term",
+ termjs: 'components/term.js/src/term',
contents: '{{ contents_js_source }}',
},
shim: {
diff --git a/IPython/html/tests/util.js b/IPython/html/tests/util.js
index 464751cae..61f0a23c0 100644
--- a/IPython/html/tests/util.js
+++ b/IPython/html/tests/util.js
@@ -22,6 +22,35 @@ casper.open_new_notebook = function () {
});
this.waitFor(this.page_loaded);
+ // Hook the log and error methods of the console, forcing them to
+ // serialize their arguments before printing. This allows the
+ // Objects to cross into the phantom/slimer regime for display.
+ this.thenEvaluate(function(){
+ var serialize_arguments = function(f, context) {
+ return function() {
+ var pretty_arguments = [];
+ for (var i = 0; i < arguments.length; i++) {
+ var value = arguments[i];
+ if (value instanceof Object) {
+ var name = value.name || 'Object';
+ // Print a JSON string representation of the object.
+ // If we don't do this, [Object object] gets printed
+ // by casper, which is useless. The long regular
+ // expression reduces the verbosity of the JSON.
+ pretty_arguments.push(name + ' {' + JSON.stringify(value, null, ' ')
+ .replace(/(\s+)?({)?(\s+)?(}(\s+)?,?)?(\s+)?(\s+)?\n/g, '\n')
+ .replace(/\n(\s+)?\n/g, '\n'));
+ } else {
+ pretty_arguments.push(value);
+ }
+ }
+ f.apply(context, pretty_arguments);
+ };
+ };
+ console.log = serialize_arguments(console.log, console);
+ console.error = serialize_arguments(console.error, console);
+ });
+
// Make sure the kernel has started
this.waitFor(this.kernel_running);
// track the IPython busy/idle state
@@ -151,10 +180,31 @@ casper.wait_for_widget = function (widget_info) {
// widget_info : object
// Object which contains info related to the widget. The model_id property
// is used to identify the widget.
+
+ // Clear the results of a previous query, if they exist. Make sure a
+ // dictionary exists to store the async results in.
+ this.thenEvaluate(function(model_id) {
+ if (window.pending_msgs === undefined) {
+ window.pending_msgs = {};
+ } else {
+ window.pending_msgs[model_id] = -1;
+ }
+ }, {model_id: widget_info.model_id});
+
+ // Wait for the pending messages to be 0.
this.waitFor(function () {
- var pending = this.evaluate(function (m) {
- return IPython.notebook.kernel.widget_manager.get_model(m).pending_msgs;
- }, {m: widget_info.model_id});
+ var pending = this.evaluate(function (model_id) {
+
+ // Get the model. Once the model is had, store it's pending_msgs
+ // count in the window's dictionary.
+ IPython.notebook.kernel.widget_manager.get_model(model_id)
+ .then(function(model) {
+ window.pending_msgs[model_id] = model.pending_msgs;
+ });
+
+ // Return the pending_msgs result.
+ return window.pending_msgs[model_id];
+ }, {model_id: widget_info.model_id});
if (pending === 0) {
return true;
@@ -285,6 +335,15 @@ casper.execute_cell_then = function(index, then_callback, expect_failure) {
return return_val;
};
+casper.wait_for_element = function(index, selector){
+ // Utility function that allows us to easily wait for an element
+ // within a cell. Uses JQuery selector to look for the element.
+ var that = this;
+ this.waitFor(function() {
+ return that.cell_element_exists(index, selector);
+ });
+};
+
casper.cell_element_exists = function(index, selector){
// Utility function that allows us to easily check if an element exists
// within a cell. Uses JQuery selector to look for the element.
@@ -655,7 +714,10 @@ casper.print_log = function () {
casper.on("page.error", function onError(msg, trace) {
// show errors in the browser
- this.echo("Page Error!");
+ this.echo("Page Error");
+ this.echo(" Message: " + msg.split('\n').join('\n '));
+ this.echo(" Call stack:");
+ var local_path = this.get_notebook_server();
for (var i = 0; i < trace.length; i++) {
var frame = trace[i];
var file = frame.file;
@@ -664,12 +726,15 @@ casper.on("page.error", function onError(msg, trace) {
if (file === "phantomjs://webpage.evaluate()") {
file = "evaluate";
}
- this.echo("line " + frame.line + " of " + file);
- if (frame.function.length > 0) {
- this.echo("in " + frame.function);
+ // remove the version tag from the path
+ file = file.replace(/(\?v=[0-9abcdef]+)/, '');
+ // remove the local address from the beginning of the path
+ if (file.indexOf(local_path) === 0) {
+ file = file.substr(local_path.length);
}
+ var frame_text = (frame.function.length > 0) ? " in " + frame.function : "";
+ this.echo(" line " + frame.line + " of " + file + frame_text);
}
- this.echo(msg);
});
@@ -680,7 +745,8 @@ casper.capture_log = function () {
this.on('remote.message', function(msg) {
captured_log.push(msg);
});
-
+
+ var that = this;
this.test.on("test.done", function (result) {
// test.done runs per-file,
// but suiteResults is per-suite (directory)
@@ -696,12 +762,38 @@ casper.capture_log = function () {
if (current_errors > seen_errors && captured_log.length > 0) {
casper.echo("\nCaptured console.log:");
for (var i = 0; i < captured_log.length; i++) {
- casper.echo(" " + captured_log[i]);
+ var output = String(captured_log[i]).split('\n');
+ for (var j = 0; j < output.length; j++) {
+ casper.echo(" " + output[j]);
+ }
}
}
+
seen_errors = current_errors;
captured_log = [];
});
};
+casper.interact = function() {
+ // Start an interactive Javascript console.
+ var system = require('system');
+ system.stdout.writeLine('JS interactive console.');
+ system.stdout.writeLine('Type `exit` to quit.');
+
+ function read_line() {
+ system.stdout.writeLine('JS: ');
+ var line = system.stdin.readLine();
+ return line;
+ }
+
+ var input = read_line();
+ while (input.trim() != 'exit') {
+ var output = this.evaluate(function(code) {
+ return String(eval(code));
+ }, {code: input});
+ system.stdout.writeLine('\nOut: ' + output);
+ input = read_line();
+ }
+};
+
casper.capture_log();
diff --git a/IPython/html/tests/widgets/manager.js b/IPython/html/tests/widgets/manager.js
index fed79fd85..3a0120325 100644
--- a/IPython/html/tests/widgets/manager.js
+++ b/IPython/html/tests/widgets/manager.js
@@ -18,12 +18,11 @@ casper.notebook_test(function () {
this.evaluate(function() {
IPython.notebook.kernel.widget_manager.create_model({
model_name: 'WidgetModel',
- widget_class: 'IPython.html.widgets.widget_int.IntSlider',
- init_state_callback: function(model) {
+ widget_class: 'IPython.html.widgets.widget_int.IntSlider'})
+ .then(function(model) {
console.log('Create success!', model);
window.slider_id = model.id;
- }
- });
+ }, function(error) { console.log(error); });
});
});
diff --git a/IPython/html/tests/widgets/widget.js b/IPython/html/tests/widgets/widget.js
index e79a91544..d3c6b6d2a 100644
--- a/IPython/html/tests/widgets/widget.js
+++ b/IPython/html/tests/widgets/widget.js
@@ -59,13 +59,27 @@ casper.notebook_test(function () {
JSON.stringify(input) + ' passed through Model._pack_model unchanged');
};
var test_unpack = function (input) {
- var output = that.evaluate(function(input) {
+ that.thenEvaluate(function(input) {
+ window.results = undefined;
var model = new IPython.WidgetModel(IPython.notebook.kernel.widget_manager, undefined);
- var results = model._unpack_models(input);
- return results;
+ model._unpack_models(input).then(function(results) {
+ window.results = results;
+ });
}, {input: input});
- that.test.assert(recursive_compare(input, output),
- JSON.stringify(input) + ' passed through Model._unpack_model unchanged');
+
+ that.waitFor(function check() {
+ return that.evaluate(function() {
+ return window.results;
+ });
+ });
+
+ that.then(function() {
+ var results = that.evaluate(function() {
+ return window.results;
+ });
+ that.test.assert(recursive_compare(input, results),
+ JSON.stringify(input) + ' passed through Model._unpack_model unchanged');
+ });
};
var test_packing = function(input) {
test_pack(input);
@@ -84,7 +98,7 @@ casper.notebook_test(function () {
test_packing([String('hi'), Date("Thu Nov 13 2014 13:46:21 GMT-0500")])
// Test multi-set, single touch code. First create a custom widget.
- this.evaluate(function() {
+ this.thenEvaluate(function() {
var MultiSetView = IPython.DOMWidgetView.extend({
render: function(){
this.model.set('a', 1);
diff --git a/IPython/html/tests/widgets/widget_bool.js b/IPython/html/tests/widgets/widget_bool.js
index 35e755be2..3586271cb 100644
--- a/IPython/html/tests/widgets/widget_bool.js
+++ b/IPython/html/tests/widgets/widget_bool.js
@@ -1,85 +1,90 @@
// Test widget bool class
casper.notebook_test(function () {
- index = this.append_cell(
- 'from IPython.html import widgets\n' +
- 'from IPython.display import display, clear_output\n' +
- 'print("Success")');
- this.execute_cell_then(index);
+ // Create a checkbox and togglebutton.
var bool_index = this.append_cell(
+ 'from IPython.html import widgets\n' +
+ 'from IPython.display import display, clear_output\n' +
'bool_widgets = [widgets.Checkbox(description="Title", value=True),\n' +
' widgets.ToggleButton(description="Title", value=True)]\n' +
'display(bool_widgets[0])\n' +
'display(bool_widgets[1])\n' +
'print("Success")');
this.execute_cell_then(bool_index, function(index){
-
this.test.assertEquals(this.get_output_cell(index).text, 'Success\n',
'Create bool widget cell executed with correct output.');
+ });
- this.test.assert(this.cell_element_exists(index,
+ // Wait for the widgets to actually display.
+ var widget_checkbox_selector = '.widget-area .widget-subarea .widget-hbox input';
+ var widget_togglebutton_selector = '.widget-area .widget-subarea button';
+ this.wait_for_element(bool_index, widget_checkbox_selector);
+ this.wait_for_element(bool_index, widget_togglebutton_selector);
+
+ // Continue the tests.
+ this.then(function() {
+ this.test.assert(this.cell_element_exists(bool_index,
'.widget-area .widget-subarea'),
'Widget subarea exists.');
- this.test.assert(this.cell_element_exists(index,
- '.widget-area .widget-subarea .widget-hbox input'),
+ this.test.assert(this.cell_element_exists(bool_index,
+ widget_checkbox_selector),
'Checkbox exists.');
- this.test.assert(this.cell_element_function(index,
- '.widget-area .widget-subarea .widget-hbox input', 'prop', ['checked']),
+ this.test.assert(this.cell_element_function(bool_index,
+ widget_checkbox_selector, 'prop', ['checked']),
'Checkbox is checked.');
- this.test.assert(this.cell_element_exists(index,
+ this.test.assert(this.cell_element_exists(bool_index,
'.widget-area .widget-subarea .widget-hbox .widget-label'),
'Checkbox label exists.');
- this.test.assert(this.cell_element_function(index,
+ this.test.assert(this.cell_element_function(bool_index,
'.widget-area .widget-subarea .widget-hbox .widget-label', 'html')=="Title",
'Checkbox labeled correctly.');
- this.test.assert(this.cell_element_exists(index,
- '.widget-area .widget-subarea button'),
+ this.test.assert(this.cell_element_exists(bool_index,
+ widget_togglebutton_selector),
'Toggle button exists.');
- this.test.assert(this.cell_element_function(index,
- '.widget-area .widget-subarea button', 'html')=="Title",
+ this.test.assert(this.cell_element_function(bool_index,
+ widget_togglebutton_selector, 'html')=="Title",
'Toggle button labeled correctly.');
- this.test.assert(this.cell_element_function(index,
- '.widget-area .widget-subarea button', 'hasClass', ['active']),
+ this.test.assert(this.cell_element_function(bool_index,
+ widget_togglebutton_selector, 'hasClass', ['active']),
'Toggle button is toggled.');
-
});
+ // Try changing the state of the widgets programatically.
index = this.append_cell(
'bool_widgets[0].value = False\n' +
'bool_widgets[1].value = False\n' +
'print("Success")');
this.execute_cell_then(index, function(index){
-
this.test.assertEquals(this.get_output_cell(index).text, 'Success\n',
'Change bool widget value cell executed with correct output.');
this.test.assert(! this.cell_element_function(bool_index,
- '.widget-area .widget-subarea .widget-hbox input', 'prop', ['checked']),
+ widget_checkbox_selector, 'prop', ['checked']),
'Checkbox is not checked. (1)');
this.test.assert(! this.cell_element_function(bool_index,
- '.widget-area .widget-subarea button', 'hasClass', ['active']),
+ widget_togglebutton_selector, 'hasClass', ['active']),
'Toggle button is not toggled. (1)');
// Try toggling the bool by clicking on the checkbox.
- this.cell_element_function(bool_index, '.widget-area .widget-subarea .widget-hbox input', 'click');
+ this.cell_element_function(bool_index, widget_checkbox_selector, 'click');
this.test.assert(this.cell_element_function(bool_index,
- '.widget-area .widget-subarea .widget-hbox input', 'prop', ['checked']),
+ widget_checkbox_selector, 'prop', ['checked']),
'Checkbox is checked. (2)');
// Try toggling the bool by clicking on the toggle button.
- this.cell_element_function(bool_index, '.widget-area .widget-subarea button', 'click');
+ this.cell_element_function(bool_index, widget_togglebutton_selector, 'click');
this.test.assert(this.cell_element_function(bool_index,
- '.widget-area .widget-subarea button', 'hasClass', ['active']),
+ widget_togglebutton_selector, 'hasClass', ['active']),
'Toggle button is toggled. (3)');
});
diff --git a/IPython/html/tests/widgets/widget_box.js b/IPython/html/tests/widgets/widget_box.js
index 6e1f242b7..617423d0c 100644
--- a/IPython/html/tests/widgets/widget_box.js
+++ b/IPython/html/tests/widgets/widget_box.js
@@ -1,12 +1,10 @@
// Test container class
casper.notebook_test(function () {
- index = this.append_cell(
- 'from IPython.html import widgets\n' +
- 'from IPython.display import display, clear_output\n' +
- 'print("Success")');
- this.execute_cell_then(index);
+ // Create a box widget.
var container_index = this.append_cell(
+ 'from IPython.html import widgets\n' +
+ 'from IPython.display import display, clear_output\n' +
'container = widgets.Box()\n' +
'button = widgets.Button()\n'+
'container.children = [button]\n'+
@@ -14,24 +12,32 @@ casper.notebook_test(function () {
'container._dom_classes = ["my-test-class"]\n'+
'print("Success")\n');
this.execute_cell_then(container_index, function(index){
-
this.test.assertEquals(this.get_output_cell(index).text, 'Success\n',
'Create container cell executed with correct output.');
+ });
- this.test.assert(this.cell_element_exists(index,
+ // Wait for the widgets to actually display.
+ var widget_box_selector = '.widget-area .widget-subarea .widget-box';
+ var widget_box_button_selector = '.widget-area .widget-subarea .widget-box button';
+ this.wait_for_element(container_index, widget_box_selector);
+ this.wait_for_element(container_index, widget_box_button_selector);
+
+ // Continue with the tests.
+ this.then(function() {
+ this.test.assert(this.cell_element_exists(container_index,
'.widget-area .widget-subarea'),
'Widget subarea exists.');
- this.test.assert(this.cell_element_exists(index,
- '.widget-area .widget-subarea .widget-box'),
+ this.test.assert(this.cell_element_exists(container_index,
+ widget_box_selector),
'Widget container exists.');
- this.test.assert(this.cell_element_exists(index,
+ this.test.assert(this.cell_element_exists(container_index,
'.widget-area .widget-subarea .my-test-class'),
'_dom_classes works.');
- this.test.assert(this.cell_element_exists(index,
- '.widget-area .widget-subarea .my-test-class button'),
+ this.test.assert(this.cell_element_exists(container_index,
+ widget_box_button_selector),
'Container parent/child relationship works.');
});
@@ -61,20 +67,26 @@ casper.notebook_test(function () {
'_dom_classes can be used to remove a class.');
});
- index = this.append_cell(
+ var boxalone_index = this.append_cell(
'display(button)\n'+
'print("Success")\n');
- this.execute_cell_then(index, function(index){
-
+ this.execute_cell_then(boxalone_index, function(index){
this.test.assertEquals(this.get_output_cell(index).text, 'Success\n',
'Display container child executed with correct output.');
+ });
+
+ // Wait for the widget to actually display.
+ var widget_button_selector = '.widget-area .widget-subarea button';
+ this.wait_for_element(boxalone_index, widget_button_selector);
- this.test.assert(! this.cell_element_exists(index,
- '.widget-area .widget-subarea .widget-box'),
+ // Continue with the tests.
+ this.then(function() {
+ this.test.assert(! this.cell_element_exists(boxalone_index,
+ widget_box_selector),
'Parent container not displayed.');
- this.test.assert(this.cell_element_exists(index,
- '.widget-area .widget-subarea button'),
+ this.test.assert(this.cell_element_exists(boxalone_index,
+ widget_button_selector),
'Child displayed.');
});
});
\ No newline at end of file
diff --git a/IPython/html/tests/widgets/widget_button.js b/IPython/html/tests/widgets/widget_button.js
index 3329a89bd..80f86732a 100644
--- a/IPython/html/tests/widgets/widget_button.js
+++ b/IPython/html/tests/widgets/widget_button.js
@@ -1,12 +1,8 @@
// Test widget button class
casper.notebook_test(function () {
- index = this.append_cell(
+ var button_index = this.append_cell(
'from IPython.html import widgets\n' +
'from IPython.display import display, clear_output\n' +
- 'print("Success")');
- this.execute_cell_then(index);
-
- var button_index = this.append_cell(
'button = widgets.Button(description="Title")\n' +
'display(button)\n' +
'print("Success")\n' +
@@ -14,24 +10,30 @@ casper.notebook_test(function () {
' display("Clicked")\n' +
'button.on_click(handle_click)');
this.execute_cell_then(button_index, function(index){
-
this.test.assertEquals(this.get_output_cell(index).text, 'Success\n',
'Create button cell executed with correct output.');
+ });
+
+ // Wait for the widgets to actually display.
+ var widget_button_selector = '.widget-area .widget-subarea button';
+ this.wait_for_element(button_index, widget_button_selector);
- this.test.assert(this.cell_element_exists(index,
+ // Continue with the tests.
+ this.then(function() {
+ this.test.assert(this.cell_element_exists(button_index,
'.widget-area .widget-subarea'),
'Widget subarea exists.');
- this.test.assert(this.cell_element_exists(index,
- '.widget-area .widget-subarea button'),
+ this.test.assert(this.cell_element_exists(button_index,
+ widget_button_selector),
'Widget button exists.');
- this.test.assert(this.cell_element_function(index,
- '.widget-area .widget-subarea button', 'html')=='Title',
+ this.test.assert(this.cell_element_function(button_index,
+ widget_button_selector, 'html')=='Title',
'Set button description.');
- this.cell_element_function(index,
- '.widget-area .widget-subarea button', 'click');
+ this.cell_element_function(button_index,
+ widget_button_selector, 'click');
});
this.wait_for_output(button_index, 1);
diff --git a/IPython/html/tests/widgets/widget_float.js b/IPython/html/tests/widgets/widget_float.js
index 291efb314..d253a80b7 100644
--- a/IPython/html/tests/widgets/widget_float.js
+++ b/IPython/html/tests/widgets/widget_float.js
@@ -1,26 +1,28 @@
// Test widget float class
casper.notebook_test(function () {
- index = this.append_cell(
- 'from IPython.html import widgets\n' +
- 'from IPython.display import display, clear_output\n' +
- 'print("Success")');
- this.execute_cell_then(index);
-
var float_text = {};
float_text.query = '.widget-area .widget-subarea .my-second-float-text input';
float_text.index = this.append_cell(
+ 'from IPython.html import widgets\n' +
+ 'from IPython.display import display, clear_output\n' +
'float_widget = widgets.FloatText()\n' +
'display(float_widget)\n' +
'float_widget._dom_classes = ["my-second-float-text"]\n' +
'print(float_widget.model_id)\n');
this.execute_cell_then(float_text.index, function(index){
float_text.model_id = this.get_output_cell(index).text.trim();
-
- this.test.assert(this.cell_element_exists(index,
+ });
+
+ // Wait for the widget to actually display.
+ this.wait_for_element(float_text.index, float_text.query);
+
+ // Continue with the tests
+ this.then(function(){
+ this.test.assert(this.cell_element_exists(float_text.index,
'.widget-area .widget-subarea'),
'Widget subarea exists.');
- this.test.assert(this.cell_element_exists(index, float_text.query),
+ this.test.assert(this.cell_element_exists(float_text.index, float_text.query),
'Widget float textbox exists.');
this.cell_element_function(float_text.index, float_text.query, 'val', ['']);
@@ -64,18 +66,23 @@ casper.notebook_test(function () {
'[display(floatrange[i]) for i in range(2)]\n' +
'print("Success")\n');
this.execute_cell_then(slider.index, function(index){
-
this.test.assertEquals(this.get_output_cell(index).text, 'Success\n',
'Create float range cell executed with correct output.');
+ });
+
+ // Wait for the widgets to actually display.
+ this.wait_for_element(slider.index, slider.query);
+ this.wait_for_element(slider.index, float_text_query);
- this.test.assert(this.cell_element_exists(index,
+ this.then(function(){
+ this.test.assert(this.cell_element_exists(slider.index,
'.widget-area .widget-subarea'),
'Widget subarea exists.');
- this.test.assert(this.cell_element_exists(index, slider.query),
+ this.test.assert(this.cell_element_exists(slider.index, slider.query),
'Widget slider exists.');
- this.test.assert(this.cell_element_exists(index, float_text_query),
+ this.test.assert(this.cell_element_exists(slider.index, float_text_query),
'Widget float textbox exists.');
});
diff --git a/IPython/html/tests/widgets/widget_image.js b/IPython/html/tests/widgets/widget_image.js
index ba10d3543..507215543 100644
--- a/IPython/html/tests/widgets/widget_image.js
+++ b/IPython/html/tests/widgets/widget_image.js
@@ -26,19 +26,23 @@ casper.notebook_test(function () {
'display(image)\n' +
'print("Success")\n');
this.execute_cell_then(image_index, function(index){
-
this.test.assertEquals(this.get_output_cell(index).text, 'Success\n',
'Create image executed with correct output.');
+ });
+
+ // Wait for the widget to actually display.
+ var img_selector = '.widget-area .widget-subarea img';
+ this.wait_for_element(image_index, img_selector);
- this.test.assert(this.cell_element_exists(index,
+ this.then(function(){
+ this.test.assert(this.cell_element_exists(image_index,
'.widget-area .widget-subarea'),
'Widget subarea exists.');
- var img_sel = '.widget-area .widget-subarea img';
- this.test.assert(this.cell_element_exists(index, img_sel), 'Image exists.');
+ this.test.assert(this.cell_element_exists(image_index, img_selector), 'Image exists.');
// Verify that the image's base64 data has made it into the DOM.
- var img_src = this.cell_element_function(image_index, img_sel, 'attr', ['src']);
+ var img_src = this.cell_element_function(image_index, img_selector, 'attr', ['src']);
this.test.assert(img_src.indexOf(test_jpg) > -1, 'Image src data exists.');
});
});
\ No newline at end of file
diff --git a/IPython/html/tests/widgets/widget_int.js b/IPython/html/tests/widgets/widget_int.js
index 086235198..8ca6ca81a 100644
--- a/IPython/html/tests/widgets/widget_int.js
+++ b/IPython/html/tests/widgets/widget_int.js
@@ -1,26 +1,28 @@
// Test widget int class
casper.notebook_test(function () {
- index = this.append_cell(
- 'from IPython.html import widgets\n' +
- 'from IPython.display import display, clear_output\n' +
- 'print("Success")');
- this.execute_cell_then(index);
-
var int_text = {};
int_text.query = '.widget-area .widget-subarea .my-second-int-text input';
int_text.index = this.append_cell(
+ 'from IPython.html import widgets\n' +
+ 'from IPython.display import display, clear_output\n' +
'int_widget = widgets.IntText()\n' +
'display(int_widget)\n' +
'int_widget._dom_classes = ["my-second-int-text"]\n' +
'print(int_widget.model_id)\n');
this.execute_cell_then(int_text.index, function(index){
int_text.model_id = this.get_output_cell(index).text.trim();
-
- this.test.assert(this.cell_element_exists(index,
+ });
+
+ // Wait for the widget to actually display.
+ this.wait_for_element(int_text.index, int_text.query);
+
+ // Continue with the tests.
+ this.then(function() {
+ this.test.assert(this.cell_element_exists(int_text.index,
'.widget-area .widget-subarea'),
'Widget subarea exists.');
- this.test.assert(this.cell_element_exists(index, int_text.query),
+ this.test.assert(this.cell_element_exists(int_text.index, int_text.query),
'Widget int textbox exists.');
this.cell_element_function(int_text.index, int_text.query, 'val', ['']);
@@ -54,13 +56,6 @@ casper.notebook_test(function () {
this.test.assertEquals(this.get_output_cell(index).text, '12\n',
'Invald int textbox value caught and filtered.');
});
-
- index = this.append_cell(
- 'from IPython.html import widgets\n' +
- 'from IPython.display import display, clear_output\n' +
- 'print("Success")');
- this.execute_cell_then(index);
-
var slider_query = '.widget-area .widget-subarea .slider';
var int_text2 = {};
@@ -73,15 +68,22 @@ casper.notebook_test(function () {
'print(intrange[0].model_id)\n');
this.execute_cell_then(int_text2.index, function(index){
int_text2.model_id = this.get_output_cell(index).text.trim();
+ });
+
+ // Wait for the widgets to actually display.
+ this.wait_for_element(int_text2.index, int_text2.query);
+ this.wait_for_element(int_text2.index, slider_query);
- this.test.assert(this.cell_element_exists(index,
+ // Continue with the tests.
+ this.then(function(){
+ this.test.assert(this.cell_element_exists(int_text2.index,
'.widget-area .widget-subarea'),
'Widget subarea exists.');
- this.test.assert(this.cell_element_exists(index, slider_query),
+ this.test.assert(this.cell_element_exists(int_text2.index, slider_query),
'Widget slider exists.');
- this.test.assert(this.cell_element_exists(index, int_text2.query),
+ this.test.assert(this.cell_element_exists(int_text2.index, int_text2.query),
'Widget int textbox exists.');
});
diff --git a/IPython/html/tests/widgets/widget_selection.js b/IPython/html/tests/widgets/widget_selection.js
index e4e4524f2..ea87a3830 100644
--- a/IPython/html/tests/widgets/widget_selection.js
+++ b/IPython/html/tests/widgets/widget_selection.js
@@ -58,21 +58,30 @@ casper.notebook_test(function () {
this.execute_cell_then(selection_index, function(index){
this.test.assertEquals(this.get_output_cell(index).text, 'Success\n',
'Create selection cell executed with correct output.');
+ });
+
+ // Wait for the widgets to actually display.
+ this.wait_for_element(selection_index, combo_selector);
+ this.wait_for_element(selection_index, multibtn_selector);
+ this.wait_for_element(selection_index, radio_selector);
+ this.wait_for_element(selection_index, list_selector);
- this.test.assert(this.cell_element_exists(index,
+ // Continue with the tests.
+ this.then(function() {
+ this.test.assert(this.cell_element_exists(selection_index,
'.widget-area .widget-subarea'),
'Widget subarea exists.');
- this.test.assert(this.cell_element_exists(index, combo_selector),
+ this.test.assert(this.cell_element_exists(selection_index, combo_selector),
'Widget combobox exists.');
- this.test.assert(this.cell_element_exists(index, multibtn_selector),
+ this.test.assert(this.cell_element_exists(selection_index, multibtn_selector),
'Widget multibutton exists.');
- this.test.assert(this.cell_element_exists(index, radio_selector),
+ this.test.assert(this.cell_element_exists(selection_index, radio_selector),
'Widget radio buttons exists.');
- this.test.assert(this.cell_element_exists(index, list_selector),
+ this.test.assert(this.cell_element_exists(selection_index, list_selector),
'Widget list exists.');
// Verify that no items are selected.
diff --git a/IPython/html/tests/widgets/widget_selectioncontainer.js b/IPython/html/tests/widgets/widget_selectioncontainer.js
index 57e9bd1c2..d8680addd 100644
--- a/IPython/html/tests/widgets/widget_selectioncontainer.js
+++ b/IPython/html/tests/widgets/widget_selectioncontainer.js
@@ -18,20 +18,22 @@ casper.notebook_test(function () {
'multicontainer.selected_index = 0\n' +
'print("Success")\n');
this.execute_cell_then(multicontainer1_index, function(index){
-
this.test.assertEquals(this.get_output_cell(index).text, 'Success\n',
'Create multicontainer cell executed with correct output. (1)');
+ });
+
+ // Wait for the widget to actually display.
+ this.wait_for_element(multicontainer1_index, multicontainer1_query);
- this.test.assert(this.cell_element_exists(index,
+ // Continue with the tests.
+ this.then(function() {
+ this.test.assert(this.cell_element_exists(multicontainer1_index,
'.widget-area .widget-subarea'),
'Widget subarea exists.');
- this.test.assert(this.cell_element_exists(index, multicontainer1_query),
+ this.test.assert(this.cell_element_exists(multicontainer1_index, multicontainer1_query),
'Widget tab list exists.');
- this.test.assert(this.cell_element_exists(index, multicontainer1_query),
- 'First widget tab list exists.');
-
// JQuery selector is 1 based
this.click(multicontainer1_query + ' li:nth-child(2) a');
});
@@ -74,23 +76,28 @@ casper.notebook_test(function () {
'multicontainer.selected_index = 0\n' +
'print("Success")\n');
this.execute_cell_then(multicontainer2_index, function(index){
-
this.test.assertEquals(this.get_output_cell(index).text, 'Success\n',
'Create multicontainer cell executed with correct output. (2)');
+ });
+
+ // Wait for the widget to actually display.
+ this.wait_for_element(multicontainer2_index, multicontainer2_query);
- this.test.assert(this.cell_element_exists(index,
+ // Continue with the tests.
+ this.then(function() {
+ this.test.assert(this.cell_element_exists(multicontainer2_index,
'.widget-area .widget-subarea'),
'Widget subarea exists.');
- this.test.assert(this.cell_element_exists(index, multicontainer2_query),
+ this.test.assert(this.cell_element_exists(multicontainer2_index, multicontainer2_query),
'Widget accordion exists.');
- this.test.assert(this.cell_element_exists(index, multicontainer2_query +
+ this.test.assert(this.cell_element_exists(multicontainer2_index, multicontainer2_query +
' .panel:nth-child(1) .panel-collapse'),
'First accordion page exists.');
// JQuery selector is 1 based
- this.test.assert(this.cell_element_function(index, multicontainer2_query +
+ this.test.assert(this.cell_element_function(multicontainer2_index, multicontainer2_query +
' .panel.panel-default:nth-child(3) .panel-heading .accordion-toggle',
'html')=='good', 'Accordion page title set (before display).');
diff --git a/IPython/html/tests/widgets/widget_string.js b/IPython/html/tests/widgets/widget_string.js
index 54e669d10..c01afb749 100644
--- a/IPython/html/tests/widgets/widget_string.js
+++ b/IPython/html/tests/widgets/widget_string.js
@@ -1,12 +1,8 @@
// Test widget string class
casper.notebook_test(function () {
- index = this.append_cell(
+ var string_index = this.append_cell(
'from IPython.html import widgets\n' +
'from IPython.display import display, clear_output\n' +
- 'print("Success")');
- this.execute_cell_then(index);
-
- var string_index = this.append_cell(
'string_widget = [widgets.Text(value = "xyz", placeholder = "abc"),\n' +
' widgets.Textarea(value = "xyz", placeholder = "def"),\n' +
' widgets.HTML(value = "xyz"),\n' +
@@ -14,40 +10,50 @@ casper.notebook_test(function () {
'[display(widget) for widget in string_widget]\n'+
'print("Success")');
this.execute_cell_then(string_index, function(index){
-
this.test.assertEquals(this.get_output_cell(index).text, 'Success\n',
'Create string widget cell executed with correct output.');
+ });
+
+ // Wait for the widget to actually display.
+ var textbox_selector = '.widget-area .widget-subarea .widget-hbox input[type=text]';
+ var textarea_selector = '.widget-area .widget-subarea .widget-hbox textarea';
+ var latex_selector = '.widget-area .widget-subarea div span.MathJax_Preview';
+ this.wait_for_element(string_index, textbox_selector);
+ this.wait_for_element(string_index, textarea_selector);
+ this.wait_for_element(string_index, latex_selector);
- this.test.assert(this.cell_element_exists(index,
+ // Continue with the tests.
+ this.then(function(){
+ this.test.assert(this.cell_element_exists(string_index,
'.widget-area .widget-subarea'),
'Widget subarea exists.');
- this.test.assert(this.cell_element_exists(index,
- '.widget-area .widget-subarea .widget-hbox input[type=text]'),
+ this.test.assert(this.cell_element_exists(string_index,
+ textbox_selector),
'Textbox exists.');
- this.test.assert(this.cell_element_exists(index,
- '.widget-area .widget-subarea .widget-hbox textarea'),
+ this.test.assert(this.cell_element_exists(string_index,
+ textarea_selector),
'Textarea exists.');
- this.test.assert(this.cell_element_function(index,
- '.widget-area .widget-subarea .widget-hbox textarea', 'val')=='xyz',
+ this.test.assert(this.cell_element_function(string_index,
+ textarea_selector, 'val')=='xyz',
'Python set textarea value.');
- this.test.assert(this.cell_element_function(index,
- '.widget-area .widget-subarea .widget-hbox input[type=text]', 'val')=='xyz',
+ this.test.assert(this.cell_element_function(string_index,
+ textbox_selector, 'val')=='xyz',
'Python set textbox value.');
this.test.assert(this.cell_element_exists(string_index,
- '.widget-area .widget-subarea div span.MathJax_Preview'),
+ latex_selector),
'MathJax parsed the LaTeX successfully.');
- this.test.assert(this.cell_element_function(index,
- '.widget-area .widget-subarea .widget-hbox textarea', 'attr', ['placeholder'])=='def',
+ this.test.assert(this.cell_element_function(string_index,
+ textarea_selector, 'attr', ['placeholder'])=='def',
'Python set textarea placeholder.');
- this.test.assert(this.cell_element_function(index,
- '.widget-area .widget-subarea .widget-hbox input[type=text]', 'attr', ['placeholder'])=='abc',
+ this.test.assert(this.cell_element_function(string_index,
+ textbox_selector, 'attr', ['placeholder'])=='abc',
'Python set textbox placehoder.');
});
});