mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
2075 lines
70 KiB
Dart
2075 lines
70 KiB
Dart
// 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 'dart:ui';
|
|
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter/rendering.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:vector_math/vector_math_64.dart' show Vector3;
|
|
|
|
import '../rendering/mock_canvas.dart';
|
|
import '../widgets/semantics_tester.dart';
|
|
import 'feedback_tester.dart';
|
|
|
|
void main() {
|
|
testWidgets('BottomNavigationBar callback test', (WidgetTester tester) async {
|
|
late int mutatedIndex;
|
|
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: Scaffold(
|
|
bottomNavigationBar: BottomNavigationBar(
|
|
items: const <BottomNavigationBarItem>[
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.ac_unit),
|
|
title: Text('AC'),
|
|
),
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.access_alarm),
|
|
title: Text('Alarm'),
|
|
),
|
|
],
|
|
onTap: (int index) {
|
|
mutatedIndex = index;
|
|
},
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
await tester.tap(find.text('Alarm'));
|
|
|
|
expect(mutatedIndex, 1);
|
|
});
|
|
|
|
testWidgets('BottomNavigationBar content test', (WidgetTester tester) async {
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: Scaffold(
|
|
bottomNavigationBar: BottomNavigationBar(
|
|
items: const <BottomNavigationBarItem>[
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.ac_unit),
|
|
label: 'AC',
|
|
),
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.access_alarm),
|
|
label: 'Alarm',
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
final RenderBox box = tester.renderObject(find.byType(BottomNavigationBar));
|
|
expect(box.size.height, kBottomNavigationBarHeight);
|
|
expect(find.text('AC'), findsOneWidget);
|
|
expect(find.text('Alarm'), findsOneWidget);
|
|
});
|
|
|
|
testWidgets('Fixed BottomNavigationBar defaults', (WidgetTester tester) async {
|
|
const Color primaryColor = Color(0xFF000001);
|
|
const Color unselectedWidgetColor = Color(0xFF000002);
|
|
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
theme: ThemeData.light().copyWith(
|
|
colorScheme: const ColorScheme.light().copyWith(primary: primaryColor),
|
|
unselectedWidgetColor: unselectedWidgetColor,
|
|
),
|
|
home: Scaffold(
|
|
bottomNavigationBar: BottomNavigationBar(
|
|
type: BottomNavigationBarType.fixed,
|
|
items: const <BottomNavigationBarItem>[
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.ac_unit),
|
|
label: 'AC',
|
|
),
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.access_alarm),
|
|
label: 'Alarm',
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
const double selectedFontSize = 14.0;
|
|
const double unselectedFontSize = 12.0;
|
|
final TextStyle selectedFontStyle = tester.renderObject<RenderParagraph>(find.text('AC')).text.style!;
|
|
final TextStyle unselectedFontStyle = tester.renderObject<RenderParagraph>(find.text('Alarm')).text.style!;
|
|
final TextStyle selectedIcon = _iconStyle(tester, Icons.ac_unit);
|
|
final TextStyle unselectedIcon = _iconStyle(tester, Icons.access_alarm);
|
|
expect(selectedFontStyle.color, equals(primaryColor));
|
|
expect(selectedFontStyle.fontSize, selectedFontSize);
|
|
expect(selectedFontStyle.fontWeight, equals(FontWeight.w400));
|
|
expect(selectedFontStyle.height, isNull);
|
|
expect(unselectedFontStyle.color, equals(unselectedWidgetColor));
|
|
expect(unselectedFontStyle.fontWeight, equals(FontWeight.w400));
|
|
expect(unselectedFontStyle.height, isNull);
|
|
// Unselected label has a font size of 14 but is scaled down to be font size 12.
|
|
expect(
|
|
tester.firstWidget<Transform>(find.ancestor(of: find.text('Alarm'), matching: find.byType(Transform))).transform,
|
|
equals(Matrix4.diagonal3(Vector3.all(unselectedFontSize / selectedFontSize))),
|
|
);
|
|
expect(selectedIcon.color, equals(primaryColor));
|
|
expect(selectedIcon.fontSize, equals(24.0));
|
|
expect(unselectedIcon.color, equals(unselectedWidgetColor));
|
|
expect(unselectedIcon.fontSize, equals(24.0));
|
|
// There should not be any [Opacity] or [FadeTransition] widgets
|
|
// since showUnselectedLabels and showSelectedLabels are true.
|
|
final Finder findOpacity = find.descendant(
|
|
of: find.byType(BottomNavigationBar),
|
|
matching: find.byType(Opacity),
|
|
);
|
|
final Finder findFadeTransition = find.descendant(
|
|
of: find.byType(BottomNavigationBar),
|
|
matching: find.byType(FadeTransition),
|
|
);
|
|
expect(findOpacity, findsNothing);
|
|
expect(findFadeTransition, findsNothing);
|
|
expect(_getMaterial(tester).elevation, equals(8.0));
|
|
});
|
|
|
|
testWidgets('Custom selected and unselected font styles', (WidgetTester tester) async {
|
|
const TextStyle selectedTextStyle = TextStyle(fontWeight: FontWeight.w200, fontSize: 18.0);
|
|
const TextStyle unselectedTextStyle = TextStyle(fontWeight: FontWeight.w600, fontSize: 12.0);
|
|
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: Scaffold(
|
|
bottomNavigationBar: BottomNavigationBar(
|
|
type: BottomNavigationBarType.fixed,
|
|
selectedLabelStyle: selectedTextStyle,
|
|
unselectedLabelStyle: unselectedTextStyle,
|
|
items: const <BottomNavigationBarItem>[
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.ac_unit),
|
|
label: 'AC',
|
|
),
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.access_alarm),
|
|
label: 'Alarm',
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
final TextStyle selectedFontStyle = tester.renderObject<RenderParagraph>(find.text('AC')).text.style!;
|
|
final TextStyle unselectedFontStyle = tester.renderObject<RenderParagraph>(find.text('Alarm')).text.style!;
|
|
expect(selectedFontStyle.fontSize, equals(selectedTextStyle.fontSize));
|
|
expect(selectedFontStyle.fontWeight, equals(selectedTextStyle.fontWeight));
|
|
expect(
|
|
tester.firstWidget<Transform>(find.ancestor(of: find.text('Alarm'), matching: find.byType(Transform))).transform,
|
|
equals(Matrix4.diagonal3(Vector3.all(unselectedTextStyle.fontSize! / selectedTextStyle.fontSize!))),
|
|
);
|
|
expect(unselectedFontStyle.fontWeight, equals(unselectedTextStyle.fontWeight));
|
|
});
|
|
|
|
testWidgets('font size on text styles overrides font size params', (WidgetTester tester) async {
|
|
const TextStyle selectedTextStyle = TextStyle(fontSize: 18.0);
|
|
const TextStyle unselectedTextStyle = TextStyle(fontSize: 12.0);
|
|
const double selectedFontSize = 17.0;
|
|
const double unselectedFontSize = 11.0;
|
|
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: Scaffold(
|
|
bottomNavigationBar: BottomNavigationBar(
|
|
type: BottomNavigationBarType.fixed,
|
|
selectedLabelStyle: selectedTextStyle,
|
|
unselectedLabelStyle: unselectedTextStyle,
|
|
selectedFontSize: selectedFontSize,
|
|
unselectedFontSize: unselectedFontSize,
|
|
items: const <BottomNavigationBarItem>[
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.ac_unit),
|
|
label: 'AC',
|
|
),
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.access_alarm),
|
|
label: 'Alarm',
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
final TextStyle selectedFontStyle = tester.renderObject<RenderParagraph>(find.text('AC')).text.style!;
|
|
expect(selectedFontStyle.fontSize, equals(selectedTextStyle.fontSize));
|
|
expect(
|
|
tester.firstWidget<Transform>(find.ancestor(of: find.text('Alarm'), matching: find.byType(Transform))).transform,
|
|
equals(Matrix4.diagonal3(Vector3.all(unselectedTextStyle.fontSize! / selectedTextStyle.fontSize!))),
|
|
);
|
|
});
|
|
|
|
testWidgets('Custom selected and unselected icon themes', (WidgetTester tester) async {
|
|
const IconThemeData selectedIconTheme = IconThemeData(size: 36, color: Color(0x00000001));
|
|
const IconThemeData unselectedIconTheme = IconThemeData(size: 18, color: Color(0x00000002));
|
|
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: Scaffold(
|
|
bottomNavigationBar: BottomNavigationBar(
|
|
type: BottomNavigationBarType.fixed,
|
|
selectedIconTheme: selectedIconTheme,
|
|
unselectedIconTheme: unselectedIconTheme,
|
|
items: const <BottomNavigationBarItem>[
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.ac_unit),
|
|
label: 'AC',
|
|
),
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.access_alarm),
|
|
label: 'Alarm',
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
final TextStyle selectedIcon = _iconStyle(tester, Icons.ac_unit);
|
|
final TextStyle unselectedIcon = _iconStyle(tester, Icons.access_alarm);
|
|
expect(selectedIcon.color, equals(selectedIconTheme.color));
|
|
expect(selectedIcon.fontSize, equals(selectedIconTheme.size));
|
|
expect(unselectedIcon.color, equals(unselectedIconTheme.color));
|
|
expect(unselectedIcon.fontSize, equals(unselectedIconTheme.size));
|
|
});
|
|
|
|
testWidgets('color on icon theme overrides selected and unselected item colors', (WidgetTester tester) async {
|
|
const IconThemeData selectedIconTheme = IconThemeData(size: 36, color: Color(0x00000001));
|
|
const IconThemeData unselectedIconTheme = IconThemeData(size: 18, color: Color(0x00000002));
|
|
const Color selectedItemColor = Color(0x00000003);
|
|
const Color unselectedItemColor = Color(0x00000004);
|
|
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: Scaffold(
|
|
bottomNavigationBar: BottomNavigationBar(
|
|
type: BottomNavigationBarType.fixed,
|
|
selectedIconTheme: selectedIconTheme,
|
|
unselectedIconTheme: unselectedIconTheme,
|
|
selectedItemColor: selectedItemColor,
|
|
unselectedItemColor: unselectedItemColor,
|
|
items: const <BottomNavigationBarItem>[
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.ac_unit),
|
|
label: 'AC',
|
|
),
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.access_alarm),
|
|
label: 'Alarm',
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
final TextStyle selectedFontStyle = tester.renderObject<RenderParagraph>(find.text('AC')).text.style!;
|
|
final TextStyle unselectedFontStyle = tester.renderObject<RenderParagraph>(find.text('Alarm')).text.style!;
|
|
final TextStyle selectedIcon = _iconStyle(tester, Icons.ac_unit);
|
|
final TextStyle unselectedIcon = _iconStyle(tester, Icons.access_alarm);
|
|
expect(selectedIcon.color, equals(selectedIconTheme.color));
|
|
expect(unselectedIcon.color, equals(unselectedIconTheme.color));
|
|
expect(selectedFontStyle.color, equals(selectedItemColor));
|
|
expect(unselectedFontStyle.color, equals(unselectedItemColor));
|
|
});
|
|
|
|
testWidgets('Padding is calculated properly on items - all labels', (WidgetTester tester) async {
|
|
const double selectedFontSize = 16.0;
|
|
const double unselectedFontSize = 12.0;
|
|
const double selectedIconSize = 36.0;
|
|
const double unselectedIconSize = 20.0;
|
|
const IconThemeData selectedIconTheme = IconThemeData(size: selectedIconSize);
|
|
const IconThemeData unselectedIconTheme = IconThemeData(size: unselectedIconSize);
|
|
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: Scaffold(
|
|
bottomNavigationBar: BottomNavigationBar(
|
|
type: BottomNavigationBarType.fixed,
|
|
showSelectedLabels: true,
|
|
showUnselectedLabels: true,
|
|
selectedFontSize: selectedFontSize,
|
|
unselectedFontSize: unselectedFontSize,
|
|
selectedIconTheme: selectedIconTheme,
|
|
unselectedIconTheme: unselectedIconTheme,
|
|
items: const <BottomNavigationBarItem>[
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.ac_unit),
|
|
label: 'AC',
|
|
),
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.access_alarm),
|
|
label: 'Alarm',
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
final EdgeInsets selectedItemPadding = _itemPadding(tester, Icons.ac_unit);
|
|
expect(selectedItemPadding.top, equals(selectedFontSize / 2.0));
|
|
expect(selectedItemPadding.bottom, equals(selectedFontSize / 2.0));
|
|
final EdgeInsets unselectedItemPadding = _itemPadding(tester, Icons.access_alarm);
|
|
const double expectedUnselectedPadding = (selectedIconSize - unselectedIconSize) / 2.0 + selectedFontSize / 2.0;
|
|
expect(unselectedItemPadding.top, equals(expectedUnselectedPadding));
|
|
expect(unselectedItemPadding.bottom, equals(expectedUnselectedPadding));
|
|
});
|
|
|
|
testWidgets('Padding is calculated properly on items - selected labels only', (WidgetTester tester) async {
|
|
const double selectedFontSize = 16.0;
|
|
const double unselectedFontSize = 12.0;
|
|
const double selectedIconSize = 36.0;
|
|
const double unselectedIconSize = 20.0;
|
|
const IconThemeData selectedIconTheme = IconThemeData(size: selectedIconSize);
|
|
const IconThemeData unselectedIconTheme = IconThemeData(size: unselectedIconSize);
|
|
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: Scaffold(
|
|
bottomNavigationBar: BottomNavigationBar(
|
|
type: BottomNavigationBarType.fixed,
|
|
showSelectedLabels: true,
|
|
showUnselectedLabels: false,
|
|
selectedFontSize: selectedFontSize,
|
|
unselectedFontSize: unselectedFontSize,
|
|
selectedIconTheme: selectedIconTheme,
|
|
unselectedIconTheme: unselectedIconTheme,
|
|
items: const <BottomNavigationBarItem>[
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.ac_unit),
|
|
label: 'AC',
|
|
),
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.access_alarm),
|
|
label: 'Alarm',
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
final EdgeInsets selectedItemPadding = _itemPadding(tester, Icons.ac_unit);
|
|
expect(selectedItemPadding.top, equals(selectedFontSize / 2.0));
|
|
expect(selectedItemPadding.bottom, equals(selectedFontSize / 2.0));
|
|
final EdgeInsets unselectedItemPadding = _itemPadding(tester, Icons.access_alarm);
|
|
expect(unselectedItemPadding.top, equals((selectedIconSize - unselectedIconSize) / 2.0 + selectedFontSize));
|
|
expect(unselectedItemPadding.bottom, equals((selectedIconSize - unselectedIconSize) / 2.0));
|
|
});
|
|
|
|
testWidgets('Padding is calculated properly on items - no labels', (WidgetTester tester) async {
|
|
const double selectedFontSize = 16.0;
|
|
const double unselectedFontSize = 12.0;
|
|
const double selectedIconSize = 36.0;
|
|
const double unselectedIconSize = 20.0;
|
|
const IconThemeData selectedIconTheme = IconThemeData(size: selectedIconSize);
|
|
const IconThemeData unselectedIconTheme = IconThemeData(size: unselectedIconSize);
|
|
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: Scaffold(
|
|
bottomNavigationBar: BottomNavigationBar(
|
|
type: BottomNavigationBarType.fixed,
|
|
showSelectedLabels: false,
|
|
showUnselectedLabels: false,
|
|
selectedFontSize: selectedFontSize,
|
|
unselectedFontSize: unselectedFontSize,
|
|
selectedIconTheme: selectedIconTheme,
|
|
unselectedIconTheme: unselectedIconTheme,
|
|
items: const <BottomNavigationBarItem>[
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.ac_unit),
|
|
label: 'AC',
|
|
),
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.access_alarm),
|
|
label: 'Alarm',
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
final EdgeInsets selectedItemPadding = _itemPadding(tester, Icons.ac_unit);
|
|
expect(selectedItemPadding.top, equals(selectedFontSize));
|
|
expect(selectedItemPadding.bottom, equals(0.0));
|
|
final EdgeInsets unselectedItemPadding = _itemPadding(tester, Icons.access_alarm);
|
|
expect(unselectedItemPadding.top, equals((selectedIconSize - unselectedIconSize) / 2.0 + selectedFontSize));
|
|
expect(unselectedItemPadding.bottom, equals((selectedIconSize - unselectedIconSize) / 2.0));
|
|
});
|
|
|
|
testWidgets('Shifting BottomNavigationBar defaults', (WidgetTester tester) async {
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: Scaffold(
|
|
bottomNavigationBar: BottomNavigationBar(
|
|
type: BottomNavigationBarType.shifting,
|
|
items: const <BottomNavigationBarItem>[
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.ac_unit),
|
|
label: 'AC',
|
|
),
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.access_alarm),
|
|
label: 'Alarm',
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
const double selectedFontSize = 14.0;
|
|
expect(tester.renderObject<RenderParagraph>(find.text('AC')).text.style!.fontSize, selectedFontSize);
|
|
expect(tester.renderObject<RenderParagraph>(find.text('AC')).text.style!.color, equals(Colors.white));
|
|
expect(_getOpacity(tester, 'Alarm'), equals(0.0));
|
|
expect(_getMaterial(tester).elevation, equals(8.0));
|
|
});
|
|
|
|
testWidgets('Fixed BottomNavigationBar custom font size, color', (WidgetTester tester) async {
|
|
const Color primaryColor = Colors.black;
|
|
const Color unselectedWidgetColor = Colors.purple;
|
|
const Color selectedColor = Colors.blue;
|
|
const Color unselectedColor = Colors.yellow;
|
|
const double selectedFontSize = 18.0;
|
|
const double unselectedFontSize = 14.0;
|
|
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
theme: ThemeData(
|
|
primaryColor: primaryColor,
|
|
unselectedWidgetColor: unselectedWidgetColor,
|
|
),
|
|
home: Scaffold(
|
|
bottomNavigationBar: BottomNavigationBar(
|
|
type: BottomNavigationBarType.fixed,
|
|
selectedFontSize: selectedFontSize,
|
|
unselectedFontSize: unselectedFontSize,
|
|
selectedItemColor: selectedColor,
|
|
unselectedItemColor: unselectedColor,
|
|
items: const <BottomNavigationBarItem>[
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.ac_unit),
|
|
label: 'AC',
|
|
),
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.access_alarm),
|
|
label: 'Alarm',
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
expect(tester.renderObject<RenderParagraph>(find.text('AC')).text.style!.fontSize, selectedFontSize);
|
|
// Unselected label has a font size of 18 but is scaled down to be font size 14.
|
|
expect(tester.renderObject<RenderParagraph>(find.text('Alarm')).text.style!.fontSize, selectedFontSize);
|
|
expect(
|
|
tester.firstWidget<Transform>(find.ancestor(of: find.text('Alarm'), matching: find.byType(Transform))).transform,
|
|
equals(Matrix4.diagonal3(Vector3.all(unselectedFontSize / selectedFontSize))),
|
|
);
|
|
expect(tester.renderObject<RenderParagraph>(find.text('AC')).text.style!.color, equals(selectedColor));
|
|
expect(tester.renderObject<RenderParagraph>(find.text('Alarm')).text.style!.color, equals(unselectedColor));
|
|
// There should not be any [Opacity] or [FadeTransition] widgets
|
|
// since showUnselectedLabels and showSelectedLabels are true.
|
|
final Finder findOpacity = find.descendant(
|
|
of: find.byType(BottomNavigationBar),
|
|
matching: find.byType(Opacity),
|
|
);
|
|
final Finder findFadeTransition = find.descendant(
|
|
of: find.byType(BottomNavigationBar),
|
|
matching: find.byType(FadeTransition),
|
|
);
|
|
expect(findOpacity, findsNothing);
|
|
expect(findFadeTransition, findsNothing);
|
|
});
|
|
|
|
|
|
testWidgets('Shifting BottomNavigationBar custom font size, color', (WidgetTester tester) async {
|
|
const Color primaryColor = Colors.black;
|
|
const Color unselectedWidgetColor = Colors.purple;
|
|
const Color selectedColor = Colors.blue;
|
|
const Color unselectedColor = Colors.yellow;
|
|
const double selectedFontSize = 18.0;
|
|
const double unselectedFontSize = 14.0;
|
|
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
theme: ThemeData(
|
|
primaryColor: primaryColor,
|
|
unselectedWidgetColor: unselectedWidgetColor,
|
|
),
|
|
home: Scaffold(
|
|
bottomNavigationBar: BottomNavigationBar(
|
|
type: BottomNavigationBarType.shifting,
|
|
selectedFontSize: selectedFontSize,
|
|
unselectedFontSize: unselectedFontSize,
|
|
selectedItemColor: selectedColor,
|
|
unselectedItemColor: unselectedColor,
|
|
items: const <BottomNavigationBarItem>[
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.ac_unit),
|
|
label: 'AC',
|
|
),
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.access_alarm),
|
|
label: 'Alarm',
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
expect(tester.renderObject<RenderParagraph>(find.text('AC')).text.style!.fontSize, selectedFontSize);
|
|
expect(tester.renderObject<RenderParagraph>(find.text('AC')).text.style!.color, equals(selectedColor));
|
|
expect(_getOpacity(tester, 'Alarm'), equals(0.0));
|
|
});
|
|
|
|
testWidgets('Fixed BottomNavigationBar can hide unselected labels', (WidgetTester tester) async {
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: Scaffold(
|
|
bottomNavigationBar: BottomNavigationBar(
|
|
type: BottomNavigationBarType.fixed,
|
|
showUnselectedLabels: false,
|
|
items: const <BottomNavigationBarItem>[
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.ac_unit),
|
|
label: 'AC',
|
|
),
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.access_alarm),
|
|
label: 'Alarm',
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
expect(_getOpacity(tester, 'AC'), equals(1.0));
|
|
expect(_getOpacity(tester, 'Alarm'), equals(0.0));
|
|
});
|
|
|
|
testWidgets('Fixed BottomNavigationBar can update background color', (WidgetTester tester) async {
|
|
const Color color = Colors.yellow;
|
|
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: Scaffold(
|
|
bottomNavigationBar: BottomNavigationBar(
|
|
type: BottomNavigationBarType.fixed,
|
|
backgroundColor: color,
|
|
items: const <BottomNavigationBarItem>[
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.ac_unit),
|
|
label: 'AC',
|
|
),
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.access_alarm),
|
|
label: 'Alarm',
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
expect(_getMaterial(tester).color, equals(color));
|
|
});
|
|
|
|
testWidgets('Shifting BottomNavigationBar background color is overridden by item color', (WidgetTester tester) async {
|
|
const Color itemColor = Colors.yellow;
|
|
const Color backgroundColor = Colors.blue;
|
|
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: Scaffold(
|
|
bottomNavigationBar: BottomNavigationBar(
|
|
type: BottomNavigationBarType.shifting,
|
|
backgroundColor: backgroundColor,
|
|
items: const <BottomNavigationBarItem>[
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.ac_unit),
|
|
label: 'AC',
|
|
backgroundColor: itemColor,
|
|
),
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.access_alarm),
|
|
label: 'Alarm',
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
expect(_getMaterial(tester).color, equals(itemColor));
|
|
});
|
|
|
|
testWidgets('Specifying both selectedItemColor and fixedColor asserts', (WidgetTester tester) async {
|
|
expect(
|
|
() {
|
|
return BottomNavigationBar(
|
|
selectedItemColor: Colors.black,
|
|
fixedColor: Colors.black,
|
|
items: const <BottomNavigationBarItem>[
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.ac_unit),
|
|
label: 'AC',
|
|
),
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.access_alarm),
|
|
label: 'Alarm',
|
|
),
|
|
],
|
|
);
|
|
},
|
|
throwsAssertionError,
|
|
);
|
|
});
|
|
|
|
testWidgets('Fixed BottomNavigationBar uses fixedColor when selectedItemColor not provided', (WidgetTester tester) async {
|
|
const Color fixedColor = Colors.black;
|
|
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: Scaffold(
|
|
bottomNavigationBar: BottomNavigationBar(
|
|
type: BottomNavigationBarType.fixed,
|
|
fixedColor: fixedColor,
|
|
items: const <BottomNavigationBarItem>[
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.ac_unit),
|
|
label: 'AC',
|
|
),
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.access_alarm),
|
|
label: 'Alarm',
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
expect(tester.renderObject<RenderParagraph>(find.text('AC')).text.style!.color, equals(fixedColor));
|
|
});
|
|
|
|
testWidgets('setting selectedFontSize to zero hides all labels', (WidgetTester tester) async {
|
|
const double customElevation = 3.0;
|
|
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: Scaffold(
|
|
bottomNavigationBar: BottomNavigationBar(
|
|
type: BottomNavigationBarType.fixed,
|
|
elevation: customElevation,
|
|
items: const <BottomNavigationBarItem>[
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.ac_unit),
|
|
label: 'AC',
|
|
),
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.access_alarm),
|
|
label: 'Alarm',
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
expect(_getMaterial(tester).elevation, equals(customElevation));
|
|
});
|
|
|
|
testWidgets('BottomNavigationBar adds bottom padding to height', (WidgetTester tester) async {
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: MediaQuery(
|
|
data: const MediaQueryData(padding: EdgeInsets.only(bottom: 40.0)),
|
|
child: Scaffold(
|
|
bottomNavigationBar: BottomNavigationBar(
|
|
items: const <BottomNavigationBarItem>[
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.ac_unit),
|
|
label: 'AC',
|
|
),
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.access_alarm),
|
|
label: 'Alarm',
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
const double expectedHeight = kBottomNavigationBarHeight + 40.0;
|
|
expect(tester.getSize(find.byType(BottomNavigationBar)).height, expectedHeight);
|
|
});
|
|
|
|
testWidgets('BottomNavigationBar adds bottom padding to height with a custom font size', (WidgetTester tester) async {
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: MediaQuery(
|
|
data: const MediaQueryData(padding: EdgeInsets.only(bottom: 40.0)),
|
|
child: Scaffold(
|
|
bottomNavigationBar: BottomNavigationBar(
|
|
selectedFontSize: 8,
|
|
items: const <BottomNavigationBarItem>[
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.ac_unit),
|
|
label: 'AC',
|
|
),
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.access_alarm),
|
|
label: 'Alarm',
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
const double expectedHeight = kBottomNavigationBarHeight + 40.0;
|
|
expect(tester.getSize(find.byType(BottomNavigationBar)).height, expectedHeight);
|
|
});
|
|
|
|
testWidgets('BottomNavigationBar action size test', (WidgetTester tester) async {
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: Scaffold(
|
|
bottomNavigationBar: BottomNavigationBar(
|
|
type: BottomNavigationBarType.shifting,
|
|
items: const <BottomNavigationBarItem>[
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.ac_unit),
|
|
label: 'AC',
|
|
),
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.access_alarm),
|
|
label: 'Alarm',
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
Iterable<RenderBox> actions = tester.renderObjectList(find.byType(InkResponse));
|
|
expect(actions.length, 2);
|
|
expect(actions.elementAt(0).size.width, 480.0);
|
|
expect(actions.elementAt(1).size.width, 320.0);
|
|
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: Scaffold(
|
|
bottomNavigationBar: BottomNavigationBar(
|
|
currentIndex: 1,
|
|
type: BottomNavigationBarType.shifting,
|
|
items: const <BottomNavigationBarItem>[
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.ac_unit),
|
|
label: 'AC',
|
|
),
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.access_alarm),
|
|
label: 'Alarm',
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
await tester.pump(const Duration(milliseconds: 200));
|
|
|
|
actions = tester.renderObjectList(find.byType(InkResponse));
|
|
expect(actions.length, 2);
|
|
expect(actions.elementAt(0).size.width, 320.0);
|
|
expect(actions.elementAt(1).size.width, 480.0);
|
|
});
|
|
|
|
testWidgets('BottomNavigationBar multiple taps test', (WidgetTester tester) async {
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: Scaffold(
|
|
bottomNavigationBar: BottomNavigationBar(
|
|
type: BottomNavigationBarType.shifting,
|
|
items: const <BottomNavigationBarItem>[
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.ac_unit),
|
|
label: 'AC',
|
|
),
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.access_alarm),
|
|
label: 'Alarm',
|
|
),
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.access_time),
|
|
label: 'Time',
|
|
),
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.add),
|
|
label: 'Add',
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
// We want to make sure that the last label does not get displaced,
|
|
// irrespective of how many taps happen on the first N - 1 labels and how
|
|
// they grow.
|
|
|
|
Iterable<RenderBox> actions = tester.renderObjectList(find.byType(InkResponse));
|
|
final Offset originalOrigin = actions.elementAt(3).localToGlobal(Offset.zero);
|
|
|
|
await tester.tap(find.text('AC'));
|
|
await tester.pump();
|
|
await tester.pump(const Duration(milliseconds: 100));
|
|
|
|
actions = tester.renderObjectList(find.byType(InkResponse));
|
|
expect(actions.elementAt(3).localToGlobal(Offset.zero), equals(originalOrigin));
|
|
|
|
await tester.tap(find.text('Alarm'));
|
|
await tester.pump();
|
|
await tester.pump(const Duration(milliseconds: 100));
|
|
|
|
actions = tester.renderObjectList(find.byType(InkResponse));
|
|
expect(actions.elementAt(3).localToGlobal(Offset.zero), equals(originalOrigin));
|
|
|
|
await tester.tap(find.text('Time'));
|
|
await tester.pump();
|
|
await tester.pump(const Duration(milliseconds: 100));
|
|
|
|
actions = tester.renderObjectList(find.byType(InkResponse));
|
|
expect(actions.elementAt(3).localToGlobal(Offset.zero), equals(originalOrigin));
|
|
});
|
|
|
|
testWidgets('BottomNavigationBar inherits shadowed app theme for shifting navbar', (WidgetTester tester) async {
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
theme: ThemeData(brightness: Brightness.light),
|
|
home: Theme(
|
|
data: ThemeData(brightness: Brightness.dark),
|
|
child: Scaffold(
|
|
bottomNavigationBar: BottomNavigationBar(
|
|
type: BottomNavigationBarType.shifting,
|
|
items: const <BottomNavigationBarItem>[
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.ac_unit),
|
|
label: 'AC',
|
|
),
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.access_alarm),
|
|
label: 'Alarm',
|
|
),
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.access_time),
|
|
label: 'Time',
|
|
),
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.add),
|
|
label: 'Add',
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
await tester.tap(find.text('Alarm'));
|
|
await tester.pump(const Duration(seconds: 1));
|
|
expect(Theme.of(tester.element(find.text('Alarm'))).brightness, equals(Brightness.dark));
|
|
});
|
|
|
|
testWidgets('BottomNavigationBar inherits shadowed app theme for fixed navbar', (WidgetTester tester) async {
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
theme: ThemeData(brightness: Brightness.light),
|
|
home: Theme(
|
|
data: ThemeData(brightness: Brightness.dark),
|
|
child: Scaffold(
|
|
bottomNavigationBar: BottomNavigationBar(
|
|
type: BottomNavigationBarType.fixed,
|
|
items: const <BottomNavigationBarItem>[
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.ac_unit),
|
|
label: 'AC',
|
|
),
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.access_alarm),
|
|
label: 'Alarm',
|
|
),
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.access_time),
|
|
label: 'Time',
|
|
),
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.add),
|
|
label: 'Add',
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
await tester.tap(find.text('Alarm'));
|
|
await tester.pump(const Duration(seconds: 1));
|
|
expect(Theme.of(tester.element(find.text('Alarm'))).brightness, equals(Brightness.dark));
|
|
});
|
|
|
|
testWidgets('BottomNavigationBar iconSize test', (WidgetTester tester) async {
|
|
late double builderIconSize;
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: Scaffold(
|
|
bottomNavigationBar: BottomNavigationBar(
|
|
iconSize: 12.0,
|
|
items: <BottomNavigationBarItem>[
|
|
const BottomNavigationBarItem(
|
|
label: 'A',
|
|
icon: Icon(Icons.ac_unit),
|
|
),
|
|
BottomNavigationBarItem(
|
|
label: 'B',
|
|
icon: Builder(
|
|
builder: (BuildContext context) {
|
|
builderIconSize = IconTheme.of(context).size!;
|
|
return SizedBox(
|
|
width: builderIconSize,
|
|
height: builderIconSize,
|
|
);
|
|
},
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
final RenderBox box = tester.renderObject(find.byType(Icon));
|
|
expect(box.size.width, equals(12.0));
|
|
expect(box.size.height, equals(12.0));
|
|
expect(builderIconSize, 12.0);
|
|
});
|
|
|
|
testWidgets('BottomNavigationBar responds to textScaleFactor', (WidgetTester tester) async {
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: Scaffold(
|
|
bottomNavigationBar: BottomNavigationBar(
|
|
type: BottomNavigationBarType.fixed,
|
|
items: const <BottomNavigationBarItem>[
|
|
BottomNavigationBarItem(
|
|
label: 'A',
|
|
icon: Icon(Icons.ac_unit),
|
|
),
|
|
BottomNavigationBarItem(
|
|
label: 'B',
|
|
icon: Icon(Icons.battery_alert),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
final RenderBox defaultBox = tester.renderObject(find.byType(BottomNavigationBar));
|
|
expect(defaultBox.size.height, equals(kBottomNavigationBarHeight));
|
|
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: Scaffold(
|
|
bottomNavigationBar: BottomNavigationBar(
|
|
type: BottomNavigationBarType.shifting,
|
|
items: const <BottomNavigationBarItem>[
|
|
BottomNavigationBarItem(
|
|
label: 'A',
|
|
icon: Icon(Icons.ac_unit),
|
|
),
|
|
BottomNavigationBarItem(
|
|
label: 'B',
|
|
icon: Icon(Icons.battery_alert),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
final RenderBox shiftingBox = tester.renderObject(find.byType(BottomNavigationBar));
|
|
expect(shiftingBox.size.height, equals(kBottomNavigationBarHeight));
|
|
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: MediaQuery(
|
|
data: const MediaQueryData(textScaleFactor: 2.0),
|
|
child: Scaffold(
|
|
bottomNavigationBar: BottomNavigationBar(
|
|
items: const <BottomNavigationBarItem>[
|
|
BottomNavigationBarItem(
|
|
title: Text('A'),
|
|
icon: Icon(Icons.ac_unit),
|
|
),
|
|
BottomNavigationBarItem(
|
|
title: Text('B'),
|
|
icon: Icon(Icons.battery_alert),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
final RenderBox box = tester.renderObject(find.byType(BottomNavigationBar));
|
|
expect(box.size.height, equals(66.0));
|
|
});
|
|
|
|
testWidgets('BottomNavigationBar does not grow with textScaleFactor when labels are provided', (WidgetTester tester) async {
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: Scaffold(
|
|
bottomNavigationBar: BottomNavigationBar(
|
|
type: BottomNavigationBarType.fixed,
|
|
items: const <BottomNavigationBarItem>[
|
|
BottomNavigationBarItem(
|
|
label: 'A',
|
|
icon: Icon(Icons.ac_unit),
|
|
),
|
|
BottomNavigationBarItem(
|
|
label: 'B',
|
|
icon: Icon(Icons.battery_alert),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
final RenderBox defaultBox = tester.renderObject(find.byType(BottomNavigationBar));
|
|
expect(defaultBox.size.height, equals(kBottomNavigationBarHeight));
|
|
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: Scaffold(
|
|
bottomNavigationBar: BottomNavigationBar(
|
|
type: BottomNavigationBarType.shifting,
|
|
items: const <BottomNavigationBarItem>[
|
|
BottomNavigationBarItem(
|
|
label: 'A',
|
|
icon: Icon(Icons.ac_unit),
|
|
),
|
|
BottomNavigationBarItem(
|
|
label: 'B',
|
|
icon: Icon(Icons.battery_alert),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
final RenderBox shiftingBox = tester.renderObject(find.byType(BottomNavigationBar));
|
|
expect(shiftingBox.size.height, equals(kBottomNavigationBarHeight));
|
|
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: MediaQuery(
|
|
data: const MediaQueryData(textScaleFactor: 2.0),
|
|
child: Scaffold(
|
|
bottomNavigationBar: BottomNavigationBar(
|
|
items: const <BottomNavigationBarItem>[
|
|
BottomNavigationBarItem(
|
|
label: 'A',
|
|
icon: Icon(Icons.ac_unit),
|
|
),
|
|
BottomNavigationBarItem(
|
|
label: 'B',
|
|
icon: Icon(Icons.battery_alert),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
final RenderBox box = tester.renderObject(find.byType(BottomNavigationBar));
|
|
expect(box.size.height, equals(kBottomNavigationBarHeight));
|
|
});
|
|
|
|
testWidgets('BottomNavigationBar shows tool tips with text scaling on long press when labels are provided', (WidgetTester tester) async {
|
|
const String label = 'Foo';
|
|
|
|
Widget buildApp({ required double textScaleFactor }) {
|
|
return MediaQuery(
|
|
data: MediaQueryData(textScaleFactor: textScaleFactor),
|
|
child: Localizations(
|
|
locale: const Locale('en', 'US'),
|
|
delegates: const <LocalizationsDelegate<dynamic>>[
|
|
DefaultMaterialLocalizations.delegate,
|
|
DefaultWidgetsLocalizations.delegate,
|
|
],
|
|
child: Directionality(
|
|
textDirection: TextDirection.ltr,
|
|
child: Navigator(
|
|
onGenerateRoute: (RouteSettings settings) {
|
|
return MaterialPageRoute<void>(
|
|
builder: (BuildContext context) {
|
|
return Scaffold(
|
|
bottomNavigationBar: BottomNavigationBar(
|
|
items: const <BottomNavigationBarItem>[
|
|
BottomNavigationBarItem(
|
|
label: label,
|
|
icon: Icon(Icons.ac_unit),
|
|
tooltip: label,
|
|
),
|
|
BottomNavigationBarItem(
|
|
label: 'B',
|
|
icon: Icon(Icons.battery_alert),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
},
|
|
);
|
|
},
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
await tester.pumpWidget(buildApp(textScaleFactor: 1.0));
|
|
expect(find.text(label), findsOneWidget);
|
|
await tester.longPress(find.text(label));
|
|
expect(find.text(label), findsNWidgets(2));
|
|
expect(tester.getSize(find.text(label).last), equals(const Size(42.0, 14.0)));
|
|
await tester.pumpAndSettle(const Duration(seconds: 2));
|
|
|
|
await tester.pumpWidget(buildApp(textScaleFactor: 4.0));
|
|
expect(find.text(label), findsOneWidget);
|
|
await tester.longPress(find.text(label));
|
|
expect(tester.getSize(find.text(label).last), equals(const Size(168.0, 56.0)));
|
|
});
|
|
|
|
testWidgets('Different behaviour of tool tip in BottomNavigationBarItem', (WidgetTester tester) async {
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: Scaffold(
|
|
bottomNavigationBar: BottomNavigationBar(
|
|
items: const <BottomNavigationBarItem>[
|
|
BottomNavigationBarItem(
|
|
label: 'A',
|
|
tooltip: 'A tooltip',
|
|
icon: Icon(Icons.ac_unit),
|
|
),
|
|
BottomNavigationBarItem(
|
|
label: 'B',
|
|
icon: Icon(Icons.battery_alert),
|
|
),
|
|
BottomNavigationBarItem(
|
|
label: 'C',
|
|
icon: Icon(Icons.cake),
|
|
tooltip: '',
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
expect(find.text('A'), findsOneWidget);
|
|
await tester.longPress(find.text('A'));
|
|
expect(find.byTooltip('A tooltip'), findsOneWidget);
|
|
|
|
expect(find.text('B'), findsOneWidget);
|
|
await tester.longPress(find.text('B'));
|
|
expect(find.byTooltip('B'), findsOneWidget);
|
|
|
|
expect(find.text('C'), findsOneWidget);
|
|
await tester.longPress(find.text('C'));
|
|
expect(find.byTooltip('C'), findsNothing);
|
|
});
|
|
|
|
testWidgets('BottomNavigationBar limits width of tiles with long titles', (WidgetTester tester) async {
|
|
final Text longTextA = Text(''.padLeft(100, 'A'));
|
|
final Text longTextB = Text(''.padLeft(100, 'B'));
|
|
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: Scaffold(
|
|
bottomNavigationBar: BottomNavigationBar(
|
|
items: <BottomNavigationBarItem>[
|
|
BottomNavigationBarItem(
|
|
title: longTextA,
|
|
icon: const Icon(Icons.ac_unit),
|
|
),
|
|
BottomNavigationBarItem(
|
|
title: longTextB,
|
|
icon: const Icon(Icons.battery_alert),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
final RenderBox box = tester.renderObject(find.byType(BottomNavigationBar));
|
|
expect(box.size.height, equals(kBottomNavigationBarHeight));
|
|
|
|
final RenderBox itemBoxA = tester.renderObject(find.text(longTextA.data!));
|
|
expect(itemBoxA.size, equals(const Size(400.0, 14.0)));
|
|
final RenderBox itemBoxB = tester.renderObject(find.text(longTextB.data!));
|
|
expect(itemBoxB.size, equals(const Size(400.0, 14.0)));
|
|
});
|
|
|
|
testWidgets('BottomNavigationBar paints circles', (WidgetTester tester) async {
|
|
await tester.pumpWidget(
|
|
boilerplate(
|
|
textDirection: TextDirection.ltr,
|
|
bottomNavigationBar: BottomNavigationBar(
|
|
items: const <BottomNavigationBarItem>[
|
|
BottomNavigationBarItem(
|
|
label: 'A',
|
|
icon: Icon(Icons.ac_unit),
|
|
),
|
|
BottomNavigationBarItem(
|
|
label: 'B',
|
|
icon: Icon(Icons.battery_alert),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
|
|
final RenderBox box = tester.renderObject(find.byType(BottomNavigationBar));
|
|
expect(box, isNot(paints..circle()));
|
|
|
|
await tester.tap(find.text('A'));
|
|
await tester.pump();
|
|
await tester.pump(const Duration(milliseconds: 20));
|
|
expect(box, paints..circle(x: 200.0));
|
|
|
|
await tester.tap(find.text('B'));
|
|
await tester.pump();
|
|
await tester.pump(const Duration(milliseconds: 20));
|
|
expect(box, paints..circle(x: 200.0)..translate(x: 400.0)..circle(x: 200.0));
|
|
|
|
// Now we flip the directionality and verify that the circles switch positions.
|
|
await tester.pumpWidget(
|
|
boilerplate(
|
|
textDirection: TextDirection.rtl,
|
|
bottomNavigationBar: BottomNavigationBar(
|
|
items: const <BottomNavigationBarItem>[
|
|
BottomNavigationBarItem(
|
|
label: 'A',
|
|
icon: Icon(Icons.ac_unit),
|
|
),
|
|
BottomNavigationBarItem(
|
|
label: 'B',
|
|
icon: Icon(Icons.battery_alert),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
|
|
expect(box, paints..translate()..save()..translate(x: 400.0)..circle(x: 200.0)..restore()..circle(x: 200.0));
|
|
|
|
await tester.tap(find.text('A'));
|
|
await tester.pump();
|
|
await tester.pump(const Duration(milliseconds: 20));
|
|
expect(
|
|
box,
|
|
paints
|
|
..translate(x: 0.0, y: 0.0)
|
|
..save()
|
|
..translate(x: 400.0)
|
|
..circle(x: 200.0)
|
|
..restore()
|
|
..circle(x: 200.0)
|
|
..translate(x: 400.0)
|
|
..circle(x: 200.0),
|
|
);
|
|
});
|
|
|
|
testWidgets('BottomNavigationBar inactiveIcon shown', (WidgetTester tester) async {
|
|
const Key filled = Key('filled');
|
|
const Key stroked = Key('stroked');
|
|
int selectedItem = 0;
|
|
|
|
await tester.pumpWidget(
|
|
boilerplate(
|
|
textDirection: TextDirection.ltr,
|
|
bottomNavigationBar: BottomNavigationBar(
|
|
currentIndex: selectedItem,
|
|
items: const <BottomNavigationBarItem>[
|
|
BottomNavigationBarItem(
|
|
activeIcon: Icon(Icons.favorite, key: filled),
|
|
icon: Icon(Icons.favorite_border, key: stroked),
|
|
label: 'Favorite',
|
|
),
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.access_alarm),
|
|
label: 'Alarm',
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
|
|
expect(find.byKey(filled), findsOneWidget);
|
|
expect(find.byKey(stroked), findsNothing);
|
|
selectedItem = 1;
|
|
|
|
await tester.pumpWidget(
|
|
boilerplate(
|
|
textDirection: TextDirection.ltr,
|
|
bottomNavigationBar: BottomNavigationBar(
|
|
currentIndex: selectedItem,
|
|
items: const <BottomNavigationBarItem>[
|
|
BottomNavigationBarItem(
|
|
activeIcon: Icon(Icons.favorite, key: filled),
|
|
icon: Icon(Icons.favorite_border, key: stroked),
|
|
label: 'Favorite',
|
|
),
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.access_alarm),
|
|
label: 'Alarm',
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
|
|
expect(find.byKey(filled), findsNothing);
|
|
expect(find.byKey(stroked), findsOneWidget);
|
|
});
|
|
|
|
testWidgets('BottomNavigationBar.fixed semantics', (WidgetTester tester) async {
|
|
await tester.pumpWidget(
|
|
boilerplate(
|
|
textDirection: TextDirection.ltr,
|
|
bottomNavigationBar: BottomNavigationBar(
|
|
items: const <BottomNavigationBarItem>[
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.ac_unit),
|
|
title: Text('AC'),
|
|
),
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.access_alarm),
|
|
title: Text('Alarm'),
|
|
),
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.hot_tub),
|
|
title: Text('Hot Tub'),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
|
|
expect(
|
|
tester.getSemantics(find.text('AC')),
|
|
matchesSemantics(
|
|
label: 'AC\nTab 1 of 3',
|
|
textDirection: TextDirection.ltr,
|
|
isFocusable: true,
|
|
isSelected: true,
|
|
hasTapAction: true,
|
|
),
|
|
);
|
|
expect(
|
|
tester.getSemantics(find.text('Alarm')),
|
|
matchesSemantics(
|
|
label: 'Alarm\nTab 2 of 3',
|
|
textDirection: TextDirection.ltr,
|
|
isFocusable: true,
|
|
hasTapAction: true,
|
|
),
|
|
);
|
|
expect(
|
|
tester.getSemantics(find.text('Hot Tub')),
|
|
matchesSemantics(
|
|
label: 'Hot Tub\nTab 3 of 3',
|
|
textDirection: TextDirection.ltr,
|
|
isFocusable: true,
|
|
hasTapAction: true,
|
|
),
|
|
);
|
|
});
|
|
|
|
testWidgets('BottomNavigationBar.shifting semantics', (WidgetTester tester) async {
|
|
await tester.pumpWidget(
|
|
boilerplate(
|
|
textDirection: TextDirection.ltr,
|
|
bottomNavigationBar: BottomNavigationBar(
|
|
type: BottomNavigationBarType.shifting,
|
|
items: const <BottomNavigationBarItem>[
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.ac_unit),
|
|
title: Text('AC'),
|
|
),
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.access_alarm),
|
|
title: Text('Alarm'),
|
|
),
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.hot_tub),
|
|
title: Text('Hot Tub'),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
|
|
expect(
|
|
tester.getSemantics(find.text('AC')),
|
|
matchesSemantics(
|
|
label: 'AC\nTab 1 of 3',
|
|
textDirection: TextDirection.ltr,
|
|
isFocusable: true,
|
|
isSelected: true,
|
|
hasTapAction: true,
|
|
),
|
|
);
|
|
expect(
|
|
tester.getSemantics(find.text('Alarm')),
|
|
matchesSemantics(
|
|
label: 'Alarm\nTab 2 of 3',
|
|
textDirection: TextDirection.ltr,
|
|
isFocusable: true,
|
|
hasTapAction: true,
|
|
),
|
|
);
|
|
expect(
|
|
tester.getSemantics(find.text('Hot Tub')),
|
|
matchesSemantics(
|
|
label: 'Hot Tub\nTab 3 of 3',
|
|
textDirection: TextDirection.ltr,
|
|
isFocusable: true,
|
|
hasTapAction: true,
|
|
),
|
|
);
|
|
});
|
|
|
|
testWidgets('BottomNavigationBar handles items.length changes', (WidgetTester tester) async {
|
|
// Regression test for https://github.com/flutter/flutter/issues/10322
|
|
|
|
Widget buildFrame(int itemCount) {
|
|
return MaterialApp(
|
|
home: Scaffold(
|
|
bottomNavigationBar: BottomNavigationBar(
|
|
type: BottomNavigationBarType.fixed,
|
|
currentIndex: 0,
|
|
items: List<BottomNavigationBarItem>.generate(itemCount, (int itemIndex) {
|
|
return BottomNavigationBarItem(
|
|
icon: const Icon(Icons.android),
|
|
label: 'item $itemIndex',
|
|
);
|
|
}),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
await tester.pumpWidget(buildFrame(3));
|
|
expect(find.text('item 0'), findsOneWidget);
|
|
expect(find.text('item 1'), findsOneWidget);
|
|
expect(find.text('item 2'), findsOneWidget);
|
|
expect(find.text('item 3'), findsNothing);
|
|
|
|
await tester.pumpWidget(buildFrame(4));
|
|
expect(find.text('item 0'), findsOneWidget);
|
|
expect(find.text('item 1'), findsOneWidget);
|
|
expect(find.text('item 2'), findsOneWidget);
|
|
expect(find.text('item 3'), findsOneWidget);
|
|
|
|
await tester.pumpWidget(buildFrame(2));
|
|
expect(find.text('item 0'), findsOneWidget);
|
|
expect(find.text('item 1'), findsOneWidget);
|
|
expect(find.text('item 2'), findsNothing);
|
|
expect(find.text('item 3'), findsNothing);
|
|
});
|
|
|
|
testWidgets('BottomNavigationBar change backgroundColor test', (WidgetTester tester) async {
|
|
// Regression test for: https://github.com/flutter/flutter/issues/19653
|
|
|
|
Color _backgroundColor = Colors.red;
|
|
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: StatefulBuilder(
|
|
builder: (BuildContext context, StateSetter setState) {
|
|
return Scaffold(
|
|
body: Center(
|
|
child: ElevatedButton(
|
|
child: const Text('green'),
|
|
onPressed: () {
|
|
setState(() {
|
|
_backgroundColor = Colors.green;
|
|
});
|
|
},
|
|
),
|
|
),
|
|
bottomNavigationBar: BottomNavigationBar(
|
|
type: BottomNavigationBarType.shifting,
|
|
items: <BottomNavigationBarItem>[
|
|
BottomNavigationBarItem(
|
|
label: 'Page 1',
|
|
backgroundColor: _backgroundColor,
|
|
icon: const Icon(Icons.dashboard),
|
|
),
|
|
BottomNavigationBarItem(
|
|
label: 'Page 2',
|
|
backgroundColor: _backgroundColor,
|
|
icon: const Icon(Icons.menu),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
},
|
|
),
|
|
),
|
|
);
|
|
|
|
final Finder backgroundMaterial = find.descendant(
|
|
of: find.byType(BottomNavigationBar),
|
|
matching: find.byWidgetPredicate((Widget w) {
|
|
if (w is Material)
|
|
return w.type == MaterialType.canvas;
|
|
return false;
|
|
}),
|
|
);
|
|
|
|
expect(_backgroundColor, Colors.red);
|
|
expect(tester.widget<Material>(backgroundMaterial).color, Colors.red);
|
|
await tester.tap(find.text('green'));
|
|
await tester.pumpAndSettle();
|
|
expect(_backgroundColor, Colors.green);
|
|
expect(tester.widget<Material>(backgroundMaterial).color, Colors.green);
|
|
});
|
|
|
|
group('BottomNavigationBar shifting backgroundColor with transition', () {
|
|
// Regression test for: https://github.com/flutter/flutter/issues/22226
|
|
Widget runTest() {
|
|
int _currentIndex = 0;
|
|
return MaterialApp(
|
|
home: StatefulBuilder(
|
|
builder: (BuildContext context, StateSetter setState) {
|
|
return Scaffold(
|
|
bottomNavigationBar: RepaintBoundary(
|
|
child: BottomNavigationBar(
|
|
type: BottomNavigationBarType.shifting,
|
|
currentIndex: _currentIndex,
|
|
onTap: (int index) {
|
|
setState(() {
|
|
_currentIndex = index;
|
|
});
|
|
},
|
|
items: const <BottomNavigationBarItem>[
|
|
BottomNavigationBarItem(
|
|
label: 'Red',
|
|
backgroundColor: Colors.red,
|
|
icon: Icon(Icons.dashboard),
|
|
),
|
|
BottomNavigationBarItem(
|
|
label: 'Green',
|
|
backgroundColor: Colors.green,
|
|
icon: Icon(Icons.menu),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
},
|
|
),
|
|
);
|
|
}
|
|
for (int pump = 1; pump < 9; pump++) {
|
|
testWidgets('pump $pump', (WidgetTester tester) async {
|
|
await tester.pumpWidget(runTest());
|
|
await tester.tap(find.text('Green'));
|
|
|
|
for (int i = 0; i < pump; i++) {
|
|
await tester.pump(const Duration(milliseconds: 30));
|
|
}
|
|
await expectLater(
|
|
find.byType(BottomNavigationBar),
|
|
matchesGoldenFile('bottom_navigation_bar.shifting_transition.${pump - 1}.png'),
|
|
);
|
|
});
|
|
}
|
|
});
|
|
|
|
testWidgets('BottomNavigationBar item title should not be nullable', (WidgetTester tester) async {
|
|
expect(() {
|
|
MaterialApp(
|
|
home: Scaffold(
|
|
bottomNavigationBar: BottomNavigationBar(
|
|
type: BottomNavigationBarType.shifting,
|
|
items: const <BottomNavigationBarItem>[
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.ac_unit),
|
|
label: 'AC',
|
|
),
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.access_alarm),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}, throwsAssertionError);
|
|
});
|
|
|
|
testWidgets(
|
|
'BottomNavigationBar [showSelectedLabels]=false and [showUnselectedLabels]=false '
|
|
'for shifting navbar, expect that there is no rendered text',
|
|
(WidgetTester tester) async {
|
|
final Widget widget = MaterialApp(
|
|
home: StatefulBuilder(
|
|
builder: (BuildContext context, StateSetter setState) {
|
|
return Scaffold(
|
|
bottomNavigationBar: BottomNavigationBar(
|
|
showSelectedLabels: false,
|
|
showUnselectedLabels: false,
|
|
type: BottomNavigationBarType.shifting,
|
|
items: const <BottomNavigationBarItem>[
|
|
BottomNavigationBarItem(
|
|
label: 'Red',
|
|
backgroundColor: Colors.red,
|
|
icon: Icon(Icons.dashboard),
|
|
),
|
|
BottomNavigationBarItem(
|
|
label: 'Green',
|
|
backgroundColor: Colors.green,
|
|
icon: Icon(Icons.menu),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
},
|
|
),
|
|
);
|
|
await tester.pumpWidget(widget);
|
|
expect(find.text('Red'), findsOneWidget);
|
|
expect(find.text('Green'), findsOneWidget);
|
|
expect(tester.widget<Opacity>(find.byType(Opacity).first).opacity, 0.0);
|
|
expect(tester.widget<Opacity>(find.byType(Opacity).last).opacity, 0.0);
|
|
},
|
|
);
|
|
|
|
testWidgets(
|
|
'BottomNavigationBar [showSelectedLabels]=false and [showUnselectedLabels]=false '
|
|
'for fixed navbar, expect that there is no rendered text',
|
|
(WidgetTester tester) async {
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: StatefulBuilder(
|
|
builder: (BuildContext context, StateSetter setState) {
|
|
return Scaffold(
|
|
bottomNavigationBar: BottomNavigationBar(
|
|
showSelectedLabels: false,
|
|
showUnselectedLabels: false,
|
|
type: BottomNavigationBarType.fixed,
|
|
items: const <BottomNavigationBarItem>[
|
|
BottomNavigationBarItem(
|
|
label: 'Red',
|
|
backgroundColor: Colors.red,
|
|
icon: Icon(Icons.dashboard),
|
|
),
|
|
BottomNavigationBarItem(
|
|
label: 'Green',
|
|
backgroundColor: Colors.green,
|
|
icon: Icon(Icons.menu),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
},
|
|
),
|
|
),
|
|
);
|
|
expect(find.text('Red'), findsOneWidget);
|
|
expect(find.text('Green'), findsOneWidget);
|
|
expect(tester.widget<Opacity>(find.byType(Opacity).first).opacity, 0.0);
|
|
expect(tester.widget<Opacity>(find.byType(Opacity).last).opacity, 0.0);
|
|
},
|
|
);
|
|
|
|
testWidgets('BottomNavigationBar.fixed [showSelectedLabels]=false and [showUnselectedLabels]=false semantics', (WidgetTester tester) async {
|
|
await tester.pumpWidget(
|
|
boilerplate(
|
|
textDirection: TextDirection.ltr,
|
|
bottomNavigationBar: BottomNavigationBar(
|
|
showSelectedLabels: false,
|
|
showUnselectedLabels: false,
|
|
items: const <BottomNavigationBarItem>[
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.ac_unit),
|
|
title: Text('Red'),
|
|
),
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.access_alarm),
|
|
title: Text('Green'),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
|
|
expect(
|
|
tester.getSemantics(find.text('Red')),
|
|
matchesSemantics(
|
|
label: 'Red\nTab 1 of 2',
|
|
textDirection: TextDirection.ltr,
|
|
isFocusable: true,
|
|
isSelected: true,
|
|
hasTapAction: true,
|
|
),
|
|
);
|
|
expect(
|
|
tester.getSemantics(find.text('Green')),
|
|
matchesSemantics(
|
|
label: 'Green\nTab 2 of 2',
|
|
textDirection: TextDirection.ltr,
|
|
isFocusable: true,
|
|
hasTapAction: true,
|
|
),
|
|
);
|
|
});
|
|
|
|
testWidgets('BottomNavigationBar.shifting [showSelectedLabels]=false and [showUnselectedLabels]=false semantics', (WidgetTester tester) async {
|
|
await tester.pumpWidget(
|
|
boilerplate(
|
|
textDirection: TextDirection.ltr,
|
|
bottomNavigationBar: BottomNavigationBar(
|
|
showSelectedLabels: false,
|
|
showUnselectedLabels: false,
|
|
type: BottomNavigationBarType.shifting,
|
|
items: const <BottomNavigationBarItem>[
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.ac_unit),
|
|
title: Text('Red'),
|
|
),
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.access_alarm),
|
|
title: Text('Green'),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
|
|
expect(
|
|
tester.getSemantics(find.text('Red')),
|
|
matchesSemantics(
|
|
label: 'Red\nTab 1 of 2',
|
|
textDirection: TextDirection.ltr,
|
|
isFocusable: true,
|
|
isSelected: true,
|
|
hasTapAction: true,
|
|
),
|
|
);
|
|
expect(
|
|
tester.getSemantics(find.text('Green')),
|
|
matchesSemantics(
|
|
label: 'Green\nTab 2 of 2',
|
|
textDirection: TextDirection.ltr,
|
|
isFocusable: true,
|
|
hasTapAction: true,
|
|
),
|
|
);
|
|
});
|
|
|
|
testWidgets('BottomNavigationBar changes mouse cursor when the tile is hovered over', (WidgetTester tester) async {
|
|
// Test BottomNavigationBar() constructor
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: Scaffold(
|
|
bottomNavigationBar: MouseRegion(
|
|
cursor: SystemMouseCursors.forbidden,
|
|
child: BottomNavigationBar(
|
|
mouseCursor: SystemMouseCursors.text,
|
|
items: const <BottomNavigationBarItem>[
|
|
BottomNavigationBarItem(icon: Icon(Icons.ac_unit), title: Text('AC')),
|
|
BottomNavigationBarItem(icon: Icon(Icons.access_alarm), title: Text('Alarm')),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse, pointer: 1);
|
|
await gesture.addPointer(location: tester.getCenter(find.text('AC')));
|
|
addTearDown(gesture.removePointer);
|
|
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(RendererBinding.instance!.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.text);
|
|
|
|
// Test default cursor
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: Scaffold(
|
|
bottomNavigationBar: MouseRegion(
|
|
cursor: SystemMouseCursors.forbidden,
|
|
child: BottomNavigationBar(
|
|
items: const <BottomNavigationBarItem>[
|
|
BottomNavigationBarItem(icon: Icon(Icons.ac_unit), title: Text('AC')),
|
|
BottomNavigationBarItem(icon: Icon(Icons.access_alarm), title: Text('Alarm')),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
expect(RendererBinding.instance!.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.click);
|
|
});
|
|
|
|
group('feedback', () {
|
|
late FeedbackTester feedback;
|
|
|
|
setUp(() {
|
|
feedback = FeedbackTester();
|
|
});
|
|
|
|
tearDown(() {
|
|
feedback.dispose();
|
|
});
|
|
|
|
Widget feedbackBoilerplate({bool? enableFeedback, bool? enableFeedbackTheme}) {
|
|
return MaterialApp(
|
|
home: Scaffold(
|
|
bottomNavigationBar: BottomNavigationBarTheme(
|
|
data: BottomNavigationBarThemeData(
|
|
enableFeedback: enableFeedbackTheme,
|
|
),
|
|
child: BottomNavigationBar(
|
|
enableFeedback: enableFeedback,
|
|
items: const <BottomNavigationBarItem>[
|
|
BottomNavigationBarItem(icon: Icon(Icons.ac_unit), title: Text('AC')),
|
|
BottomNavigationBarItem(icon: Icon(Icons.access_alarm), title: Text('Alarm')),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
testWidgets('BottomNavigationBar with enabled feedback', (WidgetTester tester) async {
|
|
const bool enableFeedback = true;
|
|
|
|
await tester.pumpWidget(feedbackBoilerplate(enableFeedback: enableFeedback));
|
|
|
|
await tester.tap(find.byType(InkResponse).first);
|
|
await tester.pumpAndSettle();
|
|
expect(feedback.clickSoundCount, 1);
|
|
expect(feedback.hapticCount, 0);
|
|
});
|
|
|
|
testWidgets('BottomNavigationBar with disabled feedback', (WidgetTester tester) async {
|
|
const bool enableFeedback = false;
|
|
|
|
await tester.pumpWidget(feedbackBoilerplate(enableFeedback: enableFeedback));
|
|
|
|
await tester.tap(find.byType(InkResponse).first);
|
|
await tester.pumpAndSettle();
|
|
expect(feedback.clickSoundCount, 0);
|
|
expect(feedback.hapticCount, 0);
|
|
});
|
|
|
|
testWidgets('BottomNavigationBar with enabled feedback by default', (WidgetTester tester) async {
|
|
await tester.pumpWidget(feedbackBoilerplate());
|
|
|
|
await tester.tap(find.byType(InkResponse).first);
|
|
await tester.pumpAndSettle();
|
|
expect(feedback.clickSoundCount, 1);
|
|
expect(feedback.hapticCount, 0);
|
|
});
|
|
|
|
testWidgets('BottomNavigationBar with disabled feedback using BottomNavigationBarTheme', (WidgetTester tester) async {
|
|
const bool enableFeedbackTheme = false;
|
|
|
|
await tester.pumpWidget(feedbackBoilerplate(enableFeedbackTheme: enableFeedbackTheme));
|
|
|
|
await tester.tap(find.byType(InkResponse).first);
|
|
await tester.pumpAndSettle();
|
|
expect(feedback.clickSoundCount, 0);
|
|
expect(feedback.hapticCount, 0);
|
|
});
|
|
|
|
testWidgets('BottomNavigationBar.enableFeedback overrides BottomNavigationBarTheme.enableFeedback', (WidgetTester tester) async {
|
|
const bool enableFeedbackTheme = false;
|
|
const bool enableFeedback = true;
|
|
|
|
await tester.pumpWidget(feedbackBoilerplate(
|
|
enableFeedbackTheme: enableFeedbackTheme,
|
|
enableFeedback: enableFeedback,
|
|
));
|
|
|
|
await tester.tap(find.byType(InkResponse).first);
|
|
await tester.pumpAndSettle();
|
|
expect(feedback.clickSoundCount, 1);
|
|
expect(feedback.hapticCount, 0);
|
|
});
|
|
});
|
|
|
|
testWidgets('BottomNavigationBar excludes semantics', (WidgetTester tester) async {
|
|
final SemanticsTester semantics = SemanticsTester(tester);
|
|
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: Scaffold(
|
|
bottomNavigationBar: BottomNavigationBar(
|
|
items: const <BottomNavigationBarItem>[
|
|
BottomNavigationBarItem(
|
|
label: 'A',
|
|
icon: Icon(Icons.ac_unit),
|
|
),
|
|
BottomNavigationBarItem(
|
|
label: 'B',
|
|
icon: Icon(Icons.battery_alert),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
expect(
|
|
semantics,
|
|
hasSemantics(
|
|
TestSemantics.root(
|
|
children: <TestSemantics>[
|
|
TestSemantics(
|
|
textDirection: TextDirection.ltr,
|
|
children: <TestSemantics>[
|
|
TestSemantics(
|
|
children: <TestSemantics>[
|
|
TestSemantics(
|
|
flags: <SemanticsFlag>[SemanticsFlag.scopesRoute],
|
|
children: <TestSemantics>[
|
|
TestSemantics(
|
|
children: <TestSemantics>[
|
|
TestSemantics(
|
|
flags: <SemanticsFlag>[
|
|
SemanticsFlag.isSelected,
|
|
SemanticsFlag.isFocusable,
|
|
],
|
|
actions: <SemanticsAction>[SemanticsAction.tap],
|
|
label: 'A\nTab 1 of 2',
|
|
textDirection: TextDirection.ltr,
|
|
),
|
|
TestSemantics(
|
|
flags: <SemanticsFlag>[SemanticsFlag.isFocusable],
|
|
actions: <SemanticsAction>[SemanticsAction.tap],
|
|
label: 'B\nTab 2 of 2',
|
|
textDirection: TextDirection.ltr,
|
|
),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
ignoreId: true,
|
|
ignoreRect: true,
|
|
ignoreTransform: true,
|
|
),
|
|
);
|
|
|
|
semantics.dispose();
|
|
});
|
|
}
|
|
|
|
Widget boilerplate({ Widget? bottomNavigationBar, required TextDirection textDirection }) {
|
|
assert(textDirection != null);
|
|
return MaterialApp(
|
|
home: Localizations(
|
|
locale: const Locale('en', 'US'),
|
|
delegates: const <LocalizationsDelegate<dynamic>>[
|
|
DefaultMaterialLocalizations.delegate,
|
|
DefaultWidgetsLocalizations.delegate,
|
|
],
|
|
child: Directionality(
|
|
textDirection: textDirection,
|
|
child: MediaQuery(
|
|
data: const MediaQueryData(),
|
|
child: Material(
|
|
child: Scaffold(
|
|
bottomNavigationBar: bottomNavigationBar,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
double _getOpacity(WidgetTester tester, String textValue) {
|
|
final FadeTransition opacityWidget = tester.widget<FadeTransition>(
|
|
find.ancestor(
|
|
of: find.text(textValue),
|
|
matching: find.byType(FadeTransition),
|
|
).first,
|
|
);
|
|
return opacityWidget.opacity.value;
|
|
}
|
|
|
|
Material _getMaterial(WidgetTester tester) {
|
|
return tester.firstWidget<Material>(
|
|
find.descendant(of: find.byType(BottomNavigationBar), matching: find.byType(Material)),
|
|
);
|
|
}
|
|
|
|
TextStyle _iconStyle(WidgetTester tester, IconData icon) {
|
|
final RichText iconRichText = tester.widget<RichText>(
|
|
find.descendant(of: find.byIcon(icon), matching: find.byType(RichText)),
|
|
);
|
|
return iconRichText.text.style!;
|
|
}
|
|
|
|
EdgeInsets _itemPadding(WidgetTester tester, IconData icon) {
|
|
return tester.widget<Padding>(
|
|
find.descendant(
|
|
of: find.ancestor(of: find.byIcon(icon), matching: find.byType(InkResponse)),
|
|
matching: find.byType(Padding),
|
|
).first,
|
|
).padding.resolve(TextDirection.ltr);
|
|
}
|