Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions integration_test/base/base_test_scenario.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,15 @@ abstract class BaseTestScenario extends BaseScenario

@override
Future<void> execute() async {
await setupPreLogin();
await executeLoginScenario();
await runTestLogic();
await disposeAfterTest();
}

Future<void> setupPreLogin() async {}

Future<void> runTestLogic();

Future<void> disposeAfterTest() async {}
}
88 changes: 88 additions & 0 deletions integration_test/mixin/provisioning_label_scenario_mixin.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import 'package:core/utils/app_logger.dart';
import 'package:jmap_dart_client/jmap/account_id.dart';
import 'package:labels/labels.dart';
import 'package:tmail_ui_user/features/labels/domain/state/create_new_label_state.dart';
import 'package:tmail_ui_user/features/labels/domain/usecases/create_new_label_interactor.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart';
import 'package:tmail_ui_user/main/routes/route_navigation.dart';

import '../models/provisioning_email.dart';
import '../models/provisioning_label.dart';

mixin ProvisioningLabelScenarioMixin {
Future<List<Label>> provisionLabels(
List<ProvisioningLabel> provisioningLabels,
) async {
if (provisioningLabels.isEmpty) {
return [];
}

final dashboardController = getBinding<MailboxDashBoardController>();
final createLabelInteractor = getBinding<CreateNewLabelInteractor>();

final accountId = dashboardController?.accountId.value;
final labelController = dashboardController?.labelController;

if (createLabelInteractor == null || accountId == null) {
log(
'ProvisioningLabelScenarioMixin::provisionLabels '
'skipped: missing CreateNewLabelInteractor or accountId',
);
return [];
}

final List<Label?> results = await Future.wait(provisioningLabels.map(
(label) => _createLabel(createLabelInteractor, accountId, label),
));

final List<Label> createdLabels = results.whereType<Label>().toList();

if (createdLabels.isNotEmpty) {
labelController?.getAllLabels(accountId);
}

return createdLabels;
}

Future<Label?> _createLabel(
CreateNewLabelInteractor createLabelInteractor,
AccountId accountId,
ProvisioningLabel provisioningLabel,
) async {
final result = await createLabelInteractor
.execute(accountId, provisioningLabel.toLabel())
.last;

return result.fold(
(_) => null,
(success) => success is CreateNewLabelSuccess ? success.newLabel : null,
);
}

Future<List<Label>> provisionLabelsByDisplayNames(List<String> labelNames) {
return provisionLabels(
labelNames.map(ProvisioningLabel.new).toList(),
);
}

List<ProvisioningEmail> buildEmailsForLabel({
required Label label,
required String toEmail,
required int count,
}) {
return List.generate(
count,
(index) {
final emailNumber = index + 1;
final displayName = label.safeDisplayName;

return ProvisioningEmail(
toEmail: toEmail,
subject: 'Email $emailNumber subject $displayName',
content: 'Email $emailNumber content $displayName',
labels: [label],
);
},
);
}
}
2 changes: 2 additions & 0 deletions integration_test/mixin/scenario_utils_mixin.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import 'package:jmap_dart_client/jmap/jmap_request.dart';
import 'package:jmap_dart_client/jmap/mail/email/email_address.dart';
import 'package:jmap_dart_client/jmap/mail/email/set/set_email_method.dart';
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
import 'package:labels/extensions/list_label_extension.dart';
import 'package:model/model.dart';
import 'package:path_provider/path_provider.dart';
import 'package:tmail_ui_user/features/composer/domain/state/upload_attachment_state.dart';
Expand Down Expand Up @@ -81,6 +82,7 @@ mixin ScenarioUtilsMixin {
identity: identity,
attachments: attachments,
hasRequestReadReceipt: requestReadReceipt,
keywords: provisioningEmail.labels.keywords,
),
)
.last;
Expand Down
4 changes: 4 additions & 0 deletions integration_test/models/provisioning_email.dart
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import 'package:labels/labels.dart';

