260 lines
8.8 KiB
Dart
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));
|
|
});
|
|
}
|