1
0
Fork 0
mirror of https://github.com/immich-app/immich.git synced 2024-12-28 22:51:59 +00:00

test(app): fix integration test and improve reliability and speed (#1792)

This commit is contained in:
Zack Pollard 2023-02-19 17:50:36 +00:00 committed by GitHub
parent 5ad4e5b614
commit 78a5fe2d37
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 77 additions and 54 deletions

View file

@ -86,8 +86,9 @@ jobs:
- uses: actions/checkout@v3
- uses: actions/setup-java@v3
with:
distribution: 'adopt'
java-version: '11'
distribution: 'zulu'
java-version: '12.x'
cache: 'gradle'
- name: Cache android SDK
uses: actions/cache@v3
id: android-sdk
@ -96,24 +97,59 @@ jobs:
path: |
/usr/local/lib/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
if: steps.android-sdk.outputs.cache-hit != 'true'
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
uses: subosito/flutter-action@v2
with:
channel: 'stable'
flutter-version: '3.7.3'
cache: true
- name: Run integration tests
uses: reactivecircus/android-emulator-runner@v2.27.0
uses: Wandalen/wretry.action@master
with:
working-directory: ./mobile
api-level: 29
arch: x86_64
profile: pixel
target: default
emulator-options: -no-window -gpu swiftshader_indirect -no-snapshot -noaudio -no-boot-anim
disable-linux-hw-accel: false
script: |
flutter pub get
flutter test integration_test
action: 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-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

View file

@ -1,3 +1,5 @@
import 'dart:async';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:hive/hive.dart';
@ -43,7 +45,6 @@ class ImmichTestHelper {
// Load main Widget
await tester.pumpWidget(app.getMainWidget(db));
// Post run tasks
await tester.pumpAndSettle();
await EasyLocalization.ensureInitialized();
}
}
@ -62,3 +63,17 @@ void immichWidgetTest(
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();
}

View file

@ -2,33 +2,20 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'general_helper.dart';
class ImmichTestLoginHelper {
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");
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<void> waitForLoginScreen() async {
await pumpUntilFound(tester, find.text("Login"));
}
Future<bool> acknowledgeNewServerVersion() async {
await pumpUntilFound(tester, find.text("Acknowledge"));
final result = find.text("Acknowledge");
if (!tester.any(result)) {
return false;
}
await tester.tap(result);
await tester.pump();
@ -43,17 +30,17 @@ class ImmichTestLoginHelper {
}) async {
final loginForms = find.byType(TextFormField);
await tester.pump(const Duration(milliseconds: 500));
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.pump();
await tester.pump(const Duration(milliseconds: 500));
await tester.enterText(loginForms.at(2), server);
await tester.pump();
await tester.testTextInput.receiveAction(TextInputAction.done);
await tester.pumpAndSettle();
await tester.pump();
}
Future<void> enterCredentialsOf(LoginCredentials credentials) async {
@ -65,32 +52,17 @@ class ImmichTestLoginHelper {
}
Future<void> pressLoginButton() async {
await pumpUntilFound(tester, find.textContaining("login_form_button_text".tr()));
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.");
await pumpUntilFound(tester, find.text("home_page_building_timeline".tr()));
}
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.");
await pumpUntilFound(tester, find.text("login_form_failed_login".tr()));
}
}