Opening deep link in integration test in Flutter - flutter

I'm trying to run an integration test which is highly dependent on the user clicking a magic link he got in his email. So far I failed to find a way of doing that. I came across Process.run but it seems like it should be run before the integration test starts and I need to do it during the test.
Any help with either iOS or Android will be highly appreciated. πŸ™
This is the code I tried so far to work on iOS but Process.run ends with ProcessException: No such file or directory:
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
testWidgets('login test', (WidgetTester tester) async {
app_sandbox.main();
await tester.pumpAndSettle(Duration(seconds: 5));
expect(find.text('foo'), findsOneWidget);
await Process.run('xcrun', [
'simctl',
'openurl',
'7D6DEC47-C1E2-4F18-A38B-7B4C17558172',
'https://myDeepLink/sign-in',
]);
await tester.pumpAndSettle();
});
}

this might only work with flutter_driver
await Process.run('xcrun', [
'simctl',
'openurl',
'booted',
'https://myDeepLink/sign-in'
]).then((result) {
stdout.write(result.stdout);
stderr.write(result.stderr);
});
not with testWidgets of integration_test
there I got this error:
> Error occured: DriverError: Failed to fulfill RequestData due to
> remote error Original error: ext.flutter.driver: (112) Service has
> disappeared Original stack trace:
> #0 new _OutstandingRequest (package:vm_service/src/vm_service.dart:1746:45)
> #1 VmService._call (package:vm_service/src/vm_service.dart:2262:21)
> #2 VmService.callServiceExtension (package:vm_service/src/vm_service.dart:2233:14)
> #3 VMServiceFlutterDriver.sendCommand (package:flutter_driver/src/driver/vmservice_driver.dart:306:66)
> #4 FlutterDriver.requestData (package:flutter_driver/src/driver/driver.dart:522:45)
> #5 integrationDriver (package:integration_test/integration_test_driver_extended.dart:51:38)
> <asynchronous suspension>

Related

My widgets tests work separately but wont work together

this is my code:
void main() {
testWidgets("Localiza os widgets na home", (WidgetTester tester) async {
await tester.pumpWidget(const MaterialApp(home: HomeView()));
final Finder drawer = find.byType(IconButton);
await tester.tap(drawer);
expect(drawer, findsOneWidget);
await tester.pumpAndSettle();
final Finder listTileDrawer = find.byType(ListTile);
expect(listTileDrawer, findsNWidgets(5));
final Finder listViewDrawer = find.byType(ListView);
expect(listViewDrawer, findsOneWidget);
});
testWidgets("Valida se snackBar estΓ‘ sendo exibida corretamente", (WidgetTester tester) async {
await tester.pumpWidget(const MaterialApp(
home: Scaffold(
body: BotaoRedirecionamentoExterno(
url: 'url invalida',
texto: 'teste',
))));
final botao = find.byType(BotaoRedirecionamentoExterno);
await tester.tap(botao);
await tester.pumpAndSettle();
final Finder snackBar = find.byType(SnackBar);
expect(snackBar, findsOneWidget);
});
}
When I run: test/view/home/home_widget_test.dart --no-sound-null-safety it works as expected:
I/flutter (11181): 00:01 +1: Valida se snackBar estΓ‘ sendo exibida corretamente
I/flutter (11181): 00:02 +2: All tests passed!
But when I try: flutter test --no-sound-null-safety:
══║ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK β•žβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•
The following TestFailure object was thrown running a test:
Expected: exactly one matching node in the widget tree
Actual: _WidgetTypeFinder:<zero widgets with type "SnackBar" (ignoring offstage widgets)>
Which: means none were found but one was expected
When the exception was thrown, this was the stack:
#4 main.<anonymous closure> (file:///Users/macos/Desktop/portal-agro-sp-master/test/view/home/home_widget_test.dart:33:5)
<asynchronous suspension>
<asynchronous suspension>
(elided one frame from package:stack_trace)
This was caught by the test expectation on the following line:
file:///Users/macos/Desktop/portal-agro-sp-master/test/view/home/home_widget_test.dart line 33
The test description was:
Valida se snackBar estΓ‘ sendo exibida corretamente
════════════════════════════════════════════════════════════════════════════════════════════════════
00:26 +25 -1: /Users/macos/Desktop/portal-agro-sp-master/test/view/home/home_widget_test.dart: Valida se snackBar estΓ‘ sendo exibida corretamente [E]
Test failed. See exception logs above.
The test description was: Valida se snackBar estΓ‘ sendo exibida corretamente
I need to be able to run all my tests together due to a customer requirement. I already have more than 23 tests ready and this is the first time this has happened.
Does anyone know why this is happening and a way to solve it ?

