Skip to content

Commit

Permalink
Merge pull request ipython#4285 from ivanov/notebook-casperjs-tests
Browse files Browse the repository at this point in the history
Notebook javascript test suite using CasperJS
  • Loading branch information
takluyver committed Oct 23, 2013
2 parents a596b29 + e351d65 commit f0d8fa4
Show file tree
Hide file tree
Showing 16 changed files with 540 additions and 36 deletions.
7 changes: 6 additions & 1 deletion .travis.yml
Expand Up @@ -4,9 +4,14 @@ python:
- 2.7
- 3.3
before_install:
# workaround for https://github.com/travis-ci/travis-cookbooks/issues/155
- sudo rm -rf /dev/shm && sudo ln -s /run/shm /dev/shm
- easy_install -q pyzmq
- pip install jinja2 sphinx pygments tornado requests
- sudo apt-get install pandoc
# Pierre Carrier's PPA for PhantomJS and CasperJS
- sudo add-apt-repository -y ppa:pcarrier/ppa
- sudo apt-get update
- sudo apt-get install pandoc casperjs
install:
- python setup.py install -q
script:
Expand Down
5 changes: 3 additions & 2 deletions IPython/html/notebookapp.py
Expand Up @@ -711,8 +711,9 @@ def cleanup_kernels(self):

def notebook_info(self):
"Return the current working directory and the server url information"
mgr_info = self.notebook_manager.info_string() + "\n"
return mgr_info +"The IPython Notebook is running at: %s" % self._url
info = self.notebook_manager.info_string() + "\n"
info += "%d active kernels \n" % len(self.kernel_manager._kernels)
return info + "The IPython Notebook is running at: %s" % self._url

