Skip to content

Commit 6bcc307

Browse files
committed
chore: write tests for survey detail screen
1 parent e1eab66 commit 6bcc307

11 files changed

+1749
-519
lines changed

coverage/lcov.info

Lines changed: 1235 additions & 519 deletions
Large diffs are not rendered by default.

lib/modules/survey_detail/components/content.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ class Content extends StatelessWidget {
2121
StreamsSelector0<SurveyInfo>.value(
2222
stream: state._survey,
2323
builder: (_, survey, __) => Image(
24+
key: SurveyDetailView.backgroundImageKey,
2425
image: NetworkImage(survey.coverImageUrl!),
2526
fit: BoxFit.fill,
2627
),
@@ -67,6 +68,7 @@ class Content extends StatelessWidget {
6768
minWidth: 140,
6869
),
6970
child: Button(
71+
key: SurveyDetailView.startSurveyButtonKey,
7072
onPressed: () => state
7173
.delegate?.startSurveyButtonDidTap
7274
.add(null),

lib/modules/survey_detail/survey_detail_view.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ abstract class SurveyDetailViewDelegate implements AlertViewMixinDelegate {
88

99
abstract class SurveyDetailView extends View<SurveyDetailViewDelegate>
1010
with ProgressHUDViewMixin, AlertViewMixin {
11+
static const backgroundImageKey = Key("background_image_");
12+
static const startSurveyButtonKey = Key("start_survey_button");
13+
1114
void setSurvey(SurveyInfo survey);
1215
}
1316

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import 'package:flutter_test/flutter_test.dart';
2+
import 'package:mockito/annotations.dart';
3+
import 'package:mockito/mockito.dart';
4+
import 'package:quick_test/quick_test.dart';
5+
import 'package:survey/models/detailed_survey_info.dart';
6+
import 'package:survey/models/survey_info.dart';
7+
import 'package:survey/modules/survey_detail/survey_detail_module.dart';
8+
import 'package:survey/repositories/survey_repository.dart';
9+
import 'package:survey/services/locator/locator_service.dart';
10+
import '../../helpers/behavior_subject_generator.dart';
11+
import 'survey_detail_interactor_test.mocks.dart';
12+
13+
@GenerateMocks([SurveyDetailInteractorDelegate, SurveyRepository])
14+
void main() {
15+
describe("a SurveyDetail interactor", () {
16+
late SurveyDetailInteractor interactor;
17+
late MockSurveyDetailInteractorDelegate delegate;
18+
late BehaviorSubjectGenerator generator;
19+
late MockSurveyRepository surveyRepository;
20+
21+
final survey = SurveyInfo();
22+
survey.id = "id";
23+
24+
beforeEach(() {
25+
generator = BehaviorSubjectGenerator();
26+
27+
surveyRepository = MockSurveyRepository();
28+
locator.registerSingleton<SurveyRepository>(surveyRepository);
29+
30+
delegate = MockSurveyDetailInteractorDelegate();
31+
when(delegate.detailedSurveyDidFetch)
32+
.thenAnswer((realInvocation) => generator.make(0));
33+
when(delegate.detailedSurveyDidFailToFetch)
34+
.thenAnswer((realInvocation) => generator.make(1));
35+
36+
interactor = SurveyDetailInteractorImpl();
37+
interactor.delegate = delegate;
38+
interactor.arguments = SurveyDetailArguments(survey: survey);
39+
});
40+
41+
describe("its survey is got", () {
42+
it("returns correct survey", () {
43+
expect(interactor.survey, survey);
44+
});
45+
});
46+
47+
describe("its fetchDetailedSurvey() is called", () {
48+
context("when survey repository's fetchDetailedSurvey() return success",
49+
() {
50+
final detailedSurvey = DetailedSurveyInfo();
51+
beforeEach(() {
52+
when(surveyRepository.fetchDetailedSurvey(any))
53+
.thenAnswer((realInvocation) => Future.value(detailedSurvey));
54+
interactor.fetchDetailedSurvey();
55+
});
56+
57+
it("triggers delegate's detailedSurveyDidFetch to emit", () {
58+
expect(delegate.detailedSurveyDidFetch, emits(detailedSurvey));
59+
});
60+
});
61+
62+
context("when survey repository's fetchDetailedSurvey() return failure",
63+
() {
64+
final exception = Exception();
65+
beforeEach(() {
66+
when(surveyRepository.fetchDetailedSurvey(any))
67+
.thenAnswer((realInvocation) => Future.error(exception));
68+
interactor.fetchDetailedSurvey();
69+
});
70+
71+
it("triggers delegate's detailedSurveyDidFailToFetch to emit", () {
72+
expect(delegate.detailedSurveyDidFailToFetch, emits(exception));
73+
});
74+
});
75+
});
76+
});
77+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// Mocks generated by Mockito 5.0.7 from annotations
2+
// in survey/test/modules/survey_detail/survey_detail_interactor_test.dart.
3+
// Do not manually edit this file.
4+
5+
import 'dart:async' as _i6;
6+
7+
import 'package:mockito/mockito.dart' as _i1;
8+
import 'package:rxdart/src/subjects/behavior_subject.dart' as _i2;
9+
import 'package:survey/models/detailed_survey_info.dart' as _i3;
10+
import 'package:survey/models/survey_info.dart' as _i7;
11+
import 'package:survey/modules/survey_detail/survey_detail_module.dart' as _i4;
12+
import 'package:survey/repositories/survey_repository.dart' as _i5;
13+
14+
// ignore_for_file: comment_references
15+
// ignore_for_file: unnecessary_parenthesis
16+
17+
// ignore_for_file: prefer_const_constructors
18+
19+
// ignore_for_file: avoid_redundant_argument_values
20+
21+
class _FakeBehaviorSubject<T> extends _i1.Fake
22+
implements _i2.BehaviorSubject<T> {}
23+
24+
class _FakeDetailedSurveyInfo extends _i1.Fake
25+
implements _i3.DetailedSurveyInfo {}
26+
27+
/// A class which mocks [SurveyDetailInteractorDelegate].
28+
///
29+
/// See the documentation for Mockito's code generation for more information.
30+
class MockSurveyDetailInteractorDelegate extends _i1.Mock
31+
implements _i4.SurveyDetailInteractorDelegate {
32+
MockSurveyDetailInteractorDelegate() {
33+
_i1.throwOnMissingStub(this);
34+
}
35+
36+
@override
37+
_i2.BehaviorSubject<_i3.DetailedSurveyInfo> get detailedSurveyDidFetch =>
38+
(super.noSuchMethod(Invocation.getter(#detailedSurveyDidFetch),
39+
returnValue: _FakeBehaviorSubject<_i3.DetailedSurveyInfo>())
40+
as _i2.BehaviorSubject<_i3.DetailedSurveyInfo>);
41+
@override
42+
_i2.BehaviorSubject<Exception> get detailedSurveyDidFailToFetch =>
43+
(super.noSuchMethod(Invocation.getter(#detailedSurveyDidFailToFetch),
44+
returnValue: _FakeBehaviorSubject<Exception>())
45+
as _i2.BehaviorSubject<Exception>);
46+
}
47+
48+
/// A class which mocks [SurveyRepository].
49+
///
50+
/// See the documentation for Mockito's code generation for more information.
51+
class MockSurveyRepository extends _i1.Mock implements _i5.SurveyRepository {
52+
MockSurveyRepository() {
53+
_i1.throwOnMissingStub(this);
54+
}
55+
56+
@override
57+
_i6.Future<bool> get isSurveysCached =>
58+
(super.noSuchMethod(Invocation.getter(#isSurveysCached),
59+
returnValue: Future<bool>.value(false)) as _i6.Future<bool>);
60+
@override
61+
_i6.Future<List<_i7.SurveyInfo>> fetchSurveys({bool? force}) =>
62+
(super.noSuchMethod(Invocation.method(#fetchSurveys, [], {#force: force}),
63+
returnValue:
64+
Future<List<_i7.SurveyInfo>>.value(<_i7.SurveyInfo>[]))
65+
as _i6.Future<List<_i7.SurveyInfo>>);
66+
@override
67+
_i6.Future<_i3.DetailedSurveyInfo> fetchDetailedSurvey(String? id) =>
68+
(super.noSuchMethod(Invocation.method(#fetchDetailedSurvey, [id]),
69+
returnValue: Future<_i3.DetailedSurveyInfo>.value(
70+
_FakeDetailedSurveyInfo()))
71+
as _i6.Future<_i3.DetailedSurveyInfo>);
72+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import 'package:flutter/widgets.dart';
2+
import 'package:flutter_test/flutter_test.dart';
3+
import 'package:quick_test/quick_test.dart';
4+
import 'package:survey/modules/survey_detail/survey_detail_module.dart';
5+
6+
import '../../mocks/build_context.dart';
7+
8+
void main() {
9+
describe("a SurveyDetail module", () {
10+
late SurveyDetailModule module;
11+
beforeEach(() {
12+
module = SurveyDetailModule();
13+
});
14+
15+
describe("its build is called", () {
16+
late Widget widget;
17+
18+
beforeEach(() {
19+
widget = module.build(MockBuildContext());
20+
});
21+
22+
it("returns SurveyDetailViewImpl", () {
23+
expect(widget, isA<SurveyDetailViewImpl>());
24+
});
25+
});
26+
});
27+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import 'package:mockito/annotations.dart';
2+
import 'package:mockito/mockito.dart';
3+
import 'package:quick_test/quick_test.dart';
4+
import 'package:survey/models/detailed_survey_info.dart';
5+
import 'package:survey/models/survey_info.dart';
6+
import 'package:survey/modules/survey_detail/survey_detail_module.dart';
7+
8+
import '../../mocks/build_context.dart';
9+
import 'survey_detail_presenter_test.mocks.dart';
10+
11+
@GenerateMocks([SurveyDetailView, SurveyDetailRouter, SurveyDetailInteractor])
12+
void main() {
13+
describe("a SurveyDetail presenter", () {
14+
late SurveyDetailPresenterImpl presenter;
15+
late MockSurveyDetailView view;
16+
late MockSurveyDetailRouter router;
17+
late MockSurveyDetailInteractor interactor;
18+
late MockBuildContext buildContext;
19+
final survey = SurveyInfo();
20+
21+
beforeEach(() {
22+
buildContext = MockBuildContext();
23+
24+
view = MockSurveyDetailView();
25+
when(view.context).thenReturn(buildContext);
26+
27+
router = MockSurveyDetailRouter();
28+
29+
interactor = MockSurveyDetailInteractor();
30+
when(interactor.survey).thenReturn(survey);
31+
32+
presenter = SurveyDetailPresenterImpl();
33+
presenter.configure(view: view, interactor: interactor, router: router);
34+
});
35+
36+
describe("its detailedSurveyDidFailToFetch to emit", () {
37+
final exception = Exception();
38+
beforeEach(() {
39+
presenter.detailedSurveyDidFailToFetch.add(exception);
40+
});
41+
42+
it("triggers view to dismiss progress hud and alert error", () {
43+
verify(view.dismissProgressHUD()).called(1);
44+
verify(view.alert(exception)).called(1);
45+
});
46+
});
47+
48+
describe("its detailedSurveyDidFetch emits", () {
49+
final survey = DetailedSurveyInfo();
50+
beforeEach(() {
51+
presenter.detailedSurveyDidFetch.add(survey);
52+
});
53+
54+
it("triggers view to dismiss progress hud", () {
55+
verify(view.dismissProgressHUD()).called(1);
56+
});
57+
58+
it("triggers router to push to Survey Questions screen", () {
59+
verify(
60+
router.pushToSurveyQuestionsScreen(buildContext, survey: survey));
61+
});
62+
});
63+
64+
describe("its stateDidInit emits", () {
65+
beforeEach(() {
66+
presenter.stateDidInit.add(null);
67+
});
68+
69+
it("triggers view to set survey", () {
70+
verify(view.setSurvey(survey)).called(1);
71+
});
72+
});
73+
74+
describe("its startSurveyButtonDidTap emits", () {
75+
beforeEach(() {
76+
presenter.startSurveyButtonDidTap.add(null);
77+
});
78+
79+
it("triggers view to dismiss progress hud", () {
80+
verify(view.showProgressHUD()).called(1);
81+
});
82+
83+
it("triggers interactor to fetch detailed survey", () {
84+
verify(interactor.fetchDetailedSurvey()).called(1);
85+
});
86+
});
87+
});
88+
}

0 commit comments

Comments
 (0)