Skip to content

Commit

Permalink
feature: flutter integration tests (#92)
Browse files Browse the repository at this point in the history
* Create login_page.dart

* feat: add constants , update login screen

* feat: update app

* Update login_page.dart

* feat: add integration tests

* wip

* Update FLUTTER_INTEGRATION_TEST.md

* feat: add integration tests support for iOS

* feat: add CI job to run integration tests

* Update app-integration-test.yml

* wip

* Update melos.yaml

* Update melos.yaml

* Update app-integration-test.yml

* Update app-integration-test.yml

* Update app-integration-test.yml

* feat: update project structure

* Update app-integration-test.yml

* Update pubspec.yaml

* update flutter_web_integration_test

* Update flutter_web_integration_test.sh

* Update flutter_web_integration_test.sh

* Update flutter_web_integration_test.sh

* wip

* wip

* Update app-integration-test.yml

* Update app-integration-test.yml

* wip

* Update flutter_web_integration_test.sh

* Update flutter_web_integration_test.sh

* Update flutter_web_integration_test.sh

* clean up

* Update project.dic

* Update project.dic

* Update project.dic

* Update project.dic

* more clean up

* Update dummy.dart

* Update FLUTTER_INTEGRATION_TEST.md

* update docs

* Update FLUTTER_INTEGRATION_TEST.md

* feat: update android project

* feat: integration scripts for iOS and Android, docs update

* feat: add flutter integration test for Android

* Update project.dic

* Update FLUTTER_INTEGRATION_TEST.md

* Update project.dic

* minor update

* Update flitter-mobile-integration-test.yml

* Update flitter-mobile-integration-test.yml

* Update flutter_android_integration_test.sh

* wip: iOS build

* Update flutter_ios_integration_test.sh

* Update flutter_ios_integration_test.sh

* wip ios

* update iOS project and tests

* update ios

* Update flutter_ios_integration_test.sh

* Update flitter-mobile-integration-test.yml
  • Loading branch information
minikin authored Nov 9, 2023
1 parent 4fc35c2 commit bed71b7
Show file tree
Hide file tree
Showing 44 changed files with 1,749 additions and 137 deletions.
23 changes: 23 additions & 0 deletions .config/dictionaries/project.dic
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
aarch
addrr
adminer
androidx
appspot
asyncio
auditability
bluefireteam
BROTLI
cardano
CEST
cfbundle
chromedriver
chrono
ciphertext
COCOAPODS
codepoints
coti
cryptoxide
Expand All @@ -20,10 +26,14 @@ dotglob
drep
dreps
encryptor
gcloud
genhtml
gmtime
gradlew
ideascale
integ
Intellij
iphoneos
jetbrains
jorm
jormungandr
Expand All @@ -40,11 +50,16 @@ netkey
oneshot
openapi
opentelemetry
Pdart
permissionless
pg_isready
plpgsql
podfile
podhelper
preprod
projectcatalyst
psql
Ptarget
pubkey
pubspec
rapidoc
Expand All @@ -54,11 +69,19 @@ saibatizoku
seckey
slotno
stevenj
subosito
tacho
thiserror
timelike
Traceback
TXNZD
vitss
voteplan
voteplans
xcconfig
xcfilelist
xcodebuild
xctest
xctestrun
xcworkspace
yoroi
55 changes: 55 additions & 0 deletions .github/workflows/flitter-mobile-integration-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
name: 🧪 Flutter iOS and Android Integration Tests

permissions:
contents: read
id-token: write

concurrency:
group: ${{ github.workflow }}-${{ github.head_ref }}
cancel-in-progress: true

on:
schedule:
# Schedule to run at midnight UTC
- cron: "0 0 * * *"

jobs:
integration-tests:
name: Mobile - Integration Tests
runs-on: macos-latest
timeout-minutes: 30
steps:
- name: ⬇️ Checkout repository
uses: actions/checkout@v3

- name: ⤵️ Authenticate with Google Cloud Platform
uses: "google-github-actions/auth@v1"
with:
credentials_json: "${{ secrets.GOOGLE_CREDENTIALS_INTEGRATION_TESTS }}"

- name: ⚙️ Setup Google Cloud SDK
uses: google-github-actions/setup-gcloud@v1

- name: ⚙️ Setup Java
uses: actions/setup-java@v1
with:
java-version: "12.x"

- name: ⚙️ Setup Flutter
uses: subosito/flutter-action@v2
with:
channel: "stable"
cache: true

- name: ⚙️ Setup Melos
uses: bluefireteam/melos-action@v2

- name: ⚙️ Install dependencies for all packages
run: melos build:pub_get:all

- name: 🤖 Run Android Integration Tests
run: ./scripts/flutter_android_integration_test.sh

# TODO: https://github.com/input-output-hk/catalyst-voices/issues/135
# - name: 📱 Run iOS Integration Tests
# run: ./scripts/flutter_ios_integration_test.sh
46 changes: 46 additions & 0 deletions .github/workflows/flitter-web-integration-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
name: 🧪 Flutter Web Integration Tests

permissions:
contents: read
id-token: write

concurrency:
group: ${{ github.workflow }}-${{ github.head_ref }}
cancel-in-progress: true

on:
pull_request:
types:
- opened
- reopened
- synchronize
branches:
- "main"
paths-ignore:
- "**.md"
- "doc/**"
- ".vscode/"

jobs:
integration-tests:
name: Web - Integration Tests
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: ⬇️ Checkout repository
uses: actions/checkout@v3

- name: ⚙️ Setup Flutter
uses: subosito/flutter-action@v2
with:
channel: "stable"
cache: true

- name: ⚙️ Setup Melos
uses: bluefireteam/melos-action@v2

- name: ⚙️ Install dependencies for all packages
run: melos build:pub_get:all

- name: 🤖 Run Integration Tests
run: ./scripts/flutter_web_integration_test.sh
13 changes: 13 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,19 @@ $RECYCLE.BIN/
!/.vscode/settings.recommended.json
!/.vscode/tasks.recommended.json

# Flutter/Dart/Pub
.dart_tool/
.packages
build/
pubspec.lock
.pub-cache/
.pub/
coverage/
.idea/

# Secrets
dev-catalyst-voice-9f78f27c6bc5.json

# Local only development artefacts can get installed here.
/local

Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions catalyst_voices/analysis_options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ include: package:catalyst_analysis/analysis_options.1.0.0.yaml
exclude:
- 'build/**'
- '**/*.g.dart'

linter:
rules:
public_member_api_docs: false
6 changes: 5 additions & 1 deletion catalyst_voices/android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ android {
targetSdkVersion flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}

signingConfigs {
Expand All @@ -74,7 +75,7 @@ android {
}

flavorDimensions "default"
productFlavors {
productFlavors {
production {
dimension "default"
applicationIdSuffix ""
Expand Down Expand Up @@ -110,4 +111,7 @@ flutter {

dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.2.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package io.projectcatalyst.catalyst_voices;

import androidx.test.rule.ActivityTestRule;
import dev.flutter.plugins.integration_test.FlutterTestRunner;
import org.junit.Rule;
import org.junit.runner.RunWith;

@RunWith(FlutterTestRunner.class)
public class MainActivityTest {
@Rule
public ActivityTestRule<MainActivity> rule = new ActivityTestRule<>(MainActivity.class, true, false);
}
5 changes: 5 additions & 0 deletions catalyst_voices/integration_test/main.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import './scenarios/login_scenario.dart' as login_scenario;

void main() {
login_scenario.main();
}
36 changes: 36 additions & 0 deletions catalyst_voices/integration_test/scenarios/login_scenario.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import 'package:catalyst_voices/main_development.dart' as app;
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';

import 'robots/login_robot.dart';

void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
LoginRobot loginRobot;

group('Login', () {
testWidgets('shows error message when login information is missing',
(tester) async {
loginRobot = await _configure(tester);

await loginRobot.enterUsername('Not Valid');
await loginRobot.tapLoginButton();
await loginRobot.checkInvalidCredentialsMessageIsShown();
});

testWidgets('authenticates a user with an username and password',
(tester) async {
loginRobot = await _configure(tester);

await loginRobot.enterUsername('robot');
await loginRobot.enterPassword('1234');
await loginRobot.tapLoginButton();
});
});
}

Future<LoginRobot> _configure(WidgetTester tester) async {
app.main();
await tester.pumpAndSettle();
return LoginRobot(widgetTester: tester);
}
44 changes: 44 additions & 0 deletions catalyst_voices/integration_test/scenarios/robots/login_robot.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import 'package:catalyst_voices/dummy/constants.dart';
import 'package:flutter_test/flutter_test.dart';

final class LoginRobot {
final WidgetTester widgetTester;

const LoginRobot({
required this.widgetTester,
});

Future<void> checkInvalidCredentialsMessageIsShown() async {
final loginErrorSnackbar = find.byKey(WidgetKeys.loginErrorSnackbar);
expect(loginErrorSnackbar, findsOneWidget);
await widgetTester.pump();
}

Future<void> enterPassword(String password) async {
final passwordTextController =
find.byKey(WidgetKeys.passwordTextController);
expect(passwordTextController, findsOneWidget);
await widgetTester.enterText(passwordTextController, password);
await widgetTester.pump();
}

Future<void> enterUsername(String username) async {
final usernameTextController =
find.byKey(WidgetKeys.usernameTextController);
expect(usernameTextController, findsOneWidget);
await widgetTester.enterText(usernameTextController, username);
await widgetTester.pump();
}

Future<void> tapLoginButton() async {
final loginButton = find.byKey(WidgetKeys.loginButton);
expect(loginButton, findsOneWidget);
await widgetTester.tap(loginButton);
await widgetTester.pump();
}

void verifyLoginScreenIsShown() {
final loginScreen = find.byKey(WidgetKeys.loginScreen);
expect(loginScreen, findsOneWidget);
}
}
1 change: 1 addition & 0 deletions catalyst_voices/ios/Flutter/Debug.xcconfig
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "Generated.xcconfig"
1 change: 1 addition & 0 deletions catalyst_voices/ios/Flutter/Release.xcconfig
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "Generated.xcconfig"
46 changes: 46 additions & 0 deletions catalyst_voices/ios/Podfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
platform :ios, '15.0'

ENV['COCOAPODS_DISABLE_STATS'] = 'true'

project 'Runner', {
'Debug' => :debug,
'Profile' => :release,
'Release' => :release,
}

def flutter_root
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
unless File.exist?(generated_xcode_build_settings_path)
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
end

File.foreach(generated_xcode_build_settings_path) do |line|
matches = line.match(/FLUTTER_ROOT\=(.*)/)
return matches[1].strip if matches
end
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
end

require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)

flutter_ios_podfile_setup

target 'Runner' do
use_frameworks!
use_modular_headers!

flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))

target 'RunnerTests' do
inherit! :search_paths
end
end

post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target)
target.build_configurations.each do |config|
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '15.0'
end
end
end
Loading

0 comments on commit bed71b7

Please sign in to comment.