def start(self):
""" Start the IPython Notebook server app, after initialization
Expand Down
31 changes: 31 additions & 0 deletions IPython/html/static/base/js/utils.js
Expand Up @@ -350,11 +350,36 @@ IPython.utils = (function (IPython) {
DOWN_ARROW: 40,
DOWNARROW: 40,
DOWN : 40,
I : 73,
M : 77,
// all three of these keys may be COMMAND on OS X:
LEFT_SUPER : 91,
RIGHT_SUPER : 92,
COMMAND : 93,
};

// trigger a key press event
var press = function (key) {
var key_press = $.Event('keydown', {which: key});
$(document).trigger(key_press);
}

var press_up = function() { press(keycodes.UP); };
var press_down = function() { press(keycodes.DOWN); };

var press_ctrl_enter = function() {
$(document).trigger($.Event('keydown', {which: keycodes.ENTER, ctrlKey: true}));
};

var press_shift_enter = function() {
$(document).trigger($.Event('keydown', {which: keycodes.ENTER, shiftKey: true}));
};

// trigger the ctrl-m shortcut followed by one of our keys
var press_ghetto = function(key) {
$(document).trigger($.Event('keydown', {which: keycodes.M, ctrlKey: true}));
press(key);
};


var points_to_pixels = function (points) {
Expand Down Expand Up @@ -411,6 +436,12 @@ IPython.utils = (function (IPython) {
uuid : uuid,
fixConsole : fixConsole,
keycodes : keycodes,
press : press,
press_up : press_up,
press_down : press_down,
press_ctrl_enter : press_ctrl_enter,
press_shift_enter : press_shift_enter,
press_ghetto : press_ghetto,
fixCarriageReturn : fixCarriageReturn,
autoLinkUrls : autoLinkUrls,
points_to_pixels : points_to_pixels,
Expand Down
1 change: 1 addition & 0 deletions IPython/html/static/services/sessions/js/session.js
Expand Up @@ -75,6 +75,7 @@ var IPython = (function (IPython) {
type : "DELETE",
dataType : "json",
};
this.kernel.running = false;
var url = utils.url_path_join(this._baseProjectUrl, 'api/sessions', this.id);
$.ajax(url, settings);
};
Expand Down
23 changes: 23 additions & 0 deletions IPython/html/tests/casperjs/README.md
@@ -0,0 +1,23 @@
# IPython Notebook Javascript Tests

Regression tests for the web notebook. These tests depend on
[CasperJS](http://casperjs.org/), which in turn requires
a recent version of [PhantomJS](http://phantomjs.org/).

Run the tests using:

```
iptest js
```

For finer granularity, or to specify more options, you can also run the
following `casperjs` command

```sh
/path/to/bin/casperjs test --includes=util.js test_cases
```

The file `util.js` contains utility functions for tests, including a path to a
running notebook server on localhost (http://127.0.0.1) with the port number
specified as a command line argument to the test suite. Port 8888 is used if
`--port=` is not specified.
39 changes: 39 additions & 0 deletions IPython/html/tests/casperjs/test_cases/check_interrupt.js
@@ -0,0 +1,39 @@
//
// Test kernel interrupt
//
casper.notebook_test(function () {
this.evaluate(function () {
var cell = IPython.notebook.get_cell(0);
cell.set_text('import time\nfor x in range(3):\n time.sleep(1)');
cell.execute();
});


// interrupt using menu item (Kernel -> Interrupt)
this.thenClick('li#int_kernel');

this.wait_for_output(0);

this.then(function () {
var result = this.get_output_cell(0);
this.test.assertEquals(result.ename, 'KeyboardInterrupt', 'keyboard interrupt (mouseclick)');
});

// run cell 0 again, now interrupting using keyboard shortcut
this.thenEvaluate(function () {
cell.clear_output();
cell.execute();
});

// interrupt using Ctrl-M I keyboard shortcut
this.thenEvaluate( function() {
IPython.utils.press_ghetto(IPython.utils.keycodes.I)
});

this.wait_for_output(0);

this.then(function () {
var result = this.get_output_cell(0);
this.test.assertEquals(result.ename, 'KeyboardInterrupt', 'keyboard interrupt (shortcut)');
});
});
21 changes: 21 additions & 0 deletions IPython/html/tests/casperjs/test_cases/empty_nb_arrow_keys.js
@@ -0,0 +1,21 @@
//
// Check for errors with up and down arrow presses in an empty notebook.
//
casper.notebook_test(function () {
var result = this.evaluate(function() {
var ncells = IPython.notebook.ncells();
var i;

// Delete all cells.
for (i = 0; i < ncells; i++) {
IPython.notebook.delete_cell();
}

// Simulate the "up arrow" and "down arrow" keys.
//
IPython.utils.press_up();
IPython.utils.press_down();
return true;
});
this.test.assertTrue(result, 'Up/down arrow okay in empty notebook.');
});
69 changes: 69 additions & 0 deletions IPython/html/tests/casperjs/test_cases/execute_code_cell.js
@@ -0,0 +1,69 @@
//
// Test code cell execution.
//
casper.notebook_test(function () {
this.evaluate(function () {
var cell = IPython.notebook.get_cell(0);
cell.set_text('a=10; print(a)');
cell.execute();
});

this.wait_for_output(0);

// refactor this into just a get_output(0)
this.then(function () {
var result = this.get_output_cell(0);
this.test.assertEquals(result.text, '10\n', 'cell execute (using js)');
});


// do it again with the keyboard shortcut
this.thenEvaluate(function () {
var cell = IPython.notebook.get_cell(0);
cell.set_text('a=11; print(a)');
cell.clear_output();
IPython.utils.press_ctrl_enter();
});

this.wait_for_output(0);

this.then(function () {
var result = this.get_output_cell(0);
var num_cells = this.get_cells_length();
this.test.assertEquals(result.text, '11\n', 'cell execute (using ctrl-enter)');
this.test.assertEquals(num_cells, 1, ' ^--- does not add a new cell')
});

// do it again with the keyboard shortcut
this.thenEvaluate(function () {
var cell = IPython.notebook.get_cell(0);
cell.set_text('a=12; print(a)');
cell.clear_output();
IPython.utils.press_shift_enter();
});

this.wait_for_output(0);

this.then(function () {
var result = this.get_output_cell(0);
var num_cells = this.get_cells_length();
this.test.assertEquals(result.text, '12\n', 'cell execute (using shift-enter)');
this.test.assertEquals(num_cells, 2, ' ^--- adds a new cell')
});

// press the "play" triangle button in the toolbar
this.thenEvaluate(function () {
var cell = IPython.notebook.get_cell(0);
IPython.notebook.select(0);
cell.clear_output();
cell.set_text('a=13; print(a)');
$('#run_b').click();
});

this.wait_for_output(0);

this.then(function () {
var result = this.get_output_cell(0);
this.test.assertEquals(result.text, '13\n', 'cell execute (using "play" toolbar button)')
});
});
37 changes: 37 additions & 0 deletions IPython/html/tests/casperjs/test_cases/merge_cells.js
@@ -0,0 +1,37 @@
//
// Test merging two notebook cells.
//
casper.notebook_test(function() {
var output = this.evaluate(function () {
// Fill in test data.
var set_cell_text = function () {
var cell_one = IPython.notebook.get_selected_cell();
cell_one.set_text('a = 5');

IPython.notebook.insert_cell_below('code');
var cell_two = IPython.notebook.get_selected_cell();
cell_two.set_text('print(a)');
};

// merge_cell_above()
set_cell_text();
IPython.notebook.merge_cell_above();
var merged_above = IPython.notebook.get_selected_cell();

// merge_cell_below()
set_cell_text();
IPython.notebook.select(0);
IPython.notebook.merge_cell_below();
var merged_below = IPython.notebook.get_selected_cell();

return {
above: merged_above.get_text(),
below: merged_below.get_text()
};
});

this.test.assertEquals(output.above, 'a = 5\nprint(a)',
'Successful insert_cell_above().');
this.test.assertEquals(output.below, 'a = 5\nprint(a)',
'Successful insert_cell_below().');
});
23 changes: 23 additions & 0 deletions IPython/html/tests/casperjs/test_cases/nb_arrow_keys.js
@@ -0,0 +1,23 @@
//
// Check for errors with up and down arrow presses in a non-empty notebook.
//
casper.notebook_test(function () {
var result = this.evaluate(function() {
pos0 = IPython.notebook.get_selected_index();
IPython.notebook.insert_cell_below('code');
pos1 = IPython.notebook.get_selected_index();
IPython.notebook.insert_cell_below('code');
pos2 = IPython.notebook.get_selected_index();
// Simulate the "up arrow" and "down arrow" keys.
IPython.utils.press_up();
pos3 = IPython.notebook.get_selected_index();
IPython.utils.press_down();
pos4 = IPython.notebook.get_selected_index();
return pos0 == 0 &&
pos1 == 1 &&
pos2 == 2 &&
pos3 == 1 &&
pos4 == 2;
});
this.test.assertTrue(result, 'Up/down arrow okay in non-empty notebook.');
});
36 changes: 36 additions & 0 deletions IPython/html/tests/casperjs/test_cases/render_markdown.js
@@ -0,0 +1,36 @@
//
// Test that a Markdown cell is rendered to HTML.
//
casper.notebook_test(function () {
// Test JavaScript models.
var output = this.evaluate(function () {
IPython.notebook.to_markdown();
var cell = IPython.notebook.get_selected_cell();
cell.set_text('# Foo');
cell.render();
return cell.get_rendered();
});
this.test.assertEquals(output, '<h1>Foo</h1>', 'Markdown JS API works.');

// Test menubar entries.
output = this.evaluate(function () {
$('#to_code').mouseenter().click();
$('#to_markdown').mouseenter().click();
var cell = IPython.notebook.get_selected_cell();
cell.set_text('# Foo');
$('#run_cell').mouseenter().click();
return cell.get_rendered();
});
this.test.assertEquals(output, '<h1>Foo</h1>', 'Markdown menubar items work.');

// Test toolbar buttons.
output = this.evaluate(function () {
$('#cell_type').val('code').change();
$('#cell_type').val('markdown').change();
var cell = IPython.notebook.get_selected_cell();
cell.set_text('# Foo');
$('#run_b').click();
return cell.get_rendered();
});
this.test.assertEquals(output, '<h1>Foo</h1>', 'Markdown toolbar items work.');
});
31 changes: 31 additions & 0 deletions IPython/html/tests/casperjs/test_cases/shutdown_notebook.js
@@ -0,0 +1,31 @@
//
// Test shutdown of a kernel.
//
casper.notebook_test(function () {
// XXX: test.begin allows named sections but requires casperjs 1.1.0-DEV.
// We will put it back into place when the next version of casper is
// released. Following that, all instances of this.test can be changed
// to just test.
//this.test.begin("shutdown tests (notebook)", 2, function(test) {

this.thenEvaluate(function () {
$('#kill_and_exit').click();
});

this.thenEvaluate(function () {
var cell = IPython.notebook.get_cell(0);
cell.set_text('a=10; print(a)');
cell.execute();
});

// refactor this into just a get_output(0)
this.then(function () {
var result = this.get_output_cell(0);
this.test.assertFalsy(result, "after shutdown: no execution results");
this.test.assertNot(this.kernel_running(),
'after shutdown: IPython.notebook.kernel.running is false ');
});

//}); // end of test.begin
});

0 comments on commit f0d8fa4

Please sign in to comment.