From 0f5f3a27f5c10d04d8514732ab32ebb9f67e20c5 Mon Sep 17 00:00:00 2001 From: Jonathan Frederic Date: Fri, 7 Mar 2014 14:10:17 -0800 Subject: [PATCH 01/38] Add dual mode JS tests --- IPython/html/tests/notebook/dualmode.js | 231 ++++++++++++++++++++++++ 1 file changed, 231 insertions(+) create mode 100644 IPython/html/tests/notebook/dualmode.js diff --git a/IPython/html/tests/notebook/dualmode.js b/IPython/html/tests/notebook/dualmode.js new file mode 100644 index 000000000..1c69c0a2c --- /dev/null +++ b/IPython/html/tests/notebook/dualmode.js @@ -0,0 +1,231 @@ +// Test the notebook dual mode feature. + +// Test +casper.notebook_test(function () { + var index = this.append_cell('print("a")'); + this.execute_cell_then(index); + index = this.append_cell('print("b")'); + this.execute_cell_then(index); + index = this.append_cell('print("c")'); + this.execute_cell_then(index); + + this.then(function () { + this.validate_state('initial state', 'edit', 0); + this.key_press('esc'); + this.validate_state('esc', 'command', 0); + this.key_press('down'); + this.validate_state('down', 'command', 1); + this.key_press('enter'); + this.validate_state('enter', 'edit', 1); + this.key_press('j'); + this.validate_state('j in edit mode', 'edit', 1); + this.key_press('esc'); + this.validate_state('esc', 'command', 1); + this.key_press('j'); + this.validate_state('j in command mode', 'command', 2); + this.click_cell(0); + this.validate_state('click cell 0', 'edit', 0); + this.click_cell(3); + this.validate_state('click cell 3', 'edit', 3); + this.key_press('esc'); + this.validate_state('esc', 'command', 3); + + // Open keyboard help + this.evaluate(function(){ + $('#keyboard_shortcuts a').click(); + }, {}); + + this.key_press('k'); + this.validate_state('k in command mode while keyboard help is up', 'command', 3); + + // Close keyboard help + this.evaluate(function(){ + $('div.modal button.close').click(); + }, {}); + + this.key_press('k'); + this.validate_state('k in command mode', 'command', 2); + this.click_cell(0); + this.validate_state('click cell 0', 'edit', 0); + this.focus_notebook(); + this.validate_state('focus #notebook', 'command', 0); + this.click_cell(0); + this.validate_state('click cell 0', 'edit', 0); + this.focus_notebook(); + this.validate_state('focus #notebook', 'command', 0); + this.click_cell(3); + this.validate_state('click cell 3', 'edit', 3); + this.key_press('shift+enter'); + this.validate_state('shift+enter (no cell below)', 'edit', 4); + this.click_cell(3); + this.validate_state('click cell 3', 'edit', 3); + this.key_press('shift+enter'); + this.validate_state('shift+enter (cell exists below)', 'command', 4); + this.click_cell(3); + this.validate_state('click cell 3', 'edit', 3); + this.key_press('alt+enter'); + this.validate_state('alt+enter', 'edit', 4); + this.key_press('ctrl+enter'); + this.validate_state('ctrl+enter', 'command', 4); + }); + + + // Utility functions. + this.validate_state = function(message, mode, cell_index) { + // General tests. + this.test.assertEquals(this._get_keyboard_mode(), this._get_notebook_mode(), + message + '; keyboard and notebook modes match'); + // Is codemirror focused appropriately? + this.test.assert(this.is_editor_focus_valid(), message + '; cell editor focused appropriately'); + // Is the selected cell the only cell that is selected? + if (cell_index!==undefined) { + this.test.assert(this.is_cell_selected(cell_index), + message + '; cell ' + cell_index + ' is the only cell selected'); + } + + // Mode specific tests. + if (mode==='command') { + // Are the notebook and keyboard manager in command mode? + this.test.assertEquals(this._get_keyboard_mode(), 'command', + message + '; in command mode'); + // Make sure there isn't a single cell in edit mode. + this.test.assert(this.is_cell_edit(null), + message + '; all cells in command mode'); + + } else if (mode==='edit') { + // Are the notebook and keyboard manager in edit mode? + this.test.assertEquals(this._get_keyboard_mode(), 'edit', + message + '; in edit mode'); + // Is the specified cell the only cell in edit mode? + if (cell_index!==undefined) { + this.test.assert(this.is_cell_edit(cell_index), + message + '; cell ' + cell_index + ' is the only cell in edit mode'); + } + + } else { + this.test.assert(false, message + '; ' + mode + ' is an unknown mode'); + } + }; + + this.is_editor_focus_valid = function() { + var cells = this._get_cells(); + for (var i = 0; i < cells.length; i++) { + if (!this.is_cell_editor_focus_valid(i)) { + return false; + } + } + return true; + }; + + this.is_cell_editor_focus_valid = function(i) { + var cell = this._get_cell(i); + if (cell) { + if (cell.mode == 'edit') { + return this._is_cell_editor_focused(i); + } else { + return !this._is_cell_editor_focused(i); + } + } + return true; + }; + + this.is_cell_selected = function(i) { + return this._is_cell_on(i, 'selected', 'unselected'); + }; + + this.is_cell_edit = function(i) { + return this._is_cell_on(i, 'edit_mode', 'command_mode'); + }; + + this.click_cell = function(index) { + // Code Mirror does not play nicely with emulated brower events. + // Instead of trying to emulate a click, here we run code similar to + // the code used in Code Mirror that handles the mousedown event on a + // region of codemirror that the user can focus. + this.evaluate(function (i) { + cm = IPython.notebook.get_cell(i).code_mirror; + if (cm.options.readOnly != "nocursor" && (document.activeElement != cm.display.input)) + cm.display.input.focus(); + }, {i: index}); + }; + + this.focus_notebook = function() { + this.evaluate(function (){ + $('#notebook').focus(); + }, {}); + }; + + this.key_press = function(key) { + this.evaluate(function (k) { + IPython.keyboard.trigger_keydown(k); + }, {k: key}); + }; + + this._is_cell_editor_focused = function(i) { + return this._is_cell_inputfield(i, '.CodeMirror-focused *'); + }; + + this._is_cell_on = function(i, on_class, off_class) { + var cells = this._get_cells(); + for (var j = 0; j < cells.length; j++) { + if (j === i) { + if (this._has_cell_class(j, off_class) || !this._has_cell_class(j, on_class)) { + return false; + } + } else { + if (!this._has_cell_class(j, off_class) || this._has_cell_class(j, on_class)) { + return false; + } + } + } + return true; + }; + + this._get_keyboard_mode = function() { + return this.evaluate(function() { + return IPython.keyboard_manager.mode; + }, {}); + }; + + this._get_notebook_mode = function() { + return this.evaluate(function() { + return IPython.notebook.mode; + }, {}); + }; + + this._get_cells = function() { + return this.evaluate(function() { + return IPython.notebook.get_cells(); + }, {}); + }; + + this._get_cell = function(index) { + return this.evaluate(function(i) { + var cell = IPython.notebook.get_cell(i); + if (cell) { + return cell; + } + return null; + }, {i : index}); + }; + + this._is_cell_inputfield = function(index, selector) { + return this.evaluate(function(i, s) { + var cell = IPython.notebook.get_cell(i); + if (cell) { + return $(cell.code_mirror.getInputField()).is(s); + } + return false; + }, {i : index, s: selector}); + }; + + this._has_cell_class = function(index, classes) { + return this.evaluate(function(i, c) { + var cell = IPython.notebook.get_cell(i); + if (cell) { + return cell.element.hasClass(c); + } + return false; + }, {i : index, c: classes}); + }; +}); From 45bbcc949edc7b651c97166b6377cbe93a82d53c Mon Sep 17 00:00:00 2001 From: Jonathan Frederic Date: Mon, 10 Mar 2014 12:27:05 -0700 Subject: [PATCH 02/38] s/key_press/trigger_keydown --- IPython/html/tests/notebook/dualmode.js | 28 ++++++++++++------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/IPython/html/tests/notebook/dualmode.js b/IPython/html/tests/notebook/dualmode.js index 1c69c0a2c..74b3b2dea 100644 --- a/IPython/html/tests/notebook/dualmode.js +++ b/IPython/html/tests/notebook/dualmode.js @@ -11,23 +11,23 @@ casper.notebook_test(function () { this.then(function () { this.validate_state('initial state', 'edit', 0); - this.key_press('esc'); + this.trigger_keydown('esc'); this.validate_state('esc', 'command', 0); - this.key_press('down'); + this.trigger_keydown('down'); this.validate_state('down', 'command', 1); - this.key_press('enter'); + this.trigger_keydown('enter'); this.validate_state('enter', 'edit', 1); - this.key_press('j'); + this.trigger_keydown('j'); this.validate_state('j in edit mode', 'edit', 1); - this.key_press('esc'); + this.trigger_keydown('esc'); this.validate_state('esc', 'command', 1); - this.key_press('j'); + this.trigger_keydown('j'); this.validate_state('j in command mode', 'command', 2); this.click_cell(0); this.validate_state('click cell 0', 'edit', 0); this.click_cell(3); this.validate_state('click cell 3', 'edit', 3); - this.key_press('esc'); + this.trigger_keydown('esc'); this.validate_state('esc', 'command', 3); // Open keyboard help @@ -35,7 +35,7 @@ casper.notebook_test(function () { $('#keyboard_shortcuts a').click(); }, {}); - this.key_press('k'); + this.trigger_keydown('k'); this.validate_state('k in command mode while keyboard help is up', 'command', 3); // Close keyboard help @@ -43,7 +43,7 @@ casper.notebook_test(function () { $('div.modal button.close').click(); }, {}); - this.key_press('k'); + this.trigger_keydown('k'); this.validate_state('k in command mode', 'command', 2); this.click_cell(0); this.validate_state('click cell 0', 'edit', 0); @@ -55,17 +55,17 @@ casper.notebook_test(function () { this.validate_state('focus #notebook', 'command', 0); this.click_cell(3); this.validate_state('click cell 3', 'edit', 3); - this.key_press('shift+enter'); + this.trigger_keydown('shift+enter'); this.validate_state('shift+enter (no cell below)', 'edit', 4); this.click_cell(3); this.validate_state('click cell 3', 'edit', 3); - this.key_press('shift+enter'); + this.trigger_keydown('shift+enter'); this.validate_state('shift+enter (cell exists below)', 'command', 4); this.click_cell(3); this.validate_state('click cell 3', 'edit', 3); - this.key_press('alt+enter'); + this.trigger_keydown('alt+enter'); this.validate_state('alt+enter', 'edit', 4); - this.key_press('ctrl+enter'); + this.trigger_keydown('ctrl+enter'); this.validate_state('ctrl+enter', 'command', 4); }); @@ -155,7 +155,7 @@ casper.notebook_test(function () { }, {}); }; - this.key_press = function(key) { + this.trigger_keydown = function(key) { this.evaluate(function (k) { IPython.keyboard.trigger_keydown(k); }, {k: key}); From 6a834223da8a4a22fe4612ac66eb9187a770df64 Mon Sep 17 00:00:00 2001 From: Jonathan Frederic Date: Mon, 10 Mar 2014 12:27:49 -0700 Subject: [PATCH 03/38] s/_is_cell_editor_focused/is_cell_editor_focused --- IPython/html/tests/notebook/dualmode.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/IPython/html/tests/notebook/dualmode.js b/IPython/html/tests/notebook/dualmode.js index 74b3b2dea..e82c9c2bf 100644 --- a/IPython/html/tests/notebook/dualmode.js +++ b/IPython/html/tests/notebook/dualmode.js @@ -121,9 +121,9 @@ casper.notebook_test(function () { var cell = this._get_cell(i); if (cell) { if (cell.mode == 'edit') { - return this._is_cell_editor_focused(i); + return this.is_cell_editor_focused(i); } else { - return !this._is_cell_editor_focused(i); + return !this.is_cell_editor_focused(i); } } return true; @@ -161,7 +161,7 @@ casper.notebook_test(function () { }, {k: key}); }; - this._is_cell_editor_focused = function(i) { + this.is_cell_editor_focused = function(i) { return this._is_cell_inputfield(i, '.CodeMirror-focused *'); }; From c43044d5142170e0bbf1e452aedd83dbb21f402e Mon Sep 17 00:00:00 2001 From: Jonathan Frederic Date: Mon, 10 Mar 2014 12:28:40 -0700 Subject: [PATCH 04/38] s/_is_cell_on/is_cell_on --- IPython/html/tests/notebook/dualmode.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/IPython/html/tests/notebook/dualmode.js b/IPython/html/tests/notebook/dualmode.js index e82c9c2bf..58e320fed 100644 --- a/IPython/html/tests/notebook/dualmode.js +++ b/IPython/html/tests/notebook/dualmode.js @@ -130,11 +130,11 @@ casper.notebook_test(function () { }; this.is_cell_selected = function(i) { - return this._is_cell_on(i, 'selected', 'unselected'); + return this.is_cell_on(i, 'selected', 'unselected'); }; this.is_cell_edit = function(i) { - return this._is_cell_on(i, 'edit_mode', 'command_mode'); + return this.is_cell_on(i, 'edit_mode', 'command_mode'); }; this.click_cell = function(index) { @@ -165,7 +165,7 @@ casper.notebook_test(function () { return this._is_cell_inputfield(i, '.CodeMirror-focused *'); }; - this._is_cell_on = function(i, on_class, off_class) { + this.is_cell_on = function(i, on_class, off_class) { var cells = this._get_cells(); for (var j = 0; j < cells.length; j++) { if (j === i) { From 86fef90a8ceb1952926de67d333fb80888db3aae Mon Sep 17 00:00:00 2001 From: Jonathan Frederic Date: Mon, 10 Mar 2014 12:31:20 -0700 Subject: [PATCH 05/38] Make a few more methods public, in preparation to move them into the base utils.js --- IPython/html/tests/notebook/dualmode.js | 38 ++++++++++++------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/IPython/html/tests/notebook/dualmode.js b/IPython/html/tests/notebook/dualmode.js index 58e320fed..830d1f3dc 100644 --- a/IPython/html/tests/notebook/dualmode.js +++ b/IPython/html/tests/notebook/dualmode.js @@ -73,7 +73,7 @@ casper.notebook_test(function () { // Utility functions. this.validate_state = function(message, mode, cell_index) { // General tests. - this.test.assertEquals(this._get_keyboard_mode(), this._get_notebook_mode(), + this.test.assertEquals(this.get_keyboard_mode(), this.get_notebook_mode(), message + '; keyboard and notebook modes match'); // Is codemirror focused appropriately? this.test.assert(this.is_editor_focus_valid(), message + '; cell editor focused appropriately'); @@ -86,7 +86,7 @@ casper.notebook_test(function () { // Mode specific tests. if (mode==='command') { // Are the notebook and keyboard manager in command mode? - this.test.assertEquals(this._get_keyboard_mode(), 'command', + this.test.assertEquals(this.get_keyboard_mode(), 'command', message + '; in command mode'); // Make sure there isn't a single cell in edit mode. this.test.assert(this.is_cell_edit(null), @@ -94,7 +94,7 @@ casper.notebook_test(function () { } else if (mode==='edit') { // Are the notebook and keyboard manager in edit mode? - this.test.assertEquals(this._get_keyboard_mode(), 'edit', + this.test.assertEquals(this.get_keyboard_mode(), 'edit', message + '; in edit mode'); // Is the specified cell the only cell in edit mode? if (cell_index!==undefined) { @@ -108,7 +108,7 @@ casper.notebook_test(function () { }; this.is_editor_focus_valid = function() { - var cells = this._get_cells(); + var cells = this.get_cells(); for (var i = 0; i < cells.length; i++) { if (!this.is_cell_editor_focus_valid(i)) { return false; @@ -117,24 +117,24 @@ casper.notebook_test(function () { return true; }; - this.is_cell_editor_focus_valid = function(i) { - var cell = this._get_cell(i); + this.is_cell_editor_focus_valid = function(index) { + var cell = this.get_cell(index); if (cell) { if (cell.mode == 'edit') { - return this.is_cell_editor_focused(i); + return this.is_cell_editor_focused(index); } else { - return !this.is_cell_editor_focused(i); + return !this.is_cell_editor_focused(index); } } return true; }; - this.is_cell_selected = function(i) { - return this.is_cell_on(i, 'selected', 'unselected'); + this.is_cell_selected = function(index) { + return this.is_cell_on(index, 'selected', 'unselected'); }; - this.is_cell_edit = function(i) { - return this.is_cell_on(i, 'edit_mode', 'command_mode'); + this.is_cell_edit = function(index) { + return this.is_cell_on(index, 'edit_mode', 'command_mode'); }; this.click_cell = function(index) { @@ -161,12 +161,12 @@ casper.notebook_test(function () { }, {k: key}); }; - this.is_cell_editor_focused = function(i) { - return this._is_cell_inputfield(i, '.CodeMirror-focused *'); + this.is_cell_editor_focused = function(index) { + return this._is_cell_inputfield(index, '.CodeMirror-focused *'); }; this.is_cell_on = function(i, on_class, off_class) { - var cells = this._get_cells(); + var cells = this.get_cells(); for (var j = 0; j < cells.length; j++) { if (j === i) { if (this._has_cell_class(j, off_class) || !this._has_cell_class(j, on_class)) { @@ -181,25 +181,25 @@ casper.notebook_test(function () { return true; }; - this._get_keyboard_mode = function() { + this.get_keyboard_mode = function() { return this.evaluate(function() { return IPython.keyboard_manager.mode; }, {}); }; - this._get_notebook_mode = function() { + this.get_notebook_mode = function() { return this.evaluate(function() { return IPython.notebook.mode; }, {}); }; - this._get_cells = function() { + this.get_cells = function() { return this.evaluate(function() { return IPython.notebook.get_cells(); }, {}); }; - this._get_cell = function(index) { + this.get_cell = function(index) { return this.evaluate(function(i) { var cell = IPython.notebook.get_cell(i); if (cell) { From 241b62a37a7863679d3b8aa76d61140d5ca0fa36 Mon Sep 17 00:00:00 2001 From: Jonathan Frederic Date: Mon, 10 Mar 2014 12:33:58 -0700 Subject: [PATCH 06/38] Move code into is_cell_editor_focused --- IPython/html/tests/notebook/dualmode.js | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/IPython/html/tests/notebook/dualmode.js b/IPython/html/tests/notebook/dualmode.js index 830d1f3dc..ab1d4cf79 100644 --- a/IPython/html/tests/notebook/dualmode.js +++ b/IPython/html/tests/notebook/dualmode.js @@ -162,7 +162,13 @@ casper.notebook_test(function () { }; this.is_cell_editor_focused = function(index) { - return this._is_cell_inputfield(index, '.CodeMirror-focused *'); + return this.evaluate(function(i) { + var cell = IPython.notebook.get_cell(i); + if (cell) { + return $(cell.code_mirror.getInputField()).is('.CodeMirror-focused *'); + } + return false; + }, {i : index}); }; this.is_cell_on = function(i, on_class, off_class) { @@ -209,16 +215,6 @@ casper.notebook_test(function () { }, {i : index}); }; - this._is_cell_inputfield = function(index, selector) { - return this.evaluate(function(i, s) { - var cell = IPython.notebook.get_cell(i); - if (cell) { - return $(cell.code_mirror.getInputField()).is(s); - } - return false; - }, {i : index, s: selector}); - }; - this._has_cell_class = function(index, classes) { return this.evaluate(function(i, c) { var cell = IPython.notebook.get_cell(i); From 2b800d3360c13858b73a3d467249c95ff431170b Mon Sep 17 00:00:00 2001 From: Jonathan Frederic Date: Mon, 10 Mar 2014 12:36:26 -0700 Subject: [PATCH 07/38] Add '_only' to only cell methods --- IPython/html/tests/notebook/dualmode.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/IPython/html/tests/notebook/dualmode.js b/IPython/html/tests/notebook/dualmode.js index ab1d4cf79..c5378edbf 100644 --- a/IPython/html/tests/notebook/dualmode.js +++ b/IPython/html/tests/notebook/dualmode.js @@ -79,7 +79,7 @@ casper.notebook_test(function () { this.test.assert(this.is_editor_focus_valid(), message + '; cell editor focused appropriately'); // Is the selected cell the only cell that is selected? if (cell_index!==undefined) { - this.test.assert(this.is_cell_selected(cell_index), + this.test.assert(this.is_only_cell_selected(cell_index), message + '; cell ' + cell_index + ' is the only cell selected'); } @@ -89,7 +89,7 @@ casper.notebook_test(function () { this.test.assertEquals(this.get_keyboard_mode(), 'command', message + '; in command mode'); // Make sure there isn't a single cell in edit mode. - this.test.assert(this.is_cell_edit(null), + this.test.assert(this.is_only_cell_edit(null), message + '; all cells in command mode'); } else if (mode==='edit') { @@ -98,7 +98,7 @@ casper.notebook_test(function () { message + '; in edit mode'); // Is the specified cell the only cell in edit mode? if (cell_index!==undefined) { - this.test.assert(this.is_cell_edit(cell_index), + this.test.assert(this.is_only_cell_edit(cell_index), message + '; cell ' + cell_index + ' is the only cell in edit mode'); } @@ -129,12 +129,12 @@ casper.notebook_test(function () { return true; }; - this.is_cell_selected = function(index) { - return this.is_cell_on(index, 'selected', 'unselected'); + this.is_only_cell_selected = function(index) { + return this.is_only_cell_on(index, 'selected', 'unselected'); }; - this.is_cell_edit = function(index) { - return this.is_cell_on(index, 'edit_mode', 'command_mode'); + this.is_only_cell_edit = function(index) { + return this.is_only_cell_on(index, 'edit_mode', 'command_mode'); }; this.click_cell = function(index) { @@ -171,7 +171,7 @@ casper.notebook_test(function () { }, {i : index}); }; - this.is_cell_on = function(i, on_class, off_class) { + this.is_only_cell_on = function(i, on_class, off_class) { var cells = this.get_cells(); for (var j = 0; j < cells.length; j++) { if (j === i) { From 9bd0ac19bf846d029ae12b960183839bd6d9205e Mon Sep 17 00:00:00 2001 From: Jonathan Frederic Date: Mon, 10 Mar 2014 12:42:32 -0700 Subject: [PATCH 08/38] sep. fucntions to move to util.js --- IPython/html/tests/notebook/dualmode.js | 69 +++++++++++++------------ 1 file changed, 37 insertions(+), 32 deletions(-) diff --git a/IPython/html/tests/notebook/dualmode.js b/IPython/html/tests/notebook/dualmode.js index c5378edbf..7126829bd 100644 --- a/IPython/html/tests/notebook/dualmode.js +++ b/IPython/html/tests/notebook/dualmode.js @@ -129,13 +129,10 @@ casper.notebook_test(function () { return true; }; - this.is_only_cell_selected = function(index) { - return this.is_only_cell_on(index, 'selected', 'unselected'); - }; - this.is_only_cell_edit = function(index) { - return this.is_only_cell_on(index, 'edit_mode', 'command_mode'); - }; + /* TODO: MOVE EVERYTHING BELOW THIS LINE INTO THE BASE (utils.js) */ + + this.click_cell = function(index) { // Code Mirror does not play nicely with emulated brower events. @@ -161,32 +158,6 @@ casper.notebook_test(function () { }, {k: key}); }; - this.is_cell_editor_focused = function(index) { - return this.evaluate(function(i) { - var cell = IPython.notebook.get_cell(i); - if (cell) { - return $(cell.code_mirror.getInputField()).is('.CodeMirror-focused *'); - } - return false; - }, {i : index}); - }; - - this.is_only_cell_on = function(i, on_class, off_class) { - var cells = this.get_cells(); - for (var j = 0; j < cells.length; j++) { - if (j === i) { - if (this._has_cell_class(j, off_class) || !this._has_cell_class(j, on_class)) { - return false; - } - } else { - if (!this._has_cell_class(j, off_class) || this._has_cell_class(j, on_class)) { - return false; - } - } - } - return true; - }; - this.get_keyboard_mode = function() { return this.evaluate(function() { return IPython.keyboard_manager.mode; @@ -215,6 +186,40 @@ casper.notebook_test(function () { }, {i : index}); }; + this.is_cell_editor_focused = function(index) { + return this.evaluate(function(i) { + var cell = IPython.notebook.get_cell(i); + if (cell) { + return $(cell.code_mirror.getInputField()).is('.CodeMirror-focused *'); + } + return false; + }, {i : index}); + }; + + this.is_only_cell_selected = function(index) { + return this.is_only_cell_on(index, 'selected', 'unselected'); + }; + + this.is_only_cell_edit = function(index) { + return this.is_only_cell_on(index, 'edit_mode', 'command_mode'); + }; + + this.is_only_cell_on = function(i, on_class, off_class) { + var cells = this.get_cells(); + for (var j = 0; j < cells.length; j++) { + if (j === i) { + if (this._has_cell_class(j, off_class) || !this._has_cell_class(j, on_class)) { + return false; + } + } else { + if (!this._has_cell_class(j, off_class) || this._has_cell_class(j, on_class)) { + return false; + } + } + } + return true; + }; + this._has_cell_class = function(index, classes) { return this.evaluate(function(i, c) { var cell = IPython.notebook.get_cell(i); From 55773dd95adbc1c834f9b048f3bdc875caaddcb2 Mon Sep 17 00:00:00 2001 From: Jonathan Frederic Date: Mon, 10 Mar 2014 13:06:53 -0700 Subject: [PATCH 09/38] Made *+enter tests more complicated. --- IPython/html/tests/notebook/dualmode.js | 58 +++++++++++++++++++++---- 1 file changed, 49 insertions(+), 9 deletions(-) diff --git a/IPython/html/tests/notebook/dualmode.js b/IPython/html/tests/notebook/dualmode.js index 7126829bd..444f0deca 100644 --- a/IPython/html/tests/notebook/dualmode.js +++ b/IPython/html/tests/notebook/dualmode.js @@ -55,18 +55,58 @@ casper.notebook_test(function () { this.validate_state('focus #notebook', 'command', 0); this.click_cell(3); this.validate_state('click cell 3', 'edit', 3); + + // shift+enter tests. + // last cell in notebook + var base_index = 3; + this.trigger_keydown('shift+enter'); // Creates one cell + this.validate_state('shift+enter (no cell below)', 'edit', base_index + 1); + // not last cell in notebook & starts in edit mode + this.click_cell(base_index); + this.validate_state('click cell %d' % base_index, 'edit', base_index); this.trigger_keydown('shift+enter'); - this.validate_state('shift+enter (no cell below)', 'edit', 4); - this.click_cell(3); - this.validate_state('click cell 3', 'edit', 3); + this.validate_state('shift+enter (cell exists below)', 'command', base_index + 1); + // starts in command mode + this.trigger_keydown('k'); + this.validate_state('k in comand mode', 'command', base_index); this.trigger_keydown('shift+enter'); - this.validate_state('shift+enter (cell exists below)', 'command', 4); - this.click_cell(3); - this.validate_state('click cell 3', 'edit', 3); - this.trigger_keydown('alt+enter'); - this.validate_state('alt+enter', 'edit', 4); + this.validate_state('shift+enter (start in command mode)', 'command', base_index + 1); + + // ctrl+enter tests. + // last cell in notebook + base_index++; this.trigger_keydown('ctrl+enter'); - this.validate_state('ctrl+enter', 'command', 4); + this.validate_state('ctrl+enter (no cell below)', 'command', base_index); + // not last cell in notebook & starts in edit mode + this.click_cell(base_index-1); + this.validate_state('click cell %d' % (base_index-1), 'edit', base_index-1); + this.trigger_keydown('ctrl+enter'); + this.validate_state('ctrl+enter (cell exists below)', 'command', base_index-1); + // starts in command mode + this.trigger_keydown('j'); + this.validate_state('j in comand mode', 'command', base_index); + this.trigger_keydown('ctrl+enter'); + this.validate_state('ctrl+enter (start in command mode)', 'command', base_index); + + // alt+enter tests. + // last cell in notebook + base_index++; + this.trigger_keydown('alt+enter'); // Creates one cell + this.validate_state('alt+enter (no cell below)', 'edit', base_index + 1); + // not last cell in notebook & starts in edit mode + this.click_cell(base_index); + this.validate_state('click cell %d' % base_index, 'edit', base_index); + this.trigger_keydown('alt+enter'); // Creates one cell + this.validate_state('alt+enter (cell exists below)', 'edit', base_index + 1); + // starts in command mode + this.trigger_keydown('esc'); + this.trigger_keydown('k'); + this.validate_state('k in comand mode', 'command', base_index); + this.trigger_keydown('alt+enter'); // Creates one cell + this.validate_state('alt+enter (start in command mode)', 'edit', base_index + 1); + + // Notebook will now have 8 cells, the index of the last cell will be 7. + }); From 4f6884f985245b4a129612e73698275439fffd8b Mon Sep 17 00:00:00 2001 From: Jonathan Frederic Date: Mon, 10 Mar 2014 13:32:19 -0700 Subject: [PATCH 10/38] Add test for cell type modifier keyboard shortcuts --- IPython/html/tests/notebook/dualmode.js | 32 +++++++++++++++++++++---- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/IPython/html/tests/notebook/dualmode.js b/IPython/html/tests/notebook/dualmode.js index 444f0deca..4403f5359 100644 --- a/IPython/html/tests/notebook/dualmode.js +++ b/IPython/html/tests/notebook/dualmode.js @@ -63,7 +63,7 @@ casper.notebook_test(function () { this.validate_state('shift+enter (no cell below)', 'edit', base_index + 1); // not last cell in notebook & starts in edit mode this.click_cell(base_index); - this.validate_state('click cell %d' % base_index, 'edit', base_index); + this.validate_state('click cell ' + base_index, 'edit', base_index); this.trigger_keydown('shift+enter'); this.validate_state('shift+enter (cell exists below)', 'command', base_index + 1); // starts in command mode @@ -79,7 +79,7 @@ casper.notebook_test(function () { this.validate_state('ctrl+enter (no cell below)', 'command', base_index); // not last cell in notebook & starts in edit mode this.click_cell(base_index-1); - this.validate_state('click cell %d' % (base_index-1), 'edit', base_index-1); + this.validate_state('click cell ' + (base_index-1), 'edit', base_index-1); this.trigger_keydown('ctrl+enter'); this.validate_state('ctrl+enter (cell exists below)', 'command', base_index-1); // starts in command mode @@ -90,12 +90,11 @@ casper.notebook_test(function () { // alt+enter tests. // last cell in notebook - base_index++; this.trigger_keydown('alt+enter'); // Creates one cell this.validate_state('alt+enter (no cell below)', 'edit', base_index + 1); // not last cell in notebook & starts in edit mode this.click_cell(base_index); - this.validate_state('click cell %d' % base_index, 'edit', base_index); + this.validate_state('click cell ' + base_index, 'edit', base_index); this.trigger_keydown('alt+enter'); // Creates one cell this.validate_state('alt+enter (cell exists below)', 'edit', base_index + 1); // starts in command mode @@ -106,7 +105,30 @@ casper.notebook_test(function () { this.validate_state('alt+enter (start in command mode)', 'edit', base_index + 1); // Notebook will now have 8 cells, the index of the last cell will be 7. - + this.test.assertEquals(this.get_cells.length, 8, '*-enter commands added cells where needed.'); + this.click_cell(7); + this.trigger_keydown('esc'); + this.validate_state('click cell ' + 7 + ' and esc', 'command', 7); + + this.trigger_keydown('r'); + this.test.assertEquals(this.get_cell(7).cell_type, 'raw', 'r; cell is raw'); + this.trigger_keydown('1'); + this.test.assertEquals(this.get_cell(7).cell_type, 'heading', '1; cell is heading'); + this.test.assertEquals(this.get_cell(7).level, 1, '1; cell is level 1 heading'); + this.trigger_keydown('2'); + this.test.assertEquals(this.get_cell(7).level, 2, '2; cell is level 2 heading'); + this.trigger_keydown('3'); + this.test.assertEquals(this.get_cell(7).level, 3, '3; cell is level 3 heading'); + this.trigger_keydown('4'); + this.test.assertEquals(this.get_cell(7).level, 4, '4; cell is level 4 heading'); + this.trigger_keydown('5'); + this.test.assertEquals(this.get_cell(7).level, 5, '5; cell is level 5 heading'); + this.trigger_keydown('6'); + this.test.assertEquals(this.get_cell(7).level, 6, '6; cell is level 6 heading'); + this.trigger_keydown('m'); + this.test.assertEquals(this.get_cell(7).cell_type, 'markdown', 'm; cell is markdown'); + this.trigger_keydown('y'); + this.test.assertEquals(this.get_cell(7).cell_type, 'code', 'y; cell is code'); }); From e647e13162066da64df85f8f1a628a64c70aabc9 Mon Sep 17 00:00:00 2001 From: Jonathan Frederic Date: Mon, 10 Mar 2014 13:58:49 -0700 Subject: [PATCH 11/38] Add dd tests --- IPython/html/tests/notebook/dualmode.js | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/IPython/html/tests/notebook/dualmode.js b/IPython/html/tests/notebook/dualmode.js index 4403f5359..2e81e5788 100644 --- a/IPython/html/tests/notebook/dualmode.js +++ b/IPython/html/tests/notebook/dualmode.js @@ -105,7 +105,7 @@ casper.notebook_test(function () { this.validate_state('alt+enter (start in command mode)', 'edit', base_index + 1); // Notebook will now have 8 cells, the index of the last cell will be 7. - this.test.assertEquals(this.get_cells.length, 8, '*-enter commands added cells where needed.'); + this.test.assertEquals(this.get_cells().length, 8, '*-enter commands added cells where needed.'); this.click_cell(7); this.trigger_keydown('esc'); this.validate_state('click cell ' + 7 + ' and esc', 'command', 7); @@ -129,8 +129,23 @@ casper.notebook_test(function () { this.test.assertEquals(this.get_cell(7).cell_type, 'markdown', 'm; cell is markdown'); this.trigger_keydown('y'); this.test.assertEquals(this.get_cell(7).cell_type, 'code', 'y; cell is code'); + + this.trigger_keydown('d'); + this.trigger_keydown('d'); + this.test.assertEquals(this.get_cells().length, 7, 'dd actually deletes a cell'); + this.validate_state('dd', 'command', 6); + + // Make sure that if the time between d presses is too long + this.trigger_keydown('d'); }); + this.wait(1000); + this.then(function () { + this.trigger_keydown('d'); + this.test.assertEquals(this.get_cells().length, 6, "d, 1 second wait, d doesn't delete a cell"); + this.validate_state('d, 1 second wait, d', 'command', 6); + + }); // Utility functions. this.validate_state = function(message, mode, cell_index) { From 13908b60a47f18dfe0bfeed6704ed88da01ba657 Mon Sep 17 00:00:00 2001 From: Jonathan Frederic Date: Mon, 10 Mar 2014 14:06:20 -0700 Subject: [PATCH 12/38] Fixed typo in dd test --- IPython/html/tests/notebook/dualmode.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/html/tests/notebook/dualmode.js b/IPython/html/tests/notebook/dualmode.js index 2e81e5788..8dc926851 100644 --- a/IPython/html/tests/notebook/dualmode.js +++ b/IPython/html/tests/notebook/dualmode.js @@ -142,7 +142,7 @@ casper.notebook_test(function () { this.then(function () { this.trigger_keydown('d'); - this.test.assertEquals(this.get_cells().length, 6, "d, 1 second wait, d doesn't delete a cell"); + this.test.assertEquals(this.get_cells().length, 7, "d, 1 second wait, d doesn't delete a cell"); this.validate_state('d, 1 second wait, d', 'command', 6); }); From 1094299934ad1599997cbabc0b62f6680b199f75 Mon Sep 17 00:00:00 2001 From: Jonathan Frederic Date: Mon, 10 Mar 2014 18:14:58 -0700 Subject: [PATCH 13/38] Added up/down and markdown tests --- IPython/html/tests/notebook/dualmode.js | 99 ++++++++++++++++++++----- 1 file changed, 80 insertions(+), 19 deletions(-) diff --git a/IPython/html/tests/notebook/dualmode.js b/IPython/html/tests/notebook/dualmode.js index 8dc926851..804bebade 100644 --- a/IPython/html/tests/notebook/dualmode.js +++ b/IPython/html/tests/notebook/dualmode.js @@ -23,9 +23,9 @@ casper.notebook_test(function () { this.validate_state('esc', 'command', 1); this.trigger_keydown('j'); this.validate_state('j in command mode', 'command', 2); - this.click_cell(0); + this.click_cell_editor(0); this.validate_state('click cell 0', 'edit', 0); - this.click_cell(3); + this.click_cell_editor(3); this.validate_state('click cell 3', 'edit', 3); this.trigger_keydown('esc'); this.validate_state('esc', 'command', 3); @@ -45,15 +45,15 @@ casper.notebook_test(function () { this.trigger_keydown('k'); this.validate_state('k in command mode', 'command', 2); - this.click_cell(0); + this.click_cell_editor(0); this.validate_state('click cell 0', 'edit', 0); this.focus_notebook(); this.validate_state('focus #notebook', 'command', 0); - this.click_cell(0); + this.click_cell_editor(0); this.validate_state('click cell 0', 'edit', 0); this.focus_notebook(); this.validate_state('focus #notebook', 'command', 0); - this.click_cell(3); + this.click_cell_editor(3); this.validate_state('click cell 3', 'edit', 3); // shift+enter tests. @@ -62,7 +62,7 @@ casper.notebook_test(function () { this.trigger_keydown('shift+enter'); // Creates one cell this.validate_state('shift+enter (no cell below)', 'edit', base_index + 1); // not last cell in notebook & starts in edit mode - this.click_cell(base_index); + this.click_cell_editor(base_index); this.validate_state('click cell ' + base_index, 'edit', base_index); this.trigger_keydown('shift+enter'); this.validate_state('shift+enter (cell exists below)', 'command', base_index + 1); @@ -78,7 +78,7 @@ casper.notebook_test(function () { this.trigger_keydown('ctrl+enter'); this.validate_state('ctrl+enter (no cell below)', 'command', base_index); // not last cell in notebook & starts in edit mode - this.click_cell(base_index-1); + this.click_cell_editor(base_index-1); this.validate_state('click cell ' + (base_index-1), 'edit', base_index-1); this.trigger_keydown('ctrl+enter'); this.validate_state('ctrl+enter (cell exists below)', 'command', base_index-1); @@ -93,21 +93,19 @@ casper.notebook_test(function () { this.trigger_keydown('alt+enter'); // Creates one cell this.validate_state('alt+enter (no cell below)', 'edit', base_index + 1); // not last cell in notebook & starts in edit mode - this.click_cell(base_index); + this.click_cell_editor(base_index); this.validate_state('click cell ' + base_index, 'edit', base_index); this.trigger_keydown('alt+enter'); // Creates one cell this.validate_state('alt+enter (cell exists below)', 'edit', base_index + 1); // starts in command mode - this.trigger_keydown('esc'); - this.trigger_keydown('k'); + this.trigger_keydown('esc', 'k'); this.validate_state('k in comand mode', 'command', base_index); this.trigger_keydown('alt+enter'); // Creates one cell this.validate_state('alt+enter (start in command mode)', 'edit', base_index + 1); // Notebook will now have 8 cells, the index of the last cell will be 7. this.test.assertEquals(this.get_cells().length, 8, '*-enter commands added cells where needed.'); - this.click_cell(7); - this.trigger_keydown('esc'); + this.select_cell(7); this.validate_state('click cell ' + 7 + ' and esc', 'command', 7); this.trigger_keydown('r'); @@ -130,8 +128,7 @@ casper.notebook_test(function () { this.trigger_keydown('y'); this.test.assertEquals(this.get_cell(7).cell_type, 'code', 'y; cell is code'); - this.trigger_keydown('d'); - this.trigger_keydown('d'); + this.trigger_keydown('d', 'd'); this.test.assertEquals(this.get_cells().length, 7, 'dd actually deletes a cell'); this.validate_state('dd', 'command', 6); @@ -144,6 +141,63 @@ casper.notebook_test(function () { this.test.assertEquals(this.get_cells().length, 7, "d, 1 second wait, d doesn't delete a cell"); this.validate_state('d, 1 second wait, d', 'command', 6); + this.trigger_keydown('j'); + this.validate_state('j at end of notebook', 'command', 6); + this.trigger_keydown('down'); + this.validate_state('down at end of notebook', 'command', 6); + this.trigger_keydown('up'); + this.validate_state('up', 'command', 5); + this.select_cell(0); + this.validate_state('select 0', 'command', 0); + this.trigger_keydown('k'); + this.validate_state('k at top of notebook', 'command', 0); + this.trigger_keydown('up'); + this.validate_state('up at top of notebook', 'command', 0); + this.trigger_keydown('down'); + this.validate_state('down', 'command', 1); + + this.click_cell_editor(6); + this.validate_state('click cell 6', 'edit', 6); + this.trigger_keydown('down'); + this.validate_state('down at end of notebook', 'edit', 6); + this.trigger_keydown('up'); + this.validate_state('up', 'edit', 5); + this.click_cell_editor(0); + this.validate_state('click 0', 'edit', 0); + this.trigger_keydown('up'); + this.validate_state('up at top of notebook', 'edit', 0); + this.trigger_keydown('down'); + this.validate_state('down', 'edit', 1); + + this.select_cell(6); + this.validate_state('select 6', 'command', 6); + this.trigger_keydown('m'); + this.test.assertEquals(this.get_cell(6).cell_type, 'markdown', 'm; cell is markdown'); + this.test.assertEquals(this.get_cell(6).rendered, true, 'm; cell is rendered'); + this.trigger_keydown('enter'); + this.test.assertEquals(this.get_cell(6).rendered, false, 'enter; cell is unrendered'); + this.validate_state('enter', 'edit', 6); + this.trigger_keydown('ctrl+enter'); + this.test.assertEquals(this.get_cell(6).rendered, true, 'enter; cell is rendered'); + this.validate_state('enter', 'command', 6); + this.trigger_keydown('enter'); + this.test.assertEquals(this.get_cell(6).rendered, false, 'enter; cell is unrendered'); + this.select_cell(5); + this.test.assertEquals(this.get_cell(6).rendered, false, 'select 5; cell 6 is still unrendered'); + this.validate_state('select 5', 'command', 5); + this.select_cell(6); + this.validate_state('select 6', 'command', 5); + this.trigger_keydown('ctrl+enter'); + this.test.assertEquals(this.get_cell(6).rendered, true, 'enter; cell is rendered'); + this.select_cell(5); + this.validate_state('select 5', 'command', 5); + this.trigger_keydown('shift+enter'); + this.validate_state('shift+enter', 'command', 6); + this.test.assertEquals(this.get_cell(6).rendered, true, 'enter; cell is rendered'); + this.trigger_keydown('shift+enter'); // Creates one cell + this.validate_state('shift+enter', 'edit', 7); + this.test.assertEquals(this.get_cell(6).rendered, true, 'enter; cell is rendered'); + }); @@ -210,8 +264,13 @@ casper.notebook_test(function () { /* TODO: MOVE EVERYTHING BELOW THIS LINE INTO THE BASE (utils.js) */ + this.select_cell = function (index) { + this.evaluate(function (i) { + IPython.notebook.select(i); + }, {i: index}); + }; - this.click_cell = function(index) { + this.click_cell_editor = function(index) { // Code Mirror does not play nicely with emulated brower events. // Instead of trying to emulate a click, here we run code similar to // the code used in Code Mirror that handles the mousedown event on a @@ -229,10 +288,12 @@ casper.notebook_test(function () { }, {}); }; - this.trigger_keydown = function(key) { - this.evaluate(function (k) { - IPython.keyboard.trigger_keydown(k); - }, {k: key}); + this.trigger_keydown = function() { + for (var i = 0; i < arguments.length; i++) { + this.evaluate(function (k) { + IPython.keyboard.trigger_keydown(k); + }, {k: arguments[i]}); + } }; this.get_keyboard_mode = function() { From 26e3d14f81571abb226e69bde674ab49de307f91 Mon Sep 17 00:00:00 2001 From: Jonathan Frederic Date: Mon, 10 Mar 2014 18:24:35 -0700 Subject: [PATCH 14/38] Fixed state type for new markdown cell --- IPython/html/tests/notebook/dualmode.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/IPython/html/tests/notebook/dualmode.js b/IPython/html/tests/notebook/dualmode.js index 804bebade..43a6b38d9 100644 --- a/IPython/html/tests/notebook/dualmode.js +++ b/IPython/html/tests/notebook/dualmode.js @@ -173,12 +173,12 @@ casper.notebook_test(function () { this.validate_state('select 6', 'command', 6); this.trigger_keydown('m'); this.test.assertEquals(this.get_cell(6).cell_type, 'markdown', 'm; cell is markdown'); - this.test.assertEquals(this.get_cell(6).rendered, true, 'm; cell is rendered'); + this.test.assertEquals(this.get_cell(6).rendered, false, 'm; cell is rendered'); this.trigger_keydown('enter'); this.test.assertEquals(this.get_cell(6).rendered, false, 'enter; cell is unrendered'); this.validate_state('enter', 'edit', 6); this.trigger_keydown('ctrl+enter'); - this.test.assertEquals(this.get_cell(6).rendered, true, 'enter; cell is rendered'); + this.test.assertEquals(this.get_cell(6).rendered, true, 'ctrl+enter; cell is rendered'); this.validate_state('enter', 'command', 6); this.trigger_keydown('enter'); this.test.assertEquals(this.get_cell(6).rendered, false, 'enter; cell is unrendered'); @@ -188,15 +188,15 @@ casper.notebook_test(function () { this.select_cell(6); this.validate_state('select 6', 'command', 5); this.trigger_keydown('ctrl+enter'); - this.test.assertEquals(this.get_cell(6).rendered, true, 'enter; cell is rendered'); + this.test.assertEquals(this.get_cell(6).rendered, true, 'ctrl+enter; cell is rendered'); this.select_cell(5); this.validate_state('select 5', 'command', 5); this.trigger_keydown('shift+enter'); this.validate_state('shift+enter', 'command', 6); - this.test.assertEquals(this.get_cell(6).rendered, true, 'enter; cell is rendered'); + this.test.assertEquals(this.get_cell(6).rendered, true, 'shift+enter; cell is rendered'); this.trigger_keydown('shift+enter'); // Creates one cell this.validate_state('shift+enter', 'edit', 7); - this.test.assertEquals(this.get_cell(6).rendered, true, 'enter; cell is rendered'); + this.test.assertEquals(this.get_cell(6).rendered, true, 'shift+enter; cell is rendered'); }); From ddc21618174bf21d73ba07cb0e91af106d67b9cd Mon Sep 17 00:00:00 2001 From: Jonathan Frederic Date: Tue, 11 Mar 2014 12:29:38 -0700 Subject: [PATCH 15/38] Added ctrl+(j&k), a, and b tests --- IPython/html/tests/notebook/dualmode.js | 86 ++++++++++++++++++------- 1 file changed, 61 insertions(+), 25 deletions(-) diff --git a/IPython/html/tests/notebook/dualmode.js b/IPython/html/tests/notebook/dualmode.js index 43a6b38d9..2f7ce2e49 100644 --- a/IPython/html/tests/notebook/dualmode.js +++ b/IPython/html/tests/notebook/dualmode.js @@ -2,11 +2,16 @@ // Test casper.notebook_test(function () { - var index = this.append_cell('print("a")'); + var a = 'print("a")'; + var index = this.append_cell(a); this.execute_cell_then(index); - index = this.append_cell('print("b")'); + + var b = 'print("b")'; + index = this.append_cell(b); this.execute_cell_then(index); - index = this.append_cell('print("c")'); + + var c = 'print("c")'; + index = this.append_cell(c); this.execute_cell_then(index); this.then(function () { @@ -56,7 +61,7 @@ casper.notebook_test(function () { this.click_cell_editor(3); this.validate_state('click cell 3', 'edit', 3); - // shift+enter tests. + // shift+enter // last cell in notebook var base_index = 3; this.trigger_keydown('shift+enter'); // Creates one cell @@ -72,7 +77,7 @@ casper.notebook_test(function () { this.trigger_keydown('shift+enter'); this.validate_state('shift+enter (start in command mode)', 'command', base_index + 1); - // ctrl+enter tests. + // ctrl+enter // last cell in notebook base_index++; this.trigger_keydown('ctrl+enter'); @@ -88,7 +93,7 @@ casper.notebook_test(function () { this.trigger_keydown('ctrl+enter'); this.validate_state('ctrl+enter (start in command mode)', 'command', base_index); - // alt+enter tests. + // alt+enter // last cell in notebook this.trigger_keydown('alt+enter'); // Creates one cell this.validate_state('alt+enter (no cell below)', 'edit', base_index + 1); @@ -104,10 +109,11 @@ casper.notebook_test(function () { this.validate_state('alt+enter (start in command mode)', 'edit', base_index + 1); // Notebook will now have 8 cells, the index of the last cell will be 7. - this.test.assertEquals(this.get_cells().length, 8, '*-enter commands added cells where needed.'); + this.test.assertEquals(this.get_cells_length(), 8, '*-enter commands added cells where needed.'); this.select_cell(7); this.validate_state('click cell ' + 7 + ' and esc', 'command', 7); + // Cell mode change this.trigger_keydown('r'); this.test.assertEquals(this.get_cell(7).cell_type, 'raw', 'r; cell is raw'); this.trigger_keydown('1'); @@ -128,19 +134,21 @@ casper.notebook_test(function () { this.trigger_keydown('y'); this.test.assertEquals(this.get_cell(7).cell_type, 'code', 'y; cell is code'); + // Cell deletion this.trigger_keydown('d', 'd'); - this.test.assertEquals(this.get_cells().length, 7, 'dd actually deletes a cell'); + this.test.assertEquals(this.get_cells_length(), 7, 'dd actually deletes a cell'); this.validate_state('dd', 'command', 6); - // Make sure that if the time between d presses is too long + // Make sure that if the time between d presses is too long, nothing gets removed. this.trigger_keydown('d'); }); this.wait(1000); this.then(function () { this.trigger_keydown('d'); - - this.test.assertEquals(this.get_cells().length, 7, "d, 1 second wait, d doesn't delete a cell"); + this.test.assertEquals(this.get_cells_length(), 7, "d, 1 second wait, d doesn't delete a cell"); this.validate_state('d, 1 second wait, d', 'command', 6); + + // Up and down in command mode this.trigger_keydown('j'); this.validate_state('j at end of notebook', 'command', 6); this.trigger_keydown('down'); @@ -156,6 +164,7 @@ casper.notebook_test(function () { this.trigger_keydown('down'); this.validate_state('down', 'command', 1); + // Up and down in edit mode this.click_cell_editor(6); this.validate_state('click cell 6', 'edit', 6); this.trigger_keydown('down'); @@ -169,6 +178,7 @@ casper.notebook_test(function () { this.trigger_keydown('down'); this.validate_state('down', 'edit', 1); + // Markdown rendering / unredering this.select_cell(6); this.validate_state('select 6', 'command', 6); this.trigger_keydown('m'); @@ -186,7 +196,7 @@ casper.notebook_test(function () { this.test.assertEquals(this.get_cell(6).rendered, false, 'select 5; cell 6 is still unrendered'); this.validate_state('select 5', 'command', 5); this.select_cell(6); - this.validate_state('select 6', 'command', 5); + this.validate_state('select 6', 'command', 6); this.trigger_keydown('ctrl+enter'); this.test.assertEquals(this.get_cell(6).rendered, true, 'ctrl+enter; cell is rendered'); this.select_cell(5); @@ -198,6 +208,38 @@ casper.notebook_test(function () { this.validate_state('shift+enter', 'edit', 7); this.test.assertEquals(this.get_cell(6).rendered, true, 'shift+enter; cell is rendered'); + // Cell movement ( ctrl+(k or j) ) + this.select_cell(2); + this.test.assertEquals(this.get_cell_text(2), b, 'select 2; Cell 2 text is correct'); + this.trigger_keydown('ctrl+k'); // Move cell 2 up one + this.test.assertEquals(this.get_cell_text(1), b, 'ctrl+k; Cell 1 text is correct'); + this.test.assertEquals(this.get_cell_text(2), a, 'ctrl+k; Cell 2 text is correct'); + this.validate_state('ctrl+k', 'command', 1); + this.trigger_keydown('ctrl+j'); // Move cell 1 down one + this.test.assertEquals(this.get_cell_text(1), a, 'ctrl+j; Cell 1 text is correct'); + this.test.assertEquals(this.get_cell_text(2), b, 'ctrl+j; Cell 2 text is correct'); + this.validate_state('ctrl+j', 'command', 2); + + // Cell insertion + this.trigger_keydown('a'); // Creates one cell + this.test.assertEquals(this.get_cell_text(2), '', 'a; New cell 2 text is empty'); + this.validate_state('a', 'command', 2); + this.trigger_keydown('b'); // Creates one cell + this.test.assertEquals(this.get_cell_text(2), '', 'b; Cell 2 text is still empty'); + this.test.assertEquals(this.get_cell_text(3), '', 'b; New cell 3 text is empty'); + this.validate_state('b', 'command', 3); + + // Copy/past/cut + var num_cells = this.get_cells_length(); + this.test.assertEquals(this.get_cell_text(1), a, 'Verify that cell 1 is a'); + this.select_cell(1); + this.trigger_keydown('x'); // Cut + this.validate_state('x', 'command', 1); + this.test.assertEquals(this.get_cells_length(), num_cells-1, 'Verify that the cell was removed.'); + this.test.assertEquals(this.get_cell_text(1), '', 'Verify that cell 2 is now where cell 1 was.'); + this.select_cell(2); + this.trigger_keydown('v'); // Paste + this.validate_state('v', 'command', 3); }); @@ -239,8 +281,8 @@ casper.notebook_test(function () { }; this.is_editor_focus_valid = function() { - var cells = this.get_cells(); - for (var i = 0; i < cells.length; i++) { + var cells_length = this.get_cells_length(); + for (var i = 0; i < cells_length; i++) { if (!this.is_cell_editor_focus_valid(i)) { return false; } @@ -308,12 +350,6 @@ casper.notebook_test(function () { }, {}); }; - this.get_cells = function() { - return this.evaluate(function() { - return IPython.notebook.get_cells(); - }, {}); - }; - this.get_cell = function(index) { return this.evaluate(function(i) { var cell = IPython.notebook.get_cell(i); @@ -343,14 +379,14 @@ casper.notebook_test(function () { }; this.is_only_cell_on = function(i, on_class, off_class) { - var cells = this.get_cells(); - for (var j = 0; j < cells.length; j++) { + var cells_length = this.get_cells_length(); + for (var j = 0; j < cells_length; j++) { if (j === i) { - if (this._has_cell_class(j, off_class) || !this._has_cell_class(j, on_class)) { + if (this.cell_has_class(j, off_class) || !this.cell_has_class(j, on_class)) { return false; } } else { - if (!this._has_cell_class(j, off_class) || this._has_cell_class(j, on_class)) { + if (!this.cell_has_class(j, off_class) || this.cell_has_class(j, on_class)) { return false; } } @@ -358,7 +394,7 @@ casper.notebook_test(function () { return true; }; - this._has_cell_class = function(index, classes) { + this.cell_has_class = function(index, classes) { return this.evaluate(function(i, c) { var cell = IPython.notebook.get_cell(i); if (cell) { From 6efa0a4dae5f62db0f396e8d21756774cf0035d0 Mon Sep 17 00:00:00 2001 From: Jonathan Frederic Date: Tue, 11 Mar 2014 12:30:10 -0700 Subject: [PATCH 16/38] Added get_cell_text --- IPython/html/tests/util.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/IPython/html/tests/util.js b/IPython/html/tests/util.js index 8c49dd240..63f4ada53 100644 --- a/IPython/html/tests/util.js +++ b/IPython/html/tests/util.js @@ -153,6 +153,14 @@ casper.set_cell_text = function(index, text){ }, index, text); }; +// Get the text content of a cell. +casper.get_cell_text = function(index){ + return this.evaluate(function (index) { + var cell = IPython.notebook.get_cell(index); + return cell.get_text(); + }, index); +}; + // Inserts a cell at the bottom of the notebook // Returns the new cell's index. casper.insert_cell_at_bottom = function(cell_type){ From 23ca387dd72dc0bb7a8588d53c4365ca2e2d0420 Mon Sep 17 00:00:00 2001 From: Jonathan Frederic Date: Tue, 11 Mar 2014 12:38:08 -0700 Subject: [PATCH 17/38] cutcopyandpaste --- IPython/html/tests/notebook/dualmode.js | 31 ++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/IPython/html/tests/notebook/dualmode.js b/IPython/html/tests/notebook/dualmode.js index 2f7ce2e49..32454ef55 100644 --- a/IPython/html/tests/notebook/dualmode.js +++ b/IPython/html/tests/notebook/dualmode.js @@ -229,17 +229,42 @@ casper.notebook_test(function () { this.test.assertEquals(this.get_cell_text(3), '', 'b; New cell 3 text is empty'); this.validate_state('b', 'command', 3); - // Copy/past/cut + // Copy/paste/cut var num_cells = this.get_cells_length(); this.test.assertEquals(this.get_cell_text(1), a, 'Verify that cell 1 is a'); this.select_cell(1); this.trigger_keydown('x'); // Cut this.validate_state('x', 'command', 1); - this.test.assertEquals(this.get_cells_length(), num_cells-1, 'Verify that the cell was removed.'); + this.test.assertEquals(this.get_cells_length(), num_cells-1, 'Verify that a cell was removed.'); this.test.assertEquals(this.get_cell_text(1), '', 'Verify that cell 2 is now where cell 1 was.'); this.select_cell(2); this.trigger_keydown('v'); // Paste - this.validate_state('v', 'command', 3); + this.validate_state('v', 'command', 3); // Selection should move to pasted cell, below current cell. + this.test.assertEquals(this.get_cell_text(3), a, 'Verify that cell 3 has the cut contents.'); + this.test.assertEquals(this.get_cells_length(), num_cells, 'Verify a the cell was added.'); + this.trigger_keydown('v'); // Paste + this.validate_state('v', 'command', 4); // Selection should move to pasted cell, below current cell. + this.test.assertEquals(this.get_cell_text(4), a, 'Verify that cell 4 has the cut contents.'); + this.test.assertEquals(this.get_cells_length(), num_cells+1, 'Verify a the cell was added.'); + this.select_cell(5); + this.trigger_keydown('c'); // Copy + this.validate_state('c', 'command', 5); + this.test.assertEquals(this.get_cell_text(5), b, 'Verify that cell 5 is b'); + this.select_cell(6); + this.trigger_keydown('c'); // Copy + this.validate_state('c', 'command', 6); + this.test.assertEquals(this.get_cell_text(6), c, 'Verify that cell 6 is c'); + this.trigger_keydown('v'); // Paste + this.validate_state('v', 'command', 7); + this.test.assertEquals(this.get_cell_text(6), c, 'Verify that cell 6 still has the copied contents.'); + this.test.assertEquals(this.get_cell_text(7), c, 'Verify that cell 7 has the copied contents.'); + this.test.assertEquals(this.get_cells_length(), num_cells+2, 'Verify a the cell was added.'); + this.select_cell(0); + this.trigger_keydown('shift+v'); // Paste + this.validate_state('shift+v', 'command', 0); + this.test.assertEquals(this.get_cell_text(0), c, 'Verify that cell 0 has the copied contents.'); + this.test.assertEquals(this.get_cells_length(), num_cells+3, 'Verify a the cell was added.'); + }); From c73bef017d24ff4153800d31af34edc8e9e62266 Mon Sep 17 00:00:00 2001 From: Jonathan Frederic Date: Tue, 11 Mar 2014 12:56:05 -0700 Subject: [PATCH 18/38] Added split merge tests --- IPython/html/tests/notebook/dualmode.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/IPython/html/tests/notebook/dualmode.js b/IPython/html/tests/notebook/dualmode.js index 32454ef55..b04210e89 100644 --- a/IPython/html/tests/notebook/dualmode.js +++ b/IPython/html/tests/notebook/dualmode.js @@ -265,6 +265,22 @@ casper.notebook_test(function () { this.test.assertEquals(this.get_cell_text(0), c, 'Verify that cell 0 has the copied contents.'); this.test.assertEquals(this.get_cells_length(), num_cells+3, 'Verify a the cell was added.'); + // Split and merge cells + this.select_cell(0); + this.trigger_keydown('a', 'enter'); // Create cell above and enter edit mode. + this.validate_state('a, enter', 'edit', 0); + this.trigger_keydown('a', 'b', 'c', 'd', 'left', 'left'); // Type 'abcd' and place the cursor in the middle. + this.validate_state('a, enter', 'edit', 0); + this.test.assertEquals(this.get_cell_text(0), 'abcd', 'Verify that cell 0 has the new contents.'); + this.trigger_keydown('alt+-'); // Split + this.test.assertEquals(this.get_cell_text(0), 'ab', 'split; Verify that cell 0 has the first half.'); + this.test.assertEquals(this.get_cell_text(1), 'cd', 'split; Verify that cell 1 has the second half.'); + this.validate_state('split', 'edit', 1); + this.select_cell(0); // Move up to cell 0 + this.trigger_keydown('shift+m'); // Merge + this.validate_state('merge', 'command', 0); + this.test.assertEquals(this.get_cell_text(0), 'ab\ncd', 'merge; Verify that cell 0 has the merged contents.'); + }); From daf40e9ec5a0f8536843156028312477221cdf08 Mon Sep 17 00:00:00 2001 From: Jonathan Frederic Date: Tue, 11 Mar 2014 12:58:35 -0700 Subject: [PATCH 19/38] Moved util functions into util.js --- IPython/html/tests/notebook/dualmode.js | 104 ------------------------ IPython/html/tests/util.js | 99 ++++++++++++++++++++++ 2 files changed, 99 insertions(+), 104 deletions(-) diff --git a/IPython/html/tests/notebook/dualmode.js b/IPython/html/tests/notebook/dualmode.js index b04210e89..0c1d0be4d 100644 --- a/IPython/html/tests/notebook/dualmode.js +++ b/IPython/html/tests/notebook/dualmode.js @@ -280,8 +280,6 @@ casper.notebook_test(function () { this.trigger_keydown('shift+m'); // Merge this.validate_state('merge', 'command', 0); this.test.assertEquals(this.get_cell_text(0), 'ab\ncd', 'merge; Verify that cell 0 has the merged contents.'); - - }); // Utility functions. @@ -342,106 +340,4 @@ casper.notebook_test(function () { } return true; }; - - - /* TODO: MOVE EVERYTHING BELOW THIS LINE INTO THE BASE (utils.js) */ - - - this.select_cell = function (index) { - this.evaluate(function (i) { - IPython.notebook.select(i); - }, {i: index}); - }; - - this.click_cell_editor = function(index) { - // Code Mirror does not play nicely with emulated brower events. - // Instead of trying to emulate a click, here we run code similar to - // the code used in Code Mirror that handles the mousedown event on a - // region of codemirror that the user can focus. - this.evaluate(function (i) { - cm = IPython.notebook.get_cell(i).code_mirror; - if (cm.options.readOnly != "nocursor" && (document.activeElement != cm.display.input)) - cm.display.input.focus(); - }, {i: index}); - }; - - this.focus_notebook = function() { - this.evaluate(function (){ - $('#notebook').focus(); - }, {}); - }; - - this.trigger_keydown = function() { - for (var i = 0; i < arguments.length; i++) { - this.evaluate(function (k) { - IPython.keyboard.trigger_keydown(k); - }, {k: arguments[i]}); - } - }; - - this.get_keyboard_mode = function() { - return this.evaluate(function() { - return IPython.keyboard_manager.mode; - }, {}); - }; - - this.get_notebook_mode = function() { - return this.evaluate(function() { - return IPython.notebook.mode; - }, {}); - }; - - this.get_cell = function(index) { - return this.evaluate(function(i) { - var cell = IPython.notebook.get_cell(i); - if (cell) { - return cell; - } - return null; - }, {i : index}); - }; - - this.is_cell_editor_focused = function(index) { - return this.evaluate(function(i) { - var cell = IPython.notebook.get_cell(i); - if (cell) { - return $(cell.code_mirror.getInputField()).is('.CodeMirror-focused *'); - } - return false; - }, {i : index}); - }; - - this.is_only_cell_selected = function(index) { - return this.is_only_cell_on(index, 'selected', 'unselected'); - }; - - this.is_only_cell_edit = function(index) { - return this.is_only_cell_on(index, 'edit_mode', 'command_mode'); - }; - - this.is_only_cell_on = function(i, on_class, off_class) { - var cells_length = this.get_cells_length(); - for (var j = 0; j < cells_length; j++) { - if (j === i) { - if (this.cell_has_class(j, off_class) || !this.cell_has_class(j, on_class)) { - return false; - } - } else { - if (!this.cell_has_class(j, off_class) || this.cell_has_class(j, on_class)) { - return false; - } - } - } - return true; - }; - - this.cell_has_class = function(index, classes) { - return this.evaluate(function(i, c) { - var cell = IPython.notebook.get_cell(i); - if (cell) { - return cell.element.hasClass(c); - } - return false; - }, {i : index, c: classes}); - }; }); diff --git a/IPython/html/tests/util.js b/IPython/html/tests/util.js index 63f4ada53..eb40b7635 100644 --- a/IPython/html/tests/util.js +++ b/IPython/html/tests/util.js @@ -233,6 +233,105 @@ casper.cell_element_function = function(index, selector, function_name, function }, index, selector, function_name, function_args); }; + +casper.select_cell = function(index) { + this.evaluate(function (i) { + IPython.notebook.select(i); + }, {i: index}); +}; + +casper.click_cell_editor = function(index) { + // Code Mirror does not play nicely with emulated brower events. + // Instead of trying to emulate a click, here we run code similar to + // the code used in Code Mirror that handles the mousedown event on a + // region of codemirror that the user can focus. + this.evaluate(function (i) { + cm = IPython.notebook.get_cell(i).code_mirror; + if (cm.options.readOnly != "nocursor" && (document.activeElement != cm.display.input)) + cm.display.input.focus(); + }, {i: index}); +}; + +casper.focus_notebook = function() { + this.evaluate(function (){ + $('#notebook').focus(); + }, {}); +}; + +casper.trigger_keydown = function() { + for (var i = 0; i < arguments.length; i++) { + this.evaluate(function (k) { + IPython.keyboard.trigger_keydown(k); + }, {k: arguments[i]}); + } +}; + +casper.get_keyboard_mode = function() { + return this.evaluate(function() { + return IPython.keyboard_manager.mode; + }, {}); +}; + +casper.get_notebook_mode = function() { + return this.evaluate(function() { + return IPython.notebook.mode; + }, {}); +}; + +casper.get_cell = function(index) { + return this.evaluate(function(i) { + var cell = IPython.notebook.get_cell(i); + if (cell) { + return cell; + } + return null; + }, {i : index}); +}; + +casper.is_cell_editor_focused = function(index) { + return this.evaluate(function(i) { + var cell = IPython.notebook.get_cell(i); + if (cell) { + return $(cell.code_mirror.getInputField()).is('.CodeMirror-focused *'); + } + return false; + }, {i : index}); +}; + +casper.is_only_cell_selected = function(index) { + return this.is_only_cell_on(index, 'selected', 'unselected'); +}; + +casper.is_only_cell_edit = function(index) { + return this.is_only_cell_on(index, 'edit_mode', 'command_mode'); +}; + +casper.is_only_cell_on = function(i, on_class, off_class) { + var cells_length = this.get_cells_length(); + for (var j = 0; j < cells_length; j++) { + if (j === i) { + if (this.cell_has_class(j, off_class) || !this.cell_has_class(j, on_class)) { + return false; + } + } else { + if (!this.cell_has_class(j, off_class) || this.cell_has_class(j, on_class)) { + return false; + } + } + } + return true; +}; + +casper.cell_has_class = function(index, classes) { + return this.evaluate(function(i, c) { + var cell = IPython.notebook.get_cell(i); + if (cell) { + return cell.element.hasClass(c); + } + return false; + }, {i : index, c: classes}); +}; + // Wrap a notebook test to reduce boilerplate. casper.notebook_test = function(test) { this.open_new_notebook(); From a7dcdddd5455d75858947af3a31e90dfbcb315bf Mon Sep 17 00:00:00 2001 From: Jonathan Frederic Date: Tue, 11 Mar 2014 13:31:02 -0700 Subject: [PATCH 20/38] Fixed problem with split tests, added new function that sets the codemirror instance cursor coords --- IPython/html/tests/notebook/dualmode.js | 4 ++-- IPython/html/tests/util.js | 9 ++++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/IPython/html/tests/notebook/dualmode.js b/IPython/html/tests/notebook/dualmode.js index 0c1d0be4d..8f7d54cae 100644 --- a/IPython/html/tests/notebook/dualmode.js +++ b/IPython/html/tests/notebook/dualmode.js @@ -269,8 +269,8 @@ casper.notebook_test(function () { this.select_cell(0); this.trigger_keydown('a', 'enter'); // Create cell above and enter edit mode. this.validate_state('a, enter', 'edit', 0); - this.trigger_keydown('a', 'b', 'c', 'd', 'left', 'left'); // Type 'abcd' and place the cursor in the middle. - this.validate_state('a, enter', 'edit', 0); + this.set_cell_text(0, 'abcd'); + this.set_cell_editor_cursor(0, 0, 2); this.test.assertEquals(this.get_cell_text(0), 'abcd', 'Verify that cell 0 has the new contents.'); this.trigger_keydown('alt+-'); // Split this.test.assertEquals(this.get_cell_text(0), 'ab', 'split; Verify that cell 0 has the first half.'); diff --git a/IPython/html/tests/util.js b/IPython/html/tests/util.js index eb40b7635..2ebf112ad 100644 --- a/IPython/html/tests/util.js +++ b/IPython/html/tests/util.js @@ -246,12 +246,19 @@ casper.click_cell_editor = function(index) { // the code used in Code Mirror that handles the mousedown event on a // region of codemirror that the user can focus. this.evaluate(function (i) { - cm = IPython.notebook.get_cell(i).code_mirror; + var cm = IPython.notebook.get_cell(i).code_mirror; if (cm.options.readOnly != "nocursor" && (document.activeElement != cm.display.input)) cm.display.input.focus(); }, {i: index}); }; +casper.set_cell_editor_cursor = function(index, line_index, char_index) { + // Set the Code Mirror instance cursor's location. + this.evaluate(function (i, l, c) { + IPython.notebook.get_cell(i).code_mirror.setCursor(l, c); + }, {i: index, l: line_index, c: char_index}); +}; + casper.focus_notebook = function() { this.evaluate(function (){ $('#notebook').focus(); From b9872db82b0dd74899baf0247bd6dae1d9429f12 Mon Sep 17 00:00:00 2001 From: Jonathan Frederic Date: Tue, 11 Mar 2014 14:59:17 -0700 Subject: [PATCH 21/38] HUGE speed improvements to dual mode tests --- IPython/html/tests/notebook/dualmode.js | 174 +++++++++++------------- IPython/html/tests/util.js | 15 +- 2 files changed, 89 insertions(+), 100 deletions(-) diff --git a/IPython/html/tests/notebook/dualmode.js b/IPython/html/tests/notebook/dualmode.js index 8f7d54cae..2eb2e2d26 100644 --- a/IPython/html/tests/notebook/dualmode.js +++ b/IPython/html/tests/notebook/dualmode.js @@ -15,25 +15,26 @@ casper.notebook_test(function () { this.execute_cell_then(index); this.then(function () { - this.validate_state('initial state', 'edit', 0); + this.print_log(); + this.validate_notebook_state('initial state', 'edit', 0); this.trigger_keydown('esc'); - this.validate_state('esc', 'command', 0); + this.validate_notebook_state('esc', 'command', 0); this.trigger_keydown('down'); - this.validate_state('down', 'command', 1); + this.validate_notebook_state('down', 'command', 1); this.trigger_keydown('enter'); - this.validate_state('enter', 'edit', 1); + this.validate_notebook_state('enter', 'edit', 1); this.trigger_keydown('j'); - this.validate_state('j in edit mode', 'edit', 1); + this.validate_notebook_state('j in edit mode', 'edit', 1); this.trigger_keydown('esc'); - this.validate_state('esc', 'command', 1); + this.validate_notebook_state('esc', 'command', 1); this.trigger_keydown('j'); - this.validate_state('j in command mode', 'command', 2); + this.validate_notebook_state('j in command mode', 'command', 2); this.click_cell_editor(0); - this.validate_state('click cell 0', 'edit', 0); + this.validate_notebook_state('click cell 0', 'edit', 0); this.click_cell_editor(3); - this.validate_state('click cell 3', 'edit', 3); + this.validate_notebook_state('click cell 3', 'edit', 3); this.trigger_keydown('esc'); - this.validate_state('esc', 'command', 3); + this.validate_notebook_state('esc', 'command', 3); // Open keyboard help this.evaluate(function(){ @@ -41,7 +42,7 @@ casper.notebook_test(function () { }, {}); this.trigger_keydown('k'); - this.validate_state('k in command mode while keyboard help is up', 'command', 3); + this.validate_notebook_state('k in command mode while keyboard help is up', 'command', 3); // Close keyboard help this.evaluate(function(){ @@ -49,69 +50,69 @@ casper.notebook_test(function () { }, {}); this.trigger_keydown('k'); - this.validate_state('k in command mode', 'command', 2); + this.validate_notebook_state('k in command mode', 'command', 2); this.click_cell_editor(0); - this.validate_state('click cell 0', 'edit', 0); + this.validate_notebook_state('click cell 0', 'edit', 0); this.focus_notebook(); - this.validate_state('focus #notebook', 'command', 0); + this.validate_notebook_state('focus #notebook', 'command', 0); this.click_cell_editor(0); - this.validate_state('click cell 0', 'edit', 0); + this.validate_notebook_state('click cell 0', 'edit', 0); this.focus_notebook(); - this.validate_state('focus #notebook', 'command', 0); + this.validate_notebook_state('focus #notebook', 'command', 0); this.click_cell_editor(3); - this.validate_state('click cell 3', 'edit', 3); + this.validate_notebook_state('click cell 3', 'edit', 3); // shift+enter // last cell in notebook var base_index = 3; this.trigger_keydown('shift+enter'); // Creates one cell - this.validate_state('shift+enter (no cell below)', 'edit', base_index + 1); + this.validate_notebook_state('shift+enter (no cell below)', 'edit', base_index + 1); // not last cell in notebook & starts in edit mode this.click_cell_editor(base_index); - this.validate_state('click cell ' + base_index, 'edit', base_index); + this.validate_notebook_state('click cell ' + base_index, 'edit', base_index); this.trigger_keydown('shift+enter'); - this.validate_state('shift+enter (cell exists below)', 'command', base_index + 1); + this.validate_notebook_state('shift+enter (cell exists below)', 'command', base_index + 1); // starts in command mode this.trigger_keydown('k'); - this.validate_state('k in comand mode', 'command', base_index); + this.validate_notebook_state('k in comand mode', 'command', base_index); this.trigger_keydown('shift+enter'); - this.validate_state('shift+enter (start in command mode)', 'command', base_index + 1); + this.validate_notebook_state('shift+enter (start in command mode)', 'command', base_index + 1); // ctrl+enter // last cell in notebook base_index++; this.trigger_keydown('ctrl+enter'); - this.validate_state('ctrl+enter (no cell below)', 'command', base_index); + this.validate_notebook_state('ctrl+enter (no cell below)', 'command', base_index); // not last cell in notebook & starts in edit mode this.click_cell_editor(base_index-1); - this.validate_state('click cell ' + (base_index-1), 'edit', base_index-1); + this.validate_notebook_state('click cell ' + (base_index-1), 'edit', base_index-1); this.trigger_keydown('ctrl+enter'); - this.validate_state('ctrl+enter (cell exists below)', 'command', base_index-1); + this.validate_notebook_state('ctrl+enter (cell exists below)', 'command', base_index-1); // starts in command mode this.trigger_keydown('j'); - this.validate_state('j in comand mode', 'command', base_index); + this.validate_notebook_state('j in comand mode', 'command', base_index); this.trigger_keydown('ctrl+enter'); - this.validate_state('ctrl+enter (start in command mode)', 'command', base_index); + this.validate_notebook_state('ctrl+enter (start in command mode)', 'command', base_index); // alt+enter // last cell in notebook this.trigger_keydown('alt+enter'); // Creates one cell - this.validate_state('alt+enter (no cell below)', 'edit', base_index + 1); + this.validate_notebook_state('alt+enter (no cell below)', 'edit', base_index + 1); // not last cell in notebook & starts in edit mode this.click_cell_editor(base_index); - this.validate_state('click cell ' + base_index, 'edit', base_index); + this.validate_notebook_state('click cell ' + base_index, 'edit', base_index); this.trigger_keydown('alt+enter'); // Creates one cell - this.validate_state('alt+enter (cell exists below)', 'edit', base_index + 1); + this.validate_notebook_state('alt+enter (cell exists below)', 'edit', base_index + 1); // starts in command mode this.trigger_keydown('esc', 'k'); - this.validate_state('k in comand mode', 'command', base_index); + this.validate_notebook_state('k in comand mode', 'command', base_index); this.trigger_keydown('alt+enter'); // Creates one cell - this.validate_state('alt+enter (start in command mode)', 'edit', base_index + 1); + this.validate_notebook_state('alt+enter (start in command mode)', 'edit', base_index + 1); // Notebook will now have 8 cells, the index of the last cell will be 7. this.test.assertEquals(this.get_cells_length(), 8, '*-enter commands added cells where needed.'); this.select_cell(7); - this.validate_state('click cell ' + 7 + ' and esc', 'command', 7); + this.validate_notebook_state('click cell ' + 7 + ' and esc', 'command', 7); // Cell mode change this.trigger_keydown('r'); @@ -137,7 +138,7 @@ casper.notebook_test(function () { // Cell deletion this.trigger_keydown('d', 'd'); this.test.assertEquals(this.get_cells_length(), 7, 'dd actually deletes a cell'); - this.validate_state('dd', 'command', 6); + this.validate_notebook_state('dd', 'command', 6); // Make sure that if the time between d presses is too long, nothing gets removed. this.trigger_keydown('d'); @@ -146,66 +147,66 @@ casper.notebook_test(function () { this.then(function () { this.trigger_keydown('d'); this.test.assertEquals(this.get_cells_length(), 7, "d, 1 second wait, d doesn't delete a cell"); - this.validate_state('d, 1 second wait, d', 'command', 6); + this.validate_notebook_state('d, 1 second wait, d', 'command', 6); // Up and down in command mode this.trigger_keydown('j'); - this.validate_state('j at end of notebook', 'command', 6); + this.validate_notebook_state('j at end of notebook', 'command', 6); this.trigger_keydown('down'); - this.validate_state('down at end of notebook', 'command', 6); + this.validate_notebook_state('down at end of notebook', 'command', 6); this.trigger_keydown('up'); - this.validate_state('up', 'command', 5); + this.validate_notebook_state('up', 'command', 5); this.select_cell(0); - this.validate_state('select 0', 'command', 0); + this.validate_notebook_state('select 0', 'command', 0); this.trigger_keydown('k'); - this.validate_state('k at top of notebook', 'command', 0); + this.validate_notebook_state('k at top of notebook', 'command', 0); this.trigger_keydown('up'); - this.validate_state('up at top of notebook', 'command', 0); + this.validate_notebook_state('up at top of notebook', 'command', 0); this.trigger_keydown('down'); - this.validate_state('down', 'command', 1); + this.validate_notebook_state('down', 'command', 1); // Up and down in edit mode this.click_cell_editor(6); - this.validate_state('click cell 6', 'edit', 6); + this.validate_notebook_state('click cell 6', 'edit', 6); this.trigger_keydown('down'); - this.validate_state('down at end of notebook', 'edit', 6); + this.validate_notebook_state('down at end of notebook', 'edit', 6); this.trigger_keydown('up'); - this.validate_state('up', 'edit', 5); + this.validate_notebook_state('up', 'edit', 5); this.click_cell_editor(0); - this.validate_state('click 0', 'edit', 0); + this.validate_notebook_state('click 0', 'edit', 0); this.trigger_keydown('up'); - this.validate_state('up at top of notebook', 'edit', 0); + this.validate_notebook_state('up at top of notebook', 'edit', 0); this.trigger_keydown('down'); - this.validate_state('down', 'edit', 1); + this.validate_notebook_state('down', 'edit', 1); // Markdown rendering / unredering this.select_cell(6); - this.validate_state('select 6', 'command', 6); + this.validate_notebook_state('select 6', 'command', 6); this.trigger_keydown('m'); this.test.assertEquals(this.get_cell(6).cell_type, 'markdown', 'm; cell is markdown'); this.test.assertEquals(this.get_cell(6).rendered, false, 'm; cell is rendered'); this.trigger_keydown('enter'); this.test.assertEquals(this.get_cell(6).rendered, false, 'enter; cell is unrendered'); - this.validate_state('enter', 'edit', 6); + this.validate_notebook_state('enter', 'edit', 6); this.trigger_keydown('ctrl+enter'); this.test.assertEquals(this.get_cell(6).rendered, true, 'ctrl+enter; cell is rendered'); - this.validate_state('enter', 'command', 6); + this.validate_notebook_state('enter', 'command', 6); this.trigger_keydown('enter'); this.test.assertEquals(this.get_cell(6).rendered, false, 'enter; cell is unrendered'); this.select_cell(5); this.test.assertEquals(this.get_cell(6).rendered, false, 'select 5; cell 6 is still unrendered'); - this.validate_state('select 5', 'command', 5); + this.validate_notebook_state('select 5', 'command', 5); this.select_cell(6); - this.validate_state('select 6', 'command', 6); + this.validate_notebook_state('select 6', 'command', 6); this.trigger_keydown('ctrl+enter'); this.test.assertEquals(this.get_cell(6).rendered, true, 'ctrl+enter; cell is rendered'); this.select_cell(5); - this.validate_state('select 5', 'command', 5); + this.validate_notebook_state('select 5', 'command', 5); this.trigger_keydown('shift+enter'); - this.validate_state('shift+enter', 'command', 6); + this.validate_notebook_state('shift+enter', 'command', 6); this.test.assertEquals(this.get_cell(6).rendered, true, 'shift+enter; cell is rendered'); this.trigger_keydown('shift+enter'); // Creates one cell - this.validate_state('shift+enter', 'edit', 7); + this.validate_notebook_state('shift+enter', 'edit', 7); this.test.assertEquals(this.get_cell(6).rendered, true, 'shift+enter; cell is rendered'); // Cell movement ( ctrl+(k or j) ) @@ -214,81 +215,79 @@ casper.notebook_test(function () { this.trigger_keydown('ctrl+k'); // Move cell 2 up one this.test.assertEquals(this.get_cell_text(1), b, 'ctrl+k; Cell 1 text is correct'); this.test.assertEquals(this.get_cell_text(2), a, 'ctrl+k; Cell 2 text is correct'); - this.validate_state('ctrl+k', 'command', 1); + this.validate_notebook_state('ctrl+k', 'command', 1); this.trigger_keydown('ctrl+j'); // Move cell 1 down one this.test.assertEquals(this.get_cell_text(1), a, 'ctrl+j; Cell 1 text is correct'); this.test.assertEquals(this.get_cell_text(2), b, 'ctrl+j; Cell 2 text is correct'); - this.validate_state('ctrl+j', 'command', 2); + this.validate_notebook_state('ctrl+j', 'command', 2); // Cell insertion this.trigger_keydown('a'); // Creates one cell this.test.assertEquals(this.get_cell_text(2), '', 'a; New cell 2 text is empty'); - this.validate_state('a', 'command', 2); + this.validate_notebook_state('a', 'command', 2); this.trigger_keydown('b'); // Creates one cell this.test.assertEquals(this.get_cell_text(2), '', 'b; Cell 2 text is still empty'); this.test.assertEquals(this.get_cell_text(3), '', 'b; New cell 3 text is empty'); - this.validate_state('b', 'command', 3); + this.validate_notebook_state('b', 'command', 3); // Copy/paste/cut var num_cells = this.get_cells_length(); this.test.assertEquals(this.get_cell_text(1), a, 'Verify that cell 1 is a'); this.select_cell(1); this.trigger_keydown('x'); // Cut - this.validate_state('x', 'command', 1); + this.validate_notebook_state('x', 'command', 1); this.test.assertEquals(this.get_cells_length(), num_cells-1, 'Verify that a cell was removed.'); this.test.assertEquals(this.get_cell_text(1), '', 'Verify that cell 2 is now where cell 1 was.'); this.select_cell(2); this.trigger_keydown('v'); // Paste - this.validate_state('v', 'command', 3); // Selection should move to pasted cell, below current cell. + this.validate_notebook_state('v', 'command', 3); // Selection should move to pasted cell, below current cell. this.test.assertEquals(this.get_cell_text(3), a, 'Verify that cell 3 has the cut contents.'); this.test.assertEquals(this.get_cells_length(), num_cells, 'Verify a the cell was added.'); this.trigger_keydown('v'); // Paste - this.validate_state('v', 'command', 4); // Selection should move to pasted cell, below current cell. + this.validate_notebook_state('v', 'command', 4); // Selection should move to pasted cell, below current cell. this.test.assertEquals(this.get_cell_text(4), a, 'Verify that cell 4 has the cut contents.'); this.test.assertEquals(this.get_cells_length(), num_cells+1, 'Verify a the cell was added.'); this.select_cell(5); this.trigger_keydown('c'); // Copy - this.validate_state('c', 'command', 5); + this.validate_notebook_state('c', 'command', 5); this.test.assertEquals(this.get_cell_text(5), b, 'Verify that cell 5 is b'); this.select_cell(6); this.trigger_keydown('c'); // Copy - this.validate_state('c', 'command', 6); + this.validate_notebook_state('c', 'command', 6); this.test.assertEquals(this.get_cell_text(6), c, 'Verify that cell 6 is c'); this.trigger_keydown('v'); // Paste - this.validate_state('v', 'command', 7); + this.validate_notebook_state('v', 'command', 7); this.test.assertEquals(this.get_cell_text(6), c, 'Verify that cell 6 still has the copied contents.'); this.test.assertEquals(this.get_cell_text(7), c, 'Verify that cell 7 has the copied contents.'); this.test.assertEquals(this.get_cells_length(), num_cells+2, 'Verify a the cell was added.'); this.select_cell(0); this.trigger_keydown('shift+v'); // Paste - this.validate_state('shift+v', 'command', 0); + this.validate_notebook_state('shift+v', 'command', 0); this.test.assertEquals(this.get_cell_text(0), c, 'Verify that cell 0 has the copied contents.'); this.test.assertEquals(this.get_cells_length(), num_cells+3, 'Verify a the cell was added.'); // Split and merge cells this.select_cell(0); this.trigger_keydown('a', 'enter'); // Create cell above and enter edit mode. - this.validate_state('a, enter', 'edit', 0); + this.validate_notebook_state('a, enter', 'edit', 0); this.set_cell_text(0, 'abcd'); this.set_cell_editor_cursor(0, 0, 2); this.test.assertEquals(this.get_cell_text(0), 'abcd', 'Verify that cell 0 has the new contents.'); this.trigger_keydown('alt+-'); // Split this.test.assertEquals(this.get_cell_text(0), 'ab', 'split; Verify that cell 0 has the first half.'); this.test.assertEquals(this.get_cell_text(1), 'cd', 'split; Verify that cell 1 has the second half.'); - this.validate_state('split', 'edit', 1); + this.validate_notebook_state('split', 'edit', 1); this.select_cell(0); // Move up to cell 0 this.trigger_keydown('shift+m'); // Merge - this.validate_state('merge', 'command', 0); + this.validate_notebook_state('merge', 'command', 0); this.test.assertEquals(this.get_cell_text(0), 'ab\ncd', 'merge; Verify that cell 0 has the merged contents.'); }); // Utility functions. - this.validate_state = function(message, mode, cell_index) { + this.validate_notebook_state = function(message, mode, cell_index) { // General tests. this.test.assertEquals(this.get_keyboard_mode(), this.get_notebook_mode(), message + '; keyboard and notebook modes match'); - // Is codemirror focused appropriately? - this.test.assert(this.is_editor_focus_valid(), message + '; cell editor focused appropriately'); // Is the selected cell the only cell that is selected? if (cell_index!==undefined) { this.test.assert(this.is_only_cell_selected(cell_index), @@ -303,41 +302,24 @@ casper.notebook_test(function () { // Make sure there isn't a single cell in edit mode. this.test.assert(this.is_only_cell_edit(null), message + '; all cells in command mode'); + this.test.assert(this.is_cell_editor_focused(null), + message + '; no cell editors are focused while in command mode'); } else if (mode==='edit') { // Are the notebook and keyboard manager in edit mode? this.test.assertEquals(this.get_keyboard_mode(), 'edit', message + '; in edit mode'); - // Is the specified cell the only cell in edit mode? if (cell_index!==undefined) { + // Is the specified cell the only cell in edit mode? this.test.assert(this.is_only_cell_edit(cell_index), message + '; cell ' + cell_index + ' is the only cell in edit mode'); + // Is the specified cell the only cell with a focused code mirror? + this.test.assert(this.is_cell_editor_focused(cell_index), + message + '; cell ' + cell_index + '\'s editor is appropriately focused'); } } else { this.test.assert(false, message + '; ' + mode + ' is an unknown mode'); } }; - - this.is_editor_focus_valid = function() { - var cells_length = this.get_cells_length(); - for (var i = 0; i < cells_length; i++) { - if (!this.is_cell_editor_focus_valid(i)) { - return false; - } - } - return true; - }; - - this.is_cell_editor_focus_valid = function(index) { - var cell = this.get_cell(index); - if (cell) { - if (cell.mode == 'edit') { - return this.is_cell_editor_focused(index); - } else { - return !this.is_cell_editor_focused(index); - } - } - return true; - }; }); diff --git a/IPython/html/tests/util.js b/IPython/html/tests/util.js index 2ebf112ad..6ee0341b3 100644 --- a/IPython/html/tests/util.js +++ b/IPython/html/tests/util.js @@ -296,10 +296,17 @@ casper.get_cell = function(index) { }; casper.is_cell_editor_focused = function(index) { + // Make sure a cell's editor is the only editor focused on the page. return this.evaluate(function(i) { - var cell = IPython.notebook.get_cell(i); - if (cell) { - return $(cell.code_mirror.getInputField()).is('.CodeMirror-focused *'); + var focused_textarea = $('#notebook .CodeMirror-focused textarea'); + if (focused_textarea.length > 1) { throw 'More than one Code Mirror editor is focused at once!'; } + if (i === null) { + return focused_textarea.length === 0; + } else { + var cell = IPython.notebook.get_cell(i); + if (cell) { + return cell.code_mirror.getInputField() == focused_textarea[0]; + } } return false; }, {i : index}); @@ -399,7 +406,7 @@ casper.on('waitFor.timeout', function onWaitForTimeout(timeout) { }); // Pass `console.log` calls from page JS to casper. -casper.printLog = function () { +casper.print_log = function () { this.on('remote.message', function(msg) { this.echo('Remote message caught: ' + msg); }); From 0262b724fc324a83d57810162348f228d260d229 Mon Sep 17 00:00:00 2001 From: Jonathan Frederic Date: Tue, 11 Mar 2014 15:01:23 -0700 Subject: [PATCH 22/38] Move validate notebook state into utils --- IPython/html/tests/notebook/dualmode.js | 40 ------------------------- IPython/html/tests/util.js | 38 +++++++++++++++++++++++ 2 files changed, 38 insertions(+), 40 deletions(-) diff --git a/IPython/html/tests/notebook/dualmode.js b/IPython/html/tests/notebook/dualmode.js index 2eb2e2d26..8e218ea67 100644 --- a/IPython/html/tests/notebook/dualmode.js +++ b/IPython/html/tests/notebook/dualmode.js @@ -282,44 +282,4 @@ casper.notebook_test(function () { this.validate_notebook_state('merge', 'command', 0); this.test.assertEquals(this.get_cell_text(0), 'ab\ncd', 'merge; Verify that cell 0 has the merged contents.'); }); - - // Utility functions. - this.validate_notebook_state = function(message, mode, cell_index) { - // General tests. - this.test.assertEquals(this.get_keyboard_mode(), this.get_notebook_mode(), - message + '; keyboard and notebook modes match'); - // Is the selected cell the only cell that is selected? - if (cell_index!==undefined) { - this.test.assert(this.is_only_cell_selected(cell_index), - message + '; cell ' + cell_index + ' is the only cell selected'); - } - - // Mode specific tests. - if (mode==='command') { - // Are the notebook and keyboard manager in command mode? - this.test.assertEquals(this.get_keyboard_mode(), 'command', - message + '; in command mode'); - // Make sure there isn't a single cell in edit mode. - this.test.assert(this.is_only_cell_edit(null), - message + '; all cells in command mode'); - this.test.assert(this.is_cell_editor_focused(null), - message + '; no cell editors are focused while in command mode'); - - } else if (mode==='edit') { - // Are the notebook and keyboard manager in edit mode? - this.test.assertEquals(this.get_keyboard_mode(), 'edit', - message + '; in edit mode'); - if (cell_index!==undefined) { - // Is the specified cell the only cell in edit mode? - this.test.assert(this.is_only_cell_edit(cell_index), - message + '; cell ' + cell_index + ' is the only cell in edit mode'); - // Is the specified cell the only cell with a focused code mirror? - this.test.assert(this.is_cell_editor_focused(cell_index), - message + '; cell ' + cell_index + '\'s editor is appropriately focused'); - } - - } else { - this.test.assert(false, message + '; ' + mode + ' is an unknown mode'); - } - }; }); diff --git a/IPython/html/tests/util.js b/IPython/html/tests/util.js index 6ee0341b3..836b717f2 100644 --- a/IPython/html/tests/util.js +++ b/IPython/html/tests/util.js @@ -233,6 +233,44 @@ casper.cell_element_function = function(index, selector, function_name, function }, index, selector, function_name, function_args); }; +casper.validate_notebook_state = function(message, mode, cell_index) { + // General tests. + this.test.assertEquals(this.get_keyboard_mode(), this.get_notebook_mode(), + message + '; keyboard and notebook modes match'); + // Is the selected cell the only cell that is selected? + if (cell_index!==undefined) { + this.test.assert(this.is_only_cell_selected(cell_index), + message + '; cell ' + cell_index + ' is the only cell selected'); + } + + // Mode specific tests. + if (mode==='command') { + // Are the notebook and keyboard manager in command mode? + this.test.assertEquals(this.get_keyboard_mode(), 'command', + message + '; in command mode'); + // Make sure there isn't a single cell in edit mode. + this.test.assert(this.is_only_cell_edit(null), + message + '; all cells in command mode'); + this.test.assert(this.is_cell_editor_focused(null), + message + '; no cell editors are focused while in command mode'); + + } else if (mode==='edit') { + // Are the notebook and keyboard manager in edit mode? + this.test.assertEquals(this.get_keyboard_mode(), 'edit', + message + '; in edit mode'); + if (cell_index!==undefined) { + // Is the specified cell the only cell in edit mode? + this.test.assert(this.is_only_cell_edit(cell_index), + message + '; cell ' + cell_index + ' is the only cell in edit mode'); + // Is the specified cell the only cell with a focused code mirror? + this.test.assert(this.is_cell_editor_focused(cell_index), + message + '; cell ' + cell_index + '\'s editor is appropriately focused'); + } + + } else { + this.test.assert(false, message + '; ' + mode + ' is an unknown mode'); + } +}; casper.select_cell = function(index) { this.evaluate(function (i) { From 1f4db77aec540323ea68fdb7f9b0bea7ee1ed199 Mon Sep 17 00:00:00 2001 From: Jonathan Frederic Date: Tue, 11 Mar 2014 17:00:46 -0700 Subject: [PATCH 23/38] Cleaned up test names and locations. --- IPython/html/tests/notebook/dualmode.js | 217 +----------------- .../html/tests/notebook/dualmode_arrows.js | 49 ++++ .../tests/notebook/dualmode_cellinsert.js | 27 +++ .../html/tests/notebook/dualmode_cellmode.js | 28 +++ .../html/tests/notebook/dualmode_clipboard.js | 55 +++++ .../html/tests/notebook/dualmode_execute.js | 72 ++++++ .../html/tests/notebook/dualmode_markdown.js | 39 ++++ IPython/html/tests/notebook/dualmode_merge.js | 21 ++ .../{merge_cells.js => merge_cells_api.js} | 0 9 files changed, 296 insertions(+), 212 deletions(-) create mode 100644 IPython/html/tests/notebook/dualmode_arrows.js create mode 100644 IPython/html/tests/notebook/dualmode_cellinsert.js create mode 100644 IPython/html/tests/notebook/dualmode_cellmode.js create mode 100644 IPython/html/tests/notebook/dualmode_clipboard.js create mode 100644 IPython/html/tests/notebook/dualmode_execute.js create mode 100644 IPython/html/tests/notebook/dualmode_markdown.js create mode 100644 IPython/html/tests/notebook/dualmode_merge.js rename IPython/html/tests/notebook/{merge_cells.js => merge_cells_api.js} (100%) diff --git a/IPython/html/tests/notebook/dualmode.js b/IPython/html/tests/notebook/dualmode.js index 8e218ea67..87b556765 100644 --- a/IPython/html/tests/notebook/dualmode.js +++ b/IPython/html/tests/notebook/dualmode.js @@ -15,7 +15,6 @@ casper.notebook_test(function () { this.execute_cell_then(index); this.then(function () { - this.print_log(); this.validate_notebook_state('initial state', 'edit', 0); this.trigger_keydown('esc'); this.validate_notebook_state('esc', 'command', 0); @@ -62,83 +61,10 @@ casper.notebook_test(function () { this.click_cell_editor(3); this.validate_notebook_state('click cell 3', 'edit', 3); - // shift+enter - // last cell in notebook - var base_index = 3; - this.trigger_keydown('shift+enter'); // Creates one cell - this.validate_notebook_state('shift+enter (no cell below)', 'edit', base_index + 1); - // not last cell in notebook & starts in edit mode - this.click_cell_editor(base_index); - this.validate_notebook_state('click cell ' + base_index, 'edit', base_index); - this.trigger_keydown('shift+enter'); - this.validate_notebook_state('shift+enter (cell exists below)', 'command', base_index + 1); - // starts in command mode - this.trigger_keydown('k'); - this.validate_notebook_state('k in comand mode', 'command', base_index); - this.trigger_keydown('shift+enter'); - this.validate_notebook_state('shift+enter (start in command mode)', 'command', base_index + 1); - - // ctrl+enter - // last cell in notebook - base_index++; - this.trigger_keydown('ctrl+enter'); - this.validate_notebook_state('ctrl+enter (no cell below)', 'command', base_index); - // not last cell in notebook & starts in edit mode - this.click_cell_editor(base_index-1); - this.validate_notebook_state('click cell ' + (base_index-1), 'edit', base_index-1); - this.trigger_keydown('ctrl+enter'); - this.validate_notebook_state('ctrl+enter (cell exists below)', 'command', base_index-1); - // starts in command mode - this.trigger_keydown('j'); - this.validate_notebook_state('j in comand mode', 'command', base_index); - this.trigger_keydown('ctrl+enter'); - this.validate_notebook_state('ctrl+enter (start in command mode)', 'command', base_index); - - // alt+enter - // last cell in notebook - this.trigger_keydown('alt+enter'); // Creates one cell - this.validate_notebook_state('alt+enter (no cell below)', 'edit', base_index + 1); - // not last cell in notebook & starts in edit mode - this.click_cell_editor(base_index); - this.validate_notebook_state('click cell ' + base_index, 'edit', base_index); - this.trigger_keydown('alt+enter'); // Creates one cell - this.validate_notebook_state('alt+enter (cell exists below)', 'edit', base_index + 1); - // starts in command mode - this.trigger_keydown('esc', 'k'); - this.validate_notebook_state('k in comand mode', 'command', base_index); - this.trigger_keydown('alt+enter'); // Creates one cell - this.validate_notebook_state('alt+enter (start in command mode)', 'edit', base_index + 1); - - // Notebook will now have 8 cells, the index of the last cell will be 7. - this.test.assertEquals(this.get_cells_length(), 8, '*-enter commands added cells where needed.'); - this.select_cell(7); - this.validate_notebook_state('click cell ' + 7 + ' and esc', 'command', 7); - - // Cell mode change - this.trigger_keydown('r'); - this.test.assertEquals(this.get_cell(7).cell_type, 'raw', 'r; cell is raw'); - this.trigger_keydown('1'); - this.test.assertEquals(this.get_cell(7).cell_type, 'heading', '1; cell is heading'); - this.test.assertEquals(this.get_cell(7).level, 1, '1; cell is level 1 heading'); - this.trigger_keydown('2'); - this.test.assertEquals(this.get_cell(7).level, 2, '2; cell is level 2 heading'); - this.trigger_keydown('3'); - this.test.assertEquals(this.get_cell(7).level, 3, '3; cell is level 3 heading'); - this.trigger_keydown('4'); - this.test.assertEquals(this.get_cell(7).level, 4, '4; cell is level 4 heading'); - this.trigger_keydown('5'); - this.test.assertEquals(this.get_cell(7).level, 5, '5; cell is level 5 heading'); - this.trigger_keydown('6'); - this.test.assertEquals(this.get_cell(7).level, 6, '6; cell is level 6 heading'); - this.trigger_keydown('m'); - this.test.assertEquals(this.get_cell(7).cell_type, 'markdown', 'm; cell is markdown'); - this.trigger_keydown('y'); - this.test.assertEquals(this.get_cell(7).cell_type, 'code', 'y; cell is code'); - // Cell deletion - this.trigger_keydown('d', 'd'); - this.test.assertEquals(this.get_cells_length(), 7, 'dd actually deletes a cell'); - this.validate_notebook_state('dd', 'command', 6); + this.trigger_keydown('esc', 'd', 'd'); + this.test.assertEquals(this.get_cells_length(), 3, 'dd actually deletes a cell'); + this.validate_notebook_state('dd', 'command', 2); // Make sure that if the time between d presses is too long, nothing gets removed. this.trigger_keydown('d'); @@ -146,140 +72,7 @@ casper.notebook_test(function () { this.wait(1000); this.then(function () { this.trigger_keydown('d'); - this.test.assertEquals(this.get_cells_length(), 7, "d, 1 second wait, d doesn't delete a cell"); - this.validate_notebook_state('d, 1 second wait, d', 'command', 6); - - // Up and down in command mode - this.trigger_keydown('j'); - this.validate_notebook_state('j at end of notebook', 'command', 6); - this.trigger_keydown('down'); - this.validate_notebook_state('down at end of notebook', 'command', 6); - this.trigger_keydown('up'); - this.validate_notebook_state('up', 'command', 5); - this.select_cell(0); - this.validate_notebook_state('select 0', 'command', 0); - this.trigger_keydown('k'); - this.validate_notebook_state('k at top of notebook', 'command', 0); - this.trigger_keydown('up'); - this.validate_notebook_state('up at top of notebook', 'command', 0); - this.trigger_keydown('down'); - this.validate_notebook_state('down', 'command', 1); - - // Up and down in edit mode - this.click_cell_editor(6); - this.validate_notebook_state('click cell 6', 'edit', 6); - this.trigger_keydown('down'); - this.validate_notebook_state('down at end of notebook', 'edit', 6); - this.trigger_keydown('up'); - this.validate_notebook_state('up', 'edit', 5); - this.click_cell_editor(0); - this.validate_notebook_state('click 0', 'edit', 0); - this.trigger_keydown('up'); - this.validate_notebook_state('up at top of notebook', 'edit', 0); - this.trigger_keydown('down'); - this.validate_notebook_state('down', 'edit', 1); - - // Markdown rendering / unredering - this.select_cell(6); - this.validate_notebook_state('select 6', 'command', 6); - this.trigger_keydown('m'); - this.test.assertEquals(this.get_cell(6).cell_type, 'markdown', 'm; cell is markdown'); - this.test.assertEquals(this.get_cell(6).rendered, false, 'm; cell is rendered'); - this.trigger_keydown('enter'); - this.test.assertEquals(this.get_cell(6).rendered, false, 'enter; cell is unrendered'); - this.validate_notebook_state('enter', 'edit', 6); - this.trigger_keydown('ctrl+enter'); - this.test.assertEquals(this.get_cell(6).rendered, true, 'ctrl+enter; cell is rendered'); - this.validate_notebook_state('enter', 'command', 6); - this.trigger_keydown('enter'); - this.test.assertEquals(this.get_cell(6).rendered, false, 'enter; cell is unrendered'); - this.select_cell(5); - this.test.assertEquals(this.get_cell(6).rendered, false, 'select 5; cell 6 is still unrendered'); - this.validate_notebook_state('select 5', 'command', 5); - this.select_cell(6); - this.validate_notebook_state('select 6', 'command', 6); - this.trigger_keydown('ctrl+enter'); - this.test.assertEquals(this.get_cell(6).rendered, true, 'ctrl+enter; cell is rendered'); - this.select_cell(5); - this.validate_notebook_state('select 5', 'command', 5); - this.trigger_keydown('shift+enter'); - this.validate_notebook_state('shift+enter', 'command', 6); - this.test.assertEquals(this.get_cell(6).rendered, true, 'shift+enter; cell is rendered'); - this.trigger_keydown('shift+enter'); // Creates one cell - this.validate_notebook_state('shift+enter', 'edit', 7); - this.test.assertEquals(this.get_cell(6).rendered, true, 'shift+enter; cell is rendered'); - - // Cell movement ( ctrl+(k or j) ) - this.select_cell(2); - this.test.assertEquals(this.get_cell_text(2), b, 'select 2; Cell 2 text is correct'); - this.trigger_keydown('ctrl+k'); // Move cell 2 up one - this.test.assertEquals(this.get_cell_text(1), b, 'ctrl+k; Cell 1 text is correct'); - this.test.assertEquals(this.get_cell_text(2), a, 'ctrl+k; Cell 2 text is correct'); - this.validate_notebook_state('ctrl+k', 'command', 1); - this.trigger_keydown('ctrl+j'); // Move cell 1 down one - this.test.assertEquals(this.get_cell_text(1), a, 'ctrl+j; Cell 1 text is correct'); - this.test.assertEquals(this.get_cell_text(2), b, 'ctrl+j; Cell 2 text is correct'); - this.validate_notebook_state('ctrl+j', 'command', 2); - - // Cell insertion - this.trigger_keydown('a'); // Creates one cell - this.test.assertEquals(this.get_cell_text(2), '', 'a; New cell 2 text is empty'); - this.validate_notebook_state('a', 'command', 2); - this.trigger_keydown('b'); // Creates one cell - this.test.assertEquals(this.get_cell_text(2), '', 'b; Cell 2 text is still empty'); - this.test.assertEquals(this.get_cell_text(3), '', 'b; New cell 3 text is empty'); - this.validate_notebook_state('b', 'command', 3); - - // Copy/paste/cut - var num_cells = this.get_cells_length(); - this.test.assertEquals(this.get_cell_text(1), a, 'Verify that cell 1 is a'); - this.select_cell(1); - this.trigger_keydown('x'); // Cut - this.validate_notebook_state('x', 'command', 1); - this.test.assertEquals(this.get_cells_length(), num_cells-1, 'Verify that a cell was removed.'); - this.test.assertEquals(this.get_cell_text(1), '', 'Verify that cell 2 is now where cell 1 was.'); - this.select_cell(2); - this.trigger_keydown('v'); // Paste - this.validate_notebook_state('v', 'command', 3); // Selection should move to pasted cell, below current cell. - this.test.assertEquals(this.get_cell_text(3), a, 'Verify that cell 3 has the cut contents.'); - this.test.assertEquals(this.get_cells_length(), num_cells, 'Verify a the cell was added.'); - this.trigger_keydown('v'); // Paste - this.validate_notebook_state('v', 'command', 4); // Selection should move to pasted cell, below current cell. - this.test.assertEquals(this.get_cell_text(4), a, 'Verify that cell 4 has the cut contents.'); - this.test.assertEquals(this.get_cells_length(), num_cells+1, 'Verify a the cell was added.'); - this.select_cell(5); - this.trigger_keydown('c'); // Copy - this.validate_notebook_state('c', 'command', 5); - this.test.assertEquals(this.get_cell_text(5), b, 'Verify that cell 5 is b'); - this.select_cell(6); - this.trigger_keydown('c'); // Copy - this.validate_notebook_state('c', 'command', 6); - this.test.assertEquals(this.get_cell_text(6), c, 'Verify that cell 6 is c'); - this.trigger_keydown('v'); // Paste - this.validate_notebook_state('v', 'command', 7); - this.test.assertEquals(this.get_cell_text(6), c, 'Verify that cell 6 still has the copied contents.'); - this.test.assertEquals(this.get_cell_text(7), c, 'Verify that cell 7 has the copied contents.'); - this.test.assertEquals(this.get_cells_length(), num_cells+2, 'Verify a the cell was added.'); - this.select_cell(0); - this.trigger_keydown('shift+v'); // Paste - this.validate_notebook_state('shift+v', 'command', 0); - this.test.assertEquals(this.get_cell_text(0), c, 'Verify that cell 0 has the copied contents.'); - this.test.assertEquals(this.get_cells_length(), num_cells+3, 'Verify a the cell was added.'); - - // Split and merge cells - this.select_cell(0); - this.trigger_keydown('a', 'enter'); // Create cell above and enter edit mode. - this.validate_notebook_state('a, enter', 'edit', 0); - this.set_cell_text(0, 'abcd'); - this.set_cell_editor_cursor(0, 0, 2); - this.test.assertEquals(this.get_cell_text(0), 'abcd', 'Verify that cell 0 has the new contents.'); - this.trigger_keydown('alt+-'); // Split - this.test.assertEquals(this.get_cell_text(0), 'ab', 'split; Verify that cell 0 has the first half.'); - this.test.assertEquals(this.get_cell_text(1), 'cd', 'split; Verify that cell 1 has the second half.'); - this.validate_notebook_state('split', 'edit', 1); - this.select_cell(0); // Move up to cell 0 - this.trigger_keydown('shift+m'); // Merge - this.validate_notebook_state('merge', 'command', 0); - this.test.assertEquals(this.get_cell_text(0), 'ab\ncd', 'merge; Verify that cell 0 has the merged contents.'); + this.test.assertEquals(this.get_cells_length(), 3, "d, 1 second wait, d doesn't delete a cell"); + this.validate_notebook_state('d, 1 second wait, d', 'command', 2); }); }); diff --git a/IPython/html/tests/notebook/dualmode_arrows.js b/IPython/html/tests/notebook/dualmode_arrows.js new file mode 100644 index 000000000..4b839ac8a --- /dev/null +++ b/IPython/html/tests/notebook/dualmode_arrows.js @@ -0,0 +1,49 @@ + +// Test +casper.notebook_test(function () { + var a = 'print("a")'; + var index = this.append_cell(a); + this.execute_cell_then(index); + + var b = 'print("b")'; + index = this.append_cell(b); + this.execute_cell_then(index); + + var c = 'print("c")'; + index = this.append_cell(c); + this.execute_cell_then(index); + + this.then(function () { + + // Up and down in command mode + this.select_cell(3); + this.trigger_keydown('j'); + this.validate_notebook_state('j at end of notebook', 'command', 3); + this.trigger_keydown('down'); + this.validate_notebook_state('down at end of notebook', 'command', 3); + this.trigger_keydown('up'); + this.validate_notebook_state('up', 'command', 2); + this.select_cell(0); + this.validate_notebook_state('select 0', 'command', 0); + this.trigger_keydown('k'); + this.validate_notebook_state('k at top of notebook', 'command', 0); + this.trigger_keydown('up'); + this.validate_notebook_state('up at top of notebook', 'command', 0); + this.trigger_keydown('down'); + this.validate_notebook_state('down', 'command', 1); + + // Up and down in edit mode + this.click_cell_editor(3); + this.validate_notebook_state('click cell 3', 'edit', 3); + this.trigger_keydown('down'); + this.validate_notebook_state('down at end of notebook', 'edit', 3); + this.trigger_keydown('up'); + this.validate_notebook_state('up', 'edit', 2); + this.click_cell_editor(0); + this.validate_notebook_state('click 0', 'edit', 0); + this.trigger_keydown('up'); + this.validate_notebook_state('up at top of notebook', 'edit', 0); + this.trigger_keydown('down'); + this.validate_notebook_state('down', 'edit', 1); + }); +}); diff --git a/IPython/html/tests/notebook/dualmode_cellinsert.js b/IPython/html/tests/notebook/dualmode_cellinsert.js new file mode 100644 index 000000000..59b89a329 --- /dev/null +++ b/IPython/html/tests/notebook/dualmode_cellinsert.js @@ -0,0 +1,27 @@ + +// Test +casper.notebook_test(function () { + var a = 'print("a")'; + var index = this.append_cell(a); + this.execute_cell_then(index); + + var b = 'print("b")'; + index = this.append_cell(b); + this.execute_cell_then(index); + + var c = 'print("c")'; + index = this.append_cell(c); + this.execute_cell_then(index); + + this.then(function () { + // Cell insertion + this.select_cell(2); + this.trigger_keydown('a'); // Creates one cell + this.test.assertEquals(this.get_cell_text(2), '', 'a; New cell 2 text is empty'); + this.validate_notebook_state('a', 'command', 2); + this.trigger_keydown('b'); // Creates one cell + this.test.assertEquals(this.get_cell_text(2), '', 'b; Cell 2 text is still empty'); + this.test.assertEquals(this.get_cell_text(3), '', 'b; New cell 3 text is empty'); + this.validate_notebook_state('b', 'command', 3); + }); +}); \ No newline at end of file diff --git a/IPython/html/tests/notebook/dualmode_cellmode.js b/IPython/html/tests/notebook/dualmode_cellmode.js new file mode 100644 index 000000000..d4bf5f018 --- /dev/null +++ b/IPython/html/tests/notebook/dualmode_cellmode.js @@ -0,0 +1,28 @@ +// Test keyboard shortcuts that change the cell's mode. + +// Test +casper.notebook_test(function () { + this.then(function () { + // Cell mode change + this.select_cell(0); + this.trigger_keydown('esc','r'); + this.test.assertEquals(this.get_cell(0).cell_type, 'raw', 'r; cell is raw'); + this.trigger_keydown('1'); + this.test.assertEquals(this.get_cell(0).cell_type, 'heading', '1; cell is heading'); + this.test.assertEquals(this.get_cell(0).level, 1, '1; cell is level 1 heading'); + this.trigger_keydown('2'); + this.test.assertEquals(this.get_cell(0).level, 2, '2; cell is level 2 heading'); + this.trigger_keydown('3'); + this.test.assertEquals(this.get_cell(0).level, 3, '3; cell is level 3 heading'); + this.trigger_keydown('4'); + this.test.assertEquals(this.get_cell(0).level, 4, '4; cell is level 4 heading'); + this.trigger_keydown('5'); + this.test.assertEquals(this.get_cell(0).level, 5, '5; cell is level 5 heading'); + this.trigger_keydown('6'); + this.test.assertEquals(this.get_cell(0).level, 6, '6; cell is level 6 heading'); + this.trigger_keydown('m'); + this.test.assertEquals(this.get_cell(0).cell_type, 'markdown', 'm; cell is markdown'); + this.trigger_keydown('y'); + this.test.assertEquals(this.get_cell(0).cell_type, 'code', 'y; cell is code'); + }); +}); \ No newline at end of file diff --git a/IPython/html/tests/notebook/dualmode_clipboard.js b/IPython/html/tests/notebook/dualmode_clipboard.js new file mode 100644 index 000000000..3bda68dba --- /dev/null +++ b/IPython/html/tests/notebook/dualmode_clipboard.js @@ -0,0 +1,55 @@ + + +// Test +casper.notebook_test(function () { + var a = 'print("a")'; + var index = this.append_cell(a); + this.execute_cell_then(index); + + var b = 'print("b")'; + index = this.append_cell(b); + this.execute_cell_then(index); + + var c = 'print("c")'; + index = this.append_cell(c); + this.execute_cell_then(index); + + this.then(function () { + // Copy/paste/cut + var num_cells = this.get_cells_length(); + this.test.assertEquals(this.get_cell_text(1), a, 'Verify that cell 1 is a'); + this.select_cell(1); + this.trigger_keydown('x'); // Cut + this.validate_notebook_state('x', 'command', 1); + this.test.assertEquals(this.get_cells_length(), num_cells-1, 'Verify that a cell was removed.'); + this.test.assertEquals(this.get_cell_text(1), b, 'Verify that cell 2 is now where cell 1 was.'); + this.select_cell(2); + this.trigger_keydown('v'); // Paste + this.validate_notebook_state('v', 'command', 3); // Selection should move to pasted cell, below current cell. + this.test.assertEquals(this.get_cell_text(3), a, 'Verify that cell 3 has the cut contents.'); + this.test.assertEquals(this.get_cells_length(), num_cells, 'Verify a the cell was added.'); + this.trigger_keydown('v'); // Paste + this.validate_notebook_state('v', 'command', 4); // Selection should move to pasted cell, below current cell. + this.test.assertEquals(this.get_cell_text(4), a, 'Verify that cell 4 has the cut contents.'); + this.test.assertEquals(this.get_cells_length(), num_cells+1, 'Verify a the cell was added.'); + this.select_cell(1); + this.trigger_keydown('c'); // Copy + this.validate_notebook_state('c', 'command', 1); + this.test.assertEquals(this.get_cell_text(1), b, 'Verify that cell 1 is b'); + this.select_cell(2); + this.trigger_keydown('c'); // Copy + this.validate_notebook_state('c', 'command', 2); + this.test.assertEquals(this.get_cell_text(2), c, 'Verify that cell 2 is c'); + this.select_cell(4); + this.trigger_keydown('v'); // Paste + this.validate_notebook_state('v', 'command', 5); + this.test.assertEquals(this.get_cell_text(2), c, 'Verify that cell 2 still has the copied contents.'); + this.test.assertEquals(this.get_cell_text(5), c, 'Verify that cell 5 has the copied contents.'); + this.test.assertEquals(this.get_cells_length(), num_cells+2, 'Verify a the cell was added.'); + this.select_cell(0); + this.trigger_keydown('shift+v'); // Paste + this.validate_notebook_state('shift+v', 'command', 0); + this.test.assertEquals(this.get_cell_text(0), c, 'Verify that cell 0 has the copied contents.'); + this.test.assertEquals(this.get_cells_length(), num_cells+3, 'Verify a the cell was added.'); + }); +}); \ No newline at end of file diff --git a/IPython/html/tests/notebook/dualmode_execute.js b/IPython/html/tests/notebook/dualmode_execute.js new file mode 100644 index 000000000..750486efb --- /dev/null +++ b/IPython/html/tests/notebook/dualmode_execute.js @@ -0,0 +1,72 @@ +// Test keyboard invoked execution. + +// Test +casper.notebook_test(function () { + var a = 'print("a")'; + var index = this.append_cell(a); + this.execute_cell_then(index); + + var b = 'print("b")'; + index = this.append_cell(b); + this.execute_cell_then(index); + + var c = 'print("c")'; + index = this.append_cell(c); + this.execute_cell_then(index); + + this.then(function () { + + // shift+enter + // last cell in notebook + var base_index = 3; + this.select_cell(base_index); + this.trigger_keydown('shift+enter'); // Creates one cell + this.validate_notebook_state('shift+enter (no cell below)', 'edit', base_index + 1); + // not last cell in notebook & starts in edit mode + this.click_cell_editor(base_index); + this.validate_notebook_state('click cell ' + base_index, 'edit', base_index); + this.trigger_keydown('shift+enter'); + this.validate_notebook_state('shift+enter (cell exists below)', 'command', base_index + 1); + // starts in command mode + this.trigger_keydown('k'); + this.validate_notebook_state('k in comand mode', 'command', base_index); + this.trigger_keydown('shift+enter'); + this.validate_notebook_state('shift+enter (start in command mode)', 'command', base_index + 1); + + // ctrl+enter + // last cell in notebook + base_index++; + this.trigger_keydown('ctrl+enter'); + this.validate_notebook_state('ctrl+enter (no cell below)', 'command', base_index); + // not last cell in notebook & starts in edit mode + this.click_cell_editor(base_index-1); + this.validate_notebook_state('click cell ' + (base_index-1), 'edit', base_index-1); + this.trigger_keydown('ctrl+enter'); + this.validate_notebook_state('ctrl+enter (cell exists below)', 'command', base_index-1); + // starts in command mode + this.trigger_keydown('j'); + this.validate_notebook_state('j in comand mode', 'command', base_index); + this.trigger_keydown('ctrl+enter'); + this.validate_notebook_state('ctrl+enter (start in command mode)', 'command', base_index); + + // alt+enter + // last cell in notebook + this.trigger_keydown('alt+enter'); // Creates one cell + this.validate_notebook_state('alt+enter (no cell below)', 'edit', base_index + 1); + // not last cell in notebook & starts in edit mode + this.click_cell_editor(base_index); + this.validate_notebook_state('click cell ' + base_index, 'edit', base_index); + this.trigger_keydown('alt+enter'); // Creates one cell + this.validate_notebook_state('alt+enter (cell exists below)', 'edit', base_index + 1); + // starts in command mode + this.trigger_keydown('esc', 'k'); + this.validate_notebook_state('k in comand mode', 'command', base_index); + this.trigger_keydown('alt+enter'); // Creates one cell + this.validate_notebook_state('alt+enter (start in command mode)', 'edit', base_index + 1); + + // Notebook will now have 8 cells, the index of the last cell will be 7. + this.test.assertEquals(this.get_cells_length(), 8, '*-enter commands added cells where needed.'); + this.select_cell(7); + this.validate_notebook_state('click cell ' + 7 + ' and esc', 'command', 7); + }); +}); \ No newline at end of file diff --git a/IPython/html/tests/notebook/dualmode_markdown.js b/IPython/html/tests/notebook/dualmode_markdown.js new file mode 100644 index 000000000..924ff8cf8 --- /dev/null +++ b/IPython/html/tests/notebook/dualmode_markdown.js @@ -0,0 +1,39 @@ + +// Test +casper.notebook_test(function () { + var a = 'print("a")'; + var index = this.append_cell(a); + this.execute_cell_then(index); + + this.then(function () { + // Markdown rendering / unredering + this.select_cell(1); + this.validate_notebook_state('select 1', 'command', 1); + this.trigger_keydown('m'); + this.test.assertEquals(this.get_cell(1).cell_type, 'markdown', 'm; cell is markdown'); + this.test.assertEquals(this.get_cell(1).rendered, false, 'm; cell is rendered'); + this.trigger_keydown('enter'); + this.test.assertEquals(this.get_cell(1).rendered, false, 'enter; cell is unrendered'); + this.validate_notebook_state('enter', 'edit', 1); + this.trigger_keydown('ctrl+enter'); + this.test.assertEquals(this.get_cell(1).rendered, true, 'ctrl+enter; cell is rendered'); + this.validate_notebook_state('enter', 'command', 1); + this.trigger_keydown('enter'); + this.test.assertEquals(this.get_cell(1).rendered, false, 'enter; cell is unrendered'); + this.select_cell(0); + this.test.assertEquals(this.get_cell(1).rendered, false, 'select 0; cell 1 is still unrendered'); + this.validate_notebook_state('select 0', 'command', 0); + this.select_cell(1); + this.validate_notebook_state('select 1', 'command', 1); + this.trigger_keydown('ctrl+enter'); + this.test.assertEquals(this.get_cell(1).rendered, true, 'ctrl+enter; cell is rendered'); + this.select_cell(0); + this.validate_notebook_state('select 0', 'command', 0); + this.trigger_keydown('shift+enter'); + this.validate_notebook_state('shift+enter', 'command', 1); + this.test.assertEquals(this.get_cell(1).rendered, true, 'shift+enter; cell is rendered'); + this.trigger_keydown('shift+enter'); // Creates one cell + this.validate_notebook_state('shift+enter', 'edit', 2); + this.test.assertEquals(this.get_cell(1).rendered, true, 'shift+enter; cell is rendered'); + }); +}); \ No newline at end of file diff --git a/IPython/html/tests/notebook/dualmode_merge.js b/IPython/html/tests/notebook/dualmode_merge.js new file mode 100644 index 000000000..5d8279815 --- /dev/null +++ b/IPython/html/tests/notebook/dualmode_merge.js @@ -0,0 +1,21 @@ + +// Test +casper.notebook_test(function () { + this.then(function () { + // Split and merge cells + this.select_cell(0); + this.trigger_keydown('a', 'enter'); // Create cell above and enter edit mode. + this.validate_notebook_state('a, enter', 'edit', 0); + this.set_cell_text(0, 'abcd'); + this.set_cell_editor_cursor(0, 0, 2); + this.test.assertEquals(this.get_cell_text(0), 'abcd', 'Verify that cell 0 has the new contents.'); + this.trigger_keydown('alt+-'); // Split + this.test.assertEquals(this.get_cell_text(0), 'ab', 'split; Verify that cell 0 has the first half.'); + this.test.assertEquals(this.get_cell_text(1), 'cd', 'split; Verify that cell 1 has the second half.'); + this.validate_notebook_state('split', 'edit', 1); + this.select_cell(0); // Move up to cell 0 + this.trigger_keydown('shift+m'); // Merge + this.validate_notebook_state('merge', 'command', 0); + this.test.assertEquals(this.get_cell_text(0), 'ab\ncd', 'merge; Verify that cell 0 has the merged contents.'); + }); +}); \ No newline at end of file diff --git a/IPython/html/tests/notebook/merge_cells.js b/IPython/html/tests/notebook/merge_cells_api.js similarity index 100% rename from IPython/html/tests/notebook/merge_cells.js rename to IPython/html/tests/notebook/merge_cells_api.js From 1b46a777fb795b1a8be340b1ddd6cd99550cb71e Mon Sep 17 00:00:00 2001 From: Jonathan Frederic Date: Wed, 12 Mar 2014 10:42:46 -0700 Subject: [PATCH 24/38] Removed trigger keydown from keyboard.js, also added a bunch of missing semicolons (jshint) --- IPython/html/static/base/js/keyboard.js | 6 +++--- IPython/html/tests/util.js | 4 +++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/IPython/html/static/base/js/keyboard.js b/IPython/html/static/base/js/keyboard.js index 4fa77d5c9..37ab3e35e 100644 --- a/IPython/html/static/base/js/keyboard.js +++ b/IPython/html/static/base/js/keyboard.js @@ -134,7 +134,7 @@ IPython.keyboard = (function (IPython) { element = $(element); var event = shortcut_to_event(shortcut, 'keydown'); element.trigger(event); - }; + } // Shortcut manager class @@ -192,7 +192,7 @@ IPython.keyboard = (function (IPython) { if (!suppress_help_update) { // update the keyboard shortcuts notebook help $([IPython.events]).trigger('rebuild.QuickHelp'); - } + } }; ShortcutManager.prototype.add_shortcuts = function (data) { @@ -210,7 +210,7 @@ IPython.keyboard = (function (IPython) { if (!suppress_help_update) { // update the keyboard shortcuts notebook help $([IPython.events]).trigger('rebuild.QuickHelp'); - } + } }; ShortcutManager.prototype.count_handler = function (shortcut, event, data) { diff --git a/IPython/html/tests/util.js b/IPython/html/tests/util.js index 836b717f2..c197a7cc5 100644 --- a/IPython/html/tests/util.js +++ b/IPython/html/tests/util.js @@ -306,7 +306,9 @@ casper.focus_notebook = function() { casper.trigger_keydown = function() { for (var i = 0; i < arguments.length; i++) { this.evaluate(function (k) { - IPython.keyboard.trigger_keydown(k); + var element = $(document); + var event = IPython.keyboard.shortcut_to_event(k, 'keydown'); + element.trigger(event); }, {k: arguments[i]}); } }; From a8783c45cbc2f84ca3bdc9350788b595018261e0 Mon Sep 17 00:00:00 2001 From: Jonathan Frederic Date: Wed, 12 Mar 2014 10:51:03 -0700 Subject: [PATCH 25/38] Add comments --- IPython/html/tests/util.js | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/IPython/html/tests/util.js b/IPython/html/tests/util.js index c197a7cc5..55af7ceca 100644 --- a/IPython/html/tests/util.js +++ b/IPython/html/tests/util.js @@ -233,6 +233,8 @@ casper.cell_element_function = function(index, selector, function_name, function }, index, selector, function_name, function_args); }; +// Validate the entire dual mode state of the notebook. Make sure no more than +// one cell is selected, focused, in edit mode, etc... casper.validate_notebook_state = function(message, mode, cell_index) { // General tests. this.test.assertEquals(this.get_keyboard_mode(), this.get_notebook_mode(), @@ -272,12 +274,14 @@ casper.validate_notebook_state = function(message, mode, cell_index) { } }; +// Select a cell in the notebook. casper.select_cell = function(index) { this.evaluate(function (i) { IPython.notebook.select(i); }, {i: index}); }; +// Emulate a click on a cell's editor. casper.click_cell_editor = function(index) { // Code Mirror does not play nicely with emulated brower events. // Instead of trying to emulate a click, here we run code similar to @@ -290,19 +294,21 @@ casper.click_cell_editor = function(index) { }, {i: index}); }; +// Set the Code Mirror instance cursor's location. casper.set_cell_editor_cursor = function(index, line_index, char_index) { - // Set the Code Mirror instance cursor's location. this.evaluate(function (i, l, c) { IPython.notebook.get_cell(i).code_mirror.setCursor(l, c); }, {i: index, l: line_index, c: char_index}); }; +// Focus the notebook div. casper.focus_notebook = function() { this.evaluate(function (){ $('#notebook').focus(); }, {}); }; +// Emulate a keydown in the notebook. casper.trigger_keydown = function() { for (var i = 0; i < arguments.length; i++) { this.evaluate(function (k) { @@ -313,18 +319,24 @@ casper.trigger_keydown = function() { } }; +// Get the mode of the keyboard manager. casper.get_keyboard_mode = function() { return this.evaluate(function() { return IPython.keyboard_manager.mode; }, {}); }; +// Get the mode of the notebook. casper.get_notebook_mode = function() { return this.evaluate(function() { return IPython.notebook.mode; }, {}); }; +// Get a single cell. +// +// Note: Handles to DOM elements stored in the cell will be useless once in +// CasperJS context. casper.get_cell = function(index) { return this.evaluate(function(i) { var cell = IPython.notebook.get_cell(i); @@ -335,8 +347,8 @@ casper.get_cell = function(index) { }, {i : index}); }; +// Make sure a cell's editor is the only editor focused on the page. casper.is_cell_editor_focused = function(index) { - // Make sure a cell's editor is the only editor focused on the page. return this.evaluate(function(i) { var focused_textarea = $('#notebook .CodeMirror-focused textarea'); if (focused_textarea.length > 1) { throw 'More than one Code Mirror editor is focused at once!'; } @@ -352,14 +364,21 @@ casper.is_cell_editor_focused = function(index) { }, {i : index}); }; +// Check if a cell is the only cell selected. +// Pass null as the index to check if no cells are selected. casper.is_only_cell_selected = function(index) { return this.is_only_cell_on(index, 'selected', 'unselected'); }; +// Check if a cell is the only cell in edit mode. +// Pass null as the index to check if all of the cells are in command mode. casper.is_only_cell_edit = function(index) { return this.is_only_cell_on(index, 'edit_mode', 'command_mode'); }; +// Check if a cell is the only cell with the `on_class` DOM class applied to it. +// All of the other cells are checked for the `off_class` DOM class. +// Pass null as the index to check if all of the cells have the `off_class`. casper.is_only_cell_on = function(i, on_class, off_class) { var cells_length = this.get_cells_length(); for (var j = 0; j < cells_length; j++) { @@ -376,6 +395,7 @@ casper.is_only_cell_on = function(i, on_class, off_class) { return true; }; +// Check if a cell has a class. casper.cell_has_class = function(index, classes) { return this.evaluate(function(i, c) { var cell = IPython.notebook.get_cell(i); From 147f35d899299dfb3bfd23c30554fcc396be0280 Mon Sep 17 00:00:00 2001 From: Jonathan Frederic Date: Wed, 12 Mar 2014 10:53:28 -0700 Subject: [PATCH 26/38] demsemicolons --- IPython/html/tests/util.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/IPython/html/tests/util.js b/IPython/html/tests/util.js index 55af7ceca..1636474c3 100644 --- a/IPython/html/tests/util.js +++ b/IPython/html/tests/util.js @@ -4,9 +4,9 @@ // Get the URL of a notebook server on which to run tests. casper.get_notebook_server = function () { - port = casper.cli.get("port") + port = casper.cli.get("port"); port = (typeof port === 'undefined') ? '8888' : port; - return 'http://127.0.0.1:' + port + return 'http://127.0.0.1:' + port; }; // Create and open a new notebook. @@ -107,13 +107,13 @@ casper.wait_for_widget = function (widget_info) { return IPython.notebook.kernel.widget_manager.get_model(m).pending_msgs; }, {m: widget_info.model_id}); - if (pending == 0) { + if (pending === 0) { return true; } else { return false; } }); -} +}; // return an output of a given cell casper.get_output_cell = function (cell_num, out_num) { @@ -141,7 +141,7 @@ casper.get_output_cell = function (cell_num, out_num) { casper.get_cells_length = function () { var result = casper.evaluate(function () { return IPython.notebook.get_cells().length; - }) + }); return result; }; @@ -434,14 +434,14 @@ casper.notebook_test = function(test) { casper.wait_for_dashboard = function () { // Wait for the dashboard list to load. casper.waitForSelector('.list_item'); -} +}; casper.open_dashboard = function () { // Start casper by opening the dashboard page. var baseUrl = this.get_notebook_server(); this.start(baseUrl); this.wait_for_dashboard(); -} +}; casper.dashboard_test = function (test) { // Open the dashboard page and run a test. @@ -457,9 +457,9 @@ casper.dashboard_test = function (test) { this.run(function() { this.test.done(); }); -} +}; -casper.options.waitTimeout=10000 +casper.options.waitTimeout=10000; casper.on('waitFor.timeout', function onWaitForTimeout(timeout) { this.echo("Timeout for " + casper.get_notebook_server()); this.echo("Is the notebook server running?"); From ae2b0800cf39d8e425d2690848d1459d1a664b87 Mon Sep 17 00:00:00 2001 From: Jonathan Frederic Date: Thu, 13 Mar 2014 09:59:42 -0700 Subject: [PATCH 27/38] Partial fix of problems b/c keydown move --- IPython/html/static/base/js/keyboard.js | 3 +-- IPython/html/tests/notebook/empty_arrow_keys.js | 10 +++++----- IPython/html/tests/notebook/execute_code.js | 4 ++++ 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/IPython/html/static/base/js/keyboard.js b/IPython/html/static/base/js/keyboard.js index 37ab3e35e..a5c8a69de 100644 --- a/IPython/html/static/base/js/keyboard.js +++ b/IPython/html/static/base/js/keyboard.js @@ -262,8 +262,7 @@ IPython.keyboard = (function (IPython) { normalize_key : normalize_key, normalize_shortcut : normalize_shortcut, shortcut_to_event : shortcut_to_event, - event_to_shortcut : event_to_shortcut, - trigger_keydown : trigger_keydown + event_to_shortcut : event_to_shortcut }; }(IPython)); diff --git a/IPython/html/tests/notebook/empty_arrow_keys.js b/IPython/html/tests/notebook/empty_arrow_keys.js index 6abed3a96..a949ce53a 100644 --- a/IPython/html/tests/notebook/empty_arrow_keys.js +++ b/IPython/html/tests/notebook/empty_arrow_keys.js @@ -10,12 +10,12 @@ casper.notebook_test(function () { for (i = 0; i < ncells; i++) { IPython.notebook.delete_cell(); } - - // Simulate the "up arrow" and "down arrow" keys. - // - IPython.keyboard.trigger_keydown('up'); - IPython.keyboard.trigger_keydown('down'); + return true; }); + + // Simulate the "up arrow" and "down arrow" keys. + this.trigger_keydown('up'); + this.trigger_keydown('down'); this.test.assertTrue(result, 'Up/down arrow okay in empty notebook.'); }); diff --git a/IPython/html/tests/notebook/execute_code.js b/IPython/html/tests/notebook/execute_code.js index 1af684f25..b3cc7c9a2 100644 --- a/IPython/html/tests/notebook/execute_code.js +++ b/IPython/html/tests/notebook/execute_code.js @@ -25,6 +25,10 @@ casper.notebook_test(function () { IPython.keyboard.trigger_keydown('shift-enter'); }); + this.then(function(){ + + }); + this.wait_for_output(0); this.then(function () { From baa28a0b81f7935b047fdf29b65da2696b31f4b6 Mon Sep 17 00:00:00 2001 From: Jonathan Frederic Date: Thu, 13 Mar 2014 10:22:09 -0700 Subject: [PATCH 28/38] Final fixes? --- IPython/html/tests/notebook/execute_code.js | 7 +++++-- IPython/html/tests/notebook/interrupt.js | 4 ++-- IPython/html/tests/notebook/merge_cells_api.js | 6 +++++- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/IPython/html/tests/notebook/execute_code.js b/IPython/html/tests/notebook/execute_code.js index b3cc7c9a2..076d3b70a 100644 --- a/IPython/html/tests/notebook/execute_code.js +++ b/IPython/html/tests/notebook/execute_code.js @@ -22,11 +22,11 @@ casper.notebook_test(function () { var cell = IPython.notebook.get_cell(0); cell.set_text('a=11; print(a)'); cell.clear_output(); - IPython.keyboard.trigger_keydown('shift-enter'); }); this.then(function(){ + this.trigger_keydown('shift-enter'); }); this.wait_for_output(0); @@ -45,7 +45,10 @@ casper.notebook_test(function () { var cell = IPython.notebook.get_cell(0); cell.set_text('a=12; print(a)'); cell.clear_output(); - IPython.keyboard.trigger_keydown('ctrl-enter'); + }); + + this.then(function(){ + this.trigger_keydown('ctrl-enter'); }); this.wait_for_output(0); diff --git a/IPython/html/tests/notebook/interrupt.js b/IPython/html/tests/notebook/interrupt.js index 2bb87f8a5..7c2912c4c 100644 --- a/IPython/html/tests/notebook/interrupt.js +++ b/IPython/html/tests/notebook/interrupt.js @@ -31,8 +31,8 @@ casper.notebook_test(function () { }); // interrupt using Ctrl-M I keyboard shortcut - this.thenEvaluate( function() { - IPython.keyboard.trigger_keydown('i'); + this.then(function(){ + this.trigger_keydown('i'); }); this.wait_for_output(0); diff --git a/IPython/html/tests/notebook/merge_cells_api.js b/IPython/html/tests/notebook/merge_cells_api.js index 2d8561433..de01a000d 100644 --- a/IPython/html/tests/notebook/merge_cells_api.js +++ b/IPython/html/tests/notebook/merge_cells_api.js @@ -2,6 +2,7 @@ // Test merging two notebook cells. // casper.notebook_test(function() { + var that = this; var output = this.evaluate(function () { // Fill in test data. IPython.notebook.command_mode(); @@ -9,7 +10,10 @@ casper.notebook_test(function() { var cell_one = IPython.notebook.get_selected_cell(); cell_one.set_text('a = 5'); - IPython.keyboard.trigger_keydown('b'); + var element = $(document); + var event = IPython.keyboard.shortcut_to_event('b', 'keydown'); + element.trigger(event); + var cell_two = IPython.notebook.get_selected_cell(); cell_two.set_text('print(a)'); }; From 7c6c0b22b8a670abf9043db506fe7bf5ae9fc0cc Mon Sep 17 00:00:00 2001 From: Jonathan Frederic Date: Fri, 14 Mar 2014 11:35:43 -0700 Subject: [PATCH 29/38] Pythonize me captin' Made the method comments more pythonic by moving them within the method definitions. --- IPython/html/tests/util.js | 115 +++++++++++++++++++------------------ 1 file changed, 60 insertions(+), 55 deletions(-) diff --git a/IPython/html/tests/util.js b/IPython/html/tests/util.js index 1636474c3..a572190bc 100644 --- a/IPython/html/tests/util.js +++ b/IPython/html/tests/util.js @@ -2,15 +2,15 @@ // Utility functions for the HTML notebook's CasperJS tests. // -// Get the URL of a notebook server on which to run tests. casper.get_notebook_server = function () { + // Get the URL of a notebook server on which to run tests. port = casper.cli.get("port"); port = (typeof port === 'undefined') ? '8888' : port; return 'http://127.0.0.1:' + port; }; -// Create and open a new notebook. casper.open_new_notebook = function () { + // Create and open a new notebook. var baseUrl = this.get_notebook_server(); this.start(baseUrl); this.thenClick('button#new_notebook'); @@ -34,15 +34,15 @@ casper.open_new_notebook = function () { }); }; -// Return whether or not the kernel is running. casper.kernel_running = function kernel_running() { + // Return whether or not the kernel is running. return this.evaluate(function kernel_running() { return IPython.notebook.kernel.running; }); }; -// Shut down the current notebook's kernel. casper.shutdown_current_kernel = function () { + // Shut down the current notebook's kernel. this.thenEvaluate(function() { IPython.notebook.kernel.kill(); }); @@ -50,8 +50,9 @@ casper.shutdown_current_kernel = function () { this.wait(1000); }; -// Delete created notebook. casper.delete_current_notebook = function () { + // Delete created notebook. + // For some unknown reason, this doesn't work?!? this.thenEvaluate(function() { IPython.notebook.delete(); @@ -59,6 +60,7 @@ casper.delete_current_notebook = function () { }; casper.wait_for_busy = function () { + // Waits for the notebook to enter a busy state. this.waitFor(function () { return this.evaluate(function () { return IPython._status == 'busy'; @@ -67,6 +69,7 @@ casper.wait_for_busy = function () { }; casper.wait_for_idle = function () { + // Waits for the notebook to idle. this.waitFor(function () { return this.evaluate(function () { return IPython._status == 'idle'; @@ -74,8 +77,8 @@ casper.wait_for_idle = function () { }); }; -// wait for the nth output in a given cell casper.wait_for_output = function (cell_num, out_num) { + // wait for the nth output in a given cell this.wait_for_idle(); out_num = out_num || 0; this.then(function() { @@ -94,14 +97,14 @@ casper.wait_for_output = function (cell_num, out_num) { }); }; -// wait for a widget msg que to reach 0 -// -// Parameters -// ---------- -// widget_info : object -// Object which contains info related to the widget. The model_id property -// is used to identify the widget. casper.wait_for_widget = function (widget_info) { + // wait for a widget msg que to reach 0 + // + // Parameters + // ---------- + // widget_info : object + // Object which contains info related to the widget. The model_id property + // is used to identify the widget. this.waitFor(function () { var pending = this.evaluate(function (m) { return IPython.notebook.kernel.widget_manager.get_model(m).pending_msgs; @@ -115,8 +118,8 @@ casper.wait_for_widget = function (widget_info) { }); }; -// return an output of a given cell casper.get_output_cell = function (cell_num, out_num) { + // return an output of a given cell out_num = out_num || 0; var result = casper.evaluate(function (c, o) { var cell = IPython.notebook.get_cell(c); @@ -137,33 +140,33 @@ casper.get_output_cell = function (cell_num, out_num) { } }; -// return the number of cells in the notebook casper.get_cells_length = function () { + // return the number of cells in the notebook var result = casper.evaluate(function () { return IPython.notebook.get_cells().length; }); return result; }; -// Set the text content of a cell. casper.set_cell_text = function(index, text){ + // Set the text content of a cell. this.evaluate(function (index, text) { var cell = IPython.notebook.get_cell(index); cell.set_text(text); }, index, text); }; -// Get the text content of a cell. casper.get_cell_text = function(index){ + // Get the text content of a cell. return this.evaluate(function (index) { var cell = IPython.notebook.get_cell(index); return cell.get_text(); }, index); }; -// Inserts a cell at the bottom of the notebook -// Returns the new cell's index. casper.insert_cell_at_bottom = function(cell_type){ + // Inserts a cell at the bottom of the notebook + // Returns the new cell's index. cell_type = cell_type || 'code'; return this.evaluate(function (cell_type) { @@ -172,9 +175,9 @@ casper.insert_cell_at_bottom = function(cell_type){ }, cell_type); }; -// Insert a cell at the bottom of the notebook and set the cells text. -// Returns the new cell's index. casper.append_cell = function(text, cell_type) { + // Insert a cell at the bottom of the notebook and set the cells text. + // Returns the new cell's index. var index = this.insert_cell_at_bottom(cell_type); if (text !== undefined) { this.set_cell_text(index, text); @@ -182,9 +185,9 @@ casper.append_cell = function(text, cell_type) { return index; }; -// Asynchronously executes a cell by index. -// Returns the cell's index. casper.execute_cell = function(index){ + // Asynchronously executes a cell by index. + // Returns the cell's index. var that = this; this.then(function(){ that.evaluate(function (index) { @@ -195,11 +198,11 @@ casper.execute_cell = function(index){ return index; }; -// Synchronously executes a cell by index. -// Optionally accepts a then_callback parameter. then_callback will get called -// when the cell has finished executing. -// Returns the cell's index. casper.execute_cell_then = function(index, then_callback) { + // Synchronously executes a cell by index. + // Optionally accepts a then_callback parameter. then_callback will get called + // when the cell has finished executing. + // Returns the cell's index. var return_val = this.execute_cell(index); this.wait_for_idle(); @@ -214,18 +217,18 @@ casper.execute_cell_then = function(index, then_callback) { return return_val; }; -// Utility function that allows us to easily check if an element exists -// within a cell. Uses JQuery selector to look for the element. casper.cell_element_exists = function(index, selector){ + // Utility function that allows us to easily check if an element exists + // within a cell. Uses JQuery selector to look for the element. return casper.evaluate(function (index, selector) { var $cell = IPython.notebook.get_cell(index).element; return $cell.find(selector).length > 0; }, index, selector); }; -// Utility function that allows us to execute a jQuery function on an -// element within a cell. casper.cell_element_function = function(index, selector, function_name, function_args){ + // Utility function that allows us to execute a jQuery function on an + // element within a cell. return casper.evaluate(function (index, selector, function_name, function_args) { var $cell = IPython.notebook.get_cell(index).element; var $el = $cell.find(selector); @@ -233,9 +236,10 @@ casper.cell_element_function = function(index, selector, function_name, function }, index, selector, function_name, function_args); }; -// Validate the entire dual mode state of the notebook. Make sure no more than -// one cell is selected, focused, in edit mode, etc... casper.validate_notebook_state = function(message, mode, cell_index) { + // Validate the entire dual mode state of the notebook. Make sure no more than + // one cell is selected, focused, in edit mode, etc... + // General tests. this.test.assertEquals(this.get_keyboard_mode(), this.get_notebook_mode(), message + '; keyboard and notebook modes match'); @@ -274,15 +278,16 @@ casper.validate_notebook_state = function(message, mode, cell_index) { } }; -// Select a cell in the notebook. casper.select_cell = function(index) { + // Select a cell in the notebook. this.evaluate(function (i) { IPython.notebook.select(i); }, {i: index}); }; -// Emulate a click on a cell's editor. casper.click_cell_editor = function(index) { + // Emulate a click on a cell's editor. + // Code Mirror does not play nicely with emulated brower events. // Instead of trying to emulate a click, here we run code similar to // the code used in Code Mirror that handles the mousedown event on a @@ -294,22 +299,22 @@ casper.click_cell_editor = function(index) { }, {i: index}); }; -// Set the Code Mirror instance cursor's location. casper.set_cell_editor_cursor = function(index, line_index, char_index) { + // Set the Code Mirror instance cursor's location. this.evaluate(function (i, l, c) { IPython.notebook.get_cell(i).code_mirror.setCursor(l, c); }, {i: index, l: line_index, c: char_index}); }; -// Focus the notebook div. casper.focus_notebook = function() { + // Focus the notebook div. this.evaluate(function (){ $('#notebook').focus(); }, {}); }; -// Emulate a keydown in the notebook. casper.trigger_keydown = function() { + // Emulate a keydown in the notebook. for (var i = 0; i < arguments.length; i++) { this.evaluate(function (k) { var element = $(document); @@ -319,25 +324,25 @@ casper.trigger_keydown = function() { } }; -// Get the mode of the keyboard manager. casper.get_keyboard_mode = function() { + // Get the mode of the keyboard manager. return this.evaluate(function() { return IPython.keyboard_manager.mode; }, {}); }; -// Get the mode of the notebook. casper.get_notebook_mode = function() { + // Get the mode of the notebook. return this.evaluate(function() { return IPython.notebook.mode; }, {}); }; -// Get a single cell. -// -// Note: Handles to DOM elements stored in the cell will be useless once in -// CasperJS context. casper.get_cell = function(index) { + // Get a single cell. + // + // Note: Handles to DOM elements stored in the cell will be useless once in + // CasperJS context. return this.evaluate(function(i) { var cell = IPython.notebook.get_cell(i); if (cell) { @@ -347,8 +352,8 @@ casper.get_cell = function(index) { }, {i : index}); }; -// Make sure a cell's editor is the only editor focused on the page. casper.is_cell_editor_focused = function(index) { + // Make sure a cell's editor is the only editor focused on the page. return this.evaluate(function(i) { var focused_textarea = $('#notebook .CodeMirror-focused textarea'); if (focused_textarea.length > 1) { throw 'More than one Code Mirror editor is focused at once!'; } @@ -364,22 +369,22 @@ casper.is_cell_editor_focused = function(index) { }, {i : index}); }; -// Check if a cell is the only cell selected. -// Pass null as the index to check if no cells are selected. casper.is_only_cell_selected = function(index) { + // Check if a cell is the only cell selected. + // Pass null as the index to check if no cells are selected. return this.is_only_cell_on(index, 'selected', 'unselected'); }; -// Check if a cell is the only cell in edit mode. -// Pass null as the index to check if all of the cells are in command mode. casper.is_only_cell_edit = function(index) { + // Check if a cell is the only cell in edit mode. + // Pass null as the index to check if all of the cells are in command mode. return this.is_only_cell_on(index, 'edit_mode', 'command_mode'); }; -// Check if a cell is the only cell with the `on_class` DOM class applied to it. -// All of the other cells are checked for the `off_class` DOM class. -// Pass null as the index to check if all of the cells have the `off_class`. casper.is_only_cell_on = function(i, on_class, off_class) { + // Check if a cell is the only cell with the `on_class` DOM class applied to it. + // All of the other cells are checked for the `off_class` DOM class. + // Pass null as the index to check if all of the cells have the `off_class`. var cells_length = this.get_cells_length(); for (var j = 0; j < cells_length; j++) { if (j === i) { @@ -395,8 +400,8 @@ casper.is_only_cell_on = function(i, on_class, off_class) { return true; }; -// Check if a cell has a class. casper.cell_has_class = function(index, classes) { + // Check if a cell has a class. return this.evaluate(function(i, c) { var cell = IPython.notebook.get_cell(i); if (cell) { @@ -406,8 +411,8 @@ casper.cell_has_class = function(index, classes) { }, {i : index, c: classes}); }; -// Wrap a notebook test to reduce boilerplate. casper.notebook_test = function(test) { + // Wrap a notebook test to reduce boilerplate. this.open_new_notebook(); this.then(test); @@ -465,8 +470,8 @@ casper.on('waitFor.timeout', function onWaitForTimeout(timeout) { this.echo("Is the notebook server running?"); }); -// Pass `console.log` calls from page JS to casper. casper.print_log = function () { + // Pass `console.log` calls from page JS to casper. this.on('remote.message', function(msg) { this.echo('Remote message caught: ' + msg); }); From 1754e3291a0fa3f88d6c20ca2147b57970435297 Mon Sep 17 00:00:00 2001 From: Jonathan Frederic Date: Thu, 20 Mar 2014 15:08:55 -0700 Subject: [PATCH 30/38] Call trigger_keydown in merge_cells_api test --- .../html/tests/notebook/merge_cells_api.js | 45 ++++++++++--------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/IPython/html/tests/notebook/merge_cells_api.js b/IPython/html/tests/notebook/merge_cells_api.js index de01a000d..e6f844caa 100644 --- a/IPython/html/tests/notebook/merge_cells_api.js +++ b/IPython/html/tests/notebook/merge_cells_api.js @@ -3,40 +3,41 @@ // casper.notebook_test(function() { var that = this; - var output = this.evaluate(function () { - // Fill in test data. - IPython.notebook.command_mode(); - var set_cell_text = function () { + var set_cells_text = function () { + that.evaluate(function() { var cell_one = IPython.notebook.get_selected_cell(); cell_one.set_text('a = 5'); - - var element = $(document); - var event = IPython.keyboard.shortcut_to_event('b', 'keydown'); - element.trigger(event); + }); + + that.trigger_keydown('b'); + that.evaluate(function() { var cell_two = IPython.notebook.get_selected_cell(); cell_two.set_text('print(a)'); - }; + }); + }; + + this.evaluate(function () { + IPython.notebook.command_mode(); + }); - // merge_cell_above() - set_cell_text(); + // merge_cell_above() + set_cell_text(); + var output_above = this.evaluate(function () { IPython.notebook.merge_cell_above(); - var merged_above = IPython.notebook.get_selected_cell(); + return IPython.notebook.get_selected_cell(); + }); - // merge_cell_below() - set_cell_text(); + // merge_cell_below() + set_cell_text(); + var output_below = this.evaluate(function() { 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() - }; + return IPython.notebook.get_selected_cell(); }); - this.test.assertEquals(output.above, 'a = 5\nprint(a)', + this.test.assertEquals(output_above, 'a = 5\nprint(a)', 'Successful merge_cell_above().'); - this.test.assertEquals(output.below, 'a = 5\nprint(a)', + this.test.assertEquals(output_below, 'a = 5\nprint(a)', 'Successful merge_cell_below().'); }); From ca71afc5ea71d8123381f696d758bd598521e24e Mon Sep 17 00:00:00 2001 From: Jonathan Frederic Date: Thu, 20 Mar 2014 15:46:04 -0700 Subject: [PATCH 31/38] Note to self --- IPython/html/tests/notebook/dualmode_arrows.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/IPython/html/tests/notebook/dualmode_arrows.js b/IPython/html/tests/notebook/dualmode_arrows.js index 4b839ac8a..5c00836a5 100644 --- a/IPython/html/tests/notebook/dualmode_arrows.js +++ b/IPython/html/tests/notebook/dualmode_arrows.js @@ -37,12 +37,14 @@ casper.notebook_test(function () { this.validate_notebook_state('click cell 3', 'edit', 3); this.trigger_keydown('down'); this.validate_notebook_state('down at end of notebook', 'edit', 3); + // cursor this.trigger_keydown('up'); this.validate_notebook_state('up', 'edit', 2); this.click_cell_editor(0); this.validate_notebook_state('click 0', 'edit', 0); this.trigger_keydown('up'); this.validate_notebook_state('up at top of notebook', 'edit', 0); + // cursor this.trigger_keydown('down'); this.validate_notebook_state('down', 'edit', 1); }); From 9c6d904f714a8269b8f8cd54387fc27c98a0d32a Mon Sep 17 00:00:00 2001 From: Jonathan Frederic Date: Thu, 20 Mar 2014 16:02:33 -0700 Subject: [PATCH 32/38] Set cursor pos in edit mode before attempting to jump cells. --- IPython/html/tests/notebook/dualmode_arrows.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/IPython/html/tests/notebook/dualmode_arrows.js b/IPython/html/tests/notebook/dualmode_arrows.js index 5c00836a5..034929b5f 100644 --- a/IPython/html/tests/notebook/dualmode_arrows.js +++ b/IPython/html/tests/notebook/dualmode_arrows.js @@ -37,14 +37,14 @@ casper.notebook_test(function () { this.validate_notebook_state('click cell 3', 'edit', 3); this.trigger_keydown('down'); this.validate_notebook_state('down at end of notebook', 'edit', 3); - // cursor + this.set_cell_editor_cursor(3, 0, 0); this.trigger_keydown('up'); this.validate_notebook_state('up', 'edit', 2); this.click_cell_editor(0); this.validate_notebook_state('click 0', 'edit', 0); this.trigger_keydown('up'); this.validate_notebook_state('up at top of notebook', 'edit', 0); - // cursor + this.set_cell_editor_cursor(0, 0, 10); this.trigger_keydown('down'); this.validate_notebook_state('down', 'edit', 1); }); From b80e11d3ceeb8c6be98aae600435abdae916892b Mon Sep 17 00:00:00 2001 From: Jonathan Frederic Date: Thu, 20 Mar 2014 16:08:37 -0700 Subject: [PATCH 33/38] Plus to minus shortcuts rebase fixes --- .../html/tests/notebook/dualmode_clipboard.js | 4 +- .../html/tests/notebook/dualmode_execute.js | 42 +++++++++---------- .../html/tests/notebook/dualmode_markdown.js | 20 ++++----- IPython/html/tests/notebook/dualmode_merge.js | 4 +- 4 files changed, 35 insertions(+), 35 deletions(-) diff --git a/IPython/html/tests/notebook/dualmode_clipboard.js b/IPython/html/tests/notebook/dualmode_clipboard.js index 3bda68dba..5068c49c6 100644 --- a/IPython/html/tests/notebook/dualmode_clipboard.js +++ b/IPython/html/tests/notebook/dualmode_clipboard.js @@ -47,8 +47,8 @@ casper.notebook_test(function () { this.test.assertEquals(this.get_cell_text(5), c, 'Verify that cell 5 has the copied contents.'); this.test.assertEquals(this.get_cells_length(), num_cells+2, 'Verify a the cell was added.'); this.select_cell(0); - this.trigger_keydown('shift+v'); // Paste - this.validate_notebook_state('shift+v', 'command', 0); + this.trigger_keydown('shift-v'); // Paste + this.validate_notebook_state('shift-v', 'command', 0); this.test.assertEquals(this.get_cell_text(0), c, 'Verify that cell 0 has the copied contents.'); this.test.assertEquals(this.get_cells_length(), num_cells+3, 'Verify a the cell was added.'); }); diff --git a/IPython/html/tests/notebook/dualmode_execute.js b/IPython/html/tests/notebook/dualmode_execute.js index 750486efb..f4cd9542f 100644 --- a/IPython/html/tests/notebook/dualmode_execute.js +++ b/IPython/html/tests/notebook/dualmode_execute.js @@ -16,53 +16,53 @@ casper.notebook_test(function () { this.then(function () { - // shift+enter + // shift-enter // last cell in notebook var base_index = 3; this.select_cell(base_index); - this.trigger_keydown('shift+enter'); // Creates one cell - this.validate_notebook_state('shift+enter (no cell below)', 'edit', base_index + 1); + this.trigger_keydown('shift-enter'); // Creates one cell + this.validate_notebook_state('shift-enter (no cell below)', 'edit', base_index + 1); // not last cell in notebook & starts in edit mode this.click_cell_editor(base_index); this.validate_notebook_state('click cell ' + base_index, 'edit', base_index); - this.trigger_keydown('shift+enter'); - this.validate_notebook_state('shift+enter (cell exists below)', 'command', base_index + 1); + this.trigger_keydown('shift-enter'); + this.validate_notebook_state('shift-enter (cell exists below)', 'command', base_index + 1); // starts in command mode this.trigger_keydown('k'); this.validate_notebook_state('k in comand mode', 'command', base_index); - this.trigger_keydown('shift+enter'); - this.validate_notebook_state('shift+enter (start in command mode)', 'command', base_index + 1); + this.trigger_keydown('shift-enter'); + this.validate_notebook_state('shift-enter (start in command mode)', 'command', base_index + 1); - // ctrl+enter + // ctrl-enter // last cell in notebook base_index++; - this.trigger_keydown('ctrl+enter'); - this.validate_notebook_state('ctrl+enter (no cell below)', 'command', base_index); + this.trigger_keydown('ctrl-enter'); + this.validate_notebook_state('ctrl-enter (no cell below)', 'command', base_index); // not last cell in notebook & starts in edit mode this.click_cell_editor(base_index-1); this.validate_notebook_state('click cell ' + (base_index-1), 'edit', base_index-1); - this.trigger_keydown('ctrl+enter'); - this.validate_notebook_state('ctrl+enter (cell exists below)', 'command', base_index-1); + this.trigger_keydown('ctrl-enter'); + this.validate_notebook_state('ctrl-enter (cell exists below)', 'command', base_index-1); // starts in command mode this.trigger_keydown('j'); this.validate_notebook_state('j in comand mode', 'command', base_index); - this.trigger_keydown('ctrl+enter'); - this.validate_notebook_state('ctrl+enter (start in command mode)', 'command', base_index); + this.trigger_keydown('ctrl-enter'); + this.validate_notebook_state('ctrl-enter (start in command mode)', 'command', base_index); - // alt+enter + // alt-enter // last cell in notebook - this.trigger_keydown('alt+enter'); // Creates one cell - this.validate_notebook_state('alt+enter (no cell below)', 'edit', base_index + 1); + this.trigger_keydown('alt-enter'); // Creates one cell + this.validate_notebook_state('alt-enter (no cell below)', 'edit', base_index + 1); // not last cell in notebook & starts in edit mode this.click_cell_editor(base_index); this.validate_notebook_state('click cell ' + base_index, 'edit', base_index); - this.trigger_keydown('alt+enter'); // Creates one cell - this.validate_notebook_state('alt+enter (cell exists below)', 'edit', base_index + 1); + this.trigger_keydown('alt-enter'); // Creates one cell + this.validate_notebook_state('alt-enter (cell exists below)', 'edit', base_index + 1); // starts in command mode this.trigger_keydown('esc', 'k'); this.validate_notebook_state('k in comand mode', 'command', base_index); - this.trigger_keydown('alt+enter'); // Creates one cell - this.validate_notebook_state('alt+enter (start in command mode)', 'edit', base_index + 1); + this.trigger_keydown('alt-enter'); // Creates one cell + this.validate_notebook_state('alt-enter (start in command mode)', 'edit', base_index + 1); // Notebook will now have 8 cells, the index of the last cell will be 7. this.test.assertEquals(this.get_cells_length(), 8, '*-enter commands added cells where needed.'); diff --git a/IPython/html/tests/notebook/dualmode_markdown.js b/IPython/html/tests/notebook/dualmode_markdown.js index 924ff8cf8..d97405723 100644 --- a/IPython/html/tests/notebook/dualmode_markdown.js +++ b/IPython/html/tests/notebook/dualmode_markdown.js @@ -15,8 +15,8 @@ casper.notebook_test(function () { this.trigger_keydown('enter'); this.test.assertEquals(this.get_cell(1).rendered, false, 'enter; cell is unrendered'); this.validate_notebook_state('enter', 'edit', 1); - this.trigger_keydown('ctrl+enter'); - this.test.assertEquals(this.get_cell(1).rendered, true, 'ctrl+enter; cell is rendered'); + this.trigger_keydown('ctrl-enter'); + this.test.assertEquals(this.get_cell(1).rendered, true, 'ctrl-enter; cell is rendered'); this.validate_notebook_state('enter', 'command', 1); this.trigger_keydown('enter'); this.test.assertEquals(this.get_cell(1).rendered, false, 'enter; cell is unrendered'); @@ -25,15 +25,15 @@ casper.notebook_test(function () { this.validate_notebook_state('select 0', 'command', 0); this.select_cell(1); this.validate_notebook_state('select 1', 'command', 1); - this.trigger_keydown('ctrl+enter'); - this.test.assertEquals(this.get_cell(1).rendered, true, 'ctrl+enter; cell is rendered'); + this.trigger_keydown('ctrl-enter'); + this.test.assertEquals(this.get_cell(1).rendered, true, 'ctrl-enter; cell is rendered'); this.select_cell(0); this.validate_notebook_state('select 0', 'command', 0); - this.trigger_keydown('shift+enter'); - this.validate_notebook_state('shift+enter', 'command', 1); - this.test.assertEquals(this.get_cell(1).rendered, true, 'shift+enter; cell is rendered'); - this.trigger_keydown('shift+enter'); // Creates one cell - this.validate_notebook_state('shift+enter', 'edit', 2); - this.test.assertEquals(this.get_cell(1).rendered, true, 'shift+enter; cell is rendered'); + this.trigger_keydown('shift-enter'); + this.validate_notebook_state('shift-enter', 'command', 1); + this.test.assertEquals(this.get_cell(1).rendered, true, 'shift-enter; cell is rendered'); + this.trigger_keydown('shift-enter'); // Creates one cell + this.validate_notebook_state('shift-enter', 'edit', 2); + this.test.assertEquals(this.get_cell(1).rendered, true, 'shift-enter; cell is rendered'); }); }); \ No newline at end of file diff --git a/IPython/html/tests/notebook/dualmode_merge.js b/IPython/html/tests/notebook/dualmode_merge.js index 5d8279815..93bd2381b 100644 --- a/IPython/html/tests/notebook/dualmode_merge.js +++ b/IPython/html/tests/notebook/dualmode_merge.js @@ -9,12 +9,12 @@ casper.notebook_test(function () { this.set_cell_text(0, 'abcd'); this.set_cell_editor_cursor(0, 0, 2); this.test.assertEquals(this.get_cell_text(0), 'abcd', 'Verify that cell 0 has the new contents.'); - this.trigger_keydown('alt+-'); // Split + this.trigger_keydown('ctrl-shift-minus'); // Split this.test.assertEquals(this.get_cell_text(0), 'ab', 'split; Verify that cell 0 has the first half.'); this.test.assertEquals(this.get_cell_text(1), 'cd', 'split; Verify that cell 1 has the second half.'); this.validate_notebook_state('split', 'edit', 1); this.select_cell(0); // Move up to cell 0 - this.trigger_keydown('shift+m'); // Merge + this.trigger_keydown('shift-m'); // Merge this.validate_notebook_state('merge', 'command', 0); this.test.assertEquals(this.get_cell_text(0), 'ab\ncd', 'merge; Verify that cell 0 has the merged contents.'); }); From 42fa5831721c63aa43f40af232ccba146e4cfbbb Mon Sep 17 00:00:00 2001 From: Jonathan Frederic Date: Thu, 20 Mar 2014 16:12:42 -0700 Subject: [PATCH 34/38] Fix split shortcut --- IPython/html/tests/notebook/dualmode_merge.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/html/tests/notebook/dualmode_merge.js b/IPython/html/tests/notebook/dualmode_merge.js index 93bd2381b..573b4575d 100644 --- a/IPython/html/tests/notebook/dualmode_merge.js +++ b/IPython/html/tests/notebook/dualmode_merge.js @@ -9,7 +9,7 @@ casper.notebook_test(function () { this.set_cell_text(0, 'abcd'); this.set_cell_editor_cursor(0, 0, 2); this.test.assertEquals(this.get_cell_text(0), 'abcd', 'Verify that cell 0 has the new contents.'); - this.trigger_keydown('ctrl-shift-minus'); // Split + this.trigger_keydown('ctrl-shift-subtract'); // Split this.test.assertEquals(this.get_cell_text(0), 'ab', 'split; Verify that cell 0 has the first half.'); this.test.assertEquals(this.get_cell_text(1), 'cd', 'split; Verify that cell 1 has the second half.'); this.validate_notebook_state('split', 'edit', 1); From af03114ef6d565f2b1bf96e742d9dc75941cb606 Mon Sep 17 00:00:00 2001 From: Jonathan Frederic Date: Thu, 20 Mar 2014 16:15:24 -0700 Subject: [PATCH 35/38] s/set_cell_text/set_cells_text --- IPython/html/tests/notebook/merge_cells_api.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/IPython/html/tests/notebook/merge_cells_api.js b/IPython/html/tests/notebook/merge_cells_api.js index e6f844caa..5329b6f0d 100644 --- a/IPython/html/tests/notebook/merge_cells_api.js +++ b/IPython/html/tests/notebook/merge_cells_api.js @@ -22,14 +22,14 @@ casper.notebook_test(function() { }); // merge_cell_above() - set_cell_text(); + set_cells_text(); var output_above = this.evaluate(function () { IPython.notebook.merge_cell_above(); return IPython.notebook.get_selected_cell(); }); // merge_cell_below() - set_cell_text(); + set_cells_text(); var output_below = this.evaluate(function() { IPython.notebook.select(0); IPython.notebook.merge_cell_below(); From 744f057cabd215dc8e9f40ba22bd828107f74d9c Mon Sep 17 00:00:00 2001 From: Jonathan Frederic Date: Thu, 20 Mar 2014 16:22:54 -0700 Subject: [PATCH 36/38] get_text() before returning results --- IPython/html/tests/notebook/merge_cells_api.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/IPython/html/tests/notebook/merge_cells_api.js b/IPython/html/tests/notebook/merge_cells_api.js index 5329b6f0d..9dd2fbdcb 100644 --- a/IPython/html/tests/notebook/merge_cells_api.js +++ b/IPython/html/tests/notebook/merge_cells_api.js @@ -25,7 +25,7 @@ casper.notebook_test(function() { set_cells_text(); var output_above = this.evaluate(function () { IPython.notebook.merge_cell_above(); - return IPython.notebook.get_selected_cell(); + return IPython.notebook.get_selected_cell().get_text(); }); // merge_cell_below() @@ -33,7 +33,7 @@ casper.notebook_test(function() { var output_below = this.evaluate(function() { IPython.notebook.select(0); IPython.notebook.merge_cell_below(); - return IPython.notebook.get_selected_cell(); + return IPython.notebook.get_selected_cell().get_text(); }); this.test.assertEquals(output_above, 'a = 5\nprint(a)', From 607b96b19a1a14be07d9eee01791bfc47b52aef5 Mon Sep 17 00:00:00 2001 From: Jonathan Frederic Date: Thu, 20 Mar 2014 18:45:06 -0700 Subject: [PATCH 37/38] Actually remove the trigger keydown method --- IPython/html/static/base/js/keyboard.js | 9 --------- 1 file changed, 9 deletions(-) diff --git a/IPython/html/static/base/js/keyboard.js b/IPython/html/static/base/js/keyboard.js index a5c8a69de..e3c74b74b 100644 --- a/IPython/html/static/base/js/keyboard.js +++ b/IPython/html/static/base/js/keyboard.js @@ -128,15 +128,6 @@ IPython.keyboard = (function (IPython) { return shortcut; }; - var trigger_keydown = function (shortcut, element) { - // Trigger shortcut keydown on an element - element = element || document; - element = $(element); - var event = shortcut_to_event(shortcut, 'keydown'); - element.trigger(event); - } - - // Shortcut manager class var ShortcutManager = function (delay) { From e1daedf95bd6dc5d38f65f653a7e32f831e6055c Mon Sep 17 00:00:00 2001 From: Jonathan Frederic Date: Mon, 24 Mar 2014 15:43:10 -0700 Subject: [PATCH 38/38] Fixed keyboard.js indent break --- IPython/html/static/base/js/keyboard.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/IPython/html/static/base/js/keyboard.js b/IPython/html/static/base/js/keyboard.js index e3c74b74b..edfd7da07 100644 --- a/IPython/html/static/base/js/keyboard.js +++ b/IPython/html/static/base/js/keyboard.js @@ -183,7 +183,7 @@ IPython.keyboard = (function (IPython) { if (!suppress_help_update) { // update the keyboard shortcuts notebook help $([IPython.events]).trigger('rebuild.QuickHelp'); - } + } }; ShortcutManager.prototype.add_shortcuts = function (data) { @@ -201,7 +201,7 @@ IPython.keyboard = (function (IPython) { if (!suppress_help_update) { // update the keyboard shortcuts notebook help $([IPython.events]).trigger('rebuild.QuickHelp'); - } + } }; ShortcutManager.prototype.count_handler = function (shortcut, event, data) {