forked from flutter/devtools
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathintegration_test_utils.dart
More file actions
177 lines (154 loc) · 5.98 KB
/
integration_test_utils.dart
File metadata and controls
177 lines (154 loc) · 5.98 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
// Copyright 2022 The Flutter Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file or at https://developers.google.com/open-source/licenses/bsd.
import 'dart:convert';
import 'dart:ui' as ui;
import 'package:devtools_app/devtools_app.dart';
import 'package:devtools_app/main.dart' as app;
import 'package:devtools_app_shared/ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import '../helpers/actions.dart';
import '../helpers/utils.dart';
import '../test_data/sample_data.dart';
/// Required to have multiple test cases in a file.
Future<void> resetHistory() async {
await (ui.PlatformDispatcher.instance.views.single
// ignore: avoid-dynamic, necessary here.
as dynamic /* EngineFlutterWindow */ )
// This dynamic call is necessary as `EngineFlutterWindow` is declared in
// the web-specific implementation of the Flutter Engine, at
// `lib/web_ui/lib/src/engine/window.dart` in the Flutter engine
// repository.
.resetHistory();
}
Future<void> pumpAndConnectDevTools(
WidgetTester tester,
TestApp testApp,
) async {
await pumpDevTools(tester);
await connectToTestApp(tester, testApp);
}
Future<void> closeReleaseNotesViewer(WidgetTester tester) async {
// If the release notes viewer is open, close it.
final releaseNotesView = tester.widget<ReleaseNotesViewer>(
find.byType(ReleaseNotesViewer),
);
if (releaseNotesView.controller.isVisible.value) {
final closeReleaseNotesButton = find.descendant(
of: find.byType(ReleaseNotesViewer),
matching: find.byType(IconButton),
);
expect(closeReleaseNotesButton, findsOneWidget);
await tester.tap(closeReleaseNotesButton);
}
}
void _verifyFooterColor(WidgetTester tester, Color? expectedColor) {
final Container statusLineContainer = tester.widget(
find
.descendant(
of: find.byType(StatusLine),
matching: find.byType(Container),
)
.first,
);
expect(
(statusLineContainer.decoration! as BoxDecoration).color,
expectedColor,
);
}
Future<void> pumpDevTools(WidgetTester tester) async {
// TODO(kenz): how can we share code across integration_test/test and
// integration_test/test_infra? When trying to import, we get an error:
// Error when reading 'org-dartlang-app:/test_infra/shared.dart': File not found
const shouldEnableExperiments = bool.fromEnvironment('enable_experiments');
app.externalRunDevTools(
integrationTestMode: true,
// ignore: avoid_redundant_argument_values, by design
shouldEnableExperiments: shouldEnableExperiments,
sampleData: sampleData,
);
// Await a delay to ensure the widget tree has loaded.
await tester.pumpAndSettle(veryLongPumpDuration);
expect(find.byType(DevToolsApp), findsOneWidget);
await closeReleaseNotesViewer(tester);
}
Future<void> connectToTestApp(WidgetTester tester, TestApp testApp) async {
logStatus('connecting to test app');
expect(find.byType(ConnectInput), findsOneWidget);
expect(find.byType(ConnectedAppSummary), findsNothing);
_verifyFooterColor(tester, null);
final textFieldFinder = find.byType(TextField);
// TODO(https://github.com/flutter/flutter/issues/89749): use
// `tester.enterText` once this issue is fixed.
(tester.firstWidget(textFieldFinder) as TextField).controller?.text =
testApp.vmServiceUri;
await tester.tap(
find.ancestor(
of: find.text('Connect'),
matching: find.byType(DevToolsButton),
),
);
await tester.pumpAndSettle(longPumpDuration);
expect(find.byType(ConnectInput), findsNothing);
expect(find.byType(ConnectedAppSummary), findsOneWidget);
_verifyFooterColor(tester, darkColorScheme.primary);
}
Future<void> disconnectFromTestApp(WidgetTester tester) async {
logStatus('disconnect from test app');
await tester.tap(
await findTab(tester, icon: null, iconAsset: ScreenMetaData.home.iconAsset),
);
await tester.pumpAndSettle();
await tester.tap(find.byType(ConnectToNewAppButton));
await tester.pump(safePumpDuration);
}
class TestApp {
TestApp._({required this.vmServiceUri, required this.controlPort});
factory TestApp._fromJson(Map<String, Object> json) {
final serviceUri = json[serviceUriKey] as String?;
if (serviceUri == null) {
throw Exception('Cannot create a TestApp with a null service uri.');
}
final controlPort = json[controlPortKey] as int?;
return TestApp._(vmServiceUri: serviceUri, controlPort: controlPort);
}
factory TestApp.fromEnvironment() {
const testArgs = String.fromEnvironment('test_args');
final argsMap = (jsonDecode(testArgs) as Map).cast<String, Object>();
return TestApp._fromJson(argsMap);
}
static const serviceUriKey = 'service_uri';
static const controlPortKey = 'control_port';
final String vmServiceUri;
final int? controlPort;
}
Future<void> verifyScreenshot(
IntegrationTestWidgetsFlutterBinding binding,
String screenshotName, {
// TODO(https://github.com/flutter/flutter/issues/118470): remove this.
bool lastScreenshot = false,
}) async {
const updateGoldens = bool.fromEnvironment('update_goldens');
logStatus('verify $screenshotName screenshot');
await binding.takeScreenshot(screenshotName, {
'update_goldens': updateGoldens,
'last_screenshot': lastScreenshot,
});
}
/// A timeout for a "short" integration test.
///
/// Adjust as needed; this is used to override the 10-minute or infinite timeout
/// in [testWidgets].
const Timeout shortTimeout = Timeout(Duration(minutes: 2));
/// A timeout for a "medium" integration test.
///
/// Adjust as needed; this is used to override the 10-minute or infinite timeout
/// in [testWidgets].
const Timeout mediumTimeout = Timeout(Duration(minutes: 3));
/// A timeout for a "long" integration test.
///
/// Adjust as needed; this is used to override the 10-minute or infinite timeout
/// in [testWidgets].
const Timeout longTimeout = Timeout(Duration(minutes: 4));