Skip to content

Commit acebba4

Browse files
committed
test [nfc]: Introduce "finish" helper for async checks
This brings the file test/api/core_test.dart up to being clean against the `unawaited_futures` lint rule, toward #731. It does so with a smaller diff, and simpler resulting code, than by adding `await` on each of the futures. For comparison: #934 (comment)
1 parent 061821c commit acebba4

File tree

2 files changed

+38
-19
lines changed

2 files changed

+38
-19
lines changed

test/api/core_test.dart

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import 'package:zulip/model/localizations.dart';
1111

1212
import '../model/binding.dart';
1313
import '../stdlib_checks.dart';
14+
import '../test_async.dart';
1415
import 'exception_checks.dart';
1516
import 'fake_api.dart';
1617
import '../example_data.dart' as eg;
@@ -19,8 +20,8 @@ void main() {
1920
TestZulipBinding.ensureInitialized();
2021

2122
test('ApiConnection.get', () async {
22-
Future<void> checkRequest(Map<String, dynamic>? params, String expectedRelativeUrl) {
23-
return FakeApiConnection.with_(account: eg.selfAccount, (connection) async {
23+
void checkRequest(Map<String, dynamic>? params, String expectedRelativeUrl) {
24+
finish(FakeApiConnection.with_(account: eg.selfAccount, (connection) async {
2425
connection.prepare(json: {});
2526
await connection.get(kExampleRouteName, (json) => json, 'example/route', params);
2627
check(connection.lastRequest!).isA<http.Request>()
@@ -31,7 +32,7 @@ void main() {
3132
...kFallbackUserAgentHeader,
3233
})
3334
..body.equals('');
34-
});
35+
}));
3536
}
3637

3738
checkRequest(null, '/api/v1/example/route');
@@ -50,8 +51,8 @@ void main() {
5051
});
5152

5253
test('ApiConnection.post', () async {
53-
Future<void> checkRequest(Map<String, dynamic>? params, String expectedBody, {bool expectContentType = true}) {
54-
return FakeApiConnection.with_(account: eg.selfAccount, (connection) async {
54+
void checkRequest(Map<String, dynamic>? params, String expectedBody, {bool expectContentType = true}) {
55+
finish(FakeApiConnection.with_(account: eg.selfAccount, (connection) async {
5556
connection.prepare(json: {});
5657
await connection.post(kExampleRouteName, (json) => json, 'example/route', params);
5758
check(connection.lastRequest!).isA<http.Request>()
@@ -64,7 +65,7 @@ void main() {
6465
'content-type': 'application/x-www-form-urlencoded; charset=utf-8',
6566
})
6667
..body.equals(expectedBody);
67-
});
68+
}));
6869
}
6970

7071
checkRequest(null, '', expectContentType: false);
@@ -81,9 +82,9 @@ void main() {
8182
});
8283

8384
test('ApiConnection.postFileFromStream', () async {
84-
Future<void> checkRequest(List<List<int>> content, int length,
85+
void checkRequest(List<List<int>> content, int length,
8586
{String? filename, String? contentType, bool isContentTypeInvalid = false}) {
86-
return FakeApiConnection.with_(account: eg.selfAccount, (connection) async {
87+
finish(FakeApiConnection.with_(account: eg.selfAccount, (connection) async {
8788
connection.prepare(json: {});
8889
await connection.postFileFromStream(
8990
kExampleRouteName, (json) => json, 'example/route',
@@ -108,7 +109,7 @@ void main() {
108109
..has<Future<List<int>>>((f) => f.finalize().toBytes(), 'contents')
109110
.completes((it) => it.deepEquals(content.expand((l) => l)))
110111
);
111-
});
112+
}));
112113
}
113114

114115
checkRequest([], 0, filename: null);
@@ -126,8 +127,8 @@ void main() {
126127
});
127128

128129
test('ApiConnection.delete', () async {
129-
Future<void> checkRequest(Map<String, dynamic>? params, String expectedBody, {bool expectContentType = true}) {
130-
return FakeApiConnection.with_(account: eg.selfAccount, (connection) async {
130+
void checkRequest(Map<String, dynamic>? params, String expectedBody, {bool expectContentType = true}) {
131+
finish(FakeApiConnection.with_(account: eg.selfAccount, (connection) async {
131132
connection.prepare(json: {});
132133
await connection.delete(kExampleRouteName, (json) => json, 'example/route', params);
133134
check(connection.lastRequest!).isA<http.Request>()
@@ -140,7 +141,7 @@ void main() {
140141
'content-type': 'application/x-www-form-urlencoded; charset=utf-8',
141142
})
142143
..body.equals(expectedBody);
143-
});
144+
}));
144145
}
145146

146147
checkRequest(null, '', expectContentType: false);
@@ -166,13 +167,13 @@ void main() {
166167
});
167168

168169
test('API network errors', () async {
169-
Future<void> checkRequest<T extends Object>(
170+
void checkRequest<T extends Object>(
170171
T exception, Condition<NetworkException> condition) {
171-
return check(tryRequest(exception: exception))
172+
finish(check(tryRequest(exception: exception))
172173
.throws<NetworkException>((it) => it
173174
..routeName.equals(kExampleRouteName)
174175
..cause.equals(exception)
175-
..which(condition));
176+
..which(condition)));
176177
}
177178

178179
final zulipLocalizations = GlobalLocalizations.zulipLocalizations;
@@ -219,14 +220,14 @@ void main() {
219220
});
220221

221222
test('API 4xx errors, malformed', () async {
222-
Future<void> checkMalformed({
223-
int httpStatus = 400, Map<String, dynamic>? json, String? body}) async {
223+
void checkMalformed({
224+
int httpStatus = 400, Map<String, dynamic>? json, String? body}) {
224225
assert((json == null) != (body == null));
225-
await check(tryRequest(httpStatus: httpStatus, json: json, body: body))
226+
finish(check(tryRequest(httpStatus: httpStatus, json: json, body: body))
226227
.throws<MalformedServerResponseException>((it) => it
227228
..routeName.equals(kExampleRouteName)
228229
..httpStatus.equals(httpStatus)
229-
..data.deepEquals(json));
230+
..data.deepEquals(json)));
230231
}
231232

232233
await check(

test/test_async.dart

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import 'package:test_api/hooks.dart';
2+
3+
/// Ensure the test runner will wait for the given future to complete
4+
/// before considering the current test complete.
5+
///
6+
/// Consider using this function, instead of `await`, when a test invokes
7+
/// a check which is asynchronous and has no interaction with other tasks
8+
/// the test will do later.
9+
///
10+
/// Use `await`, instead of this function, when it matters what order the
11+
/// rest of the test's logic runs in relative to the asynchronous work
12+
/// represented by the given future. In particular, when calling a function
13+
/// that performs setup for later logic in the test, the returned future
14+
/// should always be awaited.
15+
void finish(Future<void> future) {
16+
final outstandingWork = TestHandle.current.markPending();
17+
future.whenComplete(outstandingWork.complete);
18+
}

0 commit comments

Comments
 (0)