首页 > 解决方案 > 错误“pumpAndSettle 超时”可能是由于riverpod

问题描述

我被小部件测试困住了,我可以使用一些帮助
来重现行为请运行下面的代码示例

import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'home_page.dart';

void main() => runApp(
      const ProviderScope(
        child: MaterialApp(
          home: Material(
            child: MyHomePage(),
          ),
        ),
      ),
    );
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';

extension RoundX on double {
  double roundToPrecision(int n) {
    final f = pow(10, n);
    return (this * f).round() / f;
  }
}

final tasksPod = Provider<List<Future<void> Function()>>(
  (ref) => [
    for (var i = 0; i < 10; ++i)
      () async {
        await Future.delayed(kThemeAnimationDuration);
      }
  ],
);

final progressPod = Provider.autoDispose<ValueNotifier<double>>((ref) {
  final notifier = ValueNotifier<double>(0);
  ref.onDispose(notifier.dispose);
  return notifier;
});

class MyHomePage extends HookWidget {
  const MyHomePage() : super(key: const ValueKey('MyHomePage'));

  @override
  Widget build(BuildContext context) {
    final progress = useProvider(progressPod);
    final tasks = useProvider(tasksPod);
    useMemoized(() async {
      final steps = tasks.length;
      if (steps < 1) {
        progress.value = 1;
      } else {
        for (final task in tasks) {
          final current = progress.value;
          if (current >= 1) {
            break;
          }
          await task();
          final value = (current + 1 / steps).roundToPrecision(1);
          print('$value');
          progress.value = value;
        }
      }
    });
    return Center(
      child: ValueListenableBuilder<double>(
        valueListenable: progress,
        child: const FlutterLogo(),
        builder: (context, value, child) =>
            value < 1 ? const CircularProgressIndicator() : child!,
      ),
    );
  }
}

运行应用程序一切都很好

✓  Built build/app/outputs/flutter-apk/app-debug.apk.
Installing build/app/outputs/flutter-apk/app.apk...                 4.7s
Syncing files to device Pixel 3a...                                 93ms

Flutter run key commands.
r Hot reload. 
R Hot restart.
h Repeat this help message.
d Detach (terminate "flutter run" but leave application running).
c Clear the screen
q Quit (terminate the application on the device).

 Running with sound null safety 

An Observatory debugger and profiler on Pixel 3a is available at: http://127.0.0.1:36517/50vVndYZ3l4=/
I/flutter (19990): 0.1
I/flutter (19990): 0.2
I/flutter (19990): 0.3
I/flutter (19990): 0.4
I/flutter (19990): 0.5
I/flutter (19990): 0.6
I/flutter (19990): 0.7
The Flutter DevTools debugger and profiler on Pixel 3a is available at: http://127.0.0.1:9101?uri=http%3A%2F%2F127.0.0.1%3A36517%2F50vVndYZ3l4%3D%2F
I/flutter (19990): 0.8
I/flutter (19990): 0.9
I/flutter (19990): 1.0
Application finished.

但未通过此测试

import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:timeout_issue/home_page.dart';

void main() {
  testWidgets(
      'WHEN tasks are not completed'
      'THEN shows `CircularProgressIndicator`', (tester) async {
    TestWidgetsFlutterBinding.ensureInitialized();

    await tester.runAsync(() async {
      await tester.pumpWidget(
        ProviderScope(
          child: const MaterialApp(
            home: Material(
              child: MyHomePage(),
            ),
          ),
        ),
      );

      await tester.pumpAndSettle(kThemeAnimationDuration);

      expect(
        find.byType(CircularProgressIndicator),
        findsOneWidget,
        reason: 'CircularProgressIndicator should be shown',
      );
    });
  });
}

有了这个输出

00:05 +0: WHEN tasks are not completedTHEN shows `CircularProgressIndicator`                                                                                                                                
══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞════════════════════════════════════════════════════
The following assertion was thrown while running async test code:
pumpAndSettle timed out

When the exception was thrown, this was the stack:
#0      WidgetTester.pumpAndSettle.<anonymous closure> (package:flutter_test/src/widget_tester.dart:651:11)
<asynchronous suspension>
<asynchronous suspension>
(elided one frame from package:stack_trace)
...
════════════════════════════════════════════════════════════════════════════════════════════════════
00:05 +0 -1: WHEN tasks are not completedTHEN shows `CircularProgressIndicator` [E]                                                                                                                         
  Test failed. See exception logs above.
  The test description was: WHEN tasks are not completedTHEN shows `CircularProgressIndicator`
  
00:05 +0 -1: Some tests failed.                

环境是

Flutter version 2.2.0-11.0.pre.176

environment:
  sdk: ">=2.12.0 <3.0.0"

dependencies:
  flutter:
    sdk: flutter
  hooks_riverpod: ^0.14.0
  flutter_hooks: ^0.16.0

任何帮助表示赞赏

标签: flutterdartriverpodwidget-test-flutterflutter-hooks

解决方案


我想说这个问题与使用 pumpAndSettle 和无限动画(循环进度指示器)有关。您可以尝试使用不带底座的泵来自己构建框架。

https://api.flutter.dev/flutter/flutter_test/WidgetTester/pumpAndSettle.html


推荐阅读