TF-4265 Add integration test for attachment reminder on mobile
This commit is contained in:
+94
@@ -0,0 +1,94 @@
|
||||
import 'package:core/utils/config/app_config_loader.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mockito/annotations.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/manager/attachment_keyword_config_manager.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/manager/attachment_keywords_configuration_parser.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/model/attachment_keyword_config.dart';
|
||||
|
||||
import 'attachment_keyword_config_manager_test.mocks.dart';
|
||||
|
||||
@GenerateMocks([AppConfigLoader])
|
||||
void main() {
|
||||
TestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
late AttachmentKeywordConfigManager manager;
|
||||
late MockAppConfigLoader mockLoader;
|
||||
|
||||
setUp(() {
|
||||
manager = AttachmentKeywordConfigManager();
|
||||
manager.clearCache();
|
||||
mockLoader = MockAppConfigLoader();
|
||||
manager.injectLoader(mockLoader);
|
||||
});
|
||||
|
||||
group('AttachmentKeywordConfigManager.getConfig', () {
|
||||
test('returns config loaded from loader on first call', () async {
|
||||
final config = AttachmentKeywordConfig(
|
||||
includeList: ['invoice'],
|
||||
excludeList: ['invoice-draft'],
|
||||
);
|
||||
|
||||
when(mockLoader.load<AttachmentKeywordConfig>(
|
||||
any,
|
||||
any,
|
||||
)).thenAnswer((_) async => config);
|
||||
|
||||
final result = await manager.getConfig();
|
||||
|
||||
expect(result.includeList, equals(['invoice']));
|
||||
expect(result.excludeList, equals(['invoice-draft']));
|
||||
});
|
||||
|
||||
test('returns cached result on second call without calling loader again', () async {
|
||||
final config = AttachmentKeywordConfig(includeList: ['invoice']);
|
||||
|
||||
when(mockLoader.load<AttachmentKeywordConfig>(any, any))
|
||||
.thenAnswer((_) async => config);
|
||||
|
||||
await manager.getConfig();
|
||||
await manager.getConfig();
|
||||
|
||||
verify(mockLoader.load<AttachmentKeywordConfig>(
|
||||
any,
|
||||
argThat(isA<AttachmentKeywordsConfigurationParser>()),
|
||||
)).called(1);
|
||||
});
|
||||
|
||||
test('returns empty AttachmentKeywordConfig when loader throws', () async {
|
||||
when(mockLoader.load<AttachmentKeywordConfig>(any, any))
|
||||
.thenThrow(Exception('file not found'));
|
||||
|
||||
final result = await manager.getConfig();
|
||||
|
||||
expect(result.includeList, isEmpty);
|
||||
expect(result.excludeList, isEmpty);
|
||||
});
|
||||
|
||||
test('caches the empty fallback config on error (loader not called again)', () async {
|
||||
when(mockLoader.load<AttachmentKeywordConfig>(any, any))
|
||||
.thenThrow(Exception('file not found'));
|
||||
|
||||
await manager.getConfig();
|
||||
await manager.getConfig();
|
||||
|
||||
verify(mockLoader.load<AttachmentKeywordConfig>(any, any)).called(1);
|
||||
});
|
||||
});
|
||||
|
||||
group('AttachmentKeywordConfigManager.clearCache', () {
|
||||
test('clearCache forces re-load on next getConfig call', () async {
|
||||
final config = AttachmentKeywordConfig(includeList: ['invoice']);
|
||||
|
||||
when(mockLoader.load<AttachmentKeywordConfig>(any, any))
|
||||
.thenAnswer((_) async => config);
|
||||
|
||||
await manager.getConfig();
|
||||
manager.clearCache();
|
||||
manager.injectLoader(mockLoader);
|
||||
await manager.getConfig();
|
||||
|
||||
verify(mockLoader.load<AttachmentKeywordConfig>(any, any)).called(2);
|
||||
});
|
||||
});
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,61 @@
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/manager/exclude_list_filter.dart';
|
||||
|
||||
/// Helper: simulate a regex [Match] at [start]..[end] within [text].
|
||||
Match _fakeMatch(String text, int start, int end) {
|
||||
final regex = RegExp(RegExp.escape(text.substring(start, end)));
|
||||
return regex.allMatches(text).firstWhere((m) => m.start == start);
|
||||
}
|
||||
|
||||
void main() {
|
||||
group('ExcludeListFilter.isValid', () {
|
||||
test('returns true when excludeList is empty', () {
|
||||
final filter = ExcludeListFilter([]);
|
||||
const text ='See the file attached.';
|
||||
final match = _fakeMatch(text, 8, 12); // "file"
|
||||
expect(filter.isValid(text, match), isTrue);
|
||||
});
|
||||
|
||||
test('blocks token that exactly matches an exclude entry', () {
|
||||
final filter = ExcludeListFilter(['file-246']);
|
||||
const text ='Please find file-246 here.';
|
||||
final match = _fakeMatch(text, 12, 16); // "file"
|
||||
expect(filter.isValid(text, match), isFalse);
|
||||
});
|
||||
|
||||
test('blocks token with trailing punctuation (e.g. "file-246.")', () {
|
||||
final filter = ExcludeListFilter(['file-246']);
|
||||
const text ='Check file-246.';
|
||||
final match = _fakeMatch(text, 6, 10); // "file"
|
||||
expect(filter.isValid(text, match), isFalse);
|
||||
});
|
||||
|
||||
test('blocks token with leading punctuation (e.g. "(file-246")', () {
|
||||
final filter = ExcludeListFilter(['file-246']);
|
||||
const text ='See (file-246 for details.';
|
||||
final match = _fakeMatch(text, 5, 9); // "file"
|
||||
expect(filter.isValid(text, match), isFalse);
|
||||
});
|
||||
|
||||
test('allows token not in the exclude list', () {
|
||||
final filter = ExcludeListFilter(['invoice-draft']);
|
||||
const text ='Please attach the file.';
|
||||
final match = _fakeMatch(text, 18, 22); // "file"
|
||||
expect(filter.isValid(text, match), isTrue);
|
||||
});
|
||||
|
||||
test('matching is case-insensitive', () {
|
||||
final filter = ExcludeListFilter(['File-246']);
|
||||
const text ='See file-246 here.';
|
||||
final match = _fakeMatch(text, 4, 8); // "file"
|
||||
expect(filter.isValid(text, match), isFalse);
|
||||
});
|
||||
|
||||
test('allows a standalone keyword not surrounded by exclude context', () {
|
||||
final filter = ExcludeListFilter(['file-246']);
|
||||
const text ='Please attach the file here.';
|
||||
final match = _fakeMatch(text, 18, 22); // "file"
|
||||
expect(filter.isValid(text, match), isTrue);
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user