Allow disabling test randomization for certain tests (#1551)
Fixes #1539
Adds an allow_test_randomization option that can be configured for certain tags, in the dart_test.yml file.
Also restructured the Configuration and SuiteConfiguration classes to make future changes less error prone, by making their parameters required. I also added some specialized constructors for the few cases where we really only want to pass a couple options.
diff --git a/pkgs/test/doc/configuration.md b/pkgs/test/doc/configuration.md
index 7a7cabb..0c78b53 100644
--- a/pkgs/test/doc/configuration.md
+++ b/pkgs/test/doc/configuration.md
@@ -32,6 +32,7 @@
* [`skip`](#skip)
* [`retry`](#retry)
* [`test_on`](#test_on)
+ * [`allow_test_randomization`](#allow_test_randomization)
* [Runner Configuration](#runner-configuration)
* [`include`](#include)
* [`paths`](#paths)
@@ -46,6 +47,7 @@
* [`run_skipped`](#run_skipped)
* [`pub_serve`](#pub_serve)
* [`reporter`](#reporter)
+ * [`file_reporters`](#file_reporters)
* [`fold_stack_frames`](#fold_stack_frames)
* [`custom_html_template_path`](#custom_html_template_path)
* [Configuring Tags](#configuring-tags)
@@ -56,13 +58,13 @@
* [`on_platform`](#on_platform)
* [`override_platforms`](#override_platforms)
* [`define_platforms`](#define_platforms)
- * [Browser/Node.js Settings](#browser-and-node-js-settings)
+ * [Browser and Node.js Settings](#browser-and-nodejs-settings)
* [`arguments`](#arguments)
* [`executable`](#executable)
* [`headless`](#headless)
* [Configuration Presets](#configuration-presets)
* [`presets`](#presets)
- * [`add_preset`](#add_preset)
+ * [`add_presets`](#add_presets)
* [Global Configuration](#global-configuration)
## Test Configuration
@@ -191,6 +193,20 @@
This field is not supported in the
[global configuration file](#global-configuration).
+### `allow_test_randomization`
+
+This can be used to disable test randomization for certain tests, regardless
+of the `--test-randomize-ordering-seed` configuration.
+
+This is typically useful when a subset of your tests are order dependent, but
+you want to run the other ones with randomized ordering.
+
+```yaml
+tags:
+ doNotRandomize:
+ allow_test_randomization: false
+```
+
## Runner Configuration
Unlike [test configuration](#test-configuration), runner configuration affects
diff --git a/pkgs/test/pubspec.yaml b/pkgs/test/pubspec.yaml
index be4baba..509b337 100644
--- a/pkgs/test/pubspec.yaml
+++ b/pkgs/test/pubspec.yaml
@@ -34,10 +34,11 @@
yaml: ^3.0.0
# Use an exact version until the test_api and test_core package are stable.
test_api: 0.4.1
- test_core: 0.3.30
+ test_core: 0.4.0
dev_dependencies:
fake_async: ^1.0.0
+ glob: ^2.0.0
shelf_test_handler: ^2.0.0
test_descriptor: ^2.0.0
test_process: ^2.0.0
diff --git a/pkgs/test/test/runner/browser/chrome_test.dart b/pkgs/test/test/runner/browser/chrome_test.dart
index a60bdf4..b5ac51e 100644
--- a/pkgs/test/test/runner/browser/chrome_test.dart
+++ b/pkgs/test/test/runner/browser/chrome_test.dart
@@ -8,7 +8,6 @@
import 'package:test/src/runner/browser/chrome.dart';
import 'package:test/src/runner/executable_settings.dart';
import 'package:test/test.dart';
-import 'package:test_core/src/runner/configuration.dart'; // ignore: implementation_imports
import 'package:test_descriptor/test_descriptor.dart' as d;
import '../../io.dart';
@@ -27,7 +26,7 @@
''');
var webSocket = server.handleWebSocket();
- var chrome = Chrome(server.url, Configuration());
+ var chrome = Chrome(server.url, configuration());
addTearDown(() => chrome.close());
expect(await (await webSocket).stream.first, equals('loaded!'));
@@ -38,12 +37,12 @@
test("a process can be killed synchronously after it's started", () async {
var server = await CodeServer.start();
- var chrome = Chrome(server.url, Configuration());
+ var chrome = Chrome(server.url, configuration());
await chrome.close();
});
test('reports an error in onExit', () {
- var chrome = Chrome(Uri.parse('http://dart-lang.org'), Configuration(),
+ var chrome = Chrome(Uri.parse('http://dart-lang.org'), configuration(),
settings: ExecutableSettings(
linuxExecutable: '_does_not_exist',
macOSExecutable: '_does_not_exist',
diff --git a/pkgs/test/test/runner/browser/loader_test.dart b/pkgs/test/test/runner/browser/loader_test.dart
index e1d6d37..30fa79c 100644
--- a/pkgs/test/test/runner/browser/loader_test.dart
+++ b/pkgs/test/test/runner/browser/loader_test.dart
@@ -27,7 +27,7 @@
/// A configuration that loads suites on Chrome.
final _chrome =
- SuiteConfiguration(runtimes: [RuntimeSelection(Runtime.chrome.identifier)]);
+ SuiteConfiguration.runtimes([RuntimeSelection(Runtime.chrome.identifier)]);
void main() {
setUp(() async {
@@ -135,7 +135,7 @@
var suites = await _loader
.loadFile(
path,
- SuiteConfiguration(runtimes: [
+ SuiteConfiguration.runtimes([
RuntimeSelection(Runtime.vm.identifier),
RuntimeSelection(Runtime.chrome.identifier)
]))
diff --git a/pkgs/test/test/runner/configuration/configuration_test.dart b/pkgs/test/test/runner/configuration/configuration_test.dart
index 83dee46..6538b75 100644
--- a/pkgs/test/test/runner/configuration/configuration_test.dart
+++ b/pkgs/test/test/runner/configuration/configuration_test.dart
@@ -6,15 +6,16 @@
import 'package:path/path.dart' as p;
import 'package:test/test.dart';
-import 'package:test_core/src/runner/configuration.dart';
import 'package:test_core/src/runner/configuration/reporters.dart';
import 'package:test_core/src/util/io.dart';
+import '../../utils.dart';
+
void main() {
group('merge', () {
group('for most fields', () {
test('if neither is defined, preserves the default', () {
- var merged = Configuration().merge(Configuration());
+ var merged = configuration().merge(configuration());
expect(merged.help, isFalse);
expect(merged.version, isFalse);
expect(merged.pauseAfterLoad, isFalse);
@@ -32,7 +33,7 @@
});
test("if only the old configuration's is defined, uses it", () {
- var merged = Configuration(
+ var merged = configuration(
help: true,
version: true,
pauseAfterLoad: true,
@@ -46,7 +47,7 @@
shardIndex: 3,
totalShards: 10,
testRandomizeOrderingSeed: 123,
- paths: ['bar']).merge(Configuration());
+ paths: ['bar']).merge(configuration());
expect(merged.help, isTrue);
expect(merged.version, isTrue);
@@ -65,7 +66,7 @@
});
test("if only the new configuration's is defined, uses it", () {
- var merged = Configuration().merge(Configuration(
+ var merged = configuration().merge(configuration(
help: true,
version: true,
pauseAfterLoad: true,
@@ -100,7 +101,7 @@
test(
"if the two configurations conflict, uses the new configuration's "
'values', () {
- var older = Configuration(
+ var older = configuration(
help: true,
version: false,
pauseAfterLoad: true,
@@ -115,7 +116,7 @@
totalShards: 4,
testRandomizeOrderingSeed: 0,
paths: ['bar']);
- var newer = Configuration(
+ var newer = configuration(
help: false,
version: true,
pauseAfterLoad: false,
@@ -151,37 +152,37 @@
group('for chosenPresets', () {
test('if neither is defined, preserves the default', () {
- var merged = Configuration().merge(Configuration());
+ var merged = configuration().merge(configuration());
expect(merged.chosenPresets, isEmpty);
});
test("if only the old configuration's is defined, uses it", () {
- var merged = Configuration(chosenPresets: ['baz', 'bang'])
- .merge(Configuration());
+ var merged = configuration(chosenPresets: ['baz', 'bang'])
+ .merge(configuration());
expect(merged.chosenPresets, equals(['baz', 'bang']));
});
test("if only the new configuration's is defined, uses it", () {
- var merged = Configuration()
- .merge(Configuration(chosenPresets: ['baz', 'bang']));
+ var merged = configuration()
+ .merge(configuration(chosenPresets: ['baz', 'bang']));
expect(merged.chosenPresets, equals(['baz', 'bang']));
});
test('if both are defined, unions them', () {
- var merged = Configuration(chosenPresets: ['baz', 'bang'])
- .merge(Configuration(chosenPresets: ['qux']));
+ var merged = configuration(chosenPresets: ['baz', 'bang'])
+ .merge(configuration(chosenPresets: ['qux']));
expect(merged.chosenPresets, equals(['baz', 'bang', 'qux']));
});
});
group('for presets', () {
test('merges each nested configuration', () {
- var merged = Configuration(presets: {
- 'bang': Configuration(pauseAfterLoad: true),
- 'qux': Configuration(color: true)
- }).merge(Configuration(presets: {
- 'qux': Configuration(color: false),
- 'zap': Configuration(help: true)
+ var merged = configuration(presets: {
+ 'bang': configuration(pauseAfterLoad: true),
+ 'qux': configuration(color: true)
+ }).merge(configuration(presets: {
+ 'qux': configuration(color: false),
+ 'zap': configuration(help: true)
}));
expect(merged.presets['bang']!.pauseAfterLoad, isTrue);
@@ -190,68 +191,67 @@
});
test('automatically resolves a matching chosen preset', () {
- var configuration = Configuration(
- presets: {'foo': Configuration(color: true)},
+ var config = configuration(
+ presets: {'foo': configuration(color: true)},
chosenPresets: ['foo']);
- expect(configuration.presets, isEmpty);
- expect(configuration.chosenPresets, equals(['foo']));
- expect(configuration.knownPresets, equals(['foo']));
- expect(configuration.color, isTrue);
+ expect(config.presets, isEmpty);
+ expect(config.chosenPresets, equals(['foo']));
+ expect(config.knownPresets, equals(['foo']));
+ expect(config.color, isTrue);
});
test('resolves a chosen presets in order', () {
- var configuration = Configuration(presets: {
- 'foo': Configuration(color: true),
- 'bar': Configuration(color: false)
+ var config = configuration(presets: {
+ 'foo': configuration(color: true),
+ 'bar': configuration(color: false)
}, chosenPresets: [
'foo',
'bar'
]);
- expect(configuration.presets, isEmpty);
- expect(configuration.chosenPresets, equals(['foo', 'bar']));
- expect(configuration.knownPresets, unorderedEquals(['foo', 'bar']));
- expect(configuration.color, isFalse);
+ expect(config.presets, isEmpty);
+ expect(config.chosenPresets, equals(['foo', 'bar']));
+ expect(config.knownPresets, unorderedEquals(['foo', 'bar']));
+ expect(config.color, isFalse);
- configuration = Configuration(presets: {
- 'foo': Configuration(color: true),
- 'bar': Configuration(color: false)
+ config = configuration(presets: {
+ 'foo': configuration(color: true),
+ 'bar': configuration(color: false)
}, chosenPresets: [
'bar',
'foo'
]);
- expect(configuration.presets, isEmpty);
- expect(configuration.chosenPresets, equals(['bar', 'foo']));
- expect(configuration.knownPresets, unorderedEquals(['foo', 'bar']));
- expect(configuration.color, isTrue);
+ expect(config.presets, isEmpty);
+ expect(config.chosenPresets, equals(['bar', 'foo']));
+ expect(config.knownPresets, unorderedEquals(['foo', 'bar']));
+ expect(config.color, isTrue);
});
test('ignores inapplicable chosen presets', () {
- var configuration = Configuration(presets: {}, chosenPresets: ['baz']);
- expect(configuration.presets, isEmpty);
- expect(configuration.chosenPresets, equals(['baz']));
- expect(configuration.knownPresets, equals(isEmpty));
+ var config = configuration(presets: {}, chosenPresets: ['baz']);
+ expect(config.presets, isEmpty);
+ expect(config.chosenPresets, equals(['baz']));
+ expect(config.knownPresets, equals(isEmpty));
});
test('resolves presets through merging', () {
- var configuration =
- Configuration(presets: {'foo': Configuration(color: true)})
- .merge(Configuration(chosenPresets: ['foo']));
+ var config = configuration(presets: {'foo': configuration(color: true)})
+ .merge(configuration(chosenPresets: ['foo']));
- expect(configuration.presets, isEmpty);
- expect(configuration.chosenPresets, equals(['foo']));
- expect(configuration.knownPresets, equals(['foo']));
- expect(configuration.color, isTrue);
+ expect(config.presets, isEmpty);
+ expect(config.chosenPresets, equals(['foo']));
+ expect(config.knownPresets, equals(['foo']));
+ expect(config.color, isTrue);
});
test('preserves known presets through merging', () {
- var configuration = Configuration(
- presets: {'foo': Configuration(color: true)},
- chosenPresets: ['foo']).merge(Configuration());
+ var config = configuration(
+ presets: {'foo': configuration(color: true)},
+ chosenPresets: ['foo']).merge(configuration());
- expect(configuration.presets, isEmpty);
- expect(configuration.chosenPresets, equals(['foo']));
- expect(configuration.knownPresets, equals(['foo']));
- expect(configuration.color, isTrue);
+ expect(config.presets, isEmpty);
+ expect(config.chosenPresets, equals(['foo']));
+ expect(config.knownPresets, equals(['foo']));
+ expect(config.color, isTrue);
});
});
});
diff --git a/pkgs/test/test/runner/configuration/randomize_order_test.dart b/pkgs/test/test/runner/configuration/randomize_order_test.dart
index 984cd0f..adb853e 100644
--- a/pkgs/test/test/runner/configuration/randomize_order_test.dart
+++ b/pkgs/test/test/runner/configuration/randomize_order_test.dart
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
@TestOn('vm')
+import 'dart:convert';
import 'package:test_descriptor/test_descriptor.dart' as d;
@@ -82,6 +83,43 @@
await test.shouldExit(0);
});
+ test('test shuffling can be disabled in dart_test.yml', () async {
+ await d
+ .file(
+ 'dart_test.yaml',
+ jsonEncode({
+ 'tags': {
+ 'doNotShuffle': {'allow_test_randomization': false}
+ }
+ }))
+ .create();
+
+ await d.file('test.dart', '''
+ @Tags(['doNotShuffle'])
+ import 'package:test/test.dart';
+
+ void main() {
+ test("test 1", () {});
+ test("test 2", () {});
+ test("test 3", () {});
+ test("test 4", () {});
+ }
+ ''').create();
+
+ var test =
+ await runTest(['test.dart', '--test-randomize-ordering-seed=987654']);
+ expect(
+ test.stdout,
+ containsInOrder([
+ '+0: test 1',
+ '+1: test 2',
+ '+2: test 3',
+ '+3: test 4',
+ '+4: All tests passed!'
+ ]));
+ await test.shouldExit(0);
+ });
+
test('shuffles each suite with the same seed', () async {
await d.file('1_test.dart', '''
import 'package:test/test.dart';
diff --git a/pkgs/test/test/runner/configuration/suite_test.dart b/pkgs/test/test/runner/configuration/suite_test.dart
index 8fa2069..bcd64a5 100644
--- a/pkgs/test/test/runner/configuration/suite_test.dart
+++ b/pkgs/test/test/runner/configuration/suite_test.dart
@@ -9,13 +9,14 @@
import 'package:test_api/src/backend/platform_selector.dart';
import 'package:test_api/src/backend/runtime.dart';
import 'package:test_core/src/runner/runtime_selection.dart';
-import 'package:test_core/src/runner/suite.dart';
+
+import '../../utils.dart';
void main() {
group('merge', () {
group('for most fields', () {
test('if neither is defined, preserves the default', () {
- var merged = SuiteConfiguration().merge(SuiteConfiguration());
+ var merged = suiteConfiguration().merge(suiteConfiguration());
expect(merged.jsTrace, isFalse);
expect(merged.runSkipped, isFalse);
expect(merged.precompiledPath, isNull);
@@ -23,12 +24,12 @@
});
test("if only the old configuration's is defined, uses it", () {
- var merged = SuiteConfiguration(
+ var merged = suiteConfiguration(
jsTrace: true,
runSkipped: true,
precompiledPath: '/tmp/js',
runtimes: [RuntimeSelection(Runtime.chrome.identifier)])
- .merge(SuiteConfiguration());
+ .merge(suiteConfiguration());
expect(merged.jsTrace, isTrue);
expect(merged.runSkipped, isTrue);
@@ -37,7 +38,7 @@
});
test("if only the configuration's is defined, uses it", () {
- var merged = SuiteConfiguration().merge(SuiteConfiguration(
+ var merged = suiteConfiguration().merge(suiteConfiguration(
jsTrace: true,
runSkipped: true,
precompiledPath: '/tmp/js',
@@ -52,12 +53,12 @@
test(
"if the two configurations conflict, uses the configuration's "
'values', () {
- var older = SuiteConfiguration(
+ var older = suiteConfiguration(
jsTrace: false,
runSkipped: true,
precompiledPath: '/tmp/js',
runtimes: [RuntimeSelection(Runtime.chrome.identifier)]);
- var newer = SuiteConfiguration(
+ var newer = suiteConfiguration(
jsTrace: true,
runSkipped: false,
precompiledPath: '../js',
@@ -73,16 +74,16 @@
group('for include and excludeTags', () {
test('if neither is defined, preserves the default', () {
- var merged = SuiteConfiguration().merge(SuiteConfiguration());
+ var merged = suiteConfiguration().merge(suiteConfiguration());
expect(merged.includeTags, equals(BooleanSelector.all));
expect(merged.excludeTags, equals(BooleanSelector.none));
});
test("if only the old configuration's is defined, uses it", () {
- var merged = SuiteConfiguration(
+ var merged = suiteConfiguration(
includeTags: BooleanSelector.parse('foo || bar'),
excludeTags: BooleanSelector.parse('baz || bang'))
- .merge(SuiteConfiguration());
+ .merge(suiteConfiguration());
expect(merged.includeTags, equals(BooleanSelector.parse('foo || bar')));
expect(
@@ -90,7 +91,7 @@
});
test("if only the configuration's is defined, uses it", () {
- var merged = SuiteConfiguration().merge(SuiteConfiguration(
+ var merged = suiteConfiguration().merge(suiteConfiguration(
includeTags: BooleanSelector.parse('foo || bar'),
excludeTags: BooleanSelector.parse('baz || bang')));
@@ -100,10 +101,10 @@
});
test('if both are defined, unions or intersects them', () {
- var older = SuiteConfiguration(
+ var older = suiteConfiguration(
includeTags: BooleanSelector.parse('foo || bar'),
excludeTags: BooleanSelector.parse('baz || bang'));
- var newer = SuiteConfiguration(
+ var newer = suiteConfiguration(
includeTags: BooleanSelector.parse('blip'),
excludeTags: BooleanSelector.parse('qux'));
var merged = older.merge(newer);
@@ -117,27 +118,27 @@
group('for sets', () {
test('if neither is defined, preserves the default', () {
- var merged = SuiteConfiguration().merge(SuiteConfiguration());
+ var merged = suiteConfiguration().merge(suiteConfiguration());
expect(merged.patterns, isEmpty);
});
test("if only the old configuration's is defined, uses it", () {
- var merged = SuiteConfiguration(patterns: ['beep', 'boop'])
- .merge(SuiteConfiguration());
+ var merged = suiteConfiguration(patterns: ['beep', 'boop'])
+ .merge(suiteConfiguration());
expect(merged.patterns, equals(['beep', 'boop']));
});
test("if only the configuration's is defined, uses it", () {
- var merged = SuiteConfiguration()
- .merge(SuiteConfiguration(patterns: ['beep', 'boop']));
+ var merged = suiteConfiguration()
+ .merge(suiteConfiguration(patterns: ['beep', 'boop']));
expect(merged.patterns, equals(['beep', 'boop']));
});
test('if both are defined, unions them', () {
- var older = SuiteConfiguration(patterns: ['beep', 'boop']);
- var newer = SuiteConfiguration(patterns: ['bonk']);
+ var older = suiteConfiguration(patterns: ['beep', 'boop']);
+ var newer = suiteConfiguration(patterns: ['bonk']);
var merged = older.merge(newer);
expect(merged.patterns, unorderedEquals(['beep', 'boop', 'bonk']));
@@ -146,25 +147,25 @@
group('for dart2jsArgs', () {
test('if neither is defined, preserves the default', () {
- var merged = SuiteConfiguration().merge(SuiteConfiguration());
+ var merged = suiteConfiguration().merge(suiteConfiguration());
expect(merged.dart2jsArgs, isEmpty);
});
test("if only the old configuration's is defined, uses it", () {
- var merged = SuiteConfiguration(dart2jsArgs: ['--foo', '--bar'])
- .merge(SuiteConfiguration());
+ var merged = suiteConfiguration(dart2jsArgs: ['--foo', '--bar'])
+ .merge(suiteConfiguration());
expect(merged.dart2jsArgs, equals(['--foo', '--bar']));
});
test("if only the configuration's is defined, uses it", () {
- var merged = SuiteConfiguration()
- .merge(SuiteConfiguration(dart2jsArgs: ['--foo', '--bar']));
+ var merged = suiteConfiguration()
+ .merge(suiteConfiguration(dart2jsArgs: ['--foo', '--bar']));
expect(merged.dart2jsArgs, equals(['--foo', '--bar']));
});
test('if both are defined, concatenates them', () {
- var older = SuiteConfiguration(dart2jsArgs: ['--foo', '--bar']);
- var newer = SuiteConfiguration(dart2jsArgs: ['--baz']);
+ var older = suiteConfiguration(dart2jsArgs: ['--foo', '--bar']);
+ var newer = suiteConfiguration(dart2jsArgs: ['--baz']);
var merged = older.merge(newer);
expect(merged.dart2jsArgs, equals(['--foo', '--bar', '--baz']));
});
@@ -172,21 +173,21 @@
group('for config maps', () {
test('merges each nested configuration', () {
- var merged = SuiteConfiguration(tags: {
+ var merged = suiteConfiguration(tags: {
BooleanSelector.parse('foo'):
- SuiteConfiguration(precompiledPath: 'path/'),
- BooleanSelector.parse('bar'): SuiteConfiguration(jsTrace: true)
+ suiteConfiguration(precompiledPath: 'path/'),
+ BooleanSelector.parse('bar'): suiteConfiguration(jsTrace: true)
}, onPlatform: {
PlatformSelector.parse('vm'):
- SuiteConfiguration(precompiledPath: 'path/'),
- PlatformSelector.parse('chrome'): SuiteConfiguration(jsTrace: true)
- }).merge(SuiteConfiguration(tags: {
- BooleanSelector.parse('bar'): SuiteConfiguration(jsTrace: false),
- BooleanSelector.parse('baz'): SuiteConfiguration(runSkipped: true)
+ suiteConfiguration(precompiledPath: 'path/'),
+ PlatformSelector.parse('chrome'): suiteConfiguration(jsTrace: true)
+ }).merge(suiteConfiguration(tags: {
+ BooleanSelector.parse('bar'): suiteConfiguration(jsTrace: false),
+ BooleanSelector.parse('baz'): suiteConfiguration(runSkipped: true)
}, onPlatform: {
- PlatformSelector.parse('chrome'): SuiteConfiguration(jsTrace: false),
+ PlatformSelector.parse('chrome'): suiteConfiguration(jsTrace: false),
PlatformSelector.parse('firefox'):
- SuiteConfiguration(runSkipped: true)
+ suiteConfiguration(runSkipped: true)
}));
expect(merged.tags[BooleanSelector.parse('foo')]!.precompiledPath,
diff --git a/pkgs/test/test/runner/loader_test.dart b/pkgs/test/test/runner/loader_test.dart
index 3469d4e..595514d 100644
--- a/pkgs/test/test/runner/loader_test.dart
+++ b/pkgs/test/test/runner/loader_test.dart
@@ -177,7 +177,7 @@
await runZoned(() async {
var suites = await _loader
.loadFile(p.join(d.sandbox, 'a_test.dart'),
- SuiteConfiguration(retry: numRetries))
+ suiteConfiguration(retry: numRetries))
.toList();
expect(suites, hasLength(1));
var loadSuite = suites.first;
diff --git a/pkgs/test/test/utils.dart b/pkgs/test/test/utils.dart
index 4b04134..123ff0a 100644
--- a/pkgs/test/test/utils.dart
+++ b/pkgs/test/test/utils.dart
@@ -5,22 +5,29 @@
import 'dart:async';
import 'dart:collection';
+import 'package:boolean_selector/boolean_selector.dart';
+import 'package:glob/glob.dart';
import 'package:test_api/src/backend/declarer.dart';
import 'package:test_api/src/backend/group.dart';
import 'package:test_api/src/backend/group_entry.dart';
import 'package:test_api/src/backend/invoker.dart';
import 'package:test_api/src/backend/live_test.dart';
import 'package:test_api/src/backend/metadata.dart';
+import 'package:test_api/src/backend/platform_selector.dart';
import 'package:test_api/src/backend/runtime.dart';
import 'package:test_api/src/backend/state.dart';
import 'package:test_api/src/backend/suite.dart';
import 'package:test_api/src/backend/suite_platform.dart';
import 'package:test_core/src/runner/application_exception.dart';
-import 'package:test_core/src/runner/suite.dart';
+import 'package:test_core/src/runner/configuration.dart';
+import 'package:test_core/src/runner/configuration/custom_runtime.dart';
+import 'package:test_core/src/runner/configuration/runtime_settings.dart';
import 'package:test_core/src/runner/engine.dart';
-import 'package:test_core/src/runner/plugin/environment.dart';
import 'package:test_core/src/runner/load_suite.dart';
+import 'package:test_core/src/runner/plugin/environment.dart';
import 'package:test_core/src/runner/runner_suite.dart';
+import 'package:test_core/src/runner/runtime_selection.dart';
+import 'package:test_core/src/runner/suite.dart';
import 'package:test/test.dart';
/// A dummy suite platform to use for testing suites.
@@ -193,7 +200,7 @@
return Engine.withSuites([
RunnerSuite(
const PluginEnvironment(),
- SuiteConfiguration(runSkipped: runSkipped),
+ SuiteConfiguration.runSkipped(runSkipped),
declarer.build(),
suitePlatform)
], coverage: coverage);
@@ -206,3 +213,143 @@
/// Returns a [LoadSuite] with a default configuration.
LoadSuite loadSuite(String name, FutureOr<RunnerSuite> Function() body) =>
LoadSuite(name, SuiteConfiguration.empty, suitePlatform, body);
+
+SuiteConfiguration suiteConfiguration(
+ {bool? allowTestRandomization,
+ bool? jsTrace,
+ bool? runSkipped,
+ Iterable<String>? dart2jsArgs,
+ String? precompiledPath,
+ Iterable<Pattern>? patterns,
+ Iterable<RuntimeSelection>? runtimes,
+ BooleanSelector? includeTags,
+ BooleanSelector? excludeTags,
+ Map<BooleanSelector, SuiteConfiguration>? tags,
+ Map<PlatformSelector, SuiteConfiguration>? onPlatform,
+
+ // Test-level configuration
+ Timeout? timeout,
+ bool? verboseTrace,
+ bool? chainStackTraces,
+ bool? skip,
+ int? retry,
+ String? skipReason,
+ PlatformSelector? testOn,
+ Iterable<String>? addTags}) =>
+ SuiteConfiguration(
+ allowTestRandomization: allowTestRandomization,
+ jsTrace: jsTrace,
+ runSkipped: runSkipped,
+ dart2jsArgs: dart2jsArgs,
+ precompiledPath: precompiledPath,
+ patterns: patterns,
+ runtimes: runtimes,
+ includeTags: includeTags,
+ excludeTags: excludeTags,
+ tags: tags,
+ onPlatform: onPlatform,
+ timeout: timeout,
+ verboseTrace: verboseTrace,
+ chainStackTraces: chainStackTraces,
+ skip: skip,
+ retry: retry,
+ skipReason: skipReason,
+ testOn: testOn,
+ addTags: addTags);
+
+Configuration configuration(
+ {bool? help,
+ String? customHtmlTemplatePath,
+ bool? version,
+ bool? pauseAfterLoad,
+ bool? debug,
+ bool? color,
+ String? configurationPath,
+ String? dart2jsPath,
+ String? reporter,
+ Map<String, String>? fileReporters,
+ String? coverage,
+ int? pubServePort,
+ int? concurrency,
+ int? shardIndex,
+ int? totalShards,
+ Iterable<String>? paths,
+ Iterable<String>? foldTraceExcept,
+ Iterable<String>? foldTraceOnly,
+ Glob? filename,
+ Iterable<String>? chosenPresets,
+ Map<String, Configuration>? presets,
+ Map<String, RuntimeSettings>? overrideRuntimes,
+ Map<String, CustomRuntime>? defineRuntimes,
+ bool? noRetry,
+ bool? useDataIsolateStrategy,
+
+ // Suite-level configuration
+ bool? allowTestRandomization,
+ bool? jsTrace,
+ bool? runSkipped,
+ Iterable<String>? dart2jsArgs,
+ String? precompiledPath,
+ Iterable<Pattern>? patterns,
+ Iterable<RuntimeSelection>? runtimes,
+ BooleanSelector? includeTags,
+ BooleanSelector? excludeTags,
+ Map<BooleanSelector, SuiteConfiguration>? tags,
+ Map<PlatformSelector, SuiteConfiguration>? onPlatform,
+ int? testRandomizeOrderingSeed,
+
+ // Test-level configuration
+ Timeout? timeout,
+ bool? verboseTrace,
+ bool? chainStackTraces,
+ bool? skip,
+ int? retry,
+ String? skipReason,
+ PlatformSelector? testOn,
+ Iterable<String>? addTags}) =>
+ Configuration(
+ help: help,
+ customHtmlTemplatePath: customHtmlTemplatePath,
+ version: version,
+ pauseAfterLoad: pauseAfterLoad,
+ debug: debug,
+ color: color,
+ configurationPath: configurationPath,
+ dart2jsPath: dart2jsPath,
+ reporter: reporter,
+ fileReporters: fileReporters,
+ coverage: coverage,
+ pubServePort: pubServePort,
+ concurrency: concurrency,
+ shardIndex: shardIndex,
+ totalShards: totalShards,
+ paths: paths,
+ foldTraceExcept: foldTraceExcept,
+ foldTraceOnly: foldTraceOnly,
+ filename: filename,
+ chosenPresets: chosenPresets,
+ presets: presets,
+ overrideRuntimes: overrideRuntimes,
+ defineRuntimes: defineRuntimes,
+ noRetry: noRetry,
+ useDataIsolateStrategy: useDataIsolateStrategy,
+ allowTestRandomization: allowTestRandomization,
+ jsTrace: jsTrace,
+ runSkipped: runSkipped,
+ dart2jsArgs: dart2jsArgs,
+ precompiledPath: precompiledPath,
+ patterns: patterns,
+ runtimes: runtimes,
+ includeTags: includeTags,
+ excludeTags: excludeTags,
+ tags: tags,
+ onPlatform: onPlatform,
+ testRandomizeOrderingSeed: testRandomizeOrderingSeed,
+ timeout: timeout,
+ verboseTrace: verboseTrace,
+ chainStackTraces: chainStackTraces,
+ skip: skip,
+ retry: retry,
+ skipReason: skipReason,
+ testOn: testOn,
+ addTags: addTags);
diff --git a/pkgs/test_api/test/utils.dart b/pkgs/test_api/test/utils.dart
index 18981d5..22888a7 100644
--- a/pkgs/test_api/test/utils.dart
+++ b/pkgs/test_api/test/utils.dart
@@ -181,7 +181,7 @@
return Engine.withSuites([
RunnerSuite(
const PluginEnvironment(),
- SuiteConfiguration(runSkipped: runSkipped),
+ SuiteConfiguration.runSkipped(runSkipped),
declarer.build(),
suitePlatform)
]);
diff --git a/pkgs/test_core/CHANGELOG.md b/pkgs/test_core/CHANGELOG.md
index 2d33d44..95aab63 100644
--- a/pkgs/test_core/CHANGELOG.md
+++ b/pkgs/test_core/CHANGELOG.md
@@ -1,6 +1,9 @@
-## 0.3.30-dev
+## 0.4.0-dev
-* Remove support for `FORCE_TEST_EXIT`.
+* **BREAKING**: All parameters to the `SuiteConfiguration` and `Configuration`
+ constructors are now required. Some specialized constructors have been added
+ for the common cases where a subset are intended to be provided.
+* **BREAKING**: Remove support for `FORCE_TEST_EXIT`.
* Report incomplete tests as errors in the JSON reporter when the run is
canceled early.
* Don't log the --test-randomization-ordering-seed if using the json reporter.
diff --git a/pkgs/test_core/lib/src/runner/configuration.dart b/pkgs/test_core/lib/src/runner/configuration.dart
index ae21042..0f9e333 100644
--- a/pkgs/test_core/lib/src/runner/configuration.dart
+++ b/pkgs/test_core/lib/src/runner/configuration.dart
@@ -36,7 +36,7 @@
///
/// Using this is slightly more efficient than manually constructing a new
/// configuration with no arguments.
- static final empty = Configuration._();
+ static final empty = Configuration._unsafe();
/// The usage string for the command-line arguments.
static String get usage => args.usage;
@@ -202,7 +202,7 @@
///
/// The current configuration is set using [asCurrent].
static Configuration get current =>
- Zone.current[_currentKey] as Configuration? ?? Configuration();
+ Zone.current[_currentKey] as Configuration? ?? Configuration._unsafe();
/// Parses the configuration from [args].
///
@@ -236,54 +236,55 @@
parse(content, global: global, sourceUrl: sourceUrl);
factory Configuration(
- {bool? help,
- String? customHtmlTemplatePath,
- bool? version,
- bool? pauseAfterLoad,
- bool? debug,
- bool? color,
- String? configurationPath,
- String? dart2jsPath,
- String? reporter,
- Map<String, String>? fileReporters,
- String? coverage,
- int? pubServePort,
- int? concurrency,
- int? shardIndex,
- int? totalShards,
- Iterable<String>? paths,
- Iterable<String>? foldTraceExcept,
- Iterable<String>? foldTraceOnly,
- Glob? filename,
- Iterable<String>? chosenPresets,
- Map<String, Configuration>? presets,
- Map<String, RuntimeSettings>? overrideRuntimes,
- Map<String, CustomRuntime>? defineRuntimes,
- bool? noRetry,
- bool? useDataIsolateStrategy,
+ {required bool? help,
+ required String? customHtmlTemplatePath,
+ required bool? version,
+ required bool? pauseAfterLoad,
+ required bool? debug,
+ required bool? color,
+ required String? configurationPath,
+ required String? dart2jsPath,
+ required String? reporter,
+ required Map<String, String>? fileReporters,
+ required String? coverage,
+ required int? pubServePort,
+ required int? concurrency,
+ required int? shardIndex,
+ required int? totalShards,
+ required Iterable<String>? paths,
+ required Iterable<String>? foldTraceExcept,
+ required Iterable<String>? foldTraceOnly,
+ required Glob? filename,
+ required Iterable<String>? chosenPresets,
+ required Map<String, Configuration>? presets,
+ required Map<String, RuntimeSettings>? overrideRuntimes,
+ required Map<String, CustomRuntime>? defineRuntimes,
+ required bool? noRetry,
+ required bool? useDataIsolateStrategy,
+ required int? testRandomizeOrderingSeed,
// Suite-level configuration
- bool? jsTrace,
- bool? runSkipped,
- Iterable<String>? dart2jsArgs,
- String? precompiledPath,
- Iterable<Pattern>? patterns,
- Iterable<RuntimeSelection>? runtimes,
- BooleanSelector? includeTags,
- BooleanSelector? excludeTags,
- Map<BooleanSelector, SuiteConfiguration>? tags,
- Map<PlatformSelector, SuiteConfiguration>? onPlatform,
- int? testRandomizeOrderingSeed,
+ required bool? allowTestRandomization,
+ required bool? jsTrace,
+ required bool? runSkipped,
+ required Iterable<String>? dart2jsArgs,
+ required String? precompiledPath,
+ required Iterable<Pattern>? patterns,
+ required Iterable<RuntimeSelection>? runtimes,
+ required BooleanSelector? includeTags,
+ required BooleanSelector? excludeTags,
+ required Map<BooleanSelector, SuiteConfiguration>? tags,
+ required Map<PlatformSelector, SuiteConfiguration>? onPlatform,
// Test-level configuration
- Timeout? timeout,
- bool? verboseTrace,
- bool? chainStackTraces,
- bool? skip,
- int? retry,
- String? skipReason,
- PlatformSelector? testOn,
- Iterable<String>? addTags}) {
+ required Timeout? timeout,
+ required bool? verboseTrace,
+ required bool? chainStackTraces,
+ required bool? skip,
+ required int? retry,
+ required String? skipReason,
+ required PlatformSelector? testOn,
+ required Iterable<String>? addTags}) {
var chosenPresetSet = chosenPresets?.toSet();
var configuration = Configuration._(
help: help,
@@ -313,6 +314,7 @@
useDataIsolateStrategy: useDataIsolateStrategy,
testRandomizeOrderingSeed: testRandomizeOrderingSeed,
suiteDefaults: SuiteConfiguration(
+ allowTestRandomization: allowTestRandomization,
jsTrace: jsTrace,
runSkipped: runSkipped,
dart2jsArgs: dart2jsArgs,
@@ -336,6 +338,344 @@
return configuration._resolvePresets();
}
+ /// A constructor that doesn't require all of its options to be passed.
+ ///
+ /// This should only be used in situations where you really only want to
+ /// configure a specific restricted set of options.
+ factory Configuration._unsafe(
+ {bool? help,
+ String? customHtmlTemplatePath,
+ bool? version,
+ bool? pauseAfterLoad,
+ bool? debug,
+ bool? color,
+ String? configurationPath,
+ String? dart2jsPath,
+ String? reporter,
+ Map<String, String>? fileReporters,
+ String? coverage,
+ int? pubServePort,
+ int? concurrency,
+ int? shardIndex,
+ int? totalShards,
+ Iterable<String>? paths,
+ Iterable<String>? foldTraceExcept,
+ Iterable<String>? foldTraceOnly,
+ Glob? filename,
+ Iterable<String>? chosenPresets,
+ Map<String, Configuration>? presets,
+ Map<String, RuntimeSettings>? overrideRuntimes,
+ Map<String, CustomRuntime>? defineRuntimes,
+ bool? noRetry,
+ bool? useDataIsolateStrategy,
+
+ // Suite-level configuration
+ bool? allowTestRandomization,
+ bool? jsTrace,
+ bool? runSkipped,
+ Iterable<String>? dart2jsArgs,
+ String? precompiledPath,
+ Iterable<Pattern>? patterns,
+ Iterable<RuntimeSelection>? runtimes,
+ BooleanSelector? includeTags,
+ BooleanSelector? excludeTags,
+ Map<BooleanSelector, SuiteConfiguration>? tags,
+ Map<PlatformSelector, SuiteConfiguration>? onPlatform,
+ int? testRandomizeOrderingSeed,
+
+ // Test-level configuration
+ Timeout? timeout,
+ bool? verboseTrace,
+ bool? chainStackTraces,
+ bool? skip,
+ int? retry,
+ String? skipReason,
+ PlatformSelector? testOn,
+ Iterable<String>? addTags}) =>
+ Configuration(
+ help: help,
+ customHtmlTemplatePath: customHtmlTemplatePath,
+ version: version,
+ pauseAfterLoad: pauseAfterLoad,
+ debug: debug,
+ color: color,
+ configurationPath: configurationPath,
+ dart2jsPath: dart2jsPath,
+ reporter: reporter,
+ fileReporters: fileReporters,
+ coverage: coverage,
+ pubServePort: pubServePort,
+ concurrency: concurrency,
+ shardIndex: shardIndex,
+ totalShards: totalShards,
+ paths: paths,
+ foldTraceExcept: foldTraceExcept,
+ foldTraceOnly: foldTraceOnly,
+ filename: filename,
+ chosenPresets: chosenPresets,
+ presets: presets,
+ overrideRuntimes: overrideRuntimes,
+ defineRuntimes: defineRuntimes,
+ noRetry: noRetry,
+ useDataIsolateStrategy: useDataIsolateStrategy,
+ allowTestRandomization: allowTestRandomization,
+ jsTrace: jsTrace,
+ runSkipped: runSkipped,
+ dart2jsArgs: dart2jsArgs,
+ precompiledPath: precompiledPath,
+ patterns: patterns,
+ runtimes: runtimes,
+ includeTags: includeTags,
+ excludeTags: excludeTags,
+ tags: tags,
+ onPlatform: onPlatform,
+ testRandomizeOrderingSeed: testRandomizeOrderingSeed,
+ timeout: timeout,
+ verboseTrace: verboseTrace,
+ chainStackTraces: chainStackTraces,
+ skip: skip,
+ retry: retry,
+ skipReason: skipReason,
+ testOn: testOn,
+ addTags: addTags);
+
+ /// Configuration limited to the globally configurable test config.
+ factory Configuration.globalTest({
+ required bool? verboseTrace,
+ required bool? jsTrace,
+ required Timeout? timeout,
+ required Map<String, Configuration>? presets,
+ required bool? chainStackTraces,
+ required Iterable<String>? foldTraceExcept,
+ required Iterable<String>? foldTraceOnly,
+ }) =>
+ Configuration(
+ foldTraceExcept: foldTraceExcept,
+ foldTraceOnly: foldTraceOnly,
+ jsTrace: jsTrace,
+ timeout: timeout,
+ verboseTrace: verboseTrace,
+ chainStackTraces: chainStackTraces,
+ help: null,
+ customHtmlTemplatePath: null,
+ version: null,
+ pauseAfterLoad: null,
+ debug: null,
+ color: null,
+ configurationPath: null,
+ dart2jsPath: null,
+ reporter: null,
+ fileReporters: null,
+ coverage: null,
+ pubServePort: null,
+ concurrency: null,
+ shardIndex: null,
+ totalShards: null,
+ paths: null,
+ filename: null,
+ chosenPresets: null,
+ presets: presets,
+ overrideRuntimes: null,
+ defineRuntimes: null,
+ noRetry: null,
+ useDataIsolateStrategy: null,
+ testRandomizeOrderingSeed: null,
+ allowTestRandomization: null,
+ runSkipped: null,
+ dart2jsArgs: null,
+ precompiledPath: null,
+ patterns: null,
+ runtimes: null,
+ includeTags: null,
+ excludeTags: null,
+ tags: null,
+ onPlatform: null,
+ skip: null,
+ retry: null,
+ skipReason: null,
+ testOn: null,
+ addTags: null,
+ );
+
+ /// Configuration limited to the locally configurable test config.
+ factory Configuration.localTest(
+ {required bool? skip,
+ required int? retry,
+ required String? skipReason,
+ required PlatformSelector? testOn,
+ required Iterable<String>? addTags,
+ required bool? allowTestRandomization}) =>
+ Configuration(
+ allowTestRandomization: allowTestRandomization,
+ skip: skip,
+ retry: retry,
+ skipReason: skipReason,
+ testOn: testOn,
+ addTags: addTags,
+ help: null,
+ customHtmlTemplatePath: null,
+ version: null,
+ pauseAfterLoad: null,
+ debug: null,
+ color: null,
+ configurationPath: null,
+ dart2jsPath: null,
+ reporter: null,
+ fileReporters: null,
+ coverage: null,
+ pubServePort: null,
+ concurrency: null,
+ shardIndex: null,
+ totalShards: null,
+ paths: null,
+ foldTraceExcept: null,
+ foldTraceOnly: null,
+ filename: null,
+ chosenPresets: null,
+ presets: null,
+ overrideRuntimes: null,
+ defineRuntimes: null,
+ noRetry: null,
+ useDataIsolateStrategy: null,
+ testRandomizeOrderingSeed: null,
+ jsTrace: null,
+ runSkipped: null,
+ dart2jsArgs: null,
+ precompiledPath: null,
+ patterns: null,
+ runtimes: null,
+ includeTags: null,
+ excludeTags: null,
+ tags: null,
+ onPlatform: null,
+ timeout: null,
+ verboseTrace: null,
+ chainStackTraces: null,
+ );
+
+ /// Configuration options limited to the global runner config.
+ factory Configuration.globalRunner(
+ {required bool? pauseAfterLoad,
+ required String? customHtmlTemplatePath,
+ required bool? runSkipped,
+ required String? reporter,
+ required Map<String, String>? fileReporters,
+ required int? concurrency,
+ required Iterable<RuntimeSelection>? runtimes,
+ required Iterable<String>? chosenPresets,
+ required Map<String, RuntimeSettings>? overrideRuntimes}) =>
+ Configuration(
+ customHtmlTemplatePath: customHtmlTemplatePath,
+ pauseAfterLoad: pauseAfterLoad,
+ runSkipped: runSkipped,
+ reporter: reporter,
+ fileReporters: fileReporters,
+ concurrency: concurrency,
+ runtimes: runtimes,
+ chosenPresets: chosenPresets,
+ overrideRuntimes: overrideRuntimes,
+ help: null,
+ version: null,
+ debug: null,
+ color: null,
+ configurationPath: null,
+ dart2jsPath: null,
+ coverage: null,
+ pubServePort: null,
+ shardIndex: null,
+ totalShards: null,
+ paths: null,
+ foldTraceExcept: null,
+ foldTraceOnly: null,
+ filename: null,
+ presets: null,
+ defineRuntimes: null,
+ noRetry: null,
+ useDataIsolateStrategy: null,
+ testRandomizeOrderingSeed: null,
+ allowTestRandomization: null,
+ jsTrace: null,
+ dart2jsArgs: null,
+ precompiledPath: null,
+ patterns: null,
+ includeTags: null,
+ excludeTags: null,
+ tags: null,
+ onPlatform: null,
+ timeout: null,
+ verboseTrace: null,
+ chainStackTraces: null,
+ skip: null,
+ retry: null,
+ skipReason: null,
+ testOn: null,
+ addTags: null,
+ );
+
+ /// Configuration options limited to the local runner config.
+ factory Configuration.localRunner(
+ {required int? pubServePort,
+ required Iterable<Pattern>? patterns,
+ required Iterable<String>? paths,
+ required Glob? filename,
+ required BooleanSelector? includeTags,
+ required BooleanSelector? excludeTags,
+ required Map<String, CustomRuntime>? defineRuntimes}) =>
+ Configuration(
+ pubServePort: pubServePort,
+ patterns: patterns,
+ paths: paths,
+ filename: filename,
+ includeTags: includeTags,
+ excludeTags: excludeTags,
+ defineRuntimes: defineRuntimes,
+ help: null,
+ customHtmlTemplatePath: null,
+ version: null,
+ pauseAfterLoad: null,
+ debug: null,
+ color: null,
+ configurationPath: null,
+ dart2jsPath: null,
+ reporter: null,
+ fileReporters: null,
+ coverage: null,
+ concurrency: null,
+ shardIndex: null,
+ totalShards: null,
+ foldTraceExcept: null,
+ foldTraceOnly: null,
+ chosenPresets: null,
+ presets: null,
+ overrideRuntimes: null,
+ noRetry: null,
+ useDataIsolateStrategy: null,
+ testRandomizeOrderingSeed: null,
+ allowTestRandomization: null,
+ jsTrace: null,
+ runSkipped: null,
+ dart2jsArgs: null,
+ precompiledPath: null,
+ runtimes: null,
+ tags: null,
+ onPlatform: null,
+ timeout: null,
+ verboseTrace: null,
+ chainStackTraces: null,
+ skip: null,
+ retry: null,
+ skipReason: null,
+ testOn: null,
+ addTags: null);
+
+ /// A specialized constructor for configuring only `onPlatform`.
+ factory Configuration.onPlatform(
+ Map<PlatformSelector, SuiteConfiguration> onPlatform) =>
+ Configuration._unsafe(onPlatform: onPlatform);
+
+ factory Configuration.tags(Map<BooleanSelector, SuiteConfiguration> tags) =>
+ Configuration._unsafe(tags: tags);
+
static Map<String, Configuration>? _withChosenPresets(
Map<String, Configuration>? map, Set<String>? chosenPresets) {
if (map == null || chosenPresets == null) return map;
@@ -349,33 +689,33 @@
///
/// Unlike [new Configuration], this assumes [presets] is already resolved.
Configuration._(
- {bool? help,
- String? customHtmlTemplatePath,
- bool? version,
- bool? pauseAfterLoad,
- bool? debug,
- bool? color,
- String? configurationPath,
- String? dart2jsPath,
- String? reporter,
- Map<String, String>? fileReporters,
- this.coverage,
- int? pubServePort,
- int? concurrency,
- this.shardIndex,
- this.totalShards,
- Iterable<String>? paths,
- Iterable<String>? foldTraceExcept,
- Iterable<String>? foldTraceOnly,
- Glob? filename,
- Iterable<String>? chosenPresets,
- Map<String, Configuration>? presets,
- Map<String, RuntimeSettings>? overrideRuntimes,
- Map<String, CustomRuntime>? defineRuntimes,
- bool? noRetry,
- bool? useDataIsolateStrategy,
- this.testRandomizeOrderingSeed,
- SuiteConfiguration? suiteDefaults})
+ {required bool? help,
+ required String? customHtmlTemplatePath,
+ required bool? version,
+ required bool? pauseAfterLoad,
+ required bool? debug,
+ required bool? color,
+ required String? configurationPath,
+ required String? dart2jsPath,
+ required String? reporter,
+ required Map<String, String>? fileReporters,
+ required this.coverage,
+ required int? pubServePort,
+ required int? concurrency,
+ required this.shardIndex,
+ required this.totalShards,
+ required Iterable<String>? paths,
+ required Iterable<String>? foldTraceExcept,
+ required Iterable<String>? foldTraceOnly,
+ required Glob? filename,
+ required Iterable<String>? chosenPresets,
+ required Map<String, Configuration>? presets,
+ required Map<String, RuntimeSettings>? overrideRuntimes,
+ required Map<String, CustomRuntime>? defineRuntimes,
+ required bool? noRetry,
+ required bool? useDataIsolateStrategy,
+ required this.testRandomizeOrderingSeed,
+ required SuiteConfiguration? suiteDefaults})
: _help = help,
customHtmlTemplatePath = customHtmlTemplatePath,
_version = version,
@@ -402,7 +742,7 @@
_useDataIsolateStrategy = useDataIsolateStrategy,
suiteDefaults = pauseAfterLoad == true
? suiteDefaults?.change(timeout: Timeout.none) ??
- SuiteConfiguration(timeout: Timeout.none)
+ SuiteConfiguration.timeout(Timeout.none)
: suiteDefaults ?? SuiteConfiguration.empty {
if (_filename != null && _filename!.context.style != p.style) {
throw ArgumentError(
@@ -423,7 +763,35 @@
/// [SuiteConfiguration].
factory Configuration.fromSuiteConfiguration(
SuiteConfiguration suiteConfig) =>
- Configuration._(suiteDefaults: suiteConfig);
+ Configuration._(
+ suiteDefaults: suiteConfig,
+ help: null,
+ customHtmlTemplatePath: null,
+ version: null,
+ pauseAfterLoad: null,
+ debug: null,
+ color: null,
+ configurationPath: null,
+ dart2jsPath: null,
+ reporter: null,
+ fileReporters: null,
+ coverage: null,
+ pubServePort: null,
+ concurrency: null,
+ shardIndex: null,
+ totalShards: null,
+ paths: null,
+ foldTraceExcept: null,
+ foldTraceOnly: null,
+ filename: null,
+ chosenPresets: null,
+ presets: null,
+ overrideRuntimes: null,
+ defineRuntimes: null,
+ noRetry: null,
+ useDataIsolateStrategy: null,
+ testRandomizeOrderingSeed: null,
+ );
/// Returns an unmodifiable copy of [input].
///
@@ -509,6 +877,7 @@
other.customHtmlTemplatePath ?? customHtmlTemplatePath,
version: other._version ?? _version,
pauseAfterLoad: other._pauseAfterLoad ?? _pauseAfterLoad,
+ debug: other._debug ?? _debug,
color: other._color ?? _color,
configurationPath: other._configurationPath ?? _configurationPath,
dart2jsPath: other._dart2jsPath ?? _dart2jsPath,
@@ -556,11 +925,13 @@
String? customHtmlTemplatePath,
bool? version,
bool? pauseAfterLoad,
+ bool? debug,
bool? color,
String? configurationPath,
String? dart2jsPath,
String? reporter,
Map<String, String>? fileReporters,
+ String? coverage,
int? pubServePort,
int? concurrency,
int? shardIndex,
@@ -603,11 +974,13 @@
customHtmlTemplatePath ?? this.customHtmlTemplatePath,
version: version ?? _version,
pauseAfterLoad: pauseAfterLoad ?? _pauseAfterLoad,
+ debug: debug ?? _debug,
color: color ?? _color,
configurationPath: configurationPath ?? _configurationPath,
dart2jsPath: dart2jsPath ?? _dart2jsPath,
reporter: reporter ?? _reporter,
fileReporters: fileReporters ?? this.fileReporters,
+ coverage: coverage ?? this.coverage,
pubServePort: pubServePort ?? pubServeUrl?.port,
concurrency: concurrency ?? _concurrency,
shardIndex: shardIndex ?? this.shardIndex,
@@ -623,6 +996,8 @@
noRetry: noRetry ?? _noRetry,
useDataIsolateStrategy:
useDataIsolateStrategy ?? _useDataIsolateStrategy,
+ testRandomizeOrderingSeed:
+ testRandomizeOrderingSeed ?? this.testRandomizeOrderingSeed,
suiteDefaults: suiteDefaults.change(
jsTrace: jsTrace,
runSkipped: runSkipped,
diff --git a/pkgs/test_core/lib/src/runner/configuration/args.dart b/pkgs/test_core/lib/src/runner/configuration/args.dart
index e81c632..87c32ac 100644
--- a/pkgs/test_core/lib/src/runner/configuration/args.dart
+++ b/pkgs/test_core/lib/src/runner/configuration/args.dart
@@ -274,7 +274,23 @@
excludeTags: excludeTags,
noRetry: _ifParsed('no-retry'),
useDataIsolateStrategy: _ifParsed('use-data-isolate-strategy'),
- testRandomizeOrderingSeed: testRandomizeOrderingSeed);
+ testRandomizeOrderingSeed: testRandomizeOrderingSeed,
+ // Config that isn't supported on the command line
+ addTags: null,
+ allowTestRandomization: null,
+ customHtmlTemplatePath: null,
+ defineRuntimes: null,
+ filename: null,
+ foldTraceExcept: null,
+ foldTraceOnly: null,
+ onPlatform: null,
+ overrideRuntimes: null,
+ presets: null,
+ retry: null,
+ skip: null,
+ skipReason: null,
+ testOn: null,
+ tags: null);
}
/// Returns the parsed option for [name], or `null` if none was parsed.
diff --git a/pkgs/test_core/lib/src/runner/configuration/load.dart b/pkgs/test_core/lib/src/runner/configuration/load.dart
index 57084e1..888869d 100644
--- a/pkgs/test_core/lib/src/runner/configuration/load.dart
+++ b/pkgs/test_core/lib/src/runner/configuration/load.dart
@@ -147,7 +147,7 @@
key: (keyNode) => _parseIdentifierLike(keyNode, 'presets key'),
value: (valueNode) => _nestedConfig(valueNode, 'presets value'));
- var config = Configuration(
+ var config = Configuration.globalTest(
verboseTrace: verboseTrace,
jsTrace: jsTrace,
timeout: timeout,
@@ -156,7 +156,7 @@
foldTraceExcept: foldStackFrames['except'],
foldTraceOnly: foldStackFrames['only'])
.merge(_extractPresets<PlatformSelector>(
- onPlatform, (map) => Configuration(onPlatform: map)));
+ onPlatform, (map) => Configuration.onPlatform(map)));
var osConfig = onOS[currentOS];
return osConfig == null ? config : config.merge(osConfig);
@@ -174,6 +174,7 @@
_disallow('test_on');
_disallow('add_tags');
_disallow('tags');
+ _disallow('allow_test_randomization');
return Configuration.empty;
}
@@ -201,14 +202,17 @@
var retry = _getNonNegativeInt('retry');
- return Configuration(
+ var allowTestRandomization = _getBool('allow_test_randomization');
+
+ return Configuration.localTest(
skip: skip,
retry: retry,
skipReason: skipReason,
testOn: testOn,
- addTags: addTags)
+ addTags: addTags,
+ allowTestRandomization: allowTestRandomization)
.merge(_extractPresets<BooleanSelector>(
- tags, (map) => Configuration(tags: map)));
+ tags, (map) => Configuration.tags(map)));
}
/// Loads runner configuration that's allowed in the global configuration
@@ -272,7 +276,7 @@
var customHtmlTemplatePath = _getString('custom_html_template_path');
- return Configuration(
+ return Configuration.globalRunner(
pauseAfterLoad: pauseAfterLoad,
customHtmlTemplatePath: customHtmlTemplatePath,
runSkipped: runSkipped,
@@ -354,7 +358,7 @@
var defineRuntimes = _loadDefineRuntimes();
- return Configuration(
+ return Configuration.localRunner(
pubServePort: pubServePort,
patterns: patterns,
paths: paths,
diff --git a/pkgs/test_core/lib/src/runner/engine.dart b/pkgs/test_core/lib/src/runner/engine.dart
index 359374a..590e6a5 100644
--- a/pkgs/test_core/lib/src/runner/engine.dart
+++ b/pkgs/test_core/lib/src/runner/engine.dart
@@ -307,7 +307,8 @@
if (!_closed && setUpAllSucceeded) {
// shuffle the group entries
var entries = group.entries.toList();
- if (testRandomizeOrderingSeed != null &&
+ if (suiteConfig.allowTestRandomization &&
+ testRandomizeOrderingSeed != null &&
testRandomizeOrderingSeed! > 0) {
entries.shuffle(Random(testRandomizeOrderingSeed));
}
diff --git a/pkgs/test_core/lib/src/runner/suite.dart b/pkgs/test_core/lib/src/runner/suite.dart
index 7dd567b..520887f 100644
--- a/pkgs/test_core/lib/src/runner/suite.dart
+++ b/pkgs/test_core/lib/src/runner/suite.dart
@@ -23,7 +23,23 @@
///
/// Using this is slightly more efficient than manually constructing a new
/// configuration with no arguments.
- static final empty = SuiteConfiguration._();
+ static final empty = SuiteConfiguration._(
+ allowTestRandomization: null,
+ jsTrace: null,
+ runSkipped: null,
+ dart2jsArgs: null,
+ precompiledPath: null,
+ patterns: null,
+ runtimes: null,
+ includeTags: null,
+ excludeTags: null,
+ tags: null,
+ onPlatform: null,
+ metadata: null);
+
+ /// Whether test randomization should be allowed for this test.
+ bool get allowTestRandomization => _allowTestRandomization ?? true;
+ final bool? _allowTestRandomization;
/// Whether JavaScript stack traces should be left as-is or converted to
/// Dart-like traces.
@@ -125,27 +141,29 @@
}
factory SuiteConfiguration(
- {bool? jsTrace,
- bool? runSkipped,
- Iterable<String>? dart2jsArgs,
- String? precompiledPath,
- Iterable<Pattern>? patterns,
- Iterable<RuntimeSelection>? runtimes,
- BooleanSelector? includeTags,
- BooleanSelector? excludeTags,
- Map<BooleanSelector, SuiteConfiguration>? tags,
- Map<PlatformSelector, SuiteConfiguration>? onPlatform,
+ {required bool? allowTestRandomization,
+ required bool? jsTrace,
+ required bool? runSkipped,
+ required Iterable<String>? dart2jsArgs,
+ required String? precompiledPath,
+ required Iterable<Pattern>? patterns,
+ required Iterable<RuntimeSelection>? runtimes,
+ required BooleanSelector? includeTags,
+ required BooleanSelector? excludeTags,
+ required Map<BooleanSelector, SuiteConfiguration>? tags,
+ required Map<PlatformSelector, SuiteConfiguration>? onPlatform,
// Test-level configuration
- Timeout? timeout,
- bool? verboseTrace,
- bool? chainStackTraces,
- bool? skip,
- int? retry,
- String? skipReason,
- PlatformSelector? testOn,
- Iterable<String>? addTags}) {
+ required Timeout? timeout,
+ required bool? verboseTrace,
+ required bool? chainStackTraces,
+ required bool? skip,
+ required int? retry,
+ required String? skipReason,
+ required PlatformSelector? testOn,
+ required Iterable<String>? addTags}) {
var config = SuiteConfiguration._(
+ allowTestRandomization: allowTestRandomization,
jsTrace: jsTrace,
runSkipped: runSkipped,
dart2jsArgs: dart2jsArgs,
@@ -168,23 +186,84 @@
return config._resolveTags();
}
+ /// A constructor that doesn't require all of its options to be passed.
+ ///
+ /// This should only be used in situations where you really only want to
+ /// configure a specific restricted set of options.
+ factory SuiteConfiguration._unsafe(
+ {bool? allowTestRandomization,
+ bool? jsTrace,
+ bool? runSkipped,
+ Iterable<String>? dart2jsArgs,
+ String? precompiledPath,
+ Iterable<Pattern>? patterns,
+ Iterable<RuntimeSelection>? runtimes,
+ BooleanSelector? includeTags,
+ BooleanSelector? excludeTags,
+ Map<BooleanSelector, SuiteConfiguration>? tags,
+ Map<PlatformSelector, SuiteConfiguration>? onPlatform,
+
+ // Test-level configuration
+ Timeout? timeout,
+ bool? verboseTrace,
+ bool? chainStackTraces,
+ bool? skip,
+ int? retry,
+ String? skipReason,
+ PlatformSelector? testOn,
+ Iterable<String>? addTags}) =>
+ SuiteConfiguration(
+ allowTestRandomization: allowTestRandomization,
+ jsTrace: jsTrace,
+ runSkipped: runSkipped,
+ dart2jsArgs: dart2jsArgs,
+ precompiledPath: precompiledPath,
+ patterns: patterns,
+ runtimes: runtimes,
+ includeTags: includeTags,
+ excludeTags: excludeTags,
+ tags: tags,
+ onPlatform: onPlatform,
+ timeout: timeout,
+ verboseTrace: verboseTrace,
+ chainStackTraces: chainStackTraces,
+ skip: skip,
+ retry: retry,
+ skipReason: skipReason,
+ testOn: testOn,
+ addTags: addTags);
+
+ /// A specialized constructor for only configuring the runtimes.
+ factory SuiteConfiguration.runtimes(Iterable<RuntimeSelection> runtimes) =>
+ SuiteConfiguration._unsafe(runtimes: runtimes);
+
+ /// A specialized constructor for only configuring runSkipped.
+ factory SuiteConfiguration.runSkipped(bool runSkipped) =>
+ SuiteConfiguration._unsafe(runSkipped: runSkipped);
+
+ /// A specialized constructor for only configuring the timeout.
+ factory SuiteConfiguration.timeout(Timeout timeout) =>
+ SuiteConfiguration._unsafe(timeout: timeout);
+
/// Creates new SuiteConfiguration.
///
/// Unlike [new SuiteConfiguration], this assumes [tags] is already
/// resolved.
SuiteConfiguration._(
- {bool? jsTrace,
- bool? runSkipped,
- Iterable<String>? dart2jsArgs,
- this.precompiledPath,
- Iterable<Pattern>? patterns,
- Iterable<RuntimeSelection>? runtimes,
- BooleanSelector? includeTags,
- BooleanSelector? excludeTags,
- Map<BooleanSelector, SuiteConfiguration>? tags,
- Map<PlatformSelector, SuiteConfiguration>? onPlatform,
- Metadata? metadata})
- : _jsTrace = jsTrace,
+ {required bool? allowTestRandomization,
+ required bool? jsTrace,
+ required bool? runSkipped,
+ required Iterable<String>? dart2jsArgs,
+ required this.precompiledPath,
+ required Iterable<Pattern>? patterns,
+ required Iterable<RuntimeSelection>? runtimes,
+ required BooleanSelector? includeTags,
+ required BooleanSelector? excludeTags,
+ required Map<BooleanSelector, SuiteConfiguration>? tags,
+ required Map<PlatformSelector, SuiteConfiguration>? onPlatform,
+ required Metadata? metadata})
+ : _allowTestRandomization = allowTestRandomization,
+ _jsTrace = jsTrace,
_runSkipped = runSkipped,
dart2jsArgs = _list(dart2jsArgs) ?? const [],
patterns = UnmodifiableSetView(patterns?.toSet() ?? {}),
@@ -199,11 +278,21 @@
/// [metadata].
factory SuiteConfiguration.fromMetadata(Metadata metadata) =>
SuiteConfiguration._(
- tags: metadata.forTag.map((key, child) =>
- MapEntry(key, SuiteConfiguration.fromMetadata(child))),
- onPlatform: metadata.onPlatform.map((key, child) =>
- MapEntry(key, SuiteConfiguration.fromMetadata(child))),
- metadata: metadata.change(forTag: {}, onPlatform: {}));
+ tags: metadata.forTag.map((key, child) =>
+ MapEntry(key, SuiteConfiguration.fromMetadata(child))),
+ onPlatform: metadata.onPlatform.map((key, child) =>
+ MapEntry(key, SuiteConfiguration.fromMetadata(child))),
+ metadata: metadata.change(forTag: {}, onPlatform: {}),
+ allowTestRandomization: null,
+ jsTrace: null,
+ runSkipped: null,
+ dart2jsArgs: null,
+ precompiledPath: null,
+ patterns: null,
+ runtimes: null,
+ includeTags: null,
+ excludeTags: null,
+ );
/// Returns an unmodifiable copy of [input].
///
@@ -231,6 +320,8 @@
if (other == SuiteConfiguration.empty) return this;
var config = SuiteConfiguration._(
+ allowTestRandomization:
+ other._allowTestRandomization ?? _allowTestRandomization,
jsTrace: other._jsTrace ?? _jsTrace,
runSkipped: other._runSkipped ?? _runSkipped,
dart2jsArgs: dart2jsArgs.toList()..addAll(other.dart2jsArgs),
@@ -250,7 +341,8 @@
/// Note that unlike [merge], this has no merging behavior—the old value is
/// always replaced by the new one.
SuiteConfiguration change(
- {bool? jsTrace,
+ {bool? allowTestRandomization,
+ bool? jsTrace,
bool? runSkipped,
Iterable<String>? dart2jsArgs,
String? precompiledPath,
@@ -271,6 +363,8 @@
PlatformSelector? testOn,
Iterable<String>? addTags}) {
var config = SuiteConfiguration._(
+ allowTestRandomization:
+ allowTestRandomization ?? _allowTestRandomization,
jsTrace: jsTrace ?? _jsTrace,
runSkipped: runSkipped ?? _runSkipped,
dart2jsArgs: dart2jsArgs?.toList() ?? this.dart2jsArgs,
diff --git a/pkgs/test_core/pubspec.yaml b/pkgs/test_core/pubspec.yaml
index 24878e1..1b1b025 100644
--- a/pkgs/test_core/pubspec.yaml
+++ b/pkgs/test_core/pubspec.yaml
@@ -1,5 +1,5 @@
name: test_core
-version: 0.3.30-dev
+version: 0.4.0-dev
description: A basic library for writing tests and running them on the VM.
homepage: https://github.com/dart-lang/test/blob/master/pkgs/test_core