master #81
@ -1,5 +1,5 @@
|
|||||||
<!--
|
<!--
|
||||||
* Copyright (C) 2022 WYATT GROUP
|
* Copyright (C) 2023 WYATT GROUP
|
||||||
* Please see the AUTHORS file for details.
|
* Please see the AUTHORS file for details.
|
||||||
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
@ -19,9 +19,7 @@
|
|||||||
# Flutter - Authentication BLoC
|
# Flutter - Authentication BLoC
|
||||||
|
|
||||||
<p align="left">
|
<p align="left">
|
||||||
<a href="https://git.wyatt-studio.fr/Wyatt-FOSS/wyatt-packages/src/branch/master/packages/wyatt_analysis">
|
<a href="https://git.wyatt-studio.fr/Wyatt-FOSS/wyatt-packages/src/branch/master/packages/wyatt_analysis"><img src="https://img.shields.io/badge/Style-Wyatt%20Analysis-blue.svg?style=flat-square" alt="Style: Wyatt Analysis" /></a>
|
||||||
<img src="https://img.shields.io/badge/Style-Wyatt%20Analysis-blue.svg?style=flat-square" alt="Style: Wyatt Analysis" />
|
|
||||||
</a>
|
|
||||||
<img src="https://img.shields.io/badge/SDK-Flutter-blue?style=flat-square" alt="SDK: Flutter" />
|
<img src="https://img.shields.io/badge/SDK-Flutter-blue?style=flat-square" alt="SDK: Flutter" />
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@ -29,37 +27,195 @@ Authentication Bloc for Flutter.
|
|||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- Wyatt Architecture
|
* 🧐 Wyatt Architecture
|
||||||
- Entities:
|
* 🧱 Entities
|
||||||
- Account : AccountModel -> Contains account information from provider
|
- Account -> Contains account information from provider.
|
||||||
- AccountWrapper : AccountWrapperModel -> Contains account and extra data.
|
- Session -> Contains account and associated data retrieved from an external source.
|
||||||
- Data Sources:
|
- AuthenticationChangeEvent -> Describes an event in authentication change (sign in, sign up, sign out, etc...)
|
||||||
- Local:
|
- SessionWrapper -> Contains latest authentication change event and session.
|
||||||
- Cached Authentication Data : AuthenticationCacheDataSourceImpl -> Provides a cache implementation
|
* 🔑 Powerful and secured authentication repository
|
||||||
- Remote:
|
* 🔥 Multiple data sources
|
||||||
- Remote Authentication Data : AuthenticationFirebaseDataSourceImpl -> Provides a proxy to FirebaseAuth
|
- Mock
|
||||||
- Repositories:
|
- Firebase
|
||||||
- AuthenticationRepository : AuthenticationRepositoryImpl -> Provides all authentication methods
|
* 🧊 Cubits, why make it complicated when you can make it simple?
|
||||||
- Features:
|
- Goes to the essential.
|
||||||
- Authentication:
|
* 📐 Consistent
|
||||||
- AuthenticationBuilder : widget to build reactive view from authentication state
|
- Every class have same naming convention
|
||||||
- AuthenticationCubit : tracks every auth changes, have sign out capability.
|
* 🧪 Tested
|
||||||
- SignUp:
|
* 📚 Documented: [available here](./doc/api/index.md)
|
||||||
- SignUpCubit: implementation of a FormDataCubit from `wyatt_form_bloc` for the sign up
|
|
||||||
- SignIn:
|
|
||||||
- SignUpCubit: implementation of a FormDataCubit from `wyatt_form_bloc` for the sign in
|
|
||||||
- Consistent
|
|
||||||
* Every class have same naming convention
|
|
||||||
- Tested
|
|
||||||
|
|
||||||
## Getting started
|
## Getting started
|
||||||
|
|
||||||
Simply add `wyatt_authentication_bloc` in `pubspec.yaml`, then
|
Simply add `wyatt_authentication_bloc` in `pubspec.yaml` , then
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart';
|
import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart';
|
||||||
```
|
```
|
||||||
|
|
||||||
## Usage
|
### Data source
|
||||||
|
|
||||||
// TODO
|
The first step is to provide a data source.
|
||||||
|
|
||||||
|
```dart
|
||||||
|
getIt.registerLazySingleton<AuthenticationRemoteDataSource<int>>(
|
||||||
|
() => AuthenticationFirebaseDataSourceImpl<int>(
|
||||||
|
firebaseAuth: FirebaseAuth.instance,
|
||||||
|
googleSignIn:
|
||||||
|
GoogleSignIn(clientId: DefaultFirebaseOptions.ios.iosClientId)),
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
> Here we use GetIt (see example project)
|
||||||
|
|
||||||
|
### Repository
|
||||||
|
|
||||||
|
Then you can configure your repository.
|
||||||
|
|
||||||
|
```dart
|
||||||
|
final AuthenticationRepository<int> authenticationRepository = AuthenticationRepositoryImpl(
|
||||||
|
authenticationRemoteDataSource:
|
||||||
|
getIt<AuthenticationRemoteDataSource<int>>(),
|
||||||
|
customPasswordValidator: const CustomPassword.pure(),
|
||||||
|
extraSignUpInputs: [
|
||||||
|
FormInput(
|
||||||
|
AuthFormField.confirmPassword,
|
||||||
|
const ConfirmedPassword.pure(),
|
||||||
|
metadata: const FormInputMetadata<void>(export: false),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
> Here we pass some extra inputs for the sign up, and a custom password validator.
|
||||||
|
|
||||||
|
### Cubits
|
||||||
|
|
||||||
|
It is necessary to implement each cubit. Don't panic, most of the work is already done 😊 you just have to customize the logic of these.
|
||||||
|
|
||||||
|
In each of these cubits it is necessary to overload the various callbacks.
|
||||||
|
|
||||||
|
> Here the associated data `Data` is a `int`
|
||||||
|
|
||||||
|
#### Authentication
|
||||||
|
|
||||||
|
In the authentication are managed, the refresh, the deletion of account or the disconnection.
|
||||||
|
|
||||||
|
```dart
|
||||||
|
class ExampleAuthenticationCubit extends AuthenticationCubit<int> {
|
||||||
|
ExampleAuthenticationCubit({required super.authenticationRepository});
|
||||||
|
|
||||||
|
@override
|
||||||
|
FutureOrResult<int?> onReauthenticate(Result<Account, AppException> result) async {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
FutureOrResult<int?> onRefresh(Result<Account, AppException> result) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
FutureOrResult<int?> onSignInFromCache(SessionWrapper<int> wrapper) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
FutureOrResult<void> onSignOut() {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
FutureOrResult<void> onDelete() {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Sign Up
|
||||||
|
|
||||||
|
```dart
|
||||||
|
class ExampleSignUpCubit extends SignUpCubit<int> {
|
||||||
|
ExampleSignUpCubit({
|
||||||
|
required super.authenticationRepository,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
FutureOrResult<int?> onSignUpWithEmailAndPassword(Result<Account, AppException> result, WyattForm form) async {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Sign In
|
||||||
|
|
||||||
|
```dart
|
||||||
|
class ExampleSignInCubit extends SignInCubit<int> {
|
||||||
|
ExampleSignInCubit({
|
||||||
|
required super.authenticationRepository,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
FutureOrResult<int?> onSignInWithEmailAndPassword(Result<Account, AppException> result, WyattForm form) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
FutureOrResult<int?> onSignInAnonymously(Result<Account, AppException> result, WyattForm form) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
FutureOrResult<int?> onSignInWithGoogle(Result<Account, AppException> result, WyattForm form) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
After setting up all these cubits you can provide them in the application. And that's it!
|
||||||
|
|
||||||
|
```dart
|
||||||
|
BlocProvider<SignUpCubit<int>>(
|
||||||
|
create: (_) => ExampleSignUpCubit(
|
||||||
|
authenticationRepository: authenticationRepository,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
BlocProvider<SignInCubit<int>>(
|
||||||
|
create: (_) => ExampleSignInCubit(
|
||||||
|
authenticationRepository: authenticationRepository,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
```
|
||||||
|
|
||||||
|
### Widgets
|
||||||
|
|
||||||
|
Widgets are provided to make your life easier. Starting with the `AuthenticationBuilder` which allows you to build according to the authentication state.
|
||||||
|
|
||||||
|
```dart
|
||||||
|
AuthenticationBuilder<int>(
|
||||||
|
authenticated: (context, sessionWrapper) => Text(
|
||||||
|
'Logged as ${sessionWrapper.session?.account.email} | GeneratedId is ${sessionWrapper.session?.data}'),
|
||||||
|
unauthenticated: (context) =>
|
||||||
|
const Text('Not logged (unauthenticated)'),
|
||||||
|
unknown: (context) => const Text('Not logged (unknown)'),
|
||||||
|
),
|
||||||
|
```
|
||||||
|
|
||||||
|
A `BuildContext` extension is also available to access certain attributes more quickly.
|
||||||
|
|
||||||
|
```dart
|
||||||
|
Text('Home | ${context.account<AuthenticationCubit<int>, int>()?.email}'),
|
||||||
|
```
|
||||||
|
|
||||||
|
Listeners are used to listen to the status of the sign in and sign up forms.
|
||||||
|
|
||||||
|
```dart
|
||||||
|
return SignInListener<int>(
|
||||||
|
onError: (context, status, errorMessage) => ScaffoldMessenger.of(context)
|
||||||
|
..hideCurrentSnackBar()
|
||||||
|
..showSnackBar(
|
||||||
|
SnackBar(content: Text(errorMessage ?? 'Sign In Failure')),
|
||||||
|
),
|
||||||
|
child: ...
|
||||||
|
);
|
||||||
|
```
|
@ -10,7 +10,6 @@ dart pub global run dartdoc --format md \
|
|||||||
--no-auto-include-dependencies \
|
--no-auto-include-dependencies \
|
||||||
--no-validate-links \
|
--no-validate-links \
|
||||||
--show-progress \
|
--show-progress \
|
||||||
--output "/Users/hpcl/Work/Wyatt/wyatt-packages/wiki/wyatt_authentication_bloc/"
|
|
||||||
|
|
||||||
sed -i -e "s/\/\/export 'package:firebase_auth\/firebase_auth.dart';/export 'package:firebase_auth\/firebase_auth.dart';/g" lib/wyatt_authentication_bloc.dart
|
sed -i -e "s/\/\/export 'package:firebase_auth\/firebase_auth.dart';/export 'package:firebase_auth\/firebase_auth.dart';/g" lib/wyatt_authentication_bloc.dart
|
||||||
sed -i -e "s/\/\/export 'package:google_sign_in\/google_sign_in.dart';/export 'package:google_sign_in\/google_sign_in.dart';/g" lib/wyatt_authentication_bloc.dart
|
sed -i -e "s/\/\/export 'package:google_sign_in\/google_sign_in.dart';/export 'package:google_sign_in\/google_sign_in.dart';/g" lib/wyatt_authentication_bloc.dart
|
||||||
|
@ -26,25 +26,49 @@ class MockAuthenticationRepository extends Mock
|
|||||||
|
|
||||||
class MockAccount extends Mock implements Account {}
|
class MockAccount extends Mock implements Account {}
|
||||||
|
|
||||||
|
class TestAuthenticationCubit extends AuthenticationCubit<int> {
|
||||||
|
TestAuthenticationCubit({required super.authenticationRepository});
|
||||||
|
|
||||||
|
@override
|
||||||
|
FutureOrResult<void> onDelete() async => const Ok(null);
|
||||||
|
|
||||||
|
@override
|
||||||
|
FutureOrResult<int?> onReauthenticate(
|
||||||
|
Result<Account, AppException> result,
|
||||||
|
) async =>
|
||||||
|
const Ok(null);
|
||||||
|
|
||||||
|
@override
|
||||||
|
FutureOrResult<int?> onRefresh(Result<Account, AppException> result) async =>
|
||||||
|
const Ok(null);
|
||||||
|
|
||||||
|
@override
|
||||||
|
FutureOrResult<int?> onSignInFromCache(SessionWrapper<int> wrapper) async =>
|
||||||
|
const Ok(null);
|
||||||
|
|
||||||
|
@override
|
||||||
|
FutureOrResult<void> onSignOut() async => const Ok(null);
|
||||||
|
}
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
group('AuthenticationCubit<T>', () {
|
group('AuthenticationCubit<T>', () {
|
||||||
final MockAccount account = MockAccount();
|
final MockAccount account = MockAccount();
|
||||||
final AccountWrapper<int> wrapper = AccountWrapperModel(account, 10);
|
final SessionWrapper<int> wrapper = SessionWrapper(
|
||||||
|
event: const UnknownAuthenticationEvent(),
|
||||||
|
session: Session(account: account, data: 10),
|
||||||
|
);
|
||||||
late AuthenticationRepository<int> authenticationRepository;
|
late AuthenticationRepository<int> authenticationRepository;
|
||||||
|
|
||||||
setUp(() {
|
setUp(() {
|
||||||
authenticationRepository = MockAuthenticationRepository();
|
authenticationRepository = MockAuthenticationRepository();
|
||||||
when(() => authenticationRepository.streamAccount()).thenAnswer(
|
when(() => authenticationRepository.sessionStream()).thenAnswer(
|
||||||
(_) => const Stream.empty(),
|
(_) => const Stream.empty(),
|
||||||
);
|
);
|
||||||
when(
|
|
||||||
() => authenticationRepository.getAccount(),
|
|
||||||
).thenAnswer((_) async => Ok(account));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('initial auth state is `unknown`', () {
|
test('initial auth state is `unknown`', () {
|
||||||
expect(
|
expect(
|
||||||
AuthenticationCubit<int>(
|
TestAuthenticationCubit(
|
||||||
authenticationRepository: authenticationRepository,
|
authenticationRepository: authenticationRepository,
|
||||||
).state,
|
).state,
|
||||||
const AuthenticationState<Never>.unknown(),
|
const AuthenticationState<Never>.unknown(),
|
||||||
@ -53,17 +77,13 @@ void main() {
|
|||||||
|
|
||||||
group('ListenForAuthenticationChanges', () {
|
group('ListenForAuthenticationChanges', () {
|
||||||
blocTest<AuthenticationCubit<int>, AuthenticationState<int>>(
|
blocTest<AuthenticationCubit<int>, AuthenticationState<int>>(
|
||||||
'emits authenticated when stream contains account',
|
'emits authenticated when stream contains session',
|
||||||
setUp: () {
|
setUp: () {
|
||||||
when(() => authenticationRepository.streamAccount()).thenAnswer(
|
when(() => authenticationRepository.sessionStream()).thenAnswer(
|
||||||
(_) => Stream.fromIterable([
|
(_) => Stream.fromIterable([wrapper]),
|
||||||
Future.value(
|
|
||||||
Ok(wrapper),
|
|
||||||
)
|
|
||||||
]),
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
build: () => AuthenticationCubit(
|
build: () => TestAuthenticationCubit(
|
||||||
authenticationRepository: authenticationRepository,
|
authenticationRepository: authenticationRepository,
|
||||||
),
|
),
|
||||||
seed: () => const AuthenticationState.unknown(),
|
seed: () => const AuthenticationState.unknown(),
|
||||||
@ -73,39 +93,12 @@ void main() {
|
|||||||
blocTest<AuthenticationCubit<int>, AuthenticationState<int>>(
|
blocTest<AuthenticationCubit<int>, AuthenticationState<int>>(
|
||||||
'emits unauthenticated when account stream is empty',
|
'emits unauthenticated when account stream is empty',
|
||||||
setUp: () {
|
setUp: () {
|
||||||
when(
|
when(() => authenticationRepository.sessionStream()).thenAnswer(
|
||||||
() => authenticationRepository.destroyCache(),
|
(_) => Stream.fromIterable(
|
||||||
).thenAnswer((_) async => const Ok(null));
|
[const SessionWrapper(event: SignedOutEvent())],),
|
||||||
when(() => authenticationRepository.streamAccount()).thenAnswer(
|
|
||||||
(_) => Stream.fromIterable([
|
|
||||||
Future.value(
|
|
||||||
Ok(AccountWrapperModel(null, 1)),
|
|
||||||
)
|
|
||||||
]),
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
build: () => AuthenticationCubit(
|
build: () => TestAuthenticationCubit(
|
||||||
authenticationRepository: authenticationRepository,
|
|
||||||
),
|
|
||||||
seed: () => const AuthenticationState.unknown(),
|
|
||||||
expect: () => [const AuthenticationState<int>.unauthenticated()],
|
|
||||||
);
|
|
||||||
|
|
||||||
blocTest<AuthenticationCubit<int>, AuthenticationState<int>>(
|
|
||||||
'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,
|
authenticationRepository: authenticationRepository,
|
||||||
),
|
),
|
||||||
seed: () => const AuthenticationState.unknown(),
|
seed: () => const AuthenticationState.unknown(),
|
||||||
@ -121,7 +114,7 @@ void main() {
|
|||||||
() => authenticationRepository.signOut(),
|
() => authenticationRepository.signOut(),
|
||||||
).thenAnswer((_) async => const Ok(null));
|
).thenAnswer((_) async => const Ok(null));
|
||||||
},
|
},
|
||||||
build: () => AuthenticationCubit(
|
build: () => TestAuthenticationCubit(
|
||||||
authenticationRepository: authenticationRepository,
|
authenticationRepository: authenticationRepository,
|
||||||
),
|
),
|
||||||
act: (cubit) => cubit.signOut(),
|
act: (cubit) => cubit.signOut(),
|
||||||
|
@ -27,7 +27,7 @@ void main() {
|
|||||||
const AuthenticationState<void> state =
|
const AuthenticationState<void> state =
|
||||||
AuthenticationState.unauthenticated();
|
AuthenticationState.unauthenticated();
|
||||||
expect(state.status, AuthenticationStatus.unauthenticated);
|
expect(state.status, AuthenticationStatus.unauthenticated);
|
||||||
expect(state.accountWrapper, null);
|
expect(state.wrapper, null);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -36,10 +36,13 @@ void main() {
|
|||||||
final MockAccount account = MockAccount();
|
final MockAccount account = MockAccount();
|
||||||
final AuthenticationState<void> state =
|
final AuthenticationState<void> state =
|
||||||
AuthenticationState.authenticated(
|
AuthenticationState.authenticated(
|
||||||
AccountWrapperModel<void>(account, null),
|
SessionWrapper<void>(
|
||||||
|
event: SignedInEvent(account: account),
|
||||||
|
session: Session(account: account),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
expect(state.status, AuthenticationStatus.authenticated);
|
expect(state.status, AuthenticationStatus.authenticated);
|
||||||
expect(state.accountWrapper?.account, account);
|
expect(state.wrapper?.session?.account, account);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -49,11 +52,14 @@ void main() {
|
|||||||
const String extra = 'AwesomeExtraData';
|
const String extra = 'AwesomeExtraData';
|
||||||
final AuthenticationState<String> state =
|
final AuthenticationState<String> state =
|
||||||
AuthenticationState.authenticated(
|
AuthenticationState.authenticated(
|
||||||
AccountWrapperModel(account, extra),
|
SessionWrapper<String>(
|
||||||
|
event: SignedInEvent(account: account),
|
||||||
|
session: Session(account: account, data: extra),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
expect(state.status, AuthenticationStatus.authenticated);
|
expect(state.status, AuthenticationStatus.authenticated);
|
||||||
expect(state.accountWrapper?.account, account);
|
expect(state.wrapper?.session?.account, account);
|
||||||
expect(state.accountWrapper?.data, extra);
|
expect(state.wrapper?.session?.data, extra);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -39,15 +39,21 @@ void main() {
|
|||||||
|
|
||||||
setUp(() {
|
setUp(() {
|
||||||
authenticationRepository = MockAuthenticationRepository();
|
authenticationRepository = MockAuthenticationRepository();
|
||||||
when(
|
account = MockAccount();
|
||||||
() => authenticationRepository.getAccount(),
|
|
||||||
).thenAnswer((_) async => Ok(account));
|
when(() => authenticationRepository.sessionStream()).thenAnswer(
|
||||||
|
(_) => Stream.fromIterable([
|
||||||
|
SessionWrapper<int>(
|
||||||
|
event: SignedInFromCacheEvent(account: account),
|
||||||
|
session: Session<int>(account: account, data: 10),
|
||||||
|
)
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
|
||||||
when(
|
when(
|
||||||
() => authenticationRepository.refresh(),
|
() => authenticationRepository.refresh(),
|
||||||
).thenAnswer((_) async => const Ok(null));
|
).thenAnswer((_) async => Ok(account));
|
||||||
|
|
||||||
account = MockAccount();
|
|
||||||
when(
|
when(
|
||||||
() => account.emailVerified,
|
() => account.emailVerified,
|
||||||
).thenAnswer((_) => true);
|
).thenAnswer((_) => true);
|
||||||
@ -129,7 +135,7 @@ void main() {
|
|||||||
setUp: () {
|
setUp: () {
|
||||||
when(
|
when(
|
||||||
() => authenticationRepository.refresh(),
|
() => authenticationRepository.refresh(),
|
||||||
).thenAnswer((_) async => const Ok(null));
|
).thenAnswer((_) async => Ok(account));
|
||||||
},
|
},
|
||||||
build: () => EmailVerificationCubit(
|
build: () => EmailVerificationCubit(
|
||||||
authenticationRepository: authenticationRepository,
|
authenticationRepository: authenticationRepository,
|
||||||
@ -145,7 +151,7 @@ void main() {
|
|||||||
setUp: () {
|
setUp: () {
|
||||||
when(
|
when(
|
||||||
() => authenticationRepository.refresh(),
|
() => authenticationRepository.refresh(),
|
||||||
).thenAnswer((_) async => const Ok(null));
|
).thenAnswer((_) async => Ok(account));
|
||||||
when(() => account.emailVerified).thenAnswer((_) => false);
|
when(() => account.emailVerified).thenAnswer((_) => false);
|
||||||
},
|
},
|
||||||
build: () => EmailVerificationCubit(
|
build: () => EmailVerificationCubit(
|
||||||
@ -161,7 +167,7 @@ void main() {
|
|||||||
'emits success with true if verified',
|
'emits success with true if verified',
|
||||||
setUp: () {
|
setUp: () {
|
||||||
when(() => authenticationRepository.refresh())
|
when(() => authenticationRepository.refresh())
|
||||||
.thenAnswer((_) async => const Ok(null));
|
.thenAnswer((_) async => Ok(account));
|
||||||
},
|
},
|
||||||
build: () => EmailVerificationCubit(
|
build: () => EmailVerificationCubit(
|
||||||
authenticationRepository: authenticationRepository,
|
authenticationRepository: authenticationRepository,
|
||||||
@ -183,7 +189,7 @@ void main() {
|
|||||||
'emits success with false if not verified',
|
'emits success with false if not verified',
|
||||||
setUp: () {
|
setUp: () {
|
||||||
when(() => authenticationRepository.refresh())
|
when(() => authenticationRepository.refresh())
|
||||||
.thenAnswer((_) async => const Ok(null));
|
.thenAnswer((_) async => Ok(account));
|
||||||
when(() => account.emailVerified).thenAnswer((_) => false);
|
when(() => account.emailVerified).thenAnswer((_) => false);
|
||||||
},
|
},
|
||||||
build: () => EmailVerificationCubit(
|
build: () => EmailVerificationCubit(
|
||||||
@ -222,28 +228,6 @@ void main() {
|
|||||||
)
|
)
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
blocTest<EmailVerificationCubit<int>, 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,
|
|
||||||
)
|
|
||||||
],
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -59,14 +59,7 @@ void main() {
|
|||||||
formRepository = MockFormRepository();
|
formRepository = MockFormRepository();
|
||||||
|
|
||||||
when(
|
when(
|
||||||
() => authenticationRepository.signUp(
|
() => authenticationRepository.signUpWithEmailAndPassword(
|
||||||
email: any(named: 'email'),
|
|
||||||
password: any(named: 'password'),
|
|
||||||
),
|
|
||||||
).thenAnswer((_) async => Ok(account));
|
|
||||||
|
|
||||||
when(
|
|
||||||
() => authenticationRepository.signInWithEmailAndPassword(
|
|
||||||
email: any(named: 'email'),
|
email: any(named: 'email'),
|
||||||
password: any(named: 'password'),
|
password: any(named: 'password'),
|
||||||
),
|
),
|
||||||
@ -318,7 +311,7 @@ void main() {
|
|||||||
act: (cubit) => cubit.signUpWithEmailPassword(),
|
act: (cubit) => cubit.signUpWithEmailPassword(),
|
||||||
verify: (_) {
|
verify: (_) {
|
||||||
verify(
|
verify(
|
||||||
() => authenticationRepository.signUp(
|
() => authenticationRepository.signUpWithEmailAndPassword(
|
||||||
email: validEmailString,
|
email: validEmailString,
|
||||||
password: validPasswordString,
|
password: validPasswordString,
|
||||||
),
|
),
|
||||||
@ -409,7 +402,7 @@ void main() {
|
|||||||
'when signUp fails',
|
'when signUp fails',
|
||||||
setUp: () {
|
setUp: () {
|
||||||
when(
|
when(
|
||||||
() => authenticationRepository.signUp(
|
() => authenticationRepository.signUpWithEmailAndPassword(
|
||||||
email: any(named: 'email'),
|
email: any(named: 'email'),
|
||||||
password: any(named: 'password'),
|
password: any(named: 'password'),
|
||||||
),
|
),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user