diff --git a/dev/automated_tests/flutter_test/filtering_tag_test.dart b/dev/automated_tests/flutter_test/filtering_tag_test.dart new file mode 100644 index 0000000000..a550a304ea --- /dev/null +++ b/dev/automated_tests/flutter_test/filtering_tag_test.dart @@ -0,0 +1,14 @@ +// Copyright 2014 The Flutter 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' hide TypeMatcher, isInstanceOf; + +void main() { + test('included', () { + expect(2 + 2, 4); + }, tags: ['include-tag']); + test('excluded', () { + throw 'this test should have been filtered out'; + }, tags: ['exclude-tag']); +} diff --git a/packages/flutter_tools/lib/src/commands/test.dart b/packages/flutter_tools/lib/src/commands/test.dart index 5e48c4ceac..ea5ee53b9f 100644 --- a/packages/flutter_tools/lib/src/commands/test.dart +++ b/packages/flutter_tools/lib/src/commands/test.dart @@ -42,6 +42,14 @@ class TestCommand extends FlutterCommand { valueHelp: 'substring', splitCommas: false, ) + ..addOption('tags', + abbr: 't', + help: 'Run only tests associated with tags', + ) + ..addOption('exclude-tags', + abbr: 'x', + help: 'Run only tests WITHOUT given tags', + ) ..addFlag('start-paused', defaultsTo: false, negatable: false, @@ -160,6 +168,8 @@ class TestCommand extends FlutterCommand { final bool buildTestAssets = boolArg('test-assets'); final List names = stringsArg('name'); final List plainNames = stringsArg('plain-name'); + final String tags = stringArg('tags'); + final String excludeTags = stringArg('exclude-tags'); final FlutterProject flutterProject = FlutterProject.current(); if (buildTestAssets && flutterProject.manifest.assets.isNotEmpty) { @@ -250,6 +260,8 @@ class TestCommand extends FlutterCommand { workDir: workDir, names: names, plainNames: plainNames, + tags: tags, + excludeTags: excludeTags, watcher: watcher, enableObservatory: collector != null || startPaused || boolArg('enable-vmservice'), startPaused: startPaused, diff --git a/packages/flutter_tools/lib/src/test/runner.dart b/packages/flutter_tools/lib/src/test/runner.dart index 3be01e8b12..851d539d38 100644 --- a/packages/flutter_tools/lib/src/test/runner.dart +++ b/packages/flutter_tools/lib/src/test/runner.dart @@ -31,6 +31,8 @@ abstract class FlutterTestRunner { Directory workDir, List names = const [], List plainNames = const [], + String tags, + String excludeTags, bool enableObservatory = false, bool startPaused = false, bool disableServiceAuthCodes = false, @@ -62,6 +64,8 @@ class _FlutterTestRunnerImpl implements FlutterTestRunner { Directory workDir, List names = const [], List plainNames = const [], + String tags, + String excludeTags, bool enableObservatory = false, bool startPaused = false, bool disableServiceAuthCodes = false, @@ -104,6 +108,10 @@ class _FlutterTestRunnerImpl implements FlutterTestRunner { ...['--plain-name', plainName], if (randomSeed != null) '--test-randomize-ordering-seed=$randomSeed', + if (tags != null) + ...['--tags', tags], + if (excludeTags != null) + ...['--exclude-tags', excludeTags], ]; if (web) { final String tempBuildDir = globals.fs.systemTempDirectory diff --git a/packages/flutter_tools/test/commands.shard/hermetic/test_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/test_test.dart index c0a52258ea..a8830a058a 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/test_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/test_test.dart @@ -164,6 +164,8 @@ class FakeFlutterTestRunner implements FlutterTestRunner { Directory workDir, List names = const [], List plainNames = const [], + String tags, + String excludeTags, bool enableObservatory = false, bool startPaused = false, bool disableServiceAuthCodes = false, diff --git a/packages/flutter_tools/test/commands.shard/permeable/test_test.dart b/packages/flutter_tools/test/commands.shard/permeable/test_test.dart index 88005bef0f..e2347d1308 100644 --- a/packages/flutter_tools/test/commands.shard/permeable/test_test.dart +++ b/packages/flutter_tools/test/commands.shard/permeable/test_test.dart @@ -96,6 +96,35 @@ void main() { expect(result.exitCode, 0); }); + testUsingContext('flutter test should run a test with a given tag', () async { + Cache.flutterRoot = '../..'; + final ProcessResult result = await _runFlutterTest('filtering_tag', automatedTestsDirectory, flutterTestDirectory, + extraArguments: const ['--tags', 'include-tag']); + if (!(result.stdout as String).contains('+1: All tests passed')) { + fail('unexpected output from test:\n\n${result.stdout}\n-- end stdout --\n\n'); + } + expect(result.exitCode, 0); + }); + + testUsingContext('flutter test should not run a test with excluded tag', () async { + Cache.flutterRoot = '../..'; + final ProcessResult result = await _runFlutterTest('filtering_tag', automatedTestsDirectory, flutterTestDirectory, + extraArguments: const ['--exclude-tags', 'exclude-tag']); + if (!(result.stdout as String).contains('+1: All tests passed')) { + fail('unexpected output from test:\n\n${result.stdout}\n-- end stdout --\n\n'); + } + expect(result.exitCode, 0); + }); + + testUsingContext('flutter test should run all tests when tags are unspecified', () async { + Cache.flutterRoot = '../..'; + final ProcessResult result = await _runFlutterTest('filtering_tag', automatedTestsDirectory, flutterTestDirectory); + if (!(result.stdout as String).contains('+1 -1: Some tests failed')) { + fail('unexpected output from test:\n\n${result.stdout}\n-- end stdout --\n\n'); + } + expect(result.exitCode, 1); + }); + testUsingContext('flutter test should test runs to completion', () async { Cache.flutterRoot = '../..'; final ProcessResult result = await _runFlutterTest('trivial', automatedTestsDirectory, flutterTestDirectory,