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