Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 1cc796e

Browse files
Added logic search news in bloc
1 parent d045a95 commit 1cc796e

File tree

6 files changed

+216
-3
lines changed

6 files changed

+216
-3
lines changed

‎lib/feature/presentation/bloc/topheadlinesnews/top_headlines_news_bloc.dart

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,20 @@ import 'dart:async';
33
import 'package:bloc/bloc.dart';
44
import 'package:flutter_news_app/core/error/failure.dart';
55
import 'package:flutter_news_app/feature/domain/usecase/gettopheadlinesnews/get_top_headlines_news.dart';
6+
import 'package:flutter_news_app/feature/domain/usecase/searchtopheadlinesnews/search_top_headlines_news.dart';
67
import 'package:meta/meta.dart';
78

89
import './bloc.dart';
910

1011
class TopHeadlinesNewsBloc extends Bloc<TopHeadlinesNewsEvent, TopHeadlinesNewsState> {
1112
final GetTopHeadlinesNews getTopHeadlinesNews;
13+
final SearchTopHeadlinesNews searchTopHeadlinesNews;
1214

13-
TopHeadlinesNewsBloc({@required this.getTopHeadlinesNews}) : assert(getTopHeadlinesNews != null);
15+
TopHeadlinesNewsBloc({
16+
@required this.getTopHeadlinesNews,
17+
@required this.searchTopHeadlinesNews,
18+
}) : assert(getTopHeadlinesNews != null),
19+
assert(searchTopHeadlinesNews != null);
1420

1521
@override
1622
TopHeadlinesNewsState get initialState => InitialTopHeadlinesNewsState();
@@ -23,6 +29,8 @@ class TopHeadlinesNewsBloc extends Bloc<TopHeadlinesNewsEvent, TopHeadlinesNewsS
2329
yield* _mapLoadTopHeadlinesNewsEventToState(event);
2430
} else if (event is ChangeCategoryTopHeadlinesNewsEvent) {
2531
yield* _mapChangeCategoryTopHeadlinesNewsEventToState(event);
32+
} else if (event is SearchTopHeadlinesNewsEvent) {
33+
yield* _mapSearchTopHeadlinesNewsEventToState(event);
2634
}
2735
}
2836

@@ -47,4 +55,20 @@ class TopHeadlinesNewsBloc extends Bloc<TopHeadlinesNewsEvent, TopHeadlinesNewsS
4755
) async* {
4856
yield ChangedCategoryTopHeadlinesNewsState(indexCategorySelected: event.indexCategorySelected);
4957
}
58+
59+
Stream<TopHeadlinesNewsState> _mapSearchTopHeadlinesNewsEventToState(SearchTopHeadlinesNewsEvent event) async* {
60+
yield LoadingTopHeadlinesNewsState();
61+
var result = await searchTopHeadlinesNews(ParamsSearchTopHeadlinesNews(keyword: event.keyword));
62+
yield result.fold(
63+
// ignore: missing_return
64+
(failure) {
65+
if (failure is ServerFailure) {
66+
return FailureTopHeadlinesNewsState(errorMessage: failure.errorMessage);
67+
} else if (failure is ConnectionFailure) {
68+
return FailureTopHeadlinesNewsState(errorMessage: failure.errorMessage);
69+
}
70+
},
71+
(response) => SearchSuccessTopHeadlinesNewsState(listArticles: response.articles),
72+
);
73+
}
5074
}

‎lib/feature/presentation/bloc/topheadlinesnews/top_headlines_news_event.dart

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,18 @@ class ChangeCategoryTopHeadlinesNewsEvent extends TopHeadlinesNewsEvent {
3131
String toString() {
3232
return 'ChangeCategoryTopHeadlinesNewsEvent{indexCategorySelected: $indexCategorySelected}';
3333
}
34+
}
35+
36+
class SearchTopHeadlinesNewsEvent extends TopHeadlinesNewsEvent {
37+
final String keyword;
38+
39+
SearchTopHeadlinesNewsEvent({@required this.keyword});
40+
41+
@override
42+
List<Object> get props => [keyword];
43+
44+
@override
45+
String toString() {
46+
return 'SearchTopHeadlinesNewsEvent{keyword: $keyword}';
47+
}
3448
}

‎lib/feature/presentation/bloc/topheadlinesnews/top_headlines_news_state.dart

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,4 +52,18 @@ class ChangedCategoryTopHeadlinesNewsState extends TopHeadlinesNewsState {
5252
String toString() {
5353
return 'ChangedCategoryTopHeadlinesNewsState{indexCategorySelected: $indexCategorySelected}';
5454
}
55+
}
56+
57+
class SearchSuccessTopHeadlinesNewsState extends TopHeadlinesNewsState {
58+
final List<ItemArticleTopHeadlinesNewsResponseModel> listArticles;
59+
60+
SearchSuccessTopHeadlinesNewsState({this.listArticles});
61+
62+
@override
63+
List<Object> get props => [listArticles];
64+
65+
@override
66+
String toString() {
67+
return 'SearchSuccessTopHeadlinesNewsState{listArticles: $listArticles}';
68+
}
5569
}

