import 'dart:convert'; import 'package:flutter_test/flutter_test.dart'; import 'package:halkyon_app/halkyon_app.dart'; import 'package:halkyon_base_client/halkyon_base_client.dart'; import 'package:halkyon_oidc_flutter/halkyon_oidc_flutter.dart' show OidcRefusal, OidcRefusedException; import 'package:http/http.dart' as http; import 'package:http/testing.dart'; /// [refusal] as an instance sends it: named by its module. String sent(SerializableException refusal) => jsonEncode({ 'className': switch (refusal) { EmailSignInRefusedException() => 'halkyon_base.EmailSignInRefusedException', PasswordRefusedException() => 'halkyon_base.PasswordRefusedException', OidcRefusedException() => 'halkyon_oidc.OidcRefusedException', _ => throw ArgumentError.value(refusal), }, 'data': (refusal as SerializableModel).toJson(), }); void main() { test("reads the refusals an instance sends under halkyon_base's name, as " "an app's own generated protocol does", () { final protocol = BaseProtocol(); expect( protocol.decodeWithType( sent( EmailSignInRefusedException(reason: EmailSignInRefusal.wrongCode), ), ), isA().having( (refusal) => refusal.reason, 'reason', EmailSignInRefusal.wrongCode, ), ); expect( protocol.decodeWithType( sent( PasswordRefusedException(reason: PasswordRefusal.wrongCredentials), ), ), isA().having( (refusal) => refusal.reason, 'reason', PasswordRefusal.wrongCredentials, ), ); }); test("reads OpenID Connect's refusals under its own module's name, which " "halkyon_base's SimpleLogin passes on", () { expect( BaseProtocol().decodeWithType( sent(OidcRefusedException(reason: OidcRefusal.unknownAttempt)), ), isA().having( (refusal) => refusal.reason, 'reason', OidcRefusal.unknownAttempt, ), ); }); test("calls halkyon_base's endpoints at the instance, and passes its " 'refusals on as themselves', () async { final asked = []; final client = BaseClient( 'https://learn.example.org/', httpClientOverride: MockClient((request) async { asked.add(request.url.toString()); return switch (request.url.path) { '/halkyon_base.instance/basics' => http.Response( jsonEncode( InstanceBasics( app: 'learn', emailSignIn: true, sourceCodeUrl: 'https://code.example.org/learn', minimumAppBuild: 21, dataLocation: 'EU', ).toJson(), ), 200, ), '/halkyon_base.passwordSignIn/begin' => http.Response( sent( PasswordRefusedException( reason: PasswordRefusal.tooManyAttempts, ), ), 400, ), _ => http.Response('', 404), }; }), ); addTearDown(client.close); final basics = await client.modules.instance.basics(); expect(basics.emailSignIn, isTrue); expect(basics.minimumAppBuild, 21); expect(basics.dataLocation, 'EU'); await expectLater( client.modules.passwordSignIn.begin(address: 'anna@example.org'), throwsA( isA().having( (refusal) => refusal.reason, 'reason', PasswordRefusal.tooManyAttempts, ), ), ); expect(asked, [ 'https://learn.example.org/halkyon_base.instance/basics', 'https://learn.example.org/halkyon_base.passwordSignIn/begin', ]); }); }