From 09a2c253e0027c1888b6475cc121d6e944558b25 Mon Sep 17 00:00:00 2001 From: Kenzie Davisson Date: Thu, 7 May 2026 19:17:30 -0700 Subject: [PATCH 1/2] Clean up hover test. --- .../devtools_app/lib/src/shared/ui/hover.dart | 34 ++--- .../test/service/timeline_streams_test.dart | 35 +++--- .../shared/ui/hover_positioning_test.dart | 118 +++++++++--------- 3 files changed, 98 insertions(+), 89 deletions(-) diff --git a/packages/devtools_app/lib/src/shared/ui/hover.dart b/packages/devtools_app/lib/src/shared/ui/hover.dart index b4431fa5718..789e124bd9e 100644 --- a/packages/devtools_app/lib/src/shared/ui/hover.dart +++ b/packages/devtools_app/lib/src/shared/ui/hover.dart @@ -117,7 +117,8 @@ int _hoverIndexFor(double dx, TextSpan line) { const _hoverYOffset = 10.0; /// Minimum distance from the side of screen to show tooltip -const _hoverMargin = 16.0; +@visibleForTesting +const hoverMargin = 16.0; /// Defines how a [HoverCardTooltip] is positioned enum HoverCardPosition { @@ -257,18 +258,18 @@ class HoverCard { final localPosition = overlayBox.globalToLocal(event.position); final maxX = math.max( - _hoverMargin, - overlaySize.width - _hoverMargin - width, + hoverMargin, + overlaySize.width - hoverMargin - width, ); - final x = (localPosition.dx - (width / 2.0)).clamp(_hoverMargin, maxX); + final x = (localPosition.dx - (width / 2.0)).clamp(hoverMargin, maxX); final maxY = math.max( - _hoverMargin, + hoverMargin, overlaySize.height - - _hoverMargin - + hoverMargin - _totalMaxHoverCardHeight(hasTitle: title != null), ); - final y = (localPosition.dy + _hoverYOffset).clamp(_hoverMargin, maxY); + final y = (localPosition.dy + _hoverYOffset).clamp(hoverMargin, maxY); return Offset(x, y); } @@ -381,7 +382,8 @@ class HoverCardTooltip extends StatefulWidget { }) : asyncGenerateHoverCardData = null, asyncTimeout = null; - static const _hoverDelay = Duration(milliseconds: 500); + @visibleForTesting + static const hoverDelay = Duration(milliseconds: 500); static const defaultHoverWidth = 450.0; /// Whether the tooltip is currently enabled. @@ -420,7 +422,7 @@ class _HoverCardTooltipState extends State { void _onHoverExit() { _showTimer?.cancel(); - _removeTimer = Timer(HoverCardTooltip._hoverDelay, () { + _removeTimer = Timer(HoverCardTooltip.hoverDelay, () { if (_currentHoverCard != null) { _hoverCardController.maybeRemoveHoverCard(_currentHoverCard!); } @@ -448,7 +450,7 @@ class _HoverCardTooltipState extends State { final generateHoverCardData = widget.generateHoverCardData; final asyncTimeout = widget.asyncTimeout; - _showTimer = Timer(HoverCardTooltip._hoverDelay, () { + _showTimer = Timer(HoverCardTooltip.hoverDelay, () { if (asyncGenerateHoverCardData != null) { assert(generateHoverCardData == null); _showAsyncHoverCard( @@ -596,13 +598,13 @@ class _HoverCardTooltipState extends State { final box = context.findRenderObject() as RenderBox; final maxX = math.max( - _hoverMargin, - overlayBox.size.width - _hoverMargin - width, + hoverMargin, + overlayBox.size.width - hoverMargin - width, ); final maxY = math.max( - _hoverMargin, + hoverMargin, overlayBox.size.height - - _hoverMargin - + hoverMargin - _totalMaxHoverCardHeight(hasTitle: title != null), ); @@ -612,8 +614,8 @@ class _HoverCardTooltipState extends State { ); return Offset( - offset.dx.clamp(_hoverMargin, maxX), - offset.dy.clamp(_hoverMargin, maxY), + offset.dx.clamp(hoverMargin, maxX), + offset.dy.clamp(hoverMargin, maxY), ); } diff --git a/packages/devtools_app/test/service/timeline_streams_test.dart b/packages/devtools_app/test/service/timeline_streams_test.dart index c51353c007c..7c345297ab2 100644 --- a/packages/devtools_app/test/service/timeline_streams_test.dart +++ b/packages/devtools_app/test/service/timeline_streams_test.dart @@ -22,23 +22,30 @@ void main() { await env.tearDownEnvironment(force: true); }); - test('timeline streams initialized on vm service opened', () async { - await env.setupEnvironment(); + test( + 'timeline streams initialized on vm service opened', + () async { + await env.setupEnvironment(); - // Await a short delay to make sure the timelineStreamManager is done - // initializing. - await delay(); + // Await a short delay to make sure the timelineStreamManager is done + // initializing. + await delay(); - expect(serviceConnection.serviceManager.service, equals(env.service)); - expect(serviceConnection.timelineStreamManager, isNotNull); - expect(serviceConnection.timelineStreamManager.basicStreams, isNotEmpty); - expect( - serviceConnection.timelineStreamManager.advancedStreams, - isNotEmpty, - ); + expect(serviceConnection.serviceManager.service, equals(env.service)); + expect(serviceConnection.timelineStreamManager, isNotNull); + expect( + serviceConnection.timelineStreamManager.basicStreams, + isNotEmpty, + ); + expect( + serviceConnection.timelineStreamManager.advancedStreams, + isNotEmpty, + ); - await env.tearDownEnvironment(); - }, timeout: const Timeout.factor(4)); + await env.tearDownEnvironment(); + }, + timeout: const Timeout.factor(4), + ); test('notifies on stream change', () async { await env.setupEnvironment(); diff --git a/packages/devtools_app/test/shared/ui/hover_positioning_test.dart b/packages/devtools_app/test/shared/ui/hover_positioning_test.dart index 79d2acd6904..4a5d968cd2a 100644 --- a/packages/devtools_app/test/shared/ui/hover_positioning_test.dart +++ b/packages/devtools_app/test/shared/ui/hover_positioning_test.dart @@ -7,7 +7,10 @@ import 'package:devtools_test/helpers.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:provider/provider.dart'; + +const _windowWidth = 800.0; +const _windowHeight = 600.0; +const _windowSize = Size(_windowWidth, _windowHeight); void main() { Future pumpHoverCardTooltip( @@ -40,13 +43,13 @@ void main() { await gesture.addPointer(location: Offset.zero); final center = tester.getCenter(find.text('Hover Me')); await gesture.moveTo(center); - await tester.pump(const Duration(milliseconds: 500)); + await tester.pump(HoverCardTooltip.hoverDelay); await tester.pumpAndSettle(); } testWidgetsWithWindowSize( 'HoverCard at the bottom of the window should not overflow', - const Size(800, 600), + _windowSize, (WidgetTester tester) async { // Use a title to increase the height beyond the base content height. await pumpHoverCardTooltip( @@ -66,14 +69,16 @@ void main() { final position = renderBox.localToGlobal(Offset.zero); final size = renderBox.size; - // _hoverMargin = 16.0 - expect(position.dy + size.height, lessThanOrEqualTo(600.0 - 16.0)); + expect( + position.dy + size.height, + lessThanOrEqualTo(_windowHeight - hoverMargin), + ); }, ); testWidgetsWithWindowSize( 'HoverCard at the right of the window should not overflow', - const Size(800, 600), + _windowSize, (WidgetTester tester) async { await pumpHoverCardTooltip(tester, alignment: Alignment.centerRight); @@ -88,8 +93,10 @@ void main() { final position = renderBox.localToGlobal(Offset.zero); final size = renderBox.size; - // _hoverMargin = 16.0 - expect(position.dx + size.width, lessThanOrEqualTo(800.0 - 16.0)); + expect( + position.dx + size.width, + lessThanOrEqualTo(_windowWidth - hoverMargin), + ); }, ); @@ -110,38 +117,36 @@ void main() { }, ); - testWidgetsWithWindowSize( - 'HoverCard height clamping with title', - const Size(800, 600), - (WidgetTester tester) async { - await pumpHoverCardTooltip( - tester, - alignment: Alignment.bottomCenter, - title: 'An Important Title', - ); + testWidgetsWithWindowSize('HoverCard height clamping with title', _windowSize, ( + WidgetTester tester, + ) async { + await pumpHoverCardTooltip( + tester, + alignment: Alignment.bottomCenter, + title: 'An Important Title', + ); - final hoverContentFinderWithTitle = find.text('Hover Content'); - expect(hoverContentFinderWithTitle, findsOneWidget); + final hoverContentFinderWithTitle = find.text('Hover Content'); + expect(hoverContentFinderWithTitle, findsOneWidget); - final containerWithTitle = find - .ancestor( - of: hoverContentFinderWithTitle, - matching: find.byType(Container), - ) - .last; + final containerWithTitle = find + .ancestor( + of: hoverContentFinderWithTitle, + matching: find.byType(Container), + ) + .last; - final renderBoxWithTitle = - tester.renderObject(containerWithTitle) as RenderBox; - final positionWithTitle = renderBoxWithTitle.localToGlobal(Offset.zero); + final renderBoxWithTitle = + tester.renderObject(containerWithTitle) as RenderBox; + final positionWithTitle = renderBoxWithTitle.localToGlobal(Offset.zero); - // Clamps strictly at y = 274.0 because of dynamic height containing title/divider. - expect(positionWithTitle.dy, equals(274.0)); - }, - ); + // Clamps strictly at y = 274.0 because of dynamic height containing title/divider. + expect(positionWithTitle.dy, equals(274.0)); + }); testWidgetsWithWindowSize( 'HoverCard height clamping without title', - const Size(800, 600), + _windowSize, (WidgetTester tester) async { await pumpHoverCardTooltip(tester, alignment: Alignment.bottomCenter); @@ -166,39 +171,34 @@ void main() { testWidgetsWithWindowSize( 'HoverCard translates global coordinates to local coordinates for offset overlays', - const Size(800, 600), + _windowSize, (WidgetTester tester) async { final overlayKey = GlobalKey(); await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: Padding( - padding: const EdgeInsets.only(left: 50.0, top: 100.0), - child: Provider.value( - value: HoverCardController(), - child: Overlay( - key: overlayKey, - initialEntries: [ - OverlayEntry( - builder: (context) => Align( - alignment: Alignment.topLeft, - child: HoverCardTooltip.sync( - enabled: () => true, - generateHoverCardData: (event) => HoverCardData( - contents: const SizedBox( - width: 200, - height: 250, - child: Text('Hover Content'), - ), - ), - child: const Text('Hover Me Offset'), + wrapSimple( + Padding( + padding: const EdgeInsets.only(left: 50.0, top: 100.0), + child: Overlay( + key: overlayKey, + initialEntries: [ + OverlayEntry( + builder: (context) => Align( + alignment: Alignment.topLeft, + child: HoverCardTooltip.sync( + enabled: () => true, + generateHoverCardData: (event) => HoverCardData( + contents: const SizedBox( + width: 200, + height: 250, + child: Text('Hover Content'), ), ), + child: const Text('Hover Me Offset'), ), - ], + ), ), - ), + ], ), ), ), @@ -210,7 +210,7 @@ void main() { final center = tester.getCenter(find.text('Hover Me Offset')); await gesture.moveTo(center); - await tester.pump(const Duration(milliseconds: 500)); + await tester.pump(HoverCardTooltip.hoverDelay); await tester.pumpAndSettle(); final hoverContentFinder = find.text('Hover Content'); From e1d7bee531fbdd6f8a3cc08471d4ed93f2f8cc99 Mon Sep 17 00:00:00 2001 From: Kenzie Davisson Date: Fri, 8 May 2026 08:30:52 -0700 Subject: [PATCH 2/2] formatting --- .../devtools_app/lib/src/framework/observer/_memory_web.dart | 3 +-- packages/devtools_app/lib/src/shared/ui/hover.dart | 5 +---- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/packages/devtools_app/lib/src/framework/observer/_memory_web.dart b/packages/devtools_app/lib/src/framework/observer/_memory_web.dart index 251cfb64071..c6e56a3bbd3 100644 --- a/packages/devtools_app/lib/src/framework/observer/_memory_web.dart +++ b/packages/devtools_app/lib/src/framework/observer/_memory_web.dart @@ -65,8 +65,7 @@ extension type _UserAgentSpecificMemoryBreakdownAttributionElement._(JSObject _) @JS() extension type _UserAgentSpecificMemoryBreakdownAttributionContainerElement._( JSObject _ -) - implements JSObject { +) implements JSObject { external String get id; external String get url; diff --git a/packages/devtools_app/lib/src/shared/ui/hover.dart b/packages/devtools_app/lib/src/shared/ui/hover.dart index 789e124bd9e..47e0048c3bd 100644 --- a/packages/devtools_app/lib/src/shared/ui/hover.dart +++ b/packages/devtools_app/lib/src/shared/ui/hover.dart @@ -257,10 +257,7 @@ class HoverCard { final overlaySize = overlayBox.size; final localPosition = overlayBox.globalToLocal(event.position); - final maxX = math.max( - hoverMargin, - overlaySize.width - hoverMargin - width, - ); + final maxX = math.max(hoverMargin, overlaySize.width - hoverMargin - width); final x = (localPosition.dx - (width / 2.0)).clamp(hoverMargin, maxX); final maxY = math.max(