feat: patrol on-device integration smoke test
This commit is contained in:
parent
d6f4c434fa
commit
6f6fa20b58
10 changed files with 466 additions and 6 deletions
11
.gitignore
vendored
11
.gitignore
vendored
|
|
@ -42,3 +42,14 @@ app.*.map.json
|
|||
/android/app/debug
|
||||
/android/app/profile
|
||||
/android/app/release
|
||||
/android/build
|
||||
|
||||
# Rust wrapper crate (native/)
|
||||
native/target/
|
||||
|
||||
# Rust cdylibs built into the APK by devbox run build-native-android
|
||||
android/app/src/main/jniLibs/
|
||||
|
||||
# Patrol generates the bundle from the integration tests at run time
|
||||
**/test_bundle.dart
|
||||
.patrol.env
|
||||
|
|
|
|||
5
android/.gitignore
vendored
5
android/.gitignore
vendored
|
|
@ -1,8 +1,9 @@
|
|||
gradle-wrapper.jar
|
||||
/.gradle
|
||||
/captures/
|
||||
/gradlew
|
||||
/gradlew.bat
|
||||
# gradlew stays tracked: it carries the nix project-cache redirect that every
|
||||
# non-flutter gradle invocation (patrol_cli, manual builds) needs, so the
|
||||
# wrapper can't be re-injected from the template.
|
||||
/local.properties
|
||||
GeneratedPluginRegistrant.java
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,25 @@ android {
|
|||
targetSdk = flutter.targetSdkVersion
|
||||
versionCode = flutter.versionCode
|
||||
versionName = flutter.versionName
|
||||
// The Android Test Orchestrator (with clearPackageData) wipes the
|
||||
// integration flavor's app data between test runs, and the flavor
|
||||
// installs it beside — never over — the real app, so every patrol run
|
||||
// starts at onboarding with a fresh identity.
|
||||
testInstrumentationRunner = "pl.leancode.patrol.PatrolJUnitRunner"
|
||||
testInstrumentationRunnerArguments["clearPackageData"] = "true"
|
||||
}
|
||||
|
||||
testOptions {
|
||||
execution = "ANDROIDX_TEST_ORCHESTRATOR"
|
||||
}
|
||||
|
||||
flavorDimensions += "test"
|
||||
productFlavors {
|
||||
create("integration") {
|
||||
dimension = "test"
|
||||
applicationIdSuffix = ".integration"
|
||||
versionNameSuffix = "-integration"
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
|
|
@ -38,3 +57,10 @@ android {
|
|||
flutter {
|
||||
source = "../.."
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// The orchestrator referenced by testOptions.execution above. The patrol
|
||||
// native library itself comes from the patrol pub package's android
|
||||
// module (a plugin subproject), not from a Maven artifact.
|
||||
androidTestUtil("androidx.test:orchestrator:1.5.1")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
package com.app.smol_mail.integration;
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
import pl.leancode.patrol.PatrolJUnitRunner;
|
||||
|
||||
// The Patrol host class: each Dart test in the integration_test directory is
|
||||
// executed through this JUnit suite. Its package is the flavored applicationId
|
||||
// (com.app.smol_mail + .integration suffix); the namespace differs, so
|
||||
// MainActivity needs the explicit import below.
|
||||
@RunWith(Parameterized.class)
|
||||
public class MainActivityTest {
|
||||
|
||||
@Parameters(name = "{0}")
|
||||
public static Object[] testCases() {
|
||||
PatrolJUnitRunner instrumentation =
|
||||
(PatrolJUnitRunner) InstrumentationRegistry.getInstrumentation();
|
||||
instrumentation.setUp(com.example.smol_mail.MainActivity.class);
|
||||
instrumentation.waitForPatrolAppService();
|
||||
return instrumentation.listDartTests();
|
||||
}
|
||||
|
||||
public MainActivityTest(String dartTestName) {
|
||||
this.dartTestName = dartTestName;
|
||||
}
|
||||
|
||||
private final String dartTestName;
|
||||
|
||||
@Test
|
||||
public void runDartTest() {
|
||||
PatrolJUnitRunner instrumentation =
|
||||
(PatrolJUnitRunner) InstrumentationRegistry.getInstrumentation();
|
||||
instrumentation.runDartTest(dartTestName);
|
||||
}
|
||||
}
|
||||
171
android/gradlew
vendored
Executable file
171
android/gradlew
vendored
Executable file
|
|
@ -0,0 +1,171 @@
|
|||
#!/nix/store/gik3rh1vz2jlgnifb9dh6vc6sxwwz9jj-bash-5.3p9/bin/bash
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS=""
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn ( ) {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die ( ) {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
esac
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=$((i+1))
|
||||
done
|
||||
case $i in
|
||||
(0) set -- ;;
|
||||
(1) set -- "$args0" ;;
|
||||
(2) set -- "$args0" "$args1" ;;
|
||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
|
||||
function splitJvmOpts() {
|
||||
JVM_OPTS=("$@")
|
||||
}
|
||||
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
|
||||
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
|
||||
|
||||
# Nix's flutter keeps the flutter_tools/gradle composite build on a read-only
|
||||
# store path, so every gradle invocation needs its project and Kotlin caches
|
||||
# redirected off it — the same two arguments the flutter tool itself passes.
|
||||
# Without them, any gradlew run other than through the flutter tool (patrol_cli,
|
||||
# manual builds) fails with a silent exit 1.
|
||||
_nix_cache="${XDG_CACHE_HOME:-$HOME/.cache}/flutter/nix-flutter-tools-gradle/gradle-project-cache"
|
||||
case " $* " in
|
||||
*" --project-cache-dir"*) ;;
|
||||
*) set -- "$@" "--project-cache-dir=$_nix_cache" "-Pkotlin.project.persistent.dir=$_nix_cache/kotlin" ;;
|
||||
esac
|
||||
|
||||
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
|
||||
11
devbox.json
11
devbox.json
|
|
@ -10,7 +10,9 @@
|
|||
"nixpkgs#ninja",
|
||||
"nixpkgs#pkg-config",
|
||||
"nixpkgs#gtk3",
|
||||
"nixpkgs#libsysprof-capture"
|
||||
"nixpkgs#libsysprof-capture",
|
||||
"nixpkgs#rustup",
|
||||
"nixpkgs#cargo-ndk"
|
||||
],
|
||||
"shell": {
|
||||
"init_hook": [
|
||||
|
|
@ -22,7 +24,12 @@
|
|||
"test": "flutter test",
|
||||
"run-linux": "flutter run -d linux",
|
||||
"build-linux": "flutter build linux",
|
||||
"link-android-tools": "if [ -n \"$ANDROID_HOME\" ] && [ ! -d \"$ANDROID_HOME/cmdline-tools/latest\" ] && [ -d \"$ANDROID_HOME/cmdline-tools/8.0\" ]; then ln -s \"$ANDROID_HOME/cmdline-tools/8.0\" \"$ANDROID_HOME/cmdline-tools/latest\"; fi"
|
||||
"link-android-tools": "if [ -n \"$ANDROID_HOME\" ] && [ ! -d \"$ANDROID_HOME/cmdline-tools/latest\" ] && [ -d \"$ANDROID_HOME/cmdline-tools/8.0\" ]; then ln -s \"$ANDROID_HOME/cmdline-tools/8.0\" \"$ANDROID_HOME/cmdline-tools/latest\"; fi",
|
||||
"build-native": "cd native && cargo build --release",
|
||||
"build-native-android": "rustup target add aarch64-linux-android armv7-linux-androideabi x86_64-linux-android && cd native && cargo ndk -t arm64-v8a -t armeabi-v7a -t x86_64 -o ../android/app/src/main/jniLibs build --release",
|
||||
"test-native": "cd native && cargo test --release && cargo test --release -- --ignored",
|
||||
"activate-patrol": "dart pub global activate patrol_cli",
|
||||
"test-integration": "export PATH=\"$HOME/.pub-cache/bin:$PATH\" && patrol test --dart-define=SMOL_TEST_HOST=$(hostname -I | tr ' ' '\\n' | grep -E '^(192\\.168|10\\.|172\\.)' | head -1)"
|
||||
}
|
||||
},
|
||||
"env": {
|
||||
|
|
|
|||
|
|
@ -57,6 +57,10 @@
|
|||
"last_modified": "1970-01-01T00:00:00Z",
|
||||
"resolved": "path:/nix/store/v8ynlbrldn7k8byb1kx0j0wka8dsbrw9-source?narHash=sha256-BZWCi9ZRJiARTuKTbbtvFTj7t1TK4G3UEckT3HyNfRg%3D#android-tools"
|
||||
},
|
||||
"nixpkgs#cargo-ndk": {
|
||||
"last_modified": "1970-01-01T00:00:00Z",
|
||||
"resolved": "path:/nix/store/v8ynlbrldn7k8byb1kx0j0wka8dsbrw9-source?narHash=sha256-BZWCi9ZRJiARTuKTbbtvFTj7t1TK4G3UEckT3HyNfRg%3D#cargo-ndk"
|
||||
},
|
||||
"nixpkgs#clang": {
|
||||
"last_modified": "1970-01-01T00:00:00Z",
|
||||
"resolved": "path:/nix/store/v8ynlbrldn7k8byb1kx0j0wka8dsbrw9-source?narHash=sha256-BZWCi9ZRJiARTuKTbbtvFTj7t1TK4G3UEckT3HyNfRg%3D#clang"
|
||||
|
|
@ -84,6 +88,10 @@
|
|||
"nixpkgs#pkg-config": {
|
||||
"last_modified": "1970-01-01T00:00:00Z",
|
||||
"resolved": "path:/nix/store/v8ynlbrldn7k8byb1kx0j0wka8dsbrw9-source?narHash=sha256-BZWCi9ZRJiARTuKTbbtvFTj7t1TK4G3UEckT3HyNfRg%3D#pkg-config"
|
||||
},
|
||||
"nixpkgs#rustup": {
|
||||
"last_modified": "1970-01-01T00:00:00Z",
|
||||
"resolved": "path:/nix/store/v8ynlbrldn7k8byb1kx0j0wka8dsbrw9-source?narHash=sha256-BZWCi9ZRJiARTuKTbbtvFTj7t1TK4G3UEckT3HyNfRg%3D#rustup"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
97
integration_test/smoke_test.dart
Normal file
97
integration_test/smoke_test.dart
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
// Device integration tests over the real UI, driven by Patrol against the
|
||||
// system bunshin on the test host. The integration flavor installs beside
|
||||
// the real app and the instrumentation runner clears its data, so every run
|
||||
// starts at onboarding with a fresh identity — the app's own flows are the
|
||||
// subject under test, including the network path.
|
||||
//
|
||||
// Run: devbox run test-integration
|
||||
// (the script resolves the host's LAN IP into SMOL_TEST_HOST, because the
|
||||
// device reaches the server over Wi-Fi, not loopback.)
|
||||
|
||||
import "package:flutter/material.dart";
|
||||
import "package:flutter_riverpod/flutter_riverpod.dart";
|
||||
import "package:hive_flutter/hive_flutter.dart";
|
||||
import "package:path_provider/path_provider.dart";
|
||||
|
||||
import "package:patrol/patrol.dart";
|
||||
|
||||
import "package:smol_mail/data/providers/providers.dart";
|
||||
import "package:smol_mail/presentation/app_widget.dart";
|
||||
import "package:smol_mail/smol/config.dart";
|
||||
import "package:smol_mail/smol/store.dart";
|
||||
|
||||
const testHost = String.fromEnvironment("SMOL_TEST_HOST", defaultValue: "10.0.2.2");
|
||||
|
||||
// The system bunshin's static key: a documented, operator-supplied value on
|
||||
// this machine — the trusted channel SPEC.md §4 asks a pin to come from.
|
||||
const serverKey = "lm2gqd7e5q67xq3isc5hx6jfj2q7a7xvq4l7trctxipudujovmgq";
|
||||
|
||||
Future<Widget> bootApp() async {
|
||||
// main()'s boot, minus runApp: the test pumps the same tree.
|
||||
final dataDir = await getApplicationSupportDirectory();
|
||||
Hive.init(dataDir.path);
|
||||
final store = await SmolStore.open(dbPath: "${dataDir.path}/smol-mail.db");
|
||||
applyPresetServer(store);
|
||||
return ProviderScope(
|
||||
overrides: [storeProvider.overrideWithValue(store)],
|
||||
child: const AppWidget(),
|
||||
);
|
||||
}
|
||||
|
||||
void main() {
|
||||
patrolTest("smoke: onboarding, register, self-send, fetch, read in requests",
|
||||
($) async {
|
||||
await $.pumpWidgetAndSettle(await bootApp());
|
||||
|
||||
// Onboarding: a fresh identity, backed up, registered under a name no
|
||||
// server has bound yet — registration must succeed against the real
|
||||
// server over Wi-Fi, through the Dart-resolved dial path.
|
||||
await $("Create Identity").tap();
|
||||
await $.pumpAndSettle();
|
||||
await $("I have backed it up").waitUntilVisible();
|
||||
await $("I have backed it up").tap();
|
||||
await $.pumpAndSettle();
|
||||
|
||||
final user = "it${DateTime.now().millisecondsSinceEpoch.toRadixString(36)}";
|
||||
// Enter text by TextField, not by its labelText: the decoration label is
|
||||
// a RichText that is not hit-testable, so a text finder times out.
|
||||
await $.enterText($(TextField).at(0), "$user@$testHost:1961");
|
||||
await $.enterText($(TextField).at(1), serverKey);
|
||||
await $("Pin and Register").tap();
|
||||
|
||||
// The register round trip is real network: the inbox tabs only exist
|
||||
// behind HomeGuard, so reaching them proves the account bound.
|
||||
await $("Inbox").waitUntilVisible(timeout: const Duration(seconds: 30));
|
||||
await $("Requests").waitUntilVisible();
|
||||
|
||||
// Compose the first self-addressed mail.
|
||||
await $(Icons.edit).tap();
|
||||
await $.pumpAndSettle();
|
||||
await $.enterText($(TextField).at(0), "$user@$testHost:1961");
|
||||
await $.enterText($(TextField).at(1), "smoke subject");
|
||||
await $.enterText($(TextField).at(2), "smoke body from patrol");
|
||||
await $("Send").tap();
|
||||
// Compose pops back to the inbox once the send round trip completes.
|
||||
await $("Inbox").waitUntilVisible(timeout: const Duration(seconds: 30));
|
||||
await $.pumpAndSettle();
|
||||
|
||||
// Fetch over the air, then read what arrived.
|
||||
await $(Icons.cloud_download).tap();
|
||||
await $.pumpAndSettle(duration: const Duration(seconds: 5));
|
||||
await $("Requests (1)").tap();
|
||||
await $.pumpAndSettle();
|
||||
|
||||
// First contact is unsolicited, so it landed in requests (sec 5.8) —
|
||||
// and the §5.6 sent copy must read back as plain text, not <unreadable>.
|
||||
await $("smoke subject").tap();
|
||||
await $.pumpAndSettle();
|
||||
await $("smoke body from patrol").waitUntilVisible();
|
||||
await $.native.pressBack(); // ignore: deprecated_member_use
|
||||
await $.pumpAndSettle();
|
||||
await $("Sent").tap();
|
||||
await $.pumpAndSettle();
|
||||
await $("smoke subject").tap();
|
||||
await $.pumpAndSettle();
|
||||
await $("smoke body from patrol").waitUntilVisible();
|
||||
});
|
||||
}
|
||||
89
pubspec.lock
89
pubspec.lock
|
|
@ -249,6 +249,22 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.8.0"
|
||||
dispose_scope:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: dispose_scope
|
||||
sha256: "48ec38ca2631c53c4f8fa96b294c801e55c335db5e3fb9f82cede150cfe5a2af"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
equatable:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: equatable
|
||||
sha256: "3bce007a596ff8b3119c45d68aaef631272537c03d30e5d4534dd24bf4c5eaa2"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
fake_async:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
@ -258,7 +274,7 @@ packages:
|
|||
source: hosted
|
||||
version: "1.3.3"
|
||||
ffi:
|
||||
dependency: transitive
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: ffi
|
||||
sha256: "6d7fd89431262d8f3125e81b50d3847a091d846eafcd4fdb88dd06f36d705a45"
|
||||
|
|
@ -334,6 +350,11 @@ packages:
|
|||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
flutter_driver:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
flutter_launcher_icons:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
|
|
@ -384,6 +405,11 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.0"
|
||||
fuchsia_remote_debug_protocol:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
glob:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
@ -440,6 +466,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.15.7"
|
||||
http:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: http
|
||||
sha256: "87721a4a50b19c7f1d49001e51409bddc46303966ce89a65af4f4e6004896412"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.6.0"
|
||||
http_multi_server:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
@ -464,6 +498,11 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.10.1"
|
||||
integration_test:
|
||||
dependency: "direct dev"
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
intl:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
|
@ -672,6 +711,30 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.0"
|
||||
patrol:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: patrol
|
||||
sha256: "662c50d517b2f159fedbc359a7fb8d0d30cbefea6d5c2a08392a0593079d64d1"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.10.0"
|
||||
patrol_finders:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: patrol_finders
|
||||
sha256: "8608cdacaab90a3b00ecd7b09df11f13a62b01dea13c211b9f13fd86854e103a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.6.0"
|
||||
patrol_log:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: patrol_log
|
||||
sha256: "3d91c93e8d0ed19cb12d4b27aa24eca7294e0a48d9d8445505c9775feb5fde2d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.10.1"
|
||||
petitparser:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
@ -712,6 +775,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.5.2"
|
||||
process:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: process
|
||||
sha256: "4242ba3508d37e01808bdf71ad1d5bb93a8d671bf2e7450e6b1b353fb0808891"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.0.6"
|
||||
pub_semver:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
@ -869,6 +940,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.4.1"
|
||||
sync_http:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: sync_http
|
||||
sha256: "7f0cd72eca000d2e026bcd6f990b81d0ca06022ef4e32fb257b30d3d1014a961"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.3.1"
|
||||
term_glyph:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
@ -1005,6 +1084,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.3"
|
||||
webdriver:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: webdriver
|
||||
sha256: "28b82ec894fed45dd71c23ba62d1af973ed97dd59a4f5790a4d38b0b13e5657e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.2.0"
|
||||
webkit_inspection_protocol:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
|||
14
pubspec.yaml
14
pubspec.yaml
|
|
@ -12,6 +12,7 @@ dependencies:
|
|||
flutter:
|
||||
sdk: flutter
|
||||
crypto: ^3.0.3
|
||||
ffi: ^2.1.0
|
||||
hive: ^2.2.3
|
||||
hive_flutter: ^1.1.0
|
||||
auto_route: ">=11.1.0 <11.2.0"
|
||||
|
|
@ -24,12 +25,25 @@ dependencies:
|
|||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
integration_test:
|
||||
sdk: flutter
|
||||
patrol: ^4.10.0
|
||||
build_runner: ^2.4.6
|
||||
flutter_lints: ^6.0.0
|
||||
auto_route_generator: ^10.5.0
|
||||
flutter_native_splash: ^2.3.4
|
||||
flutter_launcher_icons: ^0.14.4
|
||||
|
||||
# patrol test reads this block; android.package_name is the flavored
|
||||
# applicationId (the integration flavor adds the .integration suffix), and
|
||||
# patrol_cli refuses to run without it.
|
||||
patrol:
|
||||
app_name: kirakira
|
||||
flavor: integration
|
||||
test_directory: integration_test
|
||||
android:
|
||||
package_name: com.app.smol_mail.integration
|
||||
|
||||
flutter_launcher_icons:
|
||||
android: "launcher_icon"
|
||||
ios: false
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue