##// END OF EJS Templates
Check for Python errors in js tests...
MinRK -
Show More
@@ -1,603 +1,627 b''
1 //
1 //
2 // Utility functions for the HTML notebook's CasperJS tests.
2 // Utility functions for the HTML notebook's CasperJS tests.
3 //
3 //
4 casper.get_notebook_server = function () {
4 casper.get_notebook_server = function () {
5 // Get the URL of a notebook server on which to run tests.
5 // Get the URL of a notebook server on which to run tests.
6 port = casper.cli.get("port");
6 port = casper.cli.get("port");
7 port = (typeof port === 'undefined') ? '8888' : port;
7 port = (typeof port === 'undefined') ? '8888' : port;
8 return 'http://127.0.0.1:' + port;
8 return 'http://127.0.0.1:' + port;
9 };
9 };
10
10
11 casper.open_new_notebook = function () {
11 casper.open_new_notebook = function () {
12 // Create and open a new notebook.
12 // Create and open a new notebook.
13 var baseUrl = this.get_notebook_server();
13 var baseUrl = this.get_notebook_server();
14 this.start(baseUrl);
14 this.start(baseUrl);
15 this.waitFor(this.page_loaded);
15 this.waitFor(this.page_loaded);
16 this.thenClick('button#new_notebook');
16 this.thenClick('button#new_notebook');
17 this.waitForPopup('');
17 this.waitForPopup('');
18
18
19 this.withPopup('', function () {this.waitForSelector('.CodeMirror-code');});
19 this.withPopup('', function () {this.waitForSelector('.CodeMirror-code');});
20 this.then(function () {
20 this.then(function () {
21 this.open(this.popups[0].url);
21 this.open(this.popups[0].url);
22 });
22 });
23 this.waitFor(this.page_loaded);
23 this.waitFor(this.page_loaded);
24
24
25 // Make sure the kernel has started
25 // Make sure the kernel has started
26 this.waitFor(this.kernel_running);
26 this.waitFor(this.kernel_running);
27 // track the IPython busy/idle state
27 // track the IPython busy/idle state
28 this.thenEvaluate(function () {
28 this.thenEvaluate(function () {
29 require(['base/js/namespace', 'base/js/events'], function (IPython, events) {
29 require(['base/js/namespace', 'base/js/events'], function (IPython, events) {
30
30
31 events.on('status_idle.Kernel',function () {
31 events.on('status_idle.Kernel',function () {
32 IPython._status = 'idle';
32 IPython._status = 'idle';
33 });
33 });
34 events.on('status_busy.Kernel',function () {
34 events.on('status_busy.Kernel',function () {
35 IPython._status = 'busy';
35 IPython._status = 'busy';
36 });
36 });
37 });
37 });
38 });
38 });
39
39
40 // Because of the asynchronous nature of SlimerJS (Gecko), we need to make
40 // Because of the asynchronous nature of SlimerJS (Gecko), we need to make
41 // sure the notebook has actually been loaded into the IPython namespace
41 // sure the notebook has actually been loaded into the IPython namespace
42 // before running any tests.
42 // before running any tests.
43 this.waitFor(function() {
43 this.waitFor(function() {
44 return this.evaluate(function () {
44 return this.evaluate(function () {
45 return IPython.notebook;
45 return IPython.notebook;
46 });
46 });
47 });
47 });
48 };
48 };
49
49
50 casper.page_loaded = function() {
50 casper.page_loaded = function() {
51 // Return whether or not the kernel is running.
51 // Return whether or not the kernel is running.
52 return this.evaluate(function() {
52 return this.evaluate(function() {
53 return typeof IPython !== "undefined" &&
53 return typeof IPython !== "undefined" &&
54 IPython.page !== undefined;
54 IPython.page !== undefined;
55 });
55 });
56 };
56 };
57
57
58 casper.kernel_running = function() {
58 casper.kernel_running = function() {
59 // Return whether or not the kernel is running.
59 // Return whether or not the kernel is running.
60 return this.evaluate(function() {
60 return this.evaluate(function() {
61 return IPython.notebook.kernel.running;
61 return IPython.notebook.kernel.running;
62 });
62 });
63 };
63 };
64
64
65 casper.shutdown_current_kernel = function () {
65 casper.shutdown_current_kernel = function () {
66 // Shut down the current notebook's kernel.
66 // Shut down the current notebook's kernel.
67 this.thenEvaluate(function() {
67 this.thenEvaluate(function() {
68 IPython.notebook.session.delete();
68 IPython.notebook.session.delete();
69 });
69 });
70 // We close the page right after this so we need to give it time to complete.
70 // We close the page right after this so we need to give it time to complete.
71 this.wait(1000);
71 this.wait(1000);
72 };
72 };
73
73
74 casper.delete_current_notebook = function () {
74 casper.delete_current_notebook = function () {
75 // Delete created notebook.
75 // Delete created notebook.
76
76
77 // For some unknown reason, this doesn't work?!?
77 // For some unknown reason, this doesn't work?!?
78 this.thenEvaluate(function() {
78 this.thenEvaluate(function() {
79 IPython.notebook.delete();
79 IPython.notebook.delete();
80 });
80 });
81 };
81 };
82
82
83 casper.wait_for_busy = function () {
83 casper.wait_for_busy = function () {
84 // Waits for the notebook to enter a busy state.
84 // Waits for the notebook to enter a busy state.
85 this.waitFor(function () {
85 this.waitFor(function () {
86 return this.evaluate(function () {
86 return this.evaluate(function () {
87 return IPython._status == 'busy';
87 return IPython._status == 'busy';
88 });
88 });
89 });
89 });
90 };
90 };
91
91
92 casper.wait_for_idle = function () {
92 casper.wait_for_idle = function () {
93 // Waits for the notebook to idle.
93 // Waits for the notebook to idle.
94 this.waitFor(function () {
94 this.waitFor(function () {
95 return this.evaluate(function () {
95 return this.evaluate(function () {
96 return IPython._status == 'idle';
96 return IPython._status == 'idle';
97 });
97 });
98 });
98 });
99 };
99 };
100
100
101 casper.wait_for_output = function (cell_num, out_num) {
101 casper.wait_for_output = function (cell_num, out_num) {
102 // wait for the nth output in a given cell
102 // wait for the nth output in a given cell
103 this.wait_for_idle();
103 this.wait_for_idle();
104 out_num = out_num || 0;
104 out_num = out_num || 0;
105 this.then(function() {
105 this.then(function() {
106 this.waitFor(function (c, o) {
106 this.waitFor(function (c, o) {
107 return this.evaluate(function get_output(c, o) {
107 return this.evaluate(function get_output(c, o) {
108 var cell = IPython.notebook.get_cell(c);
108 var cell = IPython.notebook.get_cell(c);
109 return cell.output_area.outputs.length > o;
109 return cell.output_area.outputs.length > o;
110 },
110 },
111 // pass parameter from the test suite js to the browser code js
111 // pass parameter from the test suite js to the browser code js
112 {c : cell_num, o : out_num});
112 {c : cell_num, o : out_num});
113 });
113 });
114 },
114 },
115 function then() { },
115 function then() { },
116 function timeout() {
116 function timeout() {
117 this.echo("wait_for_output timed out!");
117 this.echo("wait_for_output timed out!");
118 });
118 });
119 };
119 };
120
120
121 casper.wait_for_widget = function (widget_info) {
121 casper.wait_for_widget = function (widget_info) {
122 // wait for a widget msg que to reach 0
122 // wait for a widget msg que to reach 0
123 //
123 //
124 // Parameters
124 // Parameters
125 // ----------
125 // ----------
126 // widget_info : object
126 // widget_info : object
127 // Object which contains info related to the widget. The model_id property
127 // Object which contains info related to the widget. The model_id property
128 // is used to identify the widget.
128 // is used to identify the widget.
129 this.waitFor(function () {
129 this.waitFor(function () {
130 var pending = this.evaluate(function (m) {
130 var pending = this.evaluate(function (m) {
131 return IPython.notebook.kernel.widget_manager.get_model(m).pending_msgs;
131 return IPython.notebook.kernel.widget_manager.get_model(m).pending_msgs;
132 }, {m: widget_info.model_id});
132 }, {m: widget_info.model_id});
133
133
134 if (pending === 0) {
134 if (pending === 0) {
135 return true;
135 return true;
136 } else {
136 } else {
137 return false;
137 return false;
138 }
138 }
139 });
139 });
140 };
140 };
141
141
142 casper.get_output_cell = function (cell_num, out_num) {
142 casper.get_output_cell = function (cell_num, out_num) {
143 // return an output of a given cell
143 // return an output of a given cell
144 out_num = out_num || 0;
144 out_num = out_num || 0;
145 var result = casper.evaluate(function (c, o) {
145 var result = casper.evaluate(function (c, o) {
146 var cell = IPython.notebook.get_cell(c);
146 var cell = IPython.notebook.get_cell(c);
147 return cell.output_area.outputs[o];
147 return cell.output_area.outputs[o];
148 },
148 },
149 {c : cell_num, o : out_num});
149 {c : cell_num, o : out_num});
150 if (!result) {
150 if (!result) {
151 var num_outputs = casper.evaluate(function (c) {
151 var num_outputs = casper.evaluate(function (c) {
152 var cell = IPython.notebook.get_cell(c);
152 var cell = IPython.notebook.get_cell(c);
153 return cell.output_area.outputs.length;
153 return cell.output_area.outputs.length;
154 },
154 },
155 {c : cell_num});
155 {c : cell_num});
156 this.test.assertTrue(false,
156 this.test.assertTrue(false,
157 "Cell " + cell_num + " has no output #" + out_num + " (" + num_outputs + " total)"
157 "Cell " + cell_num + " has no output #" + out_num + " (" + num_outputs + " total)"
158 );
158 );
159 } else {
159 } else {
160 return result;
160 return result;
161 }
161 }
162 };
162 };
163
163
164 casper.get_cells_length = function () {
164 casper.get_cells_length = function () {
165 // return the number of cells in the notebook
165 // return the number of cells in the notebook
166 var result = casper.evaluate(function () {
166 var result = casper.evaluate(function () {
167 return IPython.notebook.get_cells().length;
167 return IPython.notebook.get_cells().length;
168 });
168 });
169 return result;
169 return result;
170 };
170 };
171
171
172 casper.set_cell_text = function(index, text){
172 casper.set_cell_text = function(index, text){
173 // Set the text content of a cell.
173 // Set the text content of a cell.
174 this.evaluate(function (index, text) {
174 this.evaluate(function (index, text) {
175 var cell = IPython.notebook.get_cell(index);
175 var cell = IPython.notebook.get_cell(index);
176 cell.set_text(text);
176 cell.set_text(text);
177 }, index, text);
177 }, index, text);
178 };
178 };
179
179
180 casper.get_cell_text = function(index){
180 casper.get_cell_text = function(index){
181 // Get the text content of a cell.
181 // Get the text content of a cell.
182 return this.evaluate(function (index) {
182 return this.evaluate(function (index) {
183 var cell = IPython.notebook.get_cell(index);
183 var cell = IPython.notebook.get_cell(index);
184 return cell.get_text();
184 return cell.get_text();
185 }, index);
185 }, index);
186 };
186 };
187
187
188 casper.insert_cell_at_bottom = function(cell_type){
188 casper.insert_cell_at_bottom = function(cell_type){
189 // Inserts a cell at the bottom of the notebook
189 // Inserts a cell at the bottom of the notebook
190 // Returns the new cell's index.
190 // Returns the new cell's index.
191 return this.evaluate(function (cell_type) {
191 return this.evaluate(function (cell_type) {
192 var cell = IPython.notebook.insert_cell_at_bottom(cell_type);
192 var cell = IPython.notebook.insert_cell_at_bottom(cell_type);
193 return IPython.notebook.find_cell_index(cell);
193 return IPython.notebook.find_cell_index(cell);
194 }, cell_type);
194 }, cell_type);
195 };
195 };
196
196
197 casper.append_cell = function(text, cell_type) {
197 casper.append_cell = function(text, cell_type) {
198 // Insert a cell at the bottom of the notebook and set the cells text.
198 // Insert a cell at the bottom of the notebook and set the cells text.
199 // Returns the new cell's index.
199 // Returns the new cell's index.
200 var index = this.insert_cell_at_bottom(cell_type);
200 var index = this.insert_cell_at_bottom(cell_type);
201 if (text !== undefined) {
201 if (text !== undefined) {
202 this.set_cell_text(index, text);
202 this.set_cell_text(index, text);
203 }
203 }
204 return index;
204 return index;
205 };
205 };
206
206
207 casper.execute_cell = function(index){
207 casper.execute_cell = function(index, expect_failure){
208 // Asynchronously executes a cell by index.
208 // Asynchronously executes a cell by index.
209 // Returns the cell's index.
209 // Returns the cell's index.
210
211 if (expect_failure === undefined) expect_failure = false;
210 var that = this;
212 var that = this;
211 this.then(function(){
213 this.then(function(){
212 that.evaluate(function (index) {
214 that.evaluate(function (index) {
213 var cell = IPython.notebook.get_cell(index);
215 var cell = IPython.notebook.get_cell(index);
214 cell.execute();
216 cell.execute();
215 }, index);
217 }, index);
216 });
218 });
219 this.wait_for_idle();
220
221 this.then(function () {
222 var error = that.evaluate(function (index) {
223 var cell = IPython.notebook.get_cell(index);
224 var outputs = cell.output_area.outputs;
225 for (var i = 0; i < outputs.length; i++) {
226 if (outputs[i].output_type == 'error') {
227 return outputs[i];
228 }
229 }
230 return false;
231 }, index);
232 if (error === null) {
233 this.test.fail("Failed to check for error output");
234 }
235 if (expect_failure && error === false) {
236 this.test.fail("Expected error while running cell");
237 } else if (!expect_failure && error !== false) {
238 this.test.fail("Error running cell:\n" + error.traceback.join('\n'));
239 }
240 });
217 return index;
241 return index;
218 };
242 };
219
243
220 casper.execute_cell_then = function(index, then_callback) {
244 casper.execute_cell_then = function(index, then_callback, expect_failure) {
221 // Synchronously executes a cell by index.
245 // Synchronously executes a cell by index.
222 // Optionally accepts a then_callback parameter. then_callback will get called
246 // Optionally accepts a then_callback parameter. then_callback will get called
223 // when the cell has finished executing.
247 // when the cell has finished executing.
224 // Returns the cell's index.
248 // Returns the cell's index.
225 var return_val = this.execute_cell(index);
249 var return_val = this.execute_cell(index, expect_failure);
226
250
227 this.wait_for_idle();
251 this.wait_for_idle();
228
252
229 var that = this;
253 var that = this;
230 this.then(function(){
254 this.then(function(){
231 if (then_callback!==undefined) {
255 if (then_callback!==undefined) {
232 then_callback.apply(that, [index]);
256 then_callback.apply(that, [index]);
233 }
257 }
234 });
258 });
235
259
236 return return_val;
260 return return_val;
237 };
261 };
238
262
239 casper.cell_element_exists = function(index, selector){
263 casper.cell_element_exists = function(index, selector){
240 // Utility function that allows us to easily check if an element exists
264 // Utility function that allows us to easily check if an element exists
241 // within a cell. Uses JQuery selector to look for the element.
265 // within a cell. Uses JQuery selector to look for the element.
242 return casper.evaluate(function (index, selector) {
266 return casper.evaluate(function (index, selector) {
243 var $cell = IPython.notebook.get_cell(index).element;
267 var $cell = IPython.notebook.get_cell(index).element;
244 return $cell.find(selector).length > 0;
268 return $cell.find(selector).length > 0;
245 }, index, selector);
269 }, index, selector);
246 };
270 };
247
271
248 casper.cell_element_function = function(index, selector, function_name, function_args){
272 casper.cell_element_function = function(index, selector, function_name, function_args){
249 // Utility function that allows us to execute a jQuery function on an
273 // Utility function that allows us to execute a jQuery function on an
250 // element within a cell.
274 // element within a cell.
251 return casper.evaluate(function (index, selector, function_name, function_args) {
275 return casper.evaluate(function (index, selector, function_name, function_args) {
252 var $cell = IPython.notebook.get_cell(index).element;
276 var $cell = IPython.notebook.get_cell(index).element;
253 var $el = $cell.find(selector);
277 var $el = $cell.find(selector);
254 return $el[function_name].apply($el, function_args);
278 return $el[function_name].apply($el, function_args);
255 }, index, selector, function_name, function_args);
279 }, index, selector, function_name, function_args);
256 };
280 };
257
281
258 casper.validate_notebook_state = function(message, mode, cell_index) {
282 casper.validate_notebook_state = function(message, mode, cell_index) {
259 // Validate the entire dual mode state of the notebook. Make sure no more than
283 // Validate the entire dual mode state of the notebook. Make sure no more than
260 // one cell is selected, focused, in edit mode, etc...
284 // one cell is selected, focused, in edit mode, etc...
261
285
262 // General tests.
286 // General tests.
263 this.test.assertEquals(this.get_keyboard_mode(), this.get_notebook_mode(),
287 this.test.assertEquals(this.get_keyboard_mode(), this.get_notebook_mode(),
264 message + '; keyboard and notebook modes match');
288 message + '; keyboard and notebook modes match');
265 // Is the selected cell the only cell that is selected?
289 // Is the selected cell the only cell that is selected?
266 if (cell_index!==undefined) {
290 if (cell_index!==undefined) {
267 this.test.assert(this.is_only_cell_selected(cell_index),
291 this.test.assert(this.is_only_cell_selected(cell_index),
268 message + '; cell ' + cell_index + ' is the only cell selected');
292 message + '; cell ' + cell_index + ' is the only cell selected');
269 }
293 }
270
294
271 // Mode specific tests.
295 // Mode specific tests.
272 if (mode==='command') {
296 if (mode==='command') {
273 // Are the notebook and keyboard manager in command mode?
297 // Are the notebook and keyboard manager in command mode?
274 this.test.assertEquals(this.get_keyboard_mode(), 'command',
298 this.test.assertEquals(this.get_keyboard_mode(), 'command',
275 message + '; in command mode');
299 message + '; in command mode');
276 // Make sure there isn't a single cell in edit mode.
300 // Make sure there isn't a single cell in edit mode.
277 this.test.assert(this.is_only_cell_edit(null),
301 this.test.assert(this.is_only_cell_edit(null),
278 message + '; all cells in command mode');
302 message + '; all cells in command mode');
279 this.test.assert(this.is_cell_editor_focused(null),
303 this.test.assert(this.is_cell_editor_focused(null),
280 message + '; no cell editors are focused while in command mode');
304 message + '; no cell editors are focused while in command mode');
281
305
282 } else if (mode==='edit') {
306 } else if (mode==='edit') {
283 // Are the notebook and keyboard manager in edit mode?
307 // Are the notebook and keyboard manager in edit mode?
284 this.test.assertEquals(this.get_keyboard_mode(), 'edit',
308 this.test.assertEquals(this.get_keyboard_mode(), 'edit',
285 message + '; in edit mode');
309 message + '; in edit mode');
286 if (cell_index!==undefined) {
310 if (cell_index!==undefined) {
287 // Is the specified cell the only cell in edit mode?
311 // Is the specified cell the only cell in edit mode?
288 this.test.assert(this.is_only_cell_edit(cell_index),
312 this.test.assert(this.is_only_cell_edit(cell_index),
289 message + '; cell ' + cell_index + ' is the only cell in edit mode');
313 message + '; cell ' + cell_index + ' is the only cell in edit mode');
290 // Is the specified cell the only cell with a focused code mirror?
314 // Is the specified cell the only cell with a focused code mirror?
291 this.test.assert(this.is_cell_editor_focused(cell_index),
315 this.test.assert(this.is_cell_editor_focused(cell_index),
292 message + '; cell ' + cell_index + '\'s editor is appropriately focused');
316 message + '; cell ' + cell_index + '\'s editor is appropriately focused');
293 }
317 }
294
318
295 } else {
319 } else {
296 this.test.assert(false, message + '; ' + mode + ' is an unknown mode');
320 this.test.assert(false, message + '; ' + mode + ' is an unknown mode');
297 }
321 }
298 };
322 };
299
323
300 casper.select_cell = function(index) {
324 casper.select_cell = function(index) {
301 // Select a cell in the notebook.
325 // Select a cell in the notebook.
302 this.evaluate(function (i) {
326 this.evaluate(function (i) {
303 IPython.notebook.select(i);
327 IPython.notebook.select(i);
304 }, {i: index});
328 }, {i: index});
305 };
329 };
306
330
307 casper.click_cell_editor = function(index) {
331 casper.click_cell_editor = function(index) {
308 // Emulate a click on a cell's editor.
332 // Emulate a click on a cell's editor.
309
333
310 // Code Mirror does not play nicely with emulated brower events.
334 // Code Mirror does not play nicely with emulated brower events.
311 // Instead of trying to emulate a click, here we run code similar to
335 // Instead of trying to emulate a click, here we run code similar to
312 // the code used in Code Mirror that handles the mousedown event on a
336 // the code used in Code Mirror that handles the mousedown event on a
313 // region of codemirror that the user can focus.
337 // region of codemirror that the user can focus.
314 this.evaluate(function (i) {
338 this.evaluate(function (i) {
315 var cm = IPython.notebook.get_cell(i).code_mirror;
339 var cm = IPython.notebook.get_cell(i).code_mirror;
316 if (cm.options.readOnly != "nocursor" && (document.activeElement != cm.display.input))
340 if (cm.options.readOnly != "nocursor" && (document.activeElement != cm.display.input))
317 cm.display.input.focus();
341 cm.display.input.focus();
318 }, {i: index});
342 }, {i: index});
319 };
343 };
320
344
321 casper.set_cell_editor_cursor = function(index, line_index, char_index) {
345 casper.set_cell_editor_cursor = function(index, line_index, char_index) {
322 // Set the Code Mirror instance cursor's location.
346 // Set the Code Mirror instance cursor's location.
323 this.evaluate(function (i, l, c) {
347 this.evaluate(function (i, l, c) {
324 IPython.notebook.get_cell(i).code_mirror.setCursor(l, c);
348 IPython.notebook.get_cell(i).code_mirror.setCursor(l, c);
325 }, {i: index, l: line_index, c: char_index});
349 }, {i: index, l: line_index, c: char_index});
326 };
350 };
327
351
328 casper.focus_notebook = function() {
352 casper.focus_notebook = function() {
329 // Focus the notebook div.
353 // Focus the notebook div.
330 this.evaluate(function (){
354 this.evaluate(function (){
331 $('#notebook').focus();
355 $('#notebook').focus();
332 }, {});
356 }, {});
333 };
357 };
334
358
335 casper.trigger_keydown = function() {
359 casper.trigger_keydown = function() {
336 // Emulate a keydown in the notebook.
360 // Emulate a keydown in the notebook.
337 for (var i = 0; i < arguments.length; i++) {
361 for (var i = 0; i < arguments.length; i++) {
338 this.evaluate(function (k) {
362 this.evaluate(function (k) {
339 var element = $(document);
363 var element = $(document);
340 var event = IPython.keyboard.shortcut_to_event(k, 'keydown');
364 var event = IPython.keyboard.shortcut_to_event(k, 'keydown');
341 element.trigger(event);
365 element.trigger(event);
342 }, {k: arguments[i]});
366 }, {k: arguments[i]});
343 }
367 }
344 };
368 };
345
369
346 casper.get_keyboard_mode = function() {
370 casper.get_keyboard_mode = function() {
347 // Get the mode of the keyboard manager.
371 // Get the mode of the keyboard manager.
348 return this.evaluate(function() {
372 return this.evaluate(function() {
349 return IPython.keyboard_manager.mode;
373 return IPython.keyboard_manager.mode;
350 }, {});
374 }, {});
351 };
375 };
352
376
353 casper.get_notebook_mode = function() {
377 casper.get_notebook_mode = function() {
354 // Get the mode of the notebook.
378 // Get the mode of the notebook.
355 return this.evaluate(function() {
379 return this.evaluate(function() {
356 return IPython.notebook.mode;
380 return IPython.notebook.mode;
357 }, {});
381 }, {});
358 };
382 };
359
383
360 casper.get_cell = function(index) {
384 casper.get_cell = function(index) {
361 // Get a single cell.
385 // Get a single cell.
362 //
386 //
363 // Note: Handles to DOM elements stored in the cell will be useless once in
387 // Note: Handles to DOM elements stored in the cell will be useless once in
364 // CasperJS context.
388 // CasperJS context.
365 return this.evaluate(function(i) {
389 return this.evaluate(function(i) {
366 var cell = IPython.notebook.get_cell(i);
390 var cell = IPython.notebook.get_cell(i);
367 if (cell) {
391 if (cell) {
368 return cell;
392 return cell;
369 }
393 }
370 return null;
394 return null;
371 }, {i : index});
395 }, {i : index});
372 };
396 };
373
397
374 casper.is_cell_editor_focused = function(index) {
398 casper.is_cell_editor_focused = function(index) {
375 // Make sure a cell's editor is the only editor focused on the page.
399 // Make sure a cell's editor is the only editor focused on the page.
376 return this.evaluate(function(i) {
400 return this.evaluate(function(i) {
377 var focused_textarea = $('#notebook .CodeMirror-focused textarea');
401 var focused_textarea = $('#notebook .CodeMirror-focused textarea');
378 if (focused_textarea.length > 1) { throw 'More than one Code Mirror editor is focused at once!'; }
402 if (focused_textarea.length > 1) { throw 'More than one Code Mirror editor is focused at once!'; }
379 if (i === null) {
403 if (i === null) {
380 return focused_textarea.length === 0;
404 return focused_textarea.length === 0;
381 } else {
405 } else {
382 var cell = IPython.notebook.get_cell(i);
406 var cell = IPython.notebook.get_cell(i);
383 if (cell) {
407 if (cell) {
384 return cell.code_mirror.getInputField() == focused_textarea[0];
408 return cell.code_mirror.getInputField() == focused_textarea[0];
385 }
409 }
386 }
410 }
387 return false;
411 return false;
388 }, {i : index});
412 }, {i : index});
389 };
413 };
390
414
391 casper.is_only_cell_selected = function(index) {
415 casper.is_only_cell_selected = function(index) {
392 // Check if a cell is the only cell selected.
416 // Check if a cell is the only cell selected.
393 // Pass null as the index to check if no cells are selected.
417 // Pass null as the index to check if no cells are selected.
394 return this.is_only_cell_on(index, 'selected', 'unselected');
418 return this.is_only_cell_on(index, 'selected', 'unselected');
395 };
419 };
396
420
397 casper.is_only_cell_edit = function(index) {
421 casper.is_only_cell_edit = function(index) {
398 // Check if a cell is the only cell in edit mode.
422 // Check if a cell is the only cell in edit mode.
399 // Pass null as the index to check if all of the cells are in command mode.
423 // Pass null as the index to check if all of the cells are in command mode.
400 return this.is_only_cell_on(index, 'edit_mode', 'command_mode');
424 return this.is_only_cell_on(index, 'edit_mode', 'command_mode');
401 };
425 };
402
426
403 casper.is_only_cell_on = function(i, on_class, off_class) {
427 casper.is_only_cell_on = function(i, on_class, off_class) {
404 // Check if a cell is the only cell with the `on_class` DOM class applied to it.
428 // Check if a cell is the only cell with the `on_class` DOM class applied to it.
405 // All of the other cells are checked for the `off_class` DOM class.
429 // All of the other cells are checked for the `off_class` DOM class.
406 // Pass null as the index to check if all of the cells have the `off_class`.
430 // Pass null as the index to check if all of the cells have the `off_class`.
407 var cells_length = this.get_cells_length();
431 var cells_length = this.get_cells_length();
408 for (var j = 0; j < cells_length; j++) {
432 for (var j = 0; j < cells_length; j++) {
409 if (j === i) {
433 if (j === i) {
410 if (this.cell_has_class(j, off_class) || !this.cell_has_class(j, on_class)) {
434 if (this.cell_has_class(j, off_class) || !this.cell_has_class(j, on_class)) {
411 return false;
435 return false;
412 }
436 }
413 } else {
437 } else {
414 if (!this.cell_has_class(j, off_class) || this.cell_has_class(j, on_class)) {
438 if (!this.cell_has_class(j, off_class) || this.cell_has_class(j, on_class)) {
415 return false;
439 return false;
416 }
440 }
417 }
441 }
418 }
442 }
419 return true;
443 return true;
420 };
444 };
421
445
422 casper.cell_has_class = function(index, classes) {
446 casper.cell_has_class = function(index, classes) {
423 // Check if a cell has a class.
447 // Check if a cell has a class.
424 return this.evaluate(function(i, c) {
448 return this.evaluate(function(i, c) {
425 var cell = IPython.notebook.get_cell(i);
449 var cell = IPython.notebook.get_cell(i);
426 if (cell) {
450 if (cell) {
427 return cell.element.hasClass(c);
451 return cell.element.hasClass(c);
428 }
452 }
429 return false;
453 return false;
430 }, {i : index, c: classes});
454 }, {i : index, c: classes});
431 };
455 };
432
456
433 casper.is_cell_rendered = function (index) {
457 casper.is_cell_rendered = function (index) {
434 return this.evaluate(function(i) {
458 return this.evaluate(function(i) {
435 return !!IPython.notebook.get_cell(i).rendered;
459 return !!IPython.notebook.get_cell(i).rendered;
436 }, {i:index});
460 }, {i:index});
437 };
461 };
438
462
439 casper.assert_colors_equal = function (hex_color, local_color, msg) {
463 casper.assert_colors_equal = function (hex_color, local_color, msg) {
440 // Tests to see if two colors are equal.
464 // Tests to see if two colors are equal.
441 //
465 //
442 // Parameters
466 // Parameters
443 // hex_color: string
467 // hex_color: string
444 // Hexadecimal color code, with or without preceeding hash character.
468 // Hexadecimal color code, with or without preceeding hash character.
445 // local_color: string
469 // local_color: string
446 // Local color representation. Can either be hexadecimal (default for
470 // Local color representation. Can either be hexadecimal (default for
447 // phantom) or rgb (default for slimer).
471 // phantom) or rgb (default for slimer).
448
472
449 // Remove parentheses, hashes, semi-colons, and space characters.
473 // Remove parentheses, hashes, semi-colons, and space characters.
450 hex_color = hex_color.replace(/[\(\); #]/, '');
474 hex_color = hex_color.replace(/[\(\); #]/, '');
451 local_color = local_color.replace(/[\(\); #]/, '');
475 local_color = local_color.replace(/[\(\); #]/, '');
452
476
453 // If the local color is rgb, clean it up and replace
477 // If the local color is rgb, clean it up and replace
454 if (local_color.substr(0,3).toLowerCase() == 'rgb') {
478 if (local_color.substr(0,3).toLowerCase() == 'rgb') {
455 components = local_color.substr(3).split(',');
479 components = local_color.substr(3).split(',');
456 local_color = '';
480 local_color = '';
457 for (var i = 0; i < components.length; i++) {
481 for (var i = 0; i < components.length; i++) {
458 var part = parseInt(components[i]).toString(16);
482 var part = parseInt(components[i]).toString(16);
459 while (part.length < 2) part = '0' + part;
483 while (part.length < 2) part = '0' + part;
460 local_color += part;
484 local_color += part;
461 }
485 }
462 }
486 }
463
487
464 this.test.assertEquals(hex_color.toUpperCase(), local_color.toUpperCase(), msg);
488 this.test.assertEquals(hex_color.toUpperCase(), local_color.toUpperCase(), msg);
465 };
489 };
466
490
467 casper.notebook_test = function(test) {
491 casper.notebook_test = function(test) {
468 // Wrap a notebook test to reduce boilerplate.
492 // Wrap a notebook test to reduce boilerplate.
469 this.open_new_notebook();
493 this.open_new_notebook();
470
494
471 // Echo whether or not we are running this test using SlimerJS
495 // Echo whether or not we are running this test using SlimerJS
472 if (this.evaluate(function(){
496 if (this.evaluate(function(){
473 return typeof InstallTrigger !== 'undefined'; // Firefox 1.0+
497 return typeof InstallTrigger !== 'undefined'; // Firefox 1.0+
474 })) {
498 })) {
475 console.log('This test is running in SlimerJS.');
499 console.log('This test is running in SlimerJS.');
476 this.slimerjs = true;
500 this.slimerjs = true;
477 }
501 }
478
502
479 // Make sure to remove the onbeforeunload callback. This callback is
503 // Make sure to remove the onbeforeunload callback. This callback is
480 // responsible for the "Are you sure you want to quit?" type messages.
504 // responsible for the "Are you sure you want to quit?" type messages.
481 // PhantomJS ignores these prompts, SlimerJS does not which causes hangs.
505 // PhantomJS ignores these prompts, SlimerJS does not which causes hangs.
482 this.then(function(){
506 this.then(function(){
483 this.evaluate(function(){
507 this.evaluate(function(){
484 window.onbeforeunload = function(){};
508 window.onbeforeunload = function(){};
485 });
509 });
486 });
510 });
487
511
488 this.then(test);
512 this.then(test);
489
513
490 // Kill the kernel and delete the notebook.
514 // Kill the kernel and delete the notebook.
491 this.shutdown_current_kernel();
515 this.shutdown_current_kernel();
492 // This is still broken but shouldn't be a problem for now.
516 // This is still broken but shouldn't be a problem for now.
493 // this.delete_current_notebook();
517 // this.delete_current_notebook();
494
518
495 // This is required to clean up the page we just finished with. If we don't call this
519 // This is required to clean up the page we just finished with. If we don't call this
496 // casperjs will leak file descriptors of all the open WebSockets in that page. We
520 // casperjs will leak file descriptors of all the open WebSockets in that page. We
497 // have to set this.page=null so that next time casper.start runs, it will create a
521 // have to set this.page=null so that next time casper.start runs, it will create a
498 // new page from scratch.
522 // new page from scratch.
499 this.then(function () {
523 this.then(function () {
500 this.page.close();
524 this.page.close();
501 this.page = null;
525 this.page = null;
502 });
526 });
503
527
504 // Run the browser automation.
528 // Run the browser automation.
505 this.run(function() {
529 this.run(function() {
506 this.test.done();
530 this.test.done();
507 });
531 });
508 };
532 };
509
533
510 casper.wait_for_dashboard = function () {
534 casper.wait_for_dashboard = function () {
511 // Wait for the dashboard list to load.
535 // Wait for the dashboard list to load.
512 casper.waitForSelector('.list_item');
536 casper.waitForSelector('.list_item');
513 };
537 };
514
538
515 casper.open_dashboard = function () {
539 casper.open_dashboard = function () {
516 // Start casper by opening the dashboard page.
540 // Start casper by opening the dashboard page.
517 var baseUrl = this.get_notebook_server();
541 var baseUrl = this.get_notebook_server();
518 this.start(baseUrl);
542 this.start(baseUrl);
519 this.waitFor(this.page_loaded);
543 this.waitFor(this.page_loaded);
520 this.wait_for_dashboard();
544 this.wait_for_dashboard();
521 };
545 };
522
546
523 casper.dashboard_test = function (test) {
547 casper.dashboard_test = function (test) {
524 // Open the dashboard page and run a test.
548 // Open the dashboard page and run a test.
525 this.open_dashboard();
549 this.open_dashboard();
526 this.then(test);
550 this.then(test);
527
551
528 this.then(function () {
552 this.then(function () {
529 this.page.close();
553 this.page.close();
530 this.page = null;
554 this.page = null;
531 });
555 });
532
556
533 // Run the browser automation.
557 // Run the browser automation.
534 this.run(function() {
558 this.run(function() {
535 this.test.done();
559 this.test.done();
536 });
560 });
537 };
561 };
538
562
539 casper.options.waitTimeout=10000;
563 casper.options.waitTimeout=10000;
540 casper.on('waitFor.timeout', function onWaitForTimeout(timeout) {
564 casper.on('waitFor.timeout', function onWaitForTimeout(timeout) {
541 this.echo("Timeout for " + casper.get_notebook_server());
565 this.echo("Timeout for " + casper.get_notebook_server());
542 this.echo("Is the notebook server running?");
566 this.echo("Is the notebook server running?");
543 });
567 });
544
568
545 casper.print_log = function () {
569 casper.print_log = function () {
546 // Pass `console.log` calls from page JS to casper.
570 // Pass `console.log` calls from page JS to casper.
547 this.on('remote.message', function(msg) {
571 this.on('remote.message', function(msg) {
548 this.echo('Remote message caught: ' + msg);
572 this.echo('Remote message caught: ' + msg);
549 });
573 });
550 };
574 };
551
575
552 casper.on("page.error", function onError(msg, trace) {
576 casper.on("page.error", function onError(msg, trace) {
553 // show errors in the browser
577 // show errors in the browser
554 this.echo("Page Error!");
578 this.echo("Page Error!");
555 for (var i = 0; i < trace.length; i++) {
579 for (var i = 0; i < trace.length; i++) {
556 var frame = trace[i];
580 var frame = trace[i];
557 var file = frame.file;
581 var file = frame.file;
558 // shorten common phantomjs evaluate url
582 // shorten common phantomjs evaluate url
559 // this will have a different value on slimerjs
583 // this will have a different value on slimerjs
560 if (file === "phantomjs://webpage.evaluate()") {
584 if (file === "phantomjs://webpage.evaluate()") {
561 file = "evaluate";
585 file = "evaluate";
562 }
586 }
563 this.echo("line " + frame.line + " of " + file);
587 this.echo("line " + frame.line + " of " + file);
564 if (frame.function.length > 0) {
588 if (frame.function.length > 0) {
565 this.echo("in " + frame.function);
589 this.echo("in " + frame.function);
566 }
590 }
567 }
591 }
568 this.echo(msg);
592 this.echo(msg);
569 });
593 });
570
594
571
595
572 casper.capture_log = function () {
596 casper.capture_log = function () {
573 // show captured errors
597 // show captured errors
574 var captured_log = [];
598 var captured_log = [];
575 var seen_errors = 0;
599 var seen_errors = 0;
576 this.on('remote.message', function(msg) {
600 this.on('remote.message', function(msg) {
577 captured_log.push(msg);
601 captured_log.push(msg);
578 });
602 });
579
603
580 this.test.on("test.done", function (result) {
604 this.test.on("test.done", function (result) {
581 // test.done runs per-file,
605 // test.done runs per-file,
582 // but suiteResults is per-suite (directory)
606 // but suiteResults is per-suite (directory)
583 var current_errors;
607 var current_errors;
584 if (this.suiteResults) {
608 if (this.suiteResults) {
585 // casper 1.1 has suiteResults
609 // casper 1.1 has suiteResults
586 current_errors = this.suiteResults.countErrors() + this.suiteResults.countFailed();
610 current_errors = this.suiteResults.countErrors() + this.suiteResults.countFailed();
587 } else {
611 } else {
588 // casper 1.0 has testResults instead
612 // casper 1.0 has testResults instead
589 current_errors = this.testResults.failed;
613 current_errors = this.testResults.failed;
590 }
614 }
591
615
592 if (current_errors > seen_errors && captured_log.length > 0) {
616 if (current_errors > seen_errors && captured_log.length > 0) {
593 casper.echo("\nCaptured console.log:");
617 casper.echo("\nCaptured console.log:");
594 for (var i = 0; i < captured_log.length; i++) {
618 for (var i = 0; i < captured_log.length; i++) {
595 casper.echo(" " + captured_log[i]);
619 casper.echo(" " + captured_log[i]);
596 }
620 }
597 }
621 }
598 seen_errors = current_errors;
622 seen_errors = current_errors;
599 captured_log = [];
623 captured_log = [];
600 });
624 });
601 };
625 };
602
626
603 casper.capture_log();
627 casper.capture_log();
General Comments 0
You need to be logged in to leave comments. Login now