Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(53)

Side by Side Diff: pkg/unittest/lib/interactive_html_config.dart

Issue 12598008: pkg/unittest: fixed deprecations in alt configs (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: spelling and copyright year Created 7 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « pkg/unittest/lib/html_layout_config.dart ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 /** 5 /**
6 * This configuration can be used to rerun selected tests, as well 6 * This configuration can be used to rerun selected tests, as well
7 * as see diagnostic output from tests. It runs each test in its own 7 * as see diagnostic output from tests. It runs each test in its own
8 * IFrame, so the configuration consists of two parts - a 'parent' 8 * IFrame, so the configuration consists of two parts - a 'parent'
9 * config that manages all the tests, and a 'child' config for the 9 * config that manages all the tests, and a 'child' config for the
10 * IFrame that runs the individual tests. 10 * IFrame that runs the individual tests.
11 */ 11 */
12 library unittest_interactive_html_config; 12 library unittest_interactive_html_config;
13 13
14 // TODO(gram) - add options for: remove IFrame on done/keep 14 // TODO(gram) - add options for: remove IFrame on done/keep
15 // IFrame for failed tests/keep IFrame for all tests. 15 // IFrame for failed tests/keep IFrame for all tests.
16 16
17 import 'dart:html'; 17 import 'dart:html';
18 import 'dart:async';
18 import 'dart:math'; 19 import 'dart:math';
19 import 'unittest.dart'; 20 import 'unittest.dart';
20 21
21 /** The messages exchanged between parent and child. */ 22 /** The messages exchanged between parent and child. */
22 23
23 class _Message { 24 class _Message {
24 static const START = 'start'; 25 static const START = 'start';
25 static const LOG = 'log'; 26 static const LOG = 'log';
26 static const STACK = 'stack'; 27 static const STACK = 'stack';
27 static const PASS = 'pass'; 28 static const PASS = 'pass';
(...skipping 18 matching lines...) Expand all
46 elapsed = int.parse(msg.substring(idx, idx2)); 47 elapsed = int.parse(msg.substring(idx, idx2));
47 ++idx2; 48 ++idx2;
48 body = msg.substring(idx2); 49 body = msg.substring(idx2);
49 } 50 }
50 51
51 String toString() => text(messageType, elapsed, body); 52 String toString() => text(messageType, elapsed, body);
52 } 53 }
53 54
54 55
55 class HtmlConfiguration extends Configuration { 56 class HtmlConfiguration extends Configuration {
56 // TODO(rnystrom): Get rid of this if we get canonical closures for methods. 57 StreamSubscription _errorSubscription;
57 EventListener _onErrorClosure;
58 58
59 void _installErrorHandler() { 59 void _installErrorHandler() {
60 if (_onErrorClosure == null) { 60 if (_errorSubscription == null) {
61 _onErrorClosure = 61 _errorSubscription = window.onError.listen((e) {
62 (e) => handleExternalError(e, '(DOM callback has errors)'); 62 handleExternalError(e, '(DOM callback has errors)');
63 // Listen for uncaught errors. 63 });
64 window.on.error.add(_onErrorClosure);
65 } 64 }
66 } 65 }
67 66
68 void _uninstallErrorHandler() { 67 void _uninstallErrorHandler() {
69 if (_onErrorClosure != null) { 68 if (_errorSubscription != null) {
70 window.on.error.remove(_onErrorClosure); 69 _errorSubscription.cancel();
71 _onErrorClosure = null; 70 _errorSubscription = null;
72 } 71 }
73 } 72 }
74 } 73 }
75 74
76 /** 75 /**
77 * The child configuration that is used to run individual tests in 76 * The child configuration that is used to run individual tests in
78 * an IFrame and post the results back to the parent. In principle 77 * an IFrame and post the results back to the parent. In principle
79 * this can run more than one test in the IFrame but currently only 78 * this can run more than one test in the IFrame but currently only
80 * one is used. 79 * one is used.
81 */ 80 */
82 class ChildInteractiveHtmlConfiguration extends HtmlConfiguration { 81 class ChildInteractiveHtmlConfiguration extends HtmlConfiguration {
83 82
84 /** The window to which results must be posted. */ 83 /** The window to which results must be posted. */
85 Window parentWindow; 84 WindowBase parentWindow;
86 85
87 /** The time at which tests start. */ 86 /** The time at which tests start. */
88 Map<int,DateTime> _testStarts; 87 Map<int,DateTime> _testStarts;
89 88
90 ChildInteractiveHtmlConfiguration() : 89 ChildInteractiveHtmlConfiguration() :
91 _testStarts = new Map<int,DateTime>(); 90 _testStarts = new Map<int,DateTime>();
92 91
93 /** Don't start running tests automatically. */ 92 /** Don't start running tests automatically. */
94 get autoStart => false; 93 get autoStart => false;
95 94
96 void onInit() { 95 void onInit() {
97 _installErrorHandler(); 96 _installErrorHandler();
98 97
99 /** 98 /**
100 * The parent posts a 'start' message to kick things off, 99 * The parent posts a 'start' message to kick things off,
101 * which is handled by this handler. It saves the parent 100 * which is handled by this handler. It saves the parent
102 * window, gets the test ID from the query parameter in the 101 * window, gets the test ID from the query parameter in the
103 * IFrame URL, sets that as a solo test and starts test execution. 102 * IFrame URL, sets that as a solo test and starts test execution.
104 */ 103 */
105 window.on.message.add((MessageEvent e) { 104 window.onMessage.listen((MessageEvent e) {
106 // Get the result, do any logging, then do a pass/fail. 105 // Get the result, do any logging, then do a pass/fail.
107 var m = new _Message.fromString(e.data); 106 var m = new _Message.fromString(e.data);
108 if (m.messageType == _Message.START) { 107 if (m.messageType == _Message.START) {
109 parentWindow = e.source; 108 parentWindow = e.source;
110 String search = window.location.search; 109 String search = window.location.search;
111 int pos = search.indexOf('t='); 110 int pos = search.indexOf('t=');
112 String ids = search.substring(pos+2); 111 String ids = search.substring(pos+2);
113 int id = int.parse(ids); 112 int id = int.parse(ids);
114 setSoloTest(id); 113 setSoloTest(id);
115 runTests(); 114 runTests();
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
181 String _stack; 180 String _stack;
182 181
183 int _testTime; 182 int _testTime;
184 /** 183 /**
185 * Whether or not we have already wrapped the TestCase test functions 184 * Whether or not we have already wrapped the TestCase test functions
186 * in new closures that instead create an IFrame and get it to run the 185 * in new closures that instead create an IFrame and get it to run the
187 * test. 186 * test.
188 */ 187 */
189 bool _doneWrap = false; 188 bool _doneWrap = false;
190 189
191 /** 190 StreamSubscription _messageSubscription;
192 * We use this to make a single closure from _handleMessage so we
193 * can remove the handler later.
194 */
195 Function _messageHandler;
196 191
197 ParentInteractiveHtmlConfiguration() : 192 ParentInteractiveHtmlConfiguration() :
198 _testStarts = new Map<int,DateTime>(); 193 _testStarts = new Map<int,DateTime>();
199 194
200 // We need to block until the test is done, so we make a 195 // We need to block until the test is done, so we make a
201 // dummy async callback that we will use to flag completion. 196 // dummy async callback that we will use to flag completion.
202 Function completeTest = null; 197 Function completeTest = null;
203 198
204 wrapTest(TestCase testCase) { 199 wrapTest(TestCase testCase) {
205 String baseUrl = window.location.toString(); 200 String baseUrl = window.location.toString();
206 String url = '${baseUrl}?t=${testCase.id}'; 201 String url = '${baseUrl}?t=${testCase.id}';
207 return () { 202 return () {
208 // Rebuild the child IFrame. 203 // Rebuild the child IFrame.
209 Element childDiv = document.query('#child'); 204 Element childDiv = document.query('#child');
210 childDiv.nodes.clear(); 205 childDiv.nodes.clear();
211 IFrameElement child = new Element.html(""" 206 IFrameElement child = new Element.html("""
212 <iframe id='childFrame${testCase.id}' src='$url' style='display:none'> 207 <iframe id='childFrame${testCase.id}' src='$url' style='display:none'>
213 </iframe>"""); 208 </iframe>""");
214 childDiv.nodes.add(child); 209 childDiv.nodes.add(child);
215 completeTest = expectAsync0((){ }); 210 completeTest = expectAsync0((){ });
216 // Kick off the test when the IFrame is loaded. 211 // Kick off the test when the IFrame is loaded.
217 child.on.load.add((e) { 212 child.onLoad.listen((e) {
218 child.contentWindow.postMessage(_Message.text(_Message.START), '*'); 213 child.contentWindow.postMessage(_Message.text(_Message.START), '*');
219 }); 214 });
220 }; 215 };
221 } 216 }
222 217
223 void _handleMessage(MessageEvent e) { 218 void _handleMessage(MessageEvent e) {
224 // Get the result, do any logging, then do a pass/fail. 219 // Get the result, do any logging, then do a pass/fail.
225 var msg = new _Message.fromString(e.data); 220 var msg = new _Message.fromString(e.data);
226 if (msg.messageType == _Message.LOG) { 221 if (msg.messageType == _Message.LOG) {
227 logMessage(e.data); 222 logMessage(e.data);
228 } else if (msg.messageType == _Message.STACK) { 223 } else if (msg.messageType == _Message.STACK) {
229 _stack = msg.body; 224 _stack = msg.body;
230 } else { 225 } else {
231 _testTime = msg.elapsed; 226 _testTime = msg.elapsed;
232 logMessage(_Message.text(_Message.LOG, _testTime, 'Complete')); 227 logMessage(_Message.text(_Message.LOG, _testTime, 'Complete'));
233 if (msg.messageType == _Message.PASS) { 228 if (msg.messageType == _Message.PASS) {
234 currentTestCase.pass(); 229 currentTestCase.pass();
235 } else if (msg.messageType == _Message.FAIL) { 230 } else if (msg.messageType == _Message.FAIL) {
236 currentTestCase.fail(msg.body, _stack); 231 currentTestCase.fail(msg.body, _stack);
237 } else if (msg.messageType == _Message.ERROR) { 232 } else if (msg.messageType == _Message.ERROR) {
238 currentTestCase.error(msg.body, _stack); 233 currentTestCase.error(msg.body, _stack);
239 } 234 }
240 completeTest(); 235 completeTest();
241 } 236 }
242 } 237 }
243 238
244 void onInit() { 239 void onInit() {
245 _installErrorHandler(); 240 _installErrorHandler();
246 _messageHandler = _handleMessage; // We need to make just one closure.
247 document.query('#group-divs').innerHtml = ""; 241 document.query('#group-divs').innerHtml = "";
248 } 242 }
249 243
250 void onStart() { 244 void onStart() {
251 _installErrorHandler(); 245 _installErrorHandler();
252 if (!_doneWrap) { 246 if (!_doneWrap) {
253 _doneWrap = true; 247 _doneWrap = true;
254 for (int i = 0; i < testCases.length; i++) { 248 for (int i = 0; i < testCases.length; i++) {
255 testCases[i].test = wrapTest(testCases[i]); 249 testCases[i].test = wrapTest(testCases[i]);
256 testCases[i].setUp = null; 250 testCases[i].setUp = null;
257 testCases[i].tearDown = null; 251 testCases[i].tearDown = null;
258 } 252 }
259 } 253 }
260 window.on.message.add(_messageHandler); 254 assert(_messageSubscription == null);
255 _messageSubscription = window.onMessage.listen(_handleMessage);
261 } 256 }
262 257
263 static final _notAlphaNumeric = new RegExp('[^a-z0-9A-Z]'); 258 static final _notAlphaNumeric = new RegExp('[^a-z0-9A-Z]');
264 259
265 String _stringToDomId(String s) { 260 String _stringToDomId(String s) {
266 if (s.length == 0) { 261 if (s.length == 0) {
267 return '-None-'; 262 return '-None-';
268 } 263 }
269 return s.trim().replaceAll(_notAlphaNumeric, '-'); 264 return s.trim().replaceAll(_notAlphaNumeric, '-');
270 } 265 }
(...skipping 19 matching lines...) Expand all
290 groupDiv = new Element.html(""" 285 groupDiv = new Element.html("""
291 <div class='test-describe' id='$groupId'> 286 <div class='test-describe' id='$groupId'>
292 <h2> 287 <h2>
293 <input type='checkbox' checked='true' class='groupselect'> 288 <input type='checkbox' checked='true' class='groupselect'>
294 Group: ${testCase.currentGroup} 289 Group: ${testCase.currentGroup}
295 </h2> 290 </h2>
296 <ul class='tests'> 291 <ul class='tests'>
297 </ul> 292 </ul>
298 </div>"""); 293 </div>""");
299 document.query('#group-divs').nodes.add(groupDiv); 294 document.query('#group-divs').nodes.add(groupDiv);
300 groupDiv.query('.groupselect').on.click.add((e) { 295 groupDiv.query('.groupselect').onClick.listen((e) {
301 var parent = document.query('#$groupId'); 296 var parent = document.query('#$groupId');
302 InputElement cb = parent.query('.groupselect'); 297 InputElement cb = parent.query('.groupselect');
303 var state = cb.checked; 298 var state = cb.checked;
304 var tests = parent.query('.tests'); 299 var tests = parent.query('.tests');
305 for (Element t in tests.elements) { 300 for (Element t in tests.children) {
306 cb = t.query('.testselect') as InputElement; 301 cb = t.query('.testselect') as InputElement;
307 cb.checked = state; 302 cb.checked = state;
308 var testId = int.parse(t.id.substring(_testIdPrefix.length)); 303 var testId = int.parse(t.id.substring(_testIdPrefix.length));
309 if (state) { 304 if (state) {
310 enableTest(testId); 305 enableTest(testId);
311 } else { 306 } else {
312 disableTest(testId); 307 disableTest(testId);
313 } 308 }
314 } 309 }
315 }); 310 });
(...skipping 12 matching lines...) Expand all
328 <span class='timer-result test-timer-result'></span> 323 <span class='timer-result test-timer-result'></span>
329 <span class='test-name closed'>${testCase.description}</span> 324 <span class='test-name closed'>${testCase.description}</span>
330 </span> 325 </span>
331 </p> 326 </p>
332 </div> 327 </div>
333 <div class='scrollpane'> 328 <div class='scrollpane'>
334 <ol class='test-actions' id='$_actionIdPrefix$id'></ol> 329 <ol class='test-actions' id='$_actionIdPrefix$id'></ol>
335 </div> 330 </div>
336 </li>"""); 331 </li>""");
337 list.nodes.add(testItem); 332 list.nodes.add(testItem);
338 testItem.query('#$_selectedIdPrefix$id').on.change.add((e) { 333 testItem.query('#$_selectedIdPrefix$id').onChange.listen((e) {
339 InputElement cb = testItem.query('#$_selectedIdPrefix$id'); 334 InputElement cb = testItem.query('#$_selectedIdPrefix$id');
340 testCase.enabled = cb.checked; 335 testCase.enabled = cb.checked;
341 }); 336 });
342 testItem.query('.test-label').on.click.add((e) { 337 testItem.query('.test-label').onClick.listen((e) {
343 var _testItem = document.query('#$_testIdPrefix$id'); 338 var _testItem = document.query('#$_testIdPrefix$id');
344 var _actions = _testItem.query('#$_actionIdPrefix$id'); 339 var _actions = _testItem.query('#$_actionIdPrefix$id');
345 var _label = _testItem.query('.test-name'); 340 var _label = _testItem.query('.test-name');
346 if (_actions.style.display == 'none') { 341 if (_actions.style.display == 'none') {
347 _actions.style.display = 'table'; 342 _actions.style.display = 'table';
348 _label.classes.remove('closed'); 343 _label.classes.remove('closed');
349 _label.classes.add('open'); 344 _label.classes.add('open');
350 } else { 345 } else {
351 _actions.style.display = 'none'; 346 _actions.style.display = 'none';
352 _label.classes.remove('open'); 347 _label.classes.remove('open');
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
407 e.classes.add(result); 402 e.classes.add(result);
408 } 403 }
409 actions.style.display = 'none'; 404 actions.style.display = 'none';
410 } 405 }
411 406
412 void onSummary(int passed, int failed, int errors, List<TestCase> results, 407 void onSummary(int passed, int failed, int errors, List<TestCase> results,
413 String uncaughtError) { 408 String uncaughtError) {
414 } 409 }
415 410
416 void onDone(bool success) { 411 void onDone(bool success) {
417 window.on.message.remove(_messageHandler); 412 assert(_messageSubscription != null);
413 _messageSubscription.cancel();
414 _messageSubscription = null;
418 _uninstallErrorHandler(); 415 _uninstallErrorHandler();
419 document.query('#busy').style.display = 'none'; 416 document.query('#busy').style.display = 'none';
420 InputElement startButton = document.query('#start'); 417 InputElement startButton = document.query('#start');
421 startButton.disabled = false; 418 startButton.disabled = false;
422 } 419 }
423 } 420 }
424 421
425 /** 422 /**
426 * Add the divs to the DOM if they are not present. We have a 'controls' 423 * Add the divs to the DOM if they are not present. We have a 'controls'
427 * div for control, 'specs' div with test results, a 'busy' div for the 424 * div for control, 'specs' div with test results, a 'busy' div for the
428 * animated GIF used to indicate tests are running, and a 'child' div to 425 * animated GIF used to indicate tests are running, and a 'child' div to
429 * hold the iframe for the test. 426 * hold the iframe for the test.
430 */ 427 */
431 void _prepareDom() { 428 void _prepareDom() {
432 if (document.query('#control') == null) { 429 if (document.query('#control') == null) {
433 // Use this as an opportunity for adding the CSS too. 430 // Use this as an opportunity for adding the CSS too.
434 // I wanted to avoid having to include a css element explicitly 431 // I wanted to avoid having to include a css element explicitly
435 // in the main html file. I considered moving all the styles 432 // in the main html file. I considered moving all the styles
436 // inline as attributes but that started getting very messy, 433 // inline as attributes but that started getting very messy,
437 // so we do it this way. 434 // so we do it this way.
438 document.body.nodes.add(new Element.html("<style>$_CSS</style>")); 435 document.body.nodes.add(new Element.html("<style>$_CSS</style>"));
439 document.body.nodes.add(new Element.html( 436 document.body.nodes.add(new Element.html(
440 "<div id='control'>" 437 "<div id='control'>"
441 "<input id='start' disabled='true' type='button' value='Run'>" 438 "<input id='start' disabled='true' type='button' value='Run'>"
442 "</div>")); 439 "</div>"));
443 document.query('#start').on.click.add((e) { 440 document.query('#start').onClick.listen((e) {
444 InputElement startButton = document.query('#start'); 441 InputElement startButton = document.query('#start');
445 startButton.disabled = true; 442 startButton.disabled = true;
446 rerunTests(); 443 rerunTests();
447 }); 444 });
448 } 445 }
449 if (document.query('#otherlogs') == null) { 446 if (document.query('#otherlogs') == null) {
450 document.body.nodes.add(new Element.html( 447 document.body.nodes.add(new Element.html(
451 "<div id='otherlogs'></div>")); 448 "<div id='otherlogs'></div>"));
452 } 449 }
453 if (document.query('#specs') == null) { 450 if (document.query('#specs') == null) {
454 document.body.nodes.add(new Element.html( 451 document.body.nodes.add(new Element.html(
455 "<div id='specs'><div id='group-divs'></div></div>")); 452 "<div id='specs'><div id='group-divs'></div></div>"));
456 } 453 }
457 if (document.query('#busy') == null) { 454 if (document.query('#busy') == null) {
458 document.body.nodes.add(new Element.html( 455 document.body.nodes.add(new Element.html(
459 "<div id='busy' style='display:none'><img src='googleballs.gif'>" 456 "<div id='busy' style='display:none'><img src='googleballs.gif'>"
460 "</img></div>")); 457 "</img></div>"));
461 } 458 }
462 if (document.query('#child') == null) { 459 if (document.query('#child') == null) {
463 document.body.nodes.add(new Element.html("<div id='child'></div>")); 460 document.body.nodes.add(new Element.html("<div id='child'></div>"));
464 } 461 }
465 } 462 }
466 463
467 /** 464 /**
468 * Allocate a Configuration. We allocate either a parent or 465 * Allocate a Configuration. We allocate either a parent or
469 * child, depedning on whether the URL has a search part. 466 * child, depending on whether the URL has a search part.
470 */ 467 */
471 void useInteractiveHtmlConfiguration() { 468 void useInteractiveHtmlConfiguration() {
472 if (config != null) return; 469 if (config != null) return;
473 if (window.location.search == '') { // This is the parent. 470 if (window.location.search == '') { // This is the parent.
474 _prepareDom(); 471 _prepareDom();
475 configure(new ParentInteractiveHtmlConfiguration()); 472 configure(new ParentInteractiveHtmlConfiguration());
476 } else { 473 } else {
477 configure(new ChildInteractiveHtmlConfiguration()); 474 configure(new ChildInteractiveHtmlConfiguration());
478 } 475 }
479 } 476 }
(...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after
670 display: block; 667 display: block;
671 list-style-type: disc; 668 list-style-type: disc;
672 -webkit-margin-before: 1em; 669 -webkit-margin-before: 1em;
673 -webkit-margin-after: 1em; 670 -webkit-margin-after: 1em;
674 -webkit-margin-start: 0px; 671 -webkit-margin-start: 0px;
675 -webkit-margin-end: 0px; 672 -webkit-margin-end: 0px;
676 -webkit-padding-start: 40px; 673 -webkit-padding-start: 40px;
677 } 674 }
678 675
679 """; 676 """;
OLDNEW
« no previous file with comments | « pkg/unittest/lib/html_layout_config.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698