diff --git a/lib/features/base/mixin/mail_api_mixin.dart b/lib/features/base/mixin/mail_api_mixin.dart index 6c3122a95..38799ee31 100644 --- a/lib/features/base/mixin/mail_api_mixin.dart +++ b/lib/features/base/mixin/mail_api_mixin.dart @@ -141,7 +141,7 @@ mixin MailAPIMixin on HandleSetErrorMixin { if (limit != null) queryEmailMethod.addLimit(limit); - if (position != null) queryEmailMethod.addPosition(position); + if (position != null && position > 0) queryEmailMethod.addPosition(position); if (sort != null) queryEmailMethod.addSorts(sort); diff --git a/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart b/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart index 9351f8b41..2f85885bf 100644 --- a/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart +++ b/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart @@ -138,6 +138,7 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/labels/handle_logic_label_extension.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/notify_thread_detail_setting_updated.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/open_and_close_composer_extension.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/quick_search_emails_extension.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/reopen_composer_cache_extension.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/select_search_filter_action_extension.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/set_error_extension.dart'; diff --git a/lib/features/mailbox_dashboard/presentation/controller/search_controller.dart b/lib/features/mailbox_dashboard/presentation/controller/search_controller.dart index 7619cc9fa..b292663b8 100644 --- a/lib/features/mailbox_dashboard/presentation/controller/search_controller.dart +++ b/lib/features/mailbox_dashboard/presentation/controller/search_controller.dart @@ -5,26 +5,15 @@ import 'package:dartz/dartz.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:jmap_dart_client/jmap/account_id.dart'; -import 'package:jmap_dart_client/jmap/core/filter/filter.dart'; -import 'package:jmap_dart_client/jmap/core/session/session.dart'; -import 'package:jmap_dart_client/jmap/core/sort/comparator.dart'; -import 'package:jmap_dart_client/jmap/core/unsigned_int.dart'; import 'package:jmap_dart_client/jmap/core/user_name.dart'; import 'package:jmap_dart_client/jmap/core/utc_date.dart'; -import 'package:jmap_dart_client/jmap/mail/email/email_comparator.dart'; -import 'package:jmap_dart_client/jmap/mail/email/email_comparator_property.dart'; -import 'package:jmap_dart_client/jmap/mail/email/email_filter_condition.dart'; import 'package:jmap_dart_client/jmap/mail/email/keyword_identifier.dart'; import 'package:labels/model/label.dart'; -import 'package:model/email/presentation_email.dart'; -import 'package:model/extensions/email_filter_condition_extension.dart'; import 'package:model/mailbox/presentation_mailbox.dart'; import 'package:tmail_ui_user/features/base/base_controller.dart'; import 'package:tmail_ui_user/features/base/mixin/date_range_picker_mixin.dart'; -import 'package:tmail_ui_user/features/email/presentation/utils/email_utils.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/model/recent_search.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/get_all_recent_search_latest_state.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/quick_search_email_state.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_all_recent_search_latest_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/quick_search_email_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/save_recent_search_interactor.dart'; @@ -38,7 +27,7 @@ import 'package:tmail_ui_user/features/thread/presentation/model/search_state.da import 'package:tmail_ui_user/features/thread/presentation/model/search_status.dart'; class SearchController extends BaseController with DateRangePickerMixin { - final QuickSearchEmailInteractor _quickSearchEmailInteractor; + final QuickSearchEmailInteractor quickSearchEmailInteractor; final SaveRecentSearchInteractor _saveRecentSearchInteractor; final GetAllRecentSearchLatestInteractor _getAllRecentSearchLatestInteractor; @@ -58,7 +47,7 @@ class SearchController extends BaseController with DateRangePickerMixin { String currentSearchText = ''; SearchController( - this._quickSearchEmailInteractor, + this.quickSearchEmailInteractor, this._saveRecentSearchInteractor, this._getAllRecentSearchLatestInteractor, ); @@ -108,59 +97,6 @@ class SearchController extends BaseController with DateRangePickerMixin { listFilterOnSuggestionForm.remove(searchFilter); } - Future> quickSearchEmails({ - required Session session, - required AccountId accountId, - required String ownEmailAddress, - required String query, - }) async { - currentSearchText = query; - return await _quickSearchEmailInteractor.execute( - session, - accountId, - limit: UnsignedInt(5), - sort: {}..add( - EmailComparator(EmailComparatorProperty.receivedAt) - ..setIsAscending(false)), - filter: _mappingToFilterOnSuggestionForm( - currentUserEmail: ownEmailAddress, - query: query, - ), - properties: EmailUtils.getPropertiesForEmailGetMethod(session, accountId), - ).then((result) => result.fold( - (failure) => [], - (success) => success is QuickSearchEmailSuccess - ? success.emailList - : [] - )); - } - - Filter? _mappingToFilterOnSuggestionForm({required String query, required String currentUserEmail}) { - log('SearchController::_mappingToFilterOnSuggestionForm():query: $query'); - final filterCondition = EmailFilterCondition( - text: query.isNotEmpty == true ? query : null, - after: listFilterOnSuggestionForm.contains(QuickSearchFilter.last7Days) - ? EmailReceiveTimeType.last7Days.toOldestUTCDate() - : null, - before: listFilterOnSuggestionForm.contains(QuickSearchFilter.last7Days) - ? EmailReceiveTimeType.last7Days.toLatestUTCDate() - : null, - hasAttachment: listFilterOnSuggestionForm.contains(QuickSearchFilter.hasAttachment) - ? true - : null, - from: listFilterOnSuggestionForm.contains(QuickSearchFilter.fromMe) && currentUserEmail.isNotEmpty - ? currentUserEmail - : null, - hasKeyword: listFilterOnSuggestionForm.contains(QuickSearchFilter.starred) - ? KeyWordIdentifier.emailFlagged.value - : null - ); - - return filterCondition.hasCondition - ? filterCondition - : null; - } - void applyFilterSuggestionToSearchFilter(String currentUserEmail) { final receiveTime = listFilterOnSuggestionForm.contains(QuickSearchFilter.last7Days) ? EmailReceiveTimeType.last7Days diff --git a/lib/features/mailbox_dashboard/presentation/extensions/quick_search_emails_extension.dart b/lib/features/mailbox_dashboard/presentation/extensions/quick_search_emails_extension.dart new file mode 100644 index 000000000..b9da0b9d8 --- /dev/null +++ b/lib/features/mailbox_dashboard/presentation/extensions/quick_search_emails_extension.dart @@ -0,0 +1,69 @@ +import 'package:core/utils/app_logger.dart'; +import 'package:jmap_dart_client/jmap/account_id.dart'; +import 'package:jmap_dart_client/jmap/core/filter/filter.dart'; +import 'package:jmap_dart_client/jmap/core/session/session.dart'; +import 'package:jmap_dart_client/jmap/core/unsigned_int.dart'; +import 'package:jmap_dart_client/jmap/mail/email/email_filter_condition.dart'; +import 'package:jmap_dart_client/jmap/mail/email/keyword_identifier.dart'; +import 'package:model/email/presentation_email.dart'; +import 'package:model/extensions/email_filter_condition_extension.dart'; +import 'package:tmail_ui_user/features/email/presentation/utils/email_utils.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/quick_search_email_state.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/search_controller.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/email_receive_time_type.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/quick_search_filter.dart'; + +extension QuickSearchEmailsExtension on SearchController { + Future> quickSearchEmails({ + required Session session, + required AccountId accountId, + required String ownEmailAddress, + required String query, + }) async { + currentSearchText = query; + return await quickSearchEmailInteractor.execute( + session, + accountId, + limit: UnsignedInt(5), + sort: searchEmailFilter.value.sortOrderType + .getSortOrder() + .toNullable(), + filter: _mappingToFilterOnSuggestionForm( + currentUserEmail: ownEmailAddress, + query: query, + ), + properties: EmailUtils.getPropertiesForEmailGetMethod(session, accountId), + ).then((result) => result.fold( + (failure) => [], + (success) => success is QuickSearchEmailSuccess + ? success.emailList + : [] + )); + } + + Filter? _mappingToFilterOnSuggestionForm({required String query, required String currentUserEmail}) { + log('SearchController::_mappingToFilterOnSuggestionForm():query: $query'); + final filterCondition = EmailFilterCondition( + text: query.isNotEmpty == true ? query : null, + after: listFilterOnSuggestionForm.contains(QuickSearchFilter.last7Days) + ? EmailReceiveTimeType.last7Days.toOldestUTCDate() + : null, + before: listFilterOnSuggestionForm.contains(QuickSearchFilter.last7Days) + ? EmailReceiveTimeType.last7Days.toLatestUTCDate() + : null, + hasAttachment: listFilterOnSuggestionForm.contains(QuickSearchFilter.hasAttachment) + ? true + : null, + from: listFilterOnSuggestionForm.contains(QuickSearchFilter.fromMe) && currentUserEmail.isNotEmpty + ? currentUserEmail + : null, + hasKeyword: listFilterOnSuggestionForm.contains(QuickSearchFilter.starred) + ? KeyWordIdentifier.emailFlagged.value + : null + ); + + return filterCondition.hasCondition + ? filterCondition + : null; + } +} \ No newline at end of file diff --git a/lib/features/thread/data/network/thread_api.dart b/lib/features/thread/data/network/thread_api.dart index 41544fa82..9c2dca6e8 100644 --- a/lib/features/thread/data/network/thread_api.dart +++ b/lib/features/thread/data/network/thread_api.dart @@ -81,7 +81,7 @@ class ThreadAPI with HandleSetErrorMixin, MailAPIMixin { if (limit != null) queryEmailMethod.addLimit(limit); - if (position != null) queryEmailMethod.addPosition(position); + if (position != null && position > 0) queryEmailMethod.addPosition(position); if (sort != null) queryEmailMethod.addSorts(sort); diff --git a/test/features/base/mixin/mail_api_mixin_test.dart b/test/features/base/mixin/mail_api_mixin_test.dart new file mode 100644 index 000000000..645ac7584 --- /dev/null +++ b/test/features/base/mixin/mail_api_mixin_test.dart @@ -0,0 +1,253 @@ +import 'package:dio/dio.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:http_mock_adapter/http_mock_adapter.dart'; +import 'package:jmap_dart_client/http/http_client.dart'; +import 'package:jmap_dart_client/jmap/core/error/set_error.dart'; +import 'package:jmap_dart_client/jmap/core/filter/filter.dart'; +import 'package:jmap_dart_client/jmap/core/id.dart'; +import 'package:jmap_dart_client/jmap/core/method/response/set_response.dart'; +import 'package:jmap_dart_client/jmap/core/state.dart'; +import 'package:jmap_dart_client/jmap/mail/email/email.dart'; +import 'package:jmap_dart_client/jmap/mail/email/email_filter_condition.dart'; +import 'package:model/error_type_handler/set_method_error_handler_mixin.dart'; +import 'package:tmail_ui_user/features/base/mixin/handle_error_mixin.dart'; +import 'package:tmail_ui_user/features/base/mixin/mail_api_mixin.dart'; +import 'package:tmail_ui_user/features/thread/domain/model/email_response.dart'; + +import '../../../fixtures/account_fixtures.dart'; +import '../../../fixtures/session_fixtures.dart'; + +class TestMailApiMixin with HandleSetErrorMixin, MailAPIMixin { + @override + void handleSetErrors({ + SetMethodErrors? notDestroyedError, + SetMethodErrors? notUpdatedError, + SetMethodErrors? notCreatedError, + Set? notDestroyedHandlers, + Set? notUpdatedHandlers, + Set? notCreatedHandlers, + SetMethodErrorHandler? unCatchErrorHandler, + }) {} + + @override + Map handleSetResponse(List listSetResponse) { + throw UnimplementedError(); + } + + @override + parseErrorForSetResponse(SetResponse? response, Id requestId) { + throw UnimplementedError(); + } +} + +void main() { + final baseOption = BaseOptions(method: 'POST'); + final dio = Dio(baseOption)..options.baseUrl = 'http://domain.com/jmap'; + late DioAdapter dioAdapter; + late HttpClient httpClient; + late TestMailApiMixin testMailApiMixin; + + final sessionState = State('some-session-state'); + final state = State('some-state'); + final filter = EmailFilterCondition(text: 'some-text'); + final queryState = State('some-query-state'); + + setUp(() { + dioAdapter = DioAdapter(dio: dio); + httpClient = HttpClient(dio); + testMailApiMixin = TestMailApiMixin(); + }); + + group('mail api mixin test:', () { + group('fetchAllEmail:', () { + Map generateRequest({ + required Filter filter, + int? position, + }) => + { + "using": [ + "urn:ietf:params:jmap:core", + "urn:ietf:params:jmap:mail", + "urn:apache:james:params:jmap:mail:shares", + ], + "methodCalls": [ + [ + "Email/query", + { + "accountId": AccountFixtures.aliceAccountId.id.value, + if (position != null) "position": position, + "filter": filter.toJson(), + }, + "c0" + ], + [ + "Email/get", + { + "accountId": AccountFixtures.aliceAccountId.id.value, + "#ids": { + "resultOf": "c0", + "name": "Email/query", + "path": "/ids/*" + }, + }, + "c1" + ] + ] + }; + + Map generateResponse({ + required List foundEmails, + required List notFoundEmailIds, + }) => + { + "sessionState": sessionState.value, + "methodResponses": [ + [ + "Email/query", + { + "accountId": AccountFixtures.aliceAccountId.id.value, + "ids": foundEmails.map((email) => email.id?.id.value).toList() + ..addAll( + notFoundEmailIds.map((emailId) => emailId.id.value)), + "queryState": queryState.value, + "canCalculateChanges": true, + "position": 0, + }, + "c0" + ], + [ + "Email/get", + { + "accountId": AccountFixtures.aliceAccountId.id.value, + "state": state.value, + "list": foundEmails.map((email) => email.toJson()).toList(), + "notFound": notFoundEmailIds + .map((emailId) => emailId.id.value) + .toList(), + }, + "c1" + ] + ] + }; + + test( + 'should not add position to request ' + 'when position is null', + () async { + // arrange + final email = Email( + id: EmailId(Id('someEmailId')), + ); + dioAdapter.onPost( + '', + (server) => server.reply( + 200, + generateResponse( + foundEmails: [email], + notFoundEmailIds: [], + ), + ), + data: generateRequest(filter: filter), + ); + + // act + final result = await testMailApiMixin.fetchAllEmail( + session: SessionFixtures.aliceSession, + accountId: AccountFixtures.aliceAccountId, + httpClient: httpClient, + filter: filter, + ); + + // assert + expect( + result, + equals( + EmailsResponse( + emailList: [email], + state: state, + notFoundEmailIds: [], + ), + ), + ); + }, + ); + + test( + 'should not add position to request ' + 'when position is 0', + () async { + // arrange + final email = Email( + id: EmailId(Id('someEmailId')), + ); + dioAdapter.onPost( + '', + (server) => server.reply( + 403, + generateResponse( + foundEmails: [email], + notFoundEmailIds: [], + ), + ), + data: generateRequest(filter: filter, position: 0), + ); + + // act & assert + expect( + () => testMailApiMixin.fetchAllEmail( + session: SessionFixtures.aliceSession, + accountId: AccountFixtures.aliceAccountId, + httpClient: httpClient, + filter: filter, + position: 0, + ), + throwsA(isA()), + ); + }, + ); + + test( + 'should add position to request ' + 'when position > 0', + () async { + // arrange + final email = Email( + id: EmailId(Id('someEmailId')), + ); + dioAdapter.onPost( + '', + (server) => server.reply( + 200, + generateResponse( + foundEmails: [email], + notFoundEmailIds: [], + ), + ), + data: generateRequest(filter: filter, position: 1), + ); + + // act + final result = await testMailApiMixin.fetchAllEmail( + session: SessionFixtures.aliceSession, + accountId: AccountFixtures.aliceAccountId, + httpClient: httpClient, + filter: filter, + position: 1, + ); + + // assert + expect( + result, + equals( + EmailsResponse( + emailList: [email], + state: state, + notFoundEmailIds: [], + ), + ), + ); + }, + ); + }); + }); +} diff --git a/test/features/mailbox_dashboard/presentation/extensions/quick_search_emails_extension_test.dart b/test/features/mailbox_dashboard/presentation/extensions/quick_search_emails_extension_test.dart new file mode 100644 index 000000000..6409051b9 --- /dev/null +++ b/test/features/mailbox_dashboard/presentation/extensions/quick_search_emails_extension_test.dart @@ -0,0 +1,101 @@ +import 'package:dartz/dartz.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:get/state_manager.dart'; +import 'package:mockito/annotations.dart'; +import 'package:mockito/mockito.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/quick_search_email_state.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/quick_search_email_interactor.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/search_controller.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/quick_search_emails_extension.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/email_sort_order_type.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/quick_search_filter.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/search_email_filter.dart'; + +import '../../../../fixtures/account_fixtures.dart'; +import '../../../../fixtures/session_fixtures.dart'; +import 'quick_search_emails_extension_test.mocks.dart'; + +@GenerateNiceMocks([ + MockSpec(), + MockSpec(), +]) +void main() { + final session = SessionFixtures.aliceSession; + final accountId = AccountFixtures.aliceAccountId; + const ownEmailAddress = 'alice@linagora.com'; + const query = 'test'; + + EmailSortOrderType? sortOrderType; + + late MockSearchController searchController; + late MockQuickSearchEmailInteractor quickSearchEmailInteractor; + + setUp(() { + quickSearchEmailInteractor = MockQuickSearchEmailInteractor(); + searchController = MockSearchController(); + when(searchController.quickSearchEmailInteractor) + .thenReturn(quickSearchEmailInteractor); + when(searchController.listFilterOnSuggestionForm) + .thenReturn([].obs); + when( + quickSearchEmailInteractor.execute( + any, + any, + limit: anyNamed('limit'), + sort: anyNamed('sort'), + filter: anyNamed('filter'), + properties: anyNamed('properties'), + ), + ).thenAnswer((_) => Future.value(Right(QuickSearchEmailSuccess([])))); + }); + + group('quickSearchEmails', () { + test( + 'should invoke quickSearchEmailInteractor.execute() with SearchController\'s sort ' + 'when sortOrderType is null', + () async { + sortOrderType = null; + when(searchController.searchEmailFilter) + .thenReturn(SearchEmailFilter(sortOrderType: sortOrderType).obs); + await searchController.quickSearchEmails( + session: session, + accountId: accountId, + ownEmailAddress: ownEmailAddress, + query: query, + ); + verify(quickSearchEmailInteractor.execute( + session, + accountId, + limit: anyNamed('limit'), + sort: sortOrderType?.getSortOrder().toNullable(), + filter: anyNamed('filter'), + properties: anyNamed('properties'), + )).called(1); + }, + ); + + test( + 'should invoke quickSearchEmailInteractor.execute() with SearchController\'s sort ' + 'when sortOrderType is not null', + () async { + sortOrderType = EmailSortOrderType.oldest; + when(searchController.searchEmailFilter) + .thenReturn(SearchEmailFilter(sortOrderType: sortOrderType).obs); + await searchController.quickSearchEmails( + session: session, + accountId: accountId, + ownEmailAddress: ownEmailAddress, + query: query, + ); + verify(quickSearchEmailInteractor.execute( + session, + accountId, + limit: anyNamed('limit'), + sort: sortOrderType?.getSortOrder().toNullable(), + filter: anyNamed('filter'), + properties: anyNamed('properties'), + )).called(1); + }, + ); + }); +} diff --git a/test/features/thread/data/network/thread_api_test.dart b/test/features/thread/data/network/thread_api_test.dart index 9537eb595..322eef396 100644 --- a/test/features/thread/data/network/thread_api_test.dart +++ b/test/features/thread/data/network/thread_api_test.dart @@ -57,9 +57,9 @@ void main() { final dioAdapterHeaders = { 'accept': 'application/json;jmapVersion=rfc-8621', }; - final dioAdapter = DioAdapter(dio: dio); - final httpClient = HttpClient(dio); - final threadApi = ThreadAPI(httpClient); + late DioAdapter dioAdapter; + late HttpClient httpClient; + late ThreadAPI threadApi; final sessionState = State('some-session-state'); final state = State('some-state'); @@ -68,9 +68,15 @@ void main() { final filter = EmailFilterCondition(text: 'some-text'); final queryState = State('some-query-state'); + setUp(() { + dioAdapter = DioAdapter(dio: dio); + httpClient = HttpClient(dio); + threadApi = ThreadAPI(httpClient); + }); + group('thread api test:', () { group('searchEmails:', () { - Map generateRequest({required Filter filter}) => { + Map generateRequest({required Filter filter, int? position}) => { "using": [ "urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail", @@ -81,6 +87,7 @@ void main() { "Email/query", { "accountId": AccountFixtures.aliceAccountId.id.value, + if (position != null) "position": position, "filter": filter.toJson(), }, "c0" @@ -267,6 +274,128 @@ void main() { ), ); }); + + test( + 'should not add position to request ' + 'when position is null', + () async { + // arrange + final searchEmail = SearchEmail( + id: EmailId(Id('someEmailId')), + searchSnippetSubject: 'searchSnippetSubject', + searchSnippetPreview: 'searchSnippetPreview', + ); + dioAdapter.onPost( + '', + (server) => server.reply( + 200, + generateResponse( + foundSearchEmails: [searchEmail], + notFoundEmailIds: [], + searchSnippetError: UnknownMethodResponse(), + ), + ), + data: generateRequest(filter: filter), + ); + + // act + final result = await threadApi.searchEmails( + SessionFixtures.aliceSession, + AccountFixtures.aliceAccountId, + filter: filter, + ); + + // assert + expect( + result, + equals( + SearchEmailsResponse( + searchSnippets: null, + emailList: [Email(id: searchEmail.id)], + state: state + ), + ), + ); + }); + + test( + 'should not add position to request ' + 'when position is 0', + () async { + // arrange + final searchEmail = SearchEmail( + id: EmailId(Id('someEmailId')), + searchSnippetSubject: 'searchSnippetSubject', + searchSnippetPreview: 'searchSnippetPreview', + ); + dioAdapter.onPost( + '', + (server) => server.reply( + 403, + generateResponse( + foundSearchEmails: [searchEmail], + notFoundEmailIds: [], + searchSnippetError: UnknownMethodResponse(), + ), + ), + data: generateRequest(filter: filter, position: 0), + ); + + // act & assert + expect( + () => threadApi.searchEmails( + SessionFixtures.aliceSession, + AccountFixtures.aliceAccountId, + filter: filter, + position: 0, + ), + throwsA(isA()), + ); + }); + + test( + 'should add position to request ' + 'when position > 0', + () async { + // arrange + final searchEmail = SearchEmail( + id: EmailId(Id('someEmailId')), + searchSnippetSubject: 'searchSnippetSubject', + searchSnippetPreview: 'searchSnippetPreview', + ); + dioAdapter.onPost( + '', + (server) => server.reply( + 200, + generateResponse( + foundSearchEmails: [searchEmail], + notFoundEmailIds: [], + searchSnippetError: UnknownMethodResponse(), + ), + ), + data: generateRequest(filter: filter, position: 1), + ); + + // act + final result = await threadApi.searchEmails( + SessionFixtures.aliceSession, + AccountFixtures.aliceAccountId, + filter: filter, + position: 1, + ); + + // assert + expect( + result, + equals( + SearchEmailsResponse( + searchSnippets: null, + emailList: [Email(id: searchEmail.id)], + state: state + ), + ), + ); + }); }); group('sortEmails::test', () {