Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create BLoC for get top headlines news #17

Merged
merged 1 commit into from
Apr 20, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions lib/feature/presentation/bloc/topheadlinesnews/bloc.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export 'top_headlines_news_bloc.dart';
export 'top_headlines_news_event.dart';
export 'top_headlines_news_state.dart';
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import 'dart:async';

import 'package:bloc/bloc.dart';
import 'package:flutter_news_app/core/error/failure.dart';
import 'package:flutter_news_app/core/usecase/usecase.dart';
import 'package:flutter_news_app/feature/domain/usecase/gettopheadlinesnews/get_top_headlines_news.dart';
import 'package:meta/meta.dart';

import './bloc.dart';

class TopHeadlinesNewsBloc extends Bloc<TopHeadlinesNewsEvent, TopHeadlinesNewsState> {
final GetTopHeadlinesNews getTopHeadlinesNews;

TopHeadlinesNewsBloc({@required this.getTopHeadlinesNews}) : assert(getTopHeadlinesNews != null);

@override
TopHeadlinesNewsState get initialState => InitialTopHeadlinesNewsState();

@override
Stream<TopHeadlinesNewsState> mapEventToState(
TopHeadlinesNewsEvent event,
) async* {
if (event is LoadTopHeadlinesNewsEvent) {
yield* _mapLoadTopHeadlinesNewsEventToState();
}
}

Stream<TopHeadlinesNewsState> _mapLoadTopHeadlinesNewsEventToState() async* {
yield LoadingTopHeadlinesNewsState();
var response = await getTopHeadlinesNews(NoParams());
yield response.fold(
// ignore: missing_return
(failure) {
if (failure is ServerFailure) {
return FailureTopHeadlinesNewsState(errorMessage: failure.errorMessage);
} else if (failure is ConnectionFailure) {
return FailureTopHeadlinesNewsState(errorMessage: failure.errorMessage);
}
},
(data) => LoadedTopHeadlinesNewsState(listArticles: data.articles),
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import 'package:equatable/equatable.dart';

abstract class TopHeadlinesNewsEvent extends Equatable {
const TopHeadlinesNewsEvent();

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

class LoadTopHeadlinesNewsEvent extends TopHeadlinesNewsEvent {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import 'package:equatable/equatable.dart';
import 'package:flutter_news_app/feature/data/model/topheadlinesnews/top_headlines_news_response_model.dart';

abstract class TopHeadlinesNewsState extends Equatable {
const TopHeadlinesNewsState();

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

class InitialTopHeadlinesNewsState extends TopHeadlinesNewsState {}

class LoadingTopHeadlinesNewsState extends TopHeadlinesNewsState {}

class LoadedTopHeadlinesNewsState extends TopHeadlinesNewsState {
final List<ItemArticleTopHeadlinesNewsResponseModel> listArticles;

LoadedTopHeadlinesNewsState({this.listArticles});

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

@override
String toString() {
return 'LoadedTopHeadlinesNewsState{listArticles: $listArticles}';
}
}

class FailureTopHeadlinesNewsState extends TopHeadlinesNewsState {
final String errorMessage;

FailureTopHeadlinesNewsState({this.errorMessage});

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

@override
String toString() {
return 'FailureTopHeadlinesNewsState{errorMessage: $errorMessage}';
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
import 'dart:convert';

import 'package:bloc_test/bloc_test.dart';
import 'package:dartz/dartz.dart';
import 'package:flutter_news_app/core/error/failure.dart';
import 'package:flutter_news_app/core/usecase/usecase.dart';
import 'package:flutter_news_app/feature/data/model/topheadlinesnews/top_headlines_news_response_model.dart';
import 'package:flutter_news_app/feature/domain/usecase/gettopheadlinesnews/get_top_headlines_news.dart';
import 'package:flutter_news_app/feature/presentation/bloc/topheadlinesnews/bloc.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/mockito.dart';

import '../../../../fixture/fixture_reader.dart';

class MockGetTopHeadlinesNews extends Mock implements GetTopHeadlinesNews {}

void main() {
MockGetTopHeadlinesNews mockGetTopHeadlinesNews;
TopHeadlinesNewsBloc topHeadlinesNewsBloc;

setUp(() {
mockGetTopHeadlinesNews = MockGetTopHeadlinesNews();
topHeadlinesNewsBloc = TopHeadlinesNewsBloc(getTopHeadlinesNews: mockGetTopHeadlinesNews);
});

tearDown(() {
topHeadlinesNewsBloc?.close();
});

test(
'make sure that AssertionError will be called when accepting null arguments',
() async {
// assert
expect(() => TopHeadlinesNewsBloc(getTopHeadlinesNews: null), throwsAssertionError);
},
);

test(
'make sure that initialState must be InitialTopHeadlinesNewsState',
() async {
// assert
expect(topHeadlinesNewsBloc.initialState, InitialTopHeadlinesNewsState());
},
);

test(
'make sure that no state are emitted when TopHeadlinesNewsBloc is closed',
() async {
// act
await topHeadlinesNewsBloc.close();

// assert
await expectLater(topHeadlinesNewsBloc, emitsInOrder([InitialTopHeadlinesNewsState(), emitsDone]));
},
);

group('LoadTopHeadlinesNews', () {
final tTopHeadlinesNewsResponseModel = TopHeadlinesNewsResponseModel.fromJson(
json.decode(
fixture('top_headlines_news_response_model.json'),
),
);

test(
'make sure that the GetTopHeadlinesNews use case is really called',
() async {
// arrange
when(mockGetTopHeadlinesNews(any)).thenAnswer((_) async => Right(tTopHeadlinesNewsResponseModel));

// act
topHeadlinesNewsBloc.add(LoadTopHeadlinesNewsEvent());
await untilCalled(mockGetTopHeadlinesNews(any));

// assert
verify(mockGetTopHeadlinesNews(NoParams()));
},
);

blocTest(
'make sure to emit [LoadingTopHeadlinesNewsState, LoadedTopHeadlinesNewsState] when receive '
'LoadTopHeadlinesNewsEvent with a successful process',
build: () async {
// arrange
when(mockGetTopHeadlinesNews(any)).thenAnswer((_) async => Right(tTopHeadlinesNewsResponseModel));
return topHeadlinesNewsBloc;
},
act: (bloc) {
// act
return bloc.add(LoadTopHeadlinesNewsEvent());
},
expect: [
LoadingTopHeadlinesNewsState(),
LoadedTopHeadlinesNewsState(listArticles: tTopHeadlinesNewsResponseModel.articles),
],
verify: (_) async {
verify(mockGetTopHeadlinesNews(NoParams())).called(1);
},
);

blocTest(
'make sure to emit [LoadingTopHeadlinesNewsState, FailureTopHeadlinesNewsState] when receive '
'LoadTopHeadlinesNewsEvent with a failed process from endpoint',
build: () async {
// arrange
when(mockGetTopHeadlinesNews(any)).thenAnswer(
(_) async => Left(
ServerFailure('testErrorMessage'),
),
);
return topHeadlinesNewsBloc;
},
act: (bloc) {
// act
return bloc.add(LoadTopHeadlinesNewsEvent());
},
expect: [
LoadingTopHeadlinesNewsState(),
FailureTopHeadlinesNewsState(errorMessage: 'testErrorMessage'),
],
verify: (_) async {
verify(mockGetTopHeadlinesNews(NoParams())).called(1);
},
);

blocTest(
'make sure to emit [LoadingTopHeadlinesNewsState, FailureTopHeadlinesNewsState] when the internet '
'connection has a problem',
build: () async {
when(mockGetTopHeadlinesNews(any)).thenAnswer((_) async => Left(ConnectionFailure()));
return topHeadlinesNewsBloc;
},
act: (bloc) {
return bloc.add(LoadTopHeadlinesNewsEvent());
},
expect: [
LoadingTopHeadlinesNewsState(),
FailureTopHeadlinesNewsState(errorMessage: messageConnectionFailure),
],
verify: (_) async {
verify(mockGetTopHeadlinesNews(NoParams())).called(1);
});
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import 'package:flutter_news_app/feature/presentation/bloc/topheadlinesnews/bloc.dart';
import 'package:flutter_test/flutter_test.dart';

void main() {
group('LoadTopHeadlinesNews', () {
test(
'make sure the props value is []',
() async {
// assert
expect(LoadTopHeadlinesNewsEvent().props, []);
},
);

test(
'make sure the output of the toString function',
() async {
// assert
expect(LoadTopHeadlinesNewsEvent().toString(), 'LoadTopHeadlinesNewsEvent');
},
);
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import 'dart:convert';

import 'package:flutter_news_app/feature/data/model/topheadlinesnews/top_headlines_news_response_model.dart';
import 'package:flutter_news_app/feature/presentation/bloc/topheadlinesnews/bloc.dart';
import 'package:flutter_test/flutter_test.dart';

import '../../../../fixture/fixture_reader.dart';

void main() {
group('InitialTopHeadlinesNewsState', () {
test(
'make sure the props value is []',
() async {
// assert
expect(InitialTopHeadlinesNewsState().props, []);
},
);

test(
'make sure the output of the toString function',
() async {
// assert
expect(InitialTopHeadlinesNewsState().toString(), 'InitialTopHeadlinesNewsState');
},
);
});

group('LoadingTopHeadlinesNewsState', () {
test(
'make sure the props value is []',
() async {
// assert
expect(LoadingTopHeadlinesNewsState().props, []);
},
);

test(
'make sure the output of the toString function',
() async {
// assert
expect(LoadingTopHeadlinesNewsState().toString(), 'LoadingTopHeadlinesNewsState');
},
);
});

group('LoadedTopHeadlinesNewsState', () {
final tTopHeadlinesNewsResponseModel = TopHeadlinesNewsResponseModel.fromJson(
json.decode(
fixture('top_headlines_news_response_model.json'),
),
);
final tListArticles = tTopHeadlinesNewsResponseModel.articles;
final tLoadedTopHeadlinesNewsState = LoadedTopHeadlinesNewsState(listArticles: tListArticles);

test(
'make sure the props value is [listArticles]',
() async {
// assert
expect(tLoadedTopHeadlinesNewsState.props, [tListArticles]);
},
);

test(
'make sure the output of the toString function',
() async {
// assert
expect(tLoadedTopHeadlinesNewsState.toString(), 'LoadedTopHeadlinesNewsState{listArticles: $tListArticles}');
},
);
});

group('FailureTopHeadlinesNewsState', () {
final tErrorMessage = 'testErrorMessage';
final tFailureTopHeadlinesNewsState = FailureTopHeadlinesNewsState(errorMessage: tErrorMessage);

test(
'make sure the props value is [errorMessage]',
() async {
// assert
expect(tFailureTopHeadlinesNewsState.props, [tErrorMessage]);
},
);

test(
'make sure the output of the toString function',
() async {
// assert
expect(tFailureTopHeadlinesNewsState.toString(), 'FailureTopHeadlinesNewsState{errorMessage: $tErrorMessage}');
},
);
});
}