blob: c6abbfbfddf0e1881b898b1742285d73108a00c8 [file] [log] [blame]
// Copyright 2016 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_test/flutter_test.dart';
void main() {
testWidgets('ExpansionPanelList test', (WidgetTester tester) async {
int index;
bool isExpanded;
await tester.pumpWidget(
new MaterialApp(
home: new SingleChildScrollView(
child: new ExpansionPanelList(
expansionCallback: (int _index, bool _isExpanded) {
index = _index;
isExpanded = _isExpanded;
},
children: <ExpansionPanel>[
new ExpansionPanel(
headerBuilder: (BuildContext context, bool isExpanded) {
return new Text(isExpanded ? 'B' : 'A');
},
body: const SizedBox(height: 100.0),
),
],
),
),
),
);
expect(find.text('A'), findsOneWidget);
expect(find.text('B'), findsNothing);
RenderBox box = tester.renderObject(find.byType(ExpansionPanelList));
final double oldHeight = box.size.height;
expect(find.byType(ExpandIcon), findsOneWidget);
await tester.tap(find.byType(ExpandIcon));
expect(index, 0);
expect(isExpanded, isFalse);
box = tester.renderObject(find.byType(ExpansionPanelList));
expect(box.size.height, equals(oldHeight));
// now expand the child panel
await tester.pumpWidget(
new MaterialApp(
home: new SingleChildScrollView(
child: new ExpansionPanelList(
expansionCallback: (int _index, bool _isExpanded) {
index = _index;
isExpanded = _isExpanded;
},
children: <ExpansionPanel>[
new ExpansionPanel(
headerBuilder: (BuildContext context, bool isExpanded) {
return new Text(isExpanded ? 'B' : 'A');
},
body: const SizedBox(height: 100.0),
isExpanded: true, // this is the addition
),
],
),
),
),
);
await tester.pump(const Duration(milliseconds: 200));
expect(find.text('A'), findsNothing);
expect(find.text('B'), findsOneWidget);
box = tester.renderObject(find.byType(ExpansionPanelList));
expect(box.size.height - oldHeight, greaterThanOrEqualTo(100.0)); // 100 + some margin
});
testWidgets('Multiple Panel List test', (WidgetTester tester) async {
await tester.pumpWidget(
new MaterialApp(
home: new ListView(
children: <ExpansionPanelList>[
new ExpansionPanelList(
children: <ExpansionPanel>[
new ExpansionPanel(
headerBuilder: (BuildContext context, bool isExpanded) {
return new Text(isExpanded ? 'B' : 'A');
},
body: const SizedBox(height: 100.0),
isExpanded: true,
),
],
),
new ExpansionPanelList(
children: <ExpansionPanel>[
new ExpansionPanel(
headerBuilder: (BuildContext context, bool isExpanded) {
return new Text(isExpanded ? 'D' : 'C');
},
body: const SizedBox(height: 100.0),
isExpanded: true,
),
],
),
],
),
),
);
await tester.pump(const Duration(milliseconds: 200));
expect(find.text('A'), findsNothing);
expect(find.text('B'), findsOneWidget);
expect(find.text('C'), findsNothing);
expect(find.text('D'), findsOneWidget);
});
testWidgets('Open/close animations', (WidgetTester tester) async {
const Duration kSizeAnimationDuration = Duration(milliseconds: 1000);
// The MaterialGaps animate in using kThemeAnimationDuration (hardcoded),
// which should be less than our test size animation length. So we can assume that they
// appear immediately. Here we just verify that our assumption is true.
expect(kThemeAnimationDuration, lessThan(kSizeAnimationDuration ~/ 2));
Widget build(bool a, bool b, bool c) {
return new MaterialApp(
home: new Column(
children: <Widget>[
new ExpansionPanelList(
animationDuration: kSizeAnimationDuration,
children: <ExpansionPanel>[
new ExpansionPanel(
headerBuilder: (BuildContext context, bool isExpanded) => const Placeholder(
fallbackHeight: 12.0,
),
body: const SizedBox(height: 100.0, child: Placeholder(
fallbackHeight: 12.0,
)),
isExpanded: a,
),
new ExpansionPanel(
headerBuilder: (BuildContext context, bool isExpanded) => const Placeholder(
fallbackHeight: 12.0,
),
body: const SizedBox(height: 100.0, child: Placeholder()),
isExpanded: b,
),
new ExpansionPanel(
headerBuilder: (BuildContext context, bool isExpanded) => const Placeholder(
fallbackHeight: 12.0,
),
body: const SizedBox(height: 100.0, child: Placeholder()),
isExpanded: c,
),
],
),
],
),
);
}
await tester.pumpWidget(build(false, false, false));
expect(tester.renderObjectList(find.byType(AnimatedSize)), hasLength(3));
expect(tester.getRect(find.byType(AnimatedSize).at(0)), new Rect.fromLTWH(0.0, 56.0, 800.0, 0.0));
expect(tester.getRect(find.byType(AnimatedSize).at(1)), new Rect.fromLTWH(0.0, 113.0, 800.0, 0.0));
expect(tester.getRect(find.byType(AnimatedSize).at(2)), new Rect.fromLTWH(0.0, 170.0, 800.0, 0.0));
await tester.pump(const Duration(milliseconds: 200));
expect(tester.getRect(find.byType(AnimatedSize).at(0)), new Rect.fromLTWH(0.0, 56.0, 800.0, 0.0));
expect(tester.getRect(find.byType(AnimatedSize).at(1)), new Rect.fromLTWH(0.0, 113.0, 800.0, 0.0));
expect(tester.getRect(find.byType(AnimatedSize).at(2)), new Rect.fromLTWH(0.0, 170.0, 800.0, 0.0));
await tester.pumpWidget(build(false, true, false));
expect(tester.getRect(find.byType(AnimatedSize).at(0)), new Rect.fromLTWH(0.0, 56.0, 800.0, 0.0));
expect(tester.getRect(find.byType(AnimatedSize).at(1)), new Rect.fromLTWH(0.0, 113.0, 800.0, 0.0));
expect(tester.getRect(find.byType(AnimatedSize).at(2)), new Rect.fromLTWH(0.0, 170.0, 800.0, 0.0));
await tester.pump(kSizeAnimationDuration ~/ 2);
expect(tester.getRect(find.byType(AnimatedSize).at(0)), new Rect.fromLTWH(0.0, 56.0, 800.0, 0.0));
final Rect rect1 = tester.getRect(find.byType(AnimatedSize).at(1));
expect(rect1.left, 0.0);
expect(rect1.top, inExclusiveRange(113.0, 113.0 + 16.0 + 32.0)); // 16.0 material gap, plus 16.0 top and bottom margins added to the header
expect(rect1.width, 800.0);
expect(rect1.height, inExclusiveRange(0.0, 100.0));
final Rect rect2 = tester.getRect(find.byType(AnimatedSize).at(2));
expect(rect2, new Rect.fromLTWH(0.0, rect1.bottom + 16.0 + 56.0, 800.0, 0.0)); // the 16.0 comes from the MaterialGap being introduced, the 56.0 is the header height.
await tester.pumpWidget(build(false, false, false));
expect(tester.getRect(find.byType(AnimatedSize).at(0)), new Rect.fromLTWH(0.0, 56.0, 800.0, 0.0));
expect(tester.getRect(find.byType(AnimatedSize).at(1)), rect1);
expect(tester.getRect(find.byType(AnimatedSize).at(2)), rect2);
await tester.pumpWidget(build(false, false, true));
expect(tester.getRect(find.byType(AnimatedSize).at(0)), new Rect.fromLTWH(0.0, 56.0, 800.0, 0.0));
expect(tester.getRect(find.byType(AnimatedSize).at(1)), rect1);
expect(tester.getRect(find.byType(AnimatedSize).at(2)), rect2);
// a few no-op pumps to make sure there's nothing fishy going on
await tester.pump();
await tester.pump();
await tester.pump();
expect(tester.getRect(find.byType(AnimatedSize).at(0)), new Rect.fromLTWH(0.0, 56.0, 800.0, 0.0));
expect(tester.getRect(find.byType(AnimatedSize).at(1)), rect1);
expect(tester.getRect(find.byType(AnimatedSize).at(2)), rect2);
await tester.pumpAndSettle();
expect(tester.getRect(find.byType(AnimatedSize).at(0)), new Rect.fromLTWH(0.0, 56.0, 800.0, 0.0));
expect(tester.getRect(find.byType(AnimatedSize).at(1)), new Rect.fromLTWH(0.0, 56.0 + 1.0 + 56.0, 800.0, 0.0));
expect(tester.getRect(find.byType(AnimatedSize).at(2)), new Rect.fromLTWH(0.0, 56.0 + 1.0 + 56.0 + 16.0 + 16.0 + 48.0 + 16.0, 800.0, 100.0));
});
testWidgets('Single Panel Open Test', (WidgetTester tester) async {
final List<ExpansionPanel> _demoItemsRadio = <ExpansionPanelRadio>[
new ExpansionPanelRadio(
headerBuilder: (BuildContext context, bool isExpanded) {
return new Text(isExpanded ? 'B' : 'A');
},
body: const SizedBox(height: 100.0),
value: 0,
),
new ExpansionPanelRadio(
headerBuilder: (BuildContext context, bool isExpanded) {
return new Text(isExpanded ? 'D' : 'C');
},
body: const SizedBox(height: 100.0),
value: 1,
),
new ExpansionPanelRadio(
headerBuilder: (BuildContext context, bool isExpanded) {
return new Text(isExpanded ? 'F' : 'E');
},
body: const SizedBox(height: 100.0),
value: 2,
),
];
final ExpansionPanelList _expansionListRadio = ExpansionPanelList.radio(
children: _demoItemsRadio,
);
await tester.pumpWidget(
new MaterialApp(
home: new SingleChildScrollView(
child: _expansionListRadio,
),
),
);
// Initializes with all panels closed
expect(find.text('A'), findsOneWidget);
expect(find.text('B'), findsNothing);
expect(find.text('C'), findsOneWidget);
expect(find.text('D'), findsNothing);
expect(find.text('E'), findsOneWidget);
expect(find.text('F'), findsNothing);
RenderBox box = tester.renderObject(find.byType(ExpansionPanelList));
double oldHeight = box.size.height;
expect(find.byType(ExpandIcon), findsNWidgets(3));
await tester.tap(find.byType(ExpandIcon).at(0));
box = tester.renderObject(find.byType(ExpansionPanelList));
expect(box.size.height, equals(oldHeight));
await tester.pump(const Duration(milliseconds: 200));
await tester.pumpAndSettle();
// Now the first panel is open
expect(find.text('A'), findsNothing);
expect(find.text('B'), findsOneWidget);
expect(find.text('C'), findsOneWidget);
expect(find.text('D'), findsNothing);
expect(find.text('E'), findsOneWidget);
expect(find.text('F'), findsNothing);
box = tester.renderObject(find.byType(ExpansionPanelList));
expect(box.size.height - oldHeight, greaterThanOrEqualTo(100.0)); // 100 + some margin
await tester.tap(find.byType(ExpandIcon).at(1));
box = tester.renderObject(find.byType(ExpansionPanelList));
oldHeight = box.size.height;
await tester.pump(const Duration(milliseconds: 200));
// Now the first panel is closed and the second should be opened
expect(find.text('A'), findsOneWidget);
expect(find.text('B'), findsNothing);
expect(find.text('C'), findsNothing);
expect(find.text('D'), findsOneWidget);
expect(find.text('E'), findsOneWidget);
expect(find.text('F'), findsNothing);
expect(box.size.height, greaterThanOrEqualTo(oldHeight));
_demoItemsRadio.removeAt(0);
await tester.pumpAndSettle();
// Now the first panel should be opened
expect(find.text('C'), findsNothing);
expect(find.text('D'), findsOneWidget);
expect(find.text('E'), findsOneWidget);
expect(find.text('F'), findsNothing);
final List<ExpansionPanel> _demoItems = <ExpansionPanel>[
new ExpansionPanel(
headerBuilder: (BuildContext context, bool isExpanded) {
return new Text(isExpanded ? 'B' : 'A');
},
body: const SizedBox(height: 100.0),
isExpanded: false,
),
new ExpansionPanel(
headerBuilder: (BuildContext context, bool isExpanded) {
return new Text(isExpanded ? 'D' : 'C');
},
body: const SizedBox(height: 100.0),
isExpanded: false,
),
new ExpansionPanel(
headerBuilder: (BuildContext context, bool isExpanded) {
return new Text(isExpanded ? 'F' : 'E');
},
body: const SizedBox(height: 100.0),
isExpanded: false,
),
];
final ExpansionPanelList _expansionList = new ExpansionPanelList(
children: _demoItems,
);
await tester.pumpWidget(
new MaterialApp(
home: new SingleChildScrollView(
child: _expansionList,
),
),
);
// We've reinitialized with a regular expansion panel so they should all be closed again
expect(find.text('A'), findsOneWidget);
expect(find.text('B'), findsNothing);
expect(find.text('C'), findsOneWidget);
expect(find.text('D'), findsNothing);
expect(find.text('E'), findsOneWidget);
expect(find.text('F'), findsNothing);
});
testWidgets('Panel header has semantics', (WidgetTester tester) async {
const Key expandedKey = Key('expanded');
const Key collapsedKey = Key('collapsed');
const DefaultMaterialLocalizations localizations = DefaultMaterialLocalizations();
final SemanticsHandle handle = tester.ensureSemantics();
final List<ExpansionPanel> _demoItems = <ExpansionPanel>[
new ExpansionPanel(
headerBuilder: (BuildContext context, bool isExpanded) {
return const Text('Expanded', key: expandedKey);
},
body: const SizedBox(height: 100.0),
isExpanded: true,
),
new ExpansionPanel(
headerBuilder: (BuildContext context, bool isExpanded) {
return const Text('Collapsed', key: collapsedKey);
},
body: const SizedBox(height: 100.0),
isExpanded: false,
),
];
final ExpansionPanelList _expansionList = new ExpansionPanelList(
children: _demoItems,
);
await tester.pumpWidget(
new MaterialApp(
home: new SingleChildScrollView(
child: _expansionList,
),
),
);
expect(tester.getSemanticsData(find.byKey(expandedKey)), matchesSemanticsData(
label: 'Expanded',
isButton: true,
hasEnabledState: true,
isEnabled: true,
hasTapAction: true,
onTapHint: localizations.expandedIconTapHint,
));
expect(tester.getSemanticsData(find.byKey(collapsedKey)), matchesSemanticsData(
label: 'Collapsed',
isButton: true,
hasEnabledState: true,
isEnabled: true,
hasTapAction: true,
onTapHint: localizations.collapsedIconTapHint,
));
handle.dispose();
});
}