import 'dart:convert'; import 'dart:io'; import 'package:angel_container/mirrors.dart'; import 'package:angel_framework/angel_framework.dart'; import 'package:angel_framework/http.dart'; import 'package:http/http.dart' as http; import 'package:io/ansi.dart'; import 'package:logging/logging.dart'; import 'package:test/test.dart'; import 'common.dart'; @Middleware([interceptor]) testMiddlewareMetadata(RequestContext req, ResponseContext res) async { return "This should not be shown."; } @Middleware([interceptService]) class QueryService extends Service { @override @Middleware([interceptor]) read(id, [Map? params]) async => params; } void interceptor(RequestContext req, ResponseContext res) { res ..write('Middleware') ..close(); } bool interceptService(RequestContext req, ResponseContext res) { res.write("Service with "); return true; } main() { Angel? app; Angel? nested; Angel? todos; String? url; http.Client? client; setUp(() async { app = Angel(reflector: MirrorsReflector()); nested = Angel(reflector: MirrorsReflector()); todos = Angel(reflector: MirrorsReflector()); [app, nested, todos].forEach((Angel? app) { app!.logger = Logger('routing_test') ..onRecord.listen((rec) { if (rec.error != null) { stdout ..writeln(cyan.wrap(rec.toString())) ..writeln(cyan.wrap(rec.error.toString())) ..writeln(cyan.wrap(rec.stackTrace.toString())); } }); }); todos!.get('/action/:action', (req, res) => res.json(req.params)); late Route ted; ted = nested!.post('/ted/:route', (RequestContext req, res) { print('Params: ${req.params}'); print('Path: ${ted.path}, uri: ${req.path}'); print('matcher: ${ted.parser}'); return req.params; }); app!.mount('/nes', nested!); app!.get('/meta', testMiddlewareMetadata); app!.get('/intercepted', (req, res) => 'This should not be shown', middleware: [interceptor]); app!.get('/hello', (req, res) => 'world'); app!.get('/name/:first/last/:last', (req, res) => req.params); app!.post( '/lambda', (RequestContext req, res) => req.parseBody().then((_) => req.bodyAsMap)); app!.mount('/todos/:id', todos!); app! .get('/greet/:name', (RequestContext req, res) async => "Hello ${req.params['name']}") .name = 'Named routes'; app!.get('/named', (req, ResponseContext res) async { await res.redirectTo('Named routes', {'name': 'tests'}); }); app!.get('/log', (RequestContext req, res) async { print("Query: ${req.queryParameters}"); return "Logged"; }); app!.get('/method', (req, res) => 'Only GET'); app!.post('/method', (req, res) => 'Only POST'); app!.use('/query', QueryService()); RequestHandler write(String message) { return (req, res) { res.write(message); return true; }; } app!.chain([write('a')]).chain([write('b'), write('c')]).get( '/chained', (req, res) => res.close()); app!.fallback((req, res) => 'MJ'); //app.dumpTree(header: "DUMPING ROUTES:", showMatchers: true); client = http.Client(); HttpServer server = await AngelHttp(app).startServer('127.0.0.1', 0); url = "http://${server.address.host}:${server.port}"; }); tearDown(() async { await app!.close(); app = null; nested = null; todos = null; client!.close(); client = null; url = null; }); test('Can match basic url', () async { var response = await client!.get(Uri.parse("$url/hello")); expect(response.body, equals('"world"')); }); test('Can match url with multiple parameters', () async { var response = await client!.get(Uri.parse('$url/name/HELLO/last/WORLD')); print('Response: ${response.body}'); var json_ = json.decode(response.body); expect(json_, const IsInstanceOf()); expect(json_['first'], equals('HELLO')); expect(json_['last'], equals('WORLD')); }); test('Chained routes', () async { var response = await client!.get(Uri.parse("$url/chained")); expect(response.body, equals('abc')); }); test('Can nest another Angel instance', () async { var response = await client!.post(Uri.parse('$url/nes/ted/foo')); var json_ = json.decode(response.body); expect(json_['route'], equals('foo')); }); test('Can parse parameters from a nested Angel instance', () async { var response = await client!.get(Uri.parse('$url/todos/1337/action/test')); var json_ = json.decode(response.body); print('JSON: $json_'); expect(json_['id'], equals('1337')); expect(json_['action'], equals('test')); }); test('Can add and use named middleware', () async { var response = await client!.get(Uri.parse('$url/intercepted')); expect(response.body, equals('Middleware')); }); test('Middleware via metadata', () async { // Metadata var response = await client!.get(Uri.parse('$url/meta')); expect(response.body, equals('Middleware')); }); test('Can serialize function result as JSON', () async { Map headers = {'Content-Type': 'application/json'}; String postData = json.encode({'it': 'works'}); var response = await client!.post(Uri.parse("$url/lambda"), headers: headers as Map, body: postData); print('Response: ${response.body}'); expect(json.decode(response.body)['it'], equals('works')); }); test('Fallback routes', () async { var response = await client!.get(Uri.parse('$url/my_favorite_artist')); expect(response.body, equals('"MJ"')); }); test('Can name routes', () { Route foo = app!.get('/framework/:id', null)..name = 'frm'; print('Foo: $foo'); String uri = foo.makeUri({'id': 'angel'}); print(uri); expect(uri, equals('framework/angel')); }); test('Redirect to named routes', () async { var response = await client!.get(Uri.parse('$url/named')); print(response.body); expect(json.decode(response.body), equals('Hello tests')); }); test('Match routes, even with query params', () async { var response = await client! .get(Uri.parse("$url/log?foo=bar&bar=baz&baz.foo=bar&baz.bar=foo")); print(response.body); expect(json.decode(response.body), equals('Logged')); response = await client!.get(Uri.parse("$url/query/foo?bar=baz")); print(response.body); expect(response.body, equals("Service with Middleware")); }); test('only match route with matching method', () async { var response = await client!.get(Uri.parse("$url/method")); print(response.body); expect(response.body, '"Only GET"'); response = await client!.post(Uri.parse("$url/method")); print(response.body); expect(response.body, '"Only POST"'); response = await client!.patch(Uri.parse("$url/method")); print(response.body); expect(response.body, '"MJ"'); }); }