From 38480d84f429fad5022e9a27135ad575e574164a Mon Sep 17 00:00:00 2001 From: Hugo Pointcheval Date: Fri, 11 Nov 2022 16:54:08 -0500 Subject: [PATCH] test(auth): add tests for all features --- .../authentication_cubit_test.dart | 144 +++--- .../authentication_state_test.dart | 22 +- .../email_verification_cubit_test.dart | 249 +++++++++++ .../email_verification_state_test.dart | 48 ++ .../password_reset_cubit_test.dart | 335 ++++++++++++++ .../password_reset_state_test.dart | 56 +++ .../test/sign_in/sign_in_cubit_test.dart | 379 +++++++++++++--- .../test/sign_in/sign_in_state_test.dart | 42 +- .../test/sign_up/sign_up_cubit_test.dart | 421 ++++++++++++++---- .../test/sign_up/sign_up_state_test.dart | 88 +--- 10 files changed, 1463 insertions(+), 321 deletions(-) create mode 100644 packages/wyatt_authentication_bloc/test/email_verification/email_verification_cubit_test.dart create mode 100644 packages/wyatt_authentication_bloc/test/email_verification/email_verification_state_test.dart create mode 100644 packages/wyatt_authentication_bloc/test/password_reset/password_reset_cubit_test.dart create mode 100644 packages/wyatt_authentication_bloc/test/password_reset/password_reset_state_test.dart diff --git a/packages/wyatt_authentication_bloc/test/authentication/authentication_cubit_test.dart b/packages/wyatt_authentication_bloc/test/authentication/authentication_cubit_test.dart index 95708942..e836bd4f 100644 --- a/packages/wyatt_authentication_bloc/test/authentication/authentication_cubit_test.dart +++ b/packages/wyatt_authentication_bloc/test/authentication/authentication_cubit_test.dart @@ -17,100 +17,114 @@ import 'package:bloc_test/bloc_test.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; +import 'package:wyatt_architecture/wyatt_architecture.dart'; import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart'; +import 'package:wyatt_type_utils/wyatt_type_utils.dart'; class MockAuthenticationRepository extends Mock - implements AuthenticationRepository {} + implements AuthenticationRepository {} -class MockUser extends Mock implements User {} +class MockAccount extends Mock implements Account {} void main() { group('AuthenticationCubit', () { - final MockUser user = MockUser(); - late AuthenticationRepository authenticationRepository; + final MockAccount account = MockAccount(); + final AccountWrapper wrapper = AccountWrapperModel(account, 10); + late AuthenticationRepository authenticationRepository; setUp(() { authenticationRepository = MockAuthenticationRepository(); - when(() => authenticationRepository.user).thenAnswer( + when(() => authenticationRepository.streamAccount()).thenAnswer( (_) => const Stream.empty(), ); - when(() => authenticationRepository.cubitStatus).thenAnswer( - (_) => Stream.fromIterable([AuthCubitStatus.stoped]), - ); when( - () => authenticationRepository.currentUser, - ).thenReturn(user); + () => authenticationRepository.getAccount(), + ).thenAnswer((_) async => Ok(account)); }); test('initial auth state is `unknown`', () { expect( - AuthenticationCubit( + AuthenticationCubit( authenticationRepository: authenticationRepository, ).state, const AuthenticationState.unknown(), ); }); - test('initial cubit status is `stoped`', () async { - expect( - await AuthenticationCubit( - authenticationRepository: authenticationRepository, - ).status, - AuthCubitStatus.stoped, - ); - }); - - group('UserChanged', () { - blocTest, AuthenticationState>( - 'emits authenticated when user is not empty', + group('ListenForAuthenticationChanges', () { + blocTest, AuthenticationState>( + 'emits authenticated when stream contains account', setUp: () { - when(() => user.isNotEmpty).thenReturn(true); - when(() => authenticationRepository.user).thenAnswer( - (_) => Stream.value(user), + when(() => authenticationRepository.streamAccount()).thenAnswer( + (_) => Stream.fromIterable([ + Future.value( + Ok(wrapper), + ) + ]), ); - when(() => authenticationRepository.cubitStatus).thenAnswer( - (_) => Stream.value(AuthCubitStatus.started), - ); - }, - build: () => AuthenticationCubit( - authenticationRepository: authenticationRepository, - )..init(), - seed: () => const AuthenticationState.unknown(), - expect: () => [AuthenticationState.authenticated(user, null)], - ); - - blocTest, AuthenticationState>( - 'emits unauthenticated when user is empty', - setUp: () { - when(() => user.isEmpty).thenReturn(true); - when(() => user.isNotEmpty).thenReturn(false); - when(() => authenticationRepository.user).thenAnswer( - (_) => Stream.value(user), - ); - when(() => authenticationRepository.cubitStatus).thenAnswer( - (_) => Stream.value(AuthCubitStatus.started), - ); - }, - build: () => AuthenticationCubit( - authenticationRepository: authenticationRepository, - )..init(), - seed: () => const AuthenticationState.unknown(), - expect: () => [const AuthenticationState.unauthenticated()], - ); - }); - - group('LogoutRequested', () { - blocTest, AuthenticationState>( - 'invokes signOut', - setUp: () { - when( - () => authenticationRepository.signOut(), - ).thenAnswer((_) async {}); }, build: () => AuthenticationCubit( authenticationRepository: authenticationRepository, ), - act: (cubit) => cubit.logOut(), + seed: () => const AuthenticationState.unknown(), + expect: () => [AuthenticationState.authenticated(wrapper)], + ); + + blocTest, AuthenticationState>( + 'emits unauthenticated when account stream is empty', + setUp: () { + when( + () => authenticationRepository.destroyCache(), + ).thenAnswer((_) async => const Ok(null)); + when(() => authenticationRepository.streamAccount()).thenAnswer( + (_) => Stream.fromIterable([ + Future.value( + Ok(AccountWrapperModel(null, 1)), + ) + ]), + ); + }, + build: () => AuthenticationCubit( + authenticationRepository: authenticationRepository, + ), + seed: () => const AuthenticationState.unknown(), + expect: () => [const AuthenticationState.unauthenticated()], + ); + + blocTest, AuthenticationState>( + 'emits unauthenticated when there is an error in stream', + setUp: () { + when( + () => authenticationRepository.destroyCache(), + ).thenAnswer((_) async => const Ok(null)); + when(() => authenticationRepository.streamAccount()).thenAnswer( + (_) => Stream.fromIterable([ + Future.value( + Err(ServerException()), + ) + ]), + ); + }, + build: () => AuthenticationCubit( + authenticationRepository: authenticationRepository, + ), + seed: () => const AuthenticationState.unknown(), + expect: () => [const AuthenticationState.unauthenticated()], + ); + }); + + group('SignOut', () { + blocTest, AuthenticationState>( + 'invokes signOut', + setUp: () { + when( + () => authenticationRepository.signOut(), + ).thenAnswer((_) async => const Ok(null)); + }, + build: () => AuthenticationCubit( + authenticationRepository: authenticationRepository, + ), + act: (cubit) => cubit.signOut(), verify: (_) { verify(() => authenticationRepository.signOut()).called(1); }, diff --git a/packages/wyatt_authentication_bloc/test/authentication/authentication_state_test.dart b/packages/wyatt_authentication_bloc/test/authentication/authentication_state_test.dart index d7ce2cb2..a85c7998 100644 --- a/packages/wyatt_authentication_bloc/test/authentication/authentication_state_test.dart +++ b/packages/wyatt_authentication_bloc/test/authentication/authentication_state_test.dart @@ -18,7 +18,7 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart'; -class MockUser extends Mock implements User {} +class MockAccount extends Mock implements Account {} void main() { group('AuthenticationState', () { @@ -27,29 +27,33 @@ void main() { const AuthenticationState state = AuthenticationState.unauthenticated(); expect(state.status, AuthenticationStatus.unauthenticated); - expect(state.user, null); + expect(state.accountWrapper, null); }); }); group('authenticated', () { test('has correct status', () { - final MockUser user = MockUser(); + final MockAccount account = MockAccount(); final AuthenticationState state = - AuthenticationState.authenticated(user, null); + AuthenticationState.authenticated( + AccountWrapperModel(account, null), + ); expect(state.status, AuthenticationStatus.authenticated); - expect(state.user, user); + expect(state.accountWrapper?.account, account); }); }); group('authenticated with extra data', () { test('has correct status', () { - final MockUser user = MockUser(); + final MockAccount account = MockAccount(); const String extra = 'AwesomeExtraData'; final AuthenticationState state = - AuthenticationState.authenticated(user, extra); + AuthenticationState.authenticated( + AccountWrapperModel(account, extra), + ); expect(state.status, AuthenticationStatus.authenticated); - expect(state.user, user); - expect(state.extra, extra); + expect(state.accountWrapper?.account, account); + expect(state.accountWrapper?.data, extra); }); }); }); diff --git a/packages/wyatt_authentication_bloc/test/email_verification/email_verification_cubit_test.dart b/packages/wyatt_authentication_bloc/test/email_verification/email_verification_cubit_test.dart new file mode 100644 index 00000000..e07a4f2d --- /dev/null +++ b/packages/wyatt_authentication_bloc/test/email_verification/email_verification_cubit_test.dart @@ -0,0 +1,249 @@ +// Copyright (C) 2022 WYATT GROUP +// Please see the AUTHORS file for details. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +import 'package:bloc_test/bloc_test.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:wyatt_architecture/wyatt_architecture.dart'; +import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart'; +import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; +import 'package:wyatt_type_utils/wyatt_type_utils.dart'; + +class MockAuthenticationRepository extends Mock + implements AuthenticationRepository {} + +class MockAuthenticationCubit extends Mock implements AuthenticationCubit { +} + +class MockAccount extends Mock implements Account {} + +class MockFormRepository extends Mock implements FormRepository {} + +void main() { + group('EmailVerificationCubit', () { + late MockAccount account; + late AuthenticationRepository authenticationRepository; + + setUp(() { + authenticationRepository = MockAuthenticationRepository(); + when( + () => authenticationRepository.getAccount(), + ).thenAnswer((_) async => Ok(account)); + + when( + () => authenticationRepository.refresh(), + ).thenAnswer((_) async => const Ok(null)); + + account = MockAccount(); + when( + () => account.emailVerified, + ).thenAnswer((_) => true); + }); + + test('initial state is `false`', () { + expect( + EmailVerificationCubit( + authenticationRepository: authenticationRepository, + ).state, + const EmailVerificationState(), + ); + }); + + group('SendVerificationEmail', () { + blocTest, EmailVerificationState>( + 'invokes sendEmailVerification,', + setUp: () { + when(() => authenticationRepository.sendEmailVerification()) + .thenAnswer((_) async => const Ok(null)); + }, + build: () => EmailVerificationCubit( + authenticationRepository: authenticationRepository, + ), + act: (cubit) => cubit.sendEmailVerification(), + verify: (_) { + verify(() => authenticationRepository.sendEmailVerification()) + .called(1); + }, + ); + + blocTest, EmailVerificationState>( + 'emits success', + setUp: () { + when(() => authenticationRepository.sendEmailVerification()) + .thenAnswer((_) async => const Ok(null)); + }, + build: () => EmailVerificationCubit( + authenticationRepository: authenticationRepository, + ), + seed: () => const EmailVerificationState(), + act: (cubit) => cubit.sendEmailVerification(), + expect: () => [ + const EmailVerificationState( + status: FormStatus.submissionInProgress, + ), + const EmailVerificationState( + status: FormStatus.submissionSuccess, + ) + ], + ); + + blocTest, EmailVerificationState>( + 'emits failure', + setUp: () { + when(() => authenticationRepository.sendEmailVerification()) + .thenAnswer((_) async => Err(ServerException('erreur'))); + }, + build: () => EmailVerificationCubit( + authenticationRepository: authenticationRepository, + ), + seed: () => const EmailVerificationState(), + act: (cubit) => cubit.sendEmailVerification(), + expect: () => [ + const EmailVerificationState( + status: FormStatus.submissionInProgress, + ), + const EmailVerificationState( + errorMessage: 'erreur', + status: FormStatus.submissionFailure, + ) + ], + ); + }); + + group('CheckEmailVerification', () { + blocTest, EmailVerificationState>( + 'invokes refresh,', + setUp: () { + when( + () => authenticationRepository.refresh(), + ).thenAnswer((_) async => const Ok(null)); + }, + build: () => EmailVerificationCubit( + authenticationRepository: authenticationRepository, + ), + act: (cubit) => cubit.checkEmailVerification(), + verify: (_) { + verify(() => authenticationRepository.refresh()).called(1); + }, + ); + + blocTest, EmailVerificationState>( + 'invokes emailVerified,', + setUp: () { + when( + () => authenticationRepository.refresh(), + ).thenAnswer((_) async => const Ok(null)); + when(() => account.emailVerified).thenAnswer((_) => false); + }, + build: () => EmailVerificationCubit( + authenticationRepository: authenticationRepository, + ), + act: (cubit) => cubit.checkEmailVerification(), + verify: (_) { + verify(() => account.emailVerified).called(1); + }, + ); + + blocTest, EmailVerificationState>( + 'emits success with true if verified', + setUp: () { + when(() => authenticationRepository.refresh()) + .thenAnswer((_) async => const Ok(null)); + }, + build: () => EmailVerificationCubit( + authenticationRepository: authenticationRepository, + ), + seed: () => const EmailVerificationState(), + act: (cubit) => cubit.checkEmailVerification(), + expect: () => [ + const EmailVerificationState( + status: FormStatus.submissionInProgress, + ), + const EmailVerificationState( + isVerified: true, + status: FormStatus.submissionSuccess, + ) + ], + ); + + blocTest, EmailVerificationState>( + 'emits success with false if not verified', + setUp: () { + when(() => authenticationRepository.refresh()) + .thenAnswer((_) async => const Ok(null)); + when(() => account.emailVerified).thenAnswer((_) => false); + }, + build: () => EmailVerificationCubit( + authenticationRepository: authenticationRepository, + ), + seed: () => const EmailVerificationState(), + act: (cubit) => cubit.checkEmailVerification(), + expect: () => [ + const EmailVerificationState( + status: FormStatus.submissionInProgress, + ), + const EmailVerificationState( + status: FormStatus.submissionSuccess, + ) + ], + ); + + blocTest, EmailVerificationState>( + 'emits failure on refresh error', + setUp: () { + when(() => authenticationRepository.refresh()) + .thenAnswer((_) async => Err(ServerException('erreur'))); + }, + build: () => EmailVerificationCubit( + authenticationRepository: authenticationRepository, + ), + seed: () => const EmailVerificationState(), + act: (cubit) => cubit.checkEmailVerification(), + expect: () => [ + const EmailVerificationState( + status: FormStatus.submissionInProgress, + ), + const EmailVerificationState( + errorMessage: 'erreur', + status: FormStatus.submissionFailure, + ) + ], + ); + + blocTest, EmailVerificationState>( + 'emits failure on get account error', + setUp: () { + when(() => authenticationRepository.getAccount()) + .thenAnswer((_) async => Err(ServerException('erreur'))); + }, + build: () => EmailVerificationCubit( + authenticationRepository: authenticationRepository, + ), + seed: () => const EmailVerificationState(), + act: (cubit) => cubit.checkEmailVerification(), + expect: () => [ + const EmailVerificationState( + status: FormStatus.submissionInProgress, + ), + const EmailVerificationState( + errorMessage: 'erreur', + status: FormStatus.submissionFailure, + ) + ], + ); + }); + }); +} diff --git a/packages/wyatt_authentication_bloc/test/email_verification/email_verification_state_test.dart b/packages/wyatt_authentication_bloc/test/email_verification/email_verification_state_test.dart new file mode 100644 index 00000000..37e030b4 --- /dev/null +++ b/packages/wyatt_authentication_bloc/test/email_verification/email_verification_state_test.dart @@ -0,0 +1,48 @@ +// Copyright (C) 2022 WYATT GROUP +// Please see the AUTHORS file for details. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +import 'package:flutter_test/flutter_test.dart'; +import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart'; +import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; + +void main() { + group('EmailVerificationState', () { + test('supports value comparisons', () { + expect( + const EmailVerificationState(isVerified: true), + const EmailVerificationState(isVerified: true), + ); + }); + + test('returns same object when no properties are passed', () { + expect( + const EmailVerificationState(isVerified: true).copyWith(), + const EmailVerificationState(isVerified: true), + ); + }); + + test('returns object with updated status when status is passed', () { + expect( + const EmailVerificationState(isVerified: true) + .copyWith(status: FormStatus.invalid), + const EmailVerificationState( + isVerified: true, + status: FormStatus.invalid, + ), + ); + }); + }); +} diff --git a/packages/wyatt_authentication_bloc/test/password_reset/password_reset_cubit_test.dart b/packages/wyatt_authentication_bloc/test/password_reset/password_reset_cubit_test.dart new file mode 100644 index 00000000..e28ecb73 --- /dev/null +++ b/packages/wyatt_authentication_bloc/test/password_reset/password_reset_cubit_test.dart @@ -0,0 +1,335 @@ +// Copyright (C) 2022 WYATT GROUP +// Please see the AUTHORS file for details. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +import 'package:bloc_test/bloc_test.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:wyatt_architecture/wyatt_architecture.dart'; +import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart'; +import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; +import 'package:wyatt_type_utils/wyatt_type_utils.dart'; + +class MockAuthenticationRepository extends Mock + implements AuthenticationRepository {} + +class MockAuthenticationCubit extends Mock implements AuthenticationCubit { +} + +class MockAccount extends Mock implements Account {} + +class MockFormRepository extends Mock implements FormRepository {} + +void main() { + const String invalidEmailString = 'invalid'; + + const String validEmailString = 'test@gmail.com'; + + group('PasswordResetCubit', () { + final WyattForm form = WyattFormImpl( + [ + FormInput(AuthFormField.email, const Email.pure()), + FormInput(AuthFormField.password, const Password.pure()) + ], + name: AuthFormName.passwordResetForm, + ); + + late MockFormRepository formRepository; + late AuthenticationRepository authenticationRepository; + + setUp(() { + authenticationRepository = MockAuthenticationRepository(); + formRepository = MockFormRepository(); + + when( + () => authenticationRepository.sendPasswordResetEmail( + email: any(named: 'email'), + ), + ).thenAnswer((_) async => const Ok(null)); + + when( + () => authenticationRepository.formRepository, + ).thenAnswer((_) => formRepository); + + when( + () => formRepository.accessForm(AuthFormName.passwordResetForm), + ).thenAnswer((_) => form); + }); + + test('initial state is pure', () { + expect( + PasswordResetCubit( + authenticationRepository: authenticationRepository, + ).state, + PasswordResetState(form: form), + ); + }); + + group('emailChanged', () { + blocTest, PasswordResetState>( + 'emits [invalid] when email is invalid', + build: () => PasswordResetCubit( + authenticationRepository: authenticationRepository, + ), + act: (cubit) => cubit.emailChanged(invalidEmailString), + expect: () => [ + PasswordResetState( + form: WyattFormImpl( + [ + FormInput( + AuthFormField.email, + const Email.dirty(invalidEmailString), + ), + ], + name: AuthFormName.passwordResetForm, + ), + status: FormStatus.invalid, + ), + ], + ); + + blocTest, PasswordResetState>( + 'emits [valid] when email is valid', + setUp: () { + when( + () => formRepository.accessForm(AuthFormName.passwordResetForm), + ).thenAnswer( + (_) => WyattFormImpl( + [ + FormInput( + AuthFormField.email, + const Email.pure(), + ), + ], + name: AuthFormName.passwordResetForm, + ), + ); + }, + build: () => PasswordResetCubit( + authenticationRepository: authenticationRepository, + ), + seed: () => PasswordResetState( + form: WyattFormImpl( + [ + FormInput( + AuthFormField.email, + const Email.pure(), + ), + ], + name: AuthFormName.passwordResetForm, + ), + status: FormStatus.invalid, + ), + act: (cubit) => cubit.emailChanged(validEmailString), + expect: () => [ + PasswordResetState( + form: WyattFormImpl( + [ + FormInput( + AuthFormField.email, + const Email.dirty(validEmailString), + ), + ], + name: AuthFormName.passwordResetForm, + ), + status: FormStatus.valid, + ), + ], + ); + }); + + group('submit', () { + blocTest, PasswordResetState>( + 'does nothing when status is not validated', + build: () => PasswordResetCubit( + authenticationRepository: authenticationRepository, + ), + act: (cubit) => cubit.submit(), + expect: () => const [], + ); + + blocTest, PasswordResetState>( + 'calls sendPasswordResetEmail with correct email', + setUp: () { + when( + () => formRepository.accessForm(AuthFormName.passwordResetForm), + ).thenAnswer( + (_) => WyattFormImpl( + [ + FormInput( + AuthFormField.email, + const Email.dirty(validEmailString), + ), + ], + name: AuthFormName.passwordResetForm, + ), + ); + }, + build: () => PasswordResetCubit( + authenticationRepository: authenticationRepository, + ), + seed: () => PasswordResetState( + form: WyattFormImpl( + [ + FormInput( + AuthFormField.email, + const Email.dirty(validEmailString), + ), + ], + name: AuthFormName.passwordResetForm, + ), + status: FormStatus.valid, + ), + act: (cubit) => cubit.submit(), + verify: (_) { + verify( + () => authenticationRepository.sendPasswordResetEmail( + email: validEmailString, + ), + ).called(1); + }, + ); + + blocTest, PasswordResetState>( + 'emits [submissionInProgress, submissionSuccess] ' + 'when sendPasswordResetEmail succeeds', + setUp: () { + when( + () => formRepository.accessForm(AuthFormName.passwordResetForm), + ).thenAnswer( + (_) => WyattFormImpl( + [ + FormInput( + AuthFormField.email, + const Email.dirty(validEmailString), + ), + ], + name: AuthFormName.passwordResetForm, + ), + ); + }, + build: () => PasswordResetCubit( + authenticationRepository: authenticationRepository, + ), + seed: () => PasswordResetState( + form: WyattFormImpl( + [ + FormInput( + AuthFormField.email, + const Email.dirty(validEmailString), + ), + ], + name: AuthFormName.passwordResetForm, + ), + status: FormStatus.valid, + ), + act: (cubit) => cubit.submit(), + expect: () => [ + PasswordResetState( + form: WyattFormImpl( + [ + FormInput( + AuthFormField.email, + const Email.dirty(validEmailString), + ), + ], + name: AuthFormName.passwordResetForm, + ), + status: FormStatus.submissionInProgress, + ), + PasswordResetState( + form: WyattFormImpl( + [ + FormInput( + AuthFormField.email, + const Email.dirty(validEmailString), + ), + ], + name: AuthFormName.passwordResetForm, + ), + status: FormStatus.submissionSuccess, + ) + ], + ); + + blocTest, PasswordResetState>( + 'emits [submissionInProgress, submissionFailure] ' + 'when sendPasswordResetEmail fails', + setUp: () { + when( + () => authenticationRepository.sendPasswordResetEmail( + email: any(named: 'email'), + ), + ).thenAnswer((_) async => Err(ServerException())); + when( + () => formRepository.accessForm(AuthFormName.passwordResetForm), + ).thenAnswer( + (_) => WyattFormImpl( + [ + FormInput( + AuthFormField.email, + const Email.dirty(validEmailString), + ), + ], + name: AuthFormName.passwordResetForm, + ), + ); + }, + build: () => PasswordResetCubit( + authenticationRepository: authenticationRepository, + ), + seed: () => PasswordResetState( + form: WyattFormImpl( + [ + FormInput( + AuthFormField.email, + const Email.dirty(validEmailString), + ), + ], + name: AuthFormName.passwordResetForm, + ), + status: FormStatus.valid, + ), + act: (cubit) => cubit.submit(), + expect: () => [ + PasswordResetState( + form: WyattFormImpl( + [ + FormInput( + AuthFormField.email, + const Email.dirty(validEmailString), + ), + ], + name: AuthFormName.passwordResetForm, + ), + status: FormStatus.submissionInProgress, + ), + PasswordResetState( + form: WyattFormImpl( + [ + FormInput( + AuthFormField.email, + const Email.dirty(validEmailString), + ), + ], + name: AuthFormName.passwordResetForm, + ), + status: FormStatus.submissionFailure, + ) + ], + ); + }); + }); +} diff --git a/packages/wyatt_authentication_bloc/test/password_reset/password_reset_state_test.dart b/packages/wyatt_authentication_bloc/test/password_reset/password_reset_state_test.dart new file mode 100644 index 00000000..661ea241 --- /dev/null +++ b/packages/wyatt_authentication_bloc/test/password_reset/password_reset_state_test.dart @@ -0,0 +1,56 @@ +// Copyright (C) 2022 WYATT GROUP +// Please see the AUTHORS file for details. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +import 'package:flutter_test/flutter_test.dart'; +import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart'; +import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; + +void main() { + final WyattForm form = WyattFormImpl( + [ + FormInput(AuthFormField.email, const Email.pure()), + ], + name: AuthFormName.passwordResetForm, + ); + + group('PasswordResetState', () { + test('supports value comparisons', () { + expect( + PasswordResetState( + form: form, + ), + PasswordResetState(form: form), + ); + }); + + test('returns same object when no properties are passed', () { + expect( + PasswordResetState(form: form).copyWith(), + PasswordResetState(form: form), + ); + }); + + test('returns object with updated status when status is passed', () { + expect( + PasswordResetState(form: form).copyWith(status: FormStatus.invalid), + PasswordResetState( + form: form, + status: FormStatus.invalid, + ), + ); + }); + }); +} diff --git a/packages/wyatt_authentication_bloc/test/sign_in/sign_in_cubit_test.dart b/packages/wyatt_authentication_bloc/test/sign_in/sign_in_cubit_test.dart index 866ed2ca..72b2834a 100644 --- a/packages/wyatt_authentication_bloc/test/sign_in/sign_in_cubit_test.dart +++ b/packages/wyatt_authentication_bloc/test/sign_in/sign_in_cubit_test.dart @@ -17,46 +17,61 @@ import 'package:bloc_test/bloc_test.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; +import 'package:wyatt_architecture/wyatt_architecture.dart'; import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart'; import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; +import 'package:wyatt_type_utils/wyatt_type_utils.dart'; class MockAuthenticationRepository extends Mock - implements AuthenticationRepository {} + implements AuthenticationRepository {} -class MockAuthenticationCubit extends Mock - implements AuthenticationCubit {} +class MockAuthenticationCubit extends Mock implements AuthenticationCubit { +} + +class MockAccount extends Mock implements Account {} + +class MockFormRepository extends Mock implements FormRepository {} void main() { const String invalidEmailString = 'invalid'; - const Email invalidEmail = Email.dirty(invalidEmailString); const String validEmailString = 'test@gmail.com'; - const Email validEmail = Email.dirty(validEmailString); const String invalidPasswordString = 'invalid'; - const Password invalidPassword = Password.dirty(invalidPasswordString); const String validPasswordString = 't0pS3cret1234'; - const Password validPassword = Password.dirty(validPasswordString); group('SignInCubit', () { - late AuthenticationRepository authenticationRepository; - late AuthenticationCubit authenticationCubit; + final MockAccount account = MockAccount(); + final WyattForm form = WyattFormImpl( + [ + FormInput(AuthFormField.email, const Email.pure()), + FormInput(AuthFormField.password, const Password.pure()) + ], + name: AuthFormName.signInForm, + ); + + late MockFormRepository formRepository; + late AuthenticationRepository authenticationRepository; setUp(() { authenticationRepository = MockAuthenticationRepository(); - authenticationCubit = MockAuthenticationCubit(); + formRepository = MockFormRepository(); when( () => authenticationRepository.signInWithEmailAndPassword( email: any(named: 'email'), password: any(named: 'password'), ), - ).thenAnswer((_) async {}); + ).thenAnswer((_) async => Ok(account)); when( - () => authenticationCubit.start(), - ).thenReturn(true); + () => authenticationRepository.formRepository, + ).thenAnswer((_) => formRepository); + + when( + () => formRepository.accessForm(AuthFormName.signInForm), + ).thenAnswer((_) => form); }); test('initial state is SignInState', () { @@ -64,33 +79,90 @@ void main() { SignInCubit( authenticationRepository: authenticationRepository, ).state, - const SignInState(), + SignInState(form: form), ); }); group('emailChanged', () { - blocTest( + blocTest, SignInState>( 'emits [invalid] when email/password are invalid', build: () => SignInCubit( authenticationRepository: authenticationRepository, ), act: (cubit) => cubit.emailChanged(invalidEmailString), - expect: () => const [ - SignInState(email: invalidEmail, status: FormStatus.invalid), + expect: () => [ + SignInState( + form: WyattFormImpl( + [ + FormInput( + AuthFormField.email, + const Email.dirty(invalidEmailString), + ), + FormInput(AuthFormField.password, const Password.pure()) + ], + name: AuthFormName.signInForm, + ), + status: FormStatus.invalid, + ), ], ); - blocTest( + blocTest, SignInState>( 'emits [valid] when email/password are valid', + setUp: () { + when( + () => formRepository.accessForm(AuthFormName.signInForm), + ).thenAnswer( + (_) => WyattFormImpl( + [ + FormInput( + AuthFormField.email, + const Email.pure(), + ), + FormInput( + AuthFormField.password, + const Password.dirty(validPasswordString), + ) + ], + name: AuthFormName.signInForm, + ), + ); + }, build: () => SignInCubit( authenticationRepository: authenticationRepository, ), - seed: () => const SignInState(password: validPassword), + seed: () => SignInState( + form: WyattFormImpl( + [ + FormInput( + AuthFormField.email, + const Email.pure(), + ), + FormInput( + AuthFormField.password, + const Password.dirty(validPasswordString), + ) + ], + name: AuthFormName.signInForm, + ), + status: FormStatus.invalid, + ), act: (cubit) => cubit.emailChanged(validEmailString), - expect: () => const [ + expect: () => [ SignInState( - email: validEmail, - password: validPassword, + form: WyattFormImpl( + [ + FormInput( + AuthFormField.email, + const Email.dirty(validEmailString), + ), + FormInput( + AuthFormField.password, + const Password.dirty(validPasswordString), + ) + ], + name: AuthFormName.signInForm, + ), status: FormStatus.valid, ), ], @@ -98,58 +170,145 @@ void main() { }); group('passwordChanged', () { - blocTest( + blocTest, SignInState>( 'emits [invalid] when email/password are invalid', build: () => SignInCubit( authenticationRepository: authenticationRepository, ), act: (cubit) => cubit.passwordChanged(invalidPasswordString), - expect: () => const [ + expect: () => [ SignInState( - password: invalidPassword, + form: WyattFormImpl( + [ + FormInput( + AuthFormField.email, + const Email.pure(), + ), + FormInput( + AuthFormField.password, + const Password.dirty(invalidPasswordString), + ) + ], + name: AuthFormName.signInForm, + ), status: FormStatus.invalid, ), ], ); - blocTest( + blocTest, SignInState>( 'emits [valid] when email/password are valid', + setUp: () { + when( + () => formRepository.accessForm(AuthFormName.signInForm), + ).thenAnswer( + (_) => WyattFormImpl( + [ + FormInput( + AuthFormField.email, + const Email.dirty(validEmailString), + ), + FormInput( + AuthFormField.password, + const Password.pure(), + ) + ], + name: AuthFormName.signInForm, + ), + ); + }, build: () => SignInCubit( authenticationRepository: authenticationRepository, ), - seed: () => const SignInState(email: validEmail), + seed: () => SignInState( + form: WyattFormImpl( + [ + FormInput( + AuthFormField.email, + const Email.dirty(validEmailString), + ), + FormInput( + AuthFormField.password, + const Password.pure(), + ) + ], + name: AuthFormName.signInForm, + ), + status: FormStatus.invalid, + ), act: (cubit) => cubit.passwordChanged(validPasswordString), - expect: () => const [ + expect: () => [ SignInState( - email: validEmail, - password: validPassword, + form: WyattFormImpl( + [ + FormInput( + AuthFormField.email, + const Email.dirty(validEmailString), + ), + FormInput( + AuthFormField.password, + const Password.dirty(validPasswordString), + ) + ], + name: AuthFormName.signInForm, + ), status: FormStatus.valid, ), ], ); }); - group('logInWithCredentials', () { - blocTest( + group('submit', () { + blocTest, SignInState>( 'does nothing when status is not validated', build: () => SignInCubit( authenticationRepository: authenticationRepository, ), - act: (cubit) => cubit.signInWithEmailAndPassword(), + act: (cubit) => cubit.submit(), expect: () => const [], ); - blocTest( + blocTest, SignInState>( 'calls signInWithEmailAndPassword with correct email/password', + setUp: () { + when( + () => formRepository.accessForm(AuthFormName.signInForm), + ).thenAnswer( + (_) => WyattFormImpl( + [ + FormInput( + AuthFormField.email, + const Email.dirty(validEmailString), + ), + FormInput( + AuthFormField.password, + const Password.dirty(validPasswordString), + ) + ], + name: AuthFormName.signInForm, + ), + ); + }, build: () => SignInCubit( authenticationRepository: authenticationRepository, ), - seed: () => const SignInState( + seed: () => SignInState( + form: WyattFormImpl( + [ + FormInput( + AuthFormField.email, + const Email.dirty(validEmailString), + ), + FormInput( + AuthFormField.password, + const Password.dirty(validPasswordString), + ) + ], + name: AuthFormName.signInForm, + ), status: FormStatus.valid, - email: validEmail, - password: validPassword, ), - act: (cubit) => cubit.signInWithEmailAndPassword(), + act: (cubit) => cubit.submit(), verify: (_) { verify( () => authenticationRepository.signInWithEmailAndPassword( @@ -160,33 +319,85 @@ void main() { }, ); - blocTest( + blocTest, SignInState>( 'emits [submissionInProgress, submissionSuccess] ' 'when signInWithEmailAndPassword succeeds', + setUp: () { + when( + () => formRepository.accessForm(AuthFormName.signInForm), + ).thenAnswer( + (_) => WyattFormImpl( + [ + FormInput( + AuthFormField.email, + const Email.dirty(validEmailString), + ), + FormInput( + AuthFormField.password, + const Password.dirty(validPasswordString), + ) + ], + name: AuthFormName.signInForm, + ), + ); + }, build: () => SignInCubit( authenticationRepository: authenticationRepository, ), - seed: () => const SignInState( + seed: () => SignInState( + form: WyattFormImpl( + [ + FormInput( + AuthFormField.email, + const Email.dirty(validEmailString), + ), + FormInput( + AuthFormField.password, + const Password.dirty(validPasswordString), + ) + ], + name: AuthFormName.signInForm, + ), status: FormStatus.valid, - email: validEmail, - password: validPassword, ), - act: (cubit) => cubit.signInWithEmailAndPassword(), - expect: () => const [ + act: (cubit) => cubit.submit(), + expect: () => [ SignInState( + form: WyattFormImpl( + [ + FormInput( + AuthFormField.email, + const Email.dirty(validEmailString), + ), + FormInput( + AuthFormField.password, + const Password.dirty(validPasswordString), + ) + ], + name: AuthFormName.signInForm, + ), status: FormStatus.submissionInProgress, - email: validEmail, - password: validPassword, ), SignInState( + form: WyattFormImpl( + [ + FormInput( + AuthFormField.email, + const Email.dirty(validEmailString), + ), + FormInput( + AuthFormField.password, + const Password.dirty(validPasswordString), + ) + ], + name: AuthFormName.signInForm, + ), status: FormStatus.submissionSuccess, - email: validEmail, - password: validPassword, ) ], ); - blocTest( + blocTest, SignInState>( 'emits [submissionInProgress, submissionFailure] ' 'when signInWithEmailAndPassword fails', setUp: () { @@ -195,27 +406,77 @@ void main() { email: any(named: 'email'), password: any(named: 'password'), ), - ).thenThrow(Exception('oops')); + ).thenAnswer((_) async => Err(ServerException())); + when( + () => formRepository.accessForm(AuthFormName.signInForm), + ).thenAnswer( + (_) => WyattFormImpl( + [ + FormInput( + AuthFormField.email, + const Email.dirty(validEmailString), + ), + FormInput( + AuthFormField.password, + const Password.dirty(validPasswordString), + ) + ], + name: AuthFormName.signInForm, + ), + ); }, build: () => SignInCubit( authenticationRepository: authenticationRepository, ), - seed: () => const SignInState( + seed: () => SignInState( + form: WyattFormImpl( + [ + FormInput( + AuthFormField.email, + const Email.dirty(validEmailString), + ), + FormInput( + AuthFormField.password, + const Password.dirty(validPasswordString), + ) + ], + name: AuthFormName.signInForm, + ), status: FormStatus.valid, - email: validEmail, - password: validPassword, ), - act: (cubit) => cubit.signInWithEmailAndPassword(), - expect: () => const [ + act: (cubit) => cubit.submit(), + expect: () => [ SignInState( + form: WyattFormImpl( + [ + FormInput( + AuthFormField.email, + const Email.dirty(validEmailString), + ), + FormInput( + AuthFormField.password, + const Password.dirty(validPasswordString), + ) + ], + name: AuthFormName.signInForm, + ), status: FormStatus.submissionInProgress, - email: validEmail, - password: validPassword, ), SignInState( + form: WyattFormImpl( + [ + FormInput( + AuthFormField.email, + const Email.dirty(validEmailString), + ), + FormInput( + AuthFormField.password, + const Password.dirty(validPasswordString), + ) + ], + name: AuthFormName.signInForm, + ), status: FormStatus.submissionFailure, - email: validEmail, - password: validPassword, ) ], ); diff --git a/packages/wyatt_authentication_bloc/test/sign_in/sign_in_state_test.dart b/packages/wyatt_authentication_bloc/test/sign_in/sign_in_state_test.dart index c7d0f892..e55d92bd 100644 --- a/packages/wyatt_authentication_bloc/test/sign_in/sign_in_state_test.dart +++ b/packages/wyatt_authentication_bloc/test/sign_in/sign_in_state_test.dart @@ -19,36 +19,38 @@ import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart'; import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; void main() { - const Email email = Email.dirty('email'); - const Password password = Password.dirty('password'); + final WyattForm form = WyattFormImpl( + [ + FormInput(AuthFormField.email, const Email.pure()), + FormInput(AuthFormField.password, const Password.pure()) + ], + name: AuthFormName.signInForm, + ); group('SignInState', () { test('supports value comparisons', () { - expect(const SignInState(), const SignInState()); + expect( + SignInState( + form: form, + ), + SignInState(form: form), + ); }); test('returns same object when no properties are passed', () { - expect(const SignInState().copyWith(), const SignInState()); + expect( + SignInState(form: form).copyWith(), + SignInState(form: form), + ); }); test('returns object with updated status when status is passed', () { expect( - const SignInState().copyWith(status: FormStatus.pure), - const SignInState(), - ); - }); - - test('returns object with updated email when email is passed', () { - expect( - const SignInState().copyWith(email: email), - const SignInState(email: email), - ); - }); - - test('returns object with updated password when password is passed', () { - expect( - const SignInState().copyWith(password: password), - const SignInState(password: password), + SignInState(form: form).copyWith(status: FormStatus.invalid), + SignInState( + form: form, + status: FormStatus.invalid, + ), ); }); }); diff --git a/packages/wyatt_authentication_bloc/test/sign_up/sign_up_cubit_test.dart b/packages/wyatt_authentication_bloc/test/sign_up/sign_up_cubit_test.dart index 0e3de2d5..0fe84d1a 100644 --- a/packages/wyatt_authentication_bloc/test/sign_up/sign_up_cubit_test.dart +++ b/packages/wyatt_authentication_bloc/test/sign_up/sign_up_cubit_test.dart @@ -17,163 +17,298 @@ import 'package:bloc_test/bloc_test.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; +import 'package:wyatt_architecture/wyatt_architecture.dart'; import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart'; import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; +import 'package:wyatt_type_utils/wyatt_type_utils.dart'; class MockAuthenticationRepository extends Mock - implements AuthenticationRepository {} + implements AuthenticationRepository {} -class MockAuthenticationCubit extends Mock - implements AuthenticationCubit {} +class MockAuthenticationCubit extends Mock implements AuthenticationCubit { +} + +class MockAccount extends Mock implements Account {} + +class MockFormRepository extends Mock implements FormRepository {} void main() { const String invalidEmailString = 'invalid'; - const Email invalidEmail = Email.dirty(invalidEmailString); const String validEmailString = 'test@gmail.com'; - const Email validEmail = Email.dirty(validEmailString); const String invalidPasswordString = 'invalid'; - const Password invalidPassword = Password.dirty(invalidPasswordString); const String validPasswordString = 't0pS3cret1234'; - const Password validPassword = Password.dirty(validPasswordString); group('SignUpCubit', () { - late AuthenticationRepository authenticationRepository; - late AuthenticationCubit authenticationCubit; + final MockAccount account = MockAccount(); + final WyattForm form = WyattFormImpl( + [ + FormInput(AuthFormField.email, const Email.pure()), + FormInput(AuthFormField.password, const Password.pure()) + ], + name: AuthFormName.signUpForm, + ); + + late MockFormRepository formRepository; + late AuthenticationRepository authenticationRepository; setUp(() { authenticationRepository = MockAuthenticationRepository(); - authenticationCubit = MockAuthenticationCubit(); + formRepository = MockFormRepository(); + when( () => authenticationRepository.signUp( email: any(named: 'email'), password: any(named: 'password'), ), - ).thenAnswer((_) async => 'uid'); + ).thenAnswer((_) async => Ok(account)); when( - () => authenticationCubit.start(), - ).thenReturn(true); + () => authenticationRepository.formRepository, + ).thenAnswer((_) => formRepository); when( - () => authenticationCubit.stop(), - ).thenReturn(true); + () => formRepository.accessForm(AuthFormName.signUpForm), + ).thenAnswer((_) => form); }); test('initial state is SignUpState', () { expect( SignUpCubit( authenticationRepository: authenticationRepository, - formData: const FormData.empty(), ).state, - const SignUpState(data: FormData.empty()), + SignUpState(form: form), ); }); group('emailChanged', () { - blocTest( + blocTest, SignUpState>( 'emits [invalid] when email/password are invalid', build: () => SignUpCubit( authenticationRepository: authenticationRepository, - formData: const FormData.empty(), ), act: (cubit) => cubit.emailChanged(invalidEmailString), expect: () => [ - const SignUpState( - email: invalidEmail, + SignUpState( + form: WyattFormImpl( + [ + FormInput( + AuthFormField.email, + const Email.dirty(invalidEmailString), + ), + FormInput(AuthFormField.password, const Password.pure()) + ], + name: AuthFormName.signUpForm, + ), status: FormStatus.invalid, - data: FormData.empty(), ), ], ); - blocTest( + blocTest, SignUpState>( 'emits [valid] when email/password are valid', + setUp: () { + when( + () => formRepository.accessForm(AuthFormName.signUpForm), + ).thenAnswer( + (_) => WyattFormImpl( + [ + FormInput( + AuthFormField.email, + const Email.pure(), + ), + FormInput( + AuthFormField.password, + const Password.dirty(validPasswordString), + ) + ], + name: AuthFormName.signUpForm, + ), + ); + }, build: () => SignUpCubit( authenticationRepository: authenticationRepository, - formData: const FormData.empty(), ), - seed: () => const SignUpState( - password: validPassword, - data: FormData.empty(), + seed: () => SignUpState( + form: WyattFormImpl( + [ + FormInput( + AuthFormField.email, + const Email.pure(), + ), + FormInput( + AuthFormField.password, + const Password.dirty(validPasswordString), + ) + ], + name: AuthFormName.signUpForm, + ), + status: FormStatus.invalid, ), act: (cubit) => cubit.emailChanged(validEmailString), expect: () => [ - const SignUpState( - email: validEmail, - password: validPassword, + SignUpState( + form: WyattFormImpl( + [ + FormInput( + AuthFormField.email, + const Email.dirty(validEmailString), + ), + FormInput( + AuthFormField.password, + const Password.dirty(validPasswordString), + ) + ], + name: AuthFormName.signUpForm, + ), status: FormStatus.valid, - data: FormData.empty(), ), ], ); }); group('passwordChanged', () { - blocTest( + blocTest, SignUpState>( 'emits [invalid] when email/password are invalid', build: () => SignUpCubit( authenticationRepository: authenticationRepository, - formData: const FormData.empty(), ), act: (cubit) => cubit.passwordChanged(invalidPasswordString), expect: () => [ - const SignUpState( - password: invalidPassword, + SignUpState( + form: WyattFormImpl( + [ + FormInput( + AuthFormField.email, + const Email.pure(), + ), + FormInput( + AuthFormField.password, + const Password.dirty(invalidPasswordString), + ) + ], + name: AuthFormName.signUpForm, + ), status: FormStatus.invalid, - data: FormData.empty(), ), ], ); - blocTest( + blocTest, SignUpState>( 'emits [valid] when email/password are valid', + setUp: () { + when( + () => formRepository.accessForm(AuthFormName.signUpForm), + ).thenAnswer( + (_) => WyattFormImpl( + [ + FormInput( + AuthFormField.email, + const Email.dirty(validEmailString), + ), + FormInput( + AuthFormField.password, + const Password.pure(), + ) + ], + name: AuthFormName.signUpForm, + ), + ); + }, build: () => SignUpCubit( authenticationRepository: authenticationRepository, - formData: const FormData.empty(), ), - seed: () => const SignUpState( - email: validEmail, - data: FormData.empty(), + seed: () => SignUpState( + form: WyattFormImpl( + [ + FormInput( + AuthFormField.email, + const Email.dirty(validEmailString), + ), + FormInput( + AuthFormField.password, + const Password.pure(), + ) + ], + name: AuthFormName.signUpForm, + ), + status: FormStatus.invalid, ), act: (cubit) => cubit.passwordChanged(validPasswordString), expect: () => [ - const SignUpState( - email: validEmail, - password: validPassword, + SignUpState( + form: WyattFormImpl( + [ + FormInput( + AuthFormField.email, + const Email.dirty(validEmailString), + ), + FormInput( + AuthFormField.password, + const Password.dirty(validPasswordString), + ) + ], + name: AuthFormName.signUpForm, + ), status: FormStatus.valid, - data: FormData.empty(), ), ], ); }); - group('signUpFormSubmitted', () { - blocTest( + group('submit', () { + blocTest, SignUpState>( 'does nothing when status is not validated', build: () => SignUpCubit( authenticationRepository: authenticationRepository, - formData: const FormData.empty(), ), - act: (cubit) => cubit.signUpFormSubmitted(), + act: (cubit) => cubit.submit(), expect: () => const [], ); - blocTest( - 'calls signUp with correct email/password/confirmedPassword', + blocTest, SignUpState>( + 'calls signUp with correct email/password', + setUp: () { + when( + () => formRepository.accessForm(AuthFormName.signUpForm), + ).thenAnswer( + (_) => WyattFormImpl( + [ + FormInput( + AuthFormField.email, + const Email.dirty(validEmailString), + ), + FormInput( + AuthFormField.password, + const Password.dirty(validPasswordString), + ) + ], + name: AuthFormName.signUpForm, + ), + ); + }, build: () => SignUpCubit( authenticationRepository: authenticationRepository, - formData: const FormData.empty(), ), - seed: () => const SignUpState( + seed: () => SignUpState( + form: WyattFormImpl( + [ + FormInput( + AuthFormField.email, + const Email.dirty(validEmailString), + ), + FormInput( + AuthFormField.password, + const Password.dirty(validPasswordString), + ) + ], + name: AuthFormName.signUpForm, + ), status: FormStatus.valid, - email: validEmail, - password: validPassword, - data: FormData.empty(), ), - act: (cubit) => cubit.signUpFormSubmitted(), + act: (cubit) => cubit.submit(), verify: (_) { verify( () => authenticationRepository.signUp( @@ -184,37 +319,85 @@ void main() { }, ); - blocTest( + blocTest, SignUpState>( 'emits [submissionInProgress, submissionSuccess] ' 'when signUp succeeds', + setUp: () { + when( + () => formRepository.accessForm(AuthFormName.signUpForm), + ).thenAnswer( + (_) => WyattFormImpl( + [ + FormInput( + AuthFormField.email, + const Email.dirty(validEmailString), + ), + FormInput( + AuthFormField.password, + const Password.dirty(validPasswordString), + ) + ], + name: AuthFormName.signUpForm, + ), + ); + }, build: () => SignUpCubit( authenticationRepository: authenticationRepository, - formData: const FormData.empty(), ), - seed: () => const SignUpState( - status: FormStatus.valid, - email: validEmail, - password: validPassword, - data: FormData.empty(), - ), - act: (cubit) => cubit.signUpFormSubmitted(), - expect: () => [ - const SignUpState( - status: FormStatus.submissionInProgress, - email: validEmail, - password: validPassword, - data: FormData.empty(), + seed: () => SignUpState( + form: WyattFormImpl( + [ + FormInput( + AuthFormField.email, + const Email.dirty(validEmailString), + ), + FormInput( + AuthFormField.password, + const Password.dirty(validPasswordString), + ) + ], + name: AuthFormName.signUpForm, ), - const SignUpState( + status: FormStatus.valid, + ), + act: (cubit) => cubit.submit(), + expect: () => [ + SignUpState( + form: WyattFormImpl( + [ + FormInput( + AuthFormField.email, + const Email.dirty(validEmailString), + ), + FormInput( + AuthFormField.password, + const Password.dirty(validPasswordString), + ) + ], + name: AuthFormName.signUpForm, + ), + status: FormStatus.submissionInProgress, + ), + SignUpState( + form: WyattFormImpl( + [ + FormInput( + AuthFormField.email, + const Email.dirty(validEmailString), + ), + FormInput( + AuthFormField.password, + const Password.dirty(validPasswordString), + ) + ], + name: AuthFormName.signUpForm, + ), status: FormStatus.submissionSuccess, - email: validEmail, - password: validPassword, - data: FormData.empty(), ) ], ); - blocTest( + blocTest, SignUpState>( 'emits [submissionInProgress, submissionFailure] ' 'when signUp fails', setUp: () { @@ -223,31 +406,77 @@ void main() { email: any(named: 'email'), password: any(named: 'password'), ), - ).thenThrow(Exception('oops')); + ).thenAnswer((_) async => Err(ServerException())); + when( + () => formRepository.accessForm(AuthFormName.signUpForm), + ).thenAnswer( + (_) => WyattFormImpl( + [ + FormInput( + AuthFormField.email, + const Email.dirty(validEmailString), + ), + FormInput( + AuthFormField.password, + const Password.dirty(validPasswordString), + ) + ], + name: AuthFormName.signUpForm, + ), + ); }, build: () => SignUpCubit( authenticationRepository: authenticationRepository, - formData: const FormData.empty(), ), - seed: () => const SignUpState( - status: FormStatus.valid, - email: validEmail, - password: validPassword, - data: FormData.empty(), - ), - act: (cubit) => cubit.signUpFormSubmitted(), - expect: () => [ - const SignUpState( - status: FormStatus.submissionInProgress, - email: validEmail, - password: validPassword, - data: FormData.empty(), + seed: () => SignUpState( + form: WyattFormImpl( + [ + FormInput( + AuthFormField.email, + const Email.dirty(validEmailString), + ), + FormInput( + AuthFormField.password, + const Password.dirty(validPasswordString), + ) + ], + name: AuthFormName.signUpForm, ), - const SignUpState( + status: FormStatus.valid, + ), + act: (cubit) => cubit.submit(), + expect: () => [ + SignUpState( + form: WyattFormImpl( + [ + FormInput( + AuthFormField.email, + const Email.dirty(validEmailString), + ), + FormInput( + AuthFormField.password, + const Password.dirty(validPasswordString), + ) + ], + name: AuthFormName.signUpForm, + ), + status: FormStatus.submissionInProgress, + ), + SignUpState( + form: WyattFormImpl( + [ + FormInput( + AuthFormField.email, + const Email.dirty(validEmailString), + ), + FormInput( + AuthFormField.password, + const Password.dirty(validPasswordString), + ) + ], + name: AuthFormName.signUpForm, + ), status: FormStatus.submissionFailure, - email: validEmail, - password: validPassword, - data: FormData.empty(), ) ], ); diff --git a/packages/wyatt_authentication_bloc/test/sign_up/sign_up_state_test.dart b/packages/wyatt_authentication_bloc/test/sign_up/sign_up_state_test.dart index 722c3043..6e67399a 100644 --- a/packages/wyatt_authentication_bloc/test/sign_up/sign_up_state_test.dart +++ b/packages/wyatt_authentication_bloc/test/sign_up/sign_up_state_test.dart @@ -19,93 +19,37 @@ import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart'; import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; void main() { - const Email email = Email.dirty('email'); - const String passwordString = 'password'; - const Password password = Password.dirty(passwordString); + final WyattForm form = WyattFormImpl( + [ + FormInput(AuthFormField.email, const Email.pure()), + FormInput(AuthFormField.password, const Password.pure()) + ], + name: AuthFormName.signInForm, + ); group('SignUpState', () { test('supports value comparisons', () { expect( - const SignUpState( - data: FormData.empty(), - ), - const SignUpState( - data: FormData.empty(), + SignUpState( + form: form, ), + SignUpState(form: form), ); }); test('returns same object when no properties are passed', () { expect( - const SignUpState( - data: FormData.empty(), - ).copyWith(), - const SignUpState( - data: FormData.empty(), - ), + SignUpState(form: form).copyWith(), + SignUpState(form: form), ); }); test('returns object with updated status when status is passed', () { expect( - const SignUpState( - data: FormData.empty(), - ).copyWith(status: FormStatus.pure), - const SignUpState( - data: FormData.empty(), - ), - ); - }); - - test('returns object with updated email when email is passed', () { - expect( - const SignUpState( - data: FormData.empty(), - ).copyWith(email: email), - const SignUpState( - email: email, - data: FormData.empty(), - ), - ); - }); - - test('returns object with updated password when password is passed', () { - expect( - const SignUpState( - data: FormData.empty(), - ).copyWith(password: password), - const SignUpState( - password: password, - data: FormData.empty(), - ), - ); - }); - - test( - 'returns object with updated data' - ' when data is passed', () { - expect( - const SignUpState( - data: FormData.empty(), - ).copyWith( - data: const FormData( - [ - FormInput( - 'field', - Name.pure(), - ), - ], - ), - ), - const SignUpState( - data: FormData( - [ - FormInput( - 'field', - Name.pure(), - ), - ], - ), + SignUpState(form: form).copyWith(status: FormStatus.invalid), + SignUpState( + form: form, + status: FormStatus.invalid, ), ); });