Skip to content

Commit ed5c28b

Browse files
authored
Enable probes. (#3268)
1 parent bae7417 commit ed5c28b

File tree

16 files changed

+197
-28
lines changed

16 files changed

+197
-28
lines changed

.github/workflows/dartpad_ui.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,5 +36,5 @@ jobs:
3636
- run: flutter analyze
3737
- run: dart format --set-exit-if-changed .
3838
- run: flutter build web
39-
- run: flutter test
39+
- run: flutter test test/presubmit
4040
- run: sh ./tool/check_cycles.sh
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
name: package:dartpad_ui
2+
3+
permissions: read-all
4+
5+
on:
6+
schedule:
7+
- cron: '0 0 * * *' # daily
8+
9+
jobs:
10+
validate:
11+
runs-on: ubuntu-latest
12+
defaults:
13+
run:
14+
working-directory: pkgs/dartpad_ui/
15+
strategy:
16+
fail-fast: false
17+
matrix:
18+
sdk: [ beta, main ]
19+
steps:
20+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
21+
- uses: subosito/flutter-action@e938fdf56512cc96ef2f93601a5a40bde3801046
22+
with:
23+
channel: ${{ matrix.sdk }}
24+
- run: flutter --version
25+
- run: flutter pub get
26+
- run: flutter test test/probes

.vscode/launch.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@
5151
"--web-launch-url",
5252
"http://localhost:8888/?genui=true&channel=localhost",
5353
],
54-
}
54+
},
55+
{
56+
"name": "current test file",
57+
"request": "launch",
58+
"type": "dart",
59+
},
5560
],
5661
}

CONTRIBUTING.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@ To run the server, see the [dart_services readme](pkgs/dart_services/README.md).
4545

4646
To run the front-end, see the [dartpad_ui readme](pkgs/dartpad_ui/README.md).
4747

