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

Side by Side Diff: lib/src/runner/browser/phantom_js.dart

Issue 1175163003: Factor out some common logic from the launchers. (Closed) Base URL: git@github.com:dart-lang/test@master
Patch Set: fix test Created 5 years, 6 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
« no previous file with comments | « lib/src/runner/browser/internet_explorer.dart ('k') | lib/src/runner/browser/safari.dart » ('j') | 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) 2015, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, 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 library test.runner.browser.phantom_js; 5 library test.runner.browser.phantom_js;
6 6
7 import 'dart:async'; 7 import 'dart:async';
8 import 'dart:convert';
9 import 'dart:io'; 8 import 'dart:io';
10 9
11 import 'package:path/path.dart' as p; 10 import 'package:path/path.dart' as p;
12 import 'package:stack_trace/stack_trace.dart';
13 11
14 import '../../util/exit_codes.dart' as exit_codes; 12 import '../../util/exit_codes.dart' as exit_codes;
15 import '../../util/io.dart'; 13 import '../../util/io.dart';
16 import '../../utils.dart';
17 import '../application_exception.dart'; 14 import '../application_exception.dart';
18 import 'browser.dart'; 15 import 'browser.dart';
19 16
20 /// The PhantomJS script that opens the host page. 17 /// The PhantomJS script that opens the host page.
21 final _script = """ 18 final _script = """
22 var system = require('system'); 19 var system = require('system');
23 var page = require('webpage').create(); 20 var page = require('webpage').create();
24 21
25 // PhantomJS versions older than 2.0.0 don't support the latest WebSocket spec. 22 // PhantomJS versions older than 2.0.0 don't support the latest WebSocket spec.
26 if (phantom.version.major < 2) phantom.exit(${exit_codes.protocol}); 23 if (phantom.version.major < 2) phantom.exit(${exit_codes.protocol});
27 24
28 // Pipe browser messages to the process's stdout. This isn't used by default, 25 // Pipe browser messages to the process's stdout. This isn't used by default,
29 // but it can be useful for debugging. 26 // but it can be useful for debugging.
30 page.onConsoleMessage = function(message) { 27 page.onConsoleMessage = function(message) {
31 console.log(message); 28 console.log(message);
32 } 29 }
33 30
34 page.open(system.args[1], function(status) { 31 page.open(system.args[1], function(status) {
35 if (status !== "success") phantom.exit(1); 32 if (status !== "success") phantom.exit(1);
36 }); 33 });
37 """; 34 """;
38 35
39 /// A class for running an instance of PhantomJS. 36 /// A class for running an instance of PhantomJS.
40 /// 37 ///
41 /// Any errors starting or running the process are reported through [onExit]. 38 /// Any errors starting or running the process are reported through [onExit].
42 class PhantomJS implements Browser { 39 class PhantomJS extends Browser {
43 /// The underlying process. 40 final name = "PhantomJS";
44 Process _process;
45 41
46 Future get onExit => _onExitCompleter.future; 42 PhantomJS(url, {String executable})
47 final _onExitCompleter = new Completer(); 43 : super(() => _startBrowser(url, executable));
48
49 /// A future that completes when the browser process has started.
50 ///
51 /// This is used to ensure that [close] works regardless of when it's called.
52 Future get _onProcessStarted => _onProcessStartedCompleter.future;
53 final _onProcessStartedCompleter = new Completer();
54 44
55 /// Starts a new instance of PhantomJS open to the given [url], which may be a 45 /// Starts a new instance of PhantomJS open to the given [url], which may be a
56 /// [Uri] or a [String]. 46 /// [Uri] or a [String].
57 /// 47 ///
58 /// If [executable] is passed, it's used as the PhantomJS executable. 48 /// If [executable] is passed, it's used as the PhantomJS executable.
59 /// Otherwise the default executable name for the current OS will be used. 49 /// Otherwise the default executable name for the current OS will be used.
60 PhantomJS(url, {String executable}) { 50 static Future<Process> _startBrowser(url, [String executable]) async {
61 if (executable == null) { 51 if (executable == null) {
62 executable = Platform.isWindows ? "phantomjs.exe" : "phantomjs"; 52 executable = Platform.isWindows ? "phantomjs.exe" : "phantomjs";
63 } 53 }
64 54
65 // Don't return a Future here because there's no need for the caller to wait 55 var dir = createTempDir();
66 // for the process to actually start. They should just wait for the HTTP 56 var script = p.join(dir, "script.js");
67 // request instead. 57 new File(script).writeAsStringSync(_script);
68 invoke(() async {
69 try {
70 var exitCode = await withTempDir((dir) async {
71 var script = p.join(dir, "script.js");
72 new File(script).writeAsStringSync(_script);
73 58
74 var process = await Process.start( 59 var process = await Process.start(
75 executable, [script, url.toString()]); 60 executable, [script, url.toString()]);
76 61
77 // PhantomJS synchronously emits standard output, which means that if we 62 // PhantomJS synchronously emits standard output, which means that if we
78 // don't drain its stdout stream it can deadlock. 63 // don't drain its stdout stream it can deadlock.
79 process.stdout.listen((_) {}); 64 process.stdout.listen((_) {});
80 65
81 _process = process; 66 process.exitCode.then((exitCode) {
82 _onProcessStartedCompleter.complete(); 67 new Directory(dir).deleteSync(recursive: true);
83 68
84 return await _process.exitCode; 69 if (exitCode == exit_codes.protocol) {
85 }); 70 throw new ApplicationException(
86 71 "Only PhantomJS version 2.0.0 or greater is supported");
87 if (exitCode == exit_codes.protocol) {
88 throw new ApplicationException(
89 "Only PhantomJS version 2.0.0 or greater is supported");
90 }
91
92 if (exitCode != 0) {
93 var error = await UTF8.decodeStream(_process.stderr);
94 throw new ApplicationException(
95 "PhantomJS failed with exit code $exitCode:\n$error");
96 }
97
98 _onExitCompleter.complete();
99 } catch (error, stackTrace) {
100 if (stackTrace == null) stackTrace = new Trace.current();
101 _onExitCompleter.completeError(
102 new ApplicationException(
103 "Failed to start PhantomJS: ${getErrorMessage(error)}."),
104 stackTrace);
105 } 72 }
106 }); 73 });
107 }
108 74
109 Future close() { 75 return process;
110 _onProcessStarted.then((_) => _process.kill());
111
112 // Swallow exceptions. The user should explicitly use [onExit] for these.
113 return onExit.catchError((_) {});
114 } 76 }
115 } 77 }
OLDNEW
« no previous file with comments | « lib/src/runner/browser/internet_explorer.dart ('k') | lib/src/runner/browser/safari.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698