Add --name and --plain-name to 'flutter test' (#11020)
This adds a way to run only a subset of the tests. (The new flags do the same thing as 'pub run test'.)
This commit is contained in:
parent
0a915d6faf
commit
6841ab22be
14
dev/automated_tests/flutter_test/filtering_test.dart
Normal file
14
dev/automated_tests/flutter_test/filtering_test.dart
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
// Copyright 2017 The Chromium Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
test('included', () {
|
||||||
|
expect(2 + 2, 4);
|
||||||
|
});
|
||||||
|
test('excluded', () {
|
||||||
|
throw "this test should have been filtered out";
|
||||||
|
});
|
||||||
|
}
|
@ -22,6 +22,18 @@ import '../test/watcher.dart';
|
|||||||
class TestCommand extends FlutterCommand {
|
class TestCommand extends FlutterCommand {
|
||||||
TestCommand({ bool verboseHelp: false }) {
|
TestCommand({ bool verboseHelp: false }) {
|
||||||
usesPubOption();
|
usesPubOption();
|
||||||
|
argParser.addOption('name',
|
||||||
|
help: 'A regular expression matching substrings of the names of tests to run.',
|
||||||
|
valueHelp: 'regexp',
|
||||||
|
allowMultiple: true,
|
||||||
|
splitCommas: false,
|
||||||
|
);
|
||||||
|
argParser.addOption('plain-name',
|
||||||
|
help: 'A plain-text substring of the names of tests to run.',
|
||||||
|
valueHelp: 'substring',
|
||||||
|
allowMultiple: true,
|
||||||
|
splitCommas: false,
|
||||||
|
);
|
||||||
argParser.addFlag('start-paused',
|
argParser.addFlag('start-paused',
|
||||||
defaultsTo: false,
|
defaultsTo: false,
|
||||||
negatable: false,
|
negatable: false,
|
||||||
@ -141,6 +153,8 @@ class TestCommand extends FlutterCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
commandValidator();
|
commandValidator();
|
||||||
|
final List<String> names = argResults['name'];
|
||||||
|
final List<String> plainNames = argResults['plain-name'];
|
||||||
|
|
||||||
Iterable<String> files = argResults.rest.map<String>((String testPath) => fs.path.absolute(testPath)).toList();
|
Iterable<String> files = argResults.rest.map<String>((String testPath) => fs.path.absolute(testPath)).toList();
|
||||||
|
|
||||||
@ -189,6 +203,8 @@ class TestCommand extends FlutterCommand {
|
|||||||
|
|
||||||
final int result = await runTests(files,
|
final int result = await runTests(files,
|
||||||
workDir: workDir,
|
workDir: workDir,
|
||||||
|
names: names,
|
||||||
|
plainNames: plainNames,
|
||||||
watcher: watcher,
|
watcher: watcher,
|
||||||
enableObservatory: collector != null || startPaused,
|
enableObservatory: collector != null || startPaused,
|
||||||
startPaused: startPaused,
|
startPaused: startPaused,
|
||||||
|
@ -21,6 +21,8 @@ import 'watcher.dart';
|
|||||||
Future<int> runTests(
|
Future<int> runTests(
|
||||||
List<String> testFiles, {
|
List<String> testFiles, {
|
||||||
Directory workDir,
|
Directory workDir,
|
||||||
|
List<String> names: const <String>[],
|
||||||
|
List<String> plainNames: const <String>[],
|
||||||
bool enableObservatory: false,
|
bool enableObservatory: false,
|
||||||
bool startPaused: false,
|
bool startPaused: false,
|
||||||
bool ipv6: false,
|
bool ipv6: false,
|
||||||
@ -41,6 +43,14 @@ Future<int> runTests(
|
|||||||
testArgs.addAll(<String>['-r', 'json']);
|
testArgs.addAll(<String>['-r', 'json']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (String name in names) {
|
||||||
|
testArgs..add("--name")..add(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (String plainName in plainNames) {
|
||||||
|
testArgs..add("--plain-name")..add(plainName);
|
||||||
|
}
|
||||||
|
|
||||||
testArgs.add('--');
|
testArgs.add('--');
|
||||||
testArgs.addAll(testFiles);
|
testArgs.addAll(testFiles);
|
||||||
|
|
||||||
|
@ -18,63 +18,63 @@ import '../src/context.dart';
|
|||||||
Future<Null> _testExclusionLock;
|
Future<Null> _testExclusionLock;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
group('test', () {
|
group('flutter test should', () {
|
||||||
|
|
||||||
final String automatedTestsDirectory = fs.path.join('..', '..', 'dev', 'automated_tests');
|
final String automatedTestsDirectory = fs.path.join('..', '..', 'dev', 'automated_tests');
|
||||||
final String flutterTestDirectory = fs.path.join(automatedTestsDirectory, 'flutter_test');
|
final String flutterTestDirectory = fs.path.join(automatedTestsDirectory, 'flutter_test');
|
||||||
|
|
||||||
testUsingContext('Exception handling in test harness', () async {
|
testUsingContext('report nice errors for exceptions thrown within testWidgets()', () async {
|
||||||
Cache.flutterRoot = '../..';
|
Cache.flutterRoot = '../..';
|
||||||
return _testFile('exception_handling', automatedTestsDirectory, flutterTestDirectory);
|
return _testFile('exception_handling', automatedTestsDirectory, flutterTestDirectory);
|
||||||
});
|
});
|
||||||
|
|
||||||
testUsingContext('TestAsyncUtils guarded function test', () async {
|
testUsingContext('report a nice error when a guarded function was called without await', () async {
|
||||||
Cache.flutterRoot = '../..';
|
Cache.flutterRoot = '../..';
|
||||||
return _testFile('test_async_utils_guarded', automatedTestsDirectory, flutterTestDirectory);
|
return _testFile('test_async_utils_guarded', automatedTestsDirectory, flutterTestDirectory);
|
||||||
});
|
});
|
||||||
|
|
||||||
testUsingContext('TestAsyncUtils unguarded function test', () async {
|
testUsingContext('report a nice error when an async function was called without await', () async {
|
||||||
Cache.flutterRoot = '../..';
|
Cache.flutterRoot = '../..';
|
||||||
return _testFile('test_async_utils_unguarded', automatedTestsDirectory, flutterTestDirectory);
|
return _testFile('test_async_utils_unguarded', automatedTestsDirectory, flutterTestDirectory);
|
||||||
});
|
});
|
||||||
|
|
||||||
testUsingContext('Missing flutter_test dependency', () async {
|
testUsingContext('report a nice error when a pubspec.yaml is missing a flutter_test dependency', () async {
|
||||||
final String missingDependencyTests = fs.path.join('..', '..', 'dev', 'missing_dependency_tests');
|
final String missingDependencyTests = fs.path.join('..', '..', 'dev', 'missing_dependency_tests');
|
||||||
Cache.flutterRoot = '../..';
|
Cache.flutterRoot = '../..';
|
||||||
return _testFile('trivial', missingDependencyTests, missingDependencyTests);
|
return _testFile('trivial', missingDependencyTests, missingDependencyTests);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testUsingContext('run a test when its name matches a regexp', () async {
|
||||||
|
Cache.flutterRoot = '../..';
|
||||||
|
final ProcessResult result = await _runFlutterTest('filtering', automatedTestsDirectory, flutterTestDirectory,
|
||||||
|
extraArgs: const <String>["--name", "inc.*de"]);
|
||||||
|
if (!result.stdout.contains("+1: All tests passed"))
|
||||||
|
fail("unexpected output from test:\n\n${result.stdout}\n-- end stdout --\n\n");
|
||||||
|
expect(result.exitCode, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
testUsingContext('run a test when its name contains a string', () async {
|
||||||
|
Cache.flutterRoot = '../..';
|
||||||
|
final ProcessResult result = await _runFlutterTest('filtering', automatedTestsDirectory, flutterTestDirectory,
|
||||||
|
extraArgs: const <String>["--plain-name", "include"]);
|
||||||
|
if (!result.stdout.contains("+1: All tests passed"))
|
||||||
|
fail("unexpected output from test:\n\n${result.stdout}\n-- end stdout --\n\n");
|
||||||
|
expect(result.exitCode, 0);
|
||||||
|
});
|
||||||
|
|
||||||
}, skip: io.Platform.isWindows); // TODO(goderbauer): enable when sky_shell is available
|
}, skip: io.Platform.isWindows); // TODO(goderbauer): enable when sky_shell is available
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Null> _testFile(String testName, String workingDirectory, String testDirectory) async {
|
Future<Null> _testFile(String testName, String workingDirectory, String testDirectory) async {
|
||||||
final String fullTestName = fs.path.join(testDirectory, '${testName}_test.dart');
|
|
||||||
final File testFile = fs.file(fullTestName);
|
|
||||||
expect(testFile.existsSync(), true);
|
|
||||||
final String fullTestExpectation = fs.path.join(testDirectory, '${testName}_expectation.txt');
|
final String fullTestExpectation = fs.path.join(testDirectory, '${testName}_expectation.txt');
|
||||||
final File expectationFile = fs.file(fullTestExpectation);
|
final File expectationFile = fs.file(fullTestExpectation);
|
||||||
expect(expectationFile.existsSync(), true);
|
if (!expectationFile.existsSync())
|
||||||
|
fail("missing expectation file: $expectationFile");
|
||||||
|
|
||||||
while (_testExclusionLock != null)
|
while (_testExclusionLock != null)
|
||||||
await _testExclusionLock;
|
await _testExclusionLock;
|
||||||
|
|
||||||
ProcessResult exec;
|
final ProcessResult exec = await _runFlutterTest(testName, workingDirectory, testDirectory);
|
||||||
final Completer<Null> testExclusionCompleter = new Completer<Null>();
|
|
||||||
_testExclusionLock = testExclusionCompleter.future;
|
|
||||||
try {
|
|
||||||
exec = await Process.run(
|
|
||||||
fs.path.join(dartSdkPath, 'bin', 'dart'),
|
|
||||||
<String>[
|
|
||||||
fs.path.absolute(fs.path.join('bin', 'flutter_tools.dart')),
|
|
||||||
'test',
|
|
||||||
'--no-color',
|
|
||||||
fullTestName,
|
|
||||||
],
|
|
||||||
workingDirectory: workingDirectory,
|
|
||||||
);
|
|
||||||
} finally {
|
|
||||||
_testExclusionLock = null;
|
|
||||||
testExclusionCompleter.complete();
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(exec.exitCode, isNonZero);
|
expect(exec.exitCode, isNonZero);
|
||||||
final List<String> output = exec.stdout.split('\n');
|
final List<String> output = exec.stdout.split('\n');
|
||||||
@ -115,3 +115,34 @@ Future<Null> _testFile(String testName, String workingDirectory, String testDire
|
|||||||
if (!haveSeenStdErrMarker)
|
if (!haveSeenStdErrMarker)
|
||||||
expect(exec.stderr, '');
|
expect(exec.stderr, '');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<ProcessResult> _runFlutterTest(String testName, String workingDirectory, String testDirectory,
|
||||||
|
{List<String> extraArgs = const <String>[]}) async {
|
||||||
|
|
||||||
|
final String testFilePath = fs.path.join(testDirectory, '${testName}_test.dart');
|
||||||
|
final File testFile = fs.file(testFilePath);
|
||||||
|
if (!testFile.existsSync())
|
||||||
|
fail("missing test file: $testFile");
|
||||||
|
|
||||||
|
final List<String> args = <String>[
|
||||||
|
fs.path.absolute(fs.path.join('bin', 'flutter_tools.dart')),
|
||||||
|
'test',
|
||||||
|
'--no-color'
|
||||||
|
]..addAll(extraArgs)..add(testFilePath);
|
||||||
|
|
||||||
|
while (_testExclusionLock != null)
|
||||||
|
await _testExclusionLock;
|
||||||
|
|
||||||
|
final Completer<Null> testExclusionCompleter = new Completer<Null>();
|
||||||
|
_testExclusionLock = testExclusionCompleter.future;
|
||||||
|
try {
|
||||||
|
return await Process.run(
|
||||||
|
fs.path.join(dartSdkPath, 'bin', 'dart'),
|
||||||
|
args,
|
||||||
|
workingDirectory: workingDirectory,
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
_testExclusionLock = null;
|
||||||
|
testExclusionCompleter.complete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user