Dart 2 fixes
This commit is contained in:
parent
06b85a8bb9
commit
046c1f7807
10 changed files with 296 additions and 110 deletions
|
@ -2,6 +2,7 @@
|
||||||
<module type="WEB_MODULE" version="4">
|
<module type="WEB_MODULE" version="4">
|
||||||
<component name="NewModuleRootManager">
|
<component name="NewModuleRootManager">
|
||||||
<content url="file://$MODULE_DIR$">
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/.dart_tool" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/.pub" />
|
<excludeFolder url="file://$MODULE_DIR$/.pub" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
|
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build" />
|
<excludeFolder url="file://$MODULE_DIR$/build" />
|
||||||
|
|
|
@ -1 +1,4 @@
|
||||||
language: dart
|
language: dart
|
||||||
|
dart:
|
||||||
|
- dev
|
||||||
|
- stable
|
3
CHANGELOG.md
Normal file
3
CHANGELOG.md
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# 1.1.0+1
|
||||||
|
* Dart 2/strong mode fixes.
|
||||||
|
* Pass a `useZone` flag to `AngelHttp` through `TestServer`.
|
3
analysis_options.yaml
Normal file
3
analysis_options.yaml
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
analyzer:
|
||||||
|
strong-mode:
|
||||||
|
implicit-casts: false
|
142
example/main.dart
Normal file
142
example/main.dart
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
import 'dart:io';
|
||||||
|
import 'package:angel_framework/angel_framework.dart';
|
||||||
|
import 'package:angel_test/angel_test.dart';
|
||||||
|
import 'package:angel_validate/angel_validate.dart';
|
||||||
|
import 'package:angel_websocket/server.dart';
|
||||||
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
|
main() {
|
||||||
|
Angel app;
|
||||||
|
TestClient client;
|
||||||
|
|
||||||
|
setUp(() async {
|
||||||
|
app = new Angel()
|
||||||
|
..get('/hello', 'Hello')
|
||||||
|
..get(
|
||||||
|
'/error',
|
||||||
|
() => throw new AngelHttpException.forbidden(message: 'Test')
|
||||||
|
..errors.addAll(['foo', 'bar']))
|
||||||
|
..get('/body', (ResponseContext res) {
|
||||||
|
res
|
||||||
|
..write('OK')
|
||||||
|
..end();
|
||||||
|
})
|
||||||
|
..get(
|
||||||
|
'/valid',
|
||||||
|
() => {
|
||||||
|
'michael': 'jackson',
|
||||||
|
'billie': {'jean': 'hee-hee', 'is_my_lover': false}
|
||||||
|
})
|
||||||
|
..post('/hello', (req, res) async {
|
||||||
|
return {'bar': req.body['foo']};
|
||||||
|
})
|
||||||
|
..get('/gzip', (req, res) async {
|
||||||
|
res
|
||||||
|
..headers['content-encoding'] = 'gzip'
|
||||||
|
..write(gzip.encode('Poop'.codeUnits))
|
||||||
|
..end();
|
||||||
|
})
|
||||||
|
..use(
|
||||||
|
'/foo',
|
||||||
|
new AnonymousService(
|
||||||
|
index: ([params]) async => [
|
||||||
|
{'michael': 'jackson'}
|
||||||
|
],
|
||||||
|
create: (data, [params]) async => {'foo': 'bar'}));
|
||||||
|
|
||||||
|
var ws = new AngelWebSocket(app);
|
||||||
|
await app.configure(ws.configureServer);
|
||||||
|
app.all('/ws', ws.handleRequest);
|
||||||
|
|
||||||
|
app.errorHandler = (e, req, res) => e.toJson();
|
||||||
|
|
||||||
|
client = await connectTo(app);
|
||||||
|
});
|
||||||
|
|
||||||
|
tearDown(() async {
|
||||||
|
await client.close();
|
||||||
|
app = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
group('matchers', () {
|
||||||
|
group('isJson+hasStatus', () {
|
||||||
|
test('get', () async {
|
||||||
|
final response = await client.get('/hello');
|
||||||
|
expect(response, isJson('Hello'));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('post', () async {
|
||||||
|
final response = await client.post('/hello', body: {'foo': 'baz'});
|
||||||
|
expect(response, allOf(hasStatus(200), isJson({'bar': 'baz'})));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('isAngelHttpException', () async {
|
||||||
|
var res = await client.get('/error');
|
||||||
|
print(res.body);
|
||||||
|
expect(res, isAngelHttpException());
|
||||||
|
expect(
|
||||||
|
res,
|
||||||
|
isAngelHttpException(
|
||||||
|
statusCode: 403, message: 'Test', errors: ['foo', 'bar']));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('hasBody', () async {
|
||||||
|
var res = await client.get('/body');
|
||||||
|
expect(res, hasBody());
|
||||||
|
expect(res, hasBody('OK'));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('hasHeader', () async {
|
||||||
|
var res = await client.get('/hello');
|
||||||
|
expect(res, hasHeader('server'));
|
||||||
|
expect(res, hasHeader('server', 'angel'));
|
||||||
|
expect(res, hasHeader('server', ['angel']));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('hasValidBody+hasContentType', () async {
|
||||||
|
var res = await client.get('/valid');
|
||||||
|
expect(res, hasContentType('application/json'));
|
||||||
|
expect(res, hasContentType(new ContentType('application', 'json')));
|
||||||
|
expect(
|
||||||
|
res,
|
||||||
|
hasValidBody(new Validator({
|
||||||
|
'michael*': [isString, isNotEmpty, equals('jackson')],
|
||||||
|
'billie': new Validator({
|
||||||
|
'jean': [isString, isNotEmpty],
|
||||||
|
'is_my_lover': [isBool, isFalse]
|
||||||
|
})
|
||||||
|
})));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('gzip decode', () async {
|
||||||
|
var res = await client.get('/gzip');
|
||||||
|
expect(res, hasHeader('content-encoding', 'gzip'));
|
||||||
|
expect(res, hasBody('Poop'));
|
||||||
|
});
|
||||||
|
|
||||||
|
group('service', () {
|
||||||
|
test('index', () async {
|
||||||
|
var foo = client.service('foo');
|
||||||
|
var result = await foo.index();
|
||||||
|
expect(result, [
|
||||||
|
{'michael': 'jackson'}
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('index', () async {
|
||||||
|
var foo = client.service('foo');
|
||||||
|
var result = await foo.create({});
|
||||||
|
expect(result, {'foo': 'bar'});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('websocket', () async {
|
||||||
|
var ws = await client.websocket();
|
||||||
|
var foo = ws.service('foo');
|
||||||
|
foo.create({});
|
||||||
|
var result = await foo.onCreated.first;
|
||||||
|
expect(result.data, equals({'foo': 'bar'}));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
|
@ -1,2 +1,2 @@
|
||||||
export 'src/client.dart';
|
export 'src/client.dart';
|
||||||
export 'src/matchers.dart';
|
export 'src/matchers.dart';
|
||||||
|
|
|
@ -1,33 +1,37 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:convert';
|
import 'dart:convert' show Encoding;
|
||||||
import 'dart:io';
|
import 'dart:io' show ContentType, Cookie, HttpSession, HttpServer, WebSocket;
|
||||||
|
import 'package:dart2_constant/convert.dart';
|
||||||
|
import 'package:dart2_constant/io.dart' hide WebSocket;
|
||||||
import 'package:angel_client/base_angel_client.dart' as client;
|
import 'package:angel_client/base_angel_client.dart' as client;
|
||||||
import 'package:angel_client/io.dart' as client;
|
import 'package:angel_client/io.dart' as client;
|
||||||
import 'package:angel_framework/angel_framework.dart';
|
import 'package:angel_framework/angel_framework.dart';
|
||||||
import 'package:angel_websocket/io.dart' as client;
|
import 'package:angel_websocket/io.dart' as client;
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http hide StreamedResponse;
|
||||||
|
import 'package:http/src/streamed_response.dart';
|
||||||
import 'package:mock_request/mock_request.dart';
|
import 'package:mock_request/mock_request.dart';
|
||||||
import 'package:web_socket_channel/web_socket_channel.dart';
|
import 'package:web_socket_channel/web_socket_channel.dart';
|
||||||
import 'package:web_socket_channel/io.dart';
|
import 'package:web_socket_channel/io.dart';
|
||||||
import 'package:uuid/uuid.dart';
|
//import 'package:uuid/uuid.dart';
|
||||||
|
|
||||||
final RegExp _straySlashes = new RegExp(r"(^/)|(/+$)");
|
final RegExp _straySlashes = new RegExp(r"(^/)|(/+$)");
|
||||||
const Map<String, String> _readHeaders = const {'Accept': 'application/json'};
|
/*const Map<String, String> _readHeaders = const {'Accept': 'application/json'};
|
||||||
const Map<String, String> _writeHeaders = const {
|
const Map<String, String> _writeHeaders = const {
|
||||||
'Accept': 'application/json',
|
'Accept': 'application/json',
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
};
|
};
|
||||||
final Uuid _uuid = new Uuid();
|
final Uuid _uuid = new Uuid();*/
|
||||||
|
|
||||||
/// Shorthand for bootstrapping a [TestClient].
|
/// Shorthand for bootstrapping a [TestClient].
|
||||||
Future<TestClient> connectTo(Angel app,
|
Future<TestClient> connectTo(Angel app,
|
||||||
{Map initialSession, bool autoDecodeGzip: true}) async {
|
{Map initialSession,
|
||||||
if (!app.isProduction)
|
bool autoDecodeGzip: true,
|
||||||
app.configuration.putIfAbsent('testMode', () => true);
|
bool useZone: false}) async {
|
||||||
|
if (!app.isProduction) app.configuration.putIfAbsent('testMode', () => true);
|
||||||
|
|
||||||
for (var plugin in app.startupHooks)
|
for (var plugin in app.startupHooks) await plugin(app);
|
||||||
await plugin(app);
|
return new TestClient(app,
|
||||||
return new TestClient(app, autoDecodeGzip: autoDecodeGzip != false)
|
autoDecodeGzip: autoDecodeGzip != false, useZone: useZone)
|
||||||
..session.addAll(initialSession ?? {});
|
..session.addAll(initialSession ?? {});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,7 +54,12 @@ class TestClient extends client.BaseAngelClient {
|
||||||
@override
|
@override
|
||||||
String authToken;
|
String authToken;
|
||||||
|
|
||||||
TestClient(this.server, {this.autoDecodeGzip: true}) : super(new http.Client(), '/');
|
AngelHttp _http;
|
||||||
|
|
||||||
|
TestClient(this.server, {this.autoDecodeGzip: true, bool useZone: false})
|
||||||
|
: super(new http.IOClient(), '/') {
|
||||||
|
_http = new AngelHttp(server, useZone: useZone);
|
||||||
|
}
|
||||||
|
|
||||||
Future close() {
|
Future close() {
|
||||||
this.client.close();
|
this.client.close();
|
||||||
|
@ -60,8 +69,8 @@ class TestClient extends client.BaseAngelClient {
|
||||||
/// Opens a WebSockets connection to the server. This will automatically bind the server
|
/// Opens a WebSockets connection to the server. This will automatically bind the server
|
||||||
/// over HTTP, if it is not already listening. Unfortunately, WebSockets cannot be mocked (yet!).
|
/// over HTTP, if it is not already listening. Unfortunately, WebSockets cannot be mocked (yet!).
|
||||||
Future<client.WebSockets> websocket({String path, Duration timeout}) async {
|
Future<client.WebSockets> websocket({String path, Duration timeout}) async {
|
||||||
HttpServer http = server.httpServer;
|
HttpServer http = _http.httpServer;
|
||||||
if (http == null) http = await server.startServer();
|
if (http == null) http = await _http.startServer();
|
||||||
var url = 'ws://${http.address.address}:${http.port}';
|
var url = 'ws://${http.address.address}:${http.port}';
|
||||||
var cleanPath = (path ?? '/ws')?.replaceAll(_straySlashes, '');
|
var cleanPath = (path ?? '/ws')?.replaceAll(_straySlashes, '');
|
||||||
if (cleanPath?.isNotEmpty == true) url += '/$cleanPath';
|
if (cleanPath?.isNotEmpty == true) url += '/$cleanPath';
|
||||||
|
@ -70,24 +79,21 @@ class TestClient extends client.BaseAngelClient {
|
||||||
return ws;
|
return ws;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<http.Response> sendUnstreamed(String method, url,
|
Future<http.Response> sendUnstreamed(
|
||||||
Map<String, String> headers,
|
String method, url, Map<String, String> headers,
|
||||||
[body, Encoding encoding]) =>
|
[body, Encoding encoding]) =>
|
||||||
send(method, url, headers, body, encoding).then(http.Response.fromStream);
|
send(method, url, headers, body, encoding).then(http.Response.fromStream);
|
||||||
|
|
||||||
Future<http.StreamedResponse> send(String method, url,
|
Future<StreamedResponse> send(String method, url, Map<String, String> headers,
|
||||||
Map<String, String> headers,
|
|
||||||
[body, Encoding encoding]) async {
|
[body, Encoding encoding]) async {
|
||||||
var rq = new MockHttpRequest(
|
var rq = new MockHttpRequest(
|
||||||
method, url is Uri ? url : Uri.parse(url.toString()));
|
method, url is Uri ? url : Uri.parse(url.toString()));
|
||||||
headers?.forEach(rq.headers.add);
|
headers?.forEach(rq.headers.add);
|
||||||
|
|
||||||
if (authToken?.isNotEmpty == true)
|
if (authToken?.isNotEmpty == true)
|
||||||
rq.headers.set(HttpHeaders.AUTHORIZATION, 'Bearer $authToken');
|
rq.headers.set('authorization', 'Bearer $authToken');
|
||||||
|
|
||||||
rq
|
rq..cookies.addAll(cookies)..session.addAll(session);
|
||||||
..cookies.addAll(cookies)
|
|
||||||
..session.addAll(session);
|
|
||||||
|
|
||||||
if (body is Stream<List<int>>) {
|
if (body is Stream<List<int>>) {
|
||||||
await rq.addStream(body);
|
await rq.addStream(body);
|
||||||
|
@ -95,16 +101,17 @@ class TestClient extends client.BaseAngelClient {
|
||||||
rq.add(body);
|
rq.add(body);
|
||||||
} else if (body is Map) {
|
} else if (body is Map) {
|
||||||
if (rq.headers.contentType == null ||
|
if (rq.headers.contentType == null ||
|
||||||
rq.headers.contentType.mimeType == ContentType.JSON.mimeType) {
|
rq.headers.contentType.mimeType == 'application/json') {
|
||||||
rq
|
rq
|
||||||
..headers.contentType = ContentType.JSON
|
..headers.contentType = new ContentType('application', 'json')
|
||||||
..write(JSON.encode(
|
..write(json.encode(body.keys.fold<Map<String, dynamic>>(
|
||||||
body.keys.fold({}, (out, k) => out..[k.toString()] = body[k])));
|
{}, (out, k) => out..[k.toString()] = body[k])));
|
||||||
} else if (rq.headers.contentType?.mimeType ==
|
} else if (rq.headers.contentType?.mimeType ==
|
||||||
'application/x-www-form-urlencoded') {
|
'application/x-www-form-urlencoded') {
|
||||||
rq.write(body.keys.fold<List<String>>([],
|
rq.write(body.keys.fold<List<String>>(
|
||||||
(out, k) => out..add('$k=' + Uri.encodeComponent(body[k])))
|
[],
|
||||||
.join());
|
(out, k) => out
|
||||||
|
..add('$k=' + Uri.encodeComponent(body[k].toString()))).join());
|
||||||
} else {
|
} else {
|
||||||
throw new UnsupportedError(
|
throw new UnsupportedError(
|
||||||
'Map bodies can only be sent for requests with the content type application/json or application/x-www-form-urlencoded.');
|
'Map bodies can only be sent for requests with the content type application/json or application/x-www-form-urlencoded.');
|
||||||
|
@ -114,7 +121,8 @@ class TestClient extends client.BaseAngelClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
await rq.close();
|
await rq.close();
|
||||||
await server.handleRequest(rq);
|
|
||||||
|
await _http.handleRequest(rq);
|
||||||
|
|
||||||
var rs = rq.response;
|
var rs = rq.response;
|
||||||
session
|
session
|
||||||
|
@ -130,17 +138,17 @@ class TestClient extends client.BaseAngelClient {
|
||||||
Stream<List<int>> stream = rs;
|
Stream<List<int>> stream = rs;
|
||||||
|
|
||||||
if (autoDecodeGzip != false &&
|
if (autoDecodeGzip != false &&
|
||||||
rs.headers[HttpHeaders.CONTENT_ENCODING]?.contains('gzip') == true)
|
rs.headers['content-encoding']?.contains('gzip') == true)
|
||||||
stream = stream.transform(GZIP.decoder);
|
stream = stream.transform(gzip.decoder);
|
||||||
|
|
||||||
return new http.StreamedResponse(stream, rs.statusCode,
|
return new StreamedResponse(stream, rs.statusCode,
|
||||||
contentLength: rs.contentLength,
|
contentLength: rs.contentLength,
|
||||||
isRedirect: rs.headers[HttpHeaders.LOCATION] != null,
|
isRedirect: rs.headers['location'] != null,
|
||||||
headers: extractedHeaders,
|
headers: extractedHeaders,
|
||||||
persistentConnection:
|
persistentConnection:
|
||||||
rq.headers.value(HttpHeaders.CONNECTION)?.toLowerCase()?.trim() ==
|
rq.headers.value('connection')?.toLowerCase()?.trim() ==
|
||||||
'keep-alive' ||
|
'keep-alive' ||
|
||||||
rq.headers.persistentConnection == true,
|
rq.headers.persistentConnection == true,
|
||||||
reasonPhrase: rs.reasonPhrase);
|
reasonPhrase: rs.reasonPhrase);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,7 +183,7 @@ class TestClient extends client.BaseAngelClient {
|
||||||
Future configure(client.AngelConfigurer configurer) => configurer(this);
|
Future configure(client.AngelConfigurer configurer) => configurer(this);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
client.Service service<T>(String path,
|
client.Service service(String path,
|
||||||
{Type type, client.AngelDeserializer deserializer}) {
|
{Type type, client.AngelDeserializer deserializer}) {
|
||||||
String uri = path.toString().replaceAll(_straySlashes, "");
|
String uri = path.toString().replaceAll(_straySlashes, "");
|
||||||
return _services.putIfAbsent(
|
return _services.putIfAbsent(
|
||||||
|
@ -191,7 +199,7 @@ class _MockService extends client.BaseAngelService {
|
||||||
: super(null, _app, basePath, deserializer: deserializer);
|
: super(null, _app, basePath, deserializer: deserializer);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<http.StreamedResponse> send(http.BaseRequest request) {
|
Future<StreamedResponse> send(http.BaseRequest request) {
|
||||||
if (app.authToken != null && app.authToken.isNotEmpty) {
|
if (app.authToken != null && app.authToken.isNotEmpty) {
|
||||||
request.headers['Authorization'] = 'Bearer ${app.authToken}';
|
request.headers['Authorization'] = 'Bearer ${app.authToken}';
|
||||||
}
|
}
|
||||||
|
@ -211,7 +219,7 @@ class _MockWebSockets extends client.WebSockets {
|
||||||
Map<String, String> headers = {};
|
Map<String, String> headers = {};
|
||||||
|
|
||||||
if (app.authToken?.isNotEmpty == true)
|
if (app.authToken?.isNotEmpty == true)
|
||||||
headers[HttpHeaders.AUTHORIZATION] = 'Bearer ${app.authToken}';
|
headers['authorization'] = 'Bearer ${app.authToken}';
|
||||||
|
|
||||||
var socket = await WebSocket.connect(basePath, headers: headers);
|
var socket = await WebSocket.connect(basePath, headers: headers);
|
||||||
return new IOWebSocketChannel(socket);
|
return new IOWebSocketChannel(socket);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import 'dart:convert';
|
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'package:angel_http_exception/angel_http_exception.dart';
|
import 'package:angel_http_exception/angel_http_exception.dart';
|
||||||
import 'package:angel_validate/angel_validate.dart';
|
import 'package:angel_validate/angel_validate.dart';
|
||||||
|
import 'package:dart2_constant/convert.dart';
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
import 'package:matcher/matcher.dart';
|
import 'package:matcher/matcher.dart';
|
||||||
|
|
||||||
|
@ -51,8 +51,9 @@ class _IsJson extends Matcher {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool matches(http.Response item, Map matchState) =>
|
bool matches(item, Map matchState) =>
|
||||||
equals(value).matches(JSON.decode(item.body), matchState);
|
item is http.Response &&
|
||||||
|
equals(value).matches(json.decode(item.body), matchState);
|
||||||
}
|
}
|
||||||
|
|
||||||
class _HasBody extends Matcher {
|
class _HasBody extends Matcher {
|
||||||
|
@ -65,12 +66,16 @@ class _HasBody extends Matcher {
|
||||||
description.add('has body $body');
|
description.add('has body $body');
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool matches(http.Response item, Map matchState) {
|
bool matches(item, Map matchState) {
|
||||||
if (body == true) return isNotEmpty.matches(item.bodyBytes, matchState);
|
if (item is http.Response) {
|
||||||
if (body is List<int>)
|
if (body == true) return isNotEmpty.matches(item.bodyBytes, matchState);
|
||||||
return equals(body).matches(item.bodyBytes, matchState);
|
if (body is List<int>)
|
||||||
else
|
return equals(body).matches(item.bodyBytes, matchState);
|
||||||
return equals(body.toString()).matches(item.body, matchState);
|
else
|
||||||
|
return equals(body.toString()).matches(item.body, matchState);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,21 +86,27 @@ class _HasContentType extends Matcher {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Description describe(Description description) {
|
Description describe(Description description) {
|
||||||
var str =
|
var str = contentType is ContentType
|
||||||
contentType is ContentType ? contentType.value : contentType.toString();
|
? ((contentType as ContentType).value)
|
||||||
|
: contentType.toString();
|
||||||
return description.add('has content type ' + str);
|
return description.add('has content type ' + str);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool matches(http.Response item, Map matchState) {
|
bool matches(item, Map matchState) {
|
||||||
if (!item.headers.containsKey(HttpHeaders.CONTENT_TYPE)) return false;
|
if (item is http.Response) {
|
||||||
|
if (!item.headers.containsKey('content-type')) return false;
|
||||||
|
|
||||||
if (contentType is ContentType) {
|
if (contentType is ContentType) {
|
||||||
var compare = ContentType.parse(item.headers[HttpHeaders.CONTENT_TYPE]);
|
var compare = ContentType.parse(item.headers['content-type']);
|
||||||
return equals(contentType.mimeType).matches(compare.mimeType, matchState);
|
return equals(contentType.mimeType)
|
||||||
|
.matches(compare.mimeType, matchState);
|
||||||
|
} else {
|
||||||
|
return equals(contentType.toString())
|
||||||
|
.matches(item.headers['content-type'], matchState);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return equals(contentType.toString())
|
return false;
|
||||||
.matches(item.headers[HttpHeaders.CONTENT_TYPE], matchState);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -115,15 +126,20 @@ class _HasHeader extends Matcher {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool matches(http.Response item, Map matchState) {
|
bool matches(item, Map matchState) {
|
||||||
if (value == true) {
|
if (item is http.Response) {
|
||||||
return contains(key.toLowerCase()).matches(item.headers.keys, matchState);
|
if (value == true) {
|
||||||
|
return contains(key.toLowerCase())
|
||||||
|
.matches(item.headers.keys, matchState);
|
||||||
|
} else {
|
||||||
|
if (!item.headers.containsKey(key.toLowerCase())) return false;
|
||||||
|
Iterable v = value is Iterable ? value : [value];
|
||||||
|
return v
|
||||||
|
.map((x) => x.toString())
|
||||||
|
.every(item.headers[key.toLowerCase()].split(',').contains);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!item.headers.containsKey(key.toLowerCase())) return false;
|
return false;
|
||||||
Iterable v = value is Iterable ? value : [value];
|
|
||||||
return v
|
|
||||||
.map((x) => x.toString())
|
|
||||||
.every(item.headers[key.toLowerCase()].split(',').contains);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -139,7 +155,8 @@ class _HasStatus extends Matcher {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool matches(http.Response item, Map matchState) =>
|
bool matches(item, Map matchState) =>
|
||||||
|
item is http.Response &&
|
||||||
equals(status).matches(item.statusCode, matchState);
|
equals(status).matches(item.statusCode, matchState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,10 +170,14 @@ class _HasValidBody extends Matcher {
|
||||||
description.add('matches validation schema ${validator.rules}');
|
description.add('matches validation schema ${validator.rules}');
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool matches(http.Response item, Map matchState) {
|
bool matches(item, Map matchState) {
|
||||||
final json = JSON.decode(item.body);
|
if (item is http.Response) {
|
||||||
if (json is! Map) return false;
|
final jsons = json.decode(item.body);
|
||||||
return validator.matches(json, matchState);
|
if (jsons is! Map) return false;
|
||||||
|
return validator.matches(jsons, matchState);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -198,30 +219,35 @@ class _IsAngelHttpException extends Matcher {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool matches(http.Response item, Map matchState) {
|
bool matches(item, Map matchState) {
|
||||||
final json = JSON.decode(item.body);
|
if (item is http.Response) {
|
||||||
|
final jsons = json.decode(item.body);
|
||||||
|
|
||||||
if (json is Map && json['isError'] == true) {
|
if (jsons is Map && jsons['isError'] == true) {
|
||||||
var exc = new AngelHttpException.fromMap(json);
|
var exc = new AngelHttpException.fromMap(jsons);
|
||||||
|
print(exc.toJson());
|
||||||
|
|
||||||
if (message?.isNotEmpty != true && statusCode == null && errors.isEmpty)
|
if (message?.isNotEmpty != true && statusCode == null && errors.isEmpty)
|
||||||
return true;
|
return true;
|
||||||
else {
|
else {
|
||||||
if (statusCode != null) if (!equals(statusCode)
|
if (statusCode != null) if (!equals(statusCode)
|
||||||
.matches(exc.statusCode, matchState)) return false;
|
.matches(exc.statusCode, matchState)) return false;
|
||||||
|
|
||||||
if (message?.isNotEmpty == true) if (!equals(message)
|
if (message?.isNotEmpty == true) if (!equals(message)
|
||||||
.matches(exc.message, matchState)) return false;
|
.matches(exc.message, matchState)) return false;
|
||||||
|
|
||||||
if (errors.isNotEmpty) {
|
if (errors.isNotEmpty) {
|
||||||
if (!errors
|
if (!errors
|
||||||
.every((err) => contains(err).matches(exc.errors, matchState)))
|
.every((err) => contains(err).matches(exc.errors, matchState)))
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
} else
|
||||||
return true;
|
return false;
|
||||||
}
|
} else {
|
||||||
} else
|
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
19
pubspec.yaml
19
pubspec.yaml
|
@ -1,18 +1,17 @@
|
||||||
author: "Tobe O <thosakwe@gmail.com>"
|
author: Tobe O <thosakwe@gmail.com>
|
||||||
description: "Testing utility library for the Angel framework."
|
description: Testing utility library for the Angel framework.
|
||||||
homepage: "https://github.com/angel-dart/test.git"
|
homepage: https://github.com/angel-dart/test.git
|
||||||
name: "angel_test"
|
name: angel_test
|
||||||
version: 1.1.0
|
version: 1.1.0+1
|
||||||
dependencies:
|
dependencies:
|
||||||
angel_client: ^1.1.0-alpha
|
angel_client: ^1.1.0-alpha
|
||||||
angel_framework: ^1.1.0-alpha
|
angel_framework: ^1.1.0-alpha
|
||||||
angel_validate: ^1.0.0
|
angel_validate: ^1.0.0
|
||||||
angel_websocket: ^1.1.0-alpha
|
angel_websocket: ^1.1.0-alpha
|
||||||
http: "^0.11.3+9"
|
http: ^0.11.0
|
||||||
matcher: "^0.12.0+2"
|
matcher: ^0.12.0+2
|
||||||
mock_request: ^1.0.0
|
mock_request: ^1.0.0
|
||||||
uuid: "^0.5.3"
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
test: "^0.12.17+2"
|
test: ^0.12.17+2
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=1.19.0"
|
sdk: ">=1.8.9 <3.0.0"
|
||||||
|
|
|
@ -32,8 +32,8 @@ main() {
|
||||||
})
|
})
|
||||||
..get('/gzip', (req, res) async {
|
..get('/gzip', (req, res) async {
|
||||||
res
|
res
|
||||||
..headers[HttpHeaders.CONTENT_ENCODING] = 'gzip'
|
..headers['content-encoding'] = 'gzip'
|
||||||
..write(GZIP.encode('Poop'.codeUnits))
|
..write(gzip.encode('Poop'.codeUnits))
|
||||||
..end();
|
..end();
|
||||||
})
|
})
|
||||||
..use(
|
..use(
|
||||||
|
@ -50,7 +50,7 @@ main() {
|
||||||
|
|
||||||
app.errorHandler = (e, req, res) => e.toJson();
|
app.errorHandler = (e, req, res) => e.toJson();
|
||||||
|
|
||||||
client = await connectTo(app);
|
client = await connectTo(app, useZone: false);
|
||||||
});
|
});
|
||||||
|
|
||||||
tearDown(() async {
|
tearDown(() async {
|
||||||
|
@ -96,8 +96,9 @@ main() {
|
||||||
|
|
||||||
test('hasValidBody+hasContentType', () async {
|
test('hasValidBody+hasContentType', () async {
|
||||||
var res = await client.get('/valid');
|
var res = await client.get('/valid');
|
||||||
|
print('Body: ${res.body}');
|
||||||
expect(res, hasContentType('application/json'));
|
expect(res, hasContentType('application/json'));
|
||||||
expect(res, hasContentType(ContentType.JSON));
|
expect(res, hasContentType(new ContentType('application', 'json')));
|
||||||
expect(
|
expect(
|
||||||
res,
|
res,
|
||||||
hasValidBody(new Validator({
|
hasValidBody(new Validator({
|
||||||
|
@ -111,7 +112,7 @@ main() {
|
||||||
|
|
||||||
test('gzip decode', () async {
|
test('gzip decode', () async {
|
||||||
var res = await client.get('/gzip');
|
var res = await client.get('/gzip');
|
||||||
expect(res, hasHeader(HttpHeaders.CONTENT_ENCODING, 'gzip'));
|
expect(res, hasHeader('content-encoding', 'gzip'));
|
||||||
expect(res, hasBody('Poop'));
|
expect(res, hasBody('Poop'));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -136,7 +137,7 @@ main() {
|
||||||
var foo = ws.service('foo');
|
var foo = ws.service('foo');
|
||||||
foo.create({});
|
foo.create({});
|
||||||
var result = await foo.onCreated.first;
|
var result = await foo.onCreated.first;
|
||||||
expect(result.data, equals({'foo': 'bar'}));
|
expect(result is Map ? result : result.data, equals({'foo': 'bar'}));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue