{"id":388274,"date":"2024-06-29T07:50:45","date_gmt":"2024-06-29T07:50:45","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=388274"},"modified":"-0001-11-30T00:00:00","modified_gmt":"2024-06-29T07:50:45","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=388274","title":{"rendered":"<span>Flutter: \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u044f UI \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u041c\u044b \u2014 \u043a\u043e\u043c\u0430\u043d\u0434\u0430 \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430 <a href=\"http:\/\/fl.ru\">FL.ru<\/a> (<a href=\"https:\/\/habr.com\/ru\/users\/asms\/\">\u0410\u043b\u0438\u043d\u0430 \u0421\u043c\u0438\u0440\u043d\u043e\u0432\u0430<\/a>, Mobile QA Engineer \u0438 <a href=\"https:\/\/habr.com\/ru\/users\/9teen90nine\/\">\u0412\u0438\u043a\u0442\u043e\u0440 \u041a\u043e\u0442\u043e\u043b\u0435\u0432\u0441\u043a\u0438\u0439<\/a>, Flutter Mobile Development Lead). \u0412 \u0441\u0432\u043e\u0435\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u0445\u043e\u0442\u0438\u043c \u043f\u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c \u0432\u0430\u0441 \u0441 Flutter Driver \u0438 \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u0430\u0442\u044c \u043e\u0431 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u0438 UI \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430. \u041b\u043e\u043d\u0433\u0440\u0438\u0434 \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 \u0434\u0432\u0443\u0445 \u0447\u0430\u0441\u0442\u0435\u0439: \u043f\u0440\u043e \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u044e \u0438 \u043f\u0440\u043e \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f Flutter Driver \u0441 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c.<\/p>\n<p>\u041d\u0430\u0447\u043d\u0435\u043c. <\/p>\n<p>\u041d\u0430\u0448 c\u0435\u0440\u0432\u0438\u0441 <a href=\"http:\/\/fl.ru\">FL.ru<\/a> \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043a\u0440\u0443\u043f\u043d\u0435\u0439\u0448\u0435\u0439 \u0440\u0443\u0441\u0441\u043a\u043e\u044f\u0437\u044b\u0447\u043d\u043e\u0439 \u0431\u0438\u0440\u0436\u0435\u0439 \u0444\u0440\u0438\u043b\u0430\u043d\u0441\u0430. \u041a\u0430\u043a \u0438 \u0432\u0441\u0435 \u043c\u044b \u0441\u0442\u0430\u043b\u043a\u0438\u0432\u0430\u0435\u043c\u0441\u044f \u0432 \u0440\u0430\u0431\u043e\u0442\u0435 \u0441 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u043c\u0438 \u0442\u0440\u0443\u0434\u043d\u043e\u0441\u0442\u044f\u043c\u0438 \u0432 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 \u0438 \u0441\u0442\u0430\u0440\u0430\u0435\u043c\u0441\u044f \u043e\u043f\u0435\u0440\u0430\u0442\u0438\u0432\u043d\u043e \u0440\u0435\u0448\u0430\u0442\u044c \u043f\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0435 \u0437\u0430\u0434\u0430\u0447\u0438. \u0421 \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f FL.ru \u043f\u043e\u044f\u0432\u0438\u043b\u0430\u0441\u044c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u044c \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0430\u0432\u0442\u043e\u0442\u0435\u0441\u0442\u043e\u0432 \u043d\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0435. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u043c\u0441\u044f \u0441 Flutter Driver.\u00a0<\/p>\n<p>Flutter Driver \u2014 \u044d\u0442\u043e \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442, \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u043e \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u043d\u043d\u044b\u0439 \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439, \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0445 \u043d\u0430 Flutter\u041e\u043d \u043e\u0447\u0435\u043d\u044c \u043f\u043e\u0445\u043e\u0436 \u043d\u0430 \u0442\u0430\u043a\u0438\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u044b, \u043a\u0430\u043a Selenium driver, Protractor \u0438 Google Espresso, \u043c\u043e\u0436\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 \u0438 \u043f\u043e\u043c\u043e\u0433\u0430\u0435\u0442 \u043f\u0438\u0441\u0430\u0442\u044c \u0442\u0435\u0441\u0442\u044b \u0434\u043b\u044f \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0433\u043e \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043d\u0430 \u044f\u0437\u044b\u043a\u0435 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f Dart. \u041c\u044b \u0440\u0435\u0448\u0438\u043b\u0438 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c\u0441\u044f \u043d\u0430 Flutter Driver, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043e\u043d \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u0431\u043e\u0439 \u043d\u0430\u0431\u043e\u0440 \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u0445 \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u043e\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043f\u0440\u044f\u043c\u043e \u0438\u0437 \u00ab\u043a\u043e\u0440\u043e\u0431\u043a\u0438\u00bb. <\/p>\n<h3>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f\u00a0<\/h3>\n<p>\u0414\u043b\u044f \u0442\u043e\u0433\u043e \u0447\u0442\u043e\u0431\u044b \u043d\u0430\u0447\u0430\u0442\u044c \u043f\u0438\u0441\u0430\u0442\u044c \u0442\u0435\u0441\u0442\u044b, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u043c\u043e\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043f\u0430\u043a\u0435\u0442 <strong>flutter driver<\/strong> \u0432 \u0444\u0430\u0439\u043b <strong>pubspec.yaml<\/strong>:\u00a0<\/p>\n<pre><code class=\"dart\">flutter_driver:     sdk: flutter   test: any<\/code><\/pre>\n<p>\u041d\u0430\u0431\u043e\u0440\u044b \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0445 \u0442\u0435\u0441\u0442\u043e\u0432 \u043d\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u044e\u0442\u0441\u044f \u0432 \u0442\u043e\u043c \u0436\u0435 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435, \u0447\u0442\u043e \u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u043c\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u043f\u0430\u043f\u043a\u0443 <strong>test driver<\/strong> \u0441 \u0434\u0432\u0443\u043c\u044f \u0444\u0430\u0439\u043b\u0430\u043c\u0438 \u0432\u043d\u0443\u0442\u0440\u0438: <strong>app.dart<\/strong> \u0438 <strong>app_test.dart<\/strong>.\u00a0<\/p>\n<p>\u041f\u0435\u0440\u0432\u044b\u0439 \u0444\u0430\u0439\u043b \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0432 \u0441\u0435\u0431\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u043e\u0441\u043d\u0430\u0449\u0435\u043d\u043d\u043e\u0435 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430\u043c\u0438 \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c \u0447\u0435\u0440\u0435\u0437 \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0435 \u043d\u0430\u0431\u043e\u0440\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u0432\u043e \u0432\u0442\u043e\u0440\u043e\u043c \u0444\u0430\u0439\u043b\u0435.<\/p>\n<p>\u041d\u0430\u0438\u043c\u0435\u043d\u043e\u0432\u0430\u043d\u0438\u0435 \u0444\u0430\u0439\u043b\u0430 <strong>app.dart<\/strong> \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043b\u044e\u0431\u044b\u043c. \u0424\u0430\u0439\u043b <strong>app_test.dart<\/strong> \u0434\u043e\u043b\u0436\u0435\u043d \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044e \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u0430, \u043d\u043e \u0441 \u043e\u043a\u043e\u043d\u0447\u0430\u043d\u0438\u0435\u043c <strong>_test. <\/strong>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u043f\u043e\u044f\u0432\u0438\u0442\u0441\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0430\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430:\u00a0<\/p>\n<pre><code class=\"dart\">my_app\/   lib\/     main.dart   test_driver\/     app.dart     app_test.dart<\/code><\/pre>\n<p>\u0418\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u043c \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435 <strong>flutter_driver <\/strong>\u0432 \u0444\u0430\u0439\u043b <strong>app.dart<\/strong> \u0438 \u0430\u043a\u0442\u0438\u0432\u0438\u0440\u0443\u0435\u043c \u0435\u0433\u043e \u0440\u0430\u0431\u043e\u0442\u0443 \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 main:\u00a0\u00a0<\/p>\n<pre><code class=\"dart\">import 'package:flutter_driver\/driver_extension.dart'; import 'package:counter_app\/main.dart' as app;  void main() {   enableFlutterDriverExtension();   app.main(); }<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0430\u0442\u044c \u043a \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044e \u0442\u0435\u0441\u0442\u043e\u0432 \u0432 \u0444\u0430\u0439\u043b\u0435 <strong>app_test.dart.<\/strong> \u0412 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u0438 \u0441 \u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u0439 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0435\u0439, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438<strong> <\/strong>flutter_driver \u0438 test. \u041f\u0435\u0440\u0432\u0430\u044f \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 API \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f flutter \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043d\u0430 \u044d\u043c\u0443\u043b\u044f\u0442\u043e\u0440\u0430\u0445 \u0438 \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0445 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430\u0445, \u0430 \u0432\u0442\u043e\u0440\u0430\u044f \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u0441\u043f\u043e\u0441\u043e\u0431 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0442\u0435\u0441\u0442\u043e\u0432 \u0432 Dart.\u00a0 \u041f\u0440\u0438\u043c\u0435\u0440 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u0433\u043e \u043d\u0430\u0431\u043e\u0440\u0430:\u00a0<\/p>\n<pre><code class=\"dart\">import 'package:flutter_driver\/flutter_driver.dart'; import 'package:test\/test.dart';     \/\/ \u0422\u0435\u0441\u0442\u044b \u043c\u043e\u0436\u043d\u043e \u0441\u0433\u0440\u0443\u043f\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u0438 group () void main() {   group(My App', () {         FlutterDriver driver;     \/\/ \u041f\u0435\u0440\u0435\u0434 \u0437\u0430\u043f\u0443\u0441\u043a\u043e\u043c \u0442\u0435\u0441\u0442\u043e\u0432 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f \u0441 flutter driver     setUpAll(() async {       driver = await FlutterDriver.connect();     });      \/\/ \u0417\u0430\u0432\u0435\u0440\u0448\u0430\u0435\u043c \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0441 flutter driver \u043f\u043e\u0441\u043b\u0435 \u043f\u0440\u043e\u0433\u043e\u043d\u0430 \u0442\u0435\u0441\u0442\u043e\u0432     tearDownAll(() async {       if (driver != null) {         driver.close();       }     });     \/\/ \u041e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u0442\u0435\u0441\u0442, \u0432 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0442\u0435\u0441\u0442 \u0438\u0449\u0435\u0442 \u0442\u0435\u043a\u0441\u0442, \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0438\u0439 \"0\"      test('starts at 0', () async {    \/\/ \u041e\u0431\u044a\u044f\u0432\u043b\u044f\u0435\u043c \u043b\u043e\u043a\u0430\u0442\u043e\u0440\u044b \u0434\u043b\u044f \u043f\u043e\u0438\u0441\u043a\u0430 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u0432 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0435        final counterTextFinder = find.byValueKey('counter');    \/\/ \u041e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u043c\u0438 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430       expect(await driver.getText(counterTextFinder), \"0\");     });   }); }<\/code><\/pre>\n<p>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u0441\u043e\u0437\u0434\u0430\u0432 \u043b\u043e\u043a\u0430\u0442\u043e\u0440\u044b \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0445 \u0432\u0438\u0434\u0436\u0435\u0442\u043e\u0432, \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0442\u0435\u0441\u0442\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0441\u0442\u0430\u0440\u0442\u0443\u044e\u0442 \u043f\u043e\u0441\u043b\u0435 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043a \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044e \u0447\u0435\u0440\u0435\u0437 \u0444\u0443\u043d\u043a\u0446\u0438\u044e <strong>setUpAll()<\/strong>, \u043f\u0440\u043e\u0445\u043e\u0434\u044f\u0442 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0438 \u0438 \u0437\u0430\u0432\u0435\u0440\u0448\u0430\u044e\u0442\u0441\u044f \u043e\u0442\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435\u043c \u043e\u0442 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0447\u0435\u0440\u0435\u0437 \u0444\u0443\u043d\u043a\u0446\u0438\u044e <strong>tearDownAll()<\/strong>. <\/p>\n<h3>\u041f\u043e\u0438\u0441\u043a \u0438 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u043b\u043e\u043a\u0430\u0442\u043e\u0440\u043e\u0432 <\/h3>\n<p>\u0427\u0442\u043e \u0442\u0430\u043a\u043e\u0435 \u043b\u043e\u043a\u0430\u0442\u043e\u0440\u044b? \u041b\u043e\u043a\u0430\u0442\u043e\u0440 \u2014 \u044d\u0442\u043e \u043a\u043e\u043c\u0430\u043d\u0434\u0430, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0441\u043e\u043e\u0431\u0449\u0430\u0435\u0442 Flutter Driver, \u043a\u0430\u043a\u0438\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u0433\u0440\u0430\u0444\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u043e\u0435 \u043f\u043e\u043b\u0435, \u043a\u043d\u043e\u043f\u043a\u0438, \u0447\u0435\u043a\u0431\u043e\u043a\u0441\u044b \u0438 \u0442. \u0434.) \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u0438\u043c\u0438\u0442\u0430\u0446\u0438\u0438 \u0440\u0430\u0431\u043e\u0442\u044b \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f (\u043f\u0440\u0438 \u043d\u0430\u0436\u0430\u0442\u0438\u0438, \u043f\u0440\u043e\u043b\u0438\u0441\u0442\u044b\u0432\u0430\u043d\u0438\u0438, \u0441\u0432\u0430\u0439\u043f\u0435 \u0438 \u0442.\u0434.).<\/p>\n<p>\u0412\u043e Flutter \u0435\u0441\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u0432 \u043f\u043e\u0438\u0441\u043a\u0430 \u0438 \u043e\u0431\u043e\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u043b\u043e\u043a\u0430\u0442\u043e\u0440\u043e\u0432: bySemanticsLabel, byTooltip, byType, byValueKey.\u00a0<\/p>\n<p>\u0427\u0442\u043e\u0431\u044b \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c UI-\u0442\u0435\u0441\u0442, \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0437\u043d\u0430\u0442\u044c, \u043a\u0430\u043a \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u00ab\u0441\u0441\u044b\u043b\u043a\u0443\u00bb \u043d\u0430 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 \u0434\u043b\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a \u0435\u0433\u043e \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430\u043c. \u0415\u0441\u043b\u0438 \u0443 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430 \u043d\u0435\u0442 \u043b\u043e\u043a\u0430\u0442\u043e\u0440\u0430, \u0441\u0430\u043c\u044b\u0439 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u0438 \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0441\u043f\u043e\u0441\u043e\u0431 \u0434\u043e\u0431\u0438\u0442\u044c\u0441\u044f \u044d\u0442\u043e\u0433\u043e \u2014 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u00ab\u0441\u0441\u044b\u043b\u043a\u0443\u00bb \u043d\u0430 \u043a\u043b\u044e\u0447 (<strong>key<\/strong>) \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 \u0438 \u043d\u0430\u0439\u0442\u0438 \u044d\u0442\u043e\u0442 \u043b\u043e\u043a\u0430\u0442\u043e\u0440 \u043c\u0435\u0442\u043e\u0434\u043e\u043c findbyValueKey().<\/p>\n<p>\u041a\u043b\u044e\u0447 (<strong>key<\/strong>) \u2014 \u044d\u0442\u043e \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u043d\u0430 \u0438\u0441\u043a\u043e\u043c\u044b\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0432 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0435 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430. \u0414\u043e\u043f\u0443\u0441\u0442\u0438\u043c, \u043d\u0430\u043c \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043a\u043b\u044e\u0447 \u0434\u043b\u044f \u043a\u043d\u043e\u043f\u043a\u0438 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0430 \u0432 \u043f\u0440\u043e\u0444\u0438\u043b\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f. \u0421\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u043d\u0443\u0436\u043d\u043e \u0443\u0431\u0435\u0434\u0438\u0442\u044c\u0441\u044f, \u0447\u0442\u043e \u0443 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 (Flat Button) \u0435\u0441\u0442\u044c \u043b\u043e\u043a\u0430\u0442\u043e\u0440 \u0438\u043b\u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0435\u0433\u043e \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u043e:<\/p>\n<pre><code class=\"dart\">return FlatButton(                       key: Key('profileButton'),                       child: Text('\u041f\u0440\u043e\u0444\u0438\u043b\u044c')             )<\/code><\/pre>\n<p>\u0415\u0441\u043b\u0438 \u043d\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043d\u043e, \u0433\u0434\u0435 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 \u0432 \u043a\u043e\u0434\u0435, \u043d\u0430 \u043f\u043e\u043c\u043e\u0449\u044c \u043f\u0440\u0438\u0434\u0443\u0442 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b Android Studio: Flutter Inspector \u0438\u043b\u0438 DevTools.\u00a0 \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e:\u00a0<\/p>\n<ul>\n<li>\n<p>\u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435<\/p>\n<\/li>\n<li>\n<p>\u041e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u043c Flutter Inspector \u0438\u043b\u0438 DevTools<\/p>\n<\/li>\n<li>\n<p>\u041f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u043c \u0432 \u0440\u0435\u0436\u0438\u043c \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0430 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 <strong>Select Widget Mode\u00a0<\/strong><\/p>\n<\/li>\n<\/ul>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0430\u043a\u0442\u0438\u0432\u0430\u0446\u0438\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 Select Widget Mode \u043b\u044e\u0431\u043e\u0435 \u043a\u0430\u0441\u0430\u043d\u0438\u0435 \u043d\u0430 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u043f\u0435\u0440\u0435\u043c\u0435\u0441\u0442\u0438\u0442\u044c\u0441\u044f \u0432 \u043a\u043e\u0434\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043d\u0430 \u0438\u0441\u043a\u043e\u043c\u044b\u0439 \u0432\u0438\u0434\u0436\u0435\u0442.\u00a0<\/p>\n<p>\u0412\u043a\u043b\u044e\u0447\u0438\u0442\u044c Flutter Inspector \u043c\u043e\u0436\u043d\u043e \u0447\u0435\u0440\u0435\u0437 <strong>View > Tool Windows<\/strong> \u0438\u043b\u0438 \u0436\u0435 \u0437\u0430\u0434\u0430\u0442\u044c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443 \u0441\u0442\u0430\u0440\u0442\u0430 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430 \u0441 \u0437\u0430\u043f\u0443\u0441\u043a\u043e\u043c Android Studio \u0447\u0435\u0440\u0435\u0437 <strong>File > Settings > Languages and Frameworks > Open Flutter Inspector on launch<\/strong>.<\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/821\/6c8\/e8a\/8216c8e8a68aea02c525efe7a35e9f3b.png\" alt=\"\" title=\"\" width=\"476\" height=\"426\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/821\/6c8\/e8a\/8216c8e8a68aea02c525efe7a35e9f3b.png\"\/><figcaption><\/figcaption><\/figure>\n<ol>\n<li>\n<p>\u0414\u043e\u0441\u0442\u0443\u043f \u043a Flutter Inspector \u0447\u0435\u0440\u0435\u0437 \u043c\u0435\u043d\u044e <\/p>\n<\/li>\n<\/ol>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/cb7\/4fc\/865\/cb74fc865b6a798ec6baf968066a9649.png\" width=\"1124\" height=\"703\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/cb7\/4fc\/865\/cb74fc865b6a798ec6baf968066a9649.png\"\/><figcaption><\/figcaption><\/figure>\n<p>2. \u0412\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 Flutter Inspector \u043f\u0440\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0435 Android Studio<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/fb7\/be5\/e48\/fb7be5e486f2d73978a798b737bc0ec4.png\" width=\"1320\" height=\"1138\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/fb7\/be5\/e48\/fb7be5e486f2d73978a798b737bc0ec4.png\"\/><figcaption><\/figcaption><\/figure>\n<p>3. \u041f\u0440\u0438\u043c\u0435\u0440 \u0440\u0430\u0431\u043e\u0442\u044b \u0444\u0443\u043d\u043a\u0446\u0438\u0438 Select Widget Mode \u0438\u0437 Flutter Inspector<\/p>\n<p>\u0427\u0435\u0440\u0435\u0437 <strong>DevTools<\/strong> \u2014 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 \u043d\u0430\u0431\u043e\u0440 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u0434\u043b\u044f \u043e\u0442\u043b\u0430\u0434\u043a\u0438 \u043f\u043e\u0434 Flutter, \u0442\u0430\u043a\u0436\u0435 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u044d\u0442\u043e\u0442 \u0436\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b, \u0437\u0430 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435\u043c \u0442\u043e\u0433\u043e, \u0447\u0442\u043e DevTools \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435. <\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/59e\/783\/3e9\/59e7833e9676889f6fd8f4fc5f16f17b.png\" width=\"575\" height=\"116\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/59e\/783\/3e9\/59e7833e9676889f6fd8f4fc5f16f17b.png\"\/><figcaption><\/figcaption><\/figure>\n<p>4. \u0418\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 DevTools \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0438\u0437 \u0432\u043a\u043b\u0430\u0434\u043a\u0438 Run<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/13f\/91a\/daf\/13f91adaf5f67535edd4f33b709e9597.png\" width=\"1462\" height=\"948\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/13f\/91a\/daf\/13f91adaf5f67535edd4f33b709e9597.png\"\/><figcaption><\/figcaption><\/figure>\n<p>5. \u041f\u0440\u0438\u043c\u0435\u0440 \u0440\u0430\u0431\u043e\u0442\u044b \u0444\u0443\u043d\u043a\u0446\u0438\u0438 Select Widget Mode \u0438\u0437 DevTools<\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e \u043a\u0430\u043a \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u043d\u0430\u0439\u0434\u0435\u043d, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u00ab\u0441\u0441\u044b\u043b\u043a\u0443\u00bb \u043d\u0430 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 \u0432 \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u043c \u0444\u0430\u0439\u043b\u0435:<\/p>\n<pre><code class=\"dart\">final userProfile = find.byValueKey('profileButton');<\/code><\/pre>\n<p>\u0418 \u043e\u043f\u0438\u0441\u0430\u0442\u044c \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0432 \u0442\u0435\u043b\u0435 \u0442\u0435\u0441\u0442\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0441 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u043c, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0438\u0442\u044c \u043d\u0430\u0436\u0430\u0442\u0438\u0435 \u0438\u043b\u0438 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u0442\u0435\u043a\u0441\u0442 \u043d\u0430 \u043a\u043d\u043e\u043f\u043a\u0435:<\/p>\n<pre><code class=\"dart\">await driver.tap(userProfile); expect(await driver.getText(userProfile), \"\u041f\u0440\u043e\u0444\u0438\u043b\u044c\");<\/code><\/pre>\n<p>\u0427\u0442\u043e\u0431\u044b \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0442\u0435\u0441\u0442\u044b \u0431\u043e\u043b\u0435\u0435 \u0447\u0438\u0442\u0430\u0435\u043c\u044b\u043c\u0438 \u0438 \u0443\u0434\u043e\u0431\u043d\u044b\u043c\u0438 \u0432 \u043e\u0431\u0441\u043b\u0443\u0436\u0438\u0432\u0430\u043d\u0438\u0438, \u0438\u0445 \u043c\u043e\u0436\u043d\u043e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u043f\u043e\u0434\u0445\u043e\u0434\u0430 DRY, \u0442\u043e \u0435\u0441\u0442\u044c \u043f\u043e\u043c\u0435\u0441\u0442\u0438\u0442\u044c \u0432\u0441\u0435 \u043b\u043e\u043a\u0430\u0442\u043e\u0440\u044b \u0432 \u043e\u0434\u043d\u043e\u043c \u043c\u0435\u0441\u0442\u0435 \u0438\u043b\u0438 \u0440\u0430\u0437\u0431\u0438\u0442\u044c \u0438\u0445 \u043d\u0430 \u043a\u043b\u0430\u0441\u0441\u044b \u043f\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u0443 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0412 \u0441\u043b\u0443\u0447\u0430\u0435, \u0435\u0441\u043b\u0438 UI \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u043a\u0430\u043a\u043e\u0433\u043e-\u0442\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430 \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u0441\u044f, \u0442\u043e \u043c\u044b \u0438\u0437\u043c\u0435\u043d\u0438\u043c \u043b\u043e\u043a\u0430\u0442\u043e\u0440 \u043b\u0438\u0448\u044c \u0432 \u043e\u0434\u043d\u043e\u043c \u043c\u0435\u0441\u0442\u0435, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043a\u043b\u0430\u0441\u0441 \u043b\u043e\u043a\u0430\u0442\u043e\u0440\u043e\u0432 \u0434\u043b\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u043f\u0440\u043e\u0444\u0438\u043b\u044f:<\/p>\n<pre><code class=\"dart\">abstract class ProfileIds {  static const profileAvatar = \"profileAvatar\";   static const buttonFeedback = \"buttonFeedback\";  static const editProfileButton = \"editProfileButton\";  static const portfolioButton = \"portfolioButton\";  }<\/code><\/pre>\n<h3>\u041c\u0435\u0442\u043e\u0434\u044b Flutter Driver\u00a0<\/h3>\n<p>\u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043c\u0435\u0442\u043e\u0434\u044b \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u043e\u043c \u0442\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u043c\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0442 \u0441\u043e\u0431\u043e\u0439 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0441\u043f\u0438\u0441\u043e\u043a:\u00a0<\/p>\n<ul>\n<li>\n<p>tap() \u2014 \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442 \u0442\u0430\u043f \u043f\u043e \u0446\u0435\u043d\u0442\u0440\u0443 \u0432\u0438\u0434\u0436\u0435\u0442\u0430;<\/p>\n<\/li>\n<li>\n<p>screenshot() \u2014 \u0441\u043e\u0437\u0434\u0430\u0435\u0442 \u0441\u043d\u0438\u043c\u043e\u043a \u044d\u043a\u0440\u0430\u043d\u0430;<\/p>\n<\/li>\n<li>\n<p>enterText() \u2014 \u0432\u0432\u043e\u0434\u0438\u0442 \u0442\u0435\u043a\u0441\u0442 \u0432 \u043f\u043e\u043b\u0435 \u0434\u043b\u044f \u0432\u0432\u043e\u0434\u0430, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0444\u043e\u043a\u0443\u0441;\u00a0<\/p>\n<\/li>\n<li>\n<p>getText() \u2014 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0442\u0435\u043a\u0441\u0442 \u0438\u0437 \u0432\u0438\u0434\u0436\u0435\u0442\u0430;\u00a0<\/p>\n<\/li>\n<li>\n<p>scroll() \u2014 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u043f\u0440\u043e\u043a\u0440\u0443\u0442\u043a\u0438 \u044d\u043a\u0440\u0430\u043d\u0430;<\/p>\n<\/li>\n<li>\n<p>scrollIntoView() \u2014 \u043f\u0440\u043e\u043a\u0440\u0443\u0447\u0438\u0432\u0430\u0435\u0442 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0441\u043e \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e\u043c Scrollable \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d \u0438\u0441\u043a\u043e\u043c\u044b\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442;\u00a0<\/p>\n<\/li>\n<li>\n<p>scrollUntilVisible() \u2014 \u043f\u043e\u0432\u0442\u043e\u0440\u044f\u0435\u0442 \u043f\u0440\u043e\u043a\u0440\u0443\u0442\u043a\u0443 \u0432\u0438\u0434\u0436\u0435\u0442\u0430\u00a0 \u0441\u043e \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e\u043c Scrollable \u0434\u043e \u0442\u0435\u0445 \u043f\u043e\u0440, \u043f\u043e\u043a\u0430 \u0438\u0441\u043a\u043e\u043c\u044b\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u043d\u0435 \u043f\u043e\u044f\u0432\u0438\u0442\u0441\u044f \u043d\u0430 \u044d\u043a\u0440\u0430\u043d\u0435.<\/p>\n<\/li>\n<\/ul>\n<h3>\u0417\u0430\u043f\u0443\u0441\u043a \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0445 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0435\u0432<\/h3>\n<pre><code class=\"dart\">flutter drive --target=test_driver\/app.dart<\/code><\/pre>\n<p>\u0414\u0430\u043d\u043d\u0430\u044f \u043a\u043e\u043c\u0430\u043d\u0434\u0430 \u0441\u043e\u0437\u0434\u0430\u0435\u0442 \u0431\u0438\u043b\u0434 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438 \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442 \u0435\u0433\u043e \u043d\u0430 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e\/\u044d\u043c\u0443\u043b\u044f\u0442\u043e\u0440, \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u044d\u0442\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0438 \u043f\u0440\u043e\u0433\u043e\u043d \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0445 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0435\u0432 \u0438\u0437 \u0438\u0437 \u0444\u0430\u0439\u043b\u0430 app_test.dart.\u00a0<\/p>\n<p>\u0414\u043b\u044f \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430 \u043c\u043e\u0436\u043d\u043e \u0440\u0430\u0437\u0431\u0438\u0442\u044c \u0442\u0435\u0441\u0442\u044b \u043d\u0430 \u0433\u0440\u0443\u043f\u043f\u044b \u0444\u0430\u0439\u043b\u043e\u0432 \u043f\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u0443 \u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0438\u0445 \u043f\u043e \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 (\u0438\u043b\u0438 \u0432\u0441\u0435 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043f\u0435\u0440\u0432\u043e\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0435\u0441\u043b\u0438 \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438\u0445 \u0432 app_test.dart):<\/p>\n<pre><code class=\"dart\">flutter drive --driver=test_driver\/ui\/login\/login_test.dart --target=test_driver\/ui\/app.dart<\/code><\/pre>\n<h3>\u041f\u0440\u0438\u043c\u0435\u0440\u044b \u0440\u0430\u0431\u043e\u0442\u044b \u043c\u0435\u0442\u043e\u0434\u043e\u0432 Flutter Driver<\/h3>\n<p>\u041d\u0430\u0436\u0438\u043c\u0430\u0435\u043c \u043d\u0430 \u0447\u0435\u043a\u0431\u043e\u043a\u0441, \u043f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e, \u043a\u0430\u043a \u043e\u043d \u043f\u043e\u044f\u0432\u0438\u0442\u0441\u044f \u043d\u0430 \u044d\u043a\u0440\u0430\u043d\u0435:<\/p>\n<pre><code class=\"dart\">final checkbox = find.byValueKey('checkboxItem');  await driver.waitFor(checkbox ).then((_) => driver.tap(checkbox));<\/code><\/pre>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/367\/9a8\/8c4\/3679a88c41462b0908989ecbb9e56726.gif\" width=\"720\" height=\"1238\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/367\/9a8\/8c4\/3679a88c41462b0908989ecbb9e56726.gif\"\/><figcaption><\/figcaption><\/figure>\n<p>\u041f\u0440\u043e\u043b\u0438\u0441\u0442\u044b\u0432\u0430\u0435\u043c \u0441\u043f\u0438\u0441\u043e\u043a \u0437\u0430\u043a\u0430\u0437\u043e\u0432 \u0434\u043e \u043f\u0435\u0440\u0432\u043e\u0439 \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0438: <\/p>\n<pre><code class=\"dart\">final feedList = find.byValueKey(FeedIds.newFeedList); final feedItem = find.byValueKey(feedProjectCard + \"1\");  await driver.scrollUntilVisible(feedList, feedItem, dyScroll: -300);<\/code><\/pre>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/03a\/7f1\/db0\/03a7f1db01780cb571c3e6f6c2221179.gif\" width=\"720\" height=\"1238\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/03a\/7f1\/db0\/03a7f1db01780cb571c3e6f6c2221179.gif\"\/><figcaption><\/figcaption><\/figure>\n<p>\u041e\u0442\u0432\u0435\u0447\u0430\u0435\u043c \u0432 \u0447\u0430\u0442\u0435:<\/p>\n<pre><code class=\"dart\">final fieldMessage = find.byValueKey(MessageIds.fieldMessage); final sendMessage = find.byValueKey(MessageIds.buttonSendMessage);  await driver.tap(fieldMessage); await driver.enterText(\"\u0417\u0434\u0440\u0430\u0432\u0441\u0442\u0432\u0443\u0439\u0442\u0435\"); await driver.waitFor(sendMessage).then((_) => driver.tap(sendMessage)); await driver.waitFor(find.text(\"\u0417\u0434\u0440\u0430\u0432\u0441\u0442\u0432\u0443\u0439\u0442\u0435\"));<\/code><\/pre>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/312\/417\/f5e\/312417f5e14015c2ee6cad786ee2e245.gif\" width=\"464\" height=\"821\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/312\/417\/f5e\/312417f5e14015c2ee6cad786ee2e245.gif\"\/><figcaption><\/figcaption><\/figure>\n<p>\u041d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0442\u0435\u0441\u0442\u043e\u0432 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 \u0438\u043c\u0435\u0435\u0442 \u043c\u043d\u043e\u0433\u043e \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432. \u042d\u0442\u043e \u043e\u0434\u0438\u043d \u0438\u0437 \u0441\u0430\u043c\u044b\u0445 \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0445 \u0442\u0438\u043f\u043e\u0432 \u0442\u0435\u0441\u0442\u043e\u0432 \u0432 \u043f\u0438\u0440\u0430\u043c\u0438\u0434\u0435 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043e\u043d\u0438 \u043d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u0431\u043b\u0438\u0437\u043a\u0438 \u043a \u043e\u043f\u044b\u0442\u0443 \u043a\u043e\u043d\u0435\u0447\u043d\u043e\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0438 \u0434\u0430\u0434\u0443\u0442 \u0432\u0430\u043c \u0443\u0432\u0435\u0440\u0435\u043d\u043d\u043e\u0441\u0442\u044c \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u0432\u0430\u0448\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0434\u043e\u043b\u0436\u043d\u044b\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c.\u00a0<\/p>\n<p>\u0412 \u0437\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0438 \u0434\u0430\u043d\u043d\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u0445\u043e\u0447\u0443 \u043f\u043e\u0434\u0435\u043b\u0438\u0442\u044c\u0441\u044f \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430\u043c\u0438, \u0441 \u043a\u043e\u0442\u043e\u0440\u044b\u043c\u0438 \u043c\u044b \u0441\u0442\u043e\u043b\u043a\u043d\u0443\u043b\u0438\u0441\u044c \u043f\u0440\u0438 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0441 Flutter Driver:\u00a0<\/p>\n<ol>\n<li>\n<p>\u043c\u0435\u0434\u043b\u0435\u043d\u043d\u043e\u0435 \u043f\u0440\u043e\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u0435 \u0442\u0435\u0441\u0442\u043e\u0432 \u2014 \u0434\u043b\u044f \u0443\u0441\u043a\u043e\u0440\u0435\u043d\u0438\u044f \u043c\u044b \u0443\u0431\u0440\u0430\u043b\u0438 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044e \u043d\u0430 \u043a\u0430\u0436\u0434\u043e\u043c \u0442\u0435\u0441\u0442\u0435;<\/p>\n<\/li>\n<li>\n<p>\u043f\u043b\u043e\u0445\u043e \u0447\u0438\u0442\u0430\u0435\u043c\u0430\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043f\u0440\u0438 \u0443\u0432\u0435\u043b\u0438\u0447\u0435\u043d\u0438\u0438 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u0442\u0435\u0441\u0442\u043e\u0432 \u2014 \u0434\u043b\u044f \u0438\u0441\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u044d\u0442\u043e\u0439 \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u0438 \u043c\u044b \u0440\u0430\u0437\u0434\u0435\u043b\u0438\u043b\u0438 \u0438\u0445 \u043f\u043e \u0433\u0440\u0443\u043f\u043f\u0430\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u0430;\u00a0<\/p>\n<\/li>\n<li>\n<p>\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044c \u0442\u0435\u0441\u0442\u043e\u0432 \u043e\u0442 \u0440\u0430\u0431\u043e\u0442\u044b back-end \u2014- \u0440\u0435\u0448\u0430\u0435\u043c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u043c\u043e\u043a\u043e\u0432 \u0432 \u0442\u0435\u0441\u0442\u0430\u0445. <\/p>\n<\/li>\n<\/ol>\n<h3>\u0420\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f Flutter Driver \u0441 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c<\/h3>\n<p>Flutter Driver \u043e\u0431\u043b\u0430\u0434\u0430\u0435\u0442 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c\u044e \u0434\u043b\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c \u043d\u0430 \u0443\u0440\u043e\u0432\u043d\u0435 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430, \u0430 \u0438\u043c\u0435\u043d\u043d\u043e \u0442\u0430\u043f\u044b, \u0432\u0432\u043e\u0434 \u0442\u0435\u043a\u0441\u0442\u0430, \u043f\u0440\u043e\u043a\u0440\u0443\u0442\u043a\u0430, \u043f\u043e\u0438\u0441\u043a \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u043f\u043e \u043a\u043b\u044e\u0447\u0443 \u0438 \u0442.\u0434. \u041d\u043e \u043f\u043e\u0440\u043e\u0439 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0431\u043e\u043b\u0435\u0435 \u0441\u043b\u043e\u0436\u043d\u044b\u0435 \u0441\u0445\u0435\u043c\u044b \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0434\u043b\u044f \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0435\u043d\u0438\u044f \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0445 \u0443\u0441\u043b\u043e\u0432\u0438\u0439 \u043f\u0440\u043e\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u044f \u0442\u0435\u0441\u0442\u043e\u0432. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u043d\u0430 \u044d\u043a\u0440\u0430\u043d\u0435 \u0435\u0441\u0442\u044c \u0432\u0438\u0434\u0436\u0435\u0442, \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043d\u0435 \u0443\u0434\u0430\u0441\u0442\u0441\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u043f\u0440\u043e\u0441\u0442\u044b\u043c driver.getText. \u0418\u043b\u0438 \u0434\u043b\u044f \u043f\u0440\u043e\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u044f \u0442\u0435\u0441\u0442\u0430 \u043d\u0443\u0436\u043d\u043e \u0441\u044b\u043c\u0438\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043e\u0442\u0432\u0435\u0442 \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u0430. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u043c\u0435\u0442\u043e\u0434 enableFlutterDriverExtension, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0432\u044b\u0437\u0432\u0430\u0442\u044c \u043f\u0435\u0440\u0435\u0434 \u0437\u0430\u043f\u0443\u0441\u043a\u043e\u043c \u0442\u0435\u0441\u0442\u043e\u0432 \u0432 \u0433\u043b\u0430\u0432\u043d\u043e\u043c \u043c\u0435\u0442\u043e\u0434\u0435 main.\u00a0<\/p>\n<p>\u041c\u0435\u0442\u043e\u0434 enableFlutterDriverExtension \u0438\u043c\u0435\u0435\u0442 \u0442\u0440\u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430: DataHandler handler, bool silenceErrors, List&lt;FinderExtension> finders. \u0420\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u044d\u0442\u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e.<\/p>\n<p>\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 DataHandler handler \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u0435\u0439:\u00a0<\/p>\n<pre><code class=\"dart\">Future&lt;String> Function(String message) <\/code><\/pre>\n<p>\u041e\u043d\u0430 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439, \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u043d\u044b\u0445 \u0447\u0435\u0440\u0435\u0437 \u043c\u0435\u0442\u043e\u0434 driver.requrestData. \u041d\u0438\u0436\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d \u043f\u0440\u0438\u043c\u0435\u0440 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u044d\u0442\u043e\u0433\u043e \u043c\u0435\u0442\u043e\u0434\u0430.<\/p>\n<pre><code class=\"dart\">void main() {  enableFlutterDriverExtension(handler: (string) => UITestMessageHandler.handle(string));   \/\/\/ \u0417\u0430\u043f\u0443\u0441\u043a driver \u0442\u0435\u0441\u0442\u043e\u0432  \/\/\/ runApp(); }  abstract class UITestMessageHandler {  static final _messageHandlers = &lt;UITestMessageHandler>[    GetStringMessageHandler(),  ];   static Future&lt;String> handle(String message) async {    try {      final json = jsonDecode(message);      final type = json['type'];      final data = json['data'];      return _messageHandlers.firstWhere((handler) => handler.canHandle(type), orElse: () => null)?.handleMessage(data) ?? null;    } catch (e) {      return null;    }  }   bool canHandle(String type);   Future&lt;String> handleMessage(data); }  class GetStringMessage extends UITestMessage {  static const String typeId = 'GetStringMessage';   GetStringMessage(String stringKey) : super(stringKey);   @override  String get type => typeId; }  class GetStringMessageHandler extends UITestMessageHandler {  @override  bool canHandle(String type) => type == GetStringMessage.typeId;   @override  Future&lt;String> handleMessage(data) async {    if (data != null &amp;&amp; data is String) {      final s = await S.load(Locale('ru', ''));      switch (data) {        case StringKey.messageOk:          return s.message_ok;        case StringKey.messageCancel:          return s.message_cancel;      }    }    return null;  } }  class StringKey {  static const messageOk = \"messageOk\";  static const messageCancel = \"messageCancel\"; }<\/code><\/pre>\n<p>\u0412 \u0434\u0430\u043d\u043d\u043e\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0432\u0441\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043f\u0435\u0440\u0435\u0434\u0430\u044e\u0442\u0441\u044f \u0432 \u0432\u0438\u0434\u0435 json \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u0441 \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u043c\u0438 \u043f\u043e\u043b\u044f\u043c\u0438 type \u0438 data. \u0422\u0438\u043f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f (type) \u043f\u043e\u043c\u043e\u0433\u0430\u0435\u0442 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u043a\u043b\u0430\u0441\u0441, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f. \u0412 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 GetStringMessage \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u043a\u043b\u0430\u0441\u0441 GetStringMessageHandler. \u041c\u0435\u0442\u043e\u0434 handleMessage \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0437\u0432\u0430\u043d \u0443\u0436\u0435 \u0432\u043d\u0443\u0442\u0440\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0442\u0435\u043c \u0441\u0430\u043c\u044b\u043c \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u043b\u043e\u043a\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0441\u0442\u0440\u043e\u043a\u0438 \u043f\u043e \u043a\u043b\u044e\u0447\u0443 \u0438\u0437 \u043a\u043b\u0430\u0441\u0441\u0430 StringKey, \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0432\u043d\u0443\u0442\u0440\u0438 \u0442\u0435\u0441\u0442\u0430 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0432\u044b\u0437\u043e\u0432:<\/p>\n<pre><code class=\"dart\">static Future&lt;void> assertString(FlutterDriver driver, String stringKey, {String keyId}) async {  final stringValue = await driver.requestData(GetStringMessage(stringKey).toString());  expect(await driver.getText(find.text(stringValue), stringValue); }<\/code><\/pre>\n<p>\u0412 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0430 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u0431\u0435\u0437 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u043a \u0441\u0435\u0440\u0432\u0435\u0440\u0443:<\/p>\n<pre><code class=\"dart\">class AuthorizeMessageHandler extends UITestMessageHandler {  @override  bool canHandle(String type) => type == AuthorizeMessage.typeId;   @override  Future&lt;String> handleMessage(data) async {    if (data != null &amp;&amp; data is Map&lt;String, dynamic>) {      final user = User.fromJson(data['user']);       return DiProvider.get&lt;LoginService>() .statuses.add(user).then((value) => 'ok');    }    return null;  } }  class AuthorizeMessage extends UITestMessage {  static const String typeId = 'AuthorizeMessage';   AuthorizeMessage(User user) : super({    'user': user.toJson(),  });   @override  String get type => typeId; }<\/code><\/pre>\n<p>\u041a\u043b\u0430\u0441\u0441 LoginService, \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0449\u0438\u0439 API \u0434\u043b\u044f \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438, \u0438\u043c\u0435\u0435\u0442 \u043f\u043e\u043b\u0435 PublishSubject&lt;User> statuses. \u0412 \u043f\u0440\u043e\u0441\u0442\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435, \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0432\u0432\u043e\u0434\u0438\u0442 \u043b\u043e\u0433\u0438\u043d\/\u043f\u0430\u0440\u043e\u043b\u044c, \u043f\u043e\u0441\u043b\u0435 \u0447\u0435\u0433\u043e \u044d\u0442\u0438 \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u0435\u0440\u0435\u0434\u0430\u044e\u0442\u0441\u044f \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440, \u0433\u0434\u0435 \u0443\u0436\u0435 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f. \u0414\u0430\u043b\u0435\u0435 \u0441\u0435\u0440\u0432\u0435\u0440 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043e\u0431\u044a\u0435\u043a\u0442 User, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0443\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432 \u043f\u043e\u0442\u043e\u043a statuses. \u0422\u0435\u043f\u0435\u0440\u044c, \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e AuthorizeMessageHandler, \u043d\u0430\u043c \u043d\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043f\u0440\u043e\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u0435 \u044d\u043a\u0440\u0430\u043d\u043e\u0432 \u0432\u0432\u043e\u0434\u0430 \u043b\u043e\u0433\u0438\u043d\u0430\/\u043f\u0430\u0440\u043e\u043b\u044f, \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0445 \u0442\u0435\u0441\u0442\u043e\u0432.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/5e2\/2cd\/8d1\/5e22cd8d1d3d2fd6ce55badf96980677.gif\" width=\"640\" height=\"1196\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/5e2\/2cd\/8d1\/5e22cd8d1d3d2fd6ce55badf96980677.gif\"\/><figcaption><\/figcaption><\/figure>\n<p>\u0414\u0430\u043b\u0435\u0435 \u043c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 List&lt;FinderExtension> finders. \u042d\u0442\u043e\u0442 \u0441\u043f\u0438\u0441\u043e\u043a \u0445\u0440\u0430\u043d\u0438\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0435 \u043a\u043b\u0430\u0441\u0441\u044b \u0434\u043b\u044f \u043f\u043e\u0438\u0441\u043a\u0430 \u0438 \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438 \u0432\u0438\u0434\u0436\u0435\u0442\u043e\u0432. \u041d\u0438\u0436\u0435 \u043f\u0440\u0438\u0432\u0435\u0434\u0435\u043d \u043f\u0440\u0438\u043c\u0435\u0440 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 FinderExtension \u0434\u043b\u044f \u043f\u043e\u0438\u0441\u043a\u0430 \u0432\u0438\u0434\u0436\u0435\u0442\u0430 MyWidget \u043f\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044e \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430 param.<\/p>\n<pre><code class=\"dart\">class MyWidget extends StatelessWidget {  final String param;  const MyWidget(this.param, {Key key}) : super(key: key);   @override  Widget build(BuildContext context) {    \/\/\/ build MyWidget  } }  class MyWidgetFinder extends SerializableFinder {  const MyWidgetFinder(this.param);   final String param;   @override  String get finderType => 'MyWidget';   @override  Map&lt;String, String> serialize() => super.serialize()    ..addAll({'param': param}); }  class MyWidgetFinderExtension extends FinderExtension {   String get finderType => 'MyWidget';   SerializableFinder deserialize(Map&lt;String, String> params, DeserializeFinderFactory finderFactory) {    return MyWidgetFinder(params['param']);  }   Finder createFinder(SerializableFinder finder) {    MyWidgetFinder myWidgetFinder = finder as MyWidgetFinder;     return myWidgetFinder.byElementPredicate((Element element) {      final Widget widget = element.widget;      if (element.widget is MyWidget) {        return element.widget.param == myWidgetFinder.param;      }      return false;    });  } <\/code><\/pre>\n<p>\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 silenceErrors \u0433\u043e\u0432\u043e\u0440\u0438\u0442 \u0441\u0430\u043c \u0437\u0430 \u0441\u0435\u0431\u044f: \u0435\u0441\u043b\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 true, \u0442\u043e \u0432\u043e\u0437\u043d\u0438\u043a\u0448\u0438\u0435 \u0432 \u0445\u043e\u0434\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043d\u0435 \u0431\u0443\u0434\u0443\u0442 \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f.<\/p>\n<p>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, Flutter Driver \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c \u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0449\u0438\u043a\u0430\u043c-\u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0442\u043e\u0440\u0430\u043c \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u0441\u0432\u043e\u0438 \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u0434\u043b\u044f \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446\u0438\u0438 \u0441\u043b\u043e\u0436\u043d\u044b\u0445 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0445 \u0442\u0435\u0441\u0442\u043e\u0432. \u0412 \u0440\u0430\u043c\u043a\u0430\u0445 \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430 FL.ru \u043c\u044b \u0441\u043c\u043e\u0433\u043b\u0438 \u043b\u0435\u0433\u043a\u043e \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0442\u0435\u0441\u0442\u044b \u043a CI, \u0447\u0442\u043e \u043f\u043e\u043c\u043e\u0433\u043b\u043e \u043d\u0430\u043c \u0443\u0441\u043a\u043e\u0440\u0438\u0442\u044c \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0438 \u043f\u043e\u0432\u044b\u0441\u0438\u0442\u044c \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u043e: \u0442\u0435\u043f\u0435\u0440\u044c \u0441\u0431\u043e\u0438 \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0438\u0432\u0430\u044e\u0442\u0441\u044f \u0431\u044b\u0441\u0442\u0440\u0435\u0435 \u0438, \u043a\u0430\u043a \u0442\u0430\u043a\u043e\u0432\u044b\u0435, \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0431\u044b\u0441\u0442\u0440\u0435\u0435 \u0443\u0441\u0442\u0440\u0430\u043d\u0435\u043d\u044b, \u0447\u0442\u043e \u0432\u0435\u0434\u0435\u0442 \u043a \u0431\u043e\u043b\u0435\u0435 \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u0438\u0432\u043d\u043e\u043c\u0443 \u0444\u043b\u043e\u0443 \u0440\u0430\u0431\u043e\u0442\u044b. <\/p>\n<p>\u0421\u0435\u0439\u0447\u0430\u0441\u00a0FL.ru\u00a0\u0430\u043a\u0442\u0438\u0432\u043d\u043e \u0440\u0430\u0441\u0442\u0451\u0442 \u0438 \u0440\u0430\u0441\u0448\u0438\u0440\u044f\u0435\u0442\u0441\u044f. \u0423 \u043d\u0430\u0441 \u0443\u0436\u0435 \u0435\u0441\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u043e\u0432\u044b\u0445 \u043a\u043e\u043c\u0430\u043d\u0434 \u0438 \u043c\u044b \u043f\u043b\u0430\u043d\u0438\u0440\u0443\u0435\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u043d\u043e\u0432\u044b\u0435. \u041c\u044b \u0441\u0435\u0439\u0447\u0430\u0441 \u043d\u0430\u0445\u043e\u0434\u0438\u043c\u0441\u044f \u0432 \u0430\u043a\u0442\u0438\u0432\u043d\u043e\u043c \u043f\u043e\u0438\u0441\u043a\u0435:<\/p>\n<ul>\n<li>\n<p>PHP \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432<\/p>\n<\/li>\n<li>\n<p>Web QA \u0438\u043d\u0436\u0435\u043d\u0435\u0440\u043e\u0432<\/p>\n<\/li>\n<li>\n<p>Mobile Flutter \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432<\/p>\n<\/li>\n<li>\n<p>DevOps \u0438\u043d\u0436\u0435\u043d\u0435\u0440\u043e\u0432<\/p>\n<\/li>\n<\/ul>\n<p>\u0415\u0441\u043b\u0438 \u0432\u0430\u043c \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0435\u043d \u043f\u0440\u043e\u0435\u043a\u0442, \u0431\u0443\u0434\u0435\u043c \u0440\u0430\u0434\u044b \u0432\u0430\u0448\u0438\u043c \u043e\u0442\u043a\u043b\u0438\u043a\u0430\u043c \u043d\u0430 <a href=\"mailto:y.starshevsky@fl.ru\">y.starshevsky@fl.ru<\/a><\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/591915\/\"> https:\/\/habr.com\/ru\/articles\/591915\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u041c\u044b \u2014 \u043a\u043e\u043c\u0430\u043d\u0434\u0430 \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430 <a href=\"http:\/\/fl.ru\">FL.ru<\/a> (<a href=\"https:\/\/habr.com\/ru\/users\/asms\/\">\u0410\u043b\u0438\u043d\u0430 \u0421\u043c\u0438\u0440\u043d\u043e\u0432\u0430<\/a>, Mobile QA Engineer \u0438 <a href=\"https:\/\/habr.com\/ru\/users\/9teen90nine\/\">\u0412\u0438\u043a\u0442\u043e\u0440 \u041a\u043e\u0442\u043e\u043b\u0435\u0432\u0441\u043a\u0438\u0439<\/a>, Flutter Mobile Development Lead). \u0412 \u0441\u0432\u043e\u0435\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u0445\u043e\u0442\u0438\u043c \u043f\u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c \u0432\u0430\u0441 \u0441 Flutter Driver \u0438 \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u0430\u0442\u044c \u043e\u0431 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u0438 UI \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430. \u041b\u043e\u043d\u0433\u0440\u0438\u0434 \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 \u0434\u0432\u0443\u0445 \u0447\u0430\u0441\u0442\u0435\u0439: \u043f\u0440\u043e \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u044e \u0438 \u043f\u0440\u043e \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f Flutter Driver \u0441 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c.<\/p>\n<p>\u041d\u0430\u0447\u043d\u0435\u043c. <\/p>\n<p>\u041d\u0430\u0448 c\u0435\u0440\u0432\u0438\u0441 <a href=\"http:\/\/fl.ru\">FL.ru<\/a> \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043a\u0440\u0443\u043f\u043d\u0435\u0439\u0448\u0435\u0439 \u0440\u0443\u0441\u0441\u043a\u043e\u044f\u0437\u044b\u0447\u043d\u043e\u0439 \u0431\u0438\u0440\u0436\u0435\u0439 \u0444\u0440\u0438\u043b\u0430\u043d\u0441\u0430. \u041a\u0430\u043a \u0438 \u0432\u0441\u0435 \u043c\u044b \u0441\u0442\u0430\u043b\u043a\u0438\u0432\u0430\u0435\u043c\u0441\u044f \u0432 \u0440\u0430\u0431\u043e\u0442\u0435 \u0441 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u043c\u0438 \u0442\u0440\u0443\u0434\u043d\u043e\u0441\u0442\u044f\u043c\u0438 \u0432 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 \u0438 \u0441\u0442\u0430\u0440\u0430\u0435\u043c\u0441\u044f \u043e\u043f\u0435\u0440\u0430\u0442\u0438\u0432\u043d\u043e \u0440\u0435\u0448\u0430\u0442\u044c \u043f\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0435 \u0437\u0430\u0434\u0430\u0447\u0438. \u0421 \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f FL.ru \u043f\u043e\u044f\u0432\u0438\u043b\u0430\u0441\u044c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u044c \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0430\u0432\u0442\u043e\u0442\u0435\u0441\u0442\u043e\u0432 \u043d\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0435. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u043c\u0441\u044f \u0441 Flutter Driver.\u00a0<\/p>\n<p>Flutter Driver \u2014 \u044d\u0442\u043e \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442, \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u043e \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u043d\u043d\u044b\u0439 \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439, \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0445 \u043d\u0430 Flutter\u041e\u043d \u043e\u0447\u0435\u043d\u044c \u043f\u043e\u0445\u043e\u0436 \u043d\u0430 \u0442\u0430\u043a\u0438\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u044b, \u043a\u0430\u043a Selenium driver, Protractor \u0438 Google Espresso, \u043c\u043e\u0436\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 \u0438 \u043f\u043e\u043c\u043e\u0433\u0430\u0435\u0442 \u043f\u0438\u0441\u0430\u0442\u044c \u0442\u0435\u0441\u0442\u044b \u0434\u043b\u044f \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0433\u043e \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043d\u0430 \u044f\u0437\u044b\u043a\u0435 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f Dart. \u041c\u044b \u0440\u0435\u0448\u0438\u043b\u0438 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c\u0441\u044f \u043d\u0430 Flutter Driver, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043e\u043d \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u0431\u043e\u0439 \u043d\u0430\u0431\u043e\u0440 \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u0445 \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u043e\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043f\u0440\u044f\u043c\u043e \u0438\u0437 \u00ab\u043a\u043e\u0440\u043e\u0431\u043a\u0438\u00bb. <\/p>\n<h3>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f\u00a0<\/h3>\n<p>\u0414\u043b\u044f \u0442\u043e\u0433\u043e \u0447\u0442\u043e\u0431\u044b \u043d\u0430\u0447\u0430\u0442\u044c \u043f\u0438\u0441\u0430\u0442\u044c \u0442\u0435\u0441\u0442\u044b, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u043c\u043e\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043f\u0430\u043a\u0435\u0442 <strong>flutter driver<\/strong> \u0432 \u0444\u0430\u0439\u043b <strong>pubspec.yaml<\/strong>:\u00a0<\/p>\n<pre><code class=\"dart\">flutter_driver:     sdk: flutter   test: any<\/code><\/pre>\n<p>\u041d\u0430\u0431\u043e\u0440\u044b \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0445 \u0442\u0435\u0441\u0442\u043e\u0432 \u043d\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u044e\u0442\u0441\u044f \u0432 \u0442\u043e\u043c \u0436\u0435 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435, \u0447\u0442\u043e \u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u043c\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u043f\u0430\u043f\u043a\u0443 <strong>test driver<\/strong> \u0441 \u0434\u0432\u0443\u043c\u044f \u0444\u0430\u0439\u043b\u0430\u043c\u0438 \u0432\u043d\u0443\u0442\u0440\u0438: <strong>app.dart<\/strong> \u0438 <strong>app_test.dart<\/strong>.\u00a0<\/p>\n<p>\u041f\u0435\u0440\u0432\u044b\u0439 \u0444\u0430\u0439\u043b \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0432 \u0441\u0435\u0431\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u043e\u0441\u043d\u0430\u0449\u0435\u043d\u043d\u043e\u0435 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430\u043c\u0438 \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c \u0447\u0435\u0440\u0435\u0437 \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0435 \u043d\u0430\u0431\u043e\u0440\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u0432\u043e \u0432\u0442\u043e\u0440\u043e\u043c \u0444\u0430\u0439\u043b\u0435.<\/p>\n<p>\u041d\u0430\u0438\u043c\u0435\u043d\u043e\u0432\u0430\u043d\u0438\u0435 \u0444\u0430\u0439\u043b\u0430 <strong>app.dart<\/strong> \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043b\u044e\u0431\u044b\u043c. \u0424\u0430\u0439\u043b <strong>app_test.dart<\/strong> \u0434\u043e\u043b\u0436\u0435\u043d \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044e \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u0430, \u043d\u043e \u0441 \u043e\u043a\u043e\u043d\u0447\u0430\u043d\u0438\u0435\u043c <strong>_test. <\/strong>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u043f\u043e\u044f\u0432\u0438\u0442\u0441\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0430\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430:\u00a0<\/p>\n<pre><code class=\"dart\">my_app\/   lib\/     main.dart   test_driver\/     app.dart     app_test.dart<\/code><\/pre>\n<p>\u0418\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u043c \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435 <strong>flutter_driver <\/strong>\u0432 \u0444\u0430\u0439\u043b <strong>app.dart<\/strong> \u0438 \u0430\u043a\u0442\u0438\u0432\u0438\u0440\u0443\u0435\u043c \u0435\u0433\u043e \u0440\u0430\u0431\u043e\u0442\u0443 \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 main:\u00a0\u00a0<\/p>\n<pre><code class=\"dart\">import 'package:flutter_driver\/driver_extension.dart'; import 'package:counter_app\/main.dart' as app;  void main() {   enableFlutterDriverExtension();   app.main(); }<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0430\u0442\u044c \u043a \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044e \u0442\u0435\u0441\u0442\u043e\u0432 \u0432 \u0444\u0430\u0439\u043b\u0435 <strong>app_test.dart.<\/strong> \u0412 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u0438 \u0441 \u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u0439 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0435\u0439, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438<strong> <\/strong>flutter_driver \u0438 test. \u041f\u0435\u0440\u0432\u0430\u044f \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 API \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f flutter \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043d\u0430 \u044d\u043c\u0443\u043b\u044f\u0442\u043e\u0440\u0430\u0445 \u0438 \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0445 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430\u0445, \u0430 \u0432\u0442\u043e\u0440\u0430\u044f \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u0441\u043f\u043e\u0441\u043e\u0431 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0442\u0435\u0441\u0442\u043e\u0432 \u0432 Dart.\u00a0 \u041f\u0440\u0438\u043c\u0435\u0440 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u0433\u043e \u043d\u0430\u0431\u043e\u0440\u0430:\u00a0<\/p>\n<pre><code class=\"dart\">import 'package:flutter_driver\/flutter_driver.dart'; import 'package:test\/test.dart';     \/\/ \u0422\u0435\u0441\u0442\u044b \u043c\u043e\u0436\u043d\u043e \u0441\u0433\u0440\u0443\u043f\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u0438 group () void main() {   group(My App', () {         FlutterDriver driver;     \/\/ \u041f\u0435\u0440\u0435\u0434 \u0437\u0430\u043f\u0443\u0441\u043a\u043e\u043c \u0442\u0435\u0441\u0442\u043e\u0432 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f \u0441 flutter driver     setUpAll(() async {       driver = await FlutterDriver.connect();     });      \/\/ \u0417\u0430\u0432\u0435\u0440\u0448\u0430\u0435\u043c \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0441 flutter driver \u043f\u043e\u0441\u043b\u0435 \u043f\u0440\u043e\u0433\u043e\u043d\u0430 \u0442\u0435\u0441\u0442\u043e\u0432     tearDownAll(() async {       if (driver != null) {         driver.close();       }     });     \/\/ \u041e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u0442\u0435\u0441\u0442, \u0432 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0442\u0435\u0441\u0442 \u0438\u0449\u0435\u0442 \u0442\u0435\u043a\u0441\u0442, \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0438\u0439 \"0\"      test('starts at 0', () async {    \/\/ \u041e\u0431\u044a\u044f\u0432\u043b\u044f\u0435\u043c \u043b\u043e\u043a\u0430\u0442\u043e\u0440\u044b \u0434\u043b\u044f \u043f\u043e\u0438\u0441\u043a\u0430 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u0432 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0435        final counterTextFinder = find.byValueKey('counter');    \/\/ \u041e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u043c\u0438 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430       expect(await driver.getText(counterTextFinder), \"0\");     });   }); }<\/code><\/pre>\n<p>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u0441\u043e\u0437\u0434\u0430\u0432 \u043b\u043e\u043a\u0430\u0442\u043e\u0440\u044b \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0445 \u0432\u0438\u0434\u0436\u0435\u0442\u043e\u0432, \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0442\u0435\u0441\u0442\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0441\u0442\u0430\u0440\u0442\u0443\u044e\u0442 \u043f\u043e\u0441\u043b\u0435 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043a \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044e \u0447\u0435\u0440\u0435\u0437 \u0444\u0443\u043d\u043a\u0446\u0438\u044e <strong>setUpAll()<\/strong>, \u043f\u0440\u043e\u0445\u043e\u0434\u044f\u0442 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0438 \u0438 \u0437\u0430\u0432\u0435\u0440\u0448\u0430\u044e\u0442\u0441\u044f \u043e\u0442\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435\u043c \u043e\u0442 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0447\u0435\u0440\u0435\u0437 \u0444\u0443\u043d\u043a\u0446\u0438\u044e <strong>tearDownAll()<\/strong>. <\/p>\n<h3>\u041f\u043e\u0438\u0441\u043a \u0438 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u043b\u043e\u043a\u0430\u0442\u043e\u0440\u043e\u0432 <\/h3>\n<p>\u0427\u0442\u043e \u0442\u0430\u043a\u043e\u0435 \u043b\u043e\u043a\u0430\u0442\u043e\u0440\u044b? \u041b\u043e\u043a\u0430\u0442\u043e\u0440 \u2014 \u044d\u0442\u043e \u043a\u043e\u043c\u0430\u043d\u0434\u0430, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0441\u043e\u043e\u0431\u0449\u0430\u0435\u0442 Flutter Driver, \u043a\u0430\u043a\u0438\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u0433\u0440\u0430\u0444\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u043e\u0435 \u043f\u043e\u043b\u0435, \u043a\u043d\u043e\u043f\u043a\u0438, \u0447\u0435\u043a\u0431\u043e\u043a\u0441\u044b \u0438 \u0442. \u0434.) \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u0438\u043c\u0438\u0442\u0430\u0446\u0438\u0438 \u0440\u0430\u0431\u043e\u0442\u044b \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f (\u043f\u0440\u0438 \u043d\u0430\u0436\u0430\u0442\u0438\u0438, \u043f\u0440\u043e\u043b\u0438\u0441\u0442\u044b\u0432\u0430\u043d\u0438\u0438, \u0441\u0432\u0430\u0439\u043f\u0435 \u0438 \u0442.\u0434.).<\/p>\n<p>\u0412\u043e Flutter \u0435\u0441\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u0432 \u043f\u043e\u0438\u0441\u043a\u0430 \u0438 \u043e\u0431\u043e\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u043b\u043e\u043a\u0430\u0442\u043e\u0440\u043e\u0432: bySemanticsLabel, byTooltip, byType, byValueKey.\u00a0<\/p>\n<p>\u0427\u0442\u043e\u0431\u044b \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c UI-\u0442\u0435\u0441\u0442, \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0437\u043d\u0430\u0442\u044c, \u043a\u0430\u043a \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u00ab\u0441\u0441\u044b\u043b\u043a\u0443\u00bb \u043d\u0430 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 \u0434\u043b\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a \u0435\u0433\u043e \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430\u043c. \u0415\u0441\u043b\u0438 \u0443 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430 \u043d\u0435\u0442 \u043b\u043e\u043a\u0430\u0442\u043e\u0440\u0430, \u0441\u0430\u043c\u044b\u0439 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u0438 \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0441\u043f\u043e\u0441\u043e\u0431 \u0434\u043e\u0431\u0438\u0442\u044c\u0441\u044f \u044d\u0442\u043e\u0433\u043e \u2014 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u00ab\u0441\u0441\u044b\u043b\u043a\u0443\u00bb \u043d\u0430 \u043a\u043b\u044e\u0447 (<strong>key<\/strong>) \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 \u0438 \u043d\u0430\u0439\u0442\u0438 \u044d\u0442\u043e\u0442 \u043b\u043e\u043a\u0430\u0442\u043e\u0440 \u043c\u0435\u0442\u043e\u0434\u043e\u043c findbyValueKey().<\/p>\n<p>\u041a\u043b\u044e\u0447 (<strong>key<\/strong>) \u2014 \u044d\u0442\u043e \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u043d\u0430 \u0438\u0441\u043a\u043e\u043c\u044b\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0432 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0435 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430. \u0414\u043e\u043f\u0443\u0441\u0442\u0438\u043c, \u043d\u0430\u043c \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043a\u043b\u044e\u0447 \u0434\u043b\u044f \u043a\u043d\u043e\u043f\u043a\u0438 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0430 \u0432 \u043f\u0440\u043e\u0444\u0438\u043b\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f. \u0421\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u043d\u0443\u0436\u043d\u043e \u0443\u0431\u0435\u0434\u0438\u0442\u044c\u0441\u044f, \u0447\u0442\u043e \u0443 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 (Flat Button) \u0435\u0441\u0442\u044c \u043b\u043e\u043a\u0430\u0442\u043e\u0440 \u0438\u043b\u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0435\u0433\u043e \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u043e:<\/p>\n<pre><code class=\"dart\">return FlatButton(                       key: Key('profileButton'),                       child: Text('\u041f\u0440\u043e\u0444\u0438\u043b\u044c')             )<\/code><\/pre>\n<p>\u0415\u0441\u043b\u0438 \u043d\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043d\u043e, \u0433\u0434\u0435 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 \u0432 \u043a\u043e\u0434\u0435, \u043d\u0430 \u043f\u043e\u043c\u043e\u0449\u044c \u043f\u0440\u0438\u0434\u0443\u0442 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b Android Studio: Flutter Inspector \u0438\u043b\u0438 DevTools.\u00a0 \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e:\u00a0<\/p>\n<ul>\n<li>\n<p>\u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435<\/p>\n<\/li>\n<li>\n<p>\u041e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u043c Flutter Inspector \u0438\u043b\u0438 DevTools<\/p>\n<\/li>\n<li>\n<p>\u041f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u043c \u0432 \u0440\u0435\u0436\u0438\u043c \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0430 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 <strong>Select Widget Mode\u00a0<\/strong><\/p>\n<\/li>\n<\/ul>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0430\u043a\u0442\u0438\u0432\u0430\u0446\u0438\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 Select Widget Mode \u043b\u044e\u0431\u043e\u0435 \u043a\u0430\u0441\u0430\u043d\u0438\u0435 \u043d\u0430 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u043f\u0435\u0440\u0435\u043c\u0435\u0441\u0442\u0438\u0442\u044c\u0441\u044f \u0432 \u043a\u043e\u0434\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043d\u0430 \u0438\u0441\u043a\u043e\u043c\u044b\u0439 \u0432\u0438\u0434\u0436\u0435\u0442.\u00a0<\/p>\n<p>\u0412\u043a\u043b\u044e\u0447\u0438\u0442\u044c Flutter Inspector \u043c\u043e\u0436\u043d\u043e \u0447\u0435\u0440\u0435\u0437 <strong>View > Tool Windows<\/strong> \u0438\u043b\u0438 \u0436\u0435 \u0437\u0430\u0434\u0430\u0442\u044c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443 \u0441\u0442\u0430\u0440\u0442\u0430 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430 \u0441 \u0437\u0430\u043f\u0443\u0441\u043a\u043e\u043c Android Studio \u0447\u0435\u0440\u0435\u0437 <strong>File > Settings > Languages and Frameworks > Open Flutter Inspector on launch<\/strong>.<\/p>\n<figure class=\"\"><figcaption><\/figcaption><\/figure>\n<ol>\n<li>\n<p>\u0414\u043e\u0441\u0442\u0443\u043f \u043a Flutter Inspector \u0447\u0435\u0440\u0435\u0437 \u043c\u0435\u043d\u044e <\/p>\n<\/li>\n<\/ol>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>2. \u0412\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 Flutter Inspector \u043f\u0440\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0435 Android Studio<\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>3. \u041f\u0440\u0438\u043c\u0435\u0440 \u0440\u0430\u0431\u043e\u0442\u044b \u0444\u0443\u043d\u043a\u0446\u0438\u0438 Select Widget Mode \u0438\u0437 Flutter Inspector<\/p>\n<p>\u0427\u0435\u0440\u0435\u0437 <strong>DevTools<\/strong> \u2014 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 \u043d\u0430\u0431\u043e\u0440 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u0434\u043b\u044f \u043e\u0442\u043b\u0430\u0434\u043a\u0438 \u043f\u043e\u0434 Flutter, \u0442\u0430\u043a\u0436\u0435 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u044d\u0442\u043e\u0442 \u0436\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b, \u0437\u0430 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435\u043c \u0442\u043e\u0433\u043e, \u0447\u0442\u043e DevTools \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435. <\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>4. \u0418\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 DevTools \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0438\u0437 \u0432\u043a\u043b\u0430\u0434\u043a\u0438 Run<\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>5. \u041f\u0440\u0438\u043c\u0435\u0440 \u0440\u0430\u0431\u043e\u0442\u044b \u0444\u0443\u043d\u043a\u0446\u0438\u0438 Select Widget Mode \u0438\u0437 DevTools<\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e \u043a\u0430\u043a \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u043d\u0430\u0439\u0434\u0435\u043d, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u00ab\u0441\u0441\u044b\u043b\u043a\u0443\u00bb \u043d\u0430 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 \u0432 \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u043c \u0444\u0430\u0439\u043b\u0435:<\/p>\n<pre><code class=\"dart\">final userProfile = find.byValueKey('profileButton');<\/code><\/pre>\n<p>\u0418 \u043e\u043f\u0438\u0441\u0430\u0442\u044c \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0432 \u0442\u0435\u043b\u0435 \u0442\u0435\u0441\u0442\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0441 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u043c, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0438\u0442\u044c \u043d\u0430\u0436\u0430\u0442\u0438\u0435 \u0438\u043b\u0438 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u0442\u0435\u043a\u0441\u0442 \u043d\u0430 \u043a\u043d\u043e\u043f\u043a\u0435:<\/p>\n<pre><code class=\"dart\">await driver.tap(userProfile); expect(await driver.getText(userProfile), \"\u041f\u0440\u043e\u0444\u0438\u043b\u044c\");<\/code><\/pre>\n<p>\u0427\u0442\u043e\u0431\u044b \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0442\u0435\u0441\u0442\u044b \u0431\u043e\u043b\u0435\u0435 \u0447\u0438\u0442\u0430\u0435\u043c\u044b\u043c\u0438 \u0438 \u0443\u0434\u043e\u0431\u043d\u044b\u043c\u0438 \u0432 \u043e\u0431\u0441\u043b\u0443\u0436\u0438\u0432\u0430\u043d\u0438\u0438, \u0438\u0445 \u043c\u043e\u0436\u043d\u043e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u043f\u043e\u0434\u0445\u043e\u0434\u0430 DRY, \u0442\u043e \u0435\u0441\u0442\u044c \u043f\u043e\u043c\u0435\u0441\u0442\u0438\u0442\u044c \u0432\u0441\u0435 \u043b\u043e\u043a\u0430\u0442\u043e\u0440\u044b \u0432 \u043e\u0434\u043d\u043e\u043c \u043c\u0435\u0441\u0442\u0435 \u0438\u043b\u0438 \u0440\u0430\u0437\u0431\u0438\u0442\u044c \u0438\u0445 \u043d\u0430 \u043a\u043b\u0430\u0441\u0441\u044b \u043f\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u0443 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0412 \u0441\u043b\u0443\u0447\u0430\u0435, \u0435\u0441\u043b\u0438 UI \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u043a\u0430\u043a\u043e\u0433\u043e-\u0442\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430 \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u0441\u044f, \u0442\u043e \u043c\u044b \u0438\u0437\u043c\u0435\u043d\u0438\u043c \u043b\u043e\u043a\u0430\u0442\u043e\u0440 \u043b\u0438\u0448\u044c \u0432 \u043e\u0434\u043d\u043e\u043c \u043c\u0435\u0441\u0442\u0435, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043a\u043b\u0430\u0441\u0441 \u043b\u043e\u043a\u0430\u0442\u043e\u0440\u043e\u0432 \u0434\u043b\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u043f\u0440\u043e\u0444\u0438\u043b\u044f:<\/p>\n<pre><code class=\"dart\">abstract class ProfileIds {  static const profileAvatar = \"profileAvatar\";   static const buttonFeedback = \"buttonFeedback\";  static const editProfileButton = \"editProfileButton\";  static const portfolioButton = \"portfolioButton\";  }<\/code><\/pre>\n<h3>\u041c\u0435\u0442\u043e\u0434\u044b Flutter Driver\u00a0<\/h3>\n<p>\u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043c\u0435\u0442\u043e\u0434\u044b \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u043e\u043c \u0442\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u043c\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0442 \u0441\u043e\u0431\u043e\u0439 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0441\u043f\u0438\u0441\u043e\u043a:\u00a0<\/p>\n<ul>\n<li>\n<p>tap() \u2014 \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442 \u0442\u0430\u043f \u043f\u043e \u0446\u0435\u043d\u0442\u0440\u0443 \u0432\u0438\u0434\u0436\u0435\u0442\u0430;<\/p>\n<\/li>\n<li>\n<p>screenshot() \u2014 \u0441\u043e\u0437\u0434\u0430\u0435\u0442 \u0441\u043d\u0438\u043c\u043e\u043a \u044d\u043a\u0440\u0430\u043d\u0430;<\/p>\n<\/li>\n<li>\n<p>enterText() \u2014 \u0432\u0432\u043e\u0434\u0438\u0442 \u0442\u0435\u043a\u0441\u0442 \u0432 \u043f\u043e\u043b\u0435 \u0434\u043b\u044f \u0432\u0432\u043e\u0434\u0430, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0444\u043e\u043a\u0443\u0441;\u00a0<\/p>\n<\/li>\n<li>\n<p>getText() \u2014 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0442\u0435\u043a\u0441\u0442 \u0438\u0437 \u0432\u0438\u0434\u0436\u0435\u0442\u0430;\u00a0<\/p>\n<\/li>\n<li>\n<p>scroll() \u2014 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u043f\u0440\u043e\u043a\u0440\u0443\u0442\u043a\u0438 \u044d\u043a\u0440\u0430\u043d\u0430;<\/p>\n<\/li>\n<li>\n<p>scrollIntoView() \u2014 \u043f\u0440\u043e\u043a\u0440\u0443\u0447\u0438\u0432\u0430\u0435\u0442 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0441\u043e \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e\u043c Scrollable \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d \u0438\u0441\u043a\u043e\u043c\u044b\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442;\u00a0<\/p>\n<\/li>\n<li>\n<p>scrollUntilVisible() \u2014 \u043f\u043e\u0432\u0442\u043e\u0440\u044f\u0435\u0442 \u043f\u0440\u043e\u043a\u0440\u0443\u0442\u043a\u0443 \u0432\u0438\u0434\u0436\u0435\u0442\u0430\u00a0 \u0441\u043e \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e\u043c Scrollable \u0434\u043e \u0442\u0435\u0445 \u043f\u043e\u0440, \u043f\u043e\u043a\u0430 \u0438\u0441\u043a\u043e\u043c\u044b\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u043d\u0435 \u043f\u043e\u044f\u0432\u0438\u0442\u0441\u044f \u043d\u0430 \u044d\u043a\u0440\u0430\u043d\u0435.<\/p>\n<\/li>\n<\/ul>\n<h3>\u0417\u0430\u043f\u0443\u0441\u043a \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0445 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0435\u0432<\/h3>\n<pre><code class=\"dart\">flutter drive --target=test_driver\/app.dart<\/code><\/pre>\n<p>\u0414\u0430\u043d\u043d\u0430\u044f \u043a\u043e\u043c\u0430\u043d\u0434\u0430 \u0441\u043e\u0437\u0434\u0430\u0435\u0442 \u0431\u0438\u043b\u0434 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438 \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442 \u0435\u0433\u043e \u043d\u0430 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e\/\u044d\u043c\u0443\u043b\u044f\u0442\u043e\u0440, \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u044d\u0442\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0438 \u043f\u0440\u043e\u0433\u043e\u043d \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0445 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0435\u0432 \u0438\u0437 \u0438\u0437 \u0444\u0430\u0439\u043b\u0430 app_test.dart.\u00a0<\/p>\n<p>\u0414\u043b\u044f \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430 \u043c\u043e\u0436\u043d\u043e \u0440\u0430\u0437\u0431\u0438\u0442\u044c \u0442\u0435\u0441\u0442\u044b \u043d\u0430 \u0433\u0440\u0443\u043f\u043f\u044b \u0444\u0430\u0439\u043b\u043e\u0432 \u043f\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u0443 \u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0438\u0445 \u043f\u043e \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 (\u0438\u043b\u0438 \u0432\u0441\u0435 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043f\u0435\u0440\u0432\u043e\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0435\u0441\u043b\u0438 \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438\u0445 \u0432 app_test.dart):<\/p>\n<pre><code class=\"dart\">flutter drive --driver=test_driver\/ui\/login\/login_test.dart --target=test_driver\/ui\/app.dart<\/code><\/pre>\n<h3>\u041f\u0440\u0438\u043c\u0435\u0440\u044b \u0440\u0430\u0431\u043e\u0442\u044b \u043c\u0435\u0442\u043e\u0434\u043e\u0432 Flutter Driver<\/h3>\n<p>\u041d\u0430\u0436\u0438\u043c\u0430\u0435\u043c \u043d\u0430 \u0447\u0435\u043a\u0431\u043e\u043a\u0441, \u043f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e, \u043a\u0430\u043a \u043e\u043d \u043f\u043e\u044f\u0432\u0438\u0442\u0441\u044f \u043d\u0430 \u044d\u043a\u0440\u0430\u043d\u0435:<\/p>\n<pre><code class=\"dart\">final checkbox = find.byValueKey('checkboxItem');  await driver.waitFor(checkbox ).then((_) => driver.tap(checkbox));<\/code><\/pre>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>\u041f\u0440\u043e\u043b\u0438\u0441\u0442\u044b\u0432\u0430\u0435\u043c \u0441\u043f\u0438\u0441\u043e\u043a \u0437\u0430\u043a\u0430\u0437\u043e\u0432 \u0434\u043e \u043f\u0435\u0440\u0432\u043e\u0439 \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0438: <\/p>\n<pre><code class=\"dart\">final feedList = find.byValueKey(FeedIds.newFeedList); final feedItem = find.byValueKey(feedProjectCard + \"1\");  await driver.scrollUntilVisible(feedList, feedItem, dyScroll: -300);<\/code><\/pre>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>\u041e\u0442\u0432\u0435\u0447\u0430\u0435\u043c \u0432 \u0447\u0430\u0442\u0435:<\/p>\n<pre><code class=\"dart\">final fieldMessage = find.byValueKey(MessageIds.fieldMessage); final sendMessage = find.byValueKey(MessageIds.buttonSendMessage);  await driver.tap(fieldMessage); await driver.enterText(\"\u0417\u0434\u0440\u0430\u0432\u0441\u0442\u0432\u0443\u0439\u0442\u0435\"); await driver.waitFor(sendMessage).then((_) => driver.tap(sendMessage)); await driver.waitFor(find.text(\"\u0417\u0434\u0440\u0430\u0432\u0441\u0442\u0432\u0443\u0439\u0442\u0435\"));<\/code><\/pre>\n<figure class=\"\"><figcaption><\/figcaption><\/figure>\n<p>\u041d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0442\u0435\u0441\u0442\u043e\u0432 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 \u0438\u043c\u0435\u0435\u0442 \u043c\u043d\u043e\u0433\u043e \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432. \u042d\u0442\u043e \u043e\u0434\u0438\u043d \u0438\u0437 \u0441\u0430\u043c\u044b\u0445 \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0445 \u0442\u0438\u043f\u043e\u0432 \u0442\u0435\u0441\u0442\u043e\u0432 \u0432 \u043f\u0438\u0440\u0430\u043c\u0438\u0434\u0435 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043e\u043d\u0438 \u043d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u0431\u043b\u0438\u0437\u043a\u0438 \u043a \u043e\u043f\u044b\u0442\u0443 \u043a\u043e\u043d\u0435\u0447\u043d\u043e\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0438 \u0434\u0430\u0434\u0443\u0442 \u0432\u0430\u043c \u0443\u0432\u0435\u0440\u0435\u043d\u043d\u043e\u0441\u0442\u044c \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u0432\u0430\u0448\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0434\u043e\u043b\u0436\u043d\u044b\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c.\u00a0<\/p>\n<p>\u0412 \u0437\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0438 \u0434\u0430\u043d\u043d\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u0445\u043e\u0447\u0443 \u043f\u043e\u0434\u0435\u043b\u0438\u0442\u044c\u0441\u044f \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430\u043c\u0438, \u0441 \u043a\u043e\u0442\u043e\u0440\u044b\u043c\u0438 \u043c\u044b \u0441\u0442\u043e\u043b\u043a\u043d\u0443\u043b\u0438\u0441\u044c \u043f\u0440\u0438 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0441 Flutter Driver:\u00a0<\/p>\n<ol>\n<li>\n<p>\u043c\u0435\u0434\u043b\u0435\u043d\u043d\u043e\u0435 \u043f\u0440\u043e\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u0435 \u0442\u0435\u0441\u0442\u043e\u0432 \u2014 \u0434\u043b\u044f \u0443\u0441\u043a\u043e\u0440\u0435\u043d\u0438\u044f \u043c\u044b \u0443\u0431\u0440\u0430\u043b\u0438 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044e \u043d\u0430 \u043a\u0430\u0436\u0434\u043e\u043c \u0442\u0435\u0441\u0442\u0435;<\/p>\n<\/li>\n<li>\n<p>\u043f\u043b\u043e\u0445\u043e \u0447\u0438\u0442\u0430\u0435\u043c\u0430\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043f\u0440\u0438 \u0443\u0432\u0435\u043b\u0438\u0447\u0435\u043d\u0438\u0438 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u0442\u0435\u0441\u0442\u043e\u0432 \u2014 \u0434\u043b\u044f \u0438\u0441\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u044d\u0442\u043e\u0439 \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u0438 \u043c\u044b \u0440\u0430\u0437\u0434\u0435\u043b\u0438\u043b\u0438 \u0438\u0445 \u043f\u043e \u0433\u0440\u0443\u043f\u043f\u0430\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u0430;\u00a0<\/p>\n<\/li>\n<li>\n<p>\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044c \u0442\u0435\u0441\u0442\u043e\u0432 \u043e\u0442 \u0440\u0430\u0431\u043e\u0442\u044b back-end \u2014- \u0440\u0435\u0448\u0430\u0435\u043c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u043c\u043e\u043a\u043e\u0432 \u0432 \u0442\u0435\u0441\u0442\u0430\u0445. <\/p>\n<\/li>\n<\/ol>\n<h3>\u0420\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f Flutter Driver \u0441 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c<\/h3>\n<p>Flutter Driver \u043e\u0431\u043b\u0430\u0434\u0430\u0435\u0442 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c\u044e \u0434\u043b\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c \u043d\u0430 \u0443\u0440\u043e\u0432\u043d\u0435 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430, \u0430 \u0438\u043c\u0435\u043d\u043d\u043e \u0442\u0430\u043f\u044b, \u0432\u0432\u043e\u0434 \u0442\u0435\u043a\u0441\u0442\u0430, \u043f\u0440\u043e\u043a\u0440\u0443\u0442\u043a\u0430, \u043f\u043e\u0438\u0441\u043a<\/p>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-388274","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/388274","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=388274"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/388274\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=388274"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=388274"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=388274"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}