From 616937f6d3837e38a2a287653ddaf722de260702 Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Wed, 26 Jun 2024 12:31:33 -0700 Subject: [PATCH] Update lints, test JS & Wasm (#116) * Update lints, test JS & Wasm * more bumps * require dart 3.4 --- .github/workflows/test-package.yml | 5 ++++- CHANGELOG.md | 4 ++-- analysis_options.yaml | 1 - lib/error_code.dart | 30 ++++++++++++------------------ lib/src/client.dart | 26 ++++++++++++++------------ lib/src/exception.dart | 6 ++++-- lib/src/parameters.dart | 24 ++++++++++++------------ lib/src/peer.dart | 14 +++++++------- lib/src/server.dart | 21 ++++++++++----------- lib/src/utils.dart | 6 +++--- pubspec.yaml | 10 +++++----- test/client/client_test.dart | 14 ++++++-------- test/client/utils.dart | 4 ++-- test/peer_test.dart | 6 ++++-- test/server/batch_test.dart | 5 +++-- test/server/server_test.dart | 28 +++++++++++++++++++--------- test/server/stream_test.dart | 2 +- test/server/utils.dart | 2 +- 18 files changed, 109 insertions(+), 99 deletions(-) diff --git a/.github/workflows/test-package.yml b/.github/workflows/test-package.yml index 0978fe2..c8e65b6 100644 --- a/.github/workflows/test-package.yml +++ b/.github/workflows/test-package.yml @@ -47,7 +47,7 @@ jobs: matrix: # Add macos-latest and/or windows-latest if relevant for this package. os: [ubuntu-latest] - sdk: [2.19.0, dev] + sdk: [3.4, dev] steps: - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 - uses: dart-lang/setup-dart@f0ead981b4d9a35b37f30d36160575d60931ec30 @@ -59,3 +59,6 @@ jobs: - name: Run VM tests run: dart test --platform vm if: always() && steps.install.outcome == 'success' + - name: Run browser tests + run: dart test --platform chrome --compiler dart2wasm,dart2js + if: always() && steps.install.outcome == 'success' diff --git a/CHANGELOG.md b/CHANGELOG.md index 751a8f8..aec8201 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ -## 3.0.3-dev +## 3.0.3-wip -* Require Dart 2.19 +* Require Dart 3.4 ## 3.0.2 diff --git a/analysis_options.yaml b/analysis_options.yaml index 3339609..873cf41 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -12,4 +12,3 @@ linter: - avoid_unused_constructor_parameters - cancel_subscriptions - package_api_docs - - test_types_in_equals diff --git a/lib/error_code.dart b/lib/error_code.dart index 14e0543..5f90791 100644 --- a/lib/error_code.dart +++ b/lib/error_code.dart @@ -4,7 +4,9 @@ // ignore_for_file: constant_identifier_names -/// Error codes defined in the [JSON-RPC 2.0 specificiation][spec]. +import 'src/exception.dart'; + +/// Error codes defined in the [JSON-RPC 2.0 specification][spec]. /// /// These codes are generally used for protocol-level communication. Most of /// them shouldn't be used by the application. Those that should have @@ -38,20 +40,12 @@ const SERVER_ERROR = -32000; /// Returns a human-readable name for [errorCode] if it's one specified by the /// JSON-RPC 2.0 spec. /// -/// If [errorCode] isn't defined in the JSON-RPC 2.0 spec, returns null. -String? name(int errorCode) { - switch (errorCode) { - case PARSE_ERROR: - return 'parse error'; - case INVALID_REQUEST: - return 'invalid request'; - case METHOD_NOT_FOUND: - return 'method not found'; - case INVALID_PARAMS: - return 'invalid parameters'; - case INTERNAL_ERROR: - return 'internal error'; - default: - return null; - } -} +/// If [errorCode] isn't defined in the JSON-RPC 2.0 spec, returns `null`. +String? name(int errorCode) => switch (errorCode) { + PARSE_ERROR => 'parse error', + INVALID_REQUEST => 'invalid request', + METHOD_NOT_FOUND => 'method not found', + INVALID_PARAMS => 'invalid parameters', + INTERNAL_ERROR => 'internal error', + _ => null + }; diff --git a/lib/src/client.dart b/lib/src/client.dart index a3637dd..182f945 100644 --- a/lib/src/client.dart +++ b/lib/src/client.dart @@ -47,19 +47,19 @@ class Client { /// Creates a [Client] that communicates over [channel]. /// - /// Note that the client won't begin listening to [responses] until + /// Note that the client won't begin listening to [channel] until /// [Client.listen] is called. Client(StreamChannel channel) : this.withoutJson( jsonDocument.bind(channel).transformStream(ignoreFormatExceptions)); /// Creates a [Client] that communicates using decoded messages over - /// [channel]. + /// [_channel]. /// /// Unlike [Client.new], this doesn't read or write JSON strings. Instead, it /// reads and writes decoded maps or lists. /// - /// Note that the client won't begin listening to [responses] until + /// Note that the client won't begin listening to [_channel] until /// [Client.listen] is called. Client.withoutJson(this._channel) { done.whenComplete(() { @@ -80,7 +80,8 @@ class Client { /// /// [listen] may only be called once. Future listen() { - _channel.stream.listen(_handleResponse, onError: (error, stackTrace) { + _channel.stream.listen(_handleResponse, + onError: (Object error, StackTrace stackTrace) { _done.completeError(error, stackTrace); _channel.sink.close(); }, onDone: () { @@ -113,11 +114,11 @@ class Client { /// /// Throws a [StateError] if the client is closed while the request is in /// flight, or if the client is closed when this method is called. - Future sendRequest(String method, [Object? parameters]) { + Future sendRequest(String method, [Object? parameters]) { var id = _id++; _send(method, parameters, id); - var completer = Completer.sync(); + var completer = Completer.sync(); _pendingRequests[id] = _Request(method, completer, Chain.current()); return completer.future; } @@ -141,7 +142,7 @@ class Client { /// /// Sends a request to invoke [method] with [parameters]. If [id] is given, /// the request uses that id. - void _send(String method, parameters, [int? id]) { + void _send(String method, Object? parameters, [int? id]) { if (parameters is Iterable) parameters = parameters.toList(); if (parameters is! Map && parameters is! List && parameters != null) { throw ArgumentError('Only maps and lists may be used as JSON-RPC ' @@ -172,7 +173,7 @@ class Client { /// If this is called in the context of another [withBatch] call, it just /// invokes [callback] without creating another batch. This means that /// responses are batched until the first batch ends. - void withBatch(Function() callback) { + void withBatch(FutureOr Function() callback) { if (_batch != null) { callback(); return; @@ -186,7 +187,7 @@ class Client { } /// Handles a decoded response from the server. - void _handleResponse(response) { + void _handleResponse(Object? response) { if (response is List) { response.forEach(_handleSingleResponse); } else { @@ -196,8 +197,9 @@ class Client { /// Handles a decoded response from the server after batches have been /// resolved. - void _handleSingleResponse(response) { - if (!_isResponseValid(response)) return; + void _handleSingleResponse(Object? response_) { + if (!_isResponseValid(response_)) return; + final response = response_ as Map; var id = response['id']; id = (id is String) ? int.parse(id) : id; var request = _pendingRequests.remove(id)!; @@ -212,7 +214,7 @@ class Client { } /// Determines whether the server's response is valid per the spec. - bool _isResponseValid(response) { + bool _isResponseValid(Object? response) { if (response is! Map) return false; if (response['jsonrpc'] != '2.0') return false; var id = response['id']; diff --git a/lib/src/exception.dart b/lib/src/exception.dart index 3b9c0ec..906a053 100644 --- a/lib/src/exception.dart +++ b/lib/src/exception.dart @@ -46,8 +46,10 @@ class RpcException implements Exception { Map serialize(Object? request) { dynamic modifiedData; if (data is Map && !(data as Map).containsKey('request')) { - modifiedData = Map.from(data as Map); - modifiedData['request'] = request; + modifiedData = { + ...data as Map, + 'request': request, + }; } else if (data == null) { modifiedData = {'request': request}; } else { diff --git a/lib/src/parameters.dart b/lib/src/parameters.dart index f747b98..0a18882 100644 --- a/lib/src/parameters.dart +++ b/lib/src/parameters.dart @@ -109,8 +109,8 @@ class Parameter extends Parameters { // The parent parameters, used to construct [_path]. final Parameters _parent; - /// The key used to access [this], used to construct [_path]. - final dynamic _key; + /// The key used to access `this`, used to construct [_path]. + final Object _key; /// A human-readable representation of the path of getters used to get this. /// @@ -130,20 +130,22 @@ class Parameter extends Parameters { return _key is int ? (_key + 1).toString() : jsonEncode(_key); } - String quoteKey(key) { + String quoteKey(String key) { if (key.contains(RegExp(r'[^a-zA-Z0-9_-]'))) return jsonEncode(key); return key; } - String computePath(params) { + String computePath(Parameter params) { if (params._parent is! Parameter) { - return params._key is int ? '[${params._key}]' : quoteKey(params._key); + return params._key is int + ? '[${params._key}]' + : quoteKey(params._key as String); } var path = computePath(params._parent); return params._key is int ? '$path[${params._key}]' - : '$path.${quoteKey(params._key)}'; + : '$path.${quoteKey(params._key as String)}'; } return computePath(this); @@ -152,8 +154,7 @@ class Parameter extends Parameters { /// Whether this parameter exists. bool get exists => true; - Parameter._(String method, value, this._parent, this._key) - : super(method, value); + Parameter._(super.method, super.value, this._parent, this._key); /// Returns [value], or [defaultValue] if this parameter wasn't passed. dynamic valueOr(Object? defaultValue) => value; @@ -260,8 +261,7 @@ class Parameter extends Parameters { /// If [value] doesn't exist, this returns [defaultValue]. Uri asUriOr(Uri defaultValue) => asUri; - /// Get a parameter named [named] that matches [test], or the value of calling - /// [orElse]. + /// Get a parameter named [type] that matches [test]. /// /// [type] is used for the error message. It should begin with an indefinite /// article. @@ -271,7 +271,7 @@ class Parameter extends Parameters { '"$method" must be $type, but was ${jsonEncode(value)}.'); } - dynamic _getParsed(String description, Function(String) parse) { + dynamic _getParsed(String description, void Function(String) parse) { var string = asString; try { return parse(string); @@ -316,7 +316,7 @@ class _MissingParameter extends Parameter { @override bool get exists => false; - _MissingParameter(String method, Parameters parent, key) + _MissingParameter(String method, Parameters parent, Object key) : super._(method, null, parent, key); @override diff --git a/lib/src/peer.dart b/lib/src/peer.dart index 002af31..677b6e1 100644 --- a/lib/src/peer.dart +++ b/lib/src/peer.dart @@ -29,11 +29,11 @@ class Peer implements Client, Server { /// A stream controller that forwards incoming messages to [_server] if /// they're requests. - final _serverIncomingForwarder = StreamController(sync: true); + final _serverIncomingForwarder = StreamController(sync: true); /// A stream controller that forwards incoming messages to [_client] if /// they're responses. - final _clientIncomingForwarder = StreamController(sync: true); + final _clientIncomingForwarder = StreamController(sync: true); @override late final Future done = Future.wait([_client.done, _server.done]); @@ -66,12 +66,12 @@ class Peer implements Client, Server { onUnhandledError: onUnhandledError, strictProtocolChecks: strictProtocolChecks); - /// Creates a [Peer] that communicates using decoded messages over [channel]. + /// Creates a [Peer] that communicates using decoded messages over [_channel]. /// /// Unlike [Peer.new], this doesn't read or write JSON strings. Instead, it /// reads and writes decoded maps or lists. /// - /// Note that the peer won't begin listening to [channel] until + /// Note that the peer won't begin listening to [_channel] until /// [Peer.listen] is called. /// /// Unhandled exceptions in callbacks will be forwarded to [onUnhandledError]. @@ -102,7 +102,7 @@ class Peer implements Client, Server { _client.sendNotification(method, parameters); @override - void withBatch(Function() callback) => _client.withBatch(callback); + void withBatch(void Function() callback) => _client.withBatch(callback); // Server methods. @@ -111,7 +111,7 @@ class Peer implements Client, Server { _server.registerMethod(name, callback); @override - void registerFallback(Function(Parameters parameters) callback) => + void registerFallback(void Function(Parameters parameters) callback) => _server.registerFallback(callback); // Shared methods. @@ -141,7 +141,7 @@ class Peer implements Client, Server { // server since it knows how to send error responses. _serverIncomingForwarder.add(message); } - }, onError: (error, stackTrace) { + }, onError: (Object error, StackTrace stackTrace) { _serverIncomingForwarder.addError(error, stackTrace); }, onDone: close); return done; diff --git a/lib/src/server.dart b/lib/src/server.dart index 14ef02e..2c58b79 100644 --- a/lib/src/server.dart +++ b/lib/src/server.dart @@ -21,8 +21,7 @@ typedef ErrorCallback = void Function(dynamic error, dynamic stackTrace); /// /// A server exposes methods that are called by requests, to which it provides /// responses. Methods can be registered using [registerMethod] and -/// [registerFallback]. Requests can be handled using [handleRequest] and -/// [parseRequest]. +/// [registerFallback]. /// /// Note that since requests can arrive asynchronously and methods can run /// asynchronously, it's possible for multiple methods to be invoked at the same @@ -72,7 +71,7 @@ class Server { /// Creates a [Server] that communicates over [channel]. /// - /// Note that the server won't begin listening to [requests] until + /// Note that the server won't begin listening to [channel] until /// [Server.listen] is called. /// /// Unhandled exceptions in callbacks will be forwarded to [onUnhandledError]. @@ -89,12 +88,12 @@ class Server { strictProtocolChecks: strictProtocolChecks); /// Creates a [Server] that communicates using decoded messages over - /// [channel]. + /// [_channel]. /// /// Unlike [Server.new], this doesn't read or write JSON strings. Instead, it /// reads and writes decoded maps or lists. /// - /// Note that the server won't begin listening to [requests] until + /// Note that the server won't begin listening to [_channel] until /// [Server.listen] is called. /// /// Unhandled exceptions in callbacks will be forwarded to [onUnhandledError]. @@ -113,7 +112,8 @@ class Server { /// /// [listen] may only be called once. Future listen() { - _channel.stream.listen(_handleRequest, onError: (error, stackTrace) { + _channel.stream.listen(_handleRequest, + onError: (Object error, StackTrace stackTrace) { _done.completeError(error, stackTrace); _channel.sink.close(); }, onDone: () { @@ -160,7 +160,7 @@ class Server { /// completes to a JSON-serializable object. Any errors in [callback] will be /// reported to the client as JSON-RPC 2.0 errors. [callback] may send custom /// errors by throwing an [RpcException]. - void registerFallback(Function(Parameters parameters) callback) { + void registerFallback(void Function(Parameters parameters) callback) { _fallbacks.add(callback); } @@ -169,9 +169,8 @@ class Server { /// [request] is expected to be a JSON-serializable object representing a /// request sent by a client. This calls the appropriate method or methods for /// handling that request and returns a JSON-serializable response, or `null` - /// if no response should be sent. [callback] may send custom - /// errors by throwing an [RpcException]. - Future _handleRequest(request) async { + /// if no response should be sent. + Future _handleRequest(Object? request) async { dynamic response; if (request is List) { if (request.isEmpty) { @@ -241,7 +240,7 @@ class Server { } /// Validates that [request] matches the JSON-RPC spec. - void _validateRequest(request) { + void _validateRequest(Object? request) { if (request is! Map) { throw RpcException( error_code.INVALID_REQUEST, diff --git a/lib/src/utils.dart b/lib/src/utils.dart index c7cd10f..28bbf21 100644 --- a/lib/src/utils.dart +++ b/lib/src/utils.dart @@ -9,7 +9,7 @@ import 'package:stream_channel/stream_channel.dart'; import '../error_code.dart' as error_code; import 'exception.dart'; -typedef ZeroArgumentFunction = Function(); +typedef ZeroArgumentFunction = FutureOr Function(); /// A regular expression to match the exception prefix that some exceptions' /// [Object.toString] values contain. @@ -18,7 +18,7 @@ final _exceptionPrefix = RegExp(r'^([A-Z][a-zA-Z]*)?(Exception|Error): '); /// Get a string description of an exception. /// /// Many exceptions include the exception class name at the beginning of their -/// [toString], so we remove that if it exists. +/// `toString`, so we remove that if it exists. String getErrorMessage(Object error) => error.toString().replaceFirst(_exceptionPrefix, ''); @@ -27,7 +27,7 @@ String getErrorMessage(Object error) => /// /// This is synchronicity-agnostic relative to [body]. If [body] returns a /// [Future], this wil run asynchronously; otherwise it will run synchronously. -void tryFinally(Function() body, Function() whenComplete) { +void tryFinally(dynamic Function() body, void Function() whenComplete) { dynamic result; try { result = body(); diff --git a/pubspec.yaml b/pubspec.yaml index 53f5885..ae3ee94 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,17 +1,17 @@ name: json_rpc_2 -version: 3.0.3-dev +version: 3.0.3-wip description: >- Utilities to write a client or server using the JSON-RPC 2.0 spec. repository: https://github.com/dart-lang/json_rpc_2 environment: - sdk: ">=2.19.0 <3.0.0" + sdk: ^3.4.0 dependencies: stack_trace: ^1.10.0 stream_channel: ^2.1.0 dev_dependencies: - dart_flutter_team_lints: ^1.0.0 - test: ^1.16.0 - web_socket_channel: ^2.0.0 + dart_flutter_team_lints: ^3.0.0 + test: ^1.25.5 + web_socket_channel: ^3.0.0 diff --git a/test/client/client_test.dart b/test/client/client_test.dart index df9c033..1a4f65d 100644 --- a/test/client/client_test.dart +++ b/test/client/client_test.dart @@ -89,7 +89,7 @@ void main() { test('sends a synchronous batch of requests', () { controller.expectRequest((request) { - expect(request, TypeMatcher()); + expect(request, isA()); expect(request, hasLength(3)); expect(request[0], equals({'jsonrpc': '2.0', 'method': 'foo'})); expect( @@ -121,7 +121,7 @@ void main() { test('sends an asynchronous batch of requests', () { controller.expectRequest((request) { - expect(request, TypeMatcher()); + expect(request, isA()); expect(request, hasLength(3)); expect(request[0], equals({'jsonrpc': '2.0', 'method': 'foo'})); expect( @@ -143,14 +143,12 @@ void main() { }); controller.client.withBatch(() { - return Future.value().then((_) { + return Future.value().then((_) { controller.client.sendNotification('foo'); - return Future.value(); - }).then((_) { + }).then((_) { expect(controller.client.sendRequest('bar', {'param': 'value'}), completion(equals('bar response'))); - return Future.value(); - }).then((_) { + }).then((_) { expect(controller.client.sendRequest('baz'), completion(equals('baz response'))); }); @@ -177,7 +175,7 @@ void main() { expect( controller.client.sendRequest('foo', {'param': 'value'}), - throwsA(TypeMatcher() + throwsA(isA() .having((e) => e.code, 'code', error_code.SERVER_ERROR) .having((e) => e.message, 'message', 'you are bad at requests') .having((e) => e.data, 'data', 'some junk'))); diff --git a/test/client/utils.dart b/test/client/utils.dart index acbfbe2..38e187f 100644 --- a/test/client/utils.dart +++ b/test/client/utils.dart @@ -32,7 +32,7 @@ class ClientController { /// returns a String, that's sent as the response directly. If it returns /// null, no response is sent. Otherwise, the return value is encoded and sent /// as the response. - void expectRequest(Function(dynamic) callback) { + void expectRequest(FutureOr Function(dynamic) callback) { expect( _requestController.stream.first.then((request) { return callback(jsonDecode(request)); @@ -49,7 +49,7 @@ class ClientController { sendJsonResponse(jsonEncode(response)); } - /// Sends [response], a JSON-encoded response, to [client]. + /// Sends [request], a JSON-encoded response, to [client]. void sendJsonResponse(String request) { _responseController.add(request); } diff --git a/test/peer_test.dart b/test/peer_test.dart index 4b4c44a..0df6056 100644 --- a/test/peer_test.dart +++ b/test/peer_test.dart @@ -2,6 +2,8 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +// ignore_for_file: inference_failure_on_instance_creation + import 'dart:async'; import 'dart:convert'; @@ -86,10 +88,10 @@ void main() { }); test('requests terminates when the channel is closed', () async { - var incomingController = StreamController(); + var incomingController = StreamController(); var channel = StreamChannel.withGuarantees( incomingController.stream, - StreamController(), + StreamController(), ); var peer = json_rpc.Peer.withoutJson(channel); unawaited(peer.listen()); diff --git a/test/server/batch_test.dart b/test/server/batch_test.dart index b8b8fea..af883c4 100644 --- a/test/server/batch_test.dart +++ b/test/server/batch_test.dart @@ -3,6 +3,7 @@ // BSD-style license that can be found in the LICENSE file. import 'package:json_rpc_2/error_code.dart' as error_code; +import 'package:json_rpc_2/src/parameters.dart' show Parameters; import 'package:test/test.dart'; import 'utils.dart'; @@ -14,8 +15,8 @@ void main() { controller = ServerController(); controller.server ..registerMethod('foo', () => 'foo') - ..registerMethod('id', (params) => params.value) - ..registerMethod('arg', (params) => params['arg'].value); + ..registerMethod('id', (Parameters params) => params.value) + ..registerMethod('arg', (Parameters params) => params['arg'].value); }); test('handles a batch of requests', () { diff --git a/test/server/server_test.dart b/test/server/server_test.dart index 10f2678..b3166ce 100644 --- a/test/server/server_test.dart +++ b/test/server/server_test.dart @@ -16,7 +16,7 @@ void main() { setUp(() => controller = ServerController()); test('calls a registered method with the given name', () { - controller.server.registerMethod('foo', (params) { + controller.server.registerMethod('foo', (json_rpc.Parameters params) { return {'params': params.value}; }); @@ -59,14 +59,19 @@ void main() { expectErrorResponse( controller, - {'jsonrpc': '2.0', 'method': 'foo', 'params': {}, 'id': 1234}, + { + 'jsonrpc': '2.0', + 'method': 'foo', + 'params': {}, + 'id': 1234 + }, error_code.INVALID_PARAMS, 'No parameters are allowed for method "foo".'); }); test('an unexpected error in a method is captured', () { controller.server - .registerMethod('foo', () => throw FormatException('bad format')); + .registerMethod('foo', () => throw const FormatException('bad format')); expect( controller @@ -80,7 +85,7 @@ void main() { 'data': { 'request': {'jsonrpc': '2.0', 'method': 'foo', 'id': 1234}, 'full': 'FormatException: bad format', - 'stack': TypeMatcher() + 'stack': isA() } } })); @@ -90,8 +95,8 @@ void main() { controller.server.registerMethod('foo', (args) => 'result'); expect( - controller - .handleRequest({'jsonrpc': '2.0', 'method': 'foo', 'params': {}}), + controller.handleRequest( + {'jsonrpc': '2.0', 'method': 'foo', 'params': {}}), doesNotComplete); }); @@ -102,7 +107,12 @@ void main() { expectErrorResponse( controller, - {'jsonrpc': '2.0', 'method': 'foo', 'params': {}, 'id': 1234}, + { + 'jsonrpc': '2.0', + 'method': 'foo', + 'params': {}, + 'id': 1234 + }, 5, 'Error message.', data: 'data value'); @@ -164,7 +174,7 @@ void main() { test('an unexpected error in a fallback is captured', () { controller.server - .registerFallback((_) => throw FormatException('bad format')); + .registerFallback((_) => throw const FormatException('bad format')); expect( controller @@ -178,7 +188,7 @@ void main() { 'data': { 'request': {'jsonrpc': '2.0', 'method': 'foo', 'id': 1234}, 'full': 'FormatException: bad format', - 'stack': TypeMatcher() + 'stack': isA() } } })); diff --git a/test/server/stream_test.dart b/test/server/stream_test.dart index 2f95150..832e13c 100644 --- a/test/server/stream_test.dart +++ b/test/server/stream_test.dart @@ -23,7 +23,7 @@ void main() { test('.withoutJson supports decoded stream and sink', () { server.listen(); - server.registerMethod('foo', (params) { + server.registerMethod('foo', (json_rpc.Parameters params) { return {'params': params.value}; }); diff --git a/test/server/utils.dart b/test/server/utils.dart index 9fe6eed..c94628e 100644 --- a/test/server/utils.dart +++ b/test/server/utils.dart @@ -65,6 +65,6 @@ void expectErrorResponse( /// Returns a matcher that matches a [json_rpc.RpcException] with an /// `invalid_params` error code. Matcher throwsInvalidParams(String message) => - throwsA(TypeMatcher() + throwsA(isA() .having((e) => e.code, 'code', error_code.INVALID_PARAMS) .having((e) => e.message, 'message', message));