blob: 9da89311ceb4ba2b4e9b603852133ad622755803 [file] [log] [blame]
// Copyright 2014 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:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/src/gestures/monodrag.dart';
import 'package:flutter_test/flutter_test.dart';
import 'two_dimensional_utils.dart';
Widget? _testChildBuilder(BuildContext context, ChildVicinity vicinity) {
return SizedBox(
height: 200,
width: 200,
child: Center(child: Text('C${vicinity.xIndex}:R${vicinity.yIndex}')),
);
}
void main() {
group('TwoDimensionalScrollView',() {
testWidgets('asserts the axis directions do not conflict with one another', (WidgetTester tester) async {
final List<Object> exceptions = <Object>[];
final FlutterExceptionHandler? oldHandler = FlutterError.onError;
FlutterError.onError = (FlutterErrorDetails details) {
exceptions.add(details.exception);
};
// Horizontal wrong
await tester.pumpWidget(MaterialApp(
home: SimpleBuilderTableView(
delegate: TwoDimensionalChildBuilderDelegate(builder: (_, __) => null),
horizontalDetails: const ScrollableDetails.vertical(),
// Horizontal has default const ScrollableDetails.horizontal()
),
));
// Vertical wrong
await tester.pumpWidget(MaterialApp(
home: SimpleBuilderTableView(
delegate: TwoDimensionalChildBuilderDelegate(builder: (_, __) => null),
verticalDetails: const ScrollableDetails.horizontal(),
// Horizontal has default const ScrollableDetails.horizontal()
),
));
// Both wrong
await tester.pumpWidget(MaterialApp(
home: SimpleBuilderTableView(
delegate: TwoDimensionalChildBuilderDelegate(builder: (_, __) => null),
verticalDetails: const ScrollableDetails.horizontal(),
horizontalDetails: const ScrollableDetails.vertical(),
),
));
FlutterError.onError = oldHandler;
expect(exceptions.length, 3);
for (final Object exception in exceptions) {
expect(exception, isAssertionError);
expect((exception as AssertionError).message, contains('are not Axis'));
}
}, variant: TargetPlatformVariant.all());
testWidgets('ScrollableDetails.controller can set initial scroll positions, modify within bounds', (WidgetTester tester) async {
final ScrollController verticalController = ScrollController(initialScrollOffset: 100);
final ScrollController horizontalController = ScrollController(initialScrollOffset: 50);
await tester.pumpWidget(MaterialApp(
home: SimpleBuilderTableView(
verticalDetails: ScrollableDetails.vertical(controller: verticalController),
horizontalDetails: ScrollableDetails.horizontal(controller: horizontalController),
delegate: TwoDimensionalChildBuilderDelegate(
builder: _testChildBuilder,
maxXIndex: 99,
maxYIndex: 99,
),
),
));
await tester.pumpAndSettle();
expect(verticalController.position.pixels, 100);
expect(verticalController.position.maxScrollExtent, 19400);
expect(horizontalController.position.pixels, 50);
expect(horizontalController.position.maxScrollExtent, 19200);
verticalController.jumpTo(verticalController.position.maxScrollExtent);
horizontalController.jumpTo(horizontalController.position.maxScrollExtent);
await tester.pump();
expect(verticalController.position.pixels, 19400);
expect(horizontalController.position.pixels, 19200);
// Out of bounds
verticalController.jumpTo(verticalController.position.maxScrollExtent + 100);
horizontalController.jumpTo(horizontalController.position.maxScrollExtent + 100);
// Account for varying scroll physics for different platforms (overscroll)
await tester.pumpAndSettle();
expect(verticalController.position.pixels, 19400);
expect(horizontalController.position.pixels, 19200);
}, variant: TargetPlatformVariant.all());
testWidgets('Properly assigns the PrimaryScrollController to the main axis on the correct platform', (WidgetTester tester) async {
late ScrollController controller;
Widget buildForPrimaryScrollController({
bool? explicitPrimary,
Axis mainAxis = Axis.vertical,
bool addControllerConflict = false,
}) {
return MaterialApp(
home: PrimaryScrollController(
controller: controller,
child: SimpleBuilderTableView(
mainAxis: mainAxis,
primary: explicitPrimary,
verticalDetails: ScrollableDetails.vertical(
controller: addControllerConflict && mainAxis == Axis.vertical
? ScrollController()
: null
),
horizontalDetails: ScrollableDetails.horizontal(
controller: addControllerConflict && mainAxis == Axis.horizontal
? ScrollController()
: null
),
delegate: TwoDimensionalChildBuilderDelegate(
builder: _testChildBuilder,
maxXIndex: 99,
maxYIndex: 99,
),
),
),
);
}
// Horizontal default - horizontal never automatically adopts PSC
controller = ScrollController();
await tester.pumpWidget(buildForPrimaryScrollController(
mainAxis: Axis.horizontal,
));
await tester.pumpAndSettle();
switch (defaultTargetPlatform) {
case TargetPlatform.android:
case TargetPlatform.fuchsia:
case TargetPlatform.iOS:
case TargetPlatform.linux:
case TargetPlatform.macOS:
case TargetPlatform.windows:
expect(controller.hasClients, isFalse);
}
// Horizontal explicitly true
controller = ScrollController();
await tester.pumpWidget(buildForPrimaryScrollController(
mainAxis: Axis.horizontal,
explicitPrimary: true,
));
await tester.pumpAndSettle();
switch (defaultTargetPlatform) {
// Primary explicitly true is always adopted.
case TargetPlatform.android:
case TargetPlatform.fuchsia:
case TargetPlatform.iOS:
case TargetPlatform.linux:
case TargetPlatform.macOS:
case TargetPlatform.windows:
expect(controller.hasClients, isTrue);
expect(controller.position.axis, Axis.horizontal);
}
// Horizontal explicitly false
controller = ScrollController();
await tester.pumpWidget(buildForPrimaryScrollController(
mainAxis: Axis.horizontal,
explicitPrimary: false,
));
await tester.pumpAndSettle();
switch (defaultTargetPlatform) {
// Primary explicitly false is never adopted.
case TargetPlatform.android:
case TargetPlatform.fuchsia:
case TargetPlatform.iOS:
case TargetPlatform.linux:
case TargetPlatform.macOS:
case TargetPlatform.windows:
expect(controller.hasClients, isFalse);
}
// Vertical default
controller = ScrollController();
await tester.pumpWidget(buildForPrimaryScrollController());
await tester.pumpAndSettle();
switch (defaultTargetPlatform) {
// Mobile platforms inherit the PSC without explicitly setting
// primary
case TargetPlatform.android:
case TargetPlatform.fuchsia:
case TargetPlatform.iOS:
expect(controller.hasClients, isTrue);
expect(controller.position.axis, Axis.vertical);
case TargetPlatform.linux:
case TargetPlatform.macOS:
case TargetPlatform.windows:
expect(controller.hasClients, isFalse);
}
// Vertical explicitly true
controller = ScrollController();
await tester.pumpWidget(buildForPrimaryScrollController(
explicitPrimary: true,
));
await tester.pumpAndSettle();
switch (defaultTargetPlatform) {
// Primary explicitly true is always adopted.
case TargetPlatform.android:
case TargetPlatform.fuchsia:
case TargetPlatform.iOS:
case TargetPlatform.linux:
case TargetPlatform.macOS:
case TargetPlatform.windows:
expect(controller.hasClients, isTrue);
expect(controller.position.axis, Axis.vertical);
}
// Vertical explicitly false
controller = ScrollController();
await tester.pumpWidget(buildForPrimaryScrollController(
explicitPrimary: false,
));
await tester.pumpAndSettle();
switch (defaultTargetPlatform) {
// Primary explicitly false is never adopted.
case TargetPlatform.android:
case TargetPlatform.fuchsia:
case TargetPlatform.iOS:
case TargetPlatform.linux:
case TargetPlatform.macOS:
case TargetPlatform.windows:
expect(controller.hasClients, isFalse);
}
// Assertions
final List<Object> exceptions = <Object>[];
final FlutterExceptionHandler? oldHandler = FlutterError.onError;
FlutterError.onError = (FlutterErrorDetails details) {
exceptions.add(details.exception);
};
// Vertical asserts ScrollableDetails.controller has not been provided if
// primary is explicitly set
controller = ScrollController();
await tester.pumpWidget(buildForPrimaryScrollController(
explicitPrimary: true,
addControllerConflict: true,
));
expect(exceptions.length, 1);
expect(exceptions[0], isAssertionError);
expect(
(exceptions[0] as AssertionError).message,
contains('TwoDimensionalScrollView.primary was explicitly set to true'),
);
exceptions.clear();
// Horizontal asserts ScrollableDetails.controller has not been provided
// if primary is explicitly set true
controller = ScrollController();
await tester.pumpWidget(buildForPrimaryScrollController(
mainAxis: Axis.horizontal,
explicitPrimary: true,
addControllerConflict: true,
));
expect(exceptions.length, 1);
expect(exceptions[0], isAssertionError);
expect(
(exceptions[0] as AssertionError).message,
contains('TwoDimensionalScrollView.primary was explicitly set to true'),
);
FlutterError.onError = oldHandler;
}, variant: TargetPlatformVariant.all());
testWidgets('TwoDimensionalScrollable receives the correct details from TwoDimensionalScrollView', (WidgetTester tester) async {
late BuildContext capturedContext;
// Default
await tester.pumpWidget(MaterialApp(
home: SimpleBuilderTableView(
delegate: TwoDimensionalChildBuilderDelegate(
builder: (BuildContext context, ChildVicinity vicinity) {
capturedContext = context;
return Text(vicinity.toString());
},
),
),
));
await tester.pumpAndSettle();
TwoDimensionalScrollableState scrollable = TwoDimensionalScrollable.of(
capturedContext,
);
expect(scrollable.widget.verticalDetails.direction, AxisDirection.down);
expect(scrollable.widget.horizontalDetails.direction, AxisDirection.right);
expect(scrollable.widget.diagonalDragBehavior, DiagonalDragBehavior.none);
expect(scrollable.widget.dragStartBehavior, DragStartBehavior.start);
// Customized
await tester.pumpWidget(MaterialApp(
home: SimpleBuilderTableView(
verticalDetails: const ScrollableDetails.vertical(reverse: true),
horizontalDetails: const ScrollableDetails.horizontal(reverse: true),
diagonalDragBehavior: DiagonalDragBehavior.weightedContinuous,
dragStartBehavior: DragStartBehavior.down,
delegate: TwoDimensionalChildBuilderDelegate(
builder: _testChildBuilder,
),
),
));
await tester.pumpAndSettle();
scrollable = TwoDimensionalScrollable.of(capturedContext);
expect(scrollable.widget.verticalDetails.direction, AxisDirection.up);
expect(scrollable.widget.horizontalDetails.direction, AxisDirection.left);
expect(scrollable.widget.diagonalDragBehavior, DiagonalDragBehavior.weightedContinuous);
expect(scrollable.widget.dragStartBehavior, DragStartBehavior.down);
}, variant: TargetPlatformVariant.all());
});
}