tab_test.dart 9.01 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1
// Copyright 2014 The Flutter Authors. All rights reserved.
2 3 4 5 6 7 8 9 10
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'package:flutter/cupertino.dart';
import 'package:flutter_test/flutter_test.dart';

void main() {
  testWidgets('Use home', (WidgetTester tester) async {
    await tester.pumpWidget(
11 12
      CupertinoApp(
        home: CupertinoTabView(
xster's avatar
xster committed
13 14
          builder: (BuildContext context) => const Text('home'),
        ),
15 16 17 18 19 20 21 22
      ),
    );

    expect(find.text('home'), findsOneWidget);
  });

  testWidgets('Use routes', (WidgetTester tester) async {
    await tester.pumpWidget(
23 24
      CupertinoApp(
        home: CupertinoTabView(
xster's avatar
xster committed
25 26 27 28
          routes: <String, WidgetBuilder>{
            '/': (BuildContext context) => const Text('first route'),
          },
        ),
29 30 31 32 33 34 35 36
      ),
    );

    expect(find.text('first route'), findsOneWidget);
  });

  testWidgets('Use home and named routes', (WidgetTester tester) async {
    await tester.pumpWidget(
37 38
      CupertinoApp(
        home: CupertinoTabView(
xster's avatar
xster committed
39
          builder: (BuildContext context) {
40
            return CupertinoButton(
xster's avatar
xster committed
41 42
              child: const Text('go to second page'),
              onPressed: () {
43
                Navigator.of(context).pushNamed('/2');
xster's avatar
xster committed
44 45 46 47 48 49 50
              },
            );
          },
          routes: <String, WidgetBuilder>{
            '/2': (BuildContext context) => const Text('second named route'),
          },
        ),
51 52 53 54 55 56 57 58 59 60 61 62
      ),
    );

    expect(find.text('go to second page'), findsOneWidget);
    await tester.tap(find.text('go to second page'));
    await tester.pump();
    await tester.pump(const Duration(milliseconds: 300));
    expect(find.text('second named route'), findsOneWidget);
  });

  testWidgets('Use onGenerateRoute', (WidgetTester tester) async {
    await tester.pumpWidget(
63 64
      CupertinoApp(
        home: CupertinoTabView(
xster's avatar
xster committed
65 66
          onGenerateRoute: (RouteSettings settings) {
            if (settings.name == Navigator.defaultRouteName) {
67
              return CupertinoPageRoute<void>(
xster's avatar
xster committed
68 69 70
                settings: settings,
                builder: (BuildContext context) {
                  return const Text('generated home');
71
                },
72
              );
xster's avatar
xster committed
73
            }
74
            return null;
xster's avatar
xster committed
75 76
          },
        ),
77 78 79 80 81 82 83
      ),
    );

    expect(find.text('generated home'), findsOneWidget);
  });

  testWidgets('Use onUnknownRoute', (WidgetTester tester) async {
84
    late String unknownForRouteCalled;
85
    await tester.pumpWidget(
86 87
      CupertinoApp(
        home: CupertinoTabView(
xster's avatar
xster committed
88
          onUnknownRoute: (RouteSettings settings) {
89
            unknownForRouteCalled = settings.name!;
90
            return null;
xster's avatar
xster committed
91 92
          },
        ),
93 94 95 96 97
      ),
    );

    expect(tester.takeException(), isFlutterError);
    expect(unknownForRouteCalled, '/');
98 99 100 101

    // Work-around for https://github.com/flutter/flutter/issues/65655.
    await tester.pumpWidget(Container());
    expect(tester.takeException(), isAssertionError);
102
  });
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117

  testWidgets('Can use navigatorKey to navigate', (WidgetTester tester) async {
    final GlobalKey<NavigatorState> key = GlobalKey();
    await tester.pumpWidget(
      CupertinoApp(
        home: CupertinoTabView(
          navigatorKey: key,
          builder: (BuildContext context) => const Text('first route'),
          routes: <String, WidgetBuilder>{
            '/2': (BuildContext context) => const Text('second route'),
          },
        ),
      ),
    );

118
    key.currentState!.pushNamed('/2');
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133

    await tester.pump();
    await tester.pump(const Duration(milliseconds: 300));
    expect(find.text('second route'), findsOneWidget);
  });

  testWidgets('Changing the key resets the navigator', (WidgetTester tester) async {
    final GlobalKey<NavigatorState> key = GlobalKey();
    await tester.pumpWidget(
      CupertinoApp(
        home: CupertinoTabView(
          builder: (BuildContext context) {
            return CupertinoButton(
              child: const Text('go to second page'),
              onPressed: () {
134
                Navigator.of(context).pushNamed('/2');
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
              },
            );
          },
          routes: <String, WidgetBuilder>{
            '/2': (BuildContext context) => const Text('second route'),
          },
        ),
      ),
    );

    expect(find.text('go to second page'), findsOneWidget);
    await tester.tap(find.text('go to second page'));
    await tester.pump();
    await tester.pump(const Duration(milliseconds: 300));
    expect(find.text('second route'), findsOneWidget);

    await tester.pumpWidget(
      CupertinoApp(
        home: CupertinoTabView(
          key: key,
          builder: (BuildContext context) {
            return CupertinoButton(
              child: const Text('go to second page'),
              onPressed: () {
159
                Navigator.of(context).pushNamed('/2');
160 161 162 163 164 165 166 167 168 169 170 171 172 173
              },
            );
          },
          routes: <String, WidgetBuilder>{
            '/2': (BuildContext context) => const Text('second route'),
          },
        ),
      ),
    );

    // The stack is gone and we're back to a re-built page 1.
    expect(find.text('go to second page'), findsOneWidget);
    expect(find.text('second route'), findsNothing);
  });
174

175
  testWidgets('Throws FlutterError when onUnknownRoute is null', (WidgetTester tester) async {
176 177 178 179 180 181 182 183 184
    final GlobalKey<NavigatorState> key = GlobalKey();
    await tester.pumpWidget(
      CupertinoApp(
        home: CupertinoTabView(
          navigatorKey: key,
          builder: (BuildContext context) => const Text('first route'),
        ),
      ),
    );
185
    late FlutterError error;
186
    try {
187
      key.currentState!.pushNamed('/2');
188 189 190 191
    } on FlutterError catch (e) {
      error = e;
    }
    expect(error, isNotNull);
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
    expect(
      error.toStringDeep(),
      equalsIgnoringHashCodes(
        'FlutterError\n'
        '   Could not find a generator for route RouteSettings("/2", null) in\n'
        '   the _CupertinoTabViewState.\n'
        '   Generators for routes are searched for in the following order:\n'
        '    1. For the "/" route, the "builder" property, if non-null, is\n'
        '   used.\n'
        '    2. Otherwise, the "routes" table is used, if it has an entry for\n'
        '   the route.\n'
        '    3. Otherwise, onGenerateRoute is called. It should return a\n'
        '   non-null value for any valid route not handled by "builder" and\n'
        '   "routes".\n'
        '    4. Finally if all else fails onUnknownRoute is called.\n'
        '   Unfortunately, onUnknownRoute was not set.\n',
      ),
    );
210 211
  });

212
  testWidgets('Throws FlutterError when onUnknownRoute returns null', (WidgetTester tester) async {
213 214 215 216 217 218 219 220 221 222
    final GlobalKey<NavigatorState> key = GlobalKey<NavigatorState>();
    await tester.pumpWidget(
      CupertinoApp(
        home: CupertinoTabView(
          navigatorKey: key,
          builder: (BuildContext context) => const Text('first route'),
          onUnknownRoute: (_) => null,
        ),
      ),
    );
223
    late FlutterError error;
224
    try {
225
      key.currentState!.pushNamed('/2');
226 227 228 229
    } on FlutterError catch (e) {
      error = e;
    }
    expect(error, isNotNull);
230 231 232 233 234 235 236 237 238 239
    expect(
      error.toStringDeep(),
      equalsIgnoringHashCodes(
        'FlutterError\n'
        '   The onUnknownRoute callback returned null.\n'
        '   When the _CupertinoTabViewState requested the route\n'
        '   RouteSettings("/2", null) from its onUnknownRoute callback, the\n'
        '   callback returned null. Such callbacks must never return null.\n',
      ),
    );
240
  });
241 242 243 244 245 246 247 248 249 250

  testWidgets('Navigator of CupertinoTabView restores state', (WidgetTester tester) async {
    await tester.pumpWidget(
      CupertinoApp(
        restorationScopeId: 'app',
        home: CupertinoTabView(
          restorationScopeId: 'tab',
          builder: (BuildContext context) => CupertinoButton(
            child: const Text('home'),
            onPressed: () {
251
              Navigator.of(context).restorablePushNamed('/2');
252 253 254 255
            },
          ),
          routes: <String, WidgetBuilder>{
            '/2' : (BuildContext context) => const Text('second route'),
256
          },
257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274
        ),
      ),
    );

    expect(find.text('home'), findsOneWidget);
    await tester.tap(find.text('home'));
    await tester.pumpAndSettle();

    expect(find.text('home'), findsNothing);
    expect(find.text('second route'), findsOneWidget);

    final TestRestorationData data = await tester.getRestorationData();

    await tester.restartAndRestore();

    expect(find.text('home'), findsNothing);
    expect(find.text('second route'), findsOneWidget);

275
    Navigator.of(tester.element(find.text('second route'))).pop();
276 277 278 279 280 281 282 283 284 285
    await tester.pumpAndSettle();

    expect(find.text('home'), findsOneWidget);
    expect(find.text('second route'), findsNothing);

    await tester.restoreFrom(data);

    expect(find.text('home'), findsNothing);
    expect(find.text('second route'), findsOneWidget);

286
    Navigator.of(tester.element(find.text('second route'))).pop();
287 288 289 290 291
    await tester.pumpAndSettle();

    expect(find.text('home'), findsOneWidget);
    expect(find.text('second route'), findsNothing);
  });
292
}