// Copyright 2014 The Flutter Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; // Only check the initial lines of the message, since the message walks the // entire widget tree back, and any changes to the widget tree break these // tests if we check the entire message. void _expectStartsWith(List actual, List matcher) { expect(actual.sublist(0, matcher.length), equals(matcher)); } void main() { final _MockLiveTestWidgetsFlutterBinding binding = _MockLiveTestWidgetsFlutterBinding(); testWidgets('Should print message on pointer events', (WidgetTester tester) async { final List printedMessages = []; int invocations = 0; await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: Center( child: GestureDetector( onTap: () { invocations++; }, child: const Text('Test'), ), ), ), ); final Size windowCenter = tester.binding.window.physicalSize / tester.binding.window.devicePixelRatio / 2; final double windowCenterX = windowCenter.width; final double windowCenterY = windowCenter.height; final Offset widgetCenter = tester.getRect(find.byType(Text)).center; expect(widgetCenter.dx, windowCenterX); expect(widgetCenter.dy, windowCenterY); await binding.collectDebugPrints(printedMessages, () async { await tester.tap(find.byType(Text)); }); await tester.pump(); expect(invocations, 0); _expectStartsWith(printedMessages, ''' Some possible finders for the widgets at Offset(400.0, 300.0): find.text('Test') '''.trim().split('\n')); printedMessages.clear(); await binding.collectDebugPrints(printedMessages, () async { await tester.tapAt(const Offset(1, 1)); }); expect(printedMessages, equals(''' No widgets found at Offset(1.0, 1.0). '''.trim().split('\n'))); }); testWidgets('Should print message on pointer events with setSurfaceSize', (WidgetTester tester) async { final List printedMessages = []; int invocations = 0; await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: Center( child:GestureDetector( onTap: () { invocations++; }, child: const Text('Test'), ), ), ), ); final Size originalSize = tester.binding.createViewConfiguration().size; await tester.binding.setSurfaceSize(const Size(2000, 1800)); try { await tester.pump(); final Offset widgetCenter = tester.getRect(find.byType(Text)).center; expect(widgetCenter.dx, 1000); expect(widgetCenter.dy, 900); await binding.collectDebugPrints(printedMessages, () async { await tester.tap(find.byType(Text)); }); await tester.pump(); expect(invocations, 0); _expectStartsWith(printedMessages, ''' Some possible finders for the widgets at Offset(1000.0, 900.0): find.text('Test') '''.trim().split('\n')); printedMessages.clear(); await binding.collectDebugPrints(printedMessages, () async { await tester.tapAt(const Offset(1, 1)); }); expect(printedMessages, equals(''' No widgets found at Offset(1.0, 1.0). '''.trim().split('\n'))); } finally { await tester.binding.setSurfaceSize(originalSize); } }); } class _MockLiveTestWidgetsFlutterBinding extends LiveTestWidgetsFlutterBinding { @override void handlePointerEventForSource( PointerEvent event, { TestBindingEventSource source = TestBindingEventSource.device, }) { // In this test we use `WidgetTester.tap` to simulate real device touches. // `WidgetTester.tap` sends events in the local coordinate system, while // real devices touches sends event in the global coordinate system. // See the documentation of [handlePointerEventForSource] for details. if (source == TestBindingEventSource.test) { final PointerEvent globalEvent = event.copyWith(position: localToGlobal(event.position)); return super.handlePointerEventForSource(globalEvent); } return super.handlePointerEventForSource(event, source: source); } List? _storeDebugPrints; @override DebugPrintCallback get debugPrintOverride { return _storeDebugPrints == null ? super.debugPrintOverride : ((String? message, { int? wrapWidth }) => _storeDebugPrints!.add(message)); } // Execute `task` while redirecting [debugPrint] to appending to `store`. Future collectDebugPrints(List? store, AsyncValueGetter task) async { _storeDebugPrints = store; try { await task(); } finally { _storeDebugPrints = null; } } }