Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

First integration test: Sign in with email address and password #175

Merged
merged 15 commits into from
May 16, 2022
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
244 changes: 43 additions & 201 deletions app/integration_test/README.md
Original file line number Diff line number Diff line change
@@ -1,211 +1,53 @@
# Integrations- / E2E-Tests via `integration_test`
# Integration Tests
Unit tests and widget tests are handy for testing individual classes, functions, or widgets. However, they generally don’t test how individual pieces work together as a whole, or capture the performance of an application running on a real device. These tasks are performed with integration tests.

Dieser Ordner wird für Tests mit dem [`integration_test`](https://pub.dev/packages/integration_test) Package benutzt.
Integration tests are written using the [integration_test](https://github.com/flutter/flutter/tree/master/packages/integration_test) package, provided by the SDK.

Das `integration_test`-Package ist die "verbesserte" Version von `flutter_driver` und ermöglicht es einem mit der `widgetTest`-API E2E- bzw. Integrations-Tests zu schreiben, welche auf einem Simulator, echten Gerät oder sogar dem ["Firebase Test Lab"](https://firebase.google.com/docs/test-lab) laufen.
## How to run integration tests
In order to run the integration tests, you need to setup a fresh Sharezone account which can be used for the integration tests. This account needs to be linked to an email address and a password.

Die Tests, Integration von `integration_test` und eine richtige Pipeline sind momentan noch WIP.
Es funktionieren momentan schon mal das erfolgreiche Ausführen der Platzhalter Integrations-Tests auf:
* Android (via Flutter-Driver oder `gradlew`)
* Web
* macOS

### Flutter Driver
Mithilfe folgenden Befehls kann der `foo_test.dart` lokal laufen gelassen werden.
Der Befehl muss aus dem `app`-Ordner heraus laufen gelassen werden (damit die Pfad übereinstimmen).
```
flutter drive \
--driver=test_driver/integration_test.dart \
--target=integration_test/foo_test.dart \
--flavor prod
```

Der `foo_test.dart` **soll extra fehlschlagen** (er beinhaltet einen erfolgreichen und fehlschlagen Test-Fall).

<details>
<summary>Beispiel-Output (hier wird mehrmals das gleiche ausgeprintet warum auch immer)</summary>

```
nilsreichardt marked this conversation as resolved.
Show resolved Hide resolved
Running Gradle task 'assembleProdDebug'...
Running Gradle task 'assembleProdDebug'... Done 87,4s
✓ Built build/app/outputs/flutter-apk/app-prod-debug.apk.
Installing build/app/outputs/flutter-apk/app.apk... 3,7s
I/flutter (10196): Observatory listening on http://127.0.0.1:35209/C0tp8cWHZVU=/
VMServiceFlutterDriver: Connecting to Flutter application at http://127.0.0.1:53350/EDNFZKCFfM0=/
VMServiceFlutterDriver: Isolate found with number: 109424730985447
VMServiceFlutterDriver: Isolate is paused at start.
VMServiceFlutterDriver: Attempting to resume isolate
I/flutter (10196): 00:00 +0: failing test example
VMServiceFlutterDriver: Connected to Flutter application.
I/flutter (10196): (The following exception is now available via WidgetTester.takeException:)
I/flutter (10196): ══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK
╞════════════════════════════════════════════════════
I/flutter (10196): The following TestFailure object was thrown running a test:
I/flutter (10196): Expected: <5>
I/flutter (10196): Actual: <4>
I/flutter (10196):
I/flutter (10196): When the exception was thrown, this was the stack:
I/flutter (10196): #4 main.<anonymous closure>
(file:///Users/jonassharezone/development/projects/sharezone-app/app/integration_test/foo_test.dart:8:5)
I/flutter (10196): #5 testWidgets.<anonymous closure>.<anonymous closure>
(package:flutter_test/src/widget_tester.dart:144:29)
I/flutter (10196): <asynchronous suspension>
[Ausgelassen für weniger Text]
I/flutter (10196): #35 Invoker._onRun.<anonymous closure>
(package:test_api/src/backend/invoker.dart:369:7)
I/flutter (10196): #42 Invoker._onRun (package:test_api/src/backend/invoker.dart:368:11)
I/flutter (10196): #43 LiveTestController.run
(package:test_api/src/backend/live_test_controller.dart:153:11)
I/flutter (10196): (elided 31 frames from dart:async and package:stack_trace)
I/flutter (10196):
I/flutter (10196): This was caught by the test expectation on the following line:
I/flutter (10196):
file:///Users/jonassharezone/development/projects/sharezone-app/app/integration_test/foo_test.dart line 8
I/flutter (10196): The test description was:
I/flutter (10196): failing test example
I/flutter (10196):
════════════════════════════════════════════════════════════════════════════════════════════════════
I/flutter (10196): (If WidgetTester.takeException is called, the above exception will be ignored. If it is
not, then the above exception will be dumped when another exception is caught by the framework or when the
test ends, whichever happens first, and then the test will fail due to having not caught or expected the
exception.)
I/flutter (10196): ══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK
╞════════════════════════════════════════════════════
I/flutter (10196): The following TestFailure object was thrown running a test:
I/flutter (10196): Expected: <5>
I/flutter (10196): Actual: <4>
I/flutter (10196):
I/flutter (10196): When the exception was thrown, this was the stack:
I/flutter (10196): #4 main.<anonymous closure>
(file:///Users/jonassharezone/development/projects/sharezone-app/app/integration_test/foo_test.dart:8:5)
I/flutter (10196): #5 testWidgets.<anonymous closure>.<anonymous closure>
(package:flutter_test/src/widget_tester.dart:144:29)
I/flutter (10196): <asynchronous suspension>
[Ausgelassen für weniger Text]
I/flutter (10196): #35 Invoker._onRun.<anonymous closure>
(package:test_api/src/backend/invoker.dart:369:7)
I/flutter (10196): #42 Invoker._onRun (package:test_api/src/backend/invoker.dart:368:11)
I/flutter (10196): #43 LiveTestController.run
(package:test_api/src/backend/live_test_controller.dart:153:11)
I/flutter (10196): (elided 31 frames from dart:async and package:stack_trace)
I/flutter (10196):
I/flutter (10196): This was caught by the test expectation on the following line:
I/flutter (10196):
file:///Users/jonassharezone/development/projects/sharezone-app/app/integration_test/foo_test.dart line 8
I/flutter (10196): The test description was:
I/flutter (10196): failing test example
I/flutter (10196):
════════════════════════════════════════════════════════════════════════════════════════════════════
I/flutter (10196): 00:00 +0: failing test example [E]
I/flutter (10196): Test failed. See exception logs above.
I/flutter (10196): The test description was: failing test example
I/flutter (10196):
I/flutter (10196): 00:00 +0 -1: succeeding test example
Failure Details:
Failure in method: failing test example
══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞═════════════════
The following TestFailure object was thrown running a test:
Expected: <5>
Actual: <4>

When the exception was thrown, this was the stack:
#4 main.<anonymous closure> (file:///Users/jonassharezone/development/projects/sharezone-app/app/integration_test/foo_test.dart:8:5)
#5 testWidgets.<anonymous closure>.<anonymous closure> (package:flutter_test/src/widget_tester.dart:144:29)
[Ausgelassen für weniger Text]
#35 Invoker._onRun.<anonymous closure> (package:test_api/src/backend/invoker.dart:369:7)
#42 Invoker._onRun (package:test_api/src/backend/invoker.dart:368:11)
#43 LiveTestController.run (package:test_api/src/backend/live_test_controller.dart:153:11)
(elided 31 frames from dart:async and package:stack_trace)

This was caught by the test expectation on the following line:
file:///Users/jonassharezone/development/projects/sharezone-app/app/integration_test/foo_test.dart line 8
The test description was:
failing test example
═════════════════════════════════════════════════════════════════

end of failure 1



Stopping application instance.
Driver tests failed: 1
### Mobile
You can run the integration tests using the `flutter test` command:
```sh
fvm flutter test \
integration_test \
--flavor dev \
--dart-define \
USER_1_EMAIL="[email protected]" \
--dart-define \
USER_1_PASSWORD="YOUR_PASSWORD"
```
</details>

### Web
Der Test kann wie folgt auf dem Web gelaufen lassen werden:
1. Falls nicht bereits vorhanden `chromedriver` installieren. (z.B. per `brew install chromedriver`)
2. `chromedriver --port=4444` ausführen und einen Server starten
3. In einem anderem Terminal aus dem `app`-Ordner den unten stehenden Flutter-Befehl ausführen
```
flutter drive \
--driver=test_driver/integration_test.dart \
--target=integration_test/foo_test.dart \
_Note: The integration tests are not working for the web at the moment because we need to migrate our app to null safety. Otherwise, the build will fail because of this message:_
```
org-dartlang-app:/app_test.dart:27:11: Error: Non-nullable variable 'dependencies' must be assigned before it can be used.
await dependencies.blocDependencies.auth.signOut();
^^^^^^^^^^^^
org-dartlang-app:/app_test.dart:34:30: Error: Non-nullable variable 'dependencies' must be assigned before it can be used.
beitrittsversuche: dependencies.beitrittsversuche,
^^^^^^^^^^^^
org-dartlang-app:/app_test.dart:35:29: Error: Non-nullable variable 'dependencies' must be assigned before it can be used.
blocDependencies: dependencies.blocDependencies,
^^^^^^^^^^^^
org-dartlang-app:/app_test.dart:36:28: Error: Non-nullable variable 'dependencies' must be assigned before it can be used.
dynamicLinkBloc: dependencies.dynamicLinkBloc,
^^^^^^^^^^^^
```
Comment on lines +22 to +36
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like this might happen because on web it runs with null-safety?

Couldn't we either:

  1. Use late for group variables
  late AppDependencies dependencies;
  late _UserCredentials user1;
  1. Pass --no-sound-null-safety explicitly

  2. Make the app_test file use null-safety by using // @dart=2.14

(I haven't tried any of it - just general ideas.)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also tried this, but you will get a different error other packages require null safety.


To get started testing in a web browser, download [ChromeDriver](https://chromedriver.chromium.org/downloads).

Launch WebDriver, for example:
```sh
chromedriver --port=4444
```

And then run the following command in a different process:
```sh
fvm flutter test \
integration_test
--flavor dev
-d web-server
```

### Android Device Testing
Disclaimer: Ich (Jonas) weiß noch nicht, was der Unterschied zwischen einem solchen Test und einem Flutter-Driver Test auf einem Android-Gerät ist.

Unter `app/android` folgenden Befehl ausführen:
```
./gradlew app:connectedAndroidTest -Ptarget=`pwd`/../integration_test/foo_test.dart
```

Beispiel-Output:
```
> Task :app:connectedDevDebugAndroidTest FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':app:connectedDevDebugAndroidTest'.
> There were failing tests. See the report at: file:///Users/jonassharezone/development/projects/sharezone-app/app/build/app/reports/androidTests/connected/flavors/DEV/index.html

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

Deprecated Gradle features were used in this build, making it incompatible with Gradle 7.0.
Use '--warning-mode all' to show the individual deprecation warnings.
See https://docs.gradle.org/6.3/userguide/command_line_interface.html#sec:command_line_warnings

BUILD FAILED in 2m 13s
963 actionable tasks: 961 executed, 2 up-to-date
```

### Firebase Test Lab
Noch nicht getestet.

### iOS Device Testing
**Nicht funktionell:** Für das iOS Device Testing wurde das Target "RunnerTests" unter XCode hinzugefügt. Allerdings schlägt das builden immer noch durch folgenden Fehler fehl: `'IntegrationTest/IntegrationTestIosTest.h' file not found`
Siehe Ticket: https://github.com/flutter/flutter/issues/72876

Unter `app/ios` folgenden Befehl ausführen (flavor anpassen):
```
flutter build ios --flavor prod integration_test/foo_test.dart --simulator
```

Nächster Schritt noch unklar
```
???
```

### macOS

Mit folgendem Befehl lässt sich die App für macOS builden und die momentanen Platzhalter-Tests laufen (und richtigerweise fehlschlagen):
```
flutter drive \
--driver=test_driver/integration_test.dart \
--target=integration_test/foo_test.dart \
-d macos
```


Es erscheint allerdings diese Warnung:
```
flutter: Warning: integration_test test plugin was not detected.
```

Was das genau bedeutet ist mir momentan unklar. Es kann sein, dass so richtige App- bzw. Widget-Tests doch nicht funktionieren. Das ist allerdings nur eine Vermutung.
88 changes: 88 additions & 0 deletions app/integration_test/app_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// Copyright (c) 2022 Sharezone UG (haftungsbeschränkt)
// Licensed under the EUPL-1.2-or-later.
//
// You may obtain a copy of the Licence at:
// https://joinup.ec.europa.eu/software/page/eupl
//
// SPDX-License-Identifier: EUPL-1.2

import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:sharezone/main/run_app.dart';
import 'package:sharezone/main/sharezone.dart';

void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();

AppDependencies dependencies;
_UserCredentials user1;

setUpAll(() async {
dependencies = await initializeDependencies();
});

setUp(() async {
// Credentials are passed via environment variables. See "README.md" how to
// pass the them correctly.
user1 = _UserCredentials(
email: const String.fromEnvironment('USER_1_EMAIL'),
password: const String.fromEnvironment('USER_1_PASSWORD'),
);

// We should ensure that the user is logged out before running a test, to
// have fresh start.
await dependencies.blocDependencies.auth.signOut();
nilsreichardt marked this conversation as resolved.
Show resolved Hide resolved
});

Future<void> _pumpSharezoneApp(WidgetTester tester) async {
await tester.pumpWidget(
Sharezone(
beitrittsversuche: dependencies.beitrittsversuche,
blocDependencies: dependencies.blocDependencies,
dynamicLinkBloc: dependencies.dynamicLinkBloc,
),
);
}

group('Authentication', () {
testWidgets('User should be able to sign in', (tester) async {
await _pumpSharezoneApp(tester);
await tester.pumpAndSettle(const Duration(seconds: 1));

await tester.tap(find.byKey(const Key('go-to-login-button-E2E')));
await tester.pumpAndSettle();

await tester.enterText(
find.byKey(const Key('email-text-field-E2E')),
user1.email,
);
await tester.enterText(
find.byKey(const Key('password-text-field-E2E')),
user1.password,
);

await tester.tap(find.byKey(const Key('login-button-E2E')));
await tester.pumpAndSettle();

expect(
find.byKey(const Key('dashboard-appbar-title-E2E')),
findsOneWidget,
);
});
});
}

/// The credentials for user used in the integration tests.
class _UserCredentials {
const _UserCredentials({
@required this.email,
@required this.password,
});

/// The email address of the user.
final String email;

/// The password of the user.
final String password;
}
22 changes: 0 additions & 22 deletions app/integration_test/foo_test.dart

This file was deleted.

4 changes: 2 additions & 2 deletions app/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ PODS:
- firebase_core (1.10.5):
- Firebase/CoreOnly (= 8.9.0)
- Flutter
- firebase_crashlytics (2.4.3):
- firebase_crashlytics (2.6.3):
- Firebase/Crashlytics (= 8.9.0)
- firebase_core
- Flutter
Expand Down Expand Up @@ -535,7 +535,7 @@ SPEC CHECKSUMS:
firebase_auth: fe3a1deb12ebd850295344234abc15588d086baf
firebase_auth_oauth: 2b6873838f5712f414740e98679481bbea640bd3
firebase_core: dfcae4c150a5e24436a0b7677c470478a234d5bf
firebase_crashlytics: 6713843d68feb3cefa1471e20dfaa72b934d6db8
firebase_crashlytics: cbd19db068714f8c2319491042f06fc2d2c65bcb
firebase_dynamic_links: 6aa278fc5e6e8cca17d5aa4c7aa46283f2b94749
firebase_messaging: 1109f5449638254c47fb5904d24e11a4d7736c77
firebase_performance: a87be8f45dda8d075c9ae75b1b64353aa33dd49f
Expand Down
3 changes: 2 additions & 1 deletion app/lib/blocs/blackboard/blackboard_page_bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ class BlackboardPageBloc extends BlocBase {
}

@override
void dispose() {
Future<void> dispose() async {
await _viewsSubject.drain();
_viewsSubject.close();
}
}
Loading