blob: 1b0f7958c93c51b7a5957e92ad8c5695eaa980c5 [file] [log] [blame]
// Copyright 2013 The Flutter 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:dynamic_layouts/dynamic_layouts.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets(
'DynamicGridView generates children and checks if they are layed out',
(WidgetTester tester) async {
final List<Widget> children = List<Widget>.generate(
10,
(int index) => SizedBox(
height: index.isEven ? 100 : 50,
width: index.isEven ? 95 : 180,
child: Text('Item $index'),
),
);
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
body: DynamicGridView(
gridDelegate: const SliverGridDelegateWithWrapping(),
children: children,
),
),
),
);
// Check that the children are in the tree
for (int i = 0; i < 10; i++) {
expect(find.text('Item $i'), findsOneWidget);
}
// Check that the children are in the right position
expect(tester.getTopLeft(find.text('Item 0')), Offset.zero);
expect(tester.getTopLeft(find.text('Item 1')), const Offset(95.0, 0.0));
expect(tester.getTopLeft(find.text('Item 2')), const Offset(275.0, 0.0));
expect(tester.getTopLeft(find.text('Item 3')), const Offset(370.0, 0.0));
expect(tester.getTopLeft(find.text('Item 4')), const Offset(550.0, 0.0));
expect(tester.getTopLeft(find.text('Item 5')), const Offset(0.0, 100.0));
expect(tester.getTopLeft(find.text('Item 6')), const Offset(180.0, 100.0));
expect(tester.getTopLeft(find.text('Item 7')), const Offset(275.0, 100.0));
expect(tester.getTopLeft(find.text('Item 8')), const Offset(455.0, 100.0));
expect(tester.getTopLeft(find.text('Item 9')), const Offset(550.0, 100.0));
});
testWidgets(
'Test for wrap that generates children and checks if they are layed out',
(WidgetTester tester) async {
final List<Widget> children = List<Widget>.generate(
10,
(int index) => SizedBox(
height: index.isEven ? 100 : 50,
width: index.isEven ? 95 : 180,
child: Text('Item $index'),
),
);
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
body: DynamicGridView.wrap(
children: children,
),
),
),
);
for (int i = 0; i < 10; i++) {
expect(find.text('Item $i'), findsOneWidget);
}
// Check that the children are in the right position
expect(tester.getTopLeft(find.text('Item 0')), Offset.zero);
expect(tester.getTopLeft(find.text('Item 1')), const Offset(95.0, 0.0));
expect(tester.getTopLeft(find.text('Item 2')), const Offset(275.0, 0.0));
expect(tester.getTopLeft(find.text('Item 3')), const Offset(370.0, 0.0));
expect(tester.getTopLeft(find.text('Item 4')), const Offset(550.0, 0.0));
expect(tester.getTopLeft(find.text('Item 5')), const Offset(0.0, 100.0));
expect(tester.getTopLeft(find.text('Item 6')), const Offset(180.0, 100.0));
expect(tester.getTopLeft(find.text('Item 7')), const Offset(275.0, 100.0));
expect(tester.getTopLeft(find.text('Item 8')), const Offset(455.0, 100.0));
expect(tester.getTopLeft(find.text('Item 9')), const Offset(550.0, 100.0));
});
testWidgets('Test for wrap to be laying child dynamically',
(WidgetTester tester) async {
final List<Widget> children = List<Widget>.generate(
20,
(int index) => SizedBox(
height: index.isEven ? 1000 : 50,
width: index.isEven ? 95 : 180,
child: Text('Item $index'),
),
);
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
body: DynamicGridView.builder(
itemCount: children.length,
gridDelegate: const SliverGridDelegateWithWrapping(),
itemBuilder: (BuildContext context, int index) => children[index],
),
),
),
);
for (int i = 0; i < 5; i++) {
expect(find.text('Item $i'), findsOneWidget);
}
// Check that the children are in the right position
expect(tester.getTopLeft(find.text('Item 0')), Offset.zero);
expect(tester.getTopLeft(find.text('Item 1')), const Offset(95.0, 0.0));
expect(tester.getTopLeft(find.text('Item 2')), const Offset(275.0, 0.0));
expect(tester.getTopLeft(find.text('Item 3')), const Offset(370.0, 0.0));
expect(tester.getTopLeft(find.text('Item 4')), const Offset(550.0, 0.0));
expect(find.text('Item 5'), findsNothing);
await tester.scrollUntilVisible(find.text('Item 19'), 500.0);
await tester.pumpAndSettle();
expect(find.text('Item 18'), findsOneWidget);
expect(tester.getTopLeft(find.text('Item 18')), const Offset(455.0, 0.0));
expect(find.text('Item 0'), findsNothing);
expect(find.text('Item 1'), findsNothing);
expect(find.text('Item 2'), findsNothing);
expect(find.text('Item 3'), findsNothing);
});
testWidgets(
'Test for DynamicGridView.wrap to scrollDirection Axis.horizontal',
(WidgetTester tester) async {
final List<Widget> children = List<Widget>.generate(
20,
(int index) => SizedBox(
height: index.isEven ? 100 : 50,
width: index.isEven ? 100 : 180,
child: Text('Item $index'),
),
);
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
body: DynamicGridView.wrap(
scrollDirection: Axis.horizontal,
children: children,
),
),
),
);
for (int i = 0; i < 20; i++) {
expect(find.text('Item $i'), findsOneWidget);
}
// Check that the children are in the right position
double dy = 0, dx = 0;
for (int i = 0; i < 20; i++) {
if (dy >= 600.0) {
dy = 0.0;
dx += 180.0;
}
expect(tester.getTopLeft(find.text('Item $i')), Offset(dx, dy));
dy += i.isEven ? 100 : 50;
}
});
testWidgets('Test DynamicGridView.builder for GridView.reverse to true',
(WidgetTester tester) async {
final List<Widget> children = List<Widget>.generate(
10,
(int index) => SizedBox(
height: index.isEven ? 100 : 50,
width: index.isEven ? 100 : 180,
child: Text('Item $index'),
),
);
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
body: DynamicGridView.builder(
reverse: true,
itemCount: children.length,
gridDelegate: const SliverGridDelegateWithWrapping(),
itemBuilder: (BuildContext context, int index) => children[index],
),
),
),
);
for (int i = 0; i < 10; i++) {
expect(find.text('Item $i'), findsOneWidget);
}
double dx = 0.0, dy = 600.0;
for (int i = 0; i < 10; i++) {
if (dx >= 600.0) {
dx = 0.0;
dy -= 100.0;
}
expect(tester.getBottomLeft(find.text('Item $i')), Offset(dx, dy));
dx += i.isEven ? 100 : 180;
}
});
testWidgets('DynamicGridView.wrap for GridView.reverse to true',
(WidgetTester tester) async {
final List<Widget> children = List<Widget>.generate(
20,
(int index) => SizedBox(
height: index.isEven ? 100 : 50,
width: index.isEven ? 100 : 180,
child: Text('Item $index'),
),
);
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
body: DynamicGridView.wrap(
reverse: true,
children: children,
),
),
),
);
for (int i = 0; i < 20; i++) {
expect(find.text('Item $i'), findsOneWidget);
}
// Check that the children are in the right position
double dx = 0.0, dy = 600.0;
for (int i = 0; i < 20; i++) {
if (dx >= 600.0) {
dx = 0.0;
dy -= 100.0;
}
expect(tester.getBottomLeft(find.text('Item $i')), Offset(dx, dy));
dx += i.isEven ? 100 : 180;
}
});
testWidgets('DynamicGridView.wrap dismiss keyboard onDrag test',
(WidgetTester tester) async {
final List<FocusNode> focusNodes =
List<FocusNode>.generate(50, (int i) => FocusNode());
await tester.pumpWidget(
textFieldBoilerplate(
child: GridView.extent(
padding: EdgeInsets.zero,
maxCrossAxisExtent: 300,
keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag,
children: focusNodes.map((FocusNode focusNode) {
return Container(
height: 50,
color: Colors.green,
child: TextField(
focusNode: focusNode,
style: const TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
),
),
);
}).toList(),
),
),
);
final Finder finder = find.byType(TextField).first;
final TextField textField = tester.widget(finder);
await tester.showKeyboard(finder);
expect(textField.focusNode!.hasFocus, isTrue);
await tester.drag(finder, const Offset(0.0, -40.0));
await tester.pumpAndSettle();
expect(textField.focusNode!.hasFocus, isFalse);
});
testWidgets('ChildMainAxisExtent & childCrossAxisExtent are respected',
(WidgetTester tester) async {
final List<Widget> children = List<Widget>.generate(
10,
(int index) => SizedBox(
key: Key(index.toString()),
child: Text('Item $index'),
),
);
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
body: DynamicGridView.builder(
gridDelegate: const SliverGridDelegateWithWrapping(
childMainAxisExtent: 150,
childCrossAxisExtent: 200,
),
itemCount: children.length,
itemBuilder: (BuildContext context, int index) => children[index],
),
),
),
);
for (int i = 0; i < 10; i++) {
final Size sizeOfCurrent = tester.getSize(find.byKey(Key('$i')));
expect(sizeOfCurrent.width, equals(200));
expect(sizeOfCurrent.height, equals(150));
}
// Check that the children are in the right position
double dy = 0, dx = 0;
for (int i = 0; i < 10; i++) {
if (dx > 600.0) {
dx = 0.0;
dy += 150.0;
}
expect(tester.getTopLeft(find.text('Item $i')), Offset(dx, dy));
dx += 200;
}
});
testWidgets('ChildMainAxisExtent is respected', (WidgetTester tester) async {
final List<Widget> children = List<Widget>.generate(
10,
(int index) => SizedBox(
key: Key(index.toString()),
width: index.isEven ? 100 : 180,
child: Text('Item $index'),
),
);
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
body: DynamicGridView.builder(
gridDelegate: const SliverGridDelegateWithWrapping(
childMainAxisExtent: 200,
),
itemCount: children.length,
itemBuilder: (BuildContext context, int index) => children[index],
),
),
),
);
for (int i = 0; i < 10; i++) {
final Size sizeOfCurrent = tester.getSize(find.byKey(Key('$i')));
expect(sizeOfCurrent.height, equals(200));
}
// Check that the children are in the right position
double dy = 0, dx = 0;
for (int i = 0; i < 10; i++) {
if (dx >= 600.0) {
dx = 0.0;
dy += 200.0;
}
expect(tester.getTopLeft(find.text('Item $i')), Offset(dx, dy));
dx += i.isEven ? 100 : 180;
}
});
testWidgets('ChildCrossAxisExtent is respected', (WidgetTester tester) async {
final List<Widget> children = List<Widget>.generate(
10,
(int index) => SizedBox(
height: index.isEven ? 100 : 50,
key: Key(index.toString()),
child: Text('Item $index'),
),
);
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
body: DynamicGridView.builder(
gridDelegate: const SliverGridDelegateWithWrapping(
childCrossAxisExtent: 150,
),
itemCount: children.length,
itemBuilder: (BuildContext context, int index) => children[index],
),
),
),
);
for (int i = 0; i < 10; i++) {
final Size sizeOfCurrent = tester.getSize(find.byKey(Key('$i')));
expect(sizeOfCurrent.width, equals(150));
}
// Check that the children are in the right position
double dy = 0, dx = 0;
for (int i = 0; i < 10; i++) {
if (dx >= 750.0) {
dx = 0.0;
dy += 100.0;
}
expect(tester.getTopLeft(find.text('Item $i')), Offset(dx, dy));
dx += 150;
}
});
testWidgets('Test wrap to see nothing affected if elements are deleted.',
(WidgetTester tester) async {
late StateSetter stateSetter;
final List<Widget> children = List<Widget>.generate(
10,
(int index) => SizedBox(
height: index.isEven ? 100 : 50,
width: index.isEven ? 100 : 180,
child: Text('Item $index'),
),
);
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
body: StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
stateSetter = setState;
return DynamicGridView.builder(
gridDelegate: const SliverGridDelegateWithWrapping(),
itemCount: children.length,
itemBuilder: (BuildContext context, int index) => children[index],
);
}),
),
),
);
// See if the children are in the tree.
for (int i = 0; i < 10; i++) {
expect(find.text('Item $i'), findsOneWidget);
}
// See if they are layed properly.
double dx = 0.0, dy = 0.0;
for (int i = 0; i < 10; i++) {
if (dx >= 600) {
dx = 0.0;
dy += 100;
}
expect(tester.getTopLeft(find.text('Item $i')), Offset(dx, dy));
dx += i.isEven ? 100 : 180;
}
stateSetter(() {
// Remove children
children.removeAt(0);
children.removeAt(8);
children.removeAt(5);
});
await tester.pump();
// See if the proper widgets are in the tree.
expect(find.text('Item 0'), findsNothing);
expect(find.text('Item 6'), findsNothing);
expect(find.text('Item 9'), findsNothing);
expect(find.text('Item 1'), findsOneWidget);
expect(find.text('Item 2'), findsOneWidget);
expect(find.text('Item 3'), findsOneWidget);
expect(find.text('Item 4'), findsOneWidget);
expect(find.text('Item 5'), findsOneWidget);
expect(find.text('Item 7'), findsOneWidget);
expect(find.text('Item 8'), findsOneWidget);
// See if the proper widgets are in the tree.
expect(tester.getTopLeft(find.text('Item 1')), Offset.zero);
expect(tester.getTopLeft(find.text('Item 2')), const Offset(180.0, 0.0));
expect(tester.getTopLeft(find.text('Item 3')), const Offset(280.0, 0.0));
expect(tester.getTopLeft(find.text('Item 4')), const Offset(460.0, 0.0));
expect(tester.getTopLeft(find.text('Item 5')), const Offset(560.0, 0.0));
expect(tester.getTopLeft(find.text('Item 7')), const Offset(0.0, 100.0));
expect(tester.getTopLeft(find.text('Item 8')), const Offset(180.0, 100.0));
});
testWidgets('Test wrap in Axis.vertical direction',
(WidgetTester tester) async {
final List<Widget> children = List<Widget>.generate(
5,
(int index) => SizedBox(
height: index.isEven ? 100 : 50,
width: index.isEven ? 100 : 180,
child: Text('Item $index'),
),
);
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
body: DynamicGridView.builder(
itemCount: children.length,
gridDelegate: const SliverGridDelegateWithWrapping(),
itemBuilder: (BuildContext context, int index) => children[index],
),
),
),
);
// Change the size of the screen
await tester.binding.setSurfaceSize(const Size(500, 100));
await tester.pumpAndSettle();
expect(find.text('Item 0'), findsOneWidget);
expect(find.text('Item 1'), findsOneWidget);
expect(find.text('Item 2'), findsOneWidget);
expect(tester.getTopLeft(find.text('Item 0')), Offset.zero);
expect(tester.getTopLeft(find.text('Item 1')), const Offset(100.0, 0.0));
expect(tester.getTopLeft(find.text('Item 2')), const Offset(280.0, 0.0));
expect(find.text('Item 3'), findsNothing);
expect(find.text('Item 4'), findsNothing);
await tester.binding.setSurfaceSize(const Size(560, 100));
await tester.pumpAndSettle();
expect(find.text('Item 3'), findsOneWidget);
expect(tester.getTopLeft(find.text('Item 3')), const Offset(380.0, 0.0));
expect(find.text('Item 4'), findsNothing);
await tester.binding.setSurfaceSize(const Size(280, 100));
// resets the screen to its original size after the test end
// TODO(pdblasi-google): Update `window` usages to new API after 3.9.0 is in stable. https://github.com/flutter/flutter/issues/122912
// ignore: deprecated_member_use
addTearDown(tester.binding.window.clearPhysicalSizeTestValue);
await tester.pumpAndSettle();
expect(find.text('Item 0'), findsOneWidget);
expect(find.text('Item 1'), findsOneWidget);
expect(tester.getTopLeft(find.text('Item 0')), Offset.zero);
expect(tester.getTopLeft(find.text('Item 1')), const Offset(100.0, 0.0));
expect(find.text('Item 2'), findsNothing);
expect(find.text('Item 3'), findsNothing);
expect(find.text('Item 4'), findsNothing);
});
testWidgets('Test wrap in Axis.horizontal direction',
(WidgetTester tester) async {
final List<Widget> children = List<Widget>.generate(
5,
(int index) => SizedBox(
height: index.isEven ? 100 : 50,
width: index.isEven ? 100 : 180,
child: Text('Item $index'),
),
);
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
body: DynamicGridView.wrap(
scrollDirection: Axis.horizontal,
children: children,
),
),
),
);
// Change the size of the screen
await tester.binding.setSurfaceSize(const Size(180, 150));
await tester.pumpAndSettle();
expect(find.text('Item 0'), findsOneWidget);
expect(find.text('Item 1'), findsOneWidget);
expect(tester.getTopLeft(find.text('Item 0')), Offset.zero);
expect(tester.getTopLeft(find.text('Item 1')), const Offset(0.0, 100.0));
expect(find.text('Item 2'), findsNothing);
expect(find.text('Item 3'), findsNothing);
await tester.binding.setSurfaceSize(const Size(180, 400));
await tester.pumpAndSettle();
expect(find.text('Item 0'), findsOneWidget);
expect(find.text('Item 1'), findsOneWidget);
expect(find.text('Item 2'), findsOneWidget);
expect(find.text('Item 3'), findsOneWidget);
expect(find.text('Item 4'), findsOneWidget);
expect(tester.getTopLeft(find.text('Item 0')), Offset.zero);
expect(tester.getTopLeft(find.text('Item 1')), const Offset(0.0, 100.0));
expect(tester.getTopLeft(find.text('Item 2')), const Offset(0.0, 150.0));
expect(tester.getTopLeft(find.text('Item 3')), const Offset(0.0, 250.0));
expect(tester.getTopLeft(find.text('Item 4')), const Offset(0.0, 300.0));
await tester.binding.setSurfaceSize(const Size(560, 100));
// resets the screen to its original size after the test end
// TODO(pdblasi-google): Update `window` usages to new API after 3.9.0 is in stable. https://github.com/flutter/flutter/issues/122912
// ignore: deprecated_member_use
addTearDown(tester.binding.window.clearPhysicalSizeTestValue);
await tester.pumpAndSettle();
expect(find.text('Item 0'), findsOneWidget);
expect(find.text('Item 1'), findsOneWidget);
expect(find.text('Item 2'), findsOneWidget);
expect(find.text('Item 3'), findsOneWidget);
expect(find.text('Item 4'), findsNothing);
expect(tester.getTopLeft(find.text('Item 0')), Offset.zero);
expect(tester.getTopLeft(find.text('Item 1')), const Offset(100.0, 0.0));
expect(tester.getTopLeft(find.text('Item 2')), const Offset(280.0, 0.0));
expect(tester.getTopLeft(find.text('Item 3')), const Offset(380.0, 0.0));
});
}
Widget textFieldBoilerplate({required Widget child}) {
return MaterialApp(
home: Localizations(
locale: const Locale('en', 'US'),
delegates: <LocalizationsDelegate<dynamic>>[
WidgetsLocalizationsDelegate(),
MaterialLocalizationsDelegate(),
],
child: Directionality(
textDirection: TextDirection.ltr,
child: MediaQuery(
data: const MediaQueryData(size: Size(800.0, 600.0)),
child: Center(
child: Material(
child: child,
),
),
),
),
),
);
}
class MaterialLocalizationsDelegate
extends LocalizationsDelegate<MaterialLocalizations> {
@override
bool isSupported(Locale locale) => true;
@override
Future<MaterialLocalizations> load(Locale locale) =>
DefaultMaterialLocalizations.load(locale);
@override
bool shouldReload(MaterialLocalizationsDelegate old) => false;
}
class WidgetsLocalizationsDelegate
extends LocalizationsDelegate<WidgetsLocalizations> {
@override
bool isSupported(Locale locale) => true;
@override
Future<WidgetsLocalizations> load(Locale locale) =>
DefaultWidgetsLocalizations.load(locale);
@override
bool shouldReload(WidgetsLocalizationsDelegate old) => false;
}