##// END OF EJS Templates
Merge pull request #5290 from jdfreder/dual_tests...
Thomas Kluyver -
r16028:78455bac merge
parent child Browse files
Show More
@@ -0,0 +1,78 b''
1 // Test the notebook dual mode feature.
2
3 // Test
4 casper.notebook_test(function () {
5 var a = 'print("a")';
6 var index = this.append_cell(a);
7 this.execute_cell_then(index);
8
9 var b = 'print("b")';
10 index = this.append_cell(b);
11 this.execute_cell_then(index);
12
13 var c = 'print("c")';
14 index = this.append_cell(c);
15 this.execute_cell_then(index);
16
17 this.then(function () {
18 this.validate_notebook_state('initial state', 'edit', 0);
19 this.trigger_keydown('esc');
20 this.validate_notebook_state('esc', 'command', 0);
21 this.trigger_keydown('down');
22 this.validate_notebook_state('down', 'command', 1);
23 this.trigger_keydown('enter');
24 this.validate_notebook_state('enter', 'edit', 1);
25 this.trigger_keydown('j');
26 this.validate_notebook_state('j in edit mode', 'edit', 1);
27 this.trigger_keydown('esc');
28 this.validate_notebook_state('esc', 'command', 1);
29 this.trigger_keydown('j');
30 this.validate_notebook_state('j in command mode', 'command', 2);
31 this.click_cell_editor(0);
32 this.validate_notebook_state('click cell 0', 'edit', 0);
33 this.click_cell_editor(3);
34 this.validate_notebook_state('click cell 3', 'edit', 3);
35 this.trigger_keydown('esc');
36 this.validate_notebook_state('esc', 'command', 3);
37
38 // Open keyboard help
39 this.evaluate(function(){
40 $('#keyboard_shortcuts a').click();
41 }, {});
42
43 this.trigger_keydown('k');
44 this.validate_notebook_state('k in command mode while keyboard help is up', 'command', 3);
45
46 // Close keyboard help
47 this.evaluate(function(){
48 $('div.modal button.close').click();
49 }, {});
50
51 this.trigger_keydown('k');
52 this.validate_notebook_state('k in command mode', 'command', 2);
53 this.click_cell_editor(0);
54 this.validate_notebook_state('click cell 0', 'edit', 0);
55 this.focus_notebook();
56 this.validate_notebook_state('focus #notebook', 'command', 0);
57 this.click_cell_editor(0);
58 this.validate_notebook_state('click cell 0', 'edit', 0);
59 this.focus_notebook();
60 this.validate_notebook_state('focus #notebook', 'command', 0);
61 this.click_cell_editor(3);
62 this.validate_notebook_state('click cell 3', 'edit', 3);
63
64 // Cell deletion
65 this.trigger_keydown('esc', 'd', 'd');
66 this.test.assertEquals(this.get_cells_length(), 3, 'dd actually deletes a cell');
67 this.validate_notebook_state('dd', 'command', 2);
68
69 // Make sure that if the time between d presses is too long, nothing gets removed.
70 this.trigger_keydown('d');
71 });
72 this.wait(1000);
73 this.then(function () {
74 this.trigger_keydown('d');
75 this.test.assertEquals(this.get_cells_length(), 3, "d, 1 second wait, d doesn't delete a cell");
76 this.validate_notebook_state('d, 1 second wait, d', 'command', 2);
77 });
78 });
@@ -0,0 +1,51 b''
1
2 // Test
3 casper.notebook_test(function () {
4 var a = 'print("a")';
5 var index = this.append_cell(a);
6 this.execute_cell_then(index);
7
8 var b = 'print("b")';
9 index = this.append_cell(b);
10 this.execute_cell_then(index);
11
12 var c = 'print("c")';
13 index = this.append_cell(c);
14 this.execute_cell_then(index);
15
16 this.then(function () {
17
18 // Up and down in command mode
19 this.select_cell(3);
20 this.trigger_keydown('j');
21 this.validate_notebook_state('j at end of notebook', 'command', 3);
22 this.trigger_keydown('down');
23 this.validate_notebook_state('down at end of notebook', 'command', 3);
24 this.trigger_keydown('up');
25 this.validate_notebook_state('up', 'command', 2);
26 this.select_cell(0);
27 this.validate_notebook_state('select 0', 'command', 0);
28 this.trigger_keydown('k');
29 this.validate_notebook_state('k at top of notebook', 'command', 0);
30 this.trigger_keydown('up');
31 this.validate_notebook_state('up at top of notebook', 'command', 0);
32 this.trigger_keydown('down');
33 this.validate_notebook_state('down', 'command', 1);
34
35 // Up and down in edit mode
36 this.click_cell_editor(3);
37 this.validate_notebook_state('click cell 3', 'edit', 3);
38 this.trigger_keydown('down');
39 this.validate_notebook_state('down at end of notebook', 'edit', 3);
40 this.set_cell_editor_cursor(3, 0, 0);
41 this.trigger_keydown('up');
42 this.validate_notebook_state('up', 'edit', 2);
43 this.click_cell_editor(0);
44 this.validate_notebook_state('click 0', 'edit', 0);
45 this.trigger_keydown('up');
46 this.validate_notebook_state('up at top of notebook', 'edit', 0);
47 this.set_cell_editor_cursor(0, 0, 10);
48 this.trigger_keydown('down');
49 this.validate_notebook_state('down', 'edit', 1);
50 });
51 });
@@ -0,0 +1,27 b''
1
2 // Test
3 casper.notebook_test(function () {
4 var a = 'print("a")';
5 var index = this.append_cell(a);
6 this.execute_cell_then(index);
7
8 var b = 'print("b")';
9 index = this.append_cell(b);
10 this.execute_cell_then(index);
11
12 var c = 'print("c")';
13 index = this.append_cell(c);
14 this.execute_cell_then(index);
15
16 this.then(function () {
17 // Cell insertion
18 this.select_cell(2);
19 this.trigger_keydown('a'); // Creates one cell
20 this.test.assertEquals(this.get_cell_text(2), '', 'a; New cell 2 text is empty');
21 this.validate_notebook_state('a', 'command', 2);
22 this.trigger_keydown('b'); // Creates one cell
23 this.test.assertEquals(this.get_cell_text(2), '', 'b; Cell 2 text is still empty');
24 this.test.assertEquals(this.get_cell_text(3), '', 'b; New cell 3 text is empty');
25 this.validate_notebook_state('b', 'command', 3);
26 });
27 }); No newline at end of file
@@ -0,0 +1,28 b''
1 // Test keyboard shortcuts that change the cell's mode.
2
3 // Test
4 casper.notebook_test(function () {
5 this.then(function () {
6 // Cell mode change
7 this.select_cell(0);
8 this.trigger_keydown('esc','r');
9 this.test.assertEquals(this.get_cell(0).cell_type, 'raw', 'r; cell is raw');
10 this.trigger_keydown('1');
11 this.test.assertEquals(this.get_cell(0).cell_type, 'heading', '1; cell is heading');
12 this.test.assertEquals(this.get_cell(0).level, 1, '1; cell is level 1 heading');
13 this.trigger_keydown('2');
14 this.test.assertEquals(this.get_cell(0).level, 2, '2; cell is level 2 heading');
15 this.trigger_keydown('3');
16 this.test.assertEquals(this.get_cell(0).level, 3, '3; cell is level 3 heading');
17 this.trigger_keydown('4');
18 this.test.assertEquals(this.get_cell(0).level, 4, '4; cell is level 4 heading');
19 this.trigger_keydown('5');
20 this.test.assertEquals(this.get_cell(0).level, 5, '5; cell is level 5 heading');
21 this.trigger_keydown('6');
22 this.test.assertEquals(this.get_cell(0).level, 6, '6; cell is level 6 heading');
23 this.trigger_keydown('m');
24 this.test.assertEquals(this.get_cell(0).cell_type, 'markdown', 'm; cell is markdown');
25 this.trigger_keydown('y');
26 this.test.assertEquals(this.get_cell(0).cell_type, 'code', 'y; cell is code');
27 });
28 }); No newline at end of file
@@ -0,0 +1,55 b''
1
2
3 // Test
4 casper.notebook_test(function () {
5 var a = 'print("a")';
6 var index = this.append_cell(a);
7 this.execute_cell_then(index);
8
9 var b = 'print("b")';
10 index = this.append_cell(b);
11 this.execute_cell_then(index);
12
13 var c = 'print("c")';
14 index = this.append_cell(c);
15 this.execute_cell_then(index);
16
17 this.then(function () {
18 // Copy/paste/cut
19 var num_cells = this.get_cells_length();
20 this.test.assertEquals(this.get_cell_text(1), a, 'Verify that cell 1 is a');
21 this.select_cell(1);
22 this.trigger_keydown('x'); // Cut
23 this.validate_notebook_state('x', 'command', 1);
24 this.test.assertEquals(this.get_cells_length(), num_cells-1, 'Verify that a cell was removed.');
25 this.test.assertEquals(this.get_cell_text(1), b, 'Verify that cell 2 is now where cell 1 was.');
26 this.select_cell(2);
27 this.trigger_keydown('v'); // Paste
28 this.validate_notebook_state('v', 'command', 3); // Selection should move to pasted cell, below current cell.
29 this.test.assertEquals(this.get_cell_text(3), a, 'Verify that cell 3 has the cut contents.');
30 this.test.assertEquals(this.get_cells_length(), num_cells, 'Verify a the cell was added.');
31 this.trigger_keydown('v'); // Paste
32 this.validate_notebook_state('v', 'command', 4); // Selection should move to pasted cell, below current cell.
33 this.test.assertEquals(this.get_cell_text(4), a, 'Verify that cell 4 has the cut contents.');
34 this.test.assertEquals(this.get_cells_length(), num_cells+1, 'Verify a the cell was added.');
35 this.select_cell(1);
36 this.trigger_keydown('c'); // Copy
37 this.validate_notebook_state('c', 'command', 1);
38 this.test.assertEquals(this.get_cell_text(1), b, 'Verify that cell 1 is b');
39 this.select_cell(2);
40 this.trigger_keydown('c'); // Copy
41 this.validate_notebook_state('c', 'command', 2);
42 this.test.assertEquals(this.get_cell_text(2), c, 'Verify that cell 2 is c');
43 this.select_cell(4);
44 this.trigger_keydown('v'); // Paste
45 this.validate_notebook_state('v', 'command', 5);
46 this.test.assertEquals(this.get_cell_text(2), c, 'Verify that cell 2 still has the copied contents.');
47 this.test.assertEquals(this.get_cell_text(5), c, 'Verify that cell 5 has the copied contents.');
48 this.test.assertEquals(this.get_cells_length(), num_cells+2, 'Verify a the cell was added.');
49 this.select_cell(0);
50 this.trigger_keydown('shift-v'); // Paste
51 this.validate_notebook_state('shift-v', 'command', 0);
52 this.test.assertEquals(this.get_cell_text(0), c, 'Verify that cell 0 has the copied contents.');
53 this.test.assertEquals(this.get_cells_length(), num_cells+3, 'Verify a the cell was added.');
54 });
55 }); No newline at end of file
@@ -0,0 +1,72 b''
1 // Test keyboard invoked execution.
2
3 // Test
4 casper.notebook_test(function () {
5 var a = 'print("a")';
6 var index = this.append_cell(a);
7 this.execute_cell_then(index);
8
9 var b = 'print("b")';
10 index = this.append_cell(b);
11 this.execute_cell_then(index);
12
13 var c = 'print("c")';
14 index = this.append_cell(c);
15 this.execute_cell_then(index);
16
17 this.then(function () {
18
19 // shift-enter
20 // last cell in notebook
21 var base_index = 3;
22 this.select_cell(base_index);
23 this.trigger_keydown('shift-enter'); // Creates one cell
24 this.validate_notebook_state('shift-enter (no cell below)', 'edit', base_index + 1);
25 // not last cell in notebook & starts in edit mode
26 this.click_cell_editor(base_index);
27 this.validate_notebook_state('click cell ' + base_index, 'edit', base_index);
28 this.trigger_keydown('shift-enter');
29 this.validate_notebook_state('shift-enter (cell exists below)', 'command', base_index + 1);
30 // starts in command mode
31 this.trigger_keydown('k');
32 this.validate_notebook_state('k in comand mode', 'command', base_index);
33 this.trigger_keydown('shift-enter');
34 this.validate_notebook_state('shift-enter (start in command mode)', 'command', base_index + 1);
35
36 // ctrl-enter
37 // last cell in notebook
38 base_index++;
39 this.trigger_keydown('ctrl-enter');
40 this.validate_notebook_state('ctrl-enter (no cell below)', 'command', base_index);
41 // not last cell in notebook & starts in edit mode
42 this.click_cell_editor(base_index-1);
43 this.validate_notebook_state('click cell ' + (base_index-1), 'edit', base_index-1);
44 this.trigger_keydown('ctrl-enter');
45 this.validate_notebook_state('ctrl-enter (cell exists below)', 'command', base_index-1);
46 // starts in command mode
47 this.trigger_keydown('j');
48 this.validate_notebook_state('j in comand mode', 'command', base_index);
49 this.trigger_keydown('ctrl-enter');
50 this.validate_notebook_state('ctrl-enter (start in command mode)', 'command', base_index);
51
52 // alt-enter
53 // last cell in notebook
54 this.trigger_keydown('alt-enter'); // Creates one cell
55 this.validate_notebook_state('alt-enter (no cell below)', 'edit', base_index + 1);
56 // not last cell in notebook & starts in edit mode
57 this.click_cell_editor(base_index);
58 this.validate_notebook_state('click cell ' + base_index, 'edit', base_index);
59 this.trigger_keydown('alt-enter'); // Creates one cell
60 this.validate_notebook_state('alt-enter (cell exists below)', 'edit', base_index + 1);
61 // starts in command mode
62 this.trigger_keydown('esc', 'k');
63 this.validate_notebook_state('k in comand mode', 'command', base_index);
64 this.trigger_keydown('alt-enter'); // Creates one cell
65 this.validate_notebook_state('alt-enter (start in command mode)', 'edit', base_index + 1);
66
67 // Notebook will now have 8 cells, the index of the last cell will be 7.
68 this.test.assertEquals(this.get_cells_length(), 8, '*-enter commands added cells where needed.');
69 this.select_cell(7);
70 this.validate_notebook_state('click cell ' + 7 + ' and esc', 'command', 7);
71 });
72 }); No newline at end of file
@@ -0,0 +1,39 b''
1
2 // Test
3 casper.notebook_test(function () {
4 var a = 'print("a")';
5 var index = this.append_cell(a);
6 this.execute_cell_then(index);
7
8 this.then(function () {
9 // Markdown rendering / unredering
10 this.select_cell(1);
11 this.validate_notebook_state('select 1', 'command', 1);
12 this.trigger_keydown('m');
13 this.test.assertEquals(this.get_cell(1).cell_type, 'markdown', 'm; cell is markdown');
14 this.test.assertEquals(this.get_cell(1).rendered, false, 'm; cell is rendered');
15 this.trigger_keydown('enter');
16 this.test.assertEquals(this.get_cell(1).rendered, false, 'enter; cell is unrendered');
17 this.validate_notebook_state('enter', 'edit', 1);
18 this.trigger_keydown('ctrl-enter');
19 this.test.assertEquals(this.get_cell(1).rendered, true, 'ctrl-enter; cell is rendered');
20 this.validate_notebook_state('enter', 'command', 1);
21 this.trigger_keydown('enter');
22 this.test.assertEquals(this.get_cell(1).rendered, false, 'enter; cell is unrendered');
23 this.select_cell(0);
24 this.test.assertEquals(this.get_cell(1).rendered, false, 'select 0; cell 1 is still unrendered');
25 this.validate_notebook_state('select 0', 'command', 0);
26 this.select_cell(1);
27 this.validate_notebook_state('select 1', 'command', 1);
28 this.trigger_keydown('ctrl-enter');
29 this.test.assertEquals(this.get_cell(1).rendered, true, 'ctrl-enter; cell is rendered');
30 this.select_cell(0);
31 this.validate_notebook_state('select 0', 'command', 0);
32 this.trigger_keydown('shift-enter');
33 this.validate_notebook_state('shift-enter', 'command', 1);
34 this.test.assertEquals(this.get_cell(1).rendered, true, 'shift-enter; cell is rendered');
35 this.trigger_keydown('shift-enter'); // Creates one cell
36 this.validate_notebook_state('shift-enter', 'edit', 2);
37 this.test.assertEquals(this.get_cell(1).rendered, true, 'shift-enter; cell is rendered');
38 });
39 }); No newline at end of file
@@ -0,0 +1,21 b''
1
2 // Test
3 casper.notebook_test(function () {
4 this.then(function () {
5 // Split and merge cells
6 this.select_cell(0);
7 this.trigger_keydown('a', 'enter'); // Create cell above and enter edit mode.
8 this.validate_notebook_state('a, enter', 'edit', 0);
9 this.set_cell_text(0, 'abcd');
10 this.set_cell_editor_cursor(0, 0, 2);
11 this.test.assertEquals(this.get_cell_text(0), 'abcd', 'Verify that cell 0 has the new contents.');
12 this.trigger_keydown('ctrl-shift-subtract'); // Split
13 this.test.assertEquals(this.get_cell_text(0), 'ab', 'split; Verify that cell 0 has the first half.');
14 this.test.assertEquals(this.get_cell_text(1), 'cd', 'split; Verify that cell 1 has the second half.');
15 this.validate_notebook_state('split', 'edit', 1);
16 this.select_cell(0); // Move up to cell 0
17 this.trigger_keydown('shift-m'); // Merge
18 this.validate_notebook_state('merge', 'command', 0);
19 this.test.assertEquals(this.get_cell_text(0), 'ab\ncd', 'merge; Verify that cell 0 has the merged contents.');
20 });
21 }); No newline at end of file
@@ -0,0 +1,25 b''
1
2 // Test
3 casper.notebook_test(function () {
4 var a = 'print("a")';
5 var index = this.append_cell(a);
6 this.execute_cell_then(index);
7
8 var b = 'print("b")';
9 index = this.append_cell(b);
10 this.execute_cell_then(index);
11
12 this.then(function () {
13 // Cell movement ( ctrl-(k or j) )
14 this.select_cell(2);
15 this.test.assertEquals(this.get_cell_text(2), b, 'select 2; Cell 2 text is correct');
16 this.trigger_keydown('ctrl-k'); // Move cell 2 up one
17 this.test.assertEquals(this.get_cell_text(1), b, 'ctrl-k; Cell 1 text is correct');
18 this.test.assertEquals(this.get_cell_text(2), a, 'ctrl-k; Cell 2 text is correct');
19 this.validate_notebook_state('ctrl-k', 'command', 1);
20 this.trigger_keydown('ctrl-j'); // Move cell 1 down one
21 this.test.assertEquals(this.get_cell_text(1), a, 'ctrl-j; Cell 1 text is correct');
22 this.test.assertEquals(this.get_cell_text(2), b, 'ctrl-j; Cell 2 text is correct');
23 this.validate_notebook_state('ctrl-j', 'command', 2);
24 });
25 }); No newline at end of file
@@ -1,269 +1,259 b''
1 1 //----------------------------------------------------------------------------
2 2 // Copyright (C) 2011 The IPython Development Team
3 3 //
4 4 // Distributed under the terms of the BSD License. The full license is in
5 5 // the file COPYING, distributed as part of this software.
6 6 //----------------------------------------------------------------------------
7 7
8 8 //============================================================================
9 9 // Keyboard management
10 10 //============================================================================
11 11
12 12 IPython.namespace('IPython.keyboard');
13 13
14 14 IPython.keyboard = (function (IPython) {
15 15 "use strict";
16 16
17 17 // Setup global keycodes and inverse keycodes.
18 18
19 19 // See http://unixpapa.com/js/key.html for a complete description. The short of
20 20 // it is that there are different keycode sets. Firefox uses the "Mozilla keycodes"
21 21 // and Webkit/IE use the "IE keycodes". These keycode sets are mostly the same
22 22 // but have minor differences.
23 23
24 24 // These apply to Firefox, (Webkit and IE)
25 25 var _keycodes = {
26 26 'a': 65, 'b': 66, 'c': 67, 'd': 68, 'e': 69, 'f': 70, 'g': 71, 'h': 72, 'i': 73,
27 27 'j': 74, 'k': 75, 'l': 76, 'm': 77, 'n': 78, 'o': 79, 'p': 80, 'q': 81, 'r': 82,
28 28 's': 83, 't': 84, 'u': 85, 'v': 86, 'w': 87, 'x': 88, 'y': 89, 'z': 90,
29 29 '1 !': 49, '2 @': 50, '3 #': 51, '4 $': 52, '5 %': 53, '6 ^': 54,
30 30 '7 &': 55, '8 *': 56, '9 (': 57, '0 )': 48,
31 31 '[ {': 219, '] }': 221, '` ~': 192, ', <': 188, '. >': 190, '/ ?': 191,
32 32 '\\ |': 220, '\' "': 222,
33 33 'numpad0': 96, 'numpad1': 97, 'numpad2': 98, 'numpad3': 99, 'numpad4': 100,
34 34 'numpad5': 101, 'numpad6': 102, 'numpad7': 103, 'numpad8': 104, 'numpad9': 105,
35 35 'multiply': 106, 'add': 107, 'subtract': 109, 'decimal': 110, 'divide': 111,
36 36 'f1': 112, 'f2': 113, 'f3': 114, 'f4': 115, 'f5': 116, 'f6': 117, 'f7': 118,
37 37 'f8': 119, 'f9': 120, 'f11': 122, 'f12': 123, 'f13': 124, 'f14': 125, 'f15': 126,
38 38 'backspace': 8, 'tab': 9, 'enter': 13, 'shift': 16, 'ctrl': 17, 'alt': 18,
39 39 'meta': 91, 'capslock': 20, 'esc': 27, 'space': 32, 'pageup': 33, 'pagedown': 34,
40 40 'end': 35, 'home': 36, 'left': 37, 'up': 38, 'right': 39, 'down': 40,
41 41 'insert': 45, 'delete': 46, 'numlock': 144,
42 42 };
43 43
44 44 // These apply to Firefox and Opera
45 45 var _mozilla_keycodes = {
46 46 '; :': 59, '= +': 61, '- _': 173, 'meta': 224
47 47 };
48 48
49 49 // This apply to Webkit and IE
50 50 var _ie_keycodes = {
51 51 '; :': 186, '= +': 187, '- _': 189
52 52 };
53 53
54 54 var browser = IPython.utils.browser[0];
55 55 var platform = IPython.utils.platform;
56 56
57 57 if (browser === 'Firefox' || browser === 'Opera' || browser === 'Netscape') {
58 58 $.extend(_keycodes, _mozilla_keycodes);
59 59 } else if (browser === 'Safari' || browser === 'Chrome' || browser === 'MSIE') {
60 60 $.extend(_keycodes, _ie_keycodes);
61 61 }
62 62
63 63 var keycodes = {};
64 64 var inv_keycodes = {};
65 65 for (var name in _keycodes) {
66 66 var names = name.split(' ');
67 67 if (names.length === 1) {
68 68 var n = names[0];
69 69 keycodes[n] = _keycodes[n];
70 70 inv_keycodes[_keycodes[n]] = n;
71 71 } else {
72 72 var primary = names[0];
73 73 var secondary = names[1];
74 74 keycodes[primary] = _keycodes[name];
75 75 keycodes[secondary] = _keycodes[name];
76 76 inv_keycodes[_keycodes[name]] = primary;
77 77 }
78 78 }
79 79
80 80 var normalize_key = function (key) {
81 81 return inv_keycodes[keycodes[key]];
82 82 };
83 83
84 84 var normalize_shortcut = function (shortcut) {
85 85 // Put a shortcut into normalized form:
86 86 // 1. Make lowercase
87 87 // 2. Replace cmd by meta
88 88 // 3. Sort '-' separated modifiers into the order alt-ctrl-meta-shift
89 89 // 4. Normalize keys
90 90 shortcut = shortcut.toLowerCase().replace('cmd', 'meta');
91 91 shortcut = shortcut.replace(/-$/, '_'); // catch shortcuts using '-' key
92 92 var values = shortcut.split("-");
93 93 if (values.length === 1) {
94 94 return normalize_key(values[0]);
95 95 } else {
96 96 var modifiers = values.slice(0,-1);
97 97 var key = normalize_key(values[values.length-1]);
98 98 modifiers.sort();
99 99 return modifiers.join('-') + '-' + key;
100 100 }
101 101 };
102 102
103 103 var shortcut_to_event = function (shortcut, type) {
104 104 // Convert a shortcut (shift-r) to a jQuery Event object
105 105 type = type || 'keydown';
106 106 shortcut = normalize_shortcut(shortcut);
107 107 shortcut = shortcut.replace(/-$/, '_'); // catch shortcuts using '-' key
108 108 var values = shortcut.split("-");
109 109 var modifiers = values.slice(0,-1);
110 110 var key = values[values.length-1];
111 111 var opts = {which: keycodes[key]};
112 112 if (modifiers.indexOf('alt') !== -1) {opts.altKey = true;}
113 113 if (modifiers.indexOf('ctrl') !== -1) {opts.ctrlKey = true;}
114 114 if (modifiers.indexOf('meta') !== -1) {opts.metaKey = true;}
115 115 if (modifiers.indexOf('shift') !== -1) {opts.shiftKey = true;}
116 116 return $.Event(type, opts);
117 117 };
118 118
119 119 var event_to_shortcut = function (event) {
120 120 // Convert a jQuery Event object to a shortcut (shift-r)
121 121 var shortcut = '';
122 122 var key = inv_keycodes[event.which];
123 123 if (event.altKey && key !== 'alt') {shortcut += 'alt-';}
124 124 if (event.ctrlKey && key !== 'ctrl') {shortcut += 'ctrl-';}
125 125 if (event.metaKey && key !== 'meta') {shortcut += 'meta-';}
126 126 if (event.shiftKey && key !== 'shift') {shortcut += 'shift-';}
127 127 shortcut += key;
128 128 return shortcut;
129 129 };
130 130
131 var trigger_keydown = function (shortcut, element) {
132 // Trigger shortcut keydown on an element
133 element = element || document;
134 element = $(element);
135 var event = shortcut_to_event(shortcut, 'keydown');
136 element.trigger(event);
137 };
138
139
140 131 // Shortcut manager class
141 132
142 133 var ShortcutManager = function (delay) {
143 134 this._shortcuts = {};
144 135 this._counts = {};
145 136 this._timers = {};
146 137 this.delay = delay || 800; // delay in milliseconds
147 138 };
148 139
149 140 ShortcutManager.prototype.help = function () {
150 141 var help = [];
151 142 for (var shortcut in this._shortcuts) {
152 143 var help_string = this._shortcuts[shortcut]['help'];
153 144 var help_index = this._shortcuts[shortcut]['help_index'];
154 145 if (help_string) {
155 146 if (platform === 'MacOS') {
156 147 shortcut = shortcut.replace('meta', 'cmd');
157 148 }
158 149 help.push({
159 150 shortcut: shortcut,
160 151 help: help_string,
161 152 help_index: help_index}
162 153 );
163 154 }
164 155 }
165 156 help.sort(function (a, b) {
166 157 if (a.help_index > b.help_index)
167 158 return 1;
168 159 if (a.help_index < b.help_index)
169 160 return -1;
170 161 return 0;
171 162 });
172 163 return help;
173 164 };
174 165
175 166 ShortcutManager.prototype.clear_shortcuts = function () {
176 167 this._shortcuts = {};
177 168 };
178 169
179 170 ShortcutManager.prototype.add_shortcut = function (shortcut, data, suppress_help_update) {
180 171 if (typeof(data) === 'function') {
181 172 data = {help: '', help_index: '', handler: data};
182 173 }
183 174 data.help_index = data.help_index || '';
184 175 data.help = data.help || '';
185 176 data.count = data.count || 1;
186 177 if (data.help_index === '') {
187 178 data.help_index = 'zz';
188 179 }
189 180 shortcut = normalize_shortcut(shortcut);
190 181 this._counts[shortcut] = 0;
191 182 this._shortcuts[shortcut] = data;
192 183 if (!suppress_help_update) {
193 184 // update the keyboard shortcuts notebook help
194 185 $([IPython.events]).trigger('rebuild.QuickHelp');
195 186 }
196 187 };
197 188
198 189 ShortcutManager.prototype.add_shortcuts = function (data) {
199 190 for (var shortcut in data) {
200 191 this.add_shortcut(shortcut, data[shortcut], true);
201 192 }
202 193 // update the keyboard shortcuts notebook help
203 194 $([IPython.events]).trigger('rebuild.QuickHelp');
204 195 };
205 196
206 197 ShortcutManager.prototype.remove_shortcut = function (shortcut, suppress_help_update) {
207 198 shortcut = normalize_shortcut(shortcut);
208 199 delete this._counts[shortcut];
209 200 delete this._shortcuts[shortcut];
210 201 if (!suppress_help_update) {
211 202 // update the keyboard shortcuts notebook help
212 203 $([IPython.events]).trigger('rebuild.QuickHelp');
213 204 }
214 205 };
215 206
216 207 ShortcutManager.prototype.count_handler = function (shortcut, event, data) {
217 208 var that = this;
218 209 var c = this._counts;
219 210 var t = this._timers;
220 211 var timer = null;
221 212 if (c[shortcut] === data.count-1) {
222 213 c[shortcut] = 0;
223 214 var timer = t[shortcut];
224 215 if (timer) {clearTimeout(timer); delete t[shortcut];}
225 216 return data.handler(event);
226 217 } else {
227 218 c[shortcut] = c[shortcut] + 1;
228 219 timer = setTimeout(function () {
229 220 c[shortcut] = 0;
230 221 }, that.delay);
231 222 t[shortcut] = timer;
232 223 }
233 224 return false;
234 225 };
235 226
236 227 ShortcutManager.prototype.call_handler = function (event) {
237 228 var shortcut = event_to_shortcut(event);
238 229 var data = this._shortcuts[shortcut];
239 230 if (data) {
240 231 var handler = data['handler'];
241 232 if (handler) {
242 233 if (data.count === 1) {
243 234 return handler(event);
244 235 } else if (data.count > 1) {
245 236 return this.count_handler(shortcut, event, data);
246 237 }
247 238 }
248 239 }
249 240 return true;
250 241 };
251 242
252 243 ShortcutManager.prototype.handles = function (event) {
253 244 var shortcut = event_to_shortcut(event);
254 245 var data = this._shortcuts[shortcut];
255 246 return !( data === undefined || data.handler === undefined )
256 247 }
257 248
258 249 return {
259 250 keycodes : keycodes,
260 251 inv_keycodes : inv_keycodes,
261 252 ShortcutManager : ShortcutManager,
262 253 normalize_key : normalize_key,
263 254 normalize_shortcut : normalize_shortcut,
264 255 shortcut_to_event : shortcut_to_event,
265 event_to_shortcut : event_to_shortcut,
266 trigger_keydown : trigger_keydown
256 event_to_shortcut : event_to_shortcut
267 257 };
268 258
269 259 }(IPython));
@@ -1,21 +1,21 b''
1 1 //
2 2 // Check for errors with up and down arrow presses in an empty notebook.
3 3 //
4 4 casper.notebook_test(function () {
5 5 var result = this.evaluate(function() {
6 6 var ncells = IPython.notebook.ncells();
7 7 var i;
8 8
9 9 // Delete all cells.
10 10 for (i = 0; i < ncells; i++) {
11 11 IPython.notebook.delete_cell();
12 12 }
13
14 // Simulate the "up arrow" and "down arrow" keys.
15 //
16 IPython.keyboard.trigger_keydown('up');
17 IPython.keyboard.trigger_keydown('down');
13
18 14 return true;
19 15 });
16
17 // Simulate the "up arrow" and "down arrow" keys.
18 this.trigger_keydown('up');
19 this.trigger_keydown('down');
20 20 this.test.assertTrue(result, 'Up/down arrow okay in empty notebook.');
21 21 });
@@ -1,71 +1,78 b''
1 1 //
2 2 // Test code cell execution.
3 3 //
4 4 casper.notebook_test(function () {
5 5 this.evaluate(function () {
6 6 var cell = IPython.notebook.get_cell(0);
7 7 cell.set_text('a=10; print(a)');
8 8 cell.execute();
9 9 });
10 10
11 11 this.wait_for_output(0);
12 12
13 13 // refactor this into just a get_output(0)
14 14 this.then(function () {
15 15 var result = this.get_output_cell(0);
16 16 this.test.assertEquals(result.text, '10\n', 'cell execute (using js)');
17 17 });
18 18
19 19
20 20 // do it again with the keyboard shortcut
21 21 this.thenEvaluate(function () {
22 22 var cell = IPython.notebook.get_cell(0);
23 23 cell.set_text('a=11; print(a)');
24 24 cell.clear_output();
25 IPython.keyboard.trigger_keydown('shift-enter');
25 });
26
27 this.then(function(){
28
29 this.trigger_keydown('shift-enter');
26 30 });
27 31
28 32 this.wait_for_output(0);
29 33
30 34 this.then(function () {
31 35 var result = this.get_output_cell(0);
32 36 var num_cells = this.get_cells_length();
33 37 this.test.assertEquals(result.text, '11\n', 'cell execute (using ctrl-enter)');
34 38 this.test.assertEquals(num_cells, 2, 'shift-enter adds a new cell at the bottom')
35 39 });
36 40
37 41 // do it again with the keyboard shortcut
38 42 this.thenEvaluate(function () {
39 43 IPython.notebook.select(1);
40 44 IPython.notebook.delete_cell();
41 45 var cell = IPython.notebook.get_cell(0);
42 46 cell.set_text('a=12; print(a)');
43 47 cell.clear_output();
44 IPython.keyboard.trigger_keydown('ctrl-enter');
48 });
49
50 this.then(function(){
51 this.trigger_keydown('ctrl-enter');
45 52 });
46 53
47 54 this.wait_for_output(0);
48 55
49 56 this.then(function () {
50 57 var result = this.get_output_cell(0);
51 58 var num_cells = this.get_cells_length();
52 59 this.test.assertEquals(result.text, '12\n', 'cell execute (using shift-enter)');
53 60 this.test.assertEquals(num_cells, 1, 'ctrl-enter adds no new cell at the bottom')
54 61 });
55 62
56 63 // press the "play" triangle button in the toolbar
57 64 this.thenEvaluate(function () {
58 65 var cell = IPython.notebook.get_cell(0);
59 66 IPython.notebook.select(0);
60 67 cell.clear_output();
61 68 cell.set_text('a=13; print(a)');
62 69 $('#run_b').click();
63 70 });
64 71
65 72 this.wait_for_output(0);
66 73
67 74 this.then(function () {
68 75 var result = this.get_output_cell(0);
69 76 this.test.assertEquals(result.text, '13\n', 'cell execute (using "play" toolbar button)')
70 77 });
71 78 });
@@ -1,44 +1,44 b''
1 1 //
2 2 // Test kernel interrupt
3 3 //
4 4 casper.notebook_test(function () {
5 5 this.evaluate(function () {
6 6 var cell = IPython.notebook.get_cell(0);
7 7 cell.set_text(
8 8 'import time'+
9 9 '\nfor x in range(3):'+
10 10 '\n time.sleep(1)'
11 11 );
12 12 cell.execute();
13 13 });
14 14
15 15 this.wait_for_busy();
16 16
17 17 // interrupt using menu item (Kernel -> Interrupt)
18 18 this.thenClick('li#int_kernel');
19 19
20 20 this.wait_for_output(0);
21 21
22 22 this.then(function () {
23 23 var result = this.get_output_cell(0);
24 24 this.test.assertEquals(result.ename, 'KeyboardInterrupt', 'keyboard interrupt (mouseclick)');
25 25 });
26 26
27 27 // run cell 0 again, now interrupting using keyboard shortcut
28 28 this.thenEvaluate(function () {
29 29 cell.clear_output();
30 30 cell.execute();
31 31 });
32 32
33 33 // interrupt using Ctrl-M I keyboard shortcut
34 this.thenEvaluate( function() {
35 IPython.keyboard.trigger_keydown('i');
34 this.then(function(){
35 this.trigger_keydown('i');
36 36 });
37 37
38 38 this.wait_for_output(0);
39 39
40 40 this.then(function () {
41 41 var result = this.get_output_cell(0);
42 42 this.test.assertEquals(result.ename, 'KeyboardInterrupt', 'keyboard interrupt (shortcut)');
43 43 });
44 44 });
@@ -1,38 +1,43 b''
1 1 //
2 2 // Test merging two notebook cells.
3 3 //
4 4 casper.notebook_test(function() {
5 var output = this.evaluate(function () {
6 // Fill in test data.
7 IPython.notebook.command_mode();
8 var set_cell_text = function () {
5 var that = this;
6 var set_cells_text = function () {
7 that.evaluate(function() {
9 8 var cell_one = IPython.notebook.get_selected_cell();
10 9 cell_one.set_text('a = 5');
11
12 IPython.keyboard.trigger_keydown('b');
10 });
11
12 that.trigger_keydown('b');
13
14 that.evaluate(function() {
13 15 var cell_two = IPython.notebook.get_selected_cell();
14 16 cell_two.set_text('print(a)');
15 };
17 });
18 };
19
20 this.evaluate(function () {
21 IPython.notebook.command_mode();
22 });
16 23
17 // merge_cell_above()
18 set_cell_text();
24 // merge_cell_above()
25 set_cells_text();
26 var output_above = this.evaluate(function () {
19 27 IPython.notebook.merge_cell_above();
20 var merged_above = IPython.notebook.get_selected_cell();
28 return IPython.notebook.get_selected_cell().get_text();
29 });
21 30
22 // merge_cell_below()
23 set_cell_text();
31 // merge_cell_below()
32 set_cells_text();
33 var output_below = this.evaluate(function() {
24 34 IPython.notebook.select(0);
25 35 IPython.notebook.merge_cell_below();
26 var merged_below = IPython.notebook.get_selected_cell();
27
28 return {
29 above: merged_above.get_text(),
30 below: merged_below.get_text()
31 };
36 return IPython.notebook.get_selected_cell().get_text();
32 37 });
33 38
34 this.test.assertEquals(output.above, 'a = 5\nprint(a)',
39 this.test.assertEquals(output_above, 'a = 5\nprint(a)',
35 40 'Successful merge_cell_above().');
36 this.test.assertEquals(output.below, 'a = 5\nprint(a)',
41 this.test.assertEquals(output_below, 'a = 5\nprint(a)',
37 42 'Successful merge_cell_below().');
38 43 });
@@ -1,292 +1,478 b''
1 1 //
2 2 // Utility functions for the HTML notebook's CasperJS tests.
3 3 //
4 4
5 // Get the URL of a notebook server on which to run tests.
6 5 casper.get_notebook_server = function () {
7 port = casper.cli.get("port")
6 // Get the URL of a notebook server on which to run tests.
7 port = casper.cli.get("port");
8 8 port = (typeof port === 'undefined') ? '8888' : port;
9 return 'http://127.0.0.1:' + port
9 return 'http://127.0.0.1:' + port;
10 10 };
11 11
12 // Create and open a new notebook.
13 12 casper.open_new_notebook = function () {
13 // Create and open a new notebook.
14 14 var baseUrl = this.get_notebook_server();
15 15 this.start(baseUrl);
16 16 this.thenClick('button#new_notebook');
17 17 this.waitForPopup('');
18 18
19 19 this.withPopup('', function () {this.waitForSelector('.CodeMirror-code');});
20 20 this.then(function () {
21 21 this.open(this.popups[0].url);
22 22 });
23 23
24 24 // Make sure the kernel has started
25 25 this.waitFor( this.kernel_running );
26 26 // track the IPython busy/idle state
27 27 this.thenEvaluate(function () {
28 28 $([IPython.events]).on('status_idle.Kernel',function () {
29 29 IPython._status = 'idle';
30 30 });
31 31 $([IPython.events]).on('status_busy.Kernel',function () {
32 32 IPython._status = 'busy';
33 33 });
34 34 });
35 35 };
36 36
37 // Return whether or not the kernel is running.
38 37 casper.kernel_running = function kernel_running() {
38 // Return whether or not the kernel is running.
39 39 return this.evaluate(function kernel_running() {
40 40 return IPython.notebook.kernel.running;
41 41 });
42 42 };
43 43
44 // Shut down the current notebook's kernel.
45 44 casper.shutdown_current_kernel = function () {
45 // Shut down the current notebook's kernel.
46 46 this.thenEvaluate(function() {
47 47 IPython.notebook.kernel.kill();
48 48 });
49 49 // We close the page right after this so we need to give it time to complete.
50 50 this.wait(1000);
51 51 };
52 52
53 // Delete created notebook.
54 53 casper.delete_current_notebook = function () {
54 // Delete created notebook.
55
55 56 // For some unknown reason, this doesn't work?!?
56 57 this.thenEvaluate(function() {
57 58 IPython.notebook.delete();
58 59 });
59 60 };
60 61
61 62 casper.wait_for_busy = function () {
63 // Waits for the notebook to enter a busy state.
62 64 this.waitFor(function () {
63 65 return this.evaluate(function () {
64 66 return IPython._status == 'busy';
65 67 });
66 68 });
67 69 };
68 70
69 71 casper.wait_for_idle = function () {
72 // Waits for the notebook to idle.
70 73 this.waitFor(function () {
71 74 return this.evaluate(function () {
72 75 return IPython._status == 'idle';
73 76 });
74 77 });
75 78 };
76 79
77 // wait for the nth output in a given cell
78 80 casper.wait_for_output = function (cell_num, out_num) {
81 // wait for the nth output in a given cell
79 82 this.wait_for_idle();
80 83 out_num = out_num || 0;
81 84 this.then(function() {
82 85 this.waitFor(function (c, o) {
83 86 return this.evaluate(function get_output(c, o) {
84 87 var cell = IPython.notebook.get_cell(c);
85 88 return cell.output_area.outputs.length > o;
86 89 },
87 90 // pass parameter from the test suite js to the browser code js
88 91 {c : cell_num, o : out_num});
89 92 });
90 93 },
91 94 function then() { },
92 95 function timeout() {
93 96 this.echo("wait_for_output timed out!");
94 97 });
95 98 };
96 99
97 // wait for a widget msg que to reach 0
98 //
99 // Parameters
100 // ----------
101 // widget_info : object
102 // Object which contains info related to the widget. The model_id property
103 // is used to identify the widget.
104 100 casper.wait_for_widget = function (widget_info) {
101 // wait for a widget msg que to reach 0
102 //
103 // Parameters
104 // ----------
105 // widget_info : object
106 // Object which contains info related to the widget. The model_id property
107 // is used to identify the widget.
105 108 this.waitFor(function () {
106 109 var pending = this.evaluate(function (m) {
107 110 return IPython.notebook.kernel.widget_manager.get_model(m).pending_msgs;
108 111 }, {m: widget_info.model_id});
109 112
110 if (pending == 0) {
113 if (pending === 0) {
111 114 return true;
112 115 } else {
113 116 return false;
114 117 }
115 118 });
116 }
119 };
117 120
118 // return an output of a given cell
119 121 casper.get_output_cell = function (cell_num, out_num) {
122 // return an output of a given cell
120 123 out_num = out_num || 0;
121 124 var result = casper.evaluate(function (c, o) {
122 125 var cell = IPython.notebook.get_cell(c);
123 126 return cell.output_area.outputs[o];
124 127 },
125 128 {c : cell_num, o : out_num});
126 129 if (!result) {
127 130 var num_outputs = casper.evaluate(function (c) {
128 131 var cell = IPython.notebook.get_cell(c);
129 132 return cell.output_area.outputs.length;
130 133 },
131 134 {c : cell_num});
132 135 this.test.assertTrue(false,
133 136 "Cell " + cell_num + " has no output #" + out_num + " (" + num_outputs + " total)"
134 137 );
135 138 } else {
136 139 return result;
137 140 }
138 141 };
139 142
140 // return the number of cells in the notebook
141 143 casper.get_cells_length = function () {
144 // return the number of cells in the notebook
142 145 var result = casper.evaluate(function () {
143 146 return IPython.notebook.get_cells().length;
144 })
147 });
145 148 return result;
146 149 };
147 150
148 // Set the text content of a cell.
149 151 casper.set_cell_text = function(index, text){
152 // Set the text content of a cell.
150 153 this.evaluate(function (index, text) {
151 154 var cell = IPython.notebook.get_cell(index);
152 155 cell.set_text(text);
153 156 }, index, text);
154 157 };
155 158
156 // Inserts a cell at the bottom of the notebook
157 // Returns the new cell's index.
159 casper.get_cell_text = function(index){
160 // Get the text content of a cell.
161 return this.evaluate(function (index) {
162 var cell = IPython.notebook.get_cell(index);
163 return cell.get_text();
164 }, index);
165 };
166
158 167 casper.insert_cell_at_bottom = function(cell_type){
168 // Inserts a cell at the bottom of the notebook
169 // Returns the new cell's index.
159 170 cell_type = cell_type || 'code';
160 171
161 172 return this.evaluate(function (cell_type) {
162 173 var cell = IPython.notebook.insert_cell_at_bottom(cell_type);
163 174 return IPython.notebook.find_cell_index(cell);
164 175 }, cell_type);
165 176 };
166 177
167 // Insert a cell at the bottom of the notebook and set the cells text.
168 // Returns the new cell's index.
169 178 casper.append_cell = function(text, cell_type) {
179 // Insert a cell at the bottom of the notebook and set the cells text.
180 // Returns the new cell's index.
170 181 var index = this.insert_cell_at_bottom(cell_type);
171 182 if (text !== undefined) {
172 183 this.set_cell_text(index, text);
173 184 }
174 185 return index;
175 186 };
176 187
177 // Asynchronously executes a cell by index.
178 // Returns the cell's index.
179 188 casper.execute_cell = function(index){
189 // Asynchronously executes a cell by index.
190 // Returns the cell's index.
180 191 var that = this;
181 192 this.then(function(){
182 193 that.evaluate(function (index) {
183 194 var cell = IPython.notebook.get_cell(index);
184 195 cell.execute();
185 196 }, index);
186 197 });
187 198 return index;
188 199 };
189 200
190 // Synchronously executes a cell by index.
191 // Optionally accepts a then_callback parameter. then_callback will get called
192 // when the cell has finished executing.
193 // Returns the cell's index.
194 201 casper.execute_cell_then = function(index, then_callback) {
202 // Synchronously executes a cell by index.
203 // Optionally accepts a then_callback parameter. then_callback will get called
204 // when the cell has finished executing.
205 // Returns the cell's index.
195 206 var return_val = this.execute_cell(index);
196 207
197 208 this.wait_for_idle();
198 209
199 210 var that = this;
200 211 this.then(function(){
201 212 if (then_callback!==undefined) {
202 213 then_callback.apply(that, [index]);
203 214 }
204 215 });
205 216
206 217 return return_val;
207 218 };
208 219
209 // Utility function that allows us to easily check if an element exists
210 // within a cell. Uses JQuery selector to look for the element.
211 220 casper.cell_element_exists = function(index, selector){
221 // Utility function that allows us to easily check if an element exists
222 // within a cell. Uses JQuery selector to look for the element.
212 223 return casper.evaluate(function (index, selector) {
213 224 var $cell = IPython.notebook.get_cell(index).element;
214 225 return $cell.find(selector).length > 0;
215 226 }, index, selector);
216 227 };
217 228
218 // Utility function that allows us to execute a jQuery function on an
219 // element within a cell.
220 229 casper.cell_element_function = function(index, selector, function_name, function_args){
230 // Utility function that allows us to execute a jQuery function on an
231 // element within a cell.
221 232 return casper.evaluate(function (index, selector, function_name, function_args) {
222 233 var $cell = IPython.notebook.get_cell(index).element;
223 234 var $el = $cell.find(selector);
224 235 return $el[function_name].apply($el, function_args);
225 236 }, index, selector, function_name, function_args);
226 237 };
227 238
228 // Wrap a notebook test to reduce boilerplate.
239 casper.validate_notebook_state = function(message, mode, cell_index) {
240 // Validate the entire dual mode state of the notebook. Make sure no more than
241 // one cell is selected, focused, in edit mode, etc...
242
243 // General tests.
244 this.test.assertEquals(this.get_keyboard_mode(), this.get_notebook_mode(),
245 message + '; keyboard and notebook modes match');
246 // Is the selected cell the only cell that is selected?
247 if (cell_index!==undefined) {
248 this.test.assert(this.is_only_cell_selected(cell_index),
249 message + '; cell ' + cell_index + ' is the only cell selected');
250 }
251
252 // Mode specific tests.
253 if (mode==='command') {
254 // Are the notebook and keyboard manager in command mode?
255 this.test.assertEquals(this.get_keyboard_mode(), 'command',
256 message + '; in command mode');
257 // Make sure there isn't a single cell in edit mode.
258 this.test.assert(this.is_only_cell_edit(null),
259 message + '; all cells in command mode');
260 this.test.assert(this.is_cell_editor_focused(null),
261 message + '; no cell editors are focused while in command mode');
262
263 } else if (mode==='edit') {
264 // Are the notebook and keyboard manager in edit mode?
265 this.test.assertEquals(this.get_keyboard_mode(), 'edit',
266 message + '; in edit mode');
267 if (cell_index!==undefined) {
268 // Is the specified cell the only cell in edit mode?
269 this.test.assert(this.is_only_cell_edit(cell_index),
270 message + '; cell ' + cell_index + ' is the only cell in edit mode');
271 // Is the specified cell the only cell with a focused code mirror?
272 this.test.assert(this.is_cell_editor_focused(cell_index),
273 message + '; cell ' + cell_index + '\'s editor is appropriately focused');
274 }
275
276 } else {
277 this.test.assert(false, message + '; ' + mode + ' is an unknown mode');
278 }
279 };
280
281 casper.select_cell = function(index) {
282 // Select a cell in the notebook.
283 this.evaluate(function (i) {
284 IPython.notebook.select(i);
285 }, {i: index});
286 };
287
288 casper.click_cell_editor = function(index) {
289 // Emulate a click on a cell's editor.
290
291 // Code Mirror does not play nicely with emulated brower events.
292 // Instead of trying to emulate a click, here we run code similar to
293 // the code used in Code Mirror that handles the mousedown event on a
294 // region of codemirror that the user can focus.
295 this.evaluate(function (i) {
296 var cm = IPython.notebook.get_cell(i).code_mirror;
297 if (cm.options.readOnly != "nocursor" && (document.activeElement != cm.display.input))
298 cm.display.input.focus();
299 }, {i: index});
300 };
301
302 casper.set_cell_editor_cursor = function(index, line_index, char_index) {
303 // Set the Code Mirror instance cursor's location.
304 this.evaluate(function (i, l, c) {
305 IPython.notebook.get_cell(i).code_mirror.setCursor(l, c);
306 }, {i: index, l: line_index, c: char_index});
307 };
308
309 casper.focus_notebook = function() {
310 // Focus the notebook div.
311 this.evaluate(function (){
312 $('#notebook').focus();
313 }, {});
314 };
315
316 casper.trigger_keydown = function() {
317 // Emulate a keydown in the notebook.
318 for (var i = 0; i < arguments.length; i++) {
319 this.evaluate(function (k) {
320 var element = $(document);
321 var event = IPython.keyboard.shortcut_to_event(k, 'keydown');
322 element.trigger(event);
323 }, {k: arguments[i]});
324 }
325 };
326
327 casper.get_keyboard_mode = function() {
328 // Get the mode of the keyboard manager.
329 return this.evaluate(function() {
330 return IPython.keyboard_manager.mode;
331 }, {});
332 };
333
334 casper.get_notebook_mode = function() {
335 // Get the mode of the notebook.
336 return this.evaluate(function() {
337 return IPython.notebook.mode;
338 }, {});
339 };
340
341 casper.get_cell = function(index) {
342 // Get a single cell.
343 //
344 // Note: Handles to DOM elements stored in the cell will be useless once in
345 // CasperJS context.
346 return this.evaluate(function(i) {
347 var cell = IPython.notebook.get_cell(i);
348 if (cell) {
349 return cell;
350 }
351 return null;
352 }, {i : index});
353 };
354
355 casper.is_cell_editor_focused = function(index) {
356 // Make sure a cell's editor is the only editor focused on the page.
357 return this.evaluate(function(i) {
358 var focused_textarea = $('#notebook .CodeMirror-focused textarea');
359 if (focused_textarea.length > 1) { throw 'More than one Code Mirror editor is focused at once!'; }
360 if (i === null) {
361 return focused_textarea.length === 0;
362 } else {
363 var cell = IPython.notebook.get_cell(i);
364 if (cell) {
365 return cell.code_mirror.getInputField() == focused_textarea[0];
366 }
367 }
368 return false;
369 }, {i : index});
370 };
371
372 casper.is_only_cell_selected = function(index) {
373 // Check if a cell is the only cell selected.
374 // Pass null as the index to check if no cells are selected.
375 return this.is_only_cell_on(index, 'selected', 'unselected');
376 };
377
378 casper.is_only_cell_edit = function(index) {
379 // Check if a cell is the only cell in edit mode.
380 // Pass null as the index to check if all of the cells are in command mode.
381 return this.is_only_cell_on(index, 'edit_mode', 'command_mode');
382 };
383
384 casper.is_only_cell_on = function(i, on_class, off_class) {
385 // Check if a cell is the only cell with the `on_class` DOM class applied to it.
386 // All of the other cells are checked for the `off_class` DOM class.
387 // Pass null as the index to check if all of the cells have the `off_class`.
388 var cells_length = this.get_cells_length();
389 for (var j = 0; j < cells_length; j++) {
390 if (j === i) {
391 if (this.cell_has_class(j, off_class) || !this.cell_has_class(j, on_class)) {
392 return false;
393 }
394 } else {
395 if (!this.cell_has_class(j, off_class) || this.cell_has_class(j, on_class)) {
396 return false;
397 }
398 }
399 }
400 return true;
401 };
402
403 casper.cell_has_class = function(index, classes) {
404 // Check if a cell has a class.
405 return this.evaluate(function(i, c) {
406 var cell = IPython.notebook.get_cell(i);
407 if (cell) {
408 return cell.element.hasClass(c);
409 }
410 return false;
411 }, {i : index, c: classes});
412 };
413
229 414 casper.notebook_test = function(test) {
415 // Wrap a notebook test to reduce boilerplate.
230 416 this.open_new_notebook();
231 417 this.then(test);
232 418
233 419 // Kill the kernel and delete the notebook.
234 420 this.shutdown_current_kernel();
235 421 // This is still broken but shouldn't be a problem for now.
236 422 // this.delete_current_notebook();
237 423
238 424 // This is required to clean up the page we just finished with. If we don't call this
239 425 // casperjs will leak file descriptors of all the open WebSockets in that page. We
240 426 // have to set this.page=null so that next time casper.start runs, it will create a
241 427 // new page from scratch.
242 428 this.then(function () {
243 429 this.page.close();
244 430 this.page = null;
245 431 });
246 432
247 433 // Run the browser automation.
248 434 this.run(function() {
249 435 this.test.done();
250 436 });
251 437 };
252 438
253 439 casper.wait_for_dashboard = function () {
254 440 // Wait for the dashboard list to load.
255 441 casper.waitForSelector('.list_item');
256 }
442 };
257 443
258 444 casper.open_dashboard = function () {
259 445 // Start casper by opening the dashboard page.
260 446 var baseUrl = this.get_notebook_server();
261 447 this.start(baseUrl);
262 448 this.wait_for_dashboard();
263 }
449 };
264 450
265 451 casper.dashboard_test = function (test) {
266 452 // Open the dashboard page and run a test.
267 453 this.open_dashboard();
268 454 this.then(test);
269 455
270 456 this.then(function () {
271 457 this.page.close();
272 458 this.page = null;
273 459 });
274 460
275 461 // Run the browser automation.
276 462 this.run(function() {
277 463 this.test.done();
278 464 });
279 }
465 };
280 466
281 casper.options.waitTimeout=10000
467 casper.options.waitTimeout=10000;
282 468 casper.on('waitFor.timeout', function onWaitForTimeout(timeout) {
283 469 this.echo("Timeout for " + casper.get_notebook_server());
284 470 this.echo("Is the notebook server running?");
285 471 });
286 472
287 // Pass `console.log` calls from page JS to casper.
288 casper.printLog = function () {
473 casper.print_log = function () {
474 // Pass `console.log` calls from page JS to casper.
289 475 this.on('remote.message', function(msg) {
290 476 this.echo('Remote message caught: ' + msg);
291 477 });
292 478 };
1 NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now