blob: f5e0a3fd43b0afd20017f671a4015d4dd4920aef [file] [log] [blame]
// Copyright 2022 The Chromium 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:devtools_app/devtools_app.dart';
import 'package:devtools_app/src/framework/scaffold.dart';
import 'package:devtools_app/src/shared/framework_controller.dart';
import 'package:devtools_app/src/shared/survey.dart';
import 'package:devtools_app_shared/service.dart';
import 'package:devtools_app_shared/ui.dart';
import 'package:devtools_app_shared/utils.dart';
import 'package:devtools_test/devtools_test.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/mockito.dart';
void main() {
late MockServiceConnectionManager mockServiceConnection;
setUp(() {
mockServiceConnection = createMockServiceConnectionWithDefaults();
final mockServiceManager =
mockServiceConnection.serviceManager as MockServiceManager;
when(mockServiceManager.service).thenReturn(null);
when(mockServiceManager.connectedAppInitialized).thenReturn(false);
when(mockServiceManager.connectedState).thenReturn(
ValueNotifier<ConnectedState>(const ConnectedState(false)),
);
when(mockServiceManager.hasConnection).thenReturn(false);
final mockErrorBadgeManager = MockErrorBadgeManager();
when(mockServiceConnection.errorBadgeManager)
.thenReturn(mockErrorBadgeManager);
when(mockErrorBadgeManager.errorCountNotifier(any))
.thenReturn(ValueNotifier<int>(0));
setGlobal(ServiceConnectionManager, mockServiceConnection);
setGlobal(FrameworkController, FrameworkController());
setGlobal(SurveyService, SurveyService());
setGlobal(OfflineModeController, OfflineModeController());
setGlobal(IdeTheme, IdeTheme());
setGlobal(NotificationService, NotificationService());
setGlobal(BannerMessagesController, BannerMessagesController());
});
Widget wrapScaffold(Widget child) {
return wrapWithControllers(
child,
analytics: AnalyticsController(enabled: false, firstRun: false),
releaseNotes: ReleaseNotesController(),
);
}
testWidgetsWithWindowSize(
'does not show tab overflow button when screen is wide',
const Size(2000.0, 1200.0),
(WidgetTester tester) async {
await tester.pumpWidget(
wrapScaffold(
DevToolsScaffold(
page: _screen1.screenId,
screens: const [_screen1, _screen2, _screen3, _screen4, _screen5],
),
),
);
expect(find.byKey(_k1), findsOneWidget);
expect(find.byKey(_t1), findsOneWidget);
expect(find.byKey(_t2), findsOneWidget);
expect(find.byKey(_t3), findsOneWidget);
expect(find.byKey(_t4), findsOneWidget);
expect(find.byKey(_t5), findsOneWidget);
expect(find.byType(TabOverflowButton), findsNothing);
},
);
testWidgetsWithWindowSize(
'shows tab overflow button when screen is narrow',
const Size(600.0, 1200.0),
(WidgetTester tester) async {
await tester.pumpWidget(
wrapScaffold(
DevToolsScaffold(
page: _screen1.screenId,
screens: const [_screen1, _screen2, _screen3, _screen4, _screen5],
),
),
);
expect(find.byKey(_k1), findsOneWidget);
expect(find.byKey(_t1), findsOneWidget);
expect(find.byKey(_t2), findsOneWidget);
expect(find.byKey(_t3), findsNothing);
expect(find.byKey(_t4), findsNothing);
expect(find.byKey(_t5), findsNothing);
expect(find.byType(TabOverflowButton), findsOneWidget);
},
);
testWidgetsWithWindowSize(
'can select screen from tab overflow menu',
const Size(600.0, 1200.0),
(WidgetTester tester) async {
await tester.pumpWidget(
wrapScaffold(
DevToolsScaffold(
page: _screen1.screenId,
screens: const [_screen1, _screen2, _screen3, _screen4, _screen5],
),
),
);
expect(find.byKey(_k1), findsOneWidget);
expect(find.byKey(_t1), findsOneWidget);
expect(find.byKey(_t2), findsOneWidget);
expect(find.byKey(_t3), findsNothing);
expect(find.byKey(_t4), findsNothing);
expect(find.byKey(_t5), findsNothing);
expect(find.byType(TabOverflowButton), findsOneWidget);
await tester.tap(find.byType(TabOverflowButton));
await tester.pumpAndSettle();
// The overflow tabs should now be shown in the context menu.
expect(find.byKey(_t3), findsOneWidget);
expect(find.byKey(_t4), findsOneWidget);
expect(find.byKey(_t5), findsOneWidget);
expect(find.byType(SelectedTabWrapper), findsNothing);
// Select a tab in the overflow menu.
await tester.tap(find.byKey(_t5));
await tester.pumpAndSettle();
// The overflow tabs should now be hidden again.
expect(find.byKey(_t3), findsNothing);
expect(find.byKey(_t4), findsNothing);
expect(find.byKey(_t5), findsNothing);
// The [TabOverflowButton] should now show up as selected.
expect(
find.descendant(
of: find.byType(TabOverflowButton),
matching: find.byType(SelectedTabWrapper),
),
findsOneWidget,
);
expect(find.byKey(_k1), findsNothing);
expect(find.byKey(_k5), findsOneWidget);
},
);
testWidgets(
'displays no tabs when only one is given',
(WidgetTester tester) async {
await tester.pumpWidget(
wrapScaffold(
DevToolsScaffold(page: _screen1.screenId, screens: const [_screen1]),
),
);
expect(find.byKey(_k1), findsOneWidget);
expect(find.byKey(_t1), findsNothing);
},
);
testWidgets('displays only the selected tab', (WidgetTester tester) async {
await tester.pumpWidget(
wrapScaffold(
DevToolsScaffold(
page: _screen1.screenId,
screens: const [_screen1, _screen2],
),
),
);
expect(find.byKey(_k1), findsOneWidget);
expect(find.byKey(_k2), findsNothing);
// Tap on the tab for screen 2, then let the animation finish before
// checking the body is updated.
await tester.tap(find.byKey(_t2));
await tester.pumpAndSettle();
expect(find.byKey(_k1), findsNothing);
expect(find.byKey(_k2), findsOneWidget);
// Return to screen 1.
await tester.tap(find.byKey(_t1));
await tester.pumpAndSettle();
expect(find.byKey(_k1), findsOneWidget);
expect(find.byKey(_k2), findsNothing);
});
testWidgets(
'displays the requested initial page',
(WidgetTester tester) async {
await tester.pumpWidget(
wrapScaffold(
DevToolsScaffold(
screens: const [_screen1, _screen2],
page: _screen2.screenId,
),
),
);
expect(find.byKey(_k1), findsNothing);
expect(find.byKey(_k2), findsOneWidget);
},
);
}
class _TestScreen extends Screen {
const _TestScreen(
this.name,
this.key, {
bool showFloatingDebuggerControls = true,
Key? tabKey,
}) : super(
name,
title: name,
icon: Icons.computer,
tabKey: tabKey,
showFloatingDebuggerControls: showFloatingDebuggerControls,
);
final String name;
final Key key;
@override
Widget build(BuildContext context) {
return SizedBox(key: key);
}
}
// Keys and tabs for use in the test.
const _k1 = Key('body key 1');
const _k2 = Key('body key 2');
const _k3 = Key('body key 3');
const _k4 = Key('body key 4');
const _k5 = Key('body key 5');
const _t1 = Key('tab key 1');
const _t2 = Key('tab key 2');
const _t3 = Key('tab key 3');
const _t4 = Key('tab key 4');
const _t5 = Key('tab key 5');
const _screen1 = _TestScreen('screen1', _k1, tabKey: _t1);
const _screen2 = _TestScreen('screen2', _k2, tabKey: _t2);
const _screen3 = _TestScreen('screen3', _k3, tabKey: _t3);
const _screen4 = _TestScreen('screen4', _k4, tabKey: _t4);
const _screen5 = _TestScreen('screen5', _k5, tabKey: _t5);