blob: 08cf53c776da0ef12fa6c0f00fc191065d07fcf3 [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:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:go_router/src/configuration.dart';
void main() {
group('RouteConfiguration', () {
test('throws when parentNavigatorKey is not an ancestor', () {
final GlobalKey<NavigatorState> root =
GlobalKey<NavigatorState>(debugLabel: 'root');
final GlobalKey<NavigatorState> a =
GlobalKey<NavigatorState>(debugLabel: 'a');
final GlobalKey<NavigatorState> b =
GlobalKey<NavigatorState>(debugLabel: 'b');
expect(
() {
RouteConfiguration(
navigatorKey: root,
routes: <RouteBase>[
GoRoute(
path: '/a',
builder: _mockScreenBuilder,
routes: <RouteBase>[
ShellRoute(
navigatorKey: a,
builder: _mockShellBuilder,
routes: <RouteBase>[
GoRoute(
path: 'b',
builder: _mockScreenBuilder,
)
],
),
ShellRoute(
navigatorKey: b,
builder: _mockShellBuilder,
routes: <RouteBase>[
GoRoute(
path: 'c',
parentNavigatorKey: a,
builder: _mockScreenBuilder,
)
],
),
],
),
],
redirectLimit: 10,
topRedirect: (BuildContext context, GoRouterState state) {
return null;
},
);
},
throwsAssertionError,
);
});
test('throws when ShellRoute has no children', () {
final GlobalKey<NavigatorState> root =
GlobalKey<NavigatorState>(debugLabel: 'root');
final List<RouteBase> shellRouteChildren = <RouteBase>[];
expect(
() {
RouteConfiguration(
navigatorKey: root,
routes: <RouteBase>[
ShellRoute(routes: shellRouteChildren),
],
redirectLimit: 10,
topRedirect: (BuildContext context, GoRouterState state) {
return null;
},
);
},
throwsAssertionError,
);
});
test(
'throws when there is a GoRoute ancestor with a different parentNavigatorKey',
() {
final GlobalKey<NavigatorState> root =
GlobalKey<NavigatorState>(debugLabel: 'root');
final GlobalKey<NavigatorState> shell =
GlobalKey<NavigatorState>(debugLabel: 'shell');
expect(
() {
RouteConfiguration(
navigatorKey: root,
routes: <RouteBase>[
ShellRoute(
navigatorKey: shell,
routes: <RouteBase>[
GoRoute(
path: '/',
builder: _mockScreenBuilder,
parentNavigatorKey: root,
routes: <RouteBase>[
GoRoute(
path: 'a',
builder: _mockScreenBuilder,
parentNavigatorKey: shell,
),
],
),
],
),
],
redirectLimit: 10,
topRedirect: (BuildContext context, GoRouterState state) {
return null;
},
);
},
throwsAssertionError,
);
});
test(
'Does not throw with valid parentNavigatorKey configuration',
() {
final GlobalKey<NavigatorState> root =
GlobalKey<NavigatorState>(debugLabel: 'root');
final GlobalKey<NavigatorState> shell =
GlobalKey<NavigatorState>(debugLabel: 'shell');
final GlobalKey<NavigatorState> shell2 =
GlobalKey<NavigatorState>(debugLabel: 'shell2');
RouteConfiguration(
navigatorKey: root,
routes: <RouteBase>[
ShellRoute(
navigatorKey: shell,
routes: <RouteBase>[
GoRoute(
path: '/',
builder: _mockScreenBuilder,
routes: <RouteBase>[
GoRoute(
path: 'a',
builder: _mockScreenBuilder,
parentNavigatorKey: root,
routes: <RouteBase>[
ShellRoute(
navigatorKey: shell2,
routes: <RouteBase>[
GoRoute(
path: 'b',
builder: _mockScreenBuilder,
routes: <RouteBase>[
GoRoute(
path: 'b',
builder: _mockScreenBuilder,
parentNavigatorKey: shell2,
),
],
),
],
),
],
),
],
),
],
),
],
redirectLimit: 10,
topRedirect: (BuildContext context, GoRouterState state) {
return null;
},
);
},
);
test(
'Does not throw with multiple nested GoRoutes using parentNavigatorKey in ShellRoute',
() {
final GlobalKey<NavigatorState> root =
GlobalKey<NavigatorState>(debugLabel: 'root');
final GlobalKey<NavigatorState> shell =
GlobalKey<NavigatorState>(debugLabel: 'shell');
RouteConfiguration(
navigatorKey: root,
routes: <RouteBase>[
ShellRoute(
navigatorKey: shell,
routes: <RouteBase>[
GoRoute(
path: '/',
builder: _mockScreenBuilder,
routes: <RouteBase>[
GoRoute(
path: 'a',
builder: _mockScreenBuilder,
parentNavigatorKey: root,
routes: <RouteBase>[
GoRoute(
path: 'b',
builder: _mockScreenBuilder,
parentNavigatorKey: root,
routes: <RouteBase>[
GoRoute(
path: 'c',
builder: _mockScreenBuilder,
parentNavigatorKey: root,
),
],
),
],
),
],
),
],
),
],
redirectLimit: 10,
topRedirect: (BuildContext context, GoRouterState state) {
return null;
},
);
},
);
test(
'Throws when parentNavigatorKeys are overlapping',
() {
final GlobalKey<NavigatorState> root =
GlobalKey<NavigatorState>(debugLabel: 'root');
final GlobalKey<NavigatorState> shell =
GlobalKey<NavigatorState>(debugLabel: 'shell');
expect(
() => RouteConfiguration(
navigatorKey: root,
routes: <RouteBase>[
ShellRoute(
navigatorKey: shell,
routes: <RouteBase>[
GoRoute(
path: '/',
builder: _mockScreenBuilder,
routes: <RouteBase>[
GoRoute(
path: 'a',
builder: _mockScreenBuilder,
parentNavigatorKey: root,
routes: <RouteBase>[
GoRoute(
path: 'b',
builder: _mockScreenBuilder,
routes: <RouteBase>[
GoRoute(
path: 'b',
builder: _mockScreenBuilder,
parentNavigatorKey: shell,
),
],
),
],
),
],
),
],
),
],
redirectLimit: 10,
topRedirect: (BuildContext context, GoRouterState state) {
return null;
},
),
throwsAssertionError,
);
},
);
test(
'Does not throw when parentNavigatorKeys are overlapping correctly',
() {
final GlobalKey<NavigatorState> root =
GlobalKey<NavigatorState>(debugLabel: 'root');
final GlobalKey<NavigatorState> shell =
GlobalKey<NavigatorState>(debugLabel: 'shell');
RouteConfiguration(
navigatorKey: root,
routes: <RouteBase>[
ShellRoute(
navigatorKey: shell,
routes: <RouteBase>[
GoRoute(
path: '/',
builder: _mockScreenBuilder,
routes: <RouteBase>[
GoRoute(
path: 'a',
builder: _mockScreenBuilder,
parentNavigatorKey: shell,
routes: <RouteBase>[
GoRoute(
path: 'b',
builder: _mockScreenBuilder,
routes: <RouteBase>[
GoRoute(
path: 'b',
builder: _mockScreenBuilder,
parentNavigatorKey: root,
),
],
),
],
),
],
),
],
),
],
redirectLimit: 10,
topRedirect: (BuildContext context, GoRouterState state) {
return null;
},
);
},
);
test(
'throws when a GoRoute with a different parentNavigatorKey '
'exists between a GoRoute with a parentNavigatorKey and '
'its ShellRoute ancestor',
() {
final GlobalKey<NavigatorState> root =
GlobalKey<NavigatorState>(debugLabel: 'root');
final GlobalKey<NavigatorState> shell =
GlobalKey<NavigatorState>(debugLabel: 'shell');
final GlobalKey<NavigatorState> shell2 =
GlobalKey<NavigatorState>(debugLabel: 'shell2');
expect(
() => RouteConfiguration(
navigatorKey: root,
routes: <RouteBase>[
ShellRoute(
navigatorKey: shell,
routes: <RouteBase>[
GoRoute(
path: '/',
builder: _mockScreenBuilder,
routes: <RouteBase>[
GoRoute(
path: 'a',
parentNavigatorKey: root,
builder: _mockScreenBuilder,
routes: <RouteBase>[
ShellRoute(
navigatorKey: shell2,
routes: <RouteBase>[
GoRoute(
path: 'b',
builder: _mockScreenBuilder,
routes: <RouteBase>[
GoRoute(
path: 'c',
builder: _mockScreenBuilder,
parentNavigatorKey: shell,
),
],
),
],
),
],
),
],
),
],
),
],
redirectLimit: 10,
topRedirect: (BuildContext context, GoRouterState state) {
return null;
},
),
throwsAssertionError,
);
},
);
test('does not throw when ShellRoute is the child of another ShellRoute',
() {
final GlobalKey<NavigatorState> root =
GlobalKey<NavigatorState>(debugLabel: 'root');
RouteConfiguration(
routes: <RouteBase>[
ShellRoute(
builder: _mockShellBuilder,
routes: <RouteBase>[
ShellRoute(
builder: _mockShellBuilder,
routes: <GoRoute>[
GoRoute(
path: '/a',
builder: _mockScreenBuilder,
),
],
),
GoRoute(
path: '/b',
builder: _mockScreenBuilder,
),
],
),
GoRoute(
path: '/c',
builder: _mockScreenBuilder,
),
],
redirectLimit: 10,
topRedirect: (BuildContext context, GoRouterState state) {
return null;
},
navigatorKey: root,
);
});
test(
'Does not throw with valid parentNavigatorKey configuration',
() {
final GlobalKey<NavigatorState> root =
GlobalKey<NavigatorState>(debugLabel: 'root');
final GlobalKey<NavigatorState> shell =
GlobalKey<NavigatorState>(debugLabel: 'shell');
final GlobalKey<NavigatorState> shell2 =
GlobalKey<NavigatorState>(debugLabel: 'shell2');
RouteConfiguration(
navigatorKey: root,
routes: <RouteBase>[
ShellRoute(
navigatorKey: shell,
routes: <RouteBase>[
GoRoute(
path: '/',
builder: _mockScreenBuilder,
routes: <RouteBase>[
GoRoute(
path: 'a',
builder: _mockScreenBuilder,
parentNavigatorKey: root,
routes: <RouteBase>[
ShellRoute(
navigatorKey: shell2,
routes: <RouteBase>[
GoRoute(
path: 'b',
builder: _mockScreenBuilder,
routes: <RouteBase>[
GoRoute(
path: 'b',
builder: _mockScreenBuilder,
parentNavigatorKey: shell2,
),
],
),
],
),
],
),
],
),
],
),
],
redirectLimit: 10,
topRedirect: (BuildContext context, GoRouterState state) {
return null;
},
);
},
);
test('throws when ShellRoute contains a GoRoute with a parentNavigatorKey',
() {
final GlobalKey<NavigatorState> root =
GlobalKey<NavigatorState>(debugLabel: 'root');
expect(
() {
RouteConfiguration(
navigatorKey: root,
routes: <RouteBase>[
ShellRoute(
routes: <RouteBase>[
GoRoute(
path: '/a',
builder: _mockScreenBuilder,
parentNavigatorKey: root,
),
],
),
],
redirectLimit: 10,
topRedirect: (BuildContext context, GoRouterState state) {
return null;
},
);
},
throwsAssertionError,
);
});
test(
'All known route strings returned by debugKnownRoutes are correct',
() {
final GlobalKey<NavigatorState> root =
GlobalKey<NavigatorState>(debugLabel: 'root');
final GlobalKey<NavigatorState> shell =
GlobalKey<NavigatorState>(debugLabel: 'shell');
expect(
RouteConfiguration(
navigatorKey: root,
routes: <RouteBase>[
GoRoute(
path: '/a',
parentNavigatorKey: root,
builder: _mockScreenBuilder,
routes: <RouteBase>[
ShellRoute(
navigatorKey: shell,
builder: _mockShellBuilder,
routes: <RouteBase>[
GoRoute(
path: 'b',
parentNavigatorKey: shell,
builder: _mockScreenBuilder,
),
GoRoute(
path: 'c',
parentNavigatorKey: shell,
builder: _mockScreenBuilder,
),
],
),
],
),
GoRoute(
path: '/d',
parentNavigatorKey: root,
builder: _mockScreenBuilder,
routes: <RouteBase>[
GoRoute(
path: 'e',
parentNavigatorKey: root,
builder: _mockScreenBuilder,
routes: <RouteBase>[
GoRoute(
path: 'f',
parentNavigatorKey: root,
builder: _mockScreenBuilder,
),
],
),
],
),
],
redirectLimit: 10,
topRedirect: (BuildContext context, GoRouterState state) {
return null;
},
).debugKnownRoutes(),
'Full paths for routes:\n'
' => /a\n'
' => /a/b\n'
' => /a/c\n'
' => /d\n'
' => /d/e\n'
' => /d/e/f\n',
);
},
);
});
}
class _MockScreen extends StatelessWidget {
const _MockScreen({super.key});
@override
Widget build(BuildContext context) => const Placeholder();
}
Widget _mockScreenBuilder(BuildContext context, GoRouterState state) =>
_MockScreen(key: state.pageKey);
Widget _mockShellBuilder(
BuildContext context, GoRouterState state, Widget child) =>
child;