Flutter Test Driver Run All Test - testing

In our Flutter application we have multiple integration tests.
I run them one by one by issuing:
flutter drive --target=test_driver/screenshot.dart
However I can't seem to figure out how to run all integration test inside the test_driver folder?

With Groups, but this only half addresses the issue, have your app_test.dart like normal just a main method with some grouped tests
Future<void> main() async {
group(
'Registration and password',
() {
setUp(() async {
await versionTest(driver, tester, reporter);
});
test('Register Account', () async {
await testRegisterAccount(driver, tester, reporter);
});
test('Register Account 2', () async {
await testRegisterAccount2(driver, tester, reporter);
});
tearDown(() async {
await driver.requestData('go-back');
});
},
timeout: const Timeout(
Duration(minutes: 5),
),
);
then we have an app.dart which creates the app wrapped in a test app. We mainly did this to test a splash screen that checked the apps version, so we needed a hook into before the app had really started
void main() {
makeTestApp();
}
makeTestApp does all the normal stuff like enableFlutterDriverExtensions etc but its also where we build our app with a custom launcher, the launcher is just a blank page with a button which starts the app, each test should start and finish here, going back was harder you can see we used the FlutterDriverExtensions handler message - driver.requestData('go-back')
Widget _buildHome(BuildContext context) {
return Scaffold(
child: Center(
child: GestureDetector(
onTap: () {
Navigator.of(context).pushReplacementNamed('/authentication');
},
child: SizedBox(
height: 200,
width: 200,
child: Image.asset(
'assets/images/logo.png',
fit: BoxFit.cover,
),
),
),
),
);
}
WidgetsFlutterBinding.ensureInitialized();
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]).then((_) {
runApp(App(
launcher: (context) => _buildHome(context),
));
});
now you can start the app using something like
flutter run --flavor dev --observatory-port 8888 --disable-service-auth-codes --no-hot test_driver/app.dart
and when the app is running it will display our launcher waiting for you to run a test using the code lens tools from the dart library,

One way to do it is to open a terminal window in the root directory of your Flutter app and type flutter test
See: https://github.com/flutter/flutter/wiki/Running-and-writing-tests#running-unit-tests

Related

Sharing state for background task in react native

I am writing an app with Expo that uses expo-location to track the location of a user in the background. I would like to use hooks (states, useEffect...) when my app is in the background. At the moment the background tracking code looks like that
export default function BackgroundLocationHook() {
[...]
const [position, setPosition] = useState(null);
const [newLocation, setNewLocation] = useState(null) ;
TaskManager.defineTask(LOCATION_TASK_NAME, async ({ data, error }) => {
if (error) {
console.error(error);
return;
}
if (data) {
// Extract location coordinates from data
const { locations } = data;
const location = locations[0];
if (location) {
console.log("Location in background", location.coords);
}
}
setPosition(location.coords);
});
[...]
return [position];
}
But it is a bit hacky as the geolocation_tracking task shares some states with the
I would also like to play some sounds when I am close to a some location even when my app is in the background. I plan to do it with useEffect like that:
useEffect(() => {
const requestPermissions = async () => {
if(shouldPlaySound(newLocation)){
playSound()
}
};
requestPermissions();
}, [newLocation]);
This works when my app is in the foreground but I heard that react hooks such as states, and useEffect do not work when the app is in the background. So my question is what is the alternative to make sure I still have a sound being played when my app is in the background and if it is possible to have hooks working even when the app is in the background.
I see you want to perform some task in the background when you pass a specific location,
With the expo location, we can achieve this implementation.
You can add fencing to your desired location and when the device will enter the fencing area or exits from the fencing area you will get an event to handle some tasks and you are also able to listen to the event in the background with the Expo Task manager.
You need to follow the steps to achieve this.
Define a task using Expo Task Manager outside the react life cycle,
and read the official documentation for API usage. Expo Task Manager
Take the necessary permissions to access the location in the background, and start geofencing with your component. Expo Location
Stop the fencing listener using stopGeofencingAsync from expo-location when it is not needed anymore.
Now you will get events every time you enter or exit from the specified location in startGeofencingAsync until you stop using the stopGeofencingAsync method.
Hope this will help you achieve your desired input.
to run a task in the background you can check any of these library.
react-native-background-actions
react-native-background-timer
this is some example code
import BackgroundTimer from 'react-native-background-timer';
// Start a timer that runs continuous after X milliseconds
const intervalId = BackgroundTimer.setInterval(() => {
// this will be executed every 200 ms
// even when app is the background
console.log('tic');
}, 200);
// Cancel the timer when you are done with it
BackgroundTimer.clearInterval(intervalId);
// Start a timer that runs once after X milliseconds
const timeoutId = BackgroundTimer.setTimeout(() => {
// this will be executed once after 10 seconds
// even when app is the background
console.log('tac');
}, 10000);
// Cancel the timeout if necessary
BackgroundTimer.clearTimeout(timeoutId);
this is another example of this code
import BackgroundService from 'react-native-background-actions';
const sleep = (time) => new Promise((resolve) => setTimeout(() => resolve(), time));
// You can do anything in your task such as network requests, timers and so on,
// as long as it doesn't touch UI. Once your task completes (i.e. the promise is resolved),
// React Native will go into "paused" mode (unless there are other tasks running,
// or there is a foreground app).
const veryIntensiveTask = async (taskDataArguments) => {
// Example of an infinite loop task
const { delay } = taskDataArguments;
await new Promise( async (resolve) => {
for (let i = 0; BackgroundService.isRunning(); i++) {
console.log(i);
await sleep(delay);
}
});
};
const options = {
taskName: 'Example',
taskTitle: 'ExampleTask title',
taskDesc: 'ExampleTask description',
taskIcon: {
name: 'ic_launcher',
type: 'mipmap',
},
color: '#ff00ff',
linkingURI: 'yourSchemeHere://chat/jane', // See Deep Linking for more info
parameters: {
delay: 1000,
},
};
await BackgroundService.start(veryIntensiveTask, options);
await BackgroundService.updateNotification({taskDesc: 'New ExampleTask description'}); // Only Android, iOS will ignore this call
// iOS will also run everything here in the background until .stop() is called
await BackgroundService.stop();
A third solution for android is the headlessjs that only works on android
you can tak help from this

