mirror of
https://github.com/KevinMidboe/immich.git
synced 2025-10-29 17:40:28 +00:00
chore(mobile): add login integration tests and reorganize CI definitions (#1417)
* Add integration tests for the login process * Reorganize tests * Test wrong instance URL * Run mobile unit tests in CI * Fix CI * Pin Flutter Version to 3.3.10 * Push something stupid to re-trigger CI
This commit is contained in:
@@ -8,12 +8,11 @@ void main() async {
|
||||
await ImmichTestHelper.initialize();
|
||||
|
||||
group("Login input validation test", () {
|
||||
immichWidgetTest("Test leading/trailing whitespace", (tester) async {
|
||||
await ImmichTestLoginHelper.waitForLoginScreen(tester);
|
||||
await ImmichTestLoginHelper.acknowledgeNewServerVersion(tester);
|
||||
immichWidgetTest("Test leading/trailing whitespace", (tester, helper) async {
|
||||
await helper.loginHelper.waitForLoginScreen();
|
||||
await helper.loginHelper.acknowledgeNewServerVersion();
|
||||
|
||||
await ImmichTestLoginHelper.enterLoginCredentials(
|
||||
tester,
|
||||
await helper.loginHelper.enterCredentials(
|
||||
email: " demo@immich.app"
|
||||
);
|
||||
|
||||
@@ -21,8 +20,7 @@ void main() async {
|
||||
|
||||
expect(find.text("login_form_err_leading_whitespace".tr()), findsOneWidget);
|
||||
|
||||
await ImmichTestLoginHelper.enterLoginCredentials(
|
||||
tester,
|
||||
await helper.loginHelper.enterCredentials(
|
||||
email: "demo@immich.app "
|
||||
);
|
||||
|
||||
@@ -31,12 +29,11 @@ void main() async {
|
||||
expect(find.text("login_form_err_trailing_whitespace".tr()), findsOneWidget);
|
||||
});
|
||||
|
||||
immichWidgetTest("Test invalid email", (tester) async {
|
||||
await ImmichTestLoginHelper.waitForLoginScreen(tester);
|
||||
await ImmichTestLoginHelper.acknowledgeNewServerVersion(tester);
|
||||
immichWidgetTest("Test invalid email", (tester, helper) async {
|
||||
await helper.loginHelper.waitForLoginScreen();
|
||||
await helper.loginHelper.acknowledgeNewServerVersion();
|
||||
|
||||
await ImmichTestLoginHelper.enterLoginCredentials(
|
||||
tester,
|
||||
await helper.loginHelper.enterCredentials(
|
||||
email: "demo.immich.app"
|
||||
);
|
||||
|
||||
|
||||
39
mobile/integration_test/module_login/login_test.dart
Normal file
39
mobile/integration_test/module_login/login_test.dart
Normal file
@@ -0,0 +1,39 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
import '../test_utils/general_helper.dart';
|
||||
import '../test_utils/login_helper.dart';
|
||||
|
||||
void main() async {
|
||||
await ImmichTestHelper.initialize();
|
||||
|
||||
group("Login tests", () {
|
||||
immichWidgetTest("Test correct credentials", (tester, helper) async {
|
||||
await helper.loginHelper.waitForLoginScreen();
|
||||
await helper.loginHelper.acknowledgeNewServerVersion();
|
||||
await helper.loginHelper
|
||||
.enterCredentialsOf(LoginCredentials.testInstance);
|
||||
await helper.loginHelper.pressLoginButton();
|
||||
await helper.loginHelper.assertLoginSuccess();
|
||||
});
|
||||
|
||||
immichWidgetTest("Test login with wrong password", (tester, helper) async {
|
||||
await helper.loginHelper.waitForLoginScreen();
|
||||
await helper.loginHelper.acknowledgeNewServerVersion();
|
||||
await helper.loginHelper.enterCredentialsOf(
|
||||
LoginCredentials.testInstanceButWithWrongPassword);
|
||||
await helper.loginHelper.pressLoginButton();
|
||||
await helper.loginHelper.assertLoginFailed();
|
||||
});
|
||||
|
||||
immichWidgetTest("Test login with wrong server URL", (tester, helper) async {
|
||||
await helper.loginHelper.waitForLoginScreen();
|
||||
await helper.loginHelper.acknowledgeNewServerVersion();
|
||||
await helper.loginHelper.enterCredentialsOf(
|
||||
LoginCredentials.wrongInstanceUrl);
|
||||
await helper.loginHelper.pressLoginButton();
|
||||
await helper.loginHelper.assertLoginFailed();
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -1,14 +1,28 @@
|
||||
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:immich_mobile/main.dart';
|
||||
import 'package:integration_test/integration_test.dart';
|
||||
|
||||
import 'package:meta/meta.dart';
|
||||
import 'package:immich_mobile/main.dart' as app;
|
||||
|
||||
import 'login_helper.dart';
|
||||
|
||||
class ImmichTestHelper {
|
||||
|
||||
final WidgetTester tester;
|
||||
|
||||
ImmichTestHelper(this.tester);
|
||||
|
||||
ImmichTestLoginHelper? _loginHelper;
|
||||
|
||||
ImmichTestLoginHelper get loginHelper {
|
||||
_loginHelper ??= ImmichTestLoginHelper(tester);
|
||||
return _loginHelper!;
|
||||
}
|
||||
|
||||
static Future<IntegrationTestWidgetsFlutterBinding> initialize() async {
|
||||
final binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||
binding.framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.fullyLive;
|
||||
@@ -32,9 +46,12 @@ class ImmichTestHelper {
|
||||
|
||||
}
|
||||
|
||||
void immichWidgetTest(String description, Future<void> Function(WidgetTester) test) {
|
||||
testWidgets(description, (widgetTester) async {
|
||||
await ImmichTestHelper.loadApp(widgetTester);
|
||||
await test(widgetTester);
|
||||
});
|
||||
@isTest
|
||||
void immichWidgetTest(String description, Future<void> Function(WidgetTester, ImmichTestHelper) test) {
|
||||
|
||||
testWidgets(description, (widgetTester) async {
|
||||
await ImmichTestHelper.loadApp(widgetTester);
|
||||
await test(widgetTester, ImmichTestHelper(widgetTester));
|
||||
}, semanticsEnabled: false);
|
||||
|
||||
}
|
||||
@@ -1,10 +1,15 @@
|
||||
import 'dart:async';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:immich_mobile/modules/home/ui/asset_grid/immich_asset_grid.dart';
|
||||
|
||||
class ImmichTestLoginHelper {
|
||||
static Future<void> waitForLoginScreen(WidgetTester tester,
|
||||
{int timeoutSeconds = 20}) async {
|
||||
final WidgetTester tester;
|
||||
|
||||
ImmichTestLoginHelper(this.tester);
|
||||
|
||||
Future<void> waitForLoginScreen({int timeoutSeconds = 20}) async {
|
||||
for (var i = 0; i < timeoutSeconds; i++) {
|
||||
// Search for "IMMICH" test in the app bar
|
||||
final result = find.text("IMMICH");
|
||||
@@ -21,7 +26,7 @@ class ImmichTestLoginHelper {
|
||||
fail("Timeout while waiting for login screen");
|
||||
}
|
||||
|
||||
static Future<bool> acknowledgeNewServerVersion(WidgetTester tester) async {
|
||||
Future<bool> acknowledgeNewServerVersion() async {
|
||||
final result = find.text("Acknowledge");
|
||||
if (!tester.any(result)) {
|
||||
return false;
|
||||
@@ -33,8 +38,7 @@ class ImmichTestLoginHelper {
|
||||
return true;
|
||||
}
|
||||
|
||||
static Future<void> enterLoginCredentials(
|
||||
WidgetTester tester, {
|
||||
Future<void> enterCredentials({
|
||||
String server = "",
|
||||
String email = "",
|
||||
String password = "",
|
||||
@@ -50,6 +54,70 @@ class ImmichTestLoginHelper {
|
||||
await tester.pump(const Duration(milliseconds: 500));
|
||||
await tester.enterText(loginForms.at(2), server);
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 500));
|
||||
await tester.testTextInput.receiveAction(TextInputAction.done);
|
||||
await tester.pumpAndSettle();
|
||||
}
|
||||
|
||||
Future<void> enterCredentialsOf(LoginCredentials credentials) async {
|
||||
await enterCredentials(
|
||||
server: credentials.server,
|
||||
email: credentials.email,
|
||||
password: credentials.password,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> pressLoginButton() async {
|
||||
final button = find.textContaining("login_form_button_text".tr());
|
||||
await tester.tap(button);
|
||||
}
|
||||
|
||||
Future<void> assertLoginSuccess({int timeoutSeconds = 15}) async {
|
||||
for (var i = 0; i < timeoutSeconds * 2; i++) {
|
||||
if (tester.any(find.text("home_page_building_timeline".tr()))) {
|
||||
return;
|
||||
}
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 500));
|
||||
}
|
||||
|
||||
fail("Login failed.");
|
||||
}
|
||||
|
||||
Future<void> assertLoginFailed({int timeoutSeconds = 15}) async {
|
||||
for (var i = 0; i < timeoutSeconds * 2; i++) {
|
||||
if (tester.any(find.text("login_form_failed_login".tr()))) {
|
||||
return;
|
||||
}
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 500));
|
||||
}
|
||||
|
||||
fail("Timeout.");
|
||||
}
|
||||
}
|
||||
|
||||
enum LoginCredentials {
|
||||
testInstance(
|
||||
"https://flutter-int-test.preview.immich.app",
|
||||
"demo@immich.app",
|
||||
"demo",
|
||||
),
|
||||
|
||||
testInstanceButWithWrongPassword(
|
||||
"https://flutter-int-test.preview.immich.app",
|
||||
"demo@immich.app",
|
||||
"wrong",
|
||||
),
|
||||
|
||||
wrongInstanceUrl(
|
||||
"https://does-not-exist.preview.immich.app",
|
||||
"demo@immich.app",
|
||||
"demo",
|
||||
);
|
||||
|
||||
const LoginCredentials(this.server, this.email, this.password);
|
||||
|
||||
final String server;
|
||||
final String email;
|
||||
final String password;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user