Skip to content
Open
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
6 changes: 5 additions & 1 deletion android/app/src/debug/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:networkSecurityConfig="@xml/network_security_config"
tools:replace="android:networkSecurityConfig" />
</manifest>
7 changes: 7 additions & 0 deletions android/app/src/debug/res/xml/network_security_config.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="false">localhost</domain>
<domain includeSubdomains="false">127.0.0.1</domain>
</domain-config>
</network-security-config>
34 changes: 28 additions & 6 deletions integration_test/_support/app_setup.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,15 @@ import 'package:whitenoise/src/rust/frb_generated.dart';
import '../../test/mocks/mock_secure_storage.dart';
import 'tester_helpers.dart';

const _relayUrls = ['ws://localhost:8080', 'ws://localhost:7777'];
const _relayUrlsEnv = String.fromEnvironment(
'WHITENOISE_INTEGRATION_RELAYS',
defaultValue: 'ws://localhost:8080,ws://localhost:7777',
);
final List<String> _relayUrls = _relayUrlsEnv
.split(',')
.map((s) => s.trim())
.where((s) => s.isNotEmpty)
.toList();

bool _rustBridgeInitialized = false;
Directory? _backendRoot;
Expand Down Expand Up @@ -78,21 +86,35 @@ Future<ProviderContainer> mountApp(WidgetTester tester) async {
}

Future<void> expectLocalRelaysAvailable() async {
await _expectLocalRelayAvailable(8080);
await _expectLocalRelayAvailable(7777);
for (final url in _relayUrls) {
final uri = Uri.tryParse(url);
if (uri == null) {
fail(
'Unparseable relay URL "$url" in WHITENOISE_INTEGRATION_RELAYS. '
'Fix the relay list (comma-separated) and run the test again.',
);
}
final host = uri.host;
Comment thread
dannym-arx marked this conversation as resolved.
final isLocal = host == 'localhost' || host == '127.0.0.1';
if (!isLocal) continue;
final port = uri.hasPort
? uri.port
: (uri.scheme == 'wss' ? 443 : 80);
await _expectLocalRelayAvailable(host, port);
Comment thread
dannym-arx marked this conversation as resolved.
}
}

