Is there a way to get the current project directory in flutter integration test? This is a basic test setup as an example.
import 'dart:io';
import 'package:flutter_driver/driver_extension.dart';
import 'package:ivori/main.dart' as app;
import 'package:glob/glob.dart';
void main() {
// This line enables the extension.
enableFlutterDriverExtension();
print("Where the working directory? ${Directory.current}");
print("What's under the current directory? ${Glob("*").listSync()}");
// Call the `main()` function of the app, or call `runApp` with
// any widget you are interested in testing.
app.main();
}
Both of the middle two added lines Directory.current and Glob("*").listSync() are attempts to check/show the current working directory. The output from the above is:
$ flutter drive --target=test_driver/app.dart
Changing current working directory to: /Users/yuchen/Documents/MyDemoApp
Using device iPhone SE (2nd generation).
Starting application: test_driver/app.dart
...
...
...
flutter: Where the working directory? Directory: '/'
flutter: What's under the current directory? [Directory: './home', Directory: './usr', File: './.DS_Store', Directory: './bin', Directory: './sbin', File: './.file',
Directory: './etc', Directory: './var', Directory: './Library', Directory: './System', Link: './.VolumeIcon.icns', Directory: './.fseventsd', Directory: './private',
Directory: './.vol', Directory: './Users', Directory: './Applications', Directory: './opt', Directory: './dev', Directory: './Volumes', Directory: './tmp', Directory:
'./cores']
Not hard to see, the working directory is actually set to the root folder of the computer. Is there a way to get to the current project directory or src directory somehow?
The motivation behind this is to have some test data that will be used during the test but not in the app bundle. There are some discussions (fixes and work rounds) about unit tests in this long thread https://github.com/flutter/flutter/issues/12999. However, it doesn't seem to have a solution for integration tests.
In my case, I used ext_storage to access the device's storage. The path_provider plugin seems to only able to access the app's directory.
Here's a sample of fetching the storage path for Downloads.
/// Get storage path for Downloads
/// https://pub.dev/documentation/ext_storage/latest/
Future<String> _getPath() {
return ExtStorage.getExternalStoragePublicDirectory(
ExtStorage.DIRECTORY_DOWNLOADS);
}
Flutter test command accepts a parameter --dart-define which allows you to set variables
Running your test like this:
flutter test integration_test/test.dart --dart-define=projectRoot=$(pwd)
from the root of your project will allow your test code to access the projectRoot variable and get your files
const projectRoot = String.fromEnvironment('projectRoot');
// now you can access your files like you would expect
final file = File('$projectRoot/test_resources/test.json');
Note: Flutter sets the execution directory to the root of the file system only for integration tests, you don't need this workaround for regular unit (widget) tests
Related
I'm trying to run a test for resizing images. To do that I have an Image that I load into a File.
This works locally (in IDE and via terminal) but fails in BitBucket's pipeline.
File structure:
Code that loads the image:
String rootDir = Directory.current.path;
imagePath = rootDir + '/test/assets/test_image_gradient_black_white_3000x4000.png';
File myFile = File(filePath);
This works locally, but when run in Bitbucket's pipeline the "current path" returned "does not exist".
Error message:
00:03 +24 -4: /opt/atlassian/pipelines/agent/build/my_repository/test/image_utils_test/image_utils_test.dart: given 3000x4000 pixel file - resize with half width - verify resize and aspect ratio kept [E]
FileSystemException: Cannot open file, path = '/opt/atlassian/pipelines/agent/build/test/assets/test_image_gradient_black_white_3000x4000.png' (OS Error: No such file or directory, errno = 2)
Is it possible to load files in CI?
The path was actually wrong.
When you right click a test in android studio and select run it is run from that path.
When you run it from the terminal you have to supply the full path of your file from where you are currently standing.
Directory.current.path always returns the project root path, and since my test was in a separate module I had to add the path manually.
This should only be done if we are not already in the my_repository module, otherwise we will add the path twice and we would not be able to run the tests from the IDE instead.
This is how I calculate what to add to the string depending on where the test was executed.
String get testRootDir {
String rootDir = Directory.current.path;
String testDir =
rootDir.contains('/my_repository')
? rootDir + '/test'
: rootDir + '/my_repository/test';
return testDir;
}
...
...
final String assetPath = testRootDir + 'assets/test_image_gradient_black_white_3000x4000.png';
I try to unit-test, but it fails to load:
dart:ffi new DynamicLibrary.open
package:objectbox/src/native/bindings/bindings.dart 21:28 loadObjectBoxLib
package:objectbox/src/native/bindings/bindings.dart 50:41 C
package:objectbox/src/native/model.dart 18:31 new Model
package:objectbox/src/native/store.dart 63:17 new Store
package:productivitie/features/to_do_listing/data/datasource/project_database_data_source_object_box.dart 23:15 new ProjectDataBaseDataSourceObjectBox.<fn>
dart:async _completeOnAsyncReturn
package:path_provider/path_provider.dart getApplicationDocumentsDirectory
Failed to load "F:\Programme\gitProgramme\productivitie\test\features\to_do_listing\data\datasource\project_database_data_source_object_box_test.dart": Invalid argument(s): Failed to load dynamic library (193)
My Constructor, where the problem occours:
21 ProjectDataBaseDataSourceObjectBox(){
22 getApplicationDocumentsDirectory().then((Directory dir){
23 store = Store(getObjectBoxModel() , directory: dir.path + '/objectbox' );
24 box = store!.box<Project>();
25 });
26
27 }
Flutter Doctor found no issues.
I build_run my models again (overwrote objectbox.g.dart file), didn't help.
My versions are:
objectbox: 0.14.0
objectbox_flutter_libs: any
path_provider: ^2.0.1
I first thought it was a problem with the path_provider, I did set a MockMethodCallHandler to return a mocked directory path if the path_provider tries to getApplicationDocumentsDirectory.
final directory = await Directory.systemTemp.createTemp();
const MethodChannel('plugins.flutter.io/path_provider').setMockMethodCallHandler((MethodCall call) async {
if(call.method == 'getApplicationDocumentsDirectory'){
return directory.path;
}
return null;
});
But that didn't help either.
The important part of the error is:
Failed to load dynamic library (193)
From the paths in your question, I assume you're running on Windows. In that case, you need to install the dynamic library so that the compiled test executable can find it. Respecting how Windows loads DLLs this can be either the same directory as where the .exe is, or a system directory. Following Dart CLI apps or Flutter desktop apps installation instructions should help:
Install objectbox-c system-wide (use "Git bash" on Windows):
bash <(curl -s https://raw.githubusercontent.com/objectbox/objectbox-dart/main/install.sh)
Copy the downloaded lib/objectbox.dll to C:\Windows\System32\ (requires admin privileges).
I am trying to write Flutter integration tests and to run them all with one config file instead of making config file for every single test. Is there any way to do that?
For now I have login.dart and login_test.dart and so on, for every single test. I know its convention that every config and test file must have the same name, but that's not what I need, more configurable things are welcomed. Thanks in advance.
This is my config file (login.dart)
import 'package:flutter_driver/driver_extension.dart';
import 'package:seve/main.dart' as app;
void main() {
enableFlutterDriverExtension();
app.main();
}
And test (login_test.dart) looks something like this
import ...
FlutterDriver driver;
void main() {
setUpAll(() async {
driver = await FlutterDriver.connect();
});
tearDownAll(() async {
if (driver != null) {
driver.close();
}
});
test('T001loginAsDriverAndVerifyThatDriverIsLogedInTest', () async {
some_code...
});
});
Now I want to make new test file (e.g login_warning.dart) and be able to start both tests by calling single config file (login.dart). Is that even possible?
Yes, running multiple "test" files with the same "config" is possible.
In the flutter jargon, your config file is your target and your test file is your driver. Your target is always login.dart but you have the two drivers login_test.dart and login_warning.dart.
With the flutter drive command, you can specify the target as well as the driver.
So in order to run both drivers, simply execute the following commands
flutter drive --target=test_driver/login.dart --driver=test_driver/login_test.dart
flutter drive --target=test_driver/login.dart --driver=test_driver/login_warning.dart
This executes first the login_test.dart and then the login_warning.dart driver.
You can always have one main test file that you initiate, like say
flutter drive --target=test_driver/app_test.dart
Then in that call your test groups as functions, like so -
void main() {
test1();
}
void test1() {
group('test 1', () {});}
So with one command you get to execute all the cases mentioned in the main()
Like vzurd's answer my favourit and cleanest is to create a single test file and call all main methods from within:
import './first_test.dart' as first;
import './second_test.dart' as second;
void main() {
first.main();
second.main();
}
Then just run driver on the single test file:
flutter drive --driver=test/integration/integration_test_driver.dart --target=test/integration/run_all_test.dart
to expand on to #sceee 's answer:
you can put the multiple commands into a shell script named integration_tests.sh for example and run them with a single command that way.
#!/bin/sh
flutter drive --target=test_driver/app.dart --driver=test_driver/app_test.dart
flutter drive --target=test_driver/app.dart --driver=test_driver/start_screen_test.dar
make executable:
$chmod a+rx integration_tests.sh
run it:
$./integration_tests.sh
We can use shell command to automate this process.
The following solution will work even with any new test files without manually adding its name to any of the files.
Create a shell script with name integrationTestRunner.sh inside the root directory. You can use the command
touch integrationTestRunner.sh
Inside integrationTestRunner.sh file, paste the following code.
#!/bin/bash
# Declare an array to store the file names and paths
declare -a targets
# Find all .dart files in the current directory and subdirectories
while IFS= read -r -d $'\0' file; do
targets+=("$file")
done < <(find integration_test -name "*.dart" -type f -print0)
# Loop through the array and run the flutter drive command for each target
for target in "${targets[#]}"
do
flutter drive \
--driver=test_driver/integation_test_driver.dart \
--target=$target
done
Run the integrationTestRunner.sh file with any methods:
Pressing the ▶️ button in that file (if you are in VS Code)
Running the script from command line ./integrationTestRunner.sh
I need to get the path of the file inside the private folder.
On my local machine I was able to get it by using the path "../../../../../", however, when I deployed to meteor server using meteor deploy, it doesn't work anymore. Also I tried to log the current directory using process.cwd() and got the following, which is different from the structure I got on my local machine:
/meteor/containers/3906c248-566e-61b7-4637-6fb724a33c16/bundle/programs/server
The directory logged from my local machine gives:
/Users/machineName/Documents/projectName/.meteor/local/build/programs/server
Note: I am using this path to setup https://www.npmjs.com/package/apn
You can use assets/app/ as the relative path. While this may not make sense on the first look Meteor re-arranges your /private directory to map to assets/app from the /programs/server directory. This is both in development and production.
Basically assume that private/ maps to assets/app/.
Call Assets.absoluteFilePath(assetPath) on one of the assets in the private folder, then chop of the name of the asset file from the string you get back, e.g., assuming you have a file called test.txt in the private folder:
var aFile = 'test.txt';// test.txt is in private folder
var aFilePath = Assets.absoluteFilePath(aFile);
var aFolder = aFilePath.substr(0, aFilePath.length - aFile.length);
console.log(aFolder);
https://docs.meteor.com/api/assets.html#Assets-absoluteFilePath
Summary : I am downloading files to chrome app sandbox file system. I have directory called 'downloads' in chrome app's sandbox file system.Following is the code sample
var getSubDirectory = function()
{
subdir.getFile('demo',{create: true},function(fentry)
{
console.log(fentry);
},errohandler)
}
subdir is directory entry. subdir is returning properly, I am getting its output.But when i try to create file into that directory using getFile function, it throws security error.I have permission in manifest for the filesystem.write and filesyste.directory.I tried isWritableEntry() on subdir, its returning false.