[英]Flutter integration testing : Enter text into TextFormField by label
How do I enter text into TextFormField
by using the label text?如何使用 label 文本在
TextFormField
中输入文本? My issue is that I can't find the widget while doing an integration test.我的问题是在进行集成测试时找不到小部件。 I was able to find the widget by adding a key but I don't want to change the source code of the app for doing integration testing.
我可以通过添加一个键找到小部件,但我不想更改应用程序的源代码来进行集成测试。
TextFormField(
controller: usernameController,
decoration: InputDecoration(border: UnderlineInputBorder(), labelText: "Username"),
)
Tried something like this but it doesn't work:尝试过这样的事情,但它不起作用:
final usernameField = find.descendant(
of: find.text("Username"),
matching: find.byType(EditableText),
);
List<TextField> textFields = List<TextField>();
find.byType(TextField).evaluate().toList().forEach((element) {
textFields.add(element.widget);
});
You were on the right track, just a couple of things needed adjusting.你走在正确的轨道上,只是有几件事需要调整。
Try this instead:试试这个:
final usernameField = find.ancestor(
of: find.text('Username'),
matching: find.byType(TextFormField),
);
tester.enterText(usernameField, "testing");
EditableText
EditableText
之间的关系First off, the finder couldn't find an EditableText
related to "Username" because the EditableText
used by TextFormField
is actually a sibling/cousin to any Text
type widgets related to the decoration.首先,查找器找不到与“用户名”相关的
EditableText
,因为TextFormField
使用的EditableText
实际上是与装饰相关的任何Text
类型小部件的兄弟/表亲。
You can take a look at the tree using the Widget Inspector in most IDEs, or if you want to stay completely in the test environment, try debugDumpApp to have the tree output to the console.您可以在大多数 IDE 中使用 Widget Inspector 查看树,或者如果您想完全留在测试环境中,请尝试debugDumpApp将树 output 放到控制台。 As you can see by this part of the tree, there's nothing under the
EditableText
that has the "Username" text in it.从树的这一部分可以看出,
EditableText
下没有任何内容包含“用户名”文本。
TextFormField
tree TextFormField
树│ └TextFormField(dependencies: [UnmanagedRestorationScope, _InheritedTheme, _LocalizationsScope-[GlobalKey#1c7cf]], state: _TextFormFieldState#979c2)
│ └UnmanagedRestorationScope
│ └TextField(controller: TextEditingController#7d830(TextEditingValue(text: ┤├, selection: TextSelection.invalid, composing: TextRange(start: -1, end: -1))), enabled: true, decoration: InputDecoration(labelText: "Username", floatingLabelBehavior: FloatingLabelBehavior.auto, floatingLabelAlignment: FloatingLabelAlignment.start, border: UnderlineInputBorder(), alignLabelWithHint: false), dependencies: [DefaultSelectionStyle, MediaQuery, UnmanagedRestorationScope, _InheritedTheme, _LocalizationsScope-[GlobalKey#1c7cf]], state: _TextFieldState#b279d)
│ └MouseRegion(listeners: [enter, exit], cursor: SystemMouseCursor(text), renderObject: RenderMouseRegion#0773e relayoutBoundary=up3)
│ └TextFieldTapRegion(groupId: EditableText, renderObject: RenderTapRegion#81348)
│ └IgnorePointer(ignoring: false, renderObject: RenderIgnorePointer#4fd71 relayoutBoundary=up5)
│ └AnimatedBuilder(animation: TextEditingController#7d830(TextEditingValue(text: ┤├, selection: TextSelection.invalid, composing: TextRange(start: -1, end: -1))), state: _AnimatedState#59a41)
│ └Semantics(container: false, properties: SemanticsProperties, tooltip: null, renderObject: RenderSemanticsAnnotations#eb417 relayoutBoundary=up6)
│ └TextSelectionGestureDetector(state: _TextSelectionGestureDetectorState#c5ea6)
│ └RawGestureDetector(state: RawGestureDetectorState#1eae5(gestures: [tap, long press, pan], excludeFromSemantics: true, behavior: translucent))
│ └Listener(listeners: [down, panZoomStart], behavior: translucent, renderObject: RenderPointerListener#84fb6 relayoutBoundary=up7)
│ └AnimatedBuilder(animation: Listenable.merge([FocusNode#3118d(context: Focus), TextEditingController#7d830(TextEditingValue(text: ┤├, selection: TextSelection.invalid, composing: TextRange(start: -1, end: -1)))]), state: _AnimatedState#6fcb9)
│ └InputDecorator(decoration: InputDecoration(labelText: "Username", hintMaxLines: "1", floatingLabelBehavior: FloatingLabelBehavior.auto, floatingLabelAlignment: FloatingLabelAlignment.start, border: UnderlineInputBorder(), alignLabelWithHint: false), isFocused: false, isEmpty: true, dependencies: [Directionality, MediaQuery, _InheritedTheme, _LocalizationsScope-[GlobalKey#1c7cf]], state: _InputDecoratorState#cdcb7(tickers: tracking 2 tickers))
│ └_Decorator(renderObject: _RenderDecoration#543bf relayoutBoundary=up8)
│ ├RepaintBoundary(renderObject: RenderRepaintBoundary#932e5 relayoutBoundary=up9)
│ │└UnmanagedRestorationScope
│ │ └EditableText-[LabeledGlobalKey<EditableTextState>#62cb3](controller: TextEditingController#7d830(TextEditingValue(text: ┤├, selection: TextSelection.invalid, composing: TextRange(start: -1, end: -1))), focusNode: FocusNode#3118d, debugLabel: (englishLike titleMedium 2014).merge(blackMountainView titleMedium), inherit: false, color: Color(0xdd000000), family: Roboto, size: 16.0, weight: 400, baseline: alphabetic, decoration: TextDecoration.none, textAlign: start, keyboardType: TextInputType(name: TextInputType.text, signed: null, decimal: null), autofillHints: [], dependencies: [Directionality, MediaQuery, ScrollConfiguration, _EffectiveTickerMode], state: EditableTextState#1c1c0(tickers: tracking 1 ticker))
│ │ └TextFieldTapRegion(debugLabel: EditableText, groupId: EditableText, renderObject: RenderTapRegion#9cbef)
│ │ └MouseRegion(listeners: <none>, cursor: defer, renderObject: RenderMouseRegion#74908 relayoutBoundary=up11)
│ │ └Actions(dispatcher: null, actions: {DoNothingAndStopPropagationTextIntent: DoNothingAction#4a34c, ReplaceTextIntent: CallbackAction<ReplaceTextIntent>#408b9, UpdateSelectionIntent: CallbackAction<UpdateSelectionIntent>#06984, DirectionalFocusIntent: DirectionalFocusAction#2491c, DismissIntent: CallbackAction<DismissIntent>#3e59f, DeleteCharacterIntent: _OverridableContextAction<DeleteCharacterIntent>#690f6(defaultAction: _DeleteTextAction<DeleteCharacterIntent>#0bc91), DeleteToNextWordBoundaryIntent: _OverridableContextAction<DeleteToNextWordBoundaryIntent>#c44ac(defaultAction: _DeleteTextAction<DeleteToNextWordBoundaryIntent>#119b9), DeleteToLineBreakIntent: _OverridableContextAction<DeleteToLineBreakIntent>#af3a8(defaultAction: _DeleteTextAction<DeleteToLineBreakIntent>#9eaed), ExtendSelectionByCharacterIntent: _OverridableContextAction<ExtendSelectionByCharacterIntent>#78905(defaultAction: _UpdateTextSelectionAction<ExtendSelectionByCharacterIntent>#3cb9a), ExtendSelectionToNextWordBoundaryIntent: _OverridableContextAction<ExtendSelectionToNextWordBoundaryIntent>#efea3(defaultAction: _UpdateTextSelectionAction<ExtendSelectionToNextWordBoundaryIntent>#11fdb), ExtendSelectionToLineBreakIntent: _OverridableContextAction<ExtendSelectionToLineBreakIntent>#9cdf0(defaultAction: _UpdateTextSelectionAction<ExtendSelectionToLineBreakIntent>#64825), ExpandSelectionToLineBreakIntent: _OverridableAction<ExpandSelectionToLineBreakIntent>#44e24(defaultAction: CallbackAction<ExpandSelectionToLineBreakIntent>#ce179), ExpandSelectionToDocumentBoundaryIntent: _OverridableAction<ExpandSelectionToDocumentBoundaryIntent>#1f49f(defaultAction: CallbackAction<ExpandSelectionToDocumentBoundaryIntent>#faeb6), ExtendSelectionVerticallyToAdjacentLineIntent: _OverridableContextAction<ExtendSelectionVerticallyToAdjacentLineIntent>#2444b(defaultAction: _UpdateTextSelectionToAdjacentLineAction<ExtendSelectionVerticallyToAdjacentLineIntent>#efbca), ExtendSelectionToDocumentBoundaryIntent: _OverridableContextAction<ExtendSelectionToDocumentBoundaryIntent>#a9b51(defaultAction: _UpdateTextSelectionAction<ExtendSelectionToDocumentBoundaryIntent>#d1374), ExtendSelectionToNextWordBoundaryOrCaretLocationIntent: _OverridableContextAction<ExtendSelectionToNextWordBoundaryOrCaretLocationIntent>#913d5(defaultAction: _ExtendSelectionOrCaretPositionAction#00b6c), ScrollToDocumentBoundaryIntent: _OverridableAction<ScrollToDocumentBoundaryIntent>#96e26(defaultAction: CallbackAction<ScrollToDocumentBoundaryIntent>#f52dc), SelectAllTextIntent: _OverridableContextAction<SelectAllTextIntent>#208ba(defaultAction: _SelectAllAction#1c128), CopySelectionTextIntent: _OverridableContextAction<CopySelectionTextIntent>#31482(defaultAction: _CopySelectionAction#d777b), PasteTextIntent: _OverridableAction<PasteTextIntent>#17ba0(defaultAction: CallbackAction<PasteTextIntent>#fc2e6), TransposeCharactersIntent: _OverridableAction<TransposeCharactersIntent>#909dc(defaultAction: CallbackAction<TransposeCharactersIntent>#826be)}, state: _ActionsState#6345b)
│ │ └_ActionsMarker
│ │ └_TextEditingHistory(state: _TextEditingHistoryState#c5c7e)
│ │ └Actions(dispatcher: null, actions: {UndoTextIntent: _OverridableAction<UndoTextIntent>#76c57(defaultAction: CallbackAction<UndoTextIntent>#a6b68), RedoTextIntent: _OverridableAction<RedoTextIntent>#4244e(defaultAction: CallbackAction<RedoTextIntent>#d89b9)}, state: _ActionsState#a1a96)
│ │ └_ActionsMarker
│ │ └Focus(debugLabel: "EditableText", focusNode: FocusNode#3118d, dependencies: [_FocusMarker], state: _FocusState#f3479)
│ │ └_FocusMarker
│ │ └Scrollable(axisDirection: right, physics: null, restorationId: "editable", dependencies: [MediaQuery, UnmanagedRestorationScope, _InheritedTheme, _LocalizationsScope-[GlobalKey#1c7cf]], state: ScrollableState#2fb51(position: ScrollPositionWithSingleContext#ec8ce(offset: 0.0, range: 0.0..0.0, viewport: 800.0, ScrollableState, ClampingScrollPhysics -> RangeMaintainingScrollPhysics -> ClampingScrollPhysics -> RangeMaintainingScrollPhysics, IdleScrollActivity#259e6, ScrollDirection.idle), effective physics: ClampingScrollPhysics -> RangeMaintainingScrollPhysics -> ClampingScrollPhysics -> RangeMaintainingScrollPhysics))
│ │ └_ScrollableScope
│ │ └Listener(listeners: [signal], behavior: deferToChild, renderObject: RenderPointerListener#dd2ea relayoutBoundary=up12)
│ │ └RawGestureDetector-[LabeledGlobalKey<RawGestureDetectorState>#d6db0](state: RawGestureDetectorState#cda6b(gestures: <none>, excludeFromSemantics: true, behavior: opaque))
│ │ └Listener(listeners: [down, panZoomStart], behavior: opaque, renderObject: RenderPointerListener#0abf9 relayoutBoundary=up13)
│ │ └Semantics(container: false, properties: SemanticsProperties, tooltip: null, renderObject: RenderSemanticsAnnotations#6f0e4 relayoutBoundary=up14)
│ │ └IgnorePointer-[GlobalKey#f9ddb](ignoring: false, ignoringSemantics: false, renderObject: RenderIgnorePointer#015fc relayoutBoundary=up15)
│ │ └CompositedTransformTarget(renderObject: RenderLeaderLayer#bd9fd relayoutBoundary=up16)
│ │ └Semantics(container: false, properties: SemanticsProperties, tooltip: null, renderObject: RenderSemanticsAnnotations#20253 relayoutBoundary=up17)
│ │ └_ScribbleFocusable(state: _ScribbleFocusableState#6511f)
│ │ └_Editable-[GlobalKey#9b870](dependencies: [_LocalizationsScope-[GlobalKey#1c7cf]], renderObject: RenderEditable#7f9ac relayoutBoundary=up18)
│ ├_Shaker(animation: AnimationController#c202f(⏮ 0.000; paused), state: _AnimatedState#77802)
│ │└Transform(dependencies: [Directionality], renderObject: RenderTransform#053a1 relayoutBoundary=up9)
│ │ └AnimatedOpacity(duration: 200ms, opacity: 1.0, state: _AnimatedOpacityState#bcd55(ticker inactive))
│ │ └FadeTransition(opacity: AnimationController#04a30(⏮ 0.000; paused; for AnimatedOpacity)➩Cubic(0.40, 0.00, 0.20, 1.00)➩Tween<double>(1.0 → 1.0)➩1.0, renderObject: RenderAnimatedOpacity#05cbb relayoutBoundary=up10)
│ │ └AnimatedDefaultTextStyle(duration: 200ms, debugLabel: (((englishLike titleMedium 2014).merge(blackMountainView titleMedium)).merge(unknown)).copyWith, inherit: false, color: Color(0x99000000), family: Roboto, size: 16.0, weight: 400, baseline: alphabetic, height: 1.0x, decoration: TextDecoration.none, softWrap: wrapping at box width, overflow: clip, state: _AnimatedDefaultTextStyleState#6c250(ticker inactive))
│ │ └DefaultTextStyle(debugLabel: (((englishLike titleMedium 2014).merge(blackMountainView titleMedium)).merge(unknown)).copyWith, inherit: false, color: Color(0x99000000), family: Roboto, size: 16.0, weight: 400, baseline: alphabetic, height: 1.0x, decoration: TextDecoration.none, softWrap: wrapping at box width, overflow: clip)
│ │ └Text("Username", textAlign: start, overflow: ellipsis, dependencies: [DefaultSelectionStyle, DefaultTextStyle, MediaQuery])
│ │ └RichText(softWrap: wrapping at box width, overflow: ellipsis, maxLines: unlimited, text: "Username", dependencies: [Directionality, _LocalizationsScope-[GlobalKey#1c7cf]], renderObject: RenderParagraph#128a5 relayoutBoundary=up11)
│ ├_HelperError(state: _HelperErrorState#ffb07(ticker inactive))
│ │└SizedBox(renderObject: RenderConstrainedBox#8887a relayoutBoundary=up9)
│ └_BorderContainer(dependencies: [Directionality], state: _BorderContainerState#c1c2f(tickers: tracking 2 tickers))
│ └CustomPaint(renderObject: RenderCustomPaint#f9064)
ancestor
vs. descendant
ancestor
与descendant
Secondly, you needed to use ancestor
instead of descendant
.其次,您需要使用
ancestor
而不是descendant
。 These two methods can be a bit difficult to wrap your head around, but this is how I think of it to keep them straight.这两种方法可能有点难以理解,但这就是我认为保持它们直截了当的方式。
of
finderof
取景器开始of
method, is the thing you want your matching
finder to find back up the tree (less indented), or are you going further down the tree (more indented)?of
方法,您希望matching
的查找器在树上找到备份(缩进较少),还是您要在树下更远(更多缩进)?
ancestor
ancestor
descendant
descendant
ancestor
/ descendant
method will return what matcher
defines, not what of
defines ancestor
/ descendant
方法将返回matcher
定义的内容,而不是定义of
内容I'm taking a guess here, but I think that you were trying to find an EditableText
because the documentation mentions needing one.我在这里猜测,但我认为您试图找到一个
EditableText
因为文档提到需要一个。 Thankfully, it also mentions that you can use something which has a descendant EditableText
.值得庆幸的是,它还提到您可以使用具有后代
EditableText
的东西。
As such, we can find a TextFormField
instead of a EditableText
in the matching
parameter and still use that finder with the enterText method.因此,我们可以在
matching
参数中找到一个TextFormField
而不是EditableText
,并且仍然使用该查找器和enterText方法。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.