Future<void> _expectLocalRelayAvailable(int port) async {
Future<void> _expectLocalRelayAvailable(String host, int port) async {
try {
final socket = await Socket.connect(
'127.0.0.1',
host,
port,
timeout: const Duration(seconds: 1),
);
socket.destroy();
} catch (error) {
fail(
'Expected a local Nostr relay on 127.0.0.1:$port before running this integration test. '
'Expected a local Nostr relay on $host:$port before running this integration test. '
'Run `docker compose up -d`, then run the test again. '
'Connection error: $error',
);
Expand Down
70 changes: 52 additions & 18 deletions justfile
Original file line number Diff line number Diff line change
Expand Up @@ -168,51 +168,85 @@ test-flutter-quiet:
echo "No test directory found."; \
fi

# Resolves the integration-test device: the given id, else the one booted simulator.
# Resolves the integration-test device: the given id, else the one booted iOS simulator or Android device.
_resolve-device device:
@device="{{ device }}"; \
if [ -n "$device" ]; then echo "$device"; exit 0; fi; \
booted=$(xcrun simctl list devices booted 2>/dev/null | grep -oiE '[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}'); \
count=$(printf '%s' "$booted" | grep -c .); \
if [ "$count" -eq 1 ]; then \
echo "Using booted simulator $booted" >&2; \
echo "$booted"; \
elif [ "$count" -eq 0 ]; then \
echo "No device id given and no booted simulator found. Boot one, pass a device id, or set WHITENOISE_INTEGRATION_DEVICE." >&2; \
if command -v xcrun >/dev/null 2>&1; then \
booted=$(xcrun simctl list devices booted 2>/dev/null | grep -oiE '[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}'); \
else \
booted=""; \
fi; \
ios_count=$(printf '%s' "$booted" | grep -c .); \
if command -v adb >/dev/null 2>&1; then \
android=$(adb devices 2>/dev/null | awk 'NR>1 && $2=="device" {print $1}'); \
else \
android=""; \
fi; \
android_count=$(printf '%s' "$android" | grep -c .); \
total=$((ios_count + android_count)); \
if [ "$total" -eq 1 ]; then \
picked="${booted}${android}"; \
echo "Using device $picked" >&2; \
echo "$picked"; \
elif [ "$total" -eq 0 ]; then \
echo "No device id given and no booted iOS simulator or Android device found. Boot one, pass a device id, or set WHITENOISE_INTEGRATION_DEVICE." >&2; \
exit 1; \
else \
echo "Multiple booted simulators — pass a device id or set WHITENOISE_INTEGRATION_DEVICE:" >&2; \
xcrun simctl list devices booted >&2; \
echo "Multiple devices found — pass a device id or set WHITENOISE_INTEGRATION_DEVICE:" >&2; \
[ -n "$booted" ] && echo "iOS simulators:" >&2 && echo "$booted" >&2; \
[ -n "$android" ] && echo "Android devices:" >&2 && echo "$android" >&2; \
Comment thread
dannym-arx marked this conversation as resolved.
exit 1; \
fi

# Run Flutter integration tests. Requires local Nostr relays on ports 8080 and 7777.
# If device is an Android adb device, tunnel host ports 8080/7777 to its loopback via
# `adb reverse` so `ws://localhost:<port>` from the device hits the host's docker relays.
# No-op for iOS simulators and desktop targets.
_setup-android-relays device:
@if command -v adb >/dev/null 2>&1 && adb devices 2>/dev/null | awk 'NR>1 && $2=="device" {print $1}' | grep -Fqx "{{ device }}"; then \
adb -s "{{ device }}" reverse tcp:8080 tcp:8080 >/dev/null || { echo "❌ adb reverse tcp:8080 failed for {{ device }}" >&2; exit 1; }; \
adb -s "{{ device }}" reverse tcp:7777 tcp:7777 >/dev/null || { echo "❌ adb reverse tcp:7777 failed for {{ device }}" >&2; exit 1; }; \
echo "📡 Android device {{ device }} — adb reverse set for ports 8080, 7777 → host docker relays" >&2; \
fi

# Run Flutter integration tests against local Nostr relays on ports 8080 and 7777
# (`docker compose up -d`). On Android, `adb reverse` tunnels the device's localhost
# to the host so the same URLs work on iOS simulators, desktop, and Android.

# Run one file by passing its path: `just int-test integration_test/messaging_interactions_test.dart`.
# Device: WHITENOISE_INTEGRATION_DEVICE, else the one booted simulator.
# Device: WHITENOISE_INTEGRATION_DEVICE, else the one booted simulator/emulator.
# Relays: WHITENOISE_INTEGRATION_RELAYS (comma-separated) overrides defaults.
int-test target="integration_test/all_tests.dart" device=env("WHITENOISE_INTEGRATION_DEVICE", "") flavor="staging":
@echo "🧪 Testing Flutter integration flows..."
@device=$(just _resolve-device "{{ device }}") || exit 1; \
just _setup-android-relays "$device" || exit 1; \
define=""; \
[ -n "${WHITENOISE_INTEGRATION_RELAYS:-}" ] && define="--dart-define=WHITENOISE_INTEGRATION_RELAYS=$WHITENOISE_INTEGRATION_RELAYS"; \
if [ -n "{{ flavor }}" ]; then \
flutter test -d "$device" --flavor {{ flavor }} {{ target }}; \
flutter test -d "$device" --flavor {{ flavor }} ${define:+"$define"} {{ target }}; \
else \
flutter test -d "$device" {{ target }}; \
flutter test -d "$device" ${define:+"$define"} {{ target }}; \
fi

# Run Flutter integration tests with minimal output. Requires local Nostr relays on ports 8080 and 7777.
# Run Flutter integration tests with minimal output against local Nostr relays on
# ports 8080 and 7777; Android tunnels via `adb reverse`.

# Run one file by passing its path: `just int-test-quiet integration_test/messaging_interactions_test.dart`.
# Device: WHITENOISE_INTEGRATION_DEVICE, else the one booted simulator.
# Device: WHITENOISE_INTEGRATION_DEVICE, else the one booted simulator/emulator.
# Relays: WHITENOISE_INTEGRATION_RELAYS (comma-separated) overrides defaults.
int-test-quiet target="integration_test/all_tests.dart" device=env("WHITENOISE_INTEGRATION_DEVICE", "") flavor="staging":
@if [ ! -e "{{ target }}" ]; then \
echo "No integration test target found at {{ target }}."; \
exit 1; \
fi; \
device=$(just _resolve-device "{{ device }}") || exit 1; \
just _setup-android-relays "$device" || exit 1; \
define=""; \
[ -n "${WHITENOISE_INTEGRATION_RELAYS:-}" ] && define="--dart-define=WHITENOISE_INTEGRATION_RELAYS=$WHITENOISE_INTEGRATION_RELAYS"; \
if [ -n "{{ flavor }}" ]; then \
flutter test -d "$device" --flavor {{ flavor }} --no-pub --reporter=failures-only {{ target }}; \
flutter test -d "$device" --flavor {{ flavor }} --no-pub --reporter=failures-only ${define:+"$define"} {{ target }}; \
else \
flutter test -d "$device" --no-pub --reporter=failures-only {{ target }}; \
flutter test -d "$device" --no-pub --reporter=failures-only ${define:+"$define"} {{ target }}; \
fi

coverage min="99":
Expand Down
Loading