Skip to content

Add sample data dropdown to landing screen for use in integration tests #5024

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jan 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions packages/devtools_app/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,23 @@ import 'src/shared/feature_flags.dart';
import 'src/shared/globals.dart';
import 'src/shared/preferences.dart';
import 'src/shared/primitives/url_utils.dart';
import 'src/shared/primitives/utils.dart';

void main() async {
await runDevTools();
}

Future<void> runDevTools({bool shouldEnableExperiments = false}) async {
Future<void> runDevTools({
bool shouldEnableExperiments = false,
List<DevToolsJsonFile> sampleData = const [],
}) async {
// Before switching to URL path strategy, check if this URL is in the legacy
// fragment format and redirect if necessary.
if (_handleLegacyUrl()) return;

usePathUrlStrategy();

// This may be from our Flutter integration tests. Since we call
// This may be set to true from our Flutter integration tests. Since we call
// [runDevTools] from Dart code, we cannot set the 'enable_experiments'
// environment variable before calling [runDevTools].
if (shouldEnableExperiments) {
Expand Down Expand Up @@ -61,7 +65,11 @@ Future<void> runDevTools({bool shouldEnableExperiments = false}) async {
runApp(
ProviderScope(
observers: const [ErrorLoggerObserver()],
child: DevToolsApp(defaultScreens, await analyticsController),
child: DevToolsApp(
defaultScreens,
await analyticsController,
sampleData: sampleData,
),
),
);
});
Expand Down
9 changes: 6 additions & 3 deletions packages/devtools_app/lib/src/app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import 'shared/console/primitives/simple_items.dart';
import 'shared/dialogs.dart';
import 'shared/globals.dart';
import 'shared/primitives/auto_dispose.dart';
import 'shared/primitives/utils.dart';
import 'shared/routing.dart';
import 'shared/screen.dart';
import 'shared/snapshot_screen.dart';
Expand All @@ -65,11 +66,13 @@ const showVmDeveloperMode = false;
class DevToolsApp extends StatefulWidget {
const DevToolsApp(
this.screens,
this.analyticsController,
);
this.analyticsController, {
this.sampleData = const [],
});

final List<DevToolsScreen> screens;
final AnalyticsController analyticsController;
final List<DevToolsJsonFile> sampleData;

@override
State<DevToolsApp> createState() => DevToolsAppState();
Expand Down Expand Up @@ -208,7 +211,7 @@ class DevToolsAppState extends State<DevToolsApp> with AutoDisposeMixin {
ReportFeedbackButton(),
OpenAboutAction(),
],
child: LandingScreenBody(),
child: LandingScreenBody(sampleData: widget.sampleData),
);
}

Expand Down
78 changes: 71 additions & 7 deletions packages/devtools_app/lib/src/framework/landing_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import 'dart:async';

import 'package:devtools_shared/devtools_shared.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
Expand All @@ -30,6 +31,10 @@ import 'framework_core.dart';
/// available as well as to provide access to other functionality that does not
/// require a connected Dart application.
class LandingScreenBody extends StatefulWidget {
const LandingScreenBody({this.sampleData = const []});

final List<DevToolsJsonFile> sampleData;

@override
State<LandingScreenBody> createState() => _LandingScreenBodyState();
}
Expand All @@ -45,12 +50,12 @@ class _LandingScreenBodyState extends State<LandingScreenBody> {
Widget build(BuildContext context) {
return Scrollbar(
child: ListView(
children: const [
ConnectDialog(),
SizedBox(height: defaultSpacing),
ImportFileInstructions(),
SizedBox(height: defaultSpacing),
AppSizeToolingInstructions(),
children: [
const ConnectDialog(),
const SizedBox(height: defaultSpacing),
ImportFileInstructions(sampleData: widget.sampleData),
const SizedBox(height: defaultSpacing),
const AppSizeToolingInstructions(),
],
),
);
Expand Down Expand Up @@ -247,7 +252,10 @@ class _ConnectDialogState extends State<ConnectDialog>
}

class ImportFileInstructions extends StatelessWidget {
const ImportFileInstructions({Key? key}) : super(key: key);
const ImportFileInstructions({Key? key, this.sampleData = const []})
: super(key: key);

final List<DevToolsJsonFile> sampleData;

@override
Widget build(BuildContext context) {
Expand Down Expand Up @@ -275,6 +283,10 @@ class ImportFileInstructions extends StatelessWidget {
iconData: Icons.file_upload,
),
),
if (sampleData.isNotEmpty && !kReleaseMode) ...[
const SizedBox(height: defaultSpacing),
SampleDataDropDownButton(sampleData: sampleData),
]
],
),
);
Expand Down Expand Up @@ -335,3 +347,55 @@ class AppSizeToolingInstructions extends StatelessWidget {
DevToolsRouterDelegate.of(context).navigate(appSizePageId);
}
}

