Get path to current script in dart - flutter

By running this command
flutter test test/widget_tests/rider/home/component/direction_search_fields_test.source.dart
I am trying to get this string path "test/widget_tests/rider/home/component/direction_search_fields_test.source.dart" from inside the file itself.
I tried
final dir = Platform.script.path;
But this gives me /project/path/main.dart

Related

Is it possible to load Files in tests on remote CI/CD server? [BitBucket Pipeline]

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';

How to include dlls in flutter build windows

I am working on a flutter project that runs fine in development.
However I do not know how to get the build to include dll's referenced using FFI.
I can't find clear instructions on how to do it.
I tried following the steps to build an msix here, which worked but didn't seem to include the dll (it fails in the same way as the regular build)
what is the procedure to have the build process consider the dll's?
other dll's show up in the build directory from 3rd party packages so there must be a way right?
That's really hard to discover by your own, but indeed you can bind those libraries to you MSIX. In my case I just made a package for label printers using Dart FFI and DLL`s provided by manufacturer and this is how I did it.
You need to add these DLL's to your assets setting on pubspec.yaml from your package. This is my case:
[...]
flutter:
[...]
assets:
- assets/WinPort.dll
- assets/Winppla.dll
- assets/Winpplb.dll
- assets/Winpplz.dll
With this setting you will embed your DLL files in your final MSIX, but this was the easy part. Now you have make sure to load the proper load these files in code.
Based on my own tests, I still dealing with two ways to develop and test code, the first one is when I am running a project in my machine via flutter run I must set the target for current.path, when I get it done and start building for deploy I change this to resolvedExecutable.parent.path. Where is what you need to do.
Loading you DLL in development environment (flutter run):
final String _packageAssetsDirPath = normalize(join(Directory.current.path,'assets'));
On production environment (running from .exe or MSIX installed):
final String _assetsPackageDir = normalize(
join('data', 'flutter_assets', 'packages', 'YOUR_PACKAGE_NAME', 'assets'));
final String _exeDirPath = File(Platform.resolvedExecutable).parent.path;
final String _packageAssetsDirPath =
normalize(join(_exeDirPath, _assetsPackageDir));
After with this var called _packageAssetsDirPath will be easy to load your DLL's, now you invoke a DynamicLibrary constructor:
// Path for DLL file
final String _libDllSourceFullPath =
normalize(join(_packageAssetsDirPath, 'Winppla.dll'));
// Target for copy, place DLL in same place the .exe you are running
final String _libDllDestFullPath =
normalize(join(_packageAssetsDirPath, 'YOUROWN.dll'));
// Try to copy for running exe path
File(_libDllSourceFullPath).copySync(_libDllDestFullPath);
// With this copy, would be simple to load, and if it fails, try in full path
// LOAD DLL
try {
String _packageAssetsDirPath =
normalize(join(Directory.current.path, 'assets'));
String _printerLibraryPath =
normalize(join(_packageAssetsDirPath, 'Winppla.dll'));
DynamicLibrary _library = DynamicLibrary.open(_printerLibraryPath);
return _library;
} catch (e) {
try {
DynamicLibrary _library = DynamicLibrary.open('Winppla.dll');
return _library;
} catch (e) {
// Avoing errors creating a fake DLL, but you could deal with an exception
return DynamicLibrary.process();
}
}
At this point you can load a DLL and use it, you can check my package full code at https://github.com/saviobatista/argox_printer check for lib/src/ppla.dart at function _setupDll() and you will see that loading.
I built a simpler option inspired in the solution of Sávio Batista
(You must have your .dll in your assets folder)
if (kReleaseMode) {
// I'm on release mode, absolute linking
final String local_lib = join('data', 'flutter_assets', 'assets', 'libturbojpeg.dll');
String pathToLib = join(Directory(Platform.resolvedExecutable).parent.path, local_lib);
DynamicLibrary lib = DynamicLibrary.open(pathToLib);
} else {
// I'm on debug mode, local linking
var path = Directory.current.path;
DynamicLibrary lib = DynamicLibrary.open('$path/assets/libturbojpeg.dll');
}
Just replace libturbojpeg.dll for your .dll

Get the current project directory from flutter integration test

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

Can I run multiple integration tests with one single config file in Flutter?

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

Getting Meteor private folder path in Meteor Deploy Environment

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