ionic vue background geolocation tracking stops after 5 minute

I am using plugin
https://github.com/seididieci/capacitor-backround-geolocation
to watch the user's location. then I am tracking that location with the help of a pusher. this background location works only for 5 minutes after that it just stops. I am using Capacitor's Background task. But that plugin also keeps data on phone after the user opens the app. the Background task sends data to the pusher.
Here is watch location function
getLocation: async function () {
BackgroundGeolocation.initialize({
notificationText: "Your app is running, tap to open.",
notificationTitle: "App Running",
updateInterval: 10000,
requestedAccuracy: BgGeolocationAccuracy.HIGH_ACCURACY,
// Small icon has to be in 'drawable' resources of your app
// if you does not provide one (or it is not found) a fallback icon will be used.
smallIcon: "ic_small_icon",
// Start getting location updates right away. You can set this to false or not set at all (se below).
startImmediately: true,
});
// const geolocation = new Geolocation.Geolocation();
BackgroundGeolocation.addListener("onLocation", (location) => {
// console.log("Got new location", location);
this.subscribe(location.longitude, location.latitude);
console.log(location)
});
BackgroundGeolocation.addListener("onPermissions", (location) => {
// console.log("BGLocation permissions:", location);
this.subscribe(location.longitude, location.latitude);
// Do something with data
});
BackgroundGeolocation.start();
},
Then calling function in mounted()
mounted(){
this.getLocation
App.addListener("appStateChange", (state) => {
setInterval(this.getLocation, 120000);
if (!state.isActive) {
BackgroundTask.beforeExit(async () => {
setInterval(this.getLocation, 120000);
console.og('Why')
});
}
if (state.isActive) {
setInterval(this.getLocation, 120000);
console.log('Active')
}
});
}
You need to use https://ionicframework.com/docs/native/foreground-service like this for running the background.

How to configure Detox lifecycle hooks in the latest version?