‎test/feature/presentation/bloc/topheadlinesnews/top_headlines_news_bloc_test.dart

Lines changed: 104 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import 'package:dartz/dartz.dart';
55
import 'package:flutter_news_app/core/error/failure.dart';
66
import 'package:flutter_news_app/feature/data/model/topheadlinesnews/top_headlines_news_response_model.dart';
77
import 'package:flutter_news_app/feature/domain/usecase/gettopheadlinesnews/get_top_headlines_news.dart';
8+
import 'package:flutter_news_app/feature/domain/usecase/searchtopheadlinesnews/search_top_headlines_news.dart';
89
import 'package:flutter_news_app/feature/presentation/bloc/topheadlinesnews/bloc.dart';
910
import 'package:flutter_test/flutter_test.dart';
1011
import 'package:mockito/mockito.dart';
@@ -13,13 +14,20 @@ import '../../../../fixture/fixture_reader.dart';
1314

1415
class MockGetTopHeadlinesNews extends Mock implements GetTopHeadlinesNews {}
1516

17+
class MockSearchTopHeadlinesNews extends Mock implements SearchTopHeadlinesNews {}
18+
1619
void main() {
1720
MockGetTopHeadlinesNews mockGetTopHeadlinesNews;
21+
MockSearchTopHeadlinesNews mockSearchTopHeadlinesNews;
1822
TopHeadlinesNewsBloc topHeadlinesNewsBloc;
1923

2024
setUp(() {
2125
mockGetTopHeadlinesNews = MockGetTopHeadlinesNews();
22-
topHeadlinesNewsBloc = TopHeadlinesNewsBloc(getTopHeadlinesNews: mockGetTopHeadlinesNews);
26+
mockSearchTopHeadlinesNews = MockSearchTopHeadlinesNews();
27+
topHeadlinesNewsBloc = TopHeadlinesNewsBloc(
28+
getTopHeadlinesNews: mockGetTopHeadlinesNews,
29+
searchTopHeadlinesNews: mockSearchTopHeadlinesNews,
30+
);
2331
});
2432

2533
tearDown(() {
@@ -30,7 +38,20 @@ void main() {
3038
'make sure that AssertionError will be called when accepting null arguments',
3139
() async {
3240
// assert
33-
expect(() => TopHeadlinesNewsBloc(getTopHeadlinesNews: null), throwsAssertionError);
41+
expect(
42+
() => TopHeadlinesNewsBloc(
43+
getTopHeadlinesNews: null,
44+
searchTopHeadlinesNews: mockSearchTopHeadlinesNews,
45+
),
46+
throwsAssertionError,
47+
);
48+
expect(
49+
() => TopHeadlinesNewsBloc(
50+
getTopHeadlinesNews: mockGetTopHeadlinesNews,
51+
searchTopHeadlinesNews: null,
52+
),
53+
throwsAssertionError,
54+
);
3455
},
3556
);
3657

@@ -156,4 +177,85 @@ void main() {
156177
],
157178
);
158179
});
180+
181+
group('SearchTopHeadlinesNews', () {
182+
final tKeyword = 'testKeyword';
183+
final tTopHeadlinesNewsResponseModel = TopHeadlinesNewsResponseModel.fromJson(
184+
json.decode(
185+
fixture('top_headlines_news_response_model.json'),
186+
),
187+
);
188+
189+
test(
190+
'make sure that the SearchTopHeadlinesNews use case is really called',
191+
() async {
192+
// arrange
193+
when(mockSearchTopHeadlinesNews(any)).thenAnswer((_) async => Right(tTopHeadlinesNewsResponseModel));
194+
195+
// act
196+
topHeadlinesNewsBloc.add(SearchTopHeadlinesNewsEvent(keyword: tKeyword));
197+
await untilCalled(mockSearchTopHeadlinesNews(any));
198+
199+
// assert
200+
verify(mockSearchTopHeadlinesNews(ParamsSearchTopHeadlinesNews(keyword: tKeyword)));
201+
},
202+
);
203+
204+
blocTest(
205+
'make sure to emit [LoadingTopHeadlinesNewsState, SearchSuccessTopHeadlinesNewsState] when receive '
206+
'SearchTopHeadlinesNewsEvent with a successful process',
207+
build: () async {
208+
when(mockSearchTopHeadlinesNews(any)).thenAnswer((_) async => Right(tTopHeadlinesNewsResponseModel));
209+
return topHeadlinesNewsBloc;
210+
},
211+
act: (bloc) {
212+
return bloc.add(SearchTopHeadlinesNewsEvent(keyword: tKeyword));
213+
},
214+
expect: [
215+
LoadingTopHeadlinesNewsState(),
216+
SearchSuccessTopHeadlinesNewsState(listArticles: tTopHeadlinesNewsResponseModel.articles),
217+
],
218+
verify: (_) async {
219+
verify(mockSearchTopHeadlinesNews(ParamsSearchTopHeadlinesNews(keyword: tKeyword)));
220+
},
221+
);
222+
223+
blocTest(
224+
'make sure to emit [LoadingTopHeadlinesNewsState, FailureTopHeadlinesNewsState] when receive '
225+
'SearchTopHeadlinesNewsEvent with a failed process from endpoint',
226+
build: () async {
227+
when(mockSearchTopHeadlinesNews(any)).thenAnswer((_) async => Left(ServerFailure('testErrorMessage')));
228+
return topHeadlinesNewsBloc;
229+
},
230+
act: (bloc) {
231+
return bloc.add(SearchTopHeadlinesNewsEvent(keyword: tKeyword));
232+
},
233+
expect: [
234+
LoadingTopHeadlinesNewsState(),
235+
FailureTopHeadlinesNewsState(errorMessage: 'testErrorMessage'),
236+
],
237+
verify: (_) async {
238+
verify(mockSearchTopHeadlinesNews(ParamsSearchTopHeadlinesNews(keyword: tKeyword)));
239+
},
240+
);
241+
242+
blocTest(
243+
'make sure to emit [LoadingTopHeadlinesNewsState, FailureTopHeadlinesNewsState] when the internet '
244+
'connection has a problem',
245+
build: () async {
246+
when(mockSearchTopHeadlinesNews(any)).thenAnswer((_) async => Left(ConnectionFailure()));
247+
return topHeadlinesNewsBloc;
248+
},
249+
act: (bloc) {
250+
return bloc.add(SearchTopHeadlinesNewsEvent(keyword: tKeyword));
251+
},
252+
expect: [
253+
LoadingTopHeadlinesNewsState(),
254+
FailureTopHeadlinesNewsState(errorMessage: messageConnectionFailure),
255+
],
256+
verify: (_) async {
257+
verify(mockSearchTopHeadlinesNews(ParamsSearchTopHeadlinesNews(keyword: tKeyword)));
258+
},
259+
);
260+
});
159261
}

