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