Skip to content

Commit fb97c6c

Browse files
Add sample data dropdown to landing screen for use in integration tests (#5024)
1 parent 0febe65 commit fb97c6c

File tree

4 files changed

+123
-20
lines changed

4 files changed

+123
-20
lines changed

packages/devtools_app/lib/main.dart

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,19 +20,23 @@ import 'src/shared/feature_flags.dart';
2020
import 'src/shared/globals.dart';
2121
import 'src/shared/preferences.dart';
2222
import 'src/shared/primitives/url_utils.dart';
23+
import 'src/shared/primitives/utils.dart';
2324

2425
void main() async {
2526
await runDevTools();
2627
}
2728

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

3337
usePathUrlStrategy();
3438

35-
// This may be from our Flutter integration tests. Since we call
39+
// This may be set to true from our Flutter integration tests. Since we call
3640
// [runDevTools] from Dart code, we cannot set the 'enable_experiments'
3741
// environment variable before calling [runDevTools].
3842
if (shouldEnableExperiments) {
@@ -61,7 +65,11 @@ Future<void> runDevTools({bool shouldEnableExperiments = false}) async {
6165
runApp(
6266
ProviderScope(
6367
observers: const [ErrorLoggerObserver()],
64-
child: DevToolsApp(defaultScreens, await analyticsController),
68+
child: DevToolsApp(
69+
defaultScreens,
70+
await analyticsController,
71+
sampleData: sampleData,
72+
),
6573
),
6674
);
6775
});

packages/devtools_app/lib/src/app.dart

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ import 'shared/console/primitives/simple_items.dart';
4747
import 'shared/dialogs.dart';
4848
import 'shared/globals.dart';
4949
import 'shared/primitives/auto_dispose.dart';
50+
import 'shared/primitives/utils.dart';
5051
import 'shared/routing.dart';
5152
import 'shared/screen.dart';
5253
import 'shared/snapshot_screen.dart';
@@ -65,11 +66,13 @@ const showVmDeveloperMode = false;
6566
class DevToolsApp extends StatefulWidget {
6667
const DevToolsApp(
6768
this.screens,
68-
this.analyticsController,
69-
);
69+
this.analyticsController, {
70+
this.sampleData = const [],
71+
});
7072

7173
final List<DevToolsScreen> screens;
7274
final AnalyticsController analyticsController;
75+
final List<DevToolsJsonFile> sampleData;
7376

7477
@override
7578
State<DevToolsApp> createState() => DevToolsAppState();
@@ -208,7 +211,7 @@ class DevToolsAppState extends State<DevToolsApp> with AutoDisposeMixin {
208211
ReportFeedbackButton(),
209212
OpenAboutAction(),
210213
],
211-
child: LandingScreenBody(),
214+
child: LandingScreenBody(sampleData: widget.sampleData),
212215
);
213216
}
214217

packages/devtools_app/lib/src/framework/landing_screen.dart

Lines changed: 71 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import 'dart:async';
66