‎test/feature/presentation/bloc/topheadlinesnews/top_headlines_news_event_test.dart

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,4 +50,31 @@ void main() {
5050
},
5151
);
5252
});
53+
54+
group('SearchTopHeadlinesNews', () {
55+
final tKeyword = 'testKeyword';
56+
final tSearchTopHeadlinesNewsEvent = SearchTopHeadlinesNewsEvent(keyword: tKeyword);
57+
58+
test(
59+
'make sure the props value is [keyword]',
60+
() async {
61+
// assert
62+
expect(
63+
tSearchTopHeadlinesNewsEvent.props,
64+
[tSearchTopHeadlinesNewsEvent.keyword],
65+
);
66+
},
67+
);
68+
69+
test(
70+
'make sure the output of the toString function',
71+
() async {
72+
// assert
73+
expect(
74+
tSearchTopHeadlinesNewsEvent.toString(),
75+
'SearchTopHeadlinesNewsEvent{keyword: ${tSearchTopHeadlinesNewsEvent.keyword}}',
76+
);
77+
},
78+
);
79+
});
5380
}

‎test/feature/presentation/bloc/topheadlinesnews/top_headlines_news_state_test.dart

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,4 +115,36 @@ void main() {
115115
},
116116
);
117117
});
118+
119+
group('SearchSuccessTopHeadlinesNewsState', () {
120+
final tTopHeadlinesNewsResponseModel = TopHeadlinesNewsResponseModel.fromJson(
121+
json.decode(
122+
fixture('top_headlines_news_response_model.json'),
123+
),
124+
);
125+
final tListArticles = tTopHeadlinesNewsResponseModel.articles;
126+
final tSearchSuccessTopHeadlinesNewsState = SearchSuccessTopHeadlinesNewsState(listArticles: tListArticles);
127+
128+
test(
129+
'make sure the props value is [listArticles]',
130+
() async {
131+
// assert
132+
expect(
133+
tSearchSuccessTopHeadlinesNewsState.props,
134+
[tSearchSuccessTopHeadlinesNewsState.listArticles],
135+
);
136+
},
137+
);
138+
139+
test(
140+
'make sure the output of the toString function',
141+
() async {
142+
// assert
143+
expect(
144+
tSearchSuccessTopHeadlinesNewsState.toString(),
145+
'SearchSuccessTopHeadlinesNewsState{listArticles: ${tSearchSuccessTopHeadlinesNewsState.listArticles}}',
146+
);
147+
},
148+
);
149+
});
118150
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /