A test driver for Flutter to do QA testing without sharing app source code. It exposes a JSON API using an HTTP server running inside the app. Using these APIs you can write tests in any language for your Flutter app.
Add package to dependencies:
flutter pub add autopilot
Create main_test.dart
along side of your main.dart
file. Make AutoPilot widget parent of your MaterialApp or root widget like below:
import 'package:flutter/material.dart';
import 'package:autopilot/autopilot.dart';
import 'my_app.dart';
void main() {
runApp(
Autopilot(child: MyApp())
);
}
Run your app on device/emulator:
flutter run --release --target lib/main_test.dart
On Android forward port 8080
so that you can access it via localhost
:
adb forward tcp:8080 tcp:8080
Consider following example:
Text(
"Hello World!",
key: Key("txtGreet"),
)
Example of a test in python using pytest
:
# example_test.py
import requests
root = "http://localhost:8080"
def get(path):
return requests.get(root + path).json()
def test_greet():
greet = get("/texts?key=txtGreet")[0]
assert greet["text"] == "Hello World!"
Run it:
python -m pytest example_test.py
Flutter has a really amazing testing suite for Unit, UI and Integration testing. But one problem is that you need to know/learn Dart and you have to share the source code of the app to the person who writes tests. This doesn't work in every work environments.
But Flutter framework is so transparent I was able to tap into its internals and build a JSON API which can provide pretty much everything you need to write UI automation tests.
GET /widgets?parent=:widget_type
Returns entire widget tree.
parent
(optional) - if provided, returns widget tree starting from the first widget of the specified type, otherwise considers the entire widget tree
GET /keys?parent=:widget_type
Returns list of all the keyed widgets.
parent
(optional) - if provided, returns only keyed widgets within the specified parent widget type, otherwise considers the entire widget tree
GET /texts?text=:text&key=:key&parent=:widget_type
Returns list of text widgets.
text
(optional) - filters widgets with matching textkey
(optional) - returns widget that matches keyparent
(optional) - if provided, searches only within the specified parent widget type, otherwise considers the entire widget tree
GET /editables?parent=:widget_type
Returns list of all text fields.
parent
(optional) - if provided, returns only text fields within the specified parent widget type, otherwise considers the entire widget tree
GET /type?text=:text
Types given text to the focused text field
GET /tap?x=:x&y=:y&key=:key&text=:text¢er=:center&parent=:widget_type
Taps on screen at an offset, a key or a text.
x
,y
(optional) - taps at given offsetkey
(optional) - taps on widget with given keytext
(optional) - taps on text widget with given textcenter
(optional) - set totrue
to tap at center of the widgetparent
(optional) - if provided, searches only within the specified parent widget type, otherwise considers the entire widget tree
GET /hold?x=:x&y=:y
Tap and hold on given offset
GET /drag?x=:x&y=:y&dx=:dx&dy=:dy
Taps at (x,y) and drags (dx, dy) offset
GET /scroll?key=:key&dx=:dx&dy=:dy&parent=:widget_type
Taps inside scrollable and drags.
key
- key of scrollable widgetdx
,dy
- drag offsetparent
(optional) - if provided, searches only within the specified parent widget type, otherwise considers the entire widget tree
GET /scroll-into?scrollable-key=:key&key=:key&dx=:dx&dy=:dy&delay=:delay&timeout=:timeout&parent=:widget_type
Scrolls until target widget becomes visible.
scrollable-key
- key of scrollable widgetkey
- key of widget to scroll into viewdx
,dy
- drag offsetdelay
(optional) - milliseconds between drags (default: 500)timeout
(optional) - timeout in milliseconds (default: 5000)parent
(optional) - if provided, searches only within the specified parent widget type, otherwise considers the entire widget tree
GET /screenshot
Returns screenshot of app in PNG
GET /keyboard
Shows keyboard
DELETE /keyboard
Hides keyboard
POST /keyboard?type=:type
Submits a keyboard action.
Some actions may not be available on all platforms. See TextInputAction for more information.