diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml new file mode 100644 index 0000000..01a2747 --- /dev/null +++ b/.github/workflows/integration-tests.yml @@ -0,0 +1,71 @@ +name: Integration tests + +on: + # Trigger the workflow on pushes to the main and feature branches. + push: + branches: [main, feature/**] + + # Allows us to run the workflow manually from the Actions tab + workflow_dispatch: + +env: + flutter_version: 3.13.6 + iphone_model: iPhone 8 + android_profile: Nexus 6 + android_api_level: 29 + android_target: google_apis + +jobs: + android-integration-tests: + # It should be most efficient to use the macOS because of hardware acceleration available here. + runs-on: macos-latest + steps: + - uses: actions/checkout@v4 + - uses: subosito/flutter-action@v2 + with: + flutter-version: ${{ env.flutter_version }} + channel: 'stable' + cache: true + - uses: actions/setup-java@v1 + with: + java-version: '11' + + # Run integration test with android emulator + - name: Run Flutter integration tests + uses: reactivecircus/android-emulator-runner@v2 + with: + target: ${{ env.android_target }} + api-level: ${{ env.android_api_level }} + arch: x86_64 + profile: ${{ env.android_profile }} + script: flutter test integration_test/ + + iOS-integration-tests: + runs-on: macos-latest + steps: + - uses: actions/checkout@v4 + - uses: subosito/flutter-action@v2 + with: + flutter-version: ${{ env.flutter_version }} + channel: 'stable' + cache: true + + # Start iOS simulator + - uses: futureware-tech/simulator-action@v3 + with: + model: ${{ env.iphone_model }} + + # Run integration test + - run: flutter test integration_test/ + + web-integration-test: + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + - uses: subosito/flutter-action@v2 + with: + flutter-version: ${{ env.flutter_version }} + channel: 'stable' + cache: true + - uses: nanasess/setup-chromedriver@v2 + - run: chromedriver --port=4444 & ./integration_test/run_tests.sh diff --git a/.github/workflows/integration.tests.yml b/.github/workflows/integration.tests.yml new file mode 100644 index 0000000..a62f691 --- /dev/null +++ b/.github/workflows/integration.tests.yml @@ -0,0 +1,72 @@ +name: Integration tests + +on: + # Trigger the workflow on pushes to the main and feature branches. + push: + branches: [main, feature/**] + + # Allows us to run the workflow manually from the Actions tab + workflow_dispatch: + +env: + flutter_version: 3.13.6 + iphone_model: iPhone 8 + android_profile: Nexus 6 + android_api_level: 29 + android_target: google_apis + +jobs: + android-integration-tests: + # It should be most efficient to use the macOS because of hardware acceleration available here. + runs-on: macos-latest + steps: + - uses: actions/checkout@v4 + - uses: subosito/flutter-action@v2 + with: + flutter-version: ${{ env.flutter_version }} + channel: 'stable' + cache: true + - uses: actions/setup-java@v2 + with: + distribution: 'zulu' + java-version: '11' + + # Run integration test with android emulator + - name: Run Flutter integration tests + uses: reactivecircus/android-emulator-runner@v2 + with: + target: ${{ env.android_target }} + api-level: ${{ env.android_api_level }} + arch: x86_64 + profile: ${{ env.android_profile }} + script: flutter test integration_test/ + + iOS-integration-tests: + runs-on: macos-latest + steps: + - uses: actions/checkout@v4 + - uses: subosito/flutter-action@v2 + with: + flutter-version: ${{ env.flutter_version }} + channel: 'stable' + cache: true + + # Start iOS simulator + - uses: futureware-tech/simulator-action@v3 + with: + model: ${{ env.iphone_model }} + + # Run integration test + - run: flutter test integration_test/ + + web-integration-test: + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + - uses: subosito/flutter-action@v2 + with: + flutter-version: ${{ env.flutter_version }} + channel: 'stable' + cache: true + - uses: nanasess/setup-chromedriver@v2 + - run: chromedriver --port=4444 & ./integration_test/run_tests.sh diff --git a/README.md b/README.md index dbd05b7..fe7baa8 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,34 @@ which expands into [`wallet_proxy/model.g.dart`](./lib/services/wallet_proxy/mod The generated class is checked into the repo, but imports always refer to the original one. +## Automated Tests + +For unit / widget tests, run: +```shell +flutter test +``` + +For integration tests on android or ios, make sure you have the test device connected and run: +``` shell +flutter test integration_test +``` + +To run integration tests for web, you must install chromedriver, and run it in a separate terminal: +```shell +chromedriver --port=4444 +``` +And then run the script: +```shell +./integration_test/run_tests.sh +``` +If the HEADER environment variable is set, the tests run with a header. + +To run a specific test file, examplified here with `test_file_name`, run:: +```shell +flutter drive --driver=integration_test/test_driver.dart --target=integration_test/test_file_name.dart -d web-server +``` +You can replace `-d web-server` with `-d chrome` for the test to not run headless. + ## Licenses To see the allowed licenses, check out `scripts/license.yaml`. diff --git a/integration_test/run_web_tests.sh b/integration_test/run_web_tests.sh new file mode 100755 index 0000000..db2103d --- /dev/null +++ b/integration_test/run_web_tests.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +# Use HEADER environment variable to run tests with header (as it defaults to running them headerless) +if [[ -z "${HEADER}" ]]; then + DEVICE=web-server +else + DEVICE=chrome +fi + +find integration_test -type f -name '*_test.dart' | while read -r filename; do + [ -e "$filename" ] || continue + flutter drive --driver=integration_test/test_driver.dart --target=$filename -d $DEVICE +done + diff --git a/integration_test/tac_test.dart b/integration_test/tac_test.dart new file mode 100644 index 0000000..24003b7 --- /dev/null +++ b/integration_test/tac_test.dart @@ -0,0 +1,37 @@ +import 'package:concordium_wallet/screens/terms_and_conditions/widget.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:integration_test/integration_test.dart'; +import 'package:concordium_wallet/main.dart' as start; + +void main() { + IntegrationTestWidgetsFlutterBinding.ensureInitialized(); + + testWidgets('Confirming T&C on the initial page brings us to the reset T&C page and resetting accepted T&C brings us back.', (tester) async { + // Load app widget. + start.main(); + + await tester.pumpAndSettle(); + + expect(find.textContaining('Accepted T&C version', findRichText: true), findsNothing); + expect(find.textContaining('Before you begin', findRichText: true), findsOneWidget); + + await tester.tap(find.byType(ToggleAcceptedWidget)); + + await tester.pump(); + + await tester.tap(find.text("Continue", findRichText: true)); + + // Trigger a frame. + await tester.pumpAndSettle(); + + expect(find.textContaining('Accepted T&C version', findRichText: true), findsOneWidget); + + await tester.tap(find.text("Reset accepted T&C", findRichText: true)); + + // Trigger a frame. + await tester.pumpAndSettle(); + + expect(find.textContaining('Accepted T&C version', findRichText: true), findsNothing); + expect(find.textContaining('Before you begin', findRichText: true), findsOneWidget); + }); +} diff --git a/integration_test/test_driver.dart b/integration_test/test_driver.dart new file mode 100644 index 0000000..b38629c --- /dev/null +++ b/integration_test/test_driver.dart @@ -0,0 +1,3 @@ +import 'package:integration_test/integration_test_driver.dart'; + +Future main() => integrationDriver(); diff --git a/pubspec.lock b/pubspec.lock index e4eae57..baf93b4 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -197,10 +197,10 @@ packages: dependency: transitive description: name: coverage - sha256: "595a29b55ce82d53398e1bcc2cba525d7bd7c59faeb2d2540e9d42c390cfeeeb" + sha256: "2fb815080e44a09b85e0f2ca8a820b15053982b2e714b59267719e8a9ff17097" url: "https://pub.dev" source: hosted - version: "1.6.4" + version: "1.6.3" crypto: dependency: transitive description: @@ -261,10 +261,10 @@ packages: dependency: transitive description: name: file - sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" + sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "6.1.4" fixnum: dependency: transitive description: @@ -286,6 +286,11 @@ packages: url: "https://pub.dev" source: hosted version: "8.1.3" + flutter_driver: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" flutter_lints: dependency: "direct dev" description: @@ -320,6 +325,11 @@ packages: url: "https://pub.dev" source: hosted version: "3.2.0" + fuchsia_remote_debug_protocol: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" glob: dependency: transitive description: @@ -392,6 +402,11 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.2" + integration_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" io: dependency: transitive description: @@ -620,10 +635,10 @@ packages: dependency: transitive description: name: platform - sha256: "0a279f0707af40c890e80b1e9df8bb761694c074ba7e1d4ab1bc4b728e200b59" + sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76" url: "https://pub.dev" source: hosted - version: "3.1.3" + version: "3.1.0" plugin_platform_interface: dependency: transitive description: @@ -640,6 +655,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.5.1" + process: + dependency: transitive + description: + name: process + sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09" + url: "https://pub.dev" + source: hosted + version: "4.2.4" provider: dependency: transitive description: @@ -797,6 +820,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.3.0" + sync_http: + dependency: transitive + description: + name: sync_http + sha256: "7f0cd72eca000d2e026bcd6f990b81d0ca06022ef4e32fb257b30d3d1014a961" + url: "https://pub.dev" + source: hosted + version: "0.3.1" tar: dependency: transitive description: @@ -953,10 +984,10 @@ packages: dependency: transitive description: name: vm_service - sha256: c538be99af830f478718b51630ec1b6bee5e74e52c8a802d328d9e71d35d2583 + sha256: c620a6f783fa22436da68e42db7ebbf18b8c44b9a46ab911f666ff09ffd9153f url: "https://pub.dev" source: hosted - version: "11.10.0" + version: "11.7.1" watcher: dependency: transitive description: @@ -981,6 +1012,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.4.0" + webdriver: + dependency: transitive + description: + name: webdriver + sha256: "3c923e918918feeb90c4c9fdf1fe39220fa4c0e8e2c0fffaded174498ef86c49" + url: "https://pub.dev" + source: hosted + version: "3.0.2" webkit_inspection_protocol: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 1edc948..6191ea5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -59,6 +59,8 @@ dev_dependencies: hive_generator: ^2.0.1 mocktail: ^1.0.1 bloc_test: ^9.1.5 + integration_test: + sdk: flutter license_checker: ^1.6.0 # For information on the generic Dart part of this file, see the diff --git a/scripts/license.yaml b/scripts/license.yaml index d2e8c2e..0328a80 100644 --- a/scripts/license.yaml +++ b/scripts/license.yaml @@ -16,10 +16,14 @@ rejectedLicenses: - GPL-3 packageLicenseOverride: - flutter_test: BSD-3-Clause - flutter_web_plugins: BSD-3-Clause hive_flutter: Apache-2.0 hive_generator: Apache-2.0 + # All of flutter SDK uses BSD-3-Clause + flutter_test: BSD-3-Clause + flutter_web_plugins: BSD-3-Clause + flutter_driver: BSD-3-Clause + integration_test: BSD-3-Clause + fuchsia_remote_debug_protocol: BSD-3-Clause omitDisclaimer: - flutter_test