| // 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 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({Key? key}) : super(key: key); |
| |
| @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, |
| ), |
| ), |
| ); |
| } |
| } |