Skip to content

Commit

Permalink
chore: write tests for survey detail screen
Browse files Browse the repository at this point in the history
# Conflicts:
#	lib/modules/survey_detail/components/content.dart
  • Loading branch information
markgravity committed Jun 30, 2021
1 parent 6366a02 commit f47c445
Show file tree
Hide file tree
Showing 11 changed files with 1,749 additions and 519 deletions.
1,754 changes: 1,235 additions & 519 deletions coverage/lcov.info

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions lib/modules/survey_detail/components/content.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class Content extends StatelessWidget {
StreamsSelector0<SurveyInfo>.value(
stream: state._survey,
builder: (_, survey, __) => Image(
key: SurveyDetailView.backgroundImageKey,
image: NetworkImage(survey.coverImageUrl!),
fit: BoxFit.fill,
),
Expand Down Expand Up @@ -74,6 +75,7 @@ class Content extends StatelessWidget {
minWidth: 140,
),
child: Button(
key: SurveyDetailView.startSurveyButtonKey,
onPressed: () =>
state.delegate?.startSurveyButtonDidTap.add(null),
title: AppLocalizations.of(context)!
Expand Down
3 changes: 3 additions & 0 deletions lib/modules/survey_detail/survey_detail_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ abstract class SurveyDetailViewDelegate implements AlertViewMixinDelegate {

abstract class SurveyDetailView extends View<SurveyDetailViewDelegate>
with ProgressHUDViewMixin, AlertViewMixin {
static const backgroundImageKey = Key("background_image_");
static const startSurveyButtonKey = Key("start_survey_button");

void setSurvey(SurveyInfo survey);
}

Expand Down
77 changes: 77 additions & 0 deletions test/modules/survey_detail/survey_detail_interactor_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'package:quick_test/quick_test.dart';
import 'package:survey/models/detailed_survey_info.dart';
import 'package:survey/models/survey_info.dart';
import 'package:survey/modules/survey_detail/survey_detail_module.dart';
import 'package:survey/repositories/survey_repository.dart';
import 'package:survey/services/locator/locator_service.dart';
import '../../helpers/behavior_subject_generator.dart';
import 'survey_detail_interactor_test.mocks.dart';

@GenerateMocks([SurveyDetailInteractorDelegate, SurveyRepository])
void main() {
describe("a SurveyDetail interactor", () {
late SurveyDetailInteractor interactor;
late MockSurveyDetailInteractorDelegate delegate;
late BehaviorSubjectGenerator generator;
late MockSurveyRepository surveyRepository;

final survey = SurveyInfo();
survey.id = "id";

beforeEach(() {
generator = BehaviorSubjectGenerator();

surveyRepository = MockSurveyRepository();
locator.registerSingleton<SurveyRepository>(surveyRepository);

delegate = MockSurveyDetailInteractorDelegate();
when(delegate.detailedSurveyDidFetch)
.thenAnswer((realInvocation) => generator.make(0));
when(delegate.detailedSurveyDidFailToFetch)
.thenAnswer((realInvocation) => generator.make(1));

interactor = SurveyDetailInteractorImpl();
interactor.delegate = delegate;
interactor.arguments = SurveyDetailArguments(survey: survey);
});

describe("its survey is got", () {
it("returns correct survey", () {
expect(interactor.survey, survey);
});
});

describe("its fetchDetailedSurvey() is called", () {
context("when survey repository's fetchDetailedSurvey() return success",
() {
final detailedSurvey = DetailedSurveyInfo();
beforeEach(() {
when(surveyRepository.fetchDetailedSurvey(any))
.thenAnswer((realInvocation) => Future.value(detailedSurvey));
interactor.fetchDetailedSurvey();
});

it("triggers delegate's detailedSurveyDidFetch to emit", () {
expect(delegate.detailedSurveyDidFetch, emits(detailedSurvey));
});
});

context("when survey repository's fetchDetailedSurvey() return failure",
() {
final exception = Exception();
beforeEach(() {
when(surveyRepository.fetchDetailedSurvey(any))
.thenAnswer((realInvocation) => Future.error(exception));
interactor.fetchDetailedSurvey();
});

it("triggers delegate's detailedSurveyDidFailToFetch to emit", () {
expect(delegate.detailedSurveyDidFailToFetch, emits(exception));
});
});
});
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Mocks generated by Mockito 5.0.7 from annotations
// in survey/test/modules/survey_detail/survey_detail_interactor_test.dart.
// Do not manually edit this file.

import 'dart:async' as _i6;

import 'package:mockito/mockito.dart' as _i1;
import 'package:rxdart/src/subjects/behavior_subject.dart' as _i2;
import 'package:survey/models/detailed_survey_info.dart' as _i3;
import 'package:survey/models/survey_info.dart' as _i7;
import 'package:survey/modules/survey_detail/survey_detail_module.dart' as _i4;
import 'package:survey/repositories/survey_repository.dart' as _i5;

// ignore_for_file: comment_references
// ignore_for_file: unnecessary_parenthesis

// ignore_for_file: prefer_const_constructors

// ignore_for_file: avoid_redundant_argument_values

class _FakeBehaviorSubject<T> extends _i1.Fake
implements _i2.BehaviorSubject<T> {}

class _FakeDetailedSurveyInfo extends _i1.Fake
implements _i3.DetailedSurveyInfo {}

/// A class which mocks [SurveyDetailInteractorDelegate].
///
/// See the documentation for Mockito's code generation for more information.
class MockSurveyDetailInteractorDelegate extends _i1.Mock
implements _i4.SurveyDetailInteractorDelegate {
MockSurveyDetailInteractorDelegate() {
_i1.throwOnMissingStub(this);
}

@override
_i2.BehaviorSubject<_i3.DetailedSurveyInfo> get detailedSurveyDidFetch =>
(super.noSuchMethod(Invocation.getter(#detailedSurveyDidFetch),
returnValue: _FakeBehaviorSubject<_i3.DetailedSurveyInfo>())
as _i2.BehaviorSubject<_i3.DetailedSurveyInfo>);
@override
_i2.BehaviorSubject<Exception> get detailedSurveyDidFailToFetch =>
(super.noSuchMethod(Invocation.getter(#detailedSurveyDidFailToFetch),
returnValue: _FakeBehaviorSubject<Exception>())
as _i2.BehaviorSubject<Exception>);
}

/// A class which mocks [SurveyRepository].
///
/// See the documentation for Mockito's code generation for more information.
class MockSurveyRepository extends _i1.Mock implements _i5.SurveyRepository {
MockSurveyRepository() {
_i1.throwOnMissingStub(this);
}

@override
_i6.Future<bool> get isSurveysCached =>
(super.noSuchMethod(Invocation.getter(#isSurveysCached),
returnValue: Future<bool>.value(false)) as _i6.Future<bool>);
@override
_i6.Future<List<_i7.SurveyInfo>> fetchSurveys({bool? force}) =>
(super.noSuchMethod(Invocation.method(#fetchSurveys, [], {#force: force}),
returnValue:
Future<List<_i7.SurveyInfo>>.value(<_i7.SurveyInfo>[]))
as _i6.Future<List<_i7.SurveyInfo>>);
@override
_i6.Future<_i3.DetailedSurveyInfo> fetchDetailedSurvey(String? id) =>
(super.noSuchMethod(Invocation.method(#fetchDetailedSurvey, [id]),
returnValue: Future<_i3.DetailedSurveyInfo>.value(
_FakeDetailedSurveyInfo()))
as _i6.Future<_i3.DetailedSurveyInfo>);
}
27 changes: 27 additions & 0 deletions test/modules/survey_detail/survey_detail_module_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:quick_test/quick_test.dart';
import 'package:survey/modules/survey_detail/survey_detail_module.dart';

import '../../mocks/build_context.dart';

void main() {
describe("a SurveyDetail module", () {
late SurveyDetailModule module;
beforeEach(() {
module = SurveyDetailModule();
});

describe("its build is called", () {
late Widget widget;

beforeEach(() {
widget = module.build(MockBuildContext());
});

it("returns SurveyDetailViewImpl", () {
expect(widget, isA<SurveyDetailViewImpl>());
});
});
});
}
88 changes: 88 additions & 0 deletions test/modules/survey_detail/survey_detail_presenter_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'package:quick_test/quick_test.dart';
import 'package:survey/models/detailed_survey_info.dart';
import 'package:survey/models/survey_info.dart';
import 'package:survey/modules/survey_detail/survey_detail_module.dart';

import '../../mocks/build_context.dart';
import 'survey_detail_presenter_test.mocks.dart';

@GenerateMocks([SurveyDetailView, SurveyDetailRouter, SurveyDetailInteractor])
void main() {
describe("a SurveyDetail presenter", () {
late SurveyDetailPresenterImpl presenter;
late MockSurveyDetailView view;
late MockSurveyDetailRouter router;
late MockSurveyDetailInteractor interactor;
late MockBuildContext buildContext;
final survey = SurveyInfo();

beforeEach(() {
buildContext = MockBuildContext();

view = MockSurveyDetailView();
when(view.context).thenReturn(buildContext);

router = MockSurveyDetailRouter();

interactor = MockSurveyDetailInteractor();
when(interactor.survey).thenReturn(survey);

presenter = SurveyDetailPresenterImpl();
presenter.configure(view: view, interactor: interactor, router: router);
});

describe("its detailedSurveyDidFailToFetch to emit", () {
final exception = Exception();
beforeEach(() {
presenter.detailedSurveyDidFailToFetch.add(exception);
});

it("triggers view to dismiss progress hud and alert error", () {
verify(view.dismissProgressHUD()).called(1);
verify(view.alert(exception)).called(1);
});
});

describe("its detailedSurveyDidFetch emits", () {
final survey = DetailedSurveyInfo();
beforeEach(() {
presenter.detailedSurveyDidFetch.add(survey);
});

it("triggers view to dismiss progress hud", () {
verify(view.dismissProgressHUD()).called(1);
});

it("triggers router to push to Survey Questions screen", () {
verify(
router.pushToSurveyQuestionsScreen(buildContext, survey: survey));
});
});

describe("its stateDidInit emits", () {
beforeEach(() {
presenter.stateDidInit.add(null);
});

it("triggers view to set survey", () {
verify(view.setSurvey(survey)).called(1);
});
});

describe("its startSurveyButtonDidTap emits", () {
beforeEach(() {
presenter.startSurveyButtonDidTap.add(null);
});

it("triggers view to dismiss progress hud", () {
verify(view.showProgressHUD()).called(1);
});

it("triggers interactor to fetch detailed survey", () {
verify(interactor.fetchDetailedSurvey()).called(1);
});
});
});
}
Loading

0 comments on commit f47c445

Please sign in to comment.