class SampleDataDropDownButton extends StatefulWidget {
const SampleDataDropDownButton({
super.key,
this.sampleData = const [],
});

final List<DevToolsJsonFile> sampleData;

@override
State<SampleDataDropDownButton> createState() =>
_SampleDataDropDownButtonState();
}

class _SampleDataDropDownButtonState extends State<SampleDataDropDownButton> {
DevToolsJsonFile? value;

@override
Widget build(BuildContext context) {
return Row(
children: [
RoundedDropDownButton<DevToolsJsonFile>(
value: value,
items: [
for (final data in widget.sampleData) _buildMenuItem(data),
],
onChanged: (file) => setState(() {
value = file;
}),
),
const SizedBox(width: defaultSpacing),
ElevatedButton(
onPressed: value == null
? null
: () => Provider.of<ImportController>(context, listen: false)
.importData(value!),
child: const MaterialIconLabel(
label: 'Load sample data',
iconData: Icons.file_upload,
),
),
],
);
}

DropdownMenuItem<DevToolsJsonFile> _buildMenuItem(DevToolsJsonFile file) {
return DropdownMenuItem<DevToolsJsonFile>(
value: file,
child: Text(file.path),
);
}
}
42 changes: 35 additions & 7 deletions packages/devtools_app/test/shared/landing_screen_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,10 @@
// 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/landing_screen.dart';
import 'package:devtools_app/src/service/service_manager.dart';
import 'package:devtools_app/src/shared/config_specific/ide_theme/ide_theme.dart';
import 'package:devtools_app/src/shared/globals.dart';
import 'package:devtools_test/devtools_test.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';

void main() {
Expand All @@ -20,8 +18,38 @@ void main() {
'Landing screen displays without error', const Size(2000.0, 2000.0),
(WidgetTester tester) async {
// Build our app and trigger a frame.
await tester.pumpWidget(wrap(LandingScreenBody()));
expect(find.text('Connect to a Running App'), findsOneWidget);
expect(find.text('App Size Tooling'), findsOneWidget);
await tester.pumpWidget(wrap(const LandingScreenBody()));
expect(find.byType(ConnectDialog), findsOneWidget);
expect(find.byType(ImportFileInstructions), findsOneWidget);
expect(find.byType(SampleDataDropDownButton), findsNothing);
expect(find.byType(AppSizeToolingInstructions), findsOneWidget);
});

testWidgetsWithWindowSize(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we add a test to make sure this doesn't show in release mode?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There isn't an easy way that I'm aware of to mock the value of kReleaseMode. The only way to test this would be to add another job to our github actions that runs the test suite in release mode, which may be a bit overkill for a test this small.

'Landing screen displays sample data picker', const Size(2000.0, 2000.0),
(WidgetTester tester) async {
// Build our app and trigger a frame.
await tester.pumpWidget(
wrap(
LandingScreenBody(
sampleData: [
DevToolsJsonFile(
name: 'test-data',
lastModifiedTime: DateTime.now(),
data: <String, Object?>{},
),
],
),
),
);
expect(find.byType(ConnectDialog), findsOneWidget);
expect(find.byType(ImportFileInstructions), findsOneWidget);
expect(find.byType(SampleDataDropDownButton), findsOneWidget);
expect(find.byType(AppSizeToolingInstructions), findsOneWidget);

await tester.tap(find.byType(DropdownButton<DevToolsJsonFile>));
await tester.pumpAndSettle();

expect(find.text('test-data'), findsNWidgets(2));
});
}