How to mock Socket.io client in Flutter tests

I'm using socket_io_client v0.9.12 in my flutter app (still not using null safety). I am creating a socket connection with my back-end server when the app starts and allow child widgets to access it using a provider.
I am trying to start creating the connection in the constructor so that when I need to use the socket client, it would probably be initialized already.
This is my provider class which has the creation of the socket connection:
class SocketClient {
SocketClient() {
_initializer = initialize();
}
Future _initializer;
/// Socket client
Socket client;
/// Wait until the client is properly connected with the server
Future finishInitializing() => _initializer;
/// Initialize the socket connection with the server
Future initialize() async {
final completer = Completer<Socket>();
final socket = io(
'http://localhost:3000/gateway',
OptionBuilder() //
.setTransports(['websocket'])
.disableAutoConnect()
.setQuery({'token': 'TOKEN'})
.build(),
)..connect();
socket
..onConnect((_) {
completer.complete(socket);
});
client = await completer.future;
}
}
The main app widget I have:
#override
Widget build(BuildContext context) {
return Provider<SocketClient>(
create: (_) => SocketClient(),
builder: (context, _) {
return Scaffold(
...
);
},
);
}
This is how I am trying to use the socket client:
Future<void> foo(SocketClient socketClient) async {
await socketClient.finishInitializing();
final socket = socketClient.client;
socket.on(eventName, (dynamic uploadDrawingEvent) {
...
});
}
Everything works fine up to now. πŸŽ‰
However, when I try to run my tests that depend on this socket client, I see the below error:
Pending timers:
Timer (duration: 0:00:20.000000, periodic: false), created:
#0 new FakeTimer._ (package:fake_async/fake_async.dart:284:41)
#1 FakeAsync._createTimer (package:fake_async/fake_async.dart:248:27)
#2 FakeAsync.run.<anonymous closure> (package:fake_async/fake_async.dart:181:19)
#5 Manager.connect (package:socket_io_client/src/manager.dart:232:19)
#6 Manager.open (package:socket_io_client/src/manager.dart:194:41)
#7 Socket.connect (package:socket_io_client/src/socket.dart:104:8)
#8 SocketClient.initialize (package:flutter_app/web/services/socket_provider.dart:48:8)
<asynchronous suspension>
(elided 2 frames from dart:async)
══║ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK β•žβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•
The following assertion was thrown running a test:
A Timer is still pending even after the widget tree was disposed.
'package:flutter_test/src/binding.dart':
Failed assertion: line 1241 pos 12: '!timersPending'
When the exception was thrown, this was the stack:
#2 AutomatedTestWidgetsFlutterBinding._verifyInvariants (package:flutter_test/src/binding.dart:1241:12)
#3 TestWidgetsFlutterBinding._runTestBody (package:flutter_test/src/binding.dart:803:7)
<asynchronous suspension>
(elided 2 frames from class _AssertionError)
...
initialize function keeps hanging after client = await completer.future; line. That future is not resolved even after the test is finished (see the error).
I would like to get ideas on how I can mock this socket client properly to avoid this error.
I'm looking more towards an answer which mocks the functionality of the socket client because I have some more tests to write to cover the event handlers.
Thank you in advance! πŸ™
You can use await IOOverrides for override standard Socket method like socketConnect
Exemple:
await IOOverrides.runZoned(() async {
your code
}, socketConnect: (host, port, {sourceAddress, int sourcePort = 0, timeout}) => Future.value(mockSocket));

Flutter Unhandled Exception: Null check operator used on a null value