48+
## Update goldens
49+
50+
When your change requires update to [golden images](https://api.flutter.dev/flutter/flutter_test/matchesGoldenFile.html), run the tests
51+
with flag `--update-goldens`.
52+
4853
## Other
4954

5055
See internal details at go/dartpad-manual.

pkgs/dartpad_ui/lib/main.dart

Lines changed: 38 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@ import 'utils.dart';
3333
import 'versions.dart';
3434

3535
const appName = 'DartPad';
36-
const smallScreenWidth = 840;
36+
37+
// Smallest screen width when the screen is considered to be a large screen.
38+
const minLargeScreenWidth = 866.0;
3739

3840
void main() async {
3941
usePathUrlStrategy();
@@ -227,16 +229,18 @@ class DartPadMainPage extends StatefulWidget {
227229
);
228230

229231
@override
230-
State<DartPadMainPage> createState() => _DartPadMainPageState();
232+
State<DartPadMainPage> createState() => DartPadMainPageState();
231233
}
232234

233-
class _DartPadMainPageState extends State<DartPadMainPage>
235+
@visibleForTesting
236+
class DartPadMainPageState extends State<DartPadMainPage>
234237
with SingleTickerProviderStateMixin {
235238
late final AppModel appModel;
236239
late final AppServices appServices;
237240
late final SplitViewController mainSplitter;
238241
late final SplitViewController consoleSplitter;
239242
late final TabController tabController;
243+
final initialized = Completer<void>();
240244

241245
final GlobalKey _executionWidgetKey = GlobalKey(
242246
debugLabel: 'execution-widget',
@@ -253,7 +257,10 @@ class _DartPadMainPageState extends State<DartPadMainPage>
253257
@override
254258
void initState() {
255259
super.initState();
260+
_initialize();
261+
}
256262

263+
Future<void> _initialize() async {
257264
tabController = TabController(length: 2, vsync: this)..addListener(() {
258265
// Rebuild when the user changes tabs so that the IndexedStack updates
259266
// its active child view.
@@ -282,26 +289,6 @@ class _DartPadMainPageState extends State<DartPadMainPage>
282289
appModel = AppModel();
283290
appServices = AppServices(appModel, channel ?? Channel.defaultChannel);
284291

285-
appServices.populateVersions();
286-
appServices
287-
.performInitialLoad(
288-
gistId: widget.gistId,
289-
sampleId: widget.builtinSampleId,
290-
flutterSampleId: widget.flutterSampleId,
291-
channel: widget.initialChannel,
292-
keybinding: DartPadLocalStorage.instance.getUserKeybinding(),
293-
getFallback:
294-
() =>
295-
DartPadLocalStorage.instance.getUserCode() ??
296-
Samples.defaultSnippet(),
297-
)
298-
.then((value) {
299-
// Start listening for inject code messages.
300-
handleEmbedMessage(appServices, runOnInject: widget.runOnLoad);
301-
if (widget.runOnLoad) {
302-
appServices.performCompileAndRun();
303-
}
304-
});
305292
appModel.compilingState.addListener(_handleRunStarted);
306293

307294
tabController.addListener(() {
@@ -312,6 +299,31 @@ class _DartPadMainPageState extends State<DartPadMainPage>
312299
}
313300
});
314301

302+
await Future.wait([
303+
appServices.populateVersions(),
304+
appServices
305+
.performInitialLoad(
306+
gistId: widget.gistId,
307+
sampleId: widget.builtinSampleId,
308+
flutterSampleId: widget.flutterSampleId,
309+
channel: widget.initialChannel,
310+
keybinding: DartPadLocalStorage.instance.getUserKeybinding(),
311+
getFallback:
312+
() =>
313+
DartPadLocalStorage.instance.getUserCode() ??
314+
Samples.defaultSnippet(),
315+
)
316+
.then((value) {
317+
// Start listening for inject code messages.
318+
handleEmbedMessage(appServices, runOnInject: widget.runOnLoad);
319+
if (widget.runOnLoad) {
320+
appServices.performCompileAndRun();
321+
}
322+
}),
323+
]);
324+
325+
initialized.complete();
326+
315327
debugPrint('initialized: useGenui = $useGenUI, channel = $channel.');
316328
}
317329

@@ -402,7 +414,7 @@ class _DartPadMainPageState extends State<DartPadMainPage>
402414
final scaffold = LayoutBuilder(
403415
builder: (context, constraints) {
404416
// Use the mobile UI layout for small screen widths.
405-
if (constraints.maxWidth <= smallScreenWidth) {
417+
if (constraints.maxWidth < minLargeScreenWidth) {
406418
return Scaffold(
407419
key: _scaffoldKey,
408420
appBar:
@@ -593,7 +605,7 @@ class DartPadAppBar extends StatelessWidget implements PreferredSizeWidget {
593605
Widget build(BuildContext context) {
594606
return LayoutBuilder(
595607
builder: (context, constraints) {
596-
final wideLayout = constraints.maxWidth > smallScreenWidth;
608+
final wideLayout = constraints.maxWidth >= minLargeScreenWidth;
597609

598610
return AppBar(
599611
backgroundColor: theme.colorScheme.surface,
@@ -653,7 +665,7 @@ class DartPadAppBar extends StatelessWidget implements PreferredSizeWidget {
653665
bottom: bottom,
654666
actions: [
655667
// Hide the Install SDK button when the screen width is too small.
656-
if (constraints.maxWidth > smallScreenWidth)
668+
if (constraints.maxWidth >= minLargeScreenWidth)
657669
ContinueInMenu(openInFirebaseStudio: _openInFirebaseStudio),
658670
const SizedBox(width: denseSpacing),
659671
_BrightnessButton(

pkgs/dartpad_ui/pubspec.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ dependencies:
3434
web: ^1.1.0
3535

3636
dev_dependencies:
37+
integration_test:
38+
sdk: flutter
3739
flutter_test:
3840
sdk: flutter
3941
flutter_lints: ^5.0.0
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import 'dart:async';
6+
7+
import 'package:flutter/foundation.dart';
8+
import 'package:flutter_test/flutter_test.dart';
9+
10+
/// Test configuration for each test library in this directory.
11+
///
12+
/// See https://api.flutter.dev/flutter/flutter_test/flutter_test-library.html.
13+
Future<void> testExecutable(FutureOr<void> Function() testMain) async {
14+
// Set golden file comparator to use a custom tolerance.
15+
goldenFileComparator = _GoldenDiffComparator();
16+
17+
await testMain();
18+
}
19+
20+
/// Customization of tolerance for golden file comparison.
21+
///
22+
/// See https://github.com/flutter/flutter/pull/77014#issuecomment-1048896776
23+
class _GoldenDiffComparator extends LocalFileComparator {
24+
_GoldenDiffComparator() : super(Uri.parse('.'));
25+
26+
static const _tolerance = 0.015; // 1.5% of difference is ok.
27+
28+
@override
29+
Future<bool> compare(Uint8List imageBytes, Uri golden) async {
30+
final ComparisonResult result = await GoldenFileComparator.compareLists(
31+
imageBytes,
32+
await getGoldenBytes(golden),
33+
);
34+
35+
if (!result.passed && result.diffPercent > _tolerance) {
36+
final String error = await generateFailureOutput(result, golden, basedir);
37+
throw FlutterError(error);
38+
}
39+
if (!result.passed) {
40+
debugPrint(
41+
'A tolerable difference of ${result.diffPercent * 100}% was found when '
42+
'comparing $golden, that is acceptable as it is '
43+
'less than the tolerance of ${_tolerance * 100}%.',
44+
);
45+
}
46+
return result.passed || result.diffPercent <= _tolerance;
47+
}
48+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
This folder contains presubmit tests.

0 commit comments

Comments
 (0)