// 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. // This file is run as part of a reduced test set in CI on Mac and Windows // machines. @Tags(<String>['reduced-test-set']) library; import 'package:flutter/material.dart'; import 'package:flutter/src/foundation/constants.dart'; import 'package:flutter_test/flutter_test.dart'; import '../rendering/mock_canvas.dart'; void main() { testWidgets('InkSparkle in a Button compiles and does not crash', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: Scaffold( body: Center( child: ElevatedButton( style: ElevatedButton.styleFrom(splashFactory: InkSparkle.splashFactory), child: const Text('Sparkle!'), onPressed: () { }, ), ), ), )); final Finder buttonFinder = find.text('Sparkle!'); await tester.tap(buttonFinder); await tester.pump(); await tester.pumpAndSettle(); }, skip: kIsWeb, // [intended] shaders are not yet supported for web. ); testWidgets('InkSparkle default splashFactory paints with drawRect when bounded', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: Scaffold( body: Center( child: InkWell( splashFactory: InkSparkle.splashFactory, child: const Text('Sparkle!'), onTap: () { }, ), ), ), )); final Finder buttonFinder = find.text('Sparkle!'); await tester.tap(buttonFinder); await tester.pump(); await tester.pump(const Duration(milliseconds: 200)); final MaterialInkController material = Material.of(tester.element(buttonFinder)); expect(material, paintsExactlyCountTimes(#drawRect, 1)); // ignore: avoid_dynamic_calls expect((material as dynamic).debugInkFeatures, hasLength(1)); await tester.pumpAndSettle(); // ink feature is disposed. // ignore: avoid_dynamic_calls expect((material as dynamic).debugInkFeatures, isEmpty); }, skip: kIsWeb, // [intended] shaders are not yet supported for web. ); testWidgets('InkSparkle default splashFactory paints with drawPaint when unbounded', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: Scaffold( body: Center( child: InkResponse( splashFactory: InkSparkle.splashFactory, child: const Text('Sparkle!'), onTap: () { }, ), ), ), )); final Finder buttonFinder = find.text('Sparkle!'); await tester.tap(buttonFinder); await tester.pump(); await tester.pump(const Duration(milliseconds: 200)); final MaterialInkController material = Material.of(tester.element(buttonFinder)); expect(material, paintsExactlyCountTimes(#drawPaint, 1)); }, skip: kIsWeb, // [intended] shaders are not yet supported for web. ); ///////////// // Goldens // ///////////// testWidgets('InkSparkle renders with sparkles when top left of button is tapped', (WidgetTester tester) async { await _runTest(tester, 'top_left', 0.2); }, skip: kIsWeb, // [intended] shaders are not yet supported for web. ); testWidgets('InkSparkle renders with sparkles when center of button is tapped', (WidgetTester tester) async { await _runTest(tester, 'center', 0.5); }, skip: kIsWeb, // [intended] shaders are not yet supported for web. ); testWidgets('InkSparkle renders with sparkles when bottom right of button is tapped', (WidgetTester tester) async { await _runTest(tester, 'bottom_right', 0.8); }, skip: kIsWeb, // [intended] shaders are not yet supported for web. ); } Future<void> _runTest(WidgetTester tester, String positionName, double distanceFromTopLeft) async { final Key repaintKey = UniqueKey(); final Key buttonKey = UniqueKey(); await tester.pumpWidget(MaterialApp( theme: ThemeData(useMaterial3: false), home: Scaffold( body: Center( child: RepaintBoundary( key: repaintKey, child: ElevatedButton( key: buttonKey, style: ElevatedButton.styleFrom(splashFactory: InkSparkle.constantTurbulenceSeedSplashFactory), child: const Text('Sparkle!'), onPressed: () { }, ), ), ), ), )); final Finder buttonFinder = find.byKey(buttonKey); final Finder repaintFinder = find.byKey(repaintKey); final Offset topLeft = tester.getTopLeft(buttonFinder); final Offset bottomRight = tester.getBottomRight(buttonFinder); await _warmUpShader(tester, buttonFinder); final Offset target = topLeft + (bottomRight - topLeft) * distanceFromTopLeft; await tester.tapAt(target); for (int i = 0; i <= 5; i++) { await tester.pump(const Duration(milliseconds: 50)); await expectLater( repaintFinder, matchesGoldenFile('ink_sparkle.$positionName.$i.png'), ); } } // Warm up shader. Compilation is of the order of 10 milliseconds and // Animation is < 1000 milliseconds. Use 2000 milliseconds as a safety // net to prevent flakiness. Future<void> _warmUpShader(WidgetTester tester, Finder buttonFinder) async { await tester.tap(buttonFinder); await tester.pumpAndSettle(const Duration(milliseconds: 2000)); }