mirror of
https://github.com/immich-app/immich.git
synced 2024-11-15 18:08:48 -07:00
test(app): fix integration test and improve reliability and speed (#1792)
This commit is contained in:
parent
5ad4e5b614
commit
78a5fe2d37
62
.github/workflows/test.yml
vendored
62
.github/workflows/test.yml
vendored
@ -86,8 +86,9 @@ jobs:
|
|||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/setup-java@v3
|
- uses: actions/setup-java@v3
|
||||||
with:
|
with:
|
||||||
distribution: 'adopt'
|
distribution: 'zulu'
|
||||||
java-version: '11'
|
java-version: '12.x'
|
||||||
|
cache: 'gradle'
|
||||||
- name: Cache android SDK
|
- name: Cache android SDK
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v3
|
||||||
id: android-sdk
|
id: android-sdk
|
||||||
@ -96,24 +97,59 @@ jobs:
|
|||||||
path: |
|
path: |
|
||||||
/usr/local/lib/android/
|
/usr/local/lib/android/
|
||||||
~/.android
|
~/.android
|
||||||
|
- name: Cache Gradle
|
||||||
|
uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
./mobile/build/
|
||||||
|
./mobile/android/.gradle/
|
||||||
|
key: ${{ runner.os }}-flutter-${{ hashFiles('**/*.gradle*', 'pubspec.lock') }}
|
||||||
- name: Setup Android SDK
|
- name: Setup Android SDK
|
||||||
if: steps.android-sdk.outputs.cache-hit != 'true'
|
if: steps.android-sdk.outputs.cache-hit != 'true'
|
||||||
uses: android-actions/setup-android@v2
|
uses: android-actions/setup-android@v2
|
||||||
|
- name: AVD cache
|
||||||
|
uses: actions/cache@v3
|
||||||
|
id: avd-cache
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
~/.android/avd/*
|
||||||
|
~/.android/adb*
|
||||||
|
key: avd-29
|
||||||
|
- name: create AVD and generate snapshot for caching
|
||||||
|
if: steps.avd-cache.outputs.cache-hit != 'true'
|
||||||
|
uses: reactivecircus/android-emulator-runner@v2.27.0
|
||||||
|
with:
|
||||||
|
working-directory: ./mobile
|
||||||
|
cores: 2
|
||||||
|
api-level: 29
|
||||||
|
arch: x86_64
|
||||||
|
profile: pixel
|
||||||
|
target: default
|
||||||
|
force-avd-creation: false
|
||||||
|
emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
|
||||||
|
disable-animations: false
|
||||||
|
script: echo "Generated AVD snapshot for caching."
|
||||||
- name: Setup Flutter SDK
|
- name: Setup Flutter SDK
|
||||||
uses: subosito/flutter-action@v2
|
uses: subosito/flutter-action@v2
|
||||||
with:
|
with:
|
||||||
channel: 'stable'
|
channel: 'stable'
|
||||||
flutter-version: '3.7.3'
|
flutter-version: '3.7.3'
|
||||||
|
cache: true
|
||||||
- name: Run integration tests
|
- name: Run integration tests
|
||||||
uses: reactivecircus/android-emulator-runner@v2.27.0
|
uses: Wandalen/wretry.action@master
|
||||||
with:
|
with:
|
||||||
working-directory: ./mobile
|
action: reactivecircus/android-emulator-runner@v2.27.0
|
||||||
api-level: 29
|
with: |
|
||||||
arch: x86_64
|
working-directory: ./mobile
|
||||||
profile: pixel
|
cores: 2
|
||||||
target: default
|
api-level: 29
|
||||||
emulator-options: -no-window -gpu swiftshader_indirect -no-snapshot -noaudio -no-boot-anim
|
arch: x86_64
|
||||||
disable-linux-hw-accel: false
|
profile: pixel
|
||||||
script: |
|
target: default
|
||||||
flutter pub get
|
force-avd-creation: false
|
||||||
flutter test integration_test
|
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
|
||||||
|
disable-animations: true
|
||||||
|
script: |
|
||||||
|
flutter pub get
|
||||||
|
flutter test integration_test
|
||||||
|
attempt_limit: 3
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
@ -43,7 +45,6 @@ class ImmichTestHelper {
|
|||||||
// Load main Widget
|
// Load main Widget
|
||||||
await tester.pumpWidget(app.getMainWidget(db));
|
await tester.pumpWidget(app.getMainWidget(db));
|
||||||
// Post run tasks
|
// Post run tasks
|
||||||
await tester.pumpAndSettle();
|
|
||||||
await EasyLocalization.ensureInitialized();
|
await EasyLocalization.ensureInitialized();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -62,3 +63,17 @@ void immichWidgetTest(
|
|||||||
semanticsEnabled: false,
|
semanticsEnabled: false,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> pumpUntilFound(
|
||||||
|
WidgetTester tester,
|
||||||
|
Finder finder, {
|
||||||
|
Duration timeout = const Duration(seconds: 120),
|
||||||
|
}) async {
|
||||||
|
bool found = false;
|
||||||
|
final timer = Timer(timeout, () => throw TimeoutException("Pump until has timed out"));
|
||||||
|
while (found != true) {
|
||||||
|
await tester.pump();
|
||||||
|
found = tester.any(finder);
|
||||||
|
}
|
||||||
|
timer.cancel();
|
||||||
|
}
|
||||||
|
@ -2,33 +2,20 @@ import 'package:easy_localization/easy_localization.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
|
import 'general_helper.dart';
|
||||||
|
|
||||||
class ImmichTestLoginHelper {
|
class ImmichTestLoginHelper {
|
||||||
final WidgetTester tester;
|
final WidgetTester tester;
|
||||||
|
|
||||||
ImmichTestLoginHelper(this.tester);
|
ImmichTestLoginHelper(this.tester);
|
||||||
|
|
||||||
Future<void> waitForLoginScreen({int timeoutSeconds = 20}) async {
|
Future<void> waitForLoginScreen() async {
|
||||||
for (var i = 0; i < timeoutSeconds; i++) {
|
await pumpUntilFound(tester, find.text("Login"));
|
||||||
// Search for "IMMICH" test in the app bar
|
|
||||||
final result = find.text("IMMICH");
|
|
||||||
if (tester.any(result)) {
|
|
||||||
// Wait 5s until everything settled
|
|
||||||
await tester.pump(const Duration(seconds: 5));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait 1s before trying again
|
|
||||||
await Future.delayed(const Duration(seconds: 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
fail("Timeout while waiting for login screen");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> acknowledgeNewServerVersion() async {
|
Future<bool> acknowledgeNewServerVersion() async {
|
||||||
|
await pumpUntilFound(tester, find.text("Acknowledge"));
|
||||||
final result = find.text("Acknowledge");
|
final result = find.text("Acknowledge");
|
||||||
if (!tester.any(result)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
await tester.tap(result);
|
await tester.tap(result);
|
||||||
await tester.pump();
|
await tester.pump();
|
||||||
@ -43,17 +30,17 @@ class ImmichTestLoginHelper {
|
|||||||
}) async {
|
}) async {
|
||||||
final loginForms = find.byType(TextFormField);
|
final loginForms = find.byType(TextFormField);
|
||||||
|
|
||||||
await tester.pump(const Duration(milliseconds: 500));
|
|
||||||
await tester.enterText(loginForms.at(0), email);
|
await tester.enterText(loginForms.at(0), email);
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
await tester.pump(const Duration(milliseconds: 500));
|
|
||||||
await tester.enterText(loginForms.at(1), password);
|
await tester.enterText(loginForms.at(1), password);
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
await tester.pump(const Duration(milliseconds: 500));
|
|
||||||
await tester.enterText(loginForms.at(2), server);
|
await tester.enterText(loginForms.at(2), server);
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
await tester.testTextInput.receiveAction(TextInputAction.done);
|
await tester.testTextInput.receiveAction(TextInputAction.done);
|
||||||
await tester.pumpAndSettle();
|
await tester.pump();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> enterCredentialsOf(LoginCredentials credentials) async {
|
Future<void> enterCredentialsOf(LoginCredentials credentials) async {
|
||||||
@ -65,32 +52,17 @@ class ImmichTestLoginHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> pressLoginButton() async {
|
Future<void> pressLoginButton() async {
|
||||||
|
await pumpUntilFound(tester, find.textContaining("login_form_button_text".tr()));
|
||||||
final button = find.textContaining("login_form_button_text".tr());
|
final button = find.textContaining("login_form_button_text".tr());
|
||||||
await tester.tap(button);
|
await tester.tap(button);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> assertLoginSuccess({int timeoutSeconds = 15}) async {
|
Future<void> assertLoginSuccess({int timeoutSeconds = 15}) async {
|
||||||
for (var i = 0; i < timeoutSeconds * 2; i++) {
|
await pumpUntilFound(tester, find.text("home_page_building_timeline".tr()));
|
||||||
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 {
|
Future<void> assertLoginFailed({int timeoutSeconds = 15}) async {
|
||||||
for (var i = 0; i < timeoutSeconds * 2; i++) {
|
await pumpUntilFound(tester, find.text("login_form_failed_login".tr()));
|
||||||
if (tester.any(find.text("login_form_failed_login".tr()))) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await tester.pump(const Duration(milliseconds: 500));
|
|
||||||
}
|
|
||||||
|
|
||||||
fail("Timeout.");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user