77
import 'package:devtools_shared/devtools_shared.dart';
8+
import 'package:flutter/foundation.dart';
89
import 'package:flutter/material.dart';
910
import 'package:provider/provider.dart';
1011
import 'package:shared_preferences/shared_preferences.dart';
@@ -30,6 +31,10 @@ import 'framework_core.dart';
3031
/// available as well as to provide access to other functionality that does not
3132
/// require a connected Dart application.
3233
class LandingScreenBody extends StatefulWidget {
34+
const LandingScreenBody({this.sampleData = const []});
35+
36+
final List<DevToolsJsonFile> sampleData;
37+
3338
@override
3439
State<LandingScreenBody> createState() => _LandingScreenBodyState();
3540
}
@@ -45,12 +50,12 @@ class _LandingScreenBodyState extends State<LandingScreenBody> {
4550
Widget build(BuildContext context) {
4651
return Scrollbar(
4752
child: ListView(
48-
children: const [
49-
ConnectDialog(),
50-
SizedBox(height: defaultSpacing),
51-
ImportFileInstructions(),
52-
SizedBox(height: defaultSpacing),
53-
AppSizeToolingInstructions(),
53+
children: [
54+
const ConnectDialog(),
55+
const SizedBox(height: defaultSpacing),
56+
ImportFileInstructions(sampleData: widget.sampleData),
57+
const SizedBox(height: defaultSpacing),
58+
const AppSizeToolingInstructions(),
5459
],
5560
),
5661
);
@@ -247,7 +252,10 @@ class _ConnectDialogState extends State<ConnectDialog>
247252
}
248253

249254
class ImportFileInstructions extends StatelessWidget {
250-
const ImportFileInstructions({Key? key}) : super(key: key);
255+
const ImportFileInstructions({Key? key, this.sampleData = const []})
256+
: super(key: key);
257+
258+
final List<DevToolsJsonFile> sampleData;
251259

252260
@override
253261
Widget build(BuildContext context) {
@@ -275,6 +283,10 @@ class ImportFileInstructions extends StatelessWidget {
275283
iconData: Icons.file_upload,
276284
),
277285
),
286+
if (sampleData.isNotEmpty && !kReleaseMode) ...[
287+
const SizedBox(height: defaultSpacing),
288+
SampleDataDropDownButton(sampleData: sampleData),
289+
]
278290
],
279291
),
280292
);
@@ -335,3 +347,55 @@ class AppSizeToolingInstructions extends StatelessWidget {
335347
DevToolsRouterDelegate.of(context).navigate(appSizePageId);
336348
}
337349
}
350+
351+
class SampleDataDropDownButton extends StatefulWidget {
352+
const SampleDataDropDownButton({
353+
super.key,
354+
this.sampleData = const [],
355+
});
356+
357+
final List<DevToolsJsonFile> sampleData;
358+
359+
@override
360+
State<SampleDataDropDownButton> createState() =>
361+
_SampleDataDropDownButtonState();
362+
}
363+
364+
class _SampleDataDropDownButtonState extends State<SampleDataDropDownButton> {
365+
DevToolsJsonFile? value;
366+
367+
@override
368+
Widget build(BuildContext context) {
369+
return Row(
370+
children: [
371+
RoundedDropDownButton<DevToolsJsonFile>(
372+
value: value,
373+
items: [
374+
for (final data in widget.sampleData) _buildMenuItem(data),
375+
],
376+
onChanged: (file) => setState(() {
377+
value = file;
378+
}),
379+
),
380+
const SizedBox(width: defaultSpacing),
381+
ElevatedButton(
382+
onPressed: value == null
383+
? null
384+
: () => Provider.of<ImportController>(context, listen: false)
385+
.importData(value!),
386+
child: const MaterialIconLabel(
387+
label: 'Load sample data',
388+
iconData: Icons.file_upload,
389+
),
390+
),
391+
],
392+
);
393+
}
394+
395+
DropdownMenuItem<DevToolsJsonFile> _buildMenuItem(DevToolsJsonFile file) {
396+
return DropdownMenuItem<DevToolsJsonFile>(
397+
value: file,
398+
child: Text(file.path),
399+
);
400+
}
401+
}

packages/devtools_app/test/shared/landing_screen_test.dart

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,10 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5+
import 'package:devtools_app/devtools_app.dart';
56
import 'package:devtools_app/src/framework/landing_screen.dart';
6-
import 'package:devtools_app/src/service/service_manager.dart';
7-
import 'package:devtools_app/src/shared/config_specific/ide_theme/ide_theme.dart';
8-
import 'package:devtools_app/src/shared/globals.dart';
97
import 'package:devtools_test/devtools_test.dart';
10-
import 'package:flutter/cupertino.dart';
8+
import 'package:flutter/material.dart';
119
import 'package:flutter_test/flutter_test.dart';
1210

1311
void main() {
@@ -20,8 +18,38 @@ void main() {
2018
'Landing screen displays without error', const Size(2000.0, 2000.0),
2119
(WidgetTester tester) async {
2220
// Build our app and trigger a frame.
23-
await tester.pumpWidget(wrap(LandingScreenBody()));
24-
expect(find.text('Connect to a Running App'), findsOneWidget);
25-
expect(find.text('App Size Tooling'), findsOneWidget);
21+
await tester.pumpWidget(wrap(const LandingScreenBody()));
22+
expect(find.byType(ConnectDialog), findsOneWidget);
23+
expect(find.byType(ImportFileInstructions), findsOneWidget);
24+
expect(find.byType(SampleDataDropDownButton), findsNothing);
25+
expect(find.byType(AppSizeToolingInstructions), findsOneWidget);
26+
});
27+
28+
testWidgetsWithWindowSize(
29+
'Landing screen displays sample data picker', const Size(2000.0, 2000.0),
30+
(WidgetTester tester) async {
31+
// Build our app and trigger a frame.
32+
await tester.pumpWidget(
33+
wrap(
34+
LandingScreenBody(
35+
sampleData: [
36+
DevToolsJsonFile(
37+
name: 'test-data',
38+
lastModifiedTime: DateTime.now(),
39+
data: <String, Object?>{},
40+
),
41+
],
42+
),
43+
),
44+
);
45+
expect(find.byType(ConnectDialog), findsOneWidget);
46+
expect(find.byType(ImportFileInstructions), findsOneWidget);
47+
expect(find.byType(SampleDataDropDownButton), findsOneWidget);
48+
expect(find.byType(AppSizeToolingInstructions), findsOneWidget);
49+
50+
await tester.tap(find.byType(DropdownButton<DevToolsJsonFile>));
51+
await tester.pumpAndSettle();
52+
53+
expect(find.text('test-data'), findsNWidgets(2));
2654
});
2755
}

0 commit comments

Comments
 (0)