Skip to content

Commit

Permalink
Merge pull request #37 from ucmazmehmet/main
Browse files Browse the repository at this point in the history
Unittest and bloc enhancement
  • Loading branch information
cevheri authored Nov 27, 2024
2 parents f40fae8 + f73d994 commit 99f7a01
Show file tree
Hide file tree
Showing 9 changed files with 529 additions and 26 deletions.
18 changes: 17 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,23 @@ bash

git push origin your-branch-name

6. Create a Pull Request
6. Before Pull Request !!!
- sync your fork on GitHub
- git pull on your local machine
- resolve conflicts
- run commands sequentially
```shell
flutter clean
flutter pub get
dart run build_runner build --delete-conflicting-outputs
dart run intl_utils:generate
flutter analyze
flutter test --coverage
```
- fix errors if needed


7. Create a Pull Request

Navigate to the original repository and click the "New Pull Request" button. Select your branch and provide a clear description of your changes.
Description: Provide a concise summary of what you have changed and why.
Expand Down
1 change: 1 addition & 0 deletions lib/configuration/app_key_constants.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const Key loginButtonForgotPasswordKey = Key("loginButtonForgotPasswordKey");
const Key loginButtonRegisterKey = Key("loginButtonRegisterKey");
const Key loginButtonPasswordVisibilityKey = Key("loginButtonPasswordVisibilityKey");
const Key forgotPasswordButtonSubmit = Key("forgotPasswordButtonSubmit");
const Key forgotPasswordTextFieldEmail = Key("forgotPasswordTextFieldEmail");

// register screen
const Key registerSubmitButtonKey = Key("registerSubmitButtonKey");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'dart:io';
import 'package:equatable/equatable.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_bloc_advance/configuration/app_logger.dart';
import 'package:flutter_bloc_advance/data/app_api_exception.dart';

import '../../../../data/repository/account_repository.dart';

Expand All @@ -16,7 +17,7 @@ class ForgotPasswordBloc extends Bloc<ForgotPasswordEvent, ForgotPasswordState>

