flutter/packages/flutter/test/widgets/widget_inspector_test.dart
Adam Barth c46347b6df Add RTL support to Stack (#11973)
Notice that the default alignment for Stack needs to know the
directionality.
2017-09-07 22:52:36 -07:00

260 lines
8.8 KiB
Dart

// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('WidgetInspector smoke test', (WidgetTester tester) async {
// This is a smoke test to verify that adding the inspector doesn't crash.
await tester.pumpWidget(
new Directionality(
textDirection: TextDirection.ltr,
child: new Stack(
children: <Widget>[
const Text('a', textDirection: TextDirection.ltr),
const Text('b', textDirection: TextDirection.ltr),
const Text('c', textDirection: TextDirection.ltr),
],
),
),
);
await tester.pumpWidget(
new Directionality(
textDirection: TextDirection.ltr,
child: new WidgetInspector(
selectButtonBuilder: null,
child: new Stack(
children: <Widget>[
const Text('a', textDirection: TextDirection.ltr),
const Text('b', textDirection: TextDirection.ltr),
const Text('c', textDirection: TextDirection.ltr),
],
),
),
),
);
expect(true, isTrue); // Expect that we reach here without crashing.
});
testWidgets('WidgetInspector interaction test', (WidgetTester tester) async {
final List<String> log = <String>[];
final GlobalKey selectButtonKey = new GlobalKey();
final GlobalKey inspectorKey = new GlobalKey();
final GlobalKey topButtonKey = new GlobalKey();
Widget selectButtonBuilder(BuildContext context, VoidCallback onPressed) {
return new Material(child: new RaisedButton(onPressed: onPressed, key: selectButtonKey));
}
// State type is private, hence using dynamic.
dynamic getInspectorState() => inspectorKey.currentState;
String paragraphText(RenderParagraph paragraph) => paragraph.text.text;
await tester.pumpWidget(
new Directionality(
textDirection: TextDirection.ltr,
child: new WidgetInspector(
key: inspectorKey,
selectButtonBuilder: selectButtonBuilder,
child: new Material(
child: new ListView(
children: <Widget>[
new RaisedButton(
key: topButtonKey,
onPressed: () {
log.add('top');
},
child: const Text('TOP'),
),
new RaisedButton(
onPressed: () {
log.add('bottom');
},
child: const Text('BOTTOM'),
),
],
),
),
),
),
);
expect(getInspectorState().selection.current, isNull);
await tester.tap(find.text('TOP'));
await tester.pump();
// Tap intercepted by the inspector
expect(log, equals(<String>[]));
final InspectorSelection selection = getInspectorState().selection;
expect(paragraphText(selection.current), equals('TOP'));
final RenderObject topButton = find.byKey(topButtonKey).evaluate().first.renderObject;
expect(selection.candidates.contains(topButton), isTrue);
await tester.tap(find.text('TOP'));
expect(log, equals(<String>['top']));
log.clear();
await tester.tap(find.text('BOTTOM'));
expect(log, equals(<String>['bottom']));
log.clear();
// Ensure the inspector selection has not changed to bottom.
expect(paragraphText(getInspectorState().selection.current), equals('TOP'));
await tester.tap(find.byKey(selectButtonKey));
await tester.pump();
// We are now back in select mode so tapping the bottom button will have
// not trigger a click but will cause it to be selected.
await tester.tap(find.text('BOTTOM'));
expect(log, equals(<String>[]));
log.clear();
expect(paragraphText(getInspectorState().selection.current), equals('BOTTOM'));
});
testWidgets('WidgetInspector scroll test', (WidgetTester tester) async {
final Key childKey = new UniqueKey();
final GlobalKey selectButtonKey = new GlobalKey();
final GlobalKey inspectorKey = new GlobalKey();
Widget selectButtonBuilder(BuildContext context, VoidCallback onPressed) {
return new Material(child: new RaisedButton(onPressed: onPressed, key: selectButtonKey));
}
// State type is private, hence using dynamic.
dynamic getInspectorState() => inspectorKey.currentState;
await tester.pumpWidget(
new Directionality(
textDirection: TextDirection.ltr,
child: new WidgetInspector(
key: inspectorKey,
selectButtonBuilder: selectButtonBuilder,
child: new ListView(
children: <Widget>[
new Container(
key: childKey,
height: 5000.0,
),
],
),
),
),
);
expect(tester.getTopLeft(find.byKey(childKey)).dy, equals(0.0));
await tester.fling(find.byType(ListView), const Offset(0.0, -200.0), 200.0);
await tester.pump();
// Fling does nothing as are in inspect mode.
expect(tester.getTopLeft(find.byKey(childKey)).dy, equals(0.0));
await tester.fling(find.byType(ListView), const Offset(200.0, 0.0), 200.0);
await tester.pump();
// Fling still does nothing as are in inspect mode.
expect(tester.getTopLeft(find.byKey(childKey)).dy, equals(0.0));
await tester.tap(find.byType(ListView));
await tester.pump();
expect(getInspectorState().selection.current, isNotNull);
// Now out of inspect mode due to the click.
await tester.fling(find.byType(ListView), const Offset(0.0, -200.0), 200.0);
await tester.pump();
expect(tester.getTopLeft(find.byKey(childKey)).dy, equals(-200.0));
await tester.fling(find.byType(ListView), const Offset(0.0, 200.0), 200.0);
await tester.pump();
expect(tester.getTopLeft(find.byKey(childKey)).dy, equals(0.0));
});
testWidgets('WidgetInspector long press', (WidgetTester tester) async {
bool didLongPress = false;
await tester.pumpWidget(
new Directionality(
textDirection: TextDirection.ltr,
child: new WidgetInspector(
selectButtonBuilder: null,
child: new GestureDetector(
onLongPress: () {
expect(didLongPress, isFalse);
didLongPress = true;
},
child: const Text('target', textDirection: TextDirection.ltr),
),
),
),
);
await tester.longPress(find.text('target'));
// The inspector will swallow the long press.
expect(didLongPress, isFalse);
});
testWidgets('WidgetInspector offstage', (WidgetTester tester) async {
final GlobalKey inspectorKey = new GlobalKey();
final GlobalKey clickTarget = new GlobalKey();
Widget createSubtree({ double width, Key key }) {
return new Stack(
children: <Widget>[
new Positioned(
key: key,
left: 0.0,
top: 0.0,
width: width,
height: 100.0,
child: new Text(width.toString(), textDirection: TextDirection.ltr),
),
],
);
}
await tester.pumpWidget(
new Directionality(
textDirection: TextDirection.ltr,
child: new WidgetInspector(
key: inspectorKey,
selectButtonBuilder: null,
child: new Overlay(
initialEntries: <OverlayEntry>[
new OverlayEntry(
opaque: false,
maintainState: true,
builder: (BuildContext _) => createSubtree(width: 94.0),
),
new OverlayEntry(
opaque: true,
maintainState: true,
builder: (BuildContext _) => createSubtree(width: 95.0),
),
new OverlayEntry(
opaque: false,
maintainState: true,
builder: (BuildContext _) => createSubtree(width: 96.0, key: clickTarget),
),
],
),
),
),
);
await tester.longPress(find.byKey(clickTarget));
// State type is private, hence using dynamic.
final dynamic inspectorState = inspectorKey.currentState;
// The object with width 95.0 wins over the object with width 94.0 because
// the subtree with width 94.0 is offstage.
expect(inspectorState.selection.current.semanticBounds.width, equals(95.0));
// Exactly 2 out of the 3 text elements should be in the candidate list of
// objects to select as only 2 are onstage.
expect(inspectorState.selection.candidates.where((RenderObject object) => object is RenderParagraph).length, equals(2));
});
}