I am getting the following error Unhandled Exception: Null check operator and I am not sure if it is something wrong in my code or the library I am using. I am trying to test the livequery of the parse_server_sdk used by back4app because I require sending and receiving images in Realtime. Here is the relevant code:
import 'dart:io';
import 'package:filepicker_windows/filepicker_windows.dart';
import 'package:flutter/material.dart';
import 'package:parse_server_sdk_flutter/parse_server_sdk.dart';
void main() async {
final keyApplicationId = 'EPARW6nRAAyp5uehoDE7rBEby4wtehcZf9EayykS';
final keyClientKey = 'fDaL2DjyC9YdwCwZ4RB5c5vhACROaMOO1EjjL4Zn';
final keyParseServerUrl = 'https://parseapi.back4app.com';
final LIVE_QUERY_URL = 'wss://samuraichat.b4a.io';
await Parse().initialize(keyApplicationId, keyParseServerUrl,
clientKey: keyClientKey,
autoSendSessionId: true,
liveQueryUrl: LIVE_QUERY_URL,
coreStore: CoreStoreMemoryImp());
final LiveQuery liveQuery = LiveQuery();
QueryBuilder<ParseObject> query =
QueryBuilder<ParseObject>(ParseObject('FirstClass'))
..whereEqualTo('chatId', 1);
Subscription subscription = await liveQuery.client.subscribe(query);
subscription.on(LiveQueryEvent.create, (value) {
print('*** CREATE ***: ${DateTime.now().toString()}\n $value ');
print((value as ParseObject).objectId);
print((value as ParseObject).get('message'));
});
runApp(MyApp());
}
Here is the error stack:
[ERROR:flutter/lib/ui/ui_dart_state.cc(199)] Unhandled Exception: Null check operator used on a null value
#0 MethodChannel.binaryMessenger (package:flutter/src/services/platform_channel.dart:142:86)
#1 MethodChannel._invokeMethod (package:flutter/src/services/platform_channel.dart:148:36)
#2 MethodChannel.invokeMethod (package:flutter/src/services/platform_channel.dart:331:12)
#3 MethodChannelConnectivity.checkConnectivity (package:connectivity_platform_interface/src/method_channel_connectivity.dart:41:29)
#4 Connectivity.checkConnectivity (package:connectivity/connectivity.dart:46:22)
#5 Parse.checkConnectivity (package:parse_server_sdk_flutter/parse_server_sdk.dart:106:34)
#6 new LiveQueryReconnectingController (package:parse_server_sdk/src/network/parse_live_query.dart:45:28)
#7 new LiveQueryClient._internal (package:parse_server_sdk/src/network/parse_live_query.dart:146:30)
#8 LiveQueryClient._getInstance (package:parse_server_sdk/src/network/parse_live_query.dart:153:35)
#9 new LiveQuery (package:parse_server_sdk/src/network/parse_live_query.dart:416:30)
#10 main (package:chat_app/main.dart:18:37)
<asynchronous suspension>
Thanks.
Try to clean your app cache:
flutter clean
This bug should be fixed with this PR.
You use the current nullsafety branch by overriding the dependency in your pubspec.yaml:
dependency_overrides:
parse_server_sdk_flutter:
git:
url: https://github.com/parse-community/Parse-SDK-Flutter.git
ref: nullsafety
path: packages/flutter
parse_server_sdk:
git:
url: https://github.com/parse-community/Parse-SDK-Flutter.git
ref: nullsafety
path: packages/dart

audio_service flutter package does not start

