Publish test

This commit is contained in:
thomashii 2021-05-15 16:35:27 +08:00
parent cf208bf673
commit 3ac245db46
7 changed files with 79 additions and 93 deletions

View file

@ -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 {

View file

@ -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]
}) })

View file

@ -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);

View file

@ -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;
} }

View file

@ -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

View file

@ -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() {