flutter - 构建消费者时抛出了以下 ProviderNotFoundException(肮脏的):
问题描述
该应用程序在我运行时有效。当我单击该图标时,它会显示 LogInFlow 小部件,但在测试中它不会断言它找到了一个带有 Key('LogInFlow') 的小部件。
theftion trible tribrars捕获的例外╞═════════════════════════════════════════ ══════ 在构建 Consumer(dirty) 时抛出以下 ProviderNotFoundException:错误:在此 Consumer Widget 上方找不到正确的 Provider
发生这种情况是因为您使用了BuildContext
不包括您选择的提供者的 。有几种常见的场景:
您在您的中添加了一个新的提供程序
main.dart
并执行了热重载。要修复,请执行热重启。您尝试读取的提供程序位于不同的路径中。
提供者是“范围的”。因此,如果您在路由中插入提供程序,那么其他路由将无法访问该提供程序。
您使用的
BuildContext
是您尝试读取的提供程序的祖先。确保 Consumer 在您的 MultiProvider/Provider 下。这通常发生在您创建提供程序并尝试立即读取它时。
相关的导致错误的小部件是:Consumer file:///C:/Users/calvo/Documents/flutter/projects/freegapp/lib/main.dart:48:5
══╡颤抖测试框架捕获的例外╞════════════════════════════════════════ ════════════ 运行测试时抛出以下 TestFailure 对象: 预期:小部件树中恰好有一个匹配节点 实际:_KeyFinder:<零个带有键 [<'LogInFlow'>] 的小部件(忽略后台小部件)> 其中:表示没有找到,但应该有一个
抛出异常时,这是堆栈:#4 main。(file:///C:/Users/calvo/Documents/flutter/projects/freegapp/test/main_widget_test.dart:25:5)(从包中省略一帧:stack_trace)...
这被以下行的测试期望捕获:file:///C:/Users/calvo/Documents/flutter/projects/freegapp/test/main_widget_test.dart 第 25 行测试描述是:MyStatefulWidget 创建一个默认小部件为主页
══╡颤抖测试框架捕获的例外╞════════════════════════════════════════ ════════════ 抛出以下信息:当前测试运行过程中检测到多个异常(2),至少有一个异常。
** main_widget_test.dart **
// The goal of a widget test is to verify that every widget’s UI looks and behaves as expected.//
// To perform an interaction with a widget in your test, use the WidgetTester
// utility that Flutter provides. For example, you can send tap and scroll
// gestures. You can also use WidgetTester to find child widgets in the widget
// tree, read text, and verify that the values of widget properties are correct.
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:freegapp/main.dart';
void main() {
// The WidgetTester allows building and interacting with widgets in a test environment.
testWidgets('MyStatefulWidget creates a default widget as a homepage',
(WidgetTester tester) async {
// Create the widget by telling the tester to build it. Also triggers a frame.
await tester.pumpWidget(MyApp());
expect(find.byKey(Key('default')), findsOneWidget);
// navigationIndexBar starts at 0 so TheMap should be the widget being displayed.
expect(find.byKey(Key('TheMap')), findsOneWidget);
// tap on navigationIndexBar 1
await tester.tap(find.text('icon'));
// Rebuild the widget after the state has changed.
await tester.pump();
expect(find.byKey(Key('LogInFlow')), findsOneWidget);
await tester.tap(find.text('Map'));
await tester.pump();
expect(find.byKey(Key('TheMap')), findsOneWidget);
});
}
** main.dart **
import 'package:flutter/material.dart';
import 'package:flutter_config/flutter_config.dart';
import 'package:provider/provider.dart';
import 'src/ApplicationStateLogin.dart';
import 'package:freegapp/TheMap.dart';
import 'package:freegapp/src/ApplicationStateLogin.dart';
import 'package:freegapp/src/LogInFlow.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized(); // Required by FlutterConfig
await FlutterConfig.loadEnvVariables();
runApp(
ChangeNotifierProvider(
create: (context) => ApplicationStateLogin(),
builder: (context, _) => MyApp(),
),
);
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Freegap',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyStatefulWidget(key: Key('default')),
);
}
}
class MyStatefulWidget extends StatefulWidget {
MyStatefulWidget({Key? key})
: super(key: key); // Initializes key for subclasses.
@override
_MyStatefulWidgetState createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
// for bottom navigation bar
int _selectedIndex = 0;
// Widget array for bottom navigation bar
static final List<Widget> _widgetOptions = <Widget>[
TheMap(key: Key('TheMap')),
Consumer<ApplicationStateLogin>(
builder: (context, appState, _) => LogInFlow(
email: appState.email,
loginState: appState.loginState,
startLoginFlow: appState.startLoginFlow,
verifyEmail: appState.verifyEmail,
signInWithEmailAndPassword: appState.signInWithEmailAndPassword,
cancelRegistration: appState.cancelRegistration,
registerAccount: appState.registerAccount,
signOut: appState.signOut,
key: Key('LogInFlow')),
),
];
// for bottom navigation bar
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: _widgetOptions.elementAt(_selectedIndex),
),
// body:
bottomNavigationBar: BottomNavigationBar(
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.map_outlined),
label: 'Map',
),
BottomNavigationBarItem(
icon: Icon(Icons.home_outlined),
label: 'icon',
),
],
currentIndex: _selectedIndex,
onTap: _onItemTapped,
),
);
}
}
解决方案
我想到了。我在测试文件中构建了错误的小部件。我需要构建 ChangeNotifierProvider 小部件并提供适当的包。
await tester.pumpWidget(ChangeNotifierProvider(
create: (context) => ApplicationStateFirebase(),
builder: (context, _) => MyApp(),
));
代替
await tester.pumpWidget(MyApp());
推荐阅读
- rest - Optaplanner 7.9.0 无法解组输入字符串错误调用 REST API
- apache - Apache 从 TLSv1.0 重定向到 TLSv1.2
- odoo-8 - 如何更新 invoice.line 数量?
- javascript - 收听来自 iframe 的 ajax 发布响应
- java - Android中按上午/下午时间排序的SQLite
- javascript - 输入值 onchange 不删除错误类
- python - 按索引名称过滤数据框行
- ios - 反应本机中的TextInput显示具有颜色背景的文本值
- c++ - 使用动态矩阵的 Eigen 分解过程中的错误
- google-deployment-manager - 模板模式导入文件夹中的所有文件