// 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/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; void main() { testWidgets('BackButton control test', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: const Material(child: Text('Home')), routes: <String, WidgetBuilder>{ '/next': (BuildContext context) { return const Material( child: Center( child: BackButton(), ), ); }, }, ), ); tester.state<NavigatorState>(find.byType(Navigator)).pushNamed('/next'); await tester.pumpAndSettle(); await tester.tap(find.byType(BackButton)); await tester.pumpAndSettle(); expect(find.text('Home'), findsOneWidget); }); testWidgets('BackButton onPressed overrides default pop behavior', (WidgetTester tester) async { bool customCallbackWasCalled = false; await tester.pumpWidget( MaterialApp( home: const Material(child: Text('Home')), routes: <String, WidgetBuilder>{ '/next': (BuildContext context) { return Material( child: Center( child: BackButton(onPressed: () => customCallbackWasCalled = true), ), ); }, }, ), ); tester.state<NavigatorState>(find.byType(Navigator)).pushNamed('/next'); await tester.pumpAndSettle(); expect(find.text('Home'), findsNothing); // Start off on the second page. expect(customCallbackWasCalled, false); // customCallbackWasCalled should still be false. await tester.tap(find.byType(BackButton)); await tester.pumpAndSettle(); // We're still on the second page. expect(find.text('Home'), findsNothing); // But the custom callback is called. expect(customCallbackWasCalled, true); }); testWidgets('BackButton icon', (WidgetTester tester) async { final Key androidKey = UniqueKey(); final Key iOSKey = UniqueKey(); final Key linuxKey = UniqueKey(); final Key macOSKey = UniqueKey(); final Key windowsKey = UniqueKey(); await tester.pumpWidget( MaterialApp( home: Column( children: <Widget>[ Theme( data: ThemeData(platform: TargetPlatform.android), child: BackButtonIcon(key: androidKey), ), Theme( data: ThemeData(platform: TargetPlatform.iOS), child: BackButtonIcon(key: iOSKey), ), Theme( data: ThemeData(platform: TargetPlatform.linux), child: BackButtonIcon(key: linuxKey), ), Theme( data: ThemeData(platform: TargetPlatform.macOS), child: BackButtonIcon(key: macOSKey), ), Theme( data: ThemeData(platform: TargetPlatform.windows), child: BackButtonIcon(key: windowsKey), ), ], ), ), ); final Icon androidIcon = tester.widget(find.descendant(of: find.byKey(androidKey), matching: find.byType(Icon))); final Icon iOSIcon = tester.widget(find.descendant(of: find.byKey(iOSKey), matching: find.byType(Icon))); final Icon linuxIcon = tester.widget(find.descendant(of: find.byKey(linuxKey), matching: find.byType(Icon))); final Icon macOSIcon = tester.widget(find.descendant(of: find.byKey(macOSKey), matching: find.byType(Icon))); final Icon windowsIcon = tester.widget(find.descendant(of: find.byKey(windowsKey), matching: find.byType(Icon))); expect(iOSIcon.icon == androidIcon.icon, isFalse); expect(linuxIcon.icon == androidIcon.icon, isTrue); expect(macOSIcon.icon == androidIcon.icon, isFalse); expect(macOSIcon.icon == iOSIcon.icon, isTrue); expect(windowsIcon.icon == androidIcon.icon, isTrue); }); testWidgets('BackButton color', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Material( child: BackButton( color: Colors.blue, ), ), ), ); final RichText iconText = tester.firstWidget(find.descendant( of: find.byType(BackButton), matching: find.byType(RichText) )); expect(iconText.text.style.color, Colors.blue); }); testWidgets('BackButton semantics', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); await tester.pumpWidget( MaterialApp( home: const Material(child: Text('Home')), routes: <String, WidgetBuilder>{ '/next': (BuildContext context) { return const Material( child: Center( child: BackButton(), ), ); }, }, ), ); tester.state<NavigatorState>(find.byType(Navigator)).pushNamed('/next'); await tester.pumpAndSettle(); expect(tester.getSemantics(find.byType(BackButton)), matchesSemantics( label: 'Back', isButton: true, hasEnabledState: true, isEnabled: true, hasTapAction: true, isFocusable: true, )); handle.dispose(); }); testWidgets('CloseButton color', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Material( child: CloseButton( color: Colors.red, ), ), ), ); final RichText iconText = tester.firstWidget(find.descendant( of: find.byType(CloseButton), matching: find.byType(RichText) )); expect(iconText.text.style.color, Colors.red); }); testWidgets('CloseButton onPressed overrides default pop behavior', (WidgetTester tester) async { bool customCallbackWasCalled = false; await tester.pumpWidget( MaterialApp( home: const Material(child: Text('Home')), routes: <String, WidgetBuilder>{ '/next': (BuildContext context) { return Material( child: Center( child: CloseButton(onPressed: () => customCallbackWasCalled = true), ), ); }, }, ), ); tester.state<NavigatorState>(find.byType(Navigator)).pushNamed('/next'); await tester.pumpAndSettle(); expect(find.text('Home'), findsNothing); // Start off on the second page. expect(customCallbackWasCalled, false); // customCallbackWasCalled should still be false. await tester.tap(find.byType(CloseButton)); await tester.pumpAndSettle(); // We're still on the second page. expect(find.text('Home'), findsNothing); // The custom callback is called, setting customCallbackWasCalled to true. expect(customCallbackWasCalled, true); }); }