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