@@ -24,7 +24,9 @@ import 'package:path/path.dart' as path;
24
24
import 'package:dart_dev/src/platform_util/api.dart' as platform_util;
25
25
import 'package:dart_dev/src/tasks/coverage/config.dart' ;
26
26
import 'package:dart_dev/src/tasks/coverage/exceptions.dart' ;
27
+ import 'package:dart_dev/src/tasks/serve/api.dart' ;
27
28
import 'package:dart_dev/src/tasks/task.dart' ;
29
+ import 'package:dart_dev/src/tasks/test/config.dart' ;
28
30
29
31
const String _dartFilePattern = '.dart' ;
30
32
const String _testFilePattern = '_test.dart' ;
@@ -85,14 +87,18 @@ class CoverageTask extends Task {
85
87
/// [tests] will be searched (recursively) for all files ending in
86
88
/// "_test.dart" and all matching files will be run as tests.
87
89
///
90
+ /// If [pubServe] is true, a Pub server will be automatically started and
91
+ /// used to run any browser tests.
92
+ ///
88
93
/// If [html] is true, `genhtml` will be used to generate an HTML report of
89
94
/// the collected coverage and the report will be opened.
90
95
static CoverageTask start (List <String > tests,
91
96
{bool html: defaultHtml,
97
+ bool pubServe: defaultPubServe,
92
98
String output: defaultOutput,
93
99
List <String > reportOn: defaultReportOn}) {
94
- CoverageTask coverage =
95
- new CoverageTask ._(tests, reportOn , html: html, output: output);
100
+ CoverageTask coverage = new CoverageTask ._(tests, reportOn,
101
+ pubServe : pubServe , html: html, output: output);
96
102
coverage._run ();
97
103
return coverage;
98
104
}
@@ -120,6 +126,10 @@ class CoverageTask extends Task {
120
126
/// Whether or not to generate the HTML report.
121
127
bool _html = defaultHtml;
122
128
129
+ /// Whether to automatically start and use a Pub server when running
130
+ /// browser tests.
131
+ final bool pubServe;
132
+
123
133
/// File created to run the test in a browser. Need to store it so it can be
124
134
/// cleaned up after the test finishes.
125
135
File _lastHtmlFile;
@@ -135,7 +145,9 @@ class CoverageTask extends Task {
135
145
List <String > _reportOn;
136
146
137
147
CoverageTask ._(List <String > tests, List <String > reportOn,
138
- {bool html: defaultHtml, String output: defaultOutput})
148
+ {bool html: defaultHtml,
149
+ bool this .pubServe: defaultPubServe,
150
+ String output: defaultOutput})
139
151
: _html = html,
140
152
_outputDirectory = new Directory (output),
141
153
_reportOn = reportOn {
@@ -407,45 +419,98 @@ class CoverageTask extends Task {
407
419
String _testsPassedPattern = 'All tests passed!' ;
408
420
409
421
if (isBrowserTest) {
410
- // Run the test in content-shell.
411
- String executable = 'content_shell' ;
412
- List args = [htmlFile.path];
413
- _coverageOutput.add ('' );
414
- _coverageOutput.add ('Running test suite ${file .path }' );
415
- _coverageOutput.add ('$executable ${args .join (' ' )}\n ' );
416
- TaskProcess process =
417
- _lastTestProcess = new TaskProcess ('content_shell' , args);
422
+ PubServeTask pubServeTask;
418
423
419
- // Content-shell dumps render tree to stderr, which is where the test
420
- // results will be. The observatory port should be output to stderr as
421
- // well, but it is sometimes malformed. In those cases, the correct
422
- // observatory port is output to stdout. So we listen to both.
423
- int observatoryPort;
424
- process.stdout.listen ((line) {
425
- _coverageOutput.add (' $line ' );
426
- if (line.contains (_observatoryPortPattern)) {
427
- Match m = _observatoryPortPattern.firstMatch (line);
428
- observatoryPort = int .parse (m.group (2 ));
429
- }
430
- });
431
- await for (String line in process.stderr) {
432
- _coverageOutput.add (' $line ' );
433
- if (line.contains (_observatoryFailPattern)) {
434
- throw new CoverageTestSuiteException (file.path);
435
- }
436
- if (line.contains (_observatoryPortPattern)) {
437
- Match m = _observatoryPortPattern.firstMatch (line);
438
- observatoryPort = int .parse (m.group (2 ));
439
- }
440
- if (line.contains (_testsFailedPattern)) {
441
- throw new CoverageTestSuiteException (file.path);
424
+ try {
425
+ String testPath;
426
+ if (pubServe) {
427
+ _coverageOutput.add ('Starting Pub server...' );
428
+
429
+ // Start `pub serve` on the `test` directory.
430
+ pubServeTask = startPubServe (additionalArgs: ['test' ]);
431
+
432
+ _coverageOutput.add ('::: ${pubServeTask .command }' );
433
+ String indentLine (String line) => ' $line ' ;
434
+
435
+ var startupLogFinished = new Completer ();
436
+ pubServeTask.stdOut
437
+ .transform (until (startupLogFinished.future))
438
+ .map (indentLine)
439
+ .listen (_coverageOutput.add);
440
+ pubServeTask.stdErr
441
+ .transform (until (startupLogFinished.future))
442
+ .map (indentLine)
443
+ .listen (_coverageErrorOutput.add);
444
+
445
+ PubServeInfo serveInfo = await pubServeTask.serveInfos.first;
446
+ if (! path.isWithin (serveInfo.directory, htmlFile.path)) {
447
+ throw '`pub serve` directory does not contain test file: ${htmlFile .path }' ;
448
+ }
449
+
450
+ var relativeHtmlPath =
451
+ path.relative (htmlFile.path, from: serveInfo.directory);
452
+ testPath = 'http://localhost:${serveInfo .port }/$relativeHtmlPath ' ;
453
+
454
+ startupLogFinished.complete ();
455
+ pubServeTask.stdOut.map (indentLine).join ('\n ' ).then ((stdOut) {
456
+ if (stdOut.isNotEmpty) {
457
+ _coverageOutput
458
+ .add ('`${pubServeTask .command }` (buffered stdout)' );
459
+ _coverageOutput.add (stdOut);
460
+ }
461
+ });
462
+ pubServeTask.stdErr.map (indentLine).join ('\n ' ).then ((stdErr) {
463
+ if (stdErr.isNotEmpty) {
464
+ _coverageOutput
465
+ .add ('`${pubServeTask .command }` (buffered stdout)' );
466
+ _coverageOutput.add (stdErr);
467
+ }
468
+ });
469
+ } else {
470
+ testPath = htmlFile.path;
442
471
}
443
- if (line.contains (_testsPassedPattern)) {
444
- break ;
472
+
473
+ // Run the test in content-shell.
474
+ String executable = 'content_shell' ;
475
+ List args = [testPath];
476
+ _coverageOutput.add ('' );
477
+ _coverageOutput.add ('Running test suite ${file .path }' );
478
+ _coverageOutput.add ('$executable ${args .join (' ' )}\n ' );
479
+ TaskProcess process =
480
+ _lastTestProcess = new TaskProcess ('content_shell' , args);
481
+
482
+ // Content-shell dumps render tree to stderr, which is where the test
483
+ // results will be. The observatory port should be output to stderr as
484
+ // well, but it is sometimes malformed. In those cases, the correct
485
+ // observatory port is output to stdout. So we listen to both.
486
+ int observatoryPort;
487
+ process.stdout.listen ((line) {
488
+ _coverageOutput.add (' $line ' );
489
+ if (line.contains (_observatoryPortPattern)) {
490
+ Match m = _observatoryPortPattern.firstMatch (line);
491
+ observatoryPort = int .parse (m.group (2 ));
492
+ }
493
+ });
494
+ await for (String line in process.stderr) {
495
+ _coverageOutput.add (' $line ' );
496
+ if (line.contains (_observatoryFailPattern)) {
497
+ throw new CoverageTestSuiteException (file.path);
498
+ }
499
+ if (line.contains (_observatoryPortPattern)) {
500
+ Match m = _observatoryPortPattern.firstMatch (line);
501
+ observatoryPort = int .parse (m.group (2 ));
502
+ }
503
+ if (line.contains (_testsFailedPattern)) {
504
+ throw new CoverageTestSuiteException (file.path);
505
+ }
506
+ if (line.contains (_testsPassedPattern)) {
507
+ break ;
508
+ }
445
509
}
510
+ return observatoryPort;
511
+ } finally {
512
+ pubServeTask? .stop ();
446
513
}
447
-
448
- return observatoryPort;
449
514
} else {
450
515
// Find an open port to observe the Dart VM on.
451
516
int port = await getOpenPort ();
0 commit comments