•  


Tap, drag, and enter text | Flutter

Tap, drag, and enter text

Many widgets not only display information, but also respond to user interaction. This includes buttons that can be tapped, and TextField for entering text.

To test these interactions, you need a way to simulate them in the test environment. For this purpose, use the WidgetTester library.

The WidgetTester provides methods for entering text, tapping, and dragging.

In many cases, user interactions update the state of the app. In the test environment, Flutter doesn't automatically rebuild widgets when the state changes. To ensure that the widget tree is rebuilt after simulating a user interaction, call the pump() or pumpAndSettle() methods provided by the WidgetTester . This recipe uses the following steps:

  1. Create a widget to test.
  2. Enter text in the text field.
  3. Ensure tapping a button adds the todo.
  4. Ensure swipe-to-dismiss removes the todo.

1. Create a widget to test

#

For this example, create a basic todo app that tests three features:

  1. Entering text into a TextField .
  2. Tapping a FloatingActionButton to add the text to a list of todos.
  3. Swiping-to-dismiss to remove the item from the list.

To keep the focus on testing, this recipe won't provide a detailed guide on how to build the todo app. To learn more about how this app is built, see the relevant recipes:

dart
class
 TodoList
 extends
 StatefulWidget
 {

  const
 TodoList
({
super
.key});


  @override

  State
<
TodoList
> 
createState
() => 
_TodoListState
();

}


class
 _TodoListState
 extends
 State
<
TodoList
> {

  static
 const
 _appTitle = 
'Todo List'
;

  final
 todos = <
String
>[];

  final
 controller = 
TextEditingController
();


  @override

  Widget
 build
(
BuildContext
 context) {

    return
 MaterialApp
(

      title: _appTitle,

      home: 
Scaffold
(

        appBar: 
AppBar
(

          title: 
const
 Text
(_appTitle),

        ),

        body: 
Column
(

          children: [

            TextField
(

              controller: controller,

            ),

            Expanded
(

              child: 
ListView
.
builder
(

                itemCount: todos.length,

                itemBuilder: (context, index) {

                  final
 todo = todos[index];


                  return
 Dismissible
(

                    key: 
Key
(
'
$
todo
$
index
'
),

                    onDismissed: (direction) => todos.
removeAt
(index),

                    background: 
Container
(color: 
Colors
.red),

                    child: 
ListTile
(title: 
Text
(todo)),

                  );

                },

              ),

            ),

          ],

        ),

        floatingActionButton: 
FloatingActionButton
(

          onPressed: () {

            setState
(() {

              todos.
add
(controller.text);

              controller.
clear
();

            });

          },

          child: 
const
 Icon
(
Icons
.add),

        ),

      ),

    );

  }

}

2. Enter text in the text field

#

Now that you have a todo app, begin writing the test. Start by entering text into the TextField .

Accomplish this task by:

  1. Building the widget in the test environment.
  2. Using the enterText() method from the WidgetTester .
dart
testWidgets
(
'Add and remove a todo'
, (tester) 
async
 {

  // Build the widget

  await
 tester.
pumpWidget
(
const
 TodoList
());


  // Enter 'hi' into the TextField.

  await
 tester.
enterText
(find.
byType
(
TextField
), 
'hi'
);

});

3. Ensure tapping a button adds the todo

#

After entering text into the TextField , ensure that tapping the FloatingActionButton adds the item to the list.

This involves three steps:

  1. Tap the add button using the tap() method.
  2. Rebuild the widget after the state has changed using the pump() method.
  3. Ensure that the list item appears on screen.
dart
testWidgets
(
'Add and remove a todo'
, (tester) 
async
 {

  // Enter text code...


  // Tap the add button.

  await
 tester.
tap
(find.
byType
(
FloatingActionButton
));


  // Rebuild the widget after the state has changed.

  await
 tester.
pump
();


  // Expect to find the item on screen.

  expect
(find.
text
(
'hi'
), findsOneWidget);

});

4. Ensure swipe-to-dismiss removes the todo

#

Finally, ensure that performing a swipe-to-dismiss action on the todo item removes it from the list. This involves three steps:

  1. Use the drag() method to perform a swipe-to-dismiss action.
  2. Use the pumpAndSettle() method to continually rebuild the widget tree until the dismiss animation is complete.
  3. Ensure that the item no longer appears on screen.
