An overall summary for the API case is available here.
Prerequisites
You can use the Flutster plugin with the following prerequisites:
- A Flutter app with source code and development environment (Android Studio is considered here)
- An Android device with scrcpy or an Android emulator
In addition, you can use the Flutster API with an API key from Flutster API.
Integrate the Flutster plugin to your app
In order to record your user interface tests in test records, you will integrate the Flutster plugin as follows.
Add the Flutster plugin dependency to your pubspec.yaml
file:
dependencies:
flutster:
Update dependencies with the following terminal command:
flutter pub get
Import the package from your Dart code:
import 'package:flutster/flutster.dart';
When using the Flutster API, consider the following initialization Dart code in your app:
FlutsterTestRecord.defaultRecord.apiUrl="https://flutster.com";
//Create a user at https://flutster.com
FlutsterTestRecord.defaultRecord.apiUser="Your Flutster User";
//Get your API key on the profile page at https://flutster.com
FlutsterTestRecord.defaultRecord.apiKey="Your Flutster API Key";
//The API key is made of 60 characters 0-f
Flutster is not meant to be used in a production situation. Such a Dart line takes care of this:
//Avoid using Flutster in production
FlutsterTestRecord.defaultRecord.active=!prod;
Optionally, adapt the size of the Flutster button to your screen with this Dart line:
//Set the Flutster button size
FlutsterTestRecord.defaultRecord.buttonSize=30.0;
Replace or place one Scaffold
per page you want to test with a FlutsterScaffold
. For example:
return FlutsterScaffold(
name: "myUniqueWidgetName",
appBar: AppBar(
title: Text(widget.title),
),
body: ...
);
Where name
is used to identify the Scaffold in case there is more than one on the screen.
If you don’t have a Scaffold
on a screen you want to test, you can use the following instead:
FlutsterTestRecorder(
name: "myUniqueWidgetName",
child: myWidget,
)
Make your text field cursor invisible
We recommend making the text field cursor invisible to increase the chances for the screenshots to match. This can be done by setting the app theme cursorColor
to the same color as the background as follows:
MaterialApp(
theme: ThemeData(
textSelectionTheme: TextSelectionThemeData(
cursorColor: Colors.white,
),
...
));
Create your test record
Once the Flutster plugin is integrated to your Android application, run the application either on an Android emulator or on a physical device with the help of scrcpy:
Click the blue square Flutster floating button with an equal sign in the upper left corner of the screen:
This opens the Flutster test recorder menu:
See all the details of the Flutster test recorder menu here.
Click on the blue circled square button to start recording a Flutster test record:
When in recording state, the Flutster test recorder menu displays a red disk instead of the start recording button:
Close the Flutster test recorder menu:
Interact with your app to record the test with the following limitations:
- Only the physical keyboard is recorded, not the software onscreen keyboard. This is why scrcpy is necessary for physical devices.
- Typed texts in text fields will replace the existing content of the text field when the test record will be run.
- Mouse interactions are recorded only with start – end points and durations. This means that scrolling and drag and dropping may not be replicated accurately.
While recording, the Flutster floating button is a red round disk with an equal sign inside.
Once done with your test, double click the recording Flutster floating button to take a screenshot:
The screenshot is the way to validate the test result.
Click on the recording Flutster floating button:
Then, click on the red disk button to stop the test recording:
Optionally, give a name to your test record:
If you recorded keyboard interactions, it is recommended to combine the key events with the blue sheets button displayed on such event:
Save your test record
There are 2 ways to save your test record:
- If you set the Flutster API parameters with a user name, API key and server, you can save to the Flutster API with the up arrow in a blue cloud button . Take note of API test record id for later use:
or
- Copy the test record json code to the clipboard or share it through other means depending on your Android installation with the blue share button .
Run your test record
Create a folder called integration_test
in your application folder and place test file inside:
If you are using the API, here is an example of content for the test file:
import 'package:myapp/main.dart' as theApp;
import 'package:flutster/flutster.dart';
import 'package:flutter/foundation.dart';
import 'package:integration_test/integration_test.dart';
import 'package:flutter_test/flutter_test.dart';
void main() async {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
TestWidgetsFlutterBinding.ensureInitialized();
testWidgets('Integration testing based on Flutster API',
(WidgetTester tester) async {
// Start the app
theApp.main(testing: true);
await tester.pumpAndSettle();
// Simply using the default recorder.
FlutsterTestRecord record = FlutsterTestRecord.defaultRecord;
record.apiUrl = "https://flutster.com";
record.apiUser = "Your Flutster User";//Create a user at https://flutster.com
record.apiKey =
"Your Flutster API Key";//The API key is made of 60 characters 0-f
// Loading and running the first record.
String loadResult = await record.fromApi(50, tester: tester);
if (loadResult != "Test record loaded from API") {
debugPrint(loadResult);
expect(false, true, reason: loadResult);
}
bool result = await record.playToApi(tester);
expect(result, true, reason: "API test 50 over with this result");
// Loading and running the second record.
loadResult = await record.fromApi(52, tester: tester);
if (loadResult != "Test record loaded from API") {
debugPrint(loadResult);
expect(false, true, reason: loadResult);
}
result = await record.playToApi(tester);
expect(result, true, reason: "API test 52 over with this result");
});
}
If, instead of the API, you are using the json content recorded earlier, please consider the following example test file:
import 'package:myapp/main.dart' as theApp;
import 'package:flutster/flutster.dart';
import 'package:flutter/foundation.dart';
import 'package:integration_test/integration_test.dart';
import 'package:flutter_test/flutter_test.dart';
void main() async {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
TestWidgetsFlutterBinding.ensureInitialized();
testWidgets('Integration testing based on Flutster json',
(WidgetTester tester) async {
// Start the app
theApp.main(testing: true);
await tester.pumpAndSettle();
// Simply using the default recorder.
FlutsterTestRecord record = FlutsterTestRecord.defaultRecord;
record.apiUrl = "https://me:moitiemoitie@dev.flutster.com";
record.apiUser = "louis";
record.apiKey =
"e23456789012345678901234567890123456789012345678901234567890";
record.fromJson(
'{"testName":"myapp reminders","firstRecordingStart":1655313129211,"events":[{"type":"tap","waitDuration":1487,"time":1655313154032,"widgetName":null,"tapStart.dx":89.06666666666666,"tapStart.dy":403.73333333333335,"tapDuration":103,"tapStop.dx":89.06666666666666,"tapStop.dy":403.73333333333335},{"type":"key","waitDuration":3291,"time":1655313157328,"widgetName":null,"logicalKey.keyId":50,"physicalKey.usbHidUsage":73014444032,"keyEvent.duration":233675750,"typedText":"12","keyEventDown":false,"character":"","logicalKey.keyLabel":"2"},{"type":"tap","waitDuration":1337,"time":1655313158665,"widgetName":null,"tapStart.dx":238.93333333333334,"tapStart.dy":283.73333333333335,"tapDuration":94,"tapStop.dx":238.93333333333334,"tapStop.dy":283.73333333333335},{"type":"screenShot","waitDuration":1961,"time":1655313165640,"widgetName":"reminderScreen","screenShot":"iVBORw...K5CYII=","screenShotComparisonFunctionName":"Pixel - Matching","screenShotAcceptancePctThreshold":99.999,"pixelMatchingTolerance":0.02,"IMEDBlurRatio":0.005,"IMEDSigma":1.0}]}',
tester: tester,
);
bool result = await record.play(tester);
expect(result, true, reason: "json test over with this result");
});
}
Note that the json in the above test example has been simplified. In particular, the screenshot isn’t complete.
Edit the run configuration in Android Studio:
Add a Flutter test configuration:
Set your test file to the run configuration:
Validate and select the newly created run configuration:
Run or debug the Flutster test run configuration:
Follow the run on the device screen and check the results in Android Studio:
When using the Flutster API, the test run is visible on flutster.com next to the test record and allows the comparison of screenshots:
You can replace the test record with the test run in case they differ using the Flutster API interface: