Publish test
This commit is contained in:
parent
cf208bf673
commit
3ac245db46
7 changed files with 79 additions and 93 deletions
|
@ -1,19 +1,22 @@
|
||||||
# angel_test
|
# angel3_test
|
||||||
[![Pub](https://img.shields.io/pub/v/angel_test.svg)](https://pub.dartlang.org/packages/angel_test)
|
[![version](https://img.shields.io/badge/pub-v4.0.0-brightgreen)](https://pub.dartlang.org/packages/angel3_tet)
|
||||||
[![build status](https://travis-ci.org/angel-dart/test.svg)](https://travis-ci.org/angel-dart/test)
|
[![Null Safety](https://img.shields.io/badge/null-safety-brightgreen)](https://dart.dev/null-safety)
|
||||||
|
[![Gitter](https://img.shields.io/gitter/room/angel_dart/discussion)](https://gitter.im/angel_dart/discussion)
|
||||||
|
|
||||||
|
[![License](https://img.shields.io/github/license/dukefirehawk/angel)](https://github.com/dukefirehawk/angel/tree/angel3/packages/test/LICENSE)
|
||||||
|
|
||||||
Testing utility library for the Angel framework.
|
Testing utility library for the Angel framework.
|
||||||
|
|
||||||
# TestClient
|
# TestClient
|
||||||
The `TestClient` class is a custom `angel_client` that sends mock requests to your server.
|
The `TestClient` class is a custom `angel3_client` that sends mock requests to your server.
|
||||||
This means that you will not have to bind your server to HTTP to run.
|
This means that you will not have to bind your server to HTTP to run.
|
||||||
Plus, it is an `angel_client`, and thus supports services and other goodies.
|
Plus, it is an `angel3_client`, and thus supports services and other goodies.
|
||||||
|
|
||||||
The `TestClient` also supports WebSockets. WebSockets cannot be mocked (yet!) within this library,
|
The `TestClient` also supports WebSockets. WebSockets cannot be mocked (yet!) within this library,
|
||||||
so calling the `websocket()` function will also bind your server to HTTP, if it is not already listening.
|
so calling the `websocket()` function will also bind your server to HTTP, if it is not already listening.
|
||||||
|
|
||||||
The return value is a `WebSockets` client instance
|
The return value is a `WebSockets` client instance
|
||||||
(from [`package:angel_websocket`](https://github.com/angel-dart/websocket));
|
(from [`package:angel3_websocket`](https://github.com/dukefirehawk/angel/tree/angel3/packages/websocket));
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
var ws = await client.websocket('/ws');
|
var ws = await client.websocket('/ws');
|
||||||
|
@ -52,12 +55,12 @@ test('error', () async {
|
||||||
|
|
||||||
`hasValidBody` is one of the most powerful `Matcher`s in this library,
|
`hasValidBody` is one of the most powerful `Matcher`s in this library,
|
||||||
because it allows you to validate a JSON body against a
|
because it allows you to validate a JSON body against a
|
||||||
[validation schema](https://github.com/angel-dart/validate).
|
[validation schema](https://github.com/dukefirehawk/angel/tree/angel3/packages/validate).
|
||||||
|
|
||||||
Angel provides a comprehensive validation library that integrates tightly
|
Angel provides a comprehensive validation library that integrates tightly
|
||||||
with the very `matcher` package that you already use for testing. :)
|
with the very `matcher` package that you already use for testing.
|
||||||
|
|
||||||
[https://github.com/angel-dart/validate](https://github.com/angel-dart/validate)
|
[`package:angel3_validate`](https://github.com/dukefirehawk/angel/tree/angel3/packages//validate)
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
test('validate response', () async {
|
test('validate response', () async {
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'package:angel_framework/angel_framework.dart';
|
import 'package:angel3_framework/angel3_framework.dart';
|
||||||
import 'package:angel_test/angel_test.dart';
|
import 'package:angel3_test/angel3_test.dart';
|
||||||
import 'package:angel_validate/angel_validate.dart';
|
import 'package:angel3_validate/angel3_validate.dart';
|
||||||
import 'package:angel_websocket/server.dart';
|
import 'package:angel3_websocket/server.dart';
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
main() {
|
void main() {
|
||||||
Angel? app;
|
Angel? app;
|
||||||
late TestClient client;
|
late TestClient client;
|
||||||
|
|
||||||
setUp(() async {
|
setUp(() async {
|
||||||
app = new Angel()
|
app = Angel()
|
||||||
..get('/hello', (req, res) => 'Hello')
|
..get('/hello', (req, res) => 'Hello')
|
||||||
..get(
|
..get(
|
||||||
'/error',
|
'/error',
|
||||||
(req, res) => throw new AngelHttpException.forbidden(message: 'Test')
|
(req, res) => throw AngelHttpException.forbidden(message: 'Test')
|
||||||
..errors.addAll(['foo', 'bar']))
|
..errors.addAll(['foo', 'bar']))
|
||||||
..get('/body', (req, res) {
|
..get('/body', (req, res) {
|
||||||
res
|
res
|
||||||
|
@ -39,13 +39,13 @@ main() {
|
||||||
})
|
})
|
||||||
..use(
|
..use(
|
||||||
'/foo',
|
'/foo',
|
||||||
new AnonymousService(
|
AnonymousService(
|
||||||
index: ([params]) async => [
|
index: ([params]) async => [
|
||||||
{'michael': 'jackson'}
|
{'michael': 'jackson'}
|
||||||
],
|
],
|
||||||
create: (dynamic data, [params]) async => {'foo': 'bar'}));
|
create: (dynamic data, [params]) async => {'foo': 'bar'}));
|
||||||
|
|
||||||
var ws = new AngelWebSocket(app);
|
var ws = AngelWebSocket(app);
|
||||||
await app!.configure(ws.configureServer);
|
await app!.configure(ws.configureServer);
|
||||||
app!.all('/ws', ws.handleRequest);
|
app!.all('/ws', ws.handleRequest);
|
||||||
|
|
||||||
|
@ -101,9 +101,9 @@ main() {
|
||||||
expect(res, hasContentType('application/json'));
|
expect(res, hasContentType('application/json'));
|
||||||
expect(
|
expect(
|
||||||
res,
|
res,
|
||||||
hasValidBody(new Validator({
|
hasValidBody(Validator({
|
||||||
'michael*': [isString, isNotEmpty, equals('jackson')],
|
'michael*': [isString, isNotEmpty, equals('jackson')],
|
||||||
'billie': new Validator({
|
'billie': Validator({
|
||||||
'jean': [isString, isNotEmpty],
|
'jean': [isString, isNotEmpty],
|
||||||
'is_my_lover': [isBool, isFalse]
|
'is_my_lover': [isBool, isFalse]
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,26 +1,26 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'package:angel_client/base_angel_client.dart' as client;
|
import 'package:angel3_client/base_angel_client.dart' as client;
|
||||||
import 'package:angel_client/io.dart' as client;
|
import 'package:angel3_client/io.dart' as client;
|
||||||
import 'package:angel_framework/angel_framework.dart';
|
import 'package:angel3_framework/angel3_framework.dart';
|
||||||
import 'package:angel_framework/http.dart';
|
import 'package:angel3_framework/http.dart';
|
||||||
import 'package:angel_websocket/io.dart' as client;
|
import 'package:angel3_websocket/io.dart' as client;
|
||||||
import 'package:http/http.dart' as http hide StreamedResponse;
|
import 'package:http/http.dart' as http hide StreamedResponse;
|
||||||
import 'package:http/io_client.dart' as http;
|
import 'package:http/io_client.dart' as http;
|
||||||
import 'package:http/src/streamed_response.dart';
|
import 'package:http/src/streamed_response.dart';
|
||||||
import 'package:mock_request/mock_request.dart';
|
import 'package:angel3_mock_request/angel3_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 = 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 = Uuid();*/
|
||||||
|
|
||||||
/// Shorthand for bootstrapping a [TestClient].
|
/// Shorthand for bootstrapping a [TestClient].
|
||||||
Future<TestClient> connectTo(Angel app,
|
Future<TestClient> connectTo(Angel app,
|
||||||
|
@ -36,7 +36,7 @@ Future<TestClient> connectTo(Angel app,
|
||||||
print("Load plugins");
|
print("Load plugins");
|
||||||
await plugin(app);
|
await plugin(app);
|
||||||
}
|
}
|
||||||
return new TestClient(app,
|
return TestClient(app,
|
||||||
autoDecodeGzip: autoDecodeGzip != false, useZone: useZone)
|
autoDecodeGzip: autoDecodeGzip != false, useZone: useZone)
|
||||||
..session.addAll(initialSession ?? {});
|
..session.addAll(initialSession ?? {});
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,7 @@ class TestClient extends client.BaseAngelClient {
|
||||||
final Map<String, client.Service> _services = {};
|
final Map<String, client.Service> _services = {};
|
||||||
|
|
||||||
/// Session info to be sent to the server on every request.
|
/// Session info to be sent to the server on every request.
|
||||||
final HttpSession session = new MockHttpSession(id: 'angel-test-client');
|
final HttpSession session = MockHttpSession(id: 'angel-test-client');
|
||||||
|
|
||||||
/// A list of cookies to be sent to and received from the server.
|
/// A list of cookies to be sent to and received from the server.
|
||||||
final List<Cookie> cookies = [];
|
final List<Cookie> cookies = [];
|
||||||
|
@ -101,9 +101,9 @@ class TestClient extends client.BaseAngelClient {
|
||||||
rq = newRq;
|
rq = newRq;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (authToken?.isNotEmpty == true)
|
if (authToken?.isNotEmpty == true) {
|
||||||
rq.headers.add('authorization', 'Bearer $authToken');
|
rq.headers.add('authorization', 'Bearer $authToken');
|
||||||
|
}
|
||||||
rq..cookies.addAll(cookies)..session.addAll(session);
|
rq..cookies.addAll(cookies)..session.addAll(session);
|
||||||
|
|
||||||
await request.finalize().pipe(rq);
|
await request.finalize().pipe(rq);
|
||||||
|
|
|
@ -2,8 +2,8 @@ import 'dart:convert';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
import 'package:matcher/matcher.dart';
|
import 'package:matcher/matcher.dart';
|
||||||
import 'package:angel_http_exception/angel_http_exception.dart';
|
import 'package:angel3_http_exception/angel3_http_exception.dart';
|
||||||
import 'package:angel_validate/angel_validate.dart';
|
import 'package:angel3_validate/angel3_validate.dart';
|
||||||
|
|
||||||
/// Expects a response to be a JSON representation of an `AngelHttpException`.
|
/// Expects a response to be a JSON representation of an `AngelHttpException`.
|
||||||
///
|
///
|
||||||
|
@ -12,15 +12,15 @@ Matcher isAngelHttpException(
|
||||||
{String? message,
|
{String? message,
|
||||||
int? statusCode,
|
int? statusCode,
|
||||||
Iterable<String> errors: const []}) =>
|
Iterable<String> errors: const []}) =>
|
||||||
new _IsAngelHttpException(
|
_IsAngelHttpException(
|
||||||
message: message, statusCode: statusCode, errors: errors);
|
message: message, statusCode: statusCode, errors: errors);
|
||||||
|
|
||||||
/// Expects a given response, when parsed as JSON,
|
/// Expects a given response, when parsed as JSON,
|
||||||
/// to equal a desired value.
|
/// to equal a desired value.
|
||||||
Matcher isJson(value) => new _IsJson(value);
|
Matcher isJson(value) => _IsJson(value);
|
||||||
|
|
||||||
/// Expects a response to have the given content type, whether a `String` or [ContentType].
|
/// Expects a response to have the given content type, whether a `String` or [ContentType].
|
||||||
Matcher hasContentType(contentType) => new _HasContentType(contentType);
|
Matcher hasContentType(contentType) => _HasContentType(contentType);
|
||||||
|
|
||||||
/// Expects a response to have the given body.
|
/// Expects a response to have the given body.
|
||||||
///
|
///
|
||||||
|
@ -29,18 +29,18 @@ Matcher hasContentType(contentType) => new _HasContentType(contentType);
|
||||||
///
|
///
|
||||||
/// If value is a `List<int>`, then it will be matched against `res.bodyBytes`.
|
/// If value is a `List<int>`, then it will be matched against `res.bodyBytes`.
|
||||||
/// Otherwise, the string value will be matched against `res.body`.
|
/// Otherwise, the string value will be matched against `res.body`.
|
||||||
Matcher hasBody([value]) => new _HasBody(value ?? true);
|
Matcher hasBody([value]) => _HasBody(value ?? true);
|
||||||
|
|
||||||
/// Expects a response to have a header named [key] which contains [value]. [value] can be a `String`, or a List of `String`s.
|
/// Expects a response to have a header named [key] which contains [value]. [value] can be a `String`, or a List of `String`s.
|
||||||
///
|
///
|
||||||
/// If `value` is true (default), then this matcher will simply assert that the header is present.
|
/// If `value` is true (default), then this matcher will simply assert that the header is present.
|
||||||
Matcher hasHeader(String key, [value]) => new _HasHeader(key, value ?? true);
|
Matcher hasHeader(String key, [value]) => _HasHeader(key, value ?? true);
|
||||||
|
|
||||||
/// Expects a response to have the given status code.
|
/// Expects a response to have the given status code.
|
||||||
Matcher hasStatus(int status) => new _HasStatus(status);
|
Matcher hasStatus(int status) => _HasStatus(status);
|
||||||
|
|
||||||
/// Expects a response to have a JSON body that is a `Map` and satisfies the given [validator] schema.
|
/// Expects a response to have a JSON body that is a `Map` and satisfies the given [validator] schema.
|
||||||
Matcher hasValidBody(Validator validator) => new _HasValidBody(validator);
|
Matcher hasValidBody(Validator validator) => _HasValidBody(validator);
|
||||||
|
|
||||||
class _IsJson extends Matcher {
|
class _IsJson extends Matcher {
|
||||||
var value;
|
var value;
|
||||||
|
@ -195,25 +195,28 @@ class _IsAngelHttpException extends Matcher {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Description describe(Description description) {
|
Description describe(Description description) {
|
||||||
if (message?.isNotEmpty != true && statusCode == null && errors.isEmpty)
|
if (message?.isNotEmpty != true && statusCode == null && errors.isEmpty) {
|
||||||
return description.add('is an Angel HTTP Exception');
|
return description.add('is an Angel HTTP Exception');
|
||||||
else {
|
} else {
|
||||||
var buf = new StringBuffer('is an Angel HTTP Exception with');
|
var buf = StringBuffer('is an Angel HTTP Exception with');
|
||||||
|
|
||||||
if (statusCode != null) buf.write(' status code $statusCode');
|
if (statusCode != null) buf.write(' status code $statusCode');
|
||||||
|
|
||||||
if (message?.isNotEmpty == true) {
|
if (message?.isNotEmpty == true) {
|
||||||
if (statusCode != null && errors.isNotEmpty)
|
if (statusCode != null && errors.isNotEmpty) {
|
||||||
buf.write(',');
|
buf.write(',');
|
||||||
else if (statusCode != null && errors.isEmpty) buf.write(' and');
|
} else if (statusCode != null && errors.isEmpty) {
|
||||||
|
buf.write(' and');
|
||||||
|
}
|
||||||
buf.write(' message "$message"');
|
buf.write(' message "$message"');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (errors.isNotEmpty) {
|
if (errors.isNotEmpty) {
|
||||||
if (statusCode != null || message?.isNotEmpty == true)
|
if (statusCode != null || message?.isNotEmpty == true) {
|
||||||
buf.write(' and errors $errors');
|
buf.write(' and errors $errors');
|
||||||
else
|
} else {
|
||||||
buf.write(' errors $errors');
|
buf.write(' errors $errors');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return description.add(buf.toString());
|
return description.add(buf.toString());
|
||||||
|
@ -226,12 +229,14 @@ class _IsAngelHttpException extends Matcher {
|
||||||
final jsons = json.decode(item.body);
|
final jsons = json.decode(item.body);
|
||||||
|
|
||||||
if (jsons is Map && jsons['isError'] == true) {
|
if (jsons is Map && jsons['isError'] == true) {
|
||||||
var exc = new AngelHttpException.fromMap(jsons);
|
var exc = AngelHttpException.fromMap(jsons);
|
||||||
print(exc.toJson());
|
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;
|
||||||
|
|
||||||
|
@ -239,15 +244,17 @@ class _IsAngelHttpException extends Matcher {
|
||||||
.matches(exc.message, matchState)) return false;
|
.matches(exc.message, matchState)) return false;
|
||||||
|
|
||||||
if (errors.isNotEmpty) {
|
if (errors.isNotEmpty) {
|
||||||
if (!errors
|
if (!errors.every(
|
||||||
.every((err) => contains(err).matches(exc.errors, matchState)))
|
(err) => contains(err).matches(exc.errors, matchState))) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else
|
} else {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,44 +1,20 @@
|
||||||
name: angel_test
|
name: angel3_test
|
||||||
description: Testing utility library for the Angel framework. Use with package:test.
|
|
||||||
homepage: https://github.com/dukefirehawk/angel
|
|
||||||
version: 4.0.0
|
version: 4.0.0
|
||||||
publish_to: none
|
description: Testing utility library for the Angel framework. Use with package:test.
|
||||||
|
homepage: https://github.com/dukefirehawk/angel/tree/angel3/packages/test
|
||||||
environment:
|
environment:
|
||||||
sdk: '>=2.12.0 <3.0.0'
|
sdk: '>=2.12.0 <3.0.0'
|
||||||
dependencies:
|
dependencies:
|
||||||
angel_client:
|
angel3_client: ^4.0.0
|
||||||
git:
|
angel3_framework: ^4.0.0
|
||||||
url: https://github.com/dukefirehawk/angel.git
|
angel3_http_exception: ^3.0.0
|
||||||
ref: sdk-2.12.x_nnbd
|
angel3_validate: ^4.0.0
|
||||||
path: packages/client
|
angel3_websocket: ^4.0.0
|
||||||
angel_framework:
|
angel3_mock_request: ^2.0.0
|
||||||
git:
|
angel3_container: ^3.0.0
|
||||||
url: https://github.com/dukefirehawk/angel.git
|
|
||||||
ref: sdk-2.12.x_nnbd
|
|
||||||
path: packages/framework
|
|
||||||
angel_http_exception:
|
|
||||||
git:
|
|
||||||
url: https://github.com/dukefirehawk/angel.git
|
|
||||||
ref: sdk-2.12.x_nnbd
|
|
||||||
path: packages/http_exception
|
|
||||||
angel_validate:
|
|
||||||
git:
|
|
||||||
url: https://github.com/dukefirehawk/angel.git
|
|
||||||
ref: sdk-2.12.x_nnbd
|
|
||||||
path: packages/validate
|
|
||||||
angel_websocket:
|
|
||||||
git:
|
|
||||||
url: https://github.com/dukefirehawk/angel.git
|
|
||||||
ref: sdk-2.12.x_nnbd
|
|
||||||
path: packages/websocket
|
|
||||||
http: ^0.13.1
|
http: ^0.13.1
|
||||||
matcher: ^0.12.10
|
matcher: ^0.12.10
|
||||||
mock_request:
|
|
||||||
git:
|
|
||||||
url: https://github.com/dukefirehawk/angel.git
|
|
||||||
ref: sdk-2.12.x_nnbd
|
|
||||||
path: packages/mock_request
|
|
||||||
web_socket_channel: ^2.0.0
|
web_socket_channel: ^2.0.0
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
test: ^1.17.3
|
test: ^1.17.4
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'package:angel_framework/angel_framework.dart';
|
import 'package:angel3_framework/angel3_framework.dart';
|
||||||
import 'package:angel_container/mirrors.dart';
|
import 'package:angel3_container/mirrors.dart';
|
||||||
import 'package:angel_test/angel_test.dart';
|
import 'package:angel3_test/angel3_test.dart';
|
||||||
import 'package:angel_websocket/server.dart';
|
import 'package:angel3_websocket/server.dart';
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
|
Loading…
Reference in a new issue