ForgotPasswordBloc({required AccountRepository repository})
: _repository = repository,
super(const ForgotPasswordState()) {
super(const ForgotPasswordInitialState()) {
on<ForgotPasswordEmailChanged>(_onSubmit);
}

Expand All @@ -31,16 +32,18 @@ class ForgotPasswordBloc extends Bloc<ForgotPasswordEvent, ForgotPasswordState>

FutureOr<void> _onSubmit(ForgotPasswordEmailChanged event, Emitter<ForgotPasswordState> emit) async {
_log.debug("BEGIN: forgotPassword bloc: _onSubmit");
emit(AccountResetPasswordInitialState());
emit(const ForgotPasswordLoadingState());
try {
String result = event.email.replaceAll('"', '');
var resultStatusCode = await _repository.resetPassword(result);
resultStatusCode < HttpStatus.badRequest
? emit(AccountResetPasswordCompletedState())
: emit(const AccountResetPasswordErrorState(message: "Reset Password Error"));
if(resultStatusCode < HttpStatus.badRequest){
emit(const ForgotPasswordCompletedState());
}else {
throw BadRequestException("API Error");
}
_log.debug("END: forgotPassword bloc: _onSubmit success: {}", [resultStatusCode.toString()]);
} catch (e) {
emit(const AccountResetPasswordErrorState(message: "Reset Password Error"));
emit(const ForgotPasswordErrorState(message: "Reset Password Error"));
_log.error("END: forgotPassword bloc: _onSubmit error: {}", [e.toString()]);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,7 @@ abstract class ForgotPasswordEvent extends Equatable {
const ForgotPasswordEvent();

@override
List<Object> get props => [];

@override
bool get stringify => true;
bool? get stringify => true;
}

class ForgotPasswordEmailChanged extends ForgotPasswordEvent {
Expand All @@ -16,4 +13,7 @@ class ForgotPasswordEmailChanged extends ForgotPasswordEvent {
const ForgotPasswordEmailChanged({
required this.email,
});

@override
List<Object> get props => [email];
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
part of 'forgot_password_bloc.dart';

enum ForgotPasswordStatus { none, authenticating, authenticated, failure }
enum ForgotPasswordStatus { initial, loading, success, failure }

class ForgotPasswordState extends Equatable {
final String email;
final String? email;
final ForgotPasswordStatus status;

static const String authenticationFailKey = 'error.authenticate';

const ForgotPasswordState({
this.email = '',
this.status = ForgotPasswordStatus.none,
this.email,
this.status = ForgotPasswordStatus.initial,
});

ForgotPasswordState copyWith({
Expand All @@ -24,18 +24,30 @@ class ForgotPasswordState extends Equatable {
}

@override
List<Object> get props => [email, status];
List<Object> get props => [status, email ?? ""];

@override
bool get stringify => true;
}

class AccountResetPasswordInitialState extends ForgotPasswordState {}
class ForgotPasswordInitialState extends ForgotPasswordState {
const ForgotPasswordInitialState() : super(status: ForgotPasswordStatus.initial);
}

class ForgotPasswordLoadingState extends ForgotPasswordState {
const ForgotPasswordLoadingState() : super(status: ForgotPasswordStatus.loading);
}

class AccountResetPasswordCompletedState extends ForgotPasswordState {}

class AccountResetPasswordErrorState extends ForgotPasswordState {
class ForgotPasswordCompletedState extends ForgotPasswordState {
const ForgotPasswordCompletedState() : super(status: ForgotPasswordStatus.success);
}

class ForgotPasswordErrorState extends ForgotPasswordState {
final String message;

const AccountResetPasswordErrorState({required this.message});
const ForgotPasswordErrorState({required this.message}) : super(status: ForgotPasswordStatus.failure);

@override
List<Object> get props => [status, message];
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,7 @@ class ForgotPasswordScreen extends StatelessWidget {
}

_buildAppBar(BuildContext context) {
return AppBar(
title: Text(S.of(context).password_forgot),
);
return AppBar(title: Text(S.of(context).password_forgot));
}

_buildBody(BuildContext context) {
Expand Down Expand Up @@ -62,6 +60,7 @@ class ForgotPasswordScreen extends StatelessWidget {
return SizedBox(
width: MediaQuery.of(context).size.width * 0.6,
child: FormBuilderTextField(
key: forgotPasswordTextFieldEmail,
name: "email",
decoration: InputDecoration(labelText: S.of(context).email),
maxLines: 1,
Expand Down Expand Up @@ -103,15 +102,15 @@ class ForgotPasswordScreen extends StatelessWidget {
),
);
}, buildWhen: (previous, current) {
if (current is AccountResetPasswordInitialState) {
if (current is ForgotPasswordInitialState) {
Message.getMessage(context: context, title: S.of(context).loading, content: "");
}
if (current is AccountResetPasswordCompletedState) {
if (current is ForgotPasswordCompletedState) {
Navigator.pop(context);
Message.getMessage(context: context, title: S.of(context).success, content: "");
Future.delayed(const Duration(seconds: 1), () {});
}
if (current is AccountResetPasswordErrorState) {
if (current is ForgotPasswordErrorState) {
Message.errorMessage(title: S.of(context).failed, context: context, content: "");
}
return true;
Expand Down
142 changes: 142 additions & 0 deletions test/presentation/blocs/forgot_password_bloc_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
import 'dart:io';

import 'package:bloc_test/bloc_test.dart';
import 'package:flutter_bloc_advance/data/app_api_exception.dart';
import 'package:flutter_bloc_advance/data/repository/account_repository.dart';
import 'package:flutter_bloc_advance/presentation/screen/forgot_password/bloc/forgot_password_bloc.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';

import '../../test_utils.dart';
import 'forgot_password_bloc_test.mocks.dart';

@GenerateMocks([AccountRepository])
void main() {
//region main setup
late AccountRepository repository;

setUpAll(() async{
await TestUtils().setupUnitTest();
repository = MockAccountRepository();
});

tearDown(() async {
await TestUtils().tearDownUnitTest();
});
//endregion setup

//region event
group('ForgotPasswordEvent Tests', () {
test('ForgotPasswordEmailChanged should correctly store the email', () {
// Arrange
const email = 'test@example.com';

// Act
const event = ForgotPasswordEmailChanged(email: email);

// Assert
expect(event.email, email);
});

test('ForgotPasswordEmailChanged should be equatable', () {
// Arrange
const email = 'test@example.com';
// Act
const event = ForgotPasswordEmailChanged(email: email);
// Assert
expect(event, equals(event));
});

// Props and Stringify Test
test('ForgotPasswordEvent should have props and stringify', () {
// Arrange
const email = 'test@example.com';
const event = ForgotPasswordEmailChanged(email: email);

// Assert
expect(event.stringify, true);
expect(event.props, [email]);
expect(event.toString(), contains(email));
});
});
//endregion event

//region state
/// ForgotPassword State Tests
group('ForgotPassword State Tests', () {
//ForgotPasswordState
test("supports value comparisons", () {
expect(const ForgotPasswordState(), const ForgotPasswordState());
const state = ForgotPasswordState(
status: ForgotPasswordStatus.initial,
);
expect(const ForgotPasswordState(), state);
});

//ForgotPasswordState İnitial Test
test('initial state is ForgotPasswordState', () {
expect(ForgotPasswordBloc(repository: repository).state, const ForgotPasswordInitialState());
});

//ForgotPasswordInitialState Test
test("ForgotPasswordInitialState", () {
expect(const ForgotPasswordInitialState(), const ForgotPasswordInitialState());
});

//ForgotPasswordCompletedState Test
test("ForgotPasswordCompletedState", () {
expect(const ForgotPasswordCompletedState(), const ForgotPasswordCompletedState());
});

// ForgotPasswordErrorState Test
test("ForgotPasswordErrorState", () {
expect(const ForgotPasswordErrorState(message: "Reset Password Error"), const ForgotPasswordErrorState(message: "Reset Password Error"));
//expect(const ForgotPasswordErrorState(message: "Reset Password Error", ["Reset Password Error"]);
});

test("copyWith retains the same values if no arguments are provided", () {
const state = ForgotPasswordState(status: ForgotPasswordStatus.failure, email: "test@example.com");
expect(state.copyWith(), state);
});

test("props", () {
expect(const ForgotPasswordState(status: ForgotPasswordStatus.initial, email: 'test@example.com').props,
[ForgotPasswordStatus.initial, "test@example.com"]);
});

test("initial state is ForgotPasswordState", () {
expect(ForgotPasswordBloc(repository: repository).state, const ForgotPasswordInitialState());
});
});
//endregion state

//region bloc
group("ForgotPassword Bloc Test", () {
const email = "test@test.com";
blocTest<ForgotPasswordBloc, ForgotPasswordState>(
'emits [ForgotPasswordLoadingState, ForgotPasswordCompletedState] when resetPassword is successful',
setUp: () => when(repository.resetPassword(email)).thenAnswer((_) => Future.value(HttpStatus.ok)),
build: () => ForgotPasswordBloc(repository: repository),
act: (bloc) => bloc..add(const ForgotPasswordEmailChanged(email: email)),
expect: () => [const ForgotPasswordLoadingState(), const ForgotPasswordCompletedState()],
);

blocTest<ForgotPasswordBloc, ForgotPasswordState>(
'emits [ForgotPasswordLoadingState, ForgotPasswordErrorState] when resetPassword fails',
setUp: () => when(repository.resetPassword(email)).thenAnswer((_) => Future.value(HttpStatus.badRequest)),
build: () => ForgotPasswordBloc(repository: repository),
act: (bloc) => bloc..add(const ForgotPasswordEmailChanged(email: email)),
expect: () => [const ForgotPasswordLoadingState(), const ForgotPasswordErrorState(message: "Reset Password Error")],
);
blocTest<ForgotPasswordBloc, ForgotPasswordState>(
'emits [ForgotPasswordLoadingState, ForgotPasswordErrorState] when resetPassword fails',
setUp: () => when(repository.resetPassword(email)).thenThrow(BadRequestException()),
build: () => ForgotPasswordBloc(repository: repository),
act: (bloc) => bloc..add(const ForgotPasswordEmailChanged(email: 'invalid-email')),
expect: () => [const ForgotPasswordLoadingState(), const ForgotPasswordErrorState(message: "Reset Password Error")],
);

});
//endregion bloc
}
Loading

0 comments on commit 99f7a01

Please sign in to comment.