// 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. // no-shuffle: // //TODO(gspencergoog): Remove this tag once this test's state leaks/test // dependencies have been fixed. // https://github.com/flutter/flutter/issues/85160 // Fails with "flutter test --test-randomize-ordering-seed=456" // reduced-test-set: // This file is run as part of a reduced test set in CI on Mac and Windows // machines. @Tags(<String>['reduced-test-set', 'no-shuffle']) import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; import '../rendering/mock_canvas.dart'; void main() { // The "can be constructed" tests that follow are primarily to ensure that any // animations started by the progress indicators are stopped at dispose() time. testWidgets('LinearProgressIndicator(value: 0.0) can be constructed and has empty semantics by default', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, child: Center( child: SizedBox( width: 200.0, child: LinearProgressIndicator(value: 0.0), ), ), ), ); expect(tester.getSemantics(find.byType(LinearProgressIndicator)), matchesSemantics()); handle.dispose(); }); testWidgets('LinearProgressIndicator(value: null) can be constructed and has empty semantics by default', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); await tester.pumpWidget( const Directionality( textDirection: TextDirection.rtl, child: Center( child: SizedBox( width: 200.0, child: LinearProgressIndicator(), ), ), ), ); expect(tester.getSemantics(find.byType(LinearProgressIndicator)), matchesSemantics()); handle.dispose(); }); testWidgets('LinearProgressIndicator custom minHeight', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, child: Center( child: SizedBox( width: 200.0, child: LinearProgressIndicator(value: 0.25, minHeight: 2.0), ), ), ), ); expect( find.byType(LinearProgressIndicator), paints ..rect(rect: const Rect.fromLTRB(0.0, 0.0, 200.0, 2.0)) ..rect(rect: const Rect.fromLTRB(0.0, 0.0, 50.0, 2.0)), ); // Same test, but using the theme await tester.pumpWidget( Theme( data: ThemeData( progressIndicatorTheme: const ProgressIndicatorThemeData( linearMinHeight: 2.0, ), ), child: const Directionality( textDirection: TextDirection.ltr, child: Center( child: SizedBox( width: 200.0, child: LinearProgressIndicator(value: 0.25), ), ), ), ), ); expect( find.byType(LinearProgressIndicator), paints ..rect(rect: const Rect.fromLTRB(0.0, 0.0, 200.0, 2.0)) ..rect(rect: const Rect.fromLTRB(0.0, 0.0, 50.0, 2.0)), ); }); testWidgets('LinearProgressIndicator paint (LTR)', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, child: Center( child: SizedBox( width: 200.0, child: LinearProgressIndicator(value: 0.25), ), ), ), ); expect( find.byType(LinearProgressIndicator), paints ..rect(rect: const Rect.fromLTRB(0.0, 0.0, 200.0, 4.0)) ..rect(rect: const Rect.fromLTRB(0.0, 0.0, 50.0, 4.0)), ); expect(tester.binding.transientCallbackCount, 0); }); testWidgets('LinearProgressIndicator paint (RTL)', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.rtl, child: Center( child: SizedBox( width: 200.0, child: LinearProgressIndicator(value: 0.25), ), ), ), ); expect( find.byType(LinearProgressIndicator), paints ..rect(rect: const Rect.fromLTRB(0.0, 0.0, 200.0, 4.0)) ..rect(rect: const Rect.fromLTRB(150.0, 0.0, 200.0, 4.0)), ); expect(tester.binding.transientCallbackCount, 0); }); testWidgets('LinearProgressIndicator indeterminate (LTR)', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, child: Center( child: SizedBox( width: 200.0, child: LinearProgressIndicator(), ), ), ), ); await tester.pump(const Duration(milliseconds: 300)); final double animationValue = const Interval(0.0, 750.0 / 1800.0, curve: Cubic(0.2, 0.0, 0.8, 1.0)) .transform(300.0 / 1800.0); expect( find.byType(LinearProgressIndicator), paints ..rect(rect: const Rect.fromLTRB(0.0, 0.0, 200.0, 4.0)) ..rect(rect: Rect.fromLTRB(0.0, 0.0, animationValue * 200.0, 4.0)), ); expect(tester.binding.transientCallbackCount, 1); }); testWidgets('LinearProgressIndicator paint (RTL)', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.rtl, child: Center( child: SizedBox( width: 200.0, child: LinearProgressIndicator(), ), ), ), ); await tester.pump(const Duration(milliseconds: 300)); final double animationValue = const Interval(0.0, 750.0 / 1800.0, curve: Cubic(0.2, 0.0, 0.8, 1.0)) .transform(300.0 / 1800.0); expect( find.byType(LinearProgressIndicator), paints ..rect(rect: const Rect.fromLTRB(0.0, 0.0, 200.0, 4.0)) ..rect(rect: Rect.fromLTRB(200.0 - animationValue * 200.0, 0.0, 200.0, 4.0)), ); expect(tester.binding.transientCallbackCount, 1); }); testWidgets('LinearProgressIndicator with colors', (WidgetTester tester) async { // With valueColor & color provided await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, child: Center( child: SizedBox( width: 200.0, child: LinearProgressIndicator( value: 0.25, backgroundColor: Colors.black, color: Colors.blue, valueColor: AlwaysStoppedAnimation<Color>(Colors.white), ), ), ), ), ); // Should use valueColor expect( find.byType(LinearProgressIndicator), paints ..rect(rect: const Rect.fromLTRB(0.0, 0.0, 200.0, 4.0)) ..rect(rect: const Rect.fromLTRB(0.0, 0.0, 50.0, 4.0), color: Colors.white), ); // With just color provided await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, child: Center( child: SizedBox( width: 200.0, child: LinearProgressIndicator( value: 0.25, backgroundColor: Colors.black, color: Colors.white12, ), ), ), ), ); // Should use color expect( find.byType(LinearProgressIndicator), paints ..rect(rect: const Rect.fromLTRB(0.0, 0.0, 200.0, 4.0)) ..rect(rect: const Rect.fromLTRB(0.0, 0.0, 50.0, 4.0), color: Colors.white12), ); // With no color provided const Color primaryColor = Color(0xff008800); final ThemeData theme = ThemeData(colorScheme: ColorScheme.fromSwatch().copyWith(primary: primaryColor)); await tester.pumpWidget( Theme( data: theme, child: const Directionality( textDirection: TextDirection.ltr, child: Center( child: SizedBox( width: 200.0, child: LinearProgressIndicator( value: 0.25, backgroundColor: Colors.black, ), ), ), ), ), ); // Should use the theme's primary color expect( find.byType(LinearProgressIndicator), paints ..rect(rect: const Rect.fromLTRB(0.0, 0.0, 200.0, 4.0)) ..rect(rect: const Rect.fromLTRB(0.0, 0.0, 50.0, 4.0), color: primaryColor), ); // With ProgressIndicatorTheme colors const Color indicatorColor = Color(0xff0000ff); await tester.pumpWidget( Theme( data: ThemeData( progressIndicatorTheme: const ProgressIndicatorThemeData( color: indicatorColor, linearTrackColor: Colors.black, ), ), child: const Directionality( textDirection: TextDirection.ltr, child: Center( child: SizedBox( width: 200.0, child: LinearProgressIndicator( value: 0.25, ), ), ), ), ), ); // Should use the progress indicator theme colors expect( find.byType(LinearProgressIndicator), paints ..rect(rect: const Rect.fromLTRB(0.0, 0.0, 200.0, 4.0)) ..rect(rect: const Rect.fromLTRB(0.0, 0.0, 50.0, 4.0), color: indicatorColor), ); }); testWidgets('LinearProgressIndicator with animation with null colors', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, child: Center( child: SizedBox( width: 200.0, child: LinearProgressIndicator( value: 0.25, valueColor: AlwaysStoppedAnimation<Color?>(null), backgroundColor: Colors.black, ), ), ), ), ); expect( find.byType(LinearProgressIndicator), paints ..rect(rect: const Rect.fromLTRB(0.0, 0.0, 200.0, 4.0)) ..rect(rect: const Rect.fromLTRB(0.0, 0.0, 50.0, 4.0)), ); }); testWidgets('CircularProgressIndicator(value: 0.0) can be constructed and has value semantics by default', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, child: Center( child: CircularProgressIndicator(value: 0.0), ), ), ); expect(tester.getSemantics(find.byType(CircularProgressIndicator)), matchesSemantics( value: '0%', textDirection: TextDirection.ltr, )); handle.dispose(); }); testWidgets('CircularProgressIndicator(value: null) can be constructed and has empty semantics by default', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); await tester.pumpWidget( const Center( child: CircularProgressIndicator(), ), ); expect(tester.getSemantics(find.byType(CircularProgressIndicator)), matchesSemantics()); handle.dispose(); }); testWidgets('LinearProgressIndicator causes a repaint when it changes', (WidgetTester tester) async { await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, child: ListView(children: const <Widget>[LinearProgressIndicator(value: 0.0)]), )); final List<Layer> layers1 = tester.layers; await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, child: ListView(children: const <Widget>[LinearProgressIndicator(value: 0.5)]), )); final List<Layer> layers2 = tester.layers; expect(layers1, isNot(equals(layers2))); }); testWidgets('CircularProgressIndicator stoke width', (WidgetTester tester) async { await tester.pumpWidget(const CircularProgressIndicator()); expect(find.byType(CircularProgressIndicator), paints..arc(strokeWidth: 4.0)); await tester.pumpWidget(const CircularProgressIndicator(strokeWidth: 16.0)); expect(find.byType(CircularProgressIndicator), paints..arc(strokeWidth: 16.0)); }); testWidgets('CircularProgressIndicator paint colors', (WidgetTester tester) async { const Color green = Color(0xFF00FF00); const Color blue = Color(0xFF0000FF); const Color red = Color(0xFFFF0000); // With valueColor & color provided await tester.pumpWidget(const CircularProgressIndicator( color: red, valueColor: AlwaysStoppedAnimation<Color>(blue), )); expect(find.byType(CircularProgressIndicator), paintsExactlyCountTimes(#drawArc, 1)); expect(find.byType(CircularProgressIndicator), paints..arc(color: blue)); // With just color provided await tester.pumpWidget(const CircularProgressIndicator( color: red, )); expect(find.byType(CircularProgressIndicator), paintsExactlyCountTimes(#drawArc, 1)); expect(find.byType(CircularProgressIndicator), paints..arc(color: red)); // With no color provided await tester.pumpWidget(Theme( data: ThemeData(colorScheme: ColorScheme.fromSwatch().copyWith(primary: green)), child: const CircularProgressIndicator(), )); expect(find.byType(CircularProgressIndicator), paintsExactlyCountTimes(#drawArc, 1)); expect(find.byType(CircularProgressIndicator), paints..arc(color: green)); // With background await tester.pumpWidget(const CircularProgressIndicator( backgroundColor: green, color: blue, )); expect(find.byType(CircularProgressIndicator), paintsExactlyCountTimes(#drawArc, 2)); expect(find.byType(CircularProgressIndicator), paints..arc(color: green)..arc(color: blue)); // With ProgressIndicatorTheme await tester.pumpWidget(Theme( data: ThemeData(progressIndicatorTheme: const ProgressIndicatorThemeData( color: green, circularTrackColor: blue, )), child: const CircularProgressIndicator(), )); expect(find.byType(CircularProgressIndicator), paintsExactlyCountTimes(#drawArc, 2)); expect(find.byType(CircularProgressIndicator), paints..arc(color: blue)..arc(color: green)); }); testWidgets('RefreshProgressIndicator paint colors', (WidgetTester tester) async { const Color green = Color(0xFF00FF00); const Color blue = Color(0xFF0000FF); const Color red = Color(0xFFFF0000); // With valueColor & color provided await tester.pumpWidget(const RefreshProgressIndicator( color: red, valueColor: AlwaysStoppedAnimation<Color>(blue), )); expect(find.byType(RefreshProgressIndicator), paintsExactlyCountTimes(#drawArc, 1)); expect(find.byType(RefreshProgressIndicator), paints..arc(color: blue)); // With just color provided await tester.pumpWidget(const RefreshProgressIndicator( color: red, )); expect(find.byType(RefreshProgressIndicator), paintsExactlyCountTimes(#drawArc, 1)); expect(find.byType(RefreshProgressIndicator), paints..arc(color: red)); // With no color provided await tester.pumpWidget(Theme( data: ThemeData(colorScheme: ColorScheme.fromSwatch().copyWith(primary: green)), child: const RefreshProgressIndicator(), )); expect(find.byType(RefreshProgressIndicator), paintsExactlyCountTimes(#drawArc, 1)); expect(find.byType(RefreshProgressIndicator), paints..arc(color: green)); // With background await tester.pumpWidget(const RefreshProgressIndicator( color: blue, backgroundColor: green, )); expect(find.byType(RefreshProgressIndicator), paintsExactlyCountTimes(#drawArc, 1)); expect(find.byType(RefreshProgressIndicator), paints..arc(color: blue)); final Material backgroundMaterial = tester.widget(find.descendant( of: find.byType(RefreshProgressIndicator), matching: find.byType(Material), )); expect(backgroundMaterial.type, MaterialType.circle); expect(backgroundMaterial.color, green); // With ProgressIndicatorTheme await tester.pumpWidget(Theme( data: ThemeData(progressIndicatorTheme: const ProgressIndicatorThemeData( color: green, refreshBackgroundColor: blue, )), child: const RefreshProgressIndicator(), )); expect(find.byType(RefreshProgressIndicator), paintsExactlyCountTimes(#drawArc, 1)); expect(find.byType(RefreshProgressIndicator), paints..arc(color: green)); final Material themeBackgroundMaterial = tester.widget(find.descendant( of: find.byType(RefreshProgressIndicator), matching: find.byType(Material), )); expect(themeBackgroundMaterial.type, MaterialType.circle); expect(themeBackgroundMaterial.color, blue); }); testWidgets('Indeterminate RefreshProgressIndicator keeps spinning until end of time (approximate)', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/13782 await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, child: Center( child: SizedBox( width: 200.0, child: RefreshProgressIndicator(), ), ), ), ); expect(tester.hasRunningAnimations, isTrue); await tester.pump(const Duration(seconds: 5)); expect(tester.hasRunningAnimations, isTrue); await tester.pump(const Duration(milliseconds: 1)); expect(tester.hasRunningAnimations, isTrue); await tester.pump(const Duration(days: 9999)); expect(tester.hasRunningAnimations, isTrue); }); testWidgets('RefreshProgressIndicator uses expected animation', (WidgetTester tester) async { final AnimationSheetBuilder animationSheet = AnimationSheetBuilder(frameSize: const Size(50, 50)); await tester.pumpFrames(animationSheet.record( const _RefreshProgressIndicatorGolden(), ), const Duration(seconds: 3)); await expectLater( await animationSheet.collate(20), matchesGoldenFile('material.refresh_progress_indicator.png'), ); }, skip: isBrowser); // https://github.com/flutter/flutter/issues/56001 testWidgets('Determinate CircularProgressIndicator stops the animator', (WidgetTester tester) async { double? progressValue; late StateSetter setState; await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: Center( child: StatefulBuilder( builder: (BuildContext context, StateSetter setter) { setState = setter; return CircularProgressIndicator(value: progressValue); }, ), ), ), ); expect(tester.hasRunningAnimations, isTrue); setState(() { progressValue = 1.0; }); await tester.pump(const Duration(milliseconds: 1)); expect(tester.hasRunningAnimations, isFalse); setState(() { progressValue = null; }); await tester.pump(const Duration(milliseconds: 1)); expect(tester.hasRunningAnimations, isTrue); }); testWidgets('LinearProgressIndicator with height 12.0', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, child: Center( child: SizedBox( width: 100.0, height: 12.0, child: LinearProgressIndicator(value: 0.25), ), ), ), ); expect( find.byType(LinearProgressIndicator), paints ..rect(rect: const Rect.fromLTRB(0.0, 0.0, 100.0, 12.0)) ..rect(rect: const Rect.fromLTRB(0.0, 0.0, 25.0, 12.0)), ); expect(tester.binding.transientCallbackCount, 0); }); testWidgets('LinearProgressIndicator with a height less than the minimum', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, child: Center( child: SizedBox( width: 100.0, height: 3.0, child: LinearProgressIndicator(value: 0.25), ), ), ), ); expect( find.byType(LinearProgressIndicator), paints ..rect(rect: const Rect.fromLTRB(0.0, 0.0, 100.0, 3.0)) ..rect(rect: const Rect.fromLTRB(0.0, 0.0, 25.0, 3.0)), ); expect(tester.binding.transientCallbackCount, 0); }); testWidgets('LinearProgressIndicator with default height', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, child: Center( child: SizedBox( width: 100.0, height: 4.0, child: LinearProgressIndicator(value: 0.25), ), ), ), ); expect( find.byType(LinearProgressIndicator), paints ..rect(rect: const Rect.fromLTRB(0.0, 0.0, 100.0, 4.0)) ..rect(rect: const Rect.fromLTRB(0.0, 0.0, 25.0, 4.0)), ); expect(tester.binding.transientCallbackCount, 0); }); testWidgets('LinearProgressIndicator can be made accessible', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); final GlobalKey key = GlobalKey(); const String label = 'Label'; const String value = '25%'; await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: LinearProgressIndicator( key: key, value: 0.25, semanticsLabel: label, semanticsValue: value, ), ), ); expect(tester.getSemantics(find.byKey(key)), matchesSemantics( textDirection: TextDirection.ltr, label: label, value: value, )); handle.dispose(); }); testWidgets('LinearProgressIndicator that is determinate gets default a11y value', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); final GlobalKey key = GlobalKey(); const String label = 'Label'; await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: LinearProgressIndicator( key: key, value: 0.25, semanticsLabel: label, ), ), ); expect(tester.getSemantics(find.byKey(key)), matchesSemantics( textDirection: TextDirection.ltr, label: label, value: '25%', )); handle.dispose(); }); testWidgets('LinearProgressIndicator that is determinate does not default a11y value when label is null', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); final GlobalKey key = GlobalKey(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: LinearProgressIndicator( key: key, value: 0.25, ), ), ); expect(tester.getSemantics(find.byKey(key)), matchesSemantics()); handle.dispose(); }); testWidgets('LinearProgressIndicator that is indeterminate does not default a11y value', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); final GlobalKey key = GlobalKey(); const String label = 'Progress'; await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: LinearProgressIndicator( key: key, value: 0.25, semanticsLabel: label, ), ), ); expect(tester.getSemantics(find.byKey(key)), matchesSemantics( textDirection: TextDirection.ltr, label: label, )); handle.dispose(); }); testWidgets('CircularProgressIndicator can be made accessible', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); final GlobalKey key = GlobalKey(); const String label = 'Label'; const String value = '25%'; await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: CircularProgressIndicator( key: key, value: 0.25, semanticsLabel: label, semanticsValue: value, ), ), ); expect(tester.getSemantics(find.byKey(key)), matchesSemantics( textDirection: TextDirection.ltr, label: label, value: value, )); handle.dispose(); }); testWidgets('RefreshProgressIndicator can be made accessible', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); final GlobalKey key = GlobalKey(); const String label = 'Label'; const String value = '25%'; await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: RefreshProgressIndicator( key: key, semanticsLabel: label, semanticsValue: value, ), ), ); expect(tester.getSemantics(find.byKey(key)), matchesSemantics( textDirection: TextDirection.ltr, label: label, value: value, )); handle.dispose(); }); testWidgets('Indeterminate CircularProgressIndicator uses expected animation', (WidgetTester tester) async { final AnimationSheetBuilder animationSheet = AnimationSheetBuilder(frameSize: const Size(40, 40)); await tester.pumpFrames(animationSheet.record( const Directionality( textDirection: TextDirection.ltr, child: Padding( padding: EdgeInsets.all(4), child: CircularProgressIndicator(), ), ), ), const Duration(seconds: 2)); await expectLater( await animationSheet.collate(20), matchesGoldenFile('material.circular_progress_indicator.indeterminate.png'), ); }, skip: isBrowser); // https://github.com/flutter/flutter/issues/56001 testWidgets( 'Adaptive CircularProgressIndicator displays CupertinoActivityIndicator in iOS', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Scaffold( body: Material( child: CircularProgressIndicator.adaptive(), ), ), ), ); expect(find.byType(CupertinoActivityIndicator), findsOneWidget); }, variant: const TargetPlatformVariant(<TargetPlatform> { TargetPlatform.iOS, TargetPlatform.macOS, }), ); testWidgets( 'Adaptive CircularProgressIndicator can use backgroundColor to change tick color for iOS', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Scaffold( body: Material( child: CircularProgressIndicator.adaptive( backgroundColor: Color(0xFF5D3FD3), ), ), ), ), ); expect( find.byType(CupertinoActivityIndicator), paints ..rrect(rrect: const RRect.fromLTRBXY(-1, -10 / 3, 1, -10, 1, 1), color: const Color(0x935D3FD3)), ); }, variant: const TargetPlatformVariant(<TargetPlatform> { TargetPlatform.iOS, TargetPlatform.macOS, }), ); testWidgets( 'Adaptive CircularProgressIndicator does not display CupertinoActivityIndicator in non-iOS', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Scaffold( body: Material( child: CircularProgressIndicator.adaptive(), ), ), ), ); expect(find.byType(CupertinoActivityIndicator), findsNothing); }, variant: const TargetPlatformVariant(<TargetPlatform> { TargetPlatform.android, TargetPlatform.fuchsia, TargetPlatform.windows, TargetPlatform.linux, }), ); testWidgets('ProgressIndicatorTheme.wrap() always creates a new ProgressIndicatorTheme', (WidgetTester tester) async { late BuildContext builderContext; const ProgressIndicatorThemeData themeData = ProgressIndicatorThemeData( color: Color(0xFFFF0000), linearTrackColor: Color(0xFF00FF00), ); final ProgressIndicatorTheme progressTheme = ProgressIndicatorTheme( data: themeData, child: Builder( builder: (BuildContext context) { builderContext = context; return const LinearProgressIndicator(value: 0.5); } ), ); await tester.pumpWidget(MaterialApp( home: progressTheme, )); final Widget wrappedTheme = progressTheme.wrap(builderContext, Container()); // Make sure the returned widget is a new ProgressIndicatorTheme instance // with the same theme data as the original. expect(wrappedTheme, isNot(equals(progressTheme))); expect(wrappedTheme, isInstanceOf<ProgressIndicatorTheme>()); expect((wrappedTheme as ProgressIndicatorTheme).data, themeData); }); } class _RefreshProgressIndicatorGolden extends StatefulWidget { const _RefreshProgressIndicatorGolden(); @override _RefreshProgressIndicatorGoldenState createState() => _RefreshProgressIndicatorGoldenState(); } class _RefreshProgressIndicatorGoldenState extends State<_RefreshProgressIndicatorGolden> with SingleTickerProviderStateMixin { late final AnimationController controller = AnimationController( vsync: this, duration: const Duration(seconds: 1), ) ..forward() ..addListener(() { setState(() {}); }) ..addStatusListener((AnimationStatus status) { if (status == AnimationStatus.completed) { indeterminate = true; } }); bool indeterminate = false; @override void dispose() { controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Center( child: Directionality( textDirection: TextDirection.ltr, child: RefreshProgressIndicator( value: indeterminate ? null : controller.value, ), ), ); } }