dart
testWidgets
(
'Add and remove a todo'
, (tester) 
async
 {

  // Enter text and add the item...


  // Swipe the item to dismiss it.

  await
 tester.
drag
(find.
byType
(
Dismissible
), 
const
 Offset
(
500
, 
0
));


  // Build the widget until the dismiss animation ends.

  await
 tester.
pumpAndSettle
();


  // Ensure that the item is no longer on screen.

  expect
(find.
text
(
'hi'
), findsNothing);

});

Complete example

#
dart
import
 'package:flutter/material.dart'
;

import
 'package:flutter_test/flutter_test.dart'
;


void
 main
() {

  testWidgets
(
'Add and remove a todo'
, (tester) 
async
 {

    // Build the widget.

    await
 tester.
pumpWidget
(
const
 TodoList
());


    // Enter 'hi' into the TextField.

    await
 tester.
enterText
(find.
byType
(
TextField
), 
'hi'
);


    // Tap the add button.

    await
 tester.
tap
(find.
byType
(
FloatingActionButton
));


    // Rebuild the widget with the new item.

    await
 tester.
pump
();


    // Expect to find the item on screen.

    expect
(find.
text
(
'hi'
), findsOneWidget);


    // Swipe the item to dismiss it.

    await
 tester.
drag
(find.
byType
(
Dismissible
), 
const
 Offset
(
500
, 
0
));


    // Build the widget until the dismiss animation ends.

    await
 tester.
pumpAndSettle
();


    // Ensure that the item is no longer on screen.

    expect
(find.
text
(
'hi'
), findsNothing);

  });

}


class
 TodoList
 extends
 StatefulWidget
 {

  const
 TodoList
({
super
.key});


  @override

  State
<
TodoList
> 
createState
() => 
_TodoListState
();

}


class
 _TodoListState
 extends
 State
<
TodoList
> {

  static
 const
 _appTitle = 
'Todo List'
;

  final
 todos = <
String
>[];

  final
 controller = 
TextEditingController
();


  @override

  Widget
 build
(
BuildContext
 context) {

    return
 MaterialApp
(

      title: _appTitle,

      home: 
Scaffold
(

        appBar: 
AppBar
(

          title: 
const
 Text
(_appTitle),

        ),

        body: 
Column
(

          children: [

            TextField
(

              controller: controller,

            ),

            Expanded
(

              child: 
ListView
.
builder
(

                itemCount: todos.length,

                itemBuilder: (context, index) {

                  final
 todo = todos[index];


                  return
 Dismissible
(

                    key: 
Key
(
'
$
todo
$
index
'
),

                    onDismissed: (direction) => todos.
removeAt
(index),

                    background: 
Container
(color: 
Colors
.red),

                    child: 
ListTile
(title: 
Text
(todo)),

                  );

                },

              ),

            ),

          ],

        ),

        floatingActionButton: 
FloatingActionButton
(

          onPressed: () {

            setState
(() {

              todos.
add
(controller.text);

              controller.
clear
();

            });

          },

          child: 
const
 Icon
(
Icons
.add),

        ),

      ),

    );

  }

}
- "漢字路" 한글한자자동변환 서비스는 교육부 고전문헌국역지원사업의 지원으로 구축되었습니다.
- "漢字路" 한글한자자동변환 서비스는 전통문화연구회 "울산대학교한국어처리연구실 옥철영(IT융합전공)교수팀"에서 개발한 한글한자자동변환기를 바탕하여 지속적으로 공동 연구 개발하고 있는 서비스입니다.
- 현재 고유명사(인명, 지명등)을 비롯한 여러 변환오류가 있으며 이를 해결하고자 많은 연구 개발을 진행하고자 하고 있습니다. 이를 인지하시고 다른 곳에서 인용시 한자 변환 결과를 한번 더 검토하시고 사용해 주시기 바랍니다.
- 변환오류 및 건의,문의사항은 juntong@juntong.or.kr로 메일로 보내주시면 감사하겠습니다. .
Copyright ⓒ 2020 By '전통문화연구회(傳統文化硏究會)' All Rights reserved.
 한국   대만   중국   일본