I run detox in version 17.13.2 with jest-circus as the test runner. My main problem is the app is not reset either after or before I run the tests which leads to an inconsistent state of the app.
My test file:
import { by, device, element, expect, waitFor } from "detox"
describe("Login", () => {
beforeEach(async () => {
await device.reloadReactNative()
})
it("should login with correct data", async () => {
await element(by.id("login_email_input")).typeText("ch.tietz#gmail.com")
await element(by.id("login_password_input")).typeText("12345678")
await element(by.id("login_submit_button")).tap()
await waitFor(element(by.id("workout_screen"))).toBeVisible()
// additional test steps
})
})
Now if the login actually works but the test fails at one of the subsequent steps, the state of the app user will still be "logged in".
From what I understand, it's not possible to actually alter the app state, e.g. by clearing the AsyncStorage or interacting directly with the state mgmt tool. Instead, it's recommended to just reinstall the app - but this is exactly where I am struggling.
I have tried numerous approaches and none of them worked. What makes it really hard to understand configuration is that detox completely changed how the configuration works and switched to jest-circus as the main test runner.
My setup is basically the one created by jest init -r jest. From what I understand, this already includes some defaults for detox.init() and detox.cleanup():
{
"detox": {
"behavior": {
"init": {
"reinstallApp": true,
"launchApp": true,
"exposeGlobals": true
},
"cleanup": {
"shutdownDevice": false
}
}
}
}
However, this does not seem to be sufficient to actually wipe the app state after running the tests.
I tried working with an init script as setupFilesAfterEnv, which would call cleanup() after the test suite is run. Actually that works in an older project which still uses jasmine 2 as test runner.
import { cleanup, init } from 'detox';
const adapter = require('detox/runners/jest/adapter');
const specReporter = require('detox/runners/jest/specReporter');
const config = require('../package.json').detox;
// Set the default timeout
jest.setTimeout(120000);
jasmine.getEnv().addReporter(adapter);
// This takes care of generating status logs on a per-spec basis. By default, jest only reports at file-level.
// This is strictly optional.
jasmine.getEnv().addReporter(specReporter);
beforeAll(async () => {
await init(config, { launchApp: false });
}, 300000);
beforeEach(async () => {
await adapter.beforeEach();
});
afterAll(async () => {
await adapter.afterAll();
await cleanup();
});
First off, it complains that jasmine is not defined. I guess that's because actually the adapter in this case should be a DetoxAdapterCircus which it is not, even though in my config file I specify:
{
"preset": "react-native",
"testEnvironment": "./environment.ts",
"testRunner": "jest-circus/runner",
"testTimeout": 120000,
"testRegex": "\\.e2e\\.ts$",
"reporters": ["detox/runners/jest/streamlineReporter"],
"verbose": true
}
"testRunner": "jest-circus/runner"
Another idea would be to alter the CustomDetoxEnvironment but I do not understand how I can get access to the detox lifecycle hooks.
const {
DetoxCircusEnvironment,
SpecReporter,
WorkerAssignReporter,
} = require("detox/runners/jest-circus")
class CustomDetoxEnvironment extends DetoxCircusEnvironment {
constructor(config) {
super(config)
// should I access the hooks here now?
// This takes care of generating status logs on a per-spec basis. By default, Jest only reports at file-level.
// This is strictly optional.
this.registerListeners({
SpecReporter,
WorkerAssignReporter,
})
}
}
module.exports = CustomDetoxEnvironment
Tl;dr: I don't know where to put my reusable lifecycle hooks in the latest version of Detox. Also, I wonder if these custom configurations are even needed to reinstall the app and wipe the app data before each test suite.
You can still use setupFilesAfterEnv, but you're not supposed to call the same hooks/cleanup as before (see https://github.com/wix/Detox/issues/2410#issuecomment-744387707).
here's an example of our init script:
// init.ts
// with "setupFilesAfterEnv": ["./init.ts"] in the conf
beforeAll(async () => {
// to reset the state
await device.clearKeychain();
// we are launching the app manually
await device.launchApp({
permissions: { notifications: 'YES', location: 'inuse' },
});
await device.setURLBlacklist([
// ...
]);
});

react-native-music-control closes itself

I'm building an app that streams two-player at the same time. My sources are react-native-video and react-native-youtube-iframe. I implement react-native-music-control to react-native-video and it works perfectly until youtube-iframe starts. When youtube starts, music control disappears on the notification itself and I don't wanna do that. Is there any option to force keep live? btw artwork also doesn't work but it's not important for now.
const { data, streamer, duration } = this.state;
MusicControl.enableControl("play", true);
MusicControl.enableControl("pause", true);
MusicControl.enableControl("stop", true);
MusicControl.enableControl("seekForward", true); // iOS only
MusicControl.enableControl("seekBackward", true); // iOS only
MusicControl.setNowPlaying({
title: data.name,
artwork: "https://via.placeholder.com/250x250?text=" + data.name,
artist: streamer.name,
duration: duration, // (Seconds)
description: "Description", // Android Only
color: 0xffffff, // Notification Color - Android Only
date: "1983-01-02T00:00:00Z", // Release Date (RFC 3339) - Android Only
rating: 84, // Android Only (Boolean or Number depending on the type)
});
MusicControl.enableBackgroundMode(true);
MusicControl.handleAudioInterruptions(true);
MusicControl.on("play", () => {
this.handleMainButtonTouch();
});
MusicControl.on("pause", () => {
this.handleMainButtonTouch();
});
MusicControl.on("seekForward", () => {
this.jumpSeconds(10);
});
MusicControl.on("seekBackward", () => {
this.jumpSeconds(-10);
});
Platform?
[x] iOS
[x] Android
Device/Simulator
[x] Real device

ionic 3 background geo location stops in background

I am using plugin
https://github.com/mauron85/cordova-plugin-background-geolocation
its working fine, when in foreground, but once it goes to background it stops working. Please let me know how i can handle this.
Code in my LocationProvider's constructor function
const config: BackgroundGeolocationConfig = {
desiredAccuracy: 10,
stationaryRadius: 20,
distanceFilter: 30,
debug: true, // enable this hear sounds for background-geolocation life-cycle.
stopOnTerminate: false, // enable this to clear background location settings when the app terminates
};
this.backgroundGeolocation.configure(config)
.subscribe((location: BackgroundGeolocationResponse) => {
this.zone.run(() => {
console.log(location);
})
});
Function after constructor
startTracking(){
console.log("Starting Tracking");
// start recording location
this.backgroundGeolocation.start();
}
Calling this function from home.ts constructor
this.location.startTracking();