Skip to content

Commit 2c2ac49

Browse files
authored
Expand error message for async test declaration (#2251)
Add suggestions for fixing the declared tests. Differentiate the message based on whether the test `main` is running within the test runner, or as a standalone executable.
1 parent 14f9b3e commit 2c2ac49

File tree

2 files changed

+49
-20
lines changed

2 files changed

+49
-20
lines changed

pkgs/test_api/lib/src/backend/declarer.dart

Lines changed: 48 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,16 @@ class Declarer {
112112
/// `null`.
113113
final Set<String>? _seenNames;
114114

115+
/// Whether this declarer is running in a standalone test executation.
116+
///
117+
/// The full test runner awaits asynchronous `main` declarations, and so
118+
/// asynchronous work can be performed in between calls to `group`, and `test`
119+
/// etc. When running as a standalone file tests are run synchronously
120+
/// following the first call to declare a test, so all tests must be declared
121+
/// synchronously starting at that point. Track whether we are running in this
122+
/// more limited mode to customize the error message for tests declared late.
123+
final bool _isStandalone;
124+
115125
/// Creates a new declarer for the root group.
116126
///
117127
/// This is the implicit group that exists outside of any calls to `group()`.
@@ -139,16 +149,19 @@ class Declarer {
139149
String? fullTestName,
140150
// TODO: Change the default https://github.com/dart-lang/test/issues/1571
141151
bool allowDuplicateTestNames = true,
152+
bool isStandalone = false,
142153
}) : this._(
143-
null,
144-
null,
145-
metadata ?? Metadata(),
146-
platformVariables ?? const UnmodifiableSetView.empty(),
147-
collectTraces,
148-
null,
149-
noRetry,
150-
fullTestName,
151-
allowDuplicateTestNames ? null : <String>{});
154+
null,
155+
null,
156+
metadata ?? Metadata(),
157+
platformVariables ?? const UnmodifiableSetView.empty(),
158+
collectTraces,
159+
null,
160+
noRetry,
161+
fullTestName,
162+
allowDuplicateTestNames ? null : <String>{},
163+
isStandalone,
164+
);
152165

153166
Declarer._(
154167
this._parent,
@@ -160,6 +173,7 @@ class Declarer {
160173
this._noRetry,
161174
this._fullTestName,
162175
this._seenNames,
176+
this._isStandalone,
163177
);
164178

165179
/// Runs [body] with this declarer as [Declarer.current].
@@ -252,15 +266,17 @@ class Declarer {
252266
var trace = _collectTraces ? Trace.current(2) : null;
253267

254268
var declarer = Declarer._(
255-
this,
256-
fullTestPrefix,
257-
metadata,
258-
_platformVariables,
259-
_collectTraces,
260-
trace,
261-
_noRetry,
262-
_fullTestName,
263-
_seenNames);
269+
this,
270+
fullTestPrefix,
271+
metadata,
272+
_platformVariables,
273+
_collectTraces,
274+
trace,
275+
_noRetry,
276+
_fullTestName,
277+
_seenNames,
278+
_isStandalone,
279+
);
264280
declarer.declare(() {
265281
// Cast to dynamic to avoid the analyzer complaining about us using the
266282
// result of a void method.
@@ -340,7 +356,20 @@ class Declarer {
340356
/// [name] should be the name of the method being called.
341357
void _checkNotBuilt(String name) {
342358
if (!_built) return;
343-
throw StateError("Can't call $name() once tests have begun running.");
359+
final restrictionMessage = _isStandalone
360+
? 'When running a test as an executable directly '
361+
'(not as a suite by the test runner), '
362+
'tests must be declared in a synchronous block.\n'
363+
'If async work is required before any tests are run '
364+
'use a `setUpAll` callback.\n'
365+
'If async work cannot be avoided before declaring tests, '
366+
'all async events must be complete before declaring the first test.'
367+
: 'If async work is required before any tests are run '
368+
'use a `setUpAll` callback.\n'
369+
'If async work cannot be avoided before declaring tests it must '
370+
'all be awaited within the Future returned from `main`.';
371+
throw StateError("Can't call $name() once tests have begun running.\n"
372+
'$restrictionMessage');
344373
}
345374

346375
/// Run the set-up functions for this and any parent groups.

pkgs/test_core/lib/src/scaffolding.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ Declarer get _declarer {
4444
// In order to run the tests, we set up our own Declarer via
4545
// [_globalDeclarer], and pump the event queue as a best effort to wait for
4646
// all tests to be defined before starting them.
47-
_globalDeclarer = Declarer();
47+
_globalDeclarer = Declarer(isStandalone: true);
4848

4949
() async {
5050
await pumpEventQueue();

0 commit comments

Comments
 (0)