class ProvisioningEmail {
final String toEmail;
final String subject;
final String content;
final List<String> attachmentPaths;
final List<Label> labels;

ProvisioningEmail({
required this.toEmail,
required this.subject,
required this.content,
this.attachmentPaths = const [],
this.labels = const [],
});
}
9 changes: 9 additions & 0 deletions integration_test/models/provisioning_label.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import 'package:labels/model/label.dart';

class ProvisioningLabel {
final String displayName;

ProvisioningLabel(this.displayName);

Label toLabel() => Label(displayName: displayName);
}
14 changes: 14 additions & 0 deletions integration_test/robots/label_robot.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/widgets/labels/label_list_item.dart';

import '../base/core_robot.dart';

class LabelRobot extends CoreRobot {
LabelRobot(super.$);

Future<void> openLabelByName(String name) async {
final item = $(LabelListItem).$(name);
await $.scrollUntilVisible(finder: item);
await item.tap();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import 'package:core/utils/platform_info.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:labels/labels.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/widgets/labels/label_list_view.dart';
import 'package:tmail_ui_user/features/thread/presentation/widgets/email_tile_builder.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';

import '../../base/base_test_scenario.dart';
import '../../mixin/provisioning_label_scenario_mixin.dart';
import '../../robots/label_robot.dart';
import '../../robots/thread_robot.dart';

class DisplayEmptyViewWhenOpenTagScenario extends BaseTestScenario
with ProvisioningLabelScenarioMixin {
const DisplayEmptyViewWhenOpenTagScenario(super.$);

@override
Future<void> setupPreLogin() async {
PlatformInfo.isIntegrationTesting = true;
}

@override
Future<void> runTestLogic() async {
const emailUser = String.fromEnvironment('BASIC_AUTH_EMAIL');

final threadRobot = ThreadRobot($);
final labelRobot = LabelRobot($);

final labels = await provisionLabelsByDisplayNames(
['Tag with email', 'Tag without email'],
);
await $.pumpAndSettle();

int emailCount = 3;
final labelWithEmail =
labels.firstWhere((label) => label.safeDisplayName == 'Tag with email');
final labelWithoutEmail = labels
.firstWhere((label) => label.safeDisplayName == 'Tag without email');

await provisionEmail(
buildEmailsForLabel(
label: labelWithEmail,
toEmail: emailUser,
count: emailCount,
),
requestReadReceipt: false,
);
await $.pumpAndSettle(duration: const Duration(seconds: 2));

await threadRobot.openMailbox();
await _expectLabelListViewVisible();

await labelRobot.openLabelByName(labelWithEmail.safeDisplayName);
await _expectEmailListDisplayedCorrectByTag(
label: labelWithEmail,
emailCount: emailCount,
);

await $.pumpAndSettle(duration: const Duration(seconds: 1));

await threadRobot.openMailbox();
await _expectLabelListViewVisible();

await labelRobot.openLabelByName(labelWithoutEmail.safeDisplayName);
await _expectEmptyViewVisible();
}

Future<void> _expectLabelListViewVisible() =>
expectViewVisible($(LabelListView));

Future<void> _expectEmailListDisplayedCorrectByTag({
required Label label,
required int emailCount,
}) async {
final tagDisplayName = label.safeDisplayName;

final listEmailTileWithTag = $.tester.widgetList<EmailTileBuilder>(
$(EmailTileBuilder).which<EmailTileBuilder>((widget) =>
widget.presentationEmail.subject?.contains(tagDisplayName) == true),
);

expect(listEmailTileWithTag.length, greaterThanOrEqualTo(emailCount));
}

Future<void> _expectEmptyViewVisible() async {
await expectViewVisible($(#empty_thread_view));

await expectViewVisible(
$(find.text(AppLocalizations().youDoNotHaveAnyEmailTaggedWithThis)),
);
}

@override
Future<void> disposeAfterTest() async {
PlatformInfo.isIntegrationTesting = false;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import 'package:core/utils/platform_info.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:labels/labels.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/widgets/labels/label_list_view.dart';
import 'package:tmail_ui_user/features/thread/presentation/widgets/email_tile_builder.dart';

import '../../base/base_test_scenario.dart';
import '../../mixin/provisioning_label_scenario_mixin.dart';
import '../../robots/label_robot.dart';
import '../../robots/thread_robot.dart';

class DisplayViewWithAllEmailWithTagScenario extends BaseTestScenario
with ProvisioningLabelScenarioMixin {
const DisplayViewWithAllEmailWithTagScenario(super.$);

@override
Future<void> setupPreLogin() async {
PlatformInfo.isIntegrationTesting = true;
}

@override
Future<void> runTestLogic() async {
const emailUser = String.fromEnvironment('BASIC_AUTH_EMAIL');

final threadRobot = ThreadRobot($);
final labelRobot = LabelRobot($);

final labels = await provisionLabelsByDisplayNames(
['Tag 1', 'Tag 2', 'Tag 3'],
);
await $.pumpAndSettle();

int emailCount = 3;
for (final label in labels) {
await provisionEmail(
buildEmailsForLabel(
label: label,
toEmail: emailUser,
count: emailCount,
),
requestReadReceipt: false,
);
}
await $.pumpAndSettle(duration: const Duration(seconds: 2));


for (final label in labels) {
await threadRobot.openMailbox();
await _expectLabelListViewVisible();

await labelRobot.openLabelByName(label.safeDisplayName);
await _expectEmailListDisplayedCorrectByTag(
label: label,
emailCount: emailCount,
);

await $.pumpAndSettle(duration: const Duration(seconds: 1));
}
}

Future<void> _expectLabelListViewVisible() =>
expectViewVisible($(LabelListView));

Future<void> _expectEmailListDisplayedCorrectByTag({
required Label label,
required int emailCount,
}) async {
final tagDisplayName = label.safeDisplayName;

final listEmailTileWithTag = $.tester.widgetList<EmailTileBuilder>(
$(EmailTileBuilder).which<EmailTileBuilder>((widget) =>
widget.presentationEmail.subject?.contains(tagDisplayName) == true),
);

expect(listEmailTileWithTag.length, greaterThanOrEqualTo(emailCount));
}

@override
Future<void> disposeAfterTest() async {
PlatformInfo.isIntegrationTesting = false;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import '../../base/test_base.dart';
import '../../scenarios/labels/display_empty_view_when_open_tag_scenario.dart';

void main() {
TestBase().runPatrolTest(
description: 'Should display empty view when open tag with no email',
scenarioBuilder: ($) => DisplayEmptyViewWhenOpenTagScenario($),
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import '../../base/test_base.dart';
import '../../scenarios/labels/display_view_with_all_email_with_tag_scenario.dart';

void main() {
TestBase().runPatrolTest(
description:
'Should display view with all email with tag correctly when open label',
scenarioBuilder: ($) => DisplayViewWithAllEmailWithTagScenario($),
);
}
2 changes: 1 addition & 1 deletion labels/lib/extensions/label_extension.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ extension LabelExtension on Label {
if (id?.value == moreLabelId) {
return AppColor.grayBackgroundColor;
} else {
return color?.value.toColor();
return color?.value.toColor() ?? AppColor.primaryMain;
}
}

Expand Down
4 changes: 4 additions & 0 deletions labels/lib/extensions/list_label_extension.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'package:collection/collection.dart';
import 'package:jmap_dart_client/jmap/mail/email/keyword_identifier.dart';
import 'package:labels/extensions/label_extension.dart';
import 'package:labels/model/label.dart';

Expand All @@ -13,4 +14,7 @@ extension ListLabelExtension on List<Label> {
List<String> get displayNameNotNullList => map((label) => label.safeDisplayName)
.where((name) => name.trim().isNotEmpty)
.toList();

List<KeyWordIdentifier> get keywords =>
map((label) => label.keyword).nonNulls.toList();
}
Loading
Loading