I am trying to use the audio_service package to allow background controls for my podcast playing app. The service does not start. When I call AudioService.start(), nothing is ever returned (I'm awaiting this function and trying to print a statement after this returns, but it never returns. Also, when I first attempt to play an item, it will correctly evaluate AudioService.running to false and then try to start the AudioService (hanging on the start() function). When I hit play a second time, it will evaluate AudioService.running as true (even though the start function never returned) and will then throw this error:
E/flutter ( 8726): [ERROR:flutter/lib/ui/ui_dart_state.cc(166)] Unhandled Exception: PlatformException(Attempt to invoke virtual method 'void io.flutter.plugin.common.MethodChannel.invokeMethod(java.lang.String, java.lang.Object, io.flutter.plugin.common.MethodChannel$Result)' on a null object reference, null, null)
E/flutter ( 8726): #0 StandardMethodCodec.decodeEnvelope (package:flutter/src/services/message_codecs.dart:572:7)
E/flutter ( 8726): #1 MethodChannel._invokeMethod (package:flutter/src/services/platform_channel.dart:161:18)
E/flutter ( 8726): <asynchronous suspension>
E/flutter ( 8726): #2 MethodChannel.invokeMethod (package:flutter/src/services/platform_channel.dart:334:12)
E/flutter ( 8726): #3 AudioService.play (package:audio_service/audio_service.dart:895:20)
Here is my code which calls the start function:
if(AudioService.running) {
print('playing audio service: ${AudioService.running}');
AudioService.play();
} else {
MediaItem mediaItem = MediaItem(
id: newPostPod.audioUrl,
title: newPostPod.titleTextString(),
artist: newPostPod.subtitleTextString(),
);
print('starting audio service');
bool started = await AudioService.start(
backgroundTaskEntrypoint: _backgroundTaskEntrypoint,
params: {'mediaItem': mediaItem.toJson()},
);
print('audio service started');
if(AudioService.running) {
print('starting to play via media service');
AudioService.playMediaItem(mediaItem);
} else {
print('Audio Service not yet started: $started');
}
}
The code for the background task entrypoint (which is outside of any other class, as it wasn't working inside a class I had read in another issue that it had to be top-level):
_backgroundTaskEntrypoint() {
AudioServiceBackground.run(() => PlayerTask());
}
Lastly, it doesn't appear any of the code within my onStart in my BackgroundAudioTask is running (as print statements at the top of my onStart are not being run). So I'm not sure what's happening here. It isn't give me a clear error or really any hint of where to start debugging audio_service.
Calling AudioService.connect(); before starting the service will solve the error.
For me AudioService.start() would freeze until I added the WAKE_LOCK and FOREGROUND_SERVICE permissions to the AndroidManifest.xml file per the audio_service README file.

Hosting an executable within a Flutter application

I have a basic flutter project running on android where when the application starts, I write an executable bundled in my assets.
static String appInternalPath = '/data/data/com.maksimdan.face_merger';
void writeExecutable() async {
var executablePath = join(appInternalPath, 'main');
if (await File(executablePath).exists()) {
File(executablePath).delete();
print('deleted old executable');
} else {
print('not executable exists');
}
ByteData data = await rootBundle.load('lib/py/dist/main');
List<int> bytes =
data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);
await File(executablePath).writeAsBytes(bytes);
print('wrote new executable');
}
Sometime later in my code I try to run it.
void invokeExecutable() async {
String executablePath = join(appInternalPath, 'main');
Process.run('chmod', ['u+x', executablePath]).then((ProcessResult results) {
Process.run(executablePath, []).then((ProcessResult results) {
print(results.stdout);
});
});
}
But obtain a permission denied error.
E/flutter (31825): [ERROR:flutter/lib/ui/ui_dart_state.cc(186)] Unhandled Exception: ProcessException: Permission denied
E/flutter (31825): Command: /data/data/com.maksimdan.flutter_general/main
E/flutter (31825): #0 _ProcessImpl._start (dart:io-patch/process_patch.dart:390:33)
E/flutter (31825): #1 Process.start (dart:io-patch/process_patch.dart:36:20)
E/flutter (31825): #2 _runNonInteractiveProcess (dart:io-patch/process_patch.dart:565:18)
E/flutter (31825): #3 Process.run (dart:io-patch/process_patch.dart:47:12)
E/flutter (31825): #4 _MyHomePageState.invokeExecutable.<anonymous closure> (package:flutter_general/main.dart:51:15)
E/flutter (31825): #5 _rootRunUnary (dart:async/zone.dart:1362:47)
E/flutter (31825): #6 _CustomZone.runUnary (dart:async/zone.dart:1265:19)
E/flutter (31825): <asynchronous suspension>
I've also tried:
Process.run('/system/bin/chmod', ['744', path]).then((ProcessResult results) {
print('shell1 complete');
Process.run(path, []).then((ProcessResult results) {
print('shell2 complete');
print(results.stdout);
});
});
My executable:
// 'Hello World!' program
#include <iostream>
int main()
{
std::cout << "Hello World!" << std::endl;
return 0;
}
>> g++ main.cc -o main
Is there a way to run your own executables in flutter with the proper permissions? On native android, there is an option to file.setExecutable(true); using this strategy. (Hosting an executable within Android application)
Or will I have to experiment with method channels?
pubspec.yml
name: face_merger
description: A new Flutter project.
version: 1.0.0+1
environment:
sdk: ">=2.1.0 <3.0.0"
dependencies:
flutter:
sdk: flutter
sqflite: ^1.3.0+2
process_run: ^0.10.10+1
cupertino_icons: ^0.1.3
dev_dependencies:
flutter_test:
sdk: flutter
flutter:
uses-material-design: true
assets:
- lib/py/dist/main
I also verified that the file was written to the internal memory of on the device that I expected it to be written to using android studio's device explore.
Besides the writable permission you need to have readable permission in your app.
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.xxx.yyy">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
...
You need to put the .db file extension at the end of the database name (Assuming DB_DIR is for a database). var path = join(DB_DIR, 'main.db');
Then I think you may want to use path_provider package and use
Directory documentsDirectory = await getApplicationDocumentsDirectory();
for the directory where you are accessing the database.