Skip to content

Commit 7fb09d5

Browse files
Create StubDevToolsExtensions class for use in debug and in tests (#7625)
1 parent 3d89cb3 commit 7fb09d5

File tree

12 files changed

+285
-85
lines changed

12 files changed

+285
-85
lines changed

packages/devtools_app/benchmark/web_bundle_size_test.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import 'package:path/path.dart' as path;
1111
import 'package:test/test.dart';
1212

1313
// Benchmark size in kB.
14-
const int bundleSizeBenchmark = 4800;
14+
const int bundleSizeBenchmark = 5000;
1515
const int gzipBundleSizeBenchmark = 1450;
1616

1717
void main() {

packages/devtools_app/integration_test/test/live_connection/devtools_extensions_test.dart

Lines changed: 49 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,16 @@ void main() {
3737
await pumpAndConnectDevTools(tester, testApp);
3838
resetDevToolsExtensionEnabledStates();
3939

40-
expect(extensionService.availableExtensions.value.length, 3);
41-
expect(extensionService.visibleExtensions.value.length, 3);
40+
expect(extensionService.availableExtensions.value.length, 5);
41+
expect(extensionService.visibleExtensions.value.length, 5);
4242
await _verifyExtensionsSettingsMenu(
4343
tester,
4444
[
45-
ExtensionEnabledState.none,
46-
ExtensionEnabledState.none,
47-
ExtensionEnabledState.none,
45+
ExtensionEnabledState.none, // bar
46+
ExtensionEnabledState.none, // baz
47+
ExtensionEnabledState.none, // foo
48+
ExtensionEnabledState.none, // provider
49+
ExtensionEnabledState.none, // some_tool
4850
],
4951
closeMenuWhenDone: false,
5052
);
@@ -62,16 +64,18 @@ void main() {
6264
await _verifyExtensionsSettingsMenu(
6365
tester,
6466
[
65-
ExtensionEnabledState.enabled,
66-
ExtensionEnabledState.none,
67-
ExtensionEnabledState.none,
67+
ExtensionEnabledState.enabled, // bar
68+
ExtensionEnabledState.none, // baz
69+
ExtensionEnabledState.none, // foo
70+
ExtensionEnabledState.none, // provider
71+
ExtensionEnabledState.none, // some_tool
6872
],
6973
);
7074

71-
await _verifyContextMenuActions(tester);
75+
await _verifyContextMenuActionsAndDisable(tester);
7276

73-
expect(extensionService.availableExtensions.value.length, 3);
74-
expect(extensionService.visibleExtensions.value.length, 2);
77+
expect(extensionService.availableExtensions.value.length, 5);
78+
expect(extensionService.visibleExtensions.value.length, 4);
7579
await _verifyExtensionTabVisibility(
7680
tester,
7781
extensionIndex: 0,
@@ -80,22 +84,24 @@ void main() {
8084
await _verifyExtensionsSettingsMenu(
8185
tester,
8286
[
83-
ExtensionEnabledState.disabled,
84-
ExtensionEnabledState.none,
85-
ExtensionEnabledState.none,
87+
ExtensionEnabledState.disabled, // bar
88+
ExtensionEnabledState.none, // baz
89+
ExtensionEnabledState.none, // foo
90+
ExtensionEnabledState.none, // provider
91+
ExtensionEnabledState.none, // some_tool
8692
],
8793
);
8894

89-
// Foo extension. Hide immediately, then re-enable from extensions menu.
95+
// Baz extension. Hide immediately.
9096
await _switchToExtensionScreen(
9197
tester,
9298
extensionIndex: 1,
9399
initialLoad: true,
94100
);
95101
await _answerEnableExtensionPrompt(tester, enable: false);
96102

97-
expect(extensionService.availableExtensions.value.length, 3);
98-
expect(extensionService.visibleExtensions.value.length, 1);
103+
expect(extensionService.availableExtensions.value.length, 5);
104+
expect(extensionService.visibleExtensions.value.length, 3);
99105
await _verifyExtensionTabVisibility(
100106
tester,
101107
extensionIndex: 1,
@@ -104,31 +110,36 @@ void main() {
104110
await _verifyExtensionsSettingsMenu(
105111
tester,
106112
[
107-
ExtensionEnabledState.disabled,
108-
ExtensionEnabledState.disabled,
109-
ExtensionEnabledState.none,
113+
ExtensionEnabledState.disabled, // bar
114+
ExtensionEnabledState.disabled, // baz
115+
ExtensionEnabledState.none, // foo
116+
ExtensionEnabledState.none, // provider
117+
ExtensionEnabledState.none, // some_tool
110118
],
111119
);
112120

121+
// Re-enable Baz extension from the extensions settings menu.
113122
logStatus('verify we can re-enable an extension from the settings menu');
114123
await _changeExtensionSetting(tester, extensionIndex: 1, enable: true);
115124

116-
expect(extensionService.availableExtensions.value.length, 3);
117-
expect(extensionService.visibleExtensions.value.length, 2);
125+
expect(extensionService.availableExtensions.value.length, 5);
126+
expect(extensionService.visibleExtensions.value.length, 4);
118127
await _switchToExtensionScreen(tester, extensionIndex: 1);
119128
expect(find.byType(EnableExtensionPrompt), findsNothing);
120129
expect(find.byType(EmbeddedExtensionView), findsOneWidget);
121130
expect(find.byType(HtmlElementView), findsOneWidget);
122131
await _verifyExtensionsSettingsMenu(
123132
tester,
124133
[
125-
ExtensionEnabledState.disabled,
126-
ExtensionEnabledState.enabled,
127-
ExtensionEnabledState.none,
134+
ExtensionEnabledState.disabled, // bar
135+
ExtensionEnabledState.enabled, // baz
136+
ExtensionEnabledState.none, // foo
137+
ExtensionEnabledState.none, // provider
138+
ExtensionEnabledState.none, // some_tool
128139
],
129140
);
130141

131-
// Provider extension. Disable directly from settings menu.
142+
// Foo extension. Disable directly from settings menu.
132143
logStatus(
133144
'verify we can disable an extension screen directly from the settings menu',
134145
);
@@ -140,8 +151,8 @@ void main() {
140151

141152
logStatus('disable the extension from the settings menu');
142153
await _changeExtensionSetting(tester, extensionIndex: 2, enable: false);
143-
expect(extensionService.availableExtensions.value.length, 3);
144-
expect(extensionService.visibleExtensions.value.length, 1);
154+
expect(extensionService.availableExtensions.value.length, 5);
155+
expect(extensionService.visibleExtensions.value.length, 3);
145156
await _verifyExtensionTabVisibility(
146157
tester,
147158
extensionIndex: 2,
@@ -150,9 +161,11 @@ void main() {
150161
await _verifyExtensionsSettingsMenu(
151162
tester,
152163
[
153-
ExtensionEnabledState.disabled,
154-
ExtensionEnabledState.enabled,
155-
ExtensionEnabledState.disabled,
164+
ExtensionEnabledState.disabled, // bar
165+
ExtensionEnabledState.enabled, // baz
166+
ExtensionEnabledState.disabled, // foo
167+
ExtensionEnabledState.none, // provider
168+
ExtensionEnabledState.none, // some_tool
156169
],
157170
);
158171
});
@@ -222,7 +235,7 @@ Future<void> _answerEnableExtensionPrompt(
222235
);
223236
}
224237

225-
Future<void> _verifyContextMenuActions(WidgetTester tester) async {
238+
Future<void> _verifyContextMenuActionsAndDisable(WidgetTester tester) async {
226239
logStatus('verify we can perform context menu actions');
227240
final contextMenuFinder = find.descendant(
228241
of: find.byType(EmbeddedExtensionHeader),
@@ -263,6 +276,7 @@ Future<void> _verifyExtensionsSettingsMenu(
263276
.cast<DevToolsToggleButtonGroup>()
264277
.toList();
265278
for (int i = 0; i < toggleButtonGroups.length; i++) {
279+
logStatus('verify extension settings toggle button states (index $i)');
266280
final group = toggleButtonGroups[i];
267281
final expectedStates = switch (enabledStates[i]) {
268282
ExtensionEnabledState.enabled => [true, false],
@@ -316,12 +330,12 @@ Future<void> _changeExtensionSetting(
316330
}
317331

318332
Future<void> _verifyExtensionVisibilitySetting(WidgetTester tester) async {
319-
logStatus('verify we can toggle the show only enabled extensions setting');
333+
logStatus('verify we can toggle the "show only enabled extensions" setting');
320334
expect(
321335
preferences.devToolsExtensions.showOnlyEnabledExtensions.value,
322336
isFalse,
323337
);
324-
expect(extensionService.visibleExtensions.value.length, 3);
338+
expect(extensionService.visibleExtensions.value.length, 5);
325339
// No need to open the settings menu as it should already be open.
326340
await _toggleShowOnlyEnabledExtensions(tester);
327341
expect(
@@ -336,7 +350,7 @@ Future<void> _verifyExtensionVisibilitySetting(WidgetTester tester) async {
336350
preferences.devToolsExtensions.showOnlyEnabledExtensions.value,
337351
isFalse,
338352
);
339-
expect(extensionService.visibleExtensions.value.length, 3);
353+
expect(extensionService.visibleExtensions.value.length, 5);
340354

341355
await _closeExtensionSettingsMenu(tester);
342356
}

packages/devtools_app/lib/src/extensions/extension_settings.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ class ExtensionSettingsDialog extends StatelessWidget {
4040
final theme = Theme.of(context);
4141
final availableExtensions = extensionService.availableExtensions.value;
4242
// This dialog needs a fixed height because it contains a scrollable list.
43-
final dialogHeight = scaleByFontFactor(300.0);
43+
final dialogHeight =
44+
anyTestMode ? scaleByFontFactor(1000.0) : scaleByFontFactor(300.0);
4445
return DevToolsDialog(
4546
title: const DialogTitleText('DevTools Extensions'),
4647
content: SizedBox(

packages/devtools_app/lib/src/shared/development_helpers.dart

Lines changed: 93 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ final debugDevToolsExtensions =
5555
const _debugDevToolsExtensions = false;
5656

5757
List<DevToolsExtensionConfig> debugHandleRefreshAvailableExtensions() =>
58-
debugExtensions;
58+
StubDevToolsExtensions.extensions;
5959

6060
ExtensionEnabledState debugHandleExtensionEnabledState({
6161
required String extensionName,
@@ -79,10 +79,11 @@ void resetDevToolsExtensionEnabledStates() =>
7979
/// server connection.
8080
final stubExtensionEnabledStates = <String, ExtensionEnabledState>{};
8181

82-
/// Stubbed extensions so we can develop DevTools Extensions without a server
83-
/// connection.
84-
final List<DevToolsExtensionConfig> debugExtensions = [
85-
DevToolsExtensionConfig.parse({
82+
// ignore: avoid_classes_with_only_static_members, useful for testing.
83+
abstract class StubDevToolsExtensions {
84+
/// Extension for package:foo detected from a running app that requires a
85+
/// connected app.
86+
static final fooExtension = DevToolsExtensionConfig.parse({
8687
DevToolsExtensionConfig.nameKey: 'foo',
8788
DevToolsExtensionConfig.issueTrackerKey: 'www.google.com',
8889
DevToolsExtensionConfig.versionKey: '1.0.0',
@@ -91,8 +92,11 @@ final List<DevToolsExtensionConfig> debugExtensions = [
9192
DevToolsExtensionConfig.devtoolsOptionsUriKey: '/path/to/options/file',
9293
DevToolsExtensionConfig.isPubliclyHostedKey: 'false',
9394
DevToolsExtensionConfig.detectedFromStaticContextKey: 'false',
94-
}),
95-
DevToolsExtensionConfig.parse({
95+
});
96+
97+
/// Extension for package:provider detected from a running app that requires a
98+
/// connected app.
99+
static final providerExtension = DevToolsExtensionConfig.parse({
96100
DevToolsExtensionConfig.nameKey: 'provider',
97101
DevToolsExtensionConfig.issueTrackerKey:
98102
'https://github.com/rrousselGit/provider/issues',
@@ -102,9 +106,25 @@ final List<DevToolsExtensionConfig> debugExtensions = [
102106
DevToolsExtensionConfig.devtoolsOptionsUriKey: '/path/to/options/file',
103107
DevToolsExtensionConfig.isPubliclyHostedKey: 'true',
104108
DevToolsExtensionConfig.detectedFromStaticContextKey: 'false',
105-
}),
106-
// Static extension.
107-
DevToolsExtensionConfig.parse({
109+
});
110+
111+
/// Extension for package:some_tool detected from a running app, but that does
112+
/// not require a connected app.
113+
static final someToolExtension = DevToolsExtensionConfig.parse({
114+
DevToolsExtensionConfig.nameKey: 'some_tool',
115+
DevToolsExtensionConfig.issueTrackerKey: 'www.google.com',
116+
DevToolsExtensionConfig.versionKey: '1.0.0',
117+
DevToolsExtensionConfig.materialIconCodePointKey: '0xe00c',
118+
DevToolsExtensionConfig.requiresConnectionKey: 'false',
119+
DevToolsExtensionConfig.extensionAssetsUriKey: '/path/to/some_tool',
120+
DevToolsExtensionConfig.devtoolsOptionsUriKey: '/path/to/options/file',
121+
DevToolsExtensionConfig.isPubliclyHostedKey: 'false',
122+
DevToolsExtensionConfig.detectedFromStaticContextKey: 'false',
123+
});
124+
125+
/// Extension for package:bar detected from a static context that does not
126+
/// require a connected app.
127+
static final barExtension = DevToolsExtensionConfig.parse({
108128
DevToolsExtensionConfig.nameKey: 'bar',
109129
DevToolsExtensionConfig.issueTrackerKey: 'www.google.com',
110130
DevToolsExtensionConfig.versionKey: '2.0.0',
@@ -114,8 +134,69 @@ final List<DevToolsExtensionConfig> debugExtensions = [
114134
DevToolsExtensionConfig.devtoolsOptionsUriKey: '/path/to/options/file',
115135
DevToolsExtensionConfig.isPubliclyHostedKey: 'false',
116136
DevToolsExtensionConfig.detectedFromStaticContextKey: 'true',
117-
}),
118-
];
137+
});
138+
139+
// TODO(kenz): uncomment when static extensions are supported, which includes
140+
// logic to de-duplicate extensions.
141+
// /// Extension for package:bar detected from a static context that does not
142+
// /// require a connected app and that is also a newer version of another static
143+
// /// extension.
144+
// static final newerBarExtension = DevToolsExtensionConfig.parse({
145+
// DevToolsExtensionConfig.nameKey: 'bar',
146+
// DevToolsExtensionConfig.issueTrackerKey: 'www.google.com',
147+
// DevToolsExtensionConfig.versionKey: '2.1.0', // Newer version.
148+
// DevToolsExtensionConfig.materialIconCodePointKey: 0xe638,
149+
// DevToolsExtensionConfig.requiresConnectionKey: 'false',
150+
// DevToolsExtensionConfig.extensionAssetsUriKey: '/path/to/bar',
151+
// DevToolsExtensionConfig.devtoolsOptionsUriKey: '/path/to/options/file',
152+
// DevToolsExtensionConfig.isPubliclyHostedKey: 'false',
153+
// DevToolsExtensionConfig.detectedFromStaticContextKey: 'true',
154+
// });
155+
156+
/// Extension for package:baz detected from a static context that requires a
157+
/// connected app.
158+
static final bazExtension = DevToolsExtensionConfig.parse({
159+
DevToolsExtensionConfig.nameKey: 'baz',
160+
DevToolsExtensionConfig.issueTrackerKey: 'www.google.com',
161+
DevToolsExtensionConfig.versionKey: '1.0.0',
162+
DevToolsExtensionConfig.materialIconCodePointKey: 0xe716,
163+
DevToolsExtensionConfig.extensionAssetsUriKey: '/path/to/baz',
164+
DevToolsExtensionConfig.devtoolsOptionsUriKey: '/path/to/options/file',
165+
DevToolsExtensionConfig.isPubliclyHostedKey: 'false',
166+
DevToolsExtensionConfig.detectedFromStaticContextKey: 'true',
167+
});
168+
169+
// TODO(kenz): uncomment when static extensions are supported, which includes
170+
// logic to de-duplicate extensions.
171+
// /// Extension for package:foo detected from a static context that is a duplicate
172+
// /// of a runtime extension [fooExtension].
173+
// static final duplicateFooExtension = DevToolsExtensionConfig.parse({
174+
// DevToolsExtensionConfig.nameKey: 'foo',
175+
// DevToolsExtensionConfig.issueTrackerKey: 'www.google.com',
176+
// DevToolsExtensionConfig.versionKey: '1.0.0',
177+
// DevToolsExtensionConfig.materialIconCodePointKey: '0xe0b1',
178+
// DevToolsExtensionConfig.extensionAssetsUriKey: '/path/to/foo',
179+
// DevToolsExtensionConfig.devtoolsOptionsUriKey: '/path/to/options/file',
180+
// DevToolsExtensionConfig.isPubliclyHostedKey: 'false',
181+
// DevToolsExtensionConfig.detectedFromStaticContextKey: 'true',
182+
// });
183+
184+
/// Stubbed extensions so we can develop DevTools Extensions without a server
185+
/// connection.
186+
static final List<DevToolsExtensionConfig> extensions = [
187+
fooExtension,
188+
providerExtension,
189+
someToolExtension,
190+
barExtension,
191+
// TODO(kenz): uncomment when static extensions are supported, which
192+
// includes logic to de-duplicate extensions.
193+
// newerBarExtension,
194+
bazExtension,
195+
// TODO(kenz): uncomment when static extensions are supported, which
196+
// includes logic to de-duplicate extensions.
197+
// duplicateFooExtension,
198+
];
199+
}
119200

120201
/// Enable this flag to debug the DevTools survey logic.
121202
///

packages/devtools_app/lib/src/shared/globals.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,3 +87,6 @@ void setStagerMode() {
8787
_stagerMode = true;
8888
}
8989
}
90+
91+
/// Whether DevTools is being run in any type of testing mode.
92+
bool get anyTestMode => _integrationTestMode || _testMode || _stagerMode;

packages/devtools_app/test/extensions/extension_analytics_test.dart

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,15 @@
33
// found in the LICENSE file.
44

55
import 'package:devtools_app/src/shared/analytics/constants.dart';
6+
import 'package:devtools_app/src/shared/development_helpers.dart';
67
import 'package:flutter_test/flutter_test.dart';
78

8-
import '../test_infra/test_data/extensions.dart';
9-
109
void main() {
1110
group('DevTools extension analytics', () {
1211
test(
1312
'uses extension name for public package',
1413
() {
15-
final public = providerExtension;
14+
final public = StubDevToolsExtensions.providerExtension;
1615
expect(public.isPubliclyHosted, true);
1716
expect(public.name, 'provider');
1817
expect(public.analyticsSafeName, 'provider');
@@ -51,7 +50,7 @@ void main() {
5150
test(
5251
'does not use extension name for private package',
5352
() {
54-
final private = fooExtension;
53+
final private = StubDevToolsExtensions.fooExtension;
5554
expect(private.isPubliclyHosted, false);
5655
expect(private.name, 'foo');
5756
expect(private.analyticsSafeName, 'private');

0 commit comments

Comments
 (0)