{"id":473527,"date":"2025-09-02T16:48:19","date_gmt":"2025-09-02T16:48:19","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=473527"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=473527","title":{"rendered":"<span>\u0410\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0435 \u0442\u0435\u0441\u0442\u044b \u0434\u043b\u044f UI \u0438 API \u043d\u0430 Python: \u043f\u0440\u0438\u043c\u0435\u0440\u044b, \u043f\u043e\u0434\u0432\u043e\u0434\u043d\u044b\u0435 \u043a\u0430\u043c\u043d\u0438 \u0438 \u0442\u0440\u0435\u0437\u0432\u044b\u0439 \u0432\u044b\u0432\u043e\u0434<\/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<h2>\u0412\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u0435<\/h2>\n<p>\u0418\u043d\u043e\u0433\u0434\u0430 \u043a\u0430\u0436\u0435\u0442\u0441\u044f, \u0447\u0442\u043e \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 <a href=\"https:\/\/docs.python.org\/3\/library\/asyncio-task.html\" rel=\"noopener noreferrer nofollow\">async\/await<\/a> \u0432 \u0442\u0435\u0441\u0442\u044b \u2014 \u044d\u0442\u043e \u043f\u043e\u0447\u0442\u0438 \u00ab\u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u044b\u0439 \u0441\u043f\u043e\u0441\u043e\u0431\u00bb \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0438\u0445 \u0431\u044b\u0441\u0442\u0440\u0435\u0435. \u041c\u044b \u0432\u0435\u0434\u044c \u0437\u043d\u0430\u0435\u043c, \u0447\u0442\u043e \u0442\u0435\u0441\u0442\u044b \u0447\u0430\u0441\u0442\u043e \u0442\u0440\u0430\u0442\u044f\u0442 \u0432\u0440\u0435\u043c\u044f \u043d\u0430 \u043e\u0436\u0438\u0434\u0430\u043d\u0438\u0435 \u043e\u0442\u0432\u0435\u0442\u043e\u0432 \u043e\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u0432 \u0438\u043b\u0438 UI\u2011\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439, \u0438 \u0432 \u0433\u043e\u043b\u043e\u0432\u0443 \u0441\u0440\u0430\u0437\u0443 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442 \u043c\u044b\u0441\u043b\u044c: \u00ab\u0410 \u0447\u0442\u043e, \u0435\u0441\u043b\u0438 \u043f\u043e\u043a\u0430 \u043e\u0434\u0438\u043d \u0442\u0435\u0441\u0442 \u0436\u0434\u0451\u0442 \u043e\u0442\u0432\u0435\u0442\u0430, \u0434\u0440\u0443\u0433\u043e\u0439 \u043d\u0430\u0447\u043d\u0451\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c\u0441\u044f?\u00bb \u041a\u0430\u0436\u0435\u0442\u0441\u044f \u043b\u043e\u0433\u0438\u0447\u043d\u044b\u043c, \u0447\u0442\u043e \u0442\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u0441\u044d\u043a\u043e\u043d\u043e\u043c\u0438\u0442\u044c \u043c\u0438\u043d\u0443\u0442\u044b, \u0430 \u0442\u043e \u0438 \u0434\u0435\u0441\u044f\u0442\u043a\u0438 \u043c\u0438\u043d\u0443\u0442 \u043f\u0440\u043e\u0433\u043e\u043d\u0430.<\/p>\n<p>\u041d\u043e \u043d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435 \u0432\u0441\u0451 \u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043d\u0435 \u0442\u0430\u043a \u043e\u0434\u043d\u043e\u0437\u043d\u0430\u0447\u043d\u043e. \u0410\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0441\u0442\u044c \u2014 \u044d\u0442\u043e \u043d\u0435 \u043c\u0430\u0433\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u043a\u043d\u043e\u043f\u043a\u0430, \u0434\u0435\u043b\u0430\u044e\u0449\u0430\u044f \u0442\u0435\u0441\u0442\u044b \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u044b\u043c\u0438 \u00ab\u043f\u043e \u0449\u0435\u043b\u0447\u043a\u0443\u00bb. <a href=\"https:\/\/docs.python.org\/3\/library\/asyncio-task.html\" rel=\"noopener noreferrer nofollow\">async\/await<\/a> \u0432 Python \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0432\u043d\u0443\u0442\u0440\u0438 \u043e\u0434\u043d\u043e\u0433\u043e \u043f\u043e\u0442\u043e\u043a\u0430 \u0438 \u043d\u0435 \u0441\u043e\u0437\u0434\u0430\u0451\u0442 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u0438\u0437\u043c\u0430. \u0414\u0430, \u043c\u043e\u0436\u043d\u043e \u0432\u044b\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b \u0442\u0430\u043a, \u0447\u0442\u043e \u043f\u043e\u043a\u0430 \u043e\u0434\u043d\u0430 \u0436\u0434\u0451\u0442 \u043e\u0442\u0432\u0435\u0442\u0430, \u0434\u0440\u0443\u0433\u0430\u044f \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c\u0441\u044f, \u0438 \u043d\u0430 \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u0438\u0445 \u0438\u0437\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u043f\u0440\u0438\u043c\u0435\u0440\u0430\u0445 \u044d\u0442\u043e \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0432\u043f\u0435\u0447\u0430\u0442\u043b\u044f\u044e\u0449\u0435. \u041d\u043e \u0432 \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445 \u0432\u0441\u0451 \u0441\u043b\u043e\u0436\u043d\u0435\u0435: \u043d\u0443\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u044b, \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b, \u043a\u043b\u0438\u0435\u043d\u0442\u044b, \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0442\u044c \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0435 \u0432\u0435\u0440\u0441\u0438\u0438 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a \u0438 \u043e\u0442\u043b\u0430\u0432\u043b\u0438\u0432\u0430\u0442\u044c \u043e\u0448\u0438\u0431\u043a\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0440\u0438 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u043c \u043f\u043e\u0434\u0445\u043e\u0434\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u043d\u0435 \u0432\u043e\u0437\u043d\u0438\u043a\u043b\u0438 \u0431\u044b.<\/p>\n<p>\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u0440\u0430\u0437\u0431\u0435\u0440\u0451\u043c, \u043a\u0430\u043a \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u044b\u0432\u0430\u043d\u0438\u0435 \u0430\u0432\u0442\u043e\u0442\u0435\u0441\u0442\u043e\u0432 \u043d\u0430 <a href=\"https:\/\/docs.python.org\/3\/library\/asyncio-task.html\" rel=\"noopener noreferrer nofollow\">async\/await<\/a>, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f <a href=\"https:\/\/www.python.org\/\" rel=\"noopener noreferrer nofollow\">Python<\/a> \u0438 <a href=\"https:\/\/docs.pytest.org\/en\/stable\/\" rel=\"noopener noreferrer nofollow\">Pytest<\/a>. \u0414\u043b\u044f UI \u0442\u0435\u0441\u0442\u043e\u0432 \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <a href=\"https:\/\/playwright.dev\/python\/\" rel=\"noopener noreferrer nofollow\">Playwright<\/a>, \u0434\u043b\u044f API \u2014 <a href=\"https:\/\/www.python-httpx.org\/\" rel=\"noopener noreferrer nofollow\">HTTPX<\/a>. \u041c\u044b \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c, \u043a\u0430\u043a\u0438\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043d\u0443\u0436\u043d\u043e \u0432\u043d\u043e\u0441\u0438\u0442\u044c \u0432 \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0439 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a, \u0447\u0442\u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0441 PageObject \u0438 API\u2011\u043a\u043b\u0438\u0435\u043d\u0442\u0430\u043c\u0438, \u043a\u0430\u043a \u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0442\u0435\u0441\u0442\u043e\u0432 \u0438 \u0444\u0438\u043a\u0441\u0442\u0443\u0440. \u0418 \u0447\u0442\u043e \u0432\u0430\u0436\u043d\u0435\u0435 \u2014 \u043c\u044b \u043e\u0431\u0441\u0443\u0434\u0438\u043c, \u043a\u043e\u0433\u0434\u0430 \u0442\u0430\u043a\u043e\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u0438\u043c\u0435\u0435\u0442 \u0441\u043c\u044b\u0441\u043b, \u0430 \u043a\u043e\u0433\u0434\u0430 \u043e\u043d \u0441\u043a\u043e\u0440\u0435\u0435 \u0441\u043e\u0437\u0434\u0430\u0451\u0442 \u043b\u0438\u0448\u043d\u0438\u0435 \u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u0438, \u0447\u0435\u043c \u0434\u0430\u0451\u0442 \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0439 \u0432\u044b\u0438\u0433\u0440\u044b\u0448.<\/p>\n<blockquote>\n<p>\u041e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u043e\u0442\u043c\u0435\u0447\u0443: \u0446\u0435\u043b\u044c \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0438 \u2014 \u043d\u0435 \u043f\u0440\u0438\u0437\u044b\u0432\u0430\u0442\u044c \u043a \u043c\u0430\u0441\u0441\u043e\u0432\u043e\u043c\u0443 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0443 \u043d\u0430 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0435 \u0442\u0435\u0441\u0442\u044b, \u0430 \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c, <strong>\u043a\u0430\u043a \u044d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c<\/strong> \u0438 <strong>\u0437\u0430\u0447\u0435\u043c \u0438\u043d\u043e\u0433\u0434\u0430 \u044d\u0442\u043e \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043d\u0443\u0436\u043d\u043e<\/strong>. \u041c\u044b \u043d\u0435 \u0431\u0443\u0434\u0435\u043c \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e \u043f\u043e\u0432\u0442\u043e\u0440\u044f\u0442\u044c \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u0433\u043e \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430 \u0441 \u043d\u0443\u043b\u044f (\u044d\u0442\u043e\u0442 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b \u0443\u0436\u0435 \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u043d \u0432 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u0445 \u0441\u0442\u0430\u0442\u044c\u044f\u0445), \u0430 \u0441\u043e\u0441\u0440\u0435\u0434\u043e\u0442\u043e\u0447\u0438\u043c\u0441\u044f \u043d\u0430 \u043e\u0442\u043b\u0438\u0447\u0438\u044f\u0445 \u043c\u0435\u0436\u0434\u0443 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0439 \u0438 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0435\u0439. <\/p>\n<\/blockquote>\n<p>\u0421\u0441\u044b\u043b\u043a\u0438 \u043d\u0430 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u044b \u0441 \u0431\u0430\u0437\u043e\u0432\u043e\u0439 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u043e\u0439 \u044f \u043e\u0441\u0442\u0430\u0432\u043b\u044e \u043d\u0438\u0436\u0435, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u0438 \u0436\u0435\u043b\u0430\u043d\u0438\u0438 \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u043f\u043e\u0433\u0440\u0443\u0437\u0438\u0442\u044c\u0441\u044f \u0432 \u0434\u0435\u0442\u0430\u043b\u0438:<\/p>\n<ul>\n<li>\n<p><a href=\"https:\/\/habr.com\/ru\/articles\/896936\/\" rel=\"noopener noreferrer nofollow\">UI \u0430\u0432\u0442\u043e\u0442\u0435\u0441\u0442\u044b \u043d\u0430 Python \u0441 \u0437\u0430\u043f\u0443\u0441\u043a\u043e\u043c \u043d\u0430 CI\/CD \u0438 Allure \u043e\u0442\u0447\u0435\u0442\u043e\u043c. PageObject, PageComponent, PageFactory<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/habr.com\/ru\/articles\/895452\/\" rel=\"noopener noreferrer nofollow\">API \u0430\u0432\u0442\u043e\u0442\u0435\u0441\u0442\u044b \u043d\u0430 Python \u0441 \u0437\u0430\u043f\u0443\u0441\u043a\u043e\u043c \u043d\u0430 CI\/CD \u0438 Allure \u043e\u0442\u0447\u0435\u0442\u043e\u043c<\/a><\/p>\n<\/li>\n<\/ul>\n<h2>\u0422\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0438<\/h2>\n<p>\u0414\u043b\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0445 \u0442\u0435\u0441\u0442\u043e\u0432 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u0438\u0432\u044b\u0447\u043d\u044b\u0435 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438 \u0432 \u043e\u0431\u044b\u0447\u043d\u044b\u0445 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0445 \u0442\u0435\u0441\u0442\u0430\u0445 \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u044e\u0442\u0441\u044f \u0435\u0436\u0435\u0434\u043d\u0435\u0432\u043d\u043e. \u041e\u0441\u043d\u043e\u0432\u043e\u0439, \u043a\u0430\u043a \u0438 \u043f\u0440\u0435\u0436\u0434\u0435, \u043e\u0441\u0442\u0430\u0451\u0442\u0441\u044f <a href=\"https:\/\/docs.pytest.org\/en\/stable\/\" rel=\"noopener noreferrer nofollow\">pytest<\/a> \u2014 \u043e\u043d \u0443\u0434\u043e\u0431\u0435\u043d, \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u044b, \u0440\u0430\u0441\u0448\u0438\u0440\u044f\u0435\u043c\u043e\u0441\u0442\u044c \u0438 \u0433\u0438\u0431\u043a\u0443\u044e \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446\u0438\u044e \u0442\u0435\u0441\u0442\u043e\u0432. \u0427\u0442\u043e\u0431\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0443 <a href=\"https:\/\/docs.python.org\/3\/library\/asyncio-task.html\" rel=\"noopener noreferrer nofollow\">async\/await<\/a>, \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u043f\u043b\u0430\u0433\u0438\u043d <a href=\"https:\/\/github.com\/pytest-dev\/pytest-asyncio\" rel=\"noopener noreferrer nofollow\">pytest-asyncio<\/a>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0443\u043c\u0435\u0435\u0442 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043a\u0430\u043a \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b \u0438 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u043c <a href=\"https:\/\/docs.python.org\/3\/library\/asyncio-eventloop.html\" rel=\"noopener noreferrer nofollow\">event loop<\/a> \u0432\u043d\u0443\u0442\u0440\u0438 Pytest.<\/p>\n<p>\u0414\u043b\u044f UI \u0442\u0435\u0441\u0442\u043e\u0432 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c Playwright. \u042d\u0442\u043e\u0442 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u0438\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043b\u0441\u044f \u0441 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u043e\u0439 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0433\u043e API, \u0447\u0442\u043e \u0443\u043f\u0440\u043e\u0449\u0430\u0435\u0442 \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u044e: \u0432\u043c\u0435\u0441\u0442\u043e \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0445 \u0432\u044b\u0437\u043e\u0432\u043e\u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430 \u0438 \u0441\u0442\u0440\u0430\u043d\u0438\u0446 (<a href=\"https:\/\/github.com\/microsoft\/playwright-python\/tree\/main\/playwright\/sync_api\" rel=\"noopener noreferrer nofollow\">playwright.sync_api<\/a>) \u043c\u044b \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u043c \u043d\u0430 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u0443\u044e \u0432\u0435\u0440\u0441\u0438\u044e (<a href=\"https:\/\/github.com\/microsoft\/playwright-python\/tree\/main\/playwright\/async_api\" rel=\"noopener noreferrer nofollow\">playwright.async_api<\/a>). \u0424\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438, \u044d\u0442\u043e \u043d\u0435 \u00ab\u0445\u0430\u043a\u0438\u00bb \u0438 \u043d\u0435 \u00ab\u043e\u0431\u0445\u043e\u0434\u043d\u044b\u0435 \u043f\u0443\u0442\u0438\u00bb, \u0430 \u0448\u0442\u0430\u0442\u043d\u044b\u0439 \u0441\u043f\u043e\u0441\u043e\u0431 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 Playwright.<\/p>\n<p>\u0414\u043b\u044f API \u0430\u0432\u0442\u043e\u0442\u0435\u0441\u0442\u043e\u0432 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 HTTPX, \u0443 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0443\u0436\u0435 \u0435\u0441\u0442\u044c \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u0430\u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0447\u0435\u0440\u0435\u0437 <a href=\"https:\/\/www.python-httpx.org\/async\/\" rel=\"noopener noreferrer nofollow\">AsyncClient<\/a>. \u042d\u0442\u043e \u0443\u043f\u0440\u043e\u0449\u0430\u0435\u0442 \u0437\u0430\u0434\u0430\u0447\u0443: \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u044b\u0432\u0430\u043d\u0438\u0435 \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u0441\u0432\u043e\u0434\u0438\u0442\u0441\u044f \u043a \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044e <code>async<\/code> \u0438 <code>await<\/code> \u0432 \u043c\u0435\u0442\u043e\u0434\u044b, \u0431\u0435\u0437 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0433\u043e\u0440\u043e\u0434\u0438\u0442\u044c \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u043e\u0431\u0451\u0440\u0442\u043a\u0438 \u0438\u043b\u0438 \u043f\u043e\u0434\u043c\u0435\u043d\u044f\u0442\u044c \u043d\u0438\u0437\u043a\u043e\u0443\u0440\u043e\u0432\u043d\u0435\u0432\u044b\u0439 \u0442\u0440\u0430\u043d\u0441\u043f\u043e\u0440\u0442.<\/p>\n<p>\u041e\u0441\u0442\u0430\u043b\u044c\u043d\u0430\u044f \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u0442\u0435\u0441\u0442\u043e\u0432 (\u0444\u0438\u043a\u0441\u0442\u0443\u0440\u044b, PageObject, \u043b\u043e\u0433\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435, \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u044f \u0441\u0445\u0435\u043c) \u043e\u0441\u0442\u0430\u0451\u0442\u0441\u044f \u043f\u0440\u0435\u0436\u043d\u0435\u0439. \u0415\u0441\u043b\u0438 \u0432\u044b \u0443\u0436\u0435 \u0437\u043d\u0430\u043a\u043e\u043c\u044b \u0441 \u043c\u043e\u0438\u043c\u0438 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u043c\u0438 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u0430\u043c\u0438 \u043f\u043e \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u044e \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430, \u0442\u043e \u0443\u0432\u0438\u0434\u0438\u0442\u0435, \u0447\u0442\u043e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043e\u0441\u0442\u0430\u0451\u0442\u0441\u044f \u043f\u0440\u0438\u0432\u044b\u0447\u043d\u043e\u0439 \u2014 \u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u043b\u0438\u0448\u044c \u0441\u043f\u043e\u0441\u043e\u0431 \u0432\u044b\u0437\u043e\u0432\u0430 \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u0438 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u043c\u0438 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430\u043c\u0438.<\/p>\n<p>\u041f\u043e\u0434\u0440\u043e\u0431\u043d\u043e \u0441\u0430\u043c \u043f\u043e\u0434\u0445\u043e\u0434 \u043a \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u044e UI \u0438 API \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u0432 \u043c\u044b \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u043b\u0438 \u0440\u0430\u043d\u0435\u0435:<\/p>\n<ul>\n<li>\n<p><a href=\"https:\/\/habr.com\/ru\/articles\/896936\/\" rel=\"noopener noreferrer nofollow\">UI \u0430\u0432\u0442\u043e\u0442\u0435\u0441\u0442\u044b \u043d\u0430 Python \u0441 \u0437\u0430\u043f\u0443\u0441\u043a\u043e\u043c \u043d\u0430 CI\/CD \u0438 Allure \u043e\u0442\u0447\u0435\u0442\u043e\u043c. PageObject, PageComponent, PageFactory<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/habr.com\/ru\/articles\/895452\/\" rel=\"noopener noreferrer nofollow\">API \u0430\u0432\u0442\u043e\u0442\u0435\u0441\u0442\u044b \u043d\u0430 Python \u0441 \u0437\u0430\u043f\u0443\u0441\u043a\u043e\u043c \u043d\u0430 CI\/CD \u0438 Allure \u043e\u0442\u0447\u0435\u0442\u043e\u043c<\/a><\/p>\n<\/li>\n<\/ul>\n<h2>UI \u0430\u0432\u0442\u043e\u0442\u0435\u0441\u0442\u044b<\/h2>\n<p>\u041d\u0430\u0447\u043d\u0451\u043c \u0441 UI \u0442\u0435\u0441\u0442\u043e\u0432 \u0438 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c, \u043a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439 \u043a\u043e\u0434 \u0432 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439.<\/p>\n<p>Playwright \u0432 \u044d\u0442\u043e\u043c \u043f\u043b\u0430\u043d\u0435 \u0441\u0438\u043b\u044c\u043d\u043e \u0443\u043f\u0440\u043e\u0449\u0430\u0435\u0442 \u0437\u0430\u0434\u0430\u0447\u0443: \u0438\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e \u043e\u043d \u0441\u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d \u043a\u0430\u043a \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u0430\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430, \u0438 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044f (<a href=\"https:\/\/github.com\/microsoft\/playwright-python\/tree\/main\/playwright\/sync_api\" rel=\"noopener noreferrer nofollow\">playwright.sync_api<\/a>) \u2014 \u044d\u0442\u043e \u0441\u043a\u043e\u0440\u0435\u0435 \u043e\u0431\u0451\u0440\u0442\u043a\u0430 \u043d\u0430\u0434 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u043c \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u043c API. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u0435\u0440\u0435\u0445\u043e\u0434 \u043a <a href=\"https:\/\/docs.python.org\/3\/library\/asyncio-task.html\" rel=\"noopener noreferrer nofollow\">async\/await<\/a> \u043d\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0440\u0430\u0434\u0438\u043a\u0430\u043b\u044c\u043d\u043e\u0439 \u043f\u0435\u0440\u0435\u0434\u0435\u043b\u043a\u0438 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430: \u0432\u044b \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0435\u0441\u044c \u043d\u0430 \u0434\u0440\u0443\u0433\u043e\u0439 \u043c\u043e\u0434\u0443\u043b\u044c (<a href=\"https:\/\/github.com\/microsoft\/playwright-python\/tree\/main\/playwright\/async_api\" rel=\"noopener noreferrer nofollow\">playwright.async_api<\/a>) \u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442\u0435 \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u0441\u043b\u043e\u0432\u0430 <code>async<\/code> \u0438 <code>await<\/code> \u0432 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u043c\u0435\u0441\u0442\u0430\u0445.<\/p>\n<p>\u041d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435 \u044d\u0442\u043e \u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442, \u0447\u0442\u043e \u043e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0442\u0435\u0441\u0442\u043e\u0432 \u043e\u0441\u0442\u0430\u0451\u0442\u0441\u044f \u043f\u0440\u0435\u0436\u043d\u0435\u0439: \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u044b, PageObject \u0438 PageComponent \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u044e\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u043f\u043e \u0442\u0435\u043c \u0436\u0435 \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u0430\u043c, \u043f\u0440\u043e\u0441\u0442\u043e \u0441\u0442\u0430\u043d\u043e\u0432\u044f\u0442\u0441\u044f \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u043c\u0438. \u042d\u0442\u043e\u0442 \u043c\u043e\u043c\u0435\u043d\u0442 \u0432\u0430\u0436\u0435\u043d, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u043c\u043d\u043e\u0433\u0438\u0435 \u043e\u0436\u0438\u0434\u0430\u044e\u0442, \u0447\u0442\u043e \u043f\u0440\u0438\u0434\u0451\u0442\u0441\u044f \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u00ab\u0432\u0441\u0451 \u0438 \u0441\u0440\u0430\u0437\u0443\u00bb. \u041d\u0430 \u0441\u0430\u043c\u043e\u043c \u0434\u0435\u043b\u0435 \u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u043f\u043e\u0441\u043e\u0431 \u0432\u044b\u0437\u043e\u0432\u0430 \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430 \u0438 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441\u043e \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430\u043c\u0438.<\/p>\n<p>\u041f\u043e\u043b\u043d\u044b\u0435 \u043f\u0440\u0438\u043c\u0435\u0440\u044b \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 UI \u0442\u0435\u0441\u0442\u043e\u0432 \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043d\u0430\u0439\u0442\u0438 \u0432 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f\u0445:<\/p>\n<ul>\n<li>\n<p>\u0421\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f: <a href=\"https:\/\/github.com\/Nikita-Filonov\/python-ui-tests\" rel=\"noopener noreferrer nofollow\">python-ui-tests<\/a><\/p>\n<\/li>\n<li>\n<p>\u0410\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f: <a href=\"https:\/\/github.com\/Nikita-Filonov\/python-ui-tests-async\" rel=\"noopener noreferrer nofollow\">python-ui-tests-async<\/a><\/p>\n<\/li>\n<\/ul>\n<h3>\u0424\u0438\u043a\u0441\u0442\u0443\u0440\u044b<\/h3>\n<p>\u041f\u0435\u0440\u0432\u043e\u0435, \u0447\u0442\u043e \u043d\u0443\u0436\u043d\u043e \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u043f\u0440\u0438 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0435 \u043d\u0430 <a href=\"https:\/\/docs.python.org\/3\/library\/asyncio-task.html\" rel=\"noopener noreferrer nofollow\">async\/await<\/a>, \u2014 \u044d\u0442\u043e \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u044b. \u0412 \u043e\u0431\u044b\u0447\u043d\u043e\u043c Pytest \u043e\u043d\u0438 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0435 \u0438 \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442 \u0432 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u043c \u043f\u043e\u0442\u043e\u043a\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f. \u0414\u043b\u044f \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0445 \u0442\u0435\u0441\u0442\u043e\u0432 \u043d\u0443\u0436\u0435\u043d \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0441\u043e\u0431\u044b\u0442\u0438\u0439\u043d\u044b\u0439 \u0446\u0438\u043a\u043b, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043f\u043b\u0430\u0433\u0438\u043d <a href=\"https:\/\/github.com\/pytest-dev\/pytest-asyncio\" rel=\"noopener noreferrer nofollow\">pytest-asyncio<\/a>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0443 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0445 \u0444\u0438\u043a\u0441\u0442\u0443\u0440 \u0438 \u0442\u0435\u0441\u0442\u043e\u0432.<\/p>\n<p><strong>\u0421\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f:<\/strong> <a href=\"https:\/\/github.com\/Nikita-Filonov\/python-ui-tests\/blob\/main\/fixtures\/pages.py\" rel=\"noopener noreferrer nofollow\">\/fixtures\/pages.py<\/a><\/p>\n<pre><code class=\"python\">import uuid  import allure import pytest from playwright.sync_api import Playwright, Page, expect  from config import Settings from pages.dashboard_page import DashboardPage from pages.registration_page import RegistrationPage   @pytest.fixture def chromium_page(playwright: Playwright, settings: Settings) -&gt; Page:     expect.set_options(timeout=settings.expect_timeout)      browser = playwright.chromium.launch(headless=settings.headless)     context = browser.new_context(         base_url=f\"{settings.app_url}\/\",         record_video_dir=settings.videos_dir     )     context.tracing.start(screenshots=True, snapshots=True, sources=True)      page = context.new_page()     yield page      tracing_file = settings.tracing_dir.joinpath(f'{uuid.uuid4()}.zip')     context.tracing.stop(path=tracing_file)     browser.close()      allure.attach.file(tracing_file, name='trace', extension='zip')     allure.attach.file(page.video.path(), name='video', attachment_type=allure.attachment_type.WEBM)   @pytest.fixture def dashboard_page(chromium_page: Page) -&gt; DashboardPage:     return DashboardPage(page=chromium_page)   @pytest.fixture def registration_page(chromium_page: Page) -&gt; RegistrationPage:     return RegistrationPage(page=chromium_page)<\/code><\/pre>\n<p><strong>\u0410\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f:<\/strong> <a href=\"https:\/\/github.com\/Nikita-Filonov\/python-ui-tests-async\/blob\/main\/fixtures\/pages.py\" rel=\"noopener noreferrer nofollow\">\/fixtures\/pages.py<\/a><\/p>\n<pre><code class=\"python\">import uuid  import allure import pytest_asyncio from playwright.async_api import Page, expect, async_playwright  from config import Settings from pages.dashboard_page import DashboardPage from pages.registration_page import RegistrationPage   @pytest_asyncio.fixture async def chromium_page(settings: Settings) -&gt; Page:     async with async_playwright() as playwright:         expect.set_options(timeout=settings.expect_timeout)          browser = await playwright.chromium.launch(headless=settings.headless)         context = await browser.new_context(             base_url=f\"{settings.app_url}\/\",             record_video_dir=settings.videos_dir         )         await context.tracing.start(screenshots=True, snapshots=True, sources=True)          page = await context.new_page()         yield page          video_file = await page.video.path()         tracing_file = settings.tracing_dir.joinpath(f'{uuid.uuid4()}.zip')         await context.tracing.stop(path=tracing_file)         await browser.close()          allure.attach.file(tracing_file, name='trace', extension='zip')         allure.attach.file(video_file, name='video', attachment_type=allure.attachment_type.WEBM)   @pytest_asyncio.fixture async def dashboard_page(chromium_page: Page) -&gt; DashboardPage:     return DashboardPage(page=chromium_page)   @pytest_asyncio.fixture async def registration_page(chromium_page: Page) -&gt; RegistrationPage:     return RegistrationPage(page=chromium_page) <\/code><\/pre>\n<p>\u0412 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0438 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 <code>pytest.fixture<\/code> \u0438 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439 Playwright API (<a href=\"https:\/\/github.com\/microsoft\/playwright-python\/tree\/main\/playwright\/sync_api\" rel=\"noopener noreferrer nofollow\">playwright.sync_api<\/a>). \u0417\u0430\u043f\u0443\u0441\u043a \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430, \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430 \u0438 \u043e\u0442\u043a\u0440\u044b\u0442\u0438\u0435 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u043b\u0438\u0441\u044c \u043f\u043e\u0448\u0430\u0433\u043e\u0432\u043e \u0438 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u043b\u0438 \u043f\u043e\u0442\u043e\u043a \u0434\u043e \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0448\u0430\u0433\u0430.<\/p>\n<p>\u0412 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u0432\u0441\u0451 \u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<ul>\n<li>\n<p>\u0412\u043c\u0435\u0441\u0442\u043e <code>pytest.fixture<\/code> \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f <code>pytest_asyncio.fixture<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043e\u0431\u044a\u044f\u0432\u0438\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u043a\u0430\u043a <code>async def<\/code>. \u042d\u0442\u043e \u0437\u043d\u0430\u0447\u0438\u0442, \u0447\u0442\u043e \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u0430 \u0441\u0430\u043c\u0430 \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u043e\u0439 \u0438 \u043c\u043e\u0436\u0435\u0442 \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0435 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u0431\u0435\u0437 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0438 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0433\u043e \u043f\u043e\u0442\u043e\u043a\u0430.<\/p>\n<\/li>\n<li>\n<p>\u0412\u043c\u0435\u0441\u0442\u043e <a href=\"https:\/\/github.com\/microsoft\/playwright-python\/tree\/main\/playwright\/sync_api\" rel=\"noopener noreferrer nofollow\">\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0433\u043e<\/a> API Playwright \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043c\u043e\u0434\u0443\u043b\u044c <a href=\"https:\/\/github.com\/microsoft\/playwright-python\/tree\/main\/playwright\/async_api\" rel=\"noopener noreferrer nofollow\">playwright.async_api<\/a>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0435 \u0432\u0435\u0440\u0441\u0438\u0438 \u0432\u0441\u0435\u0445 \u043c\u0435\u0442\u043e\u0434\u043e\u0432. \u0422\u0435\u043f\u0435\u0440\u044c \u0437\u0430\u043f\u0443\u0441\u043a \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430 (<code>launch<\/code>), \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430 (<code>new_context<\/code>) \u0438 \u043e\u0442\u043a\u0440\u044b\u0442\u0438\u0435 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b (<code>new_page<\/code>) \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u044e\u0442\u0441\u044f \u0441 \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u043c \u0441\u043b\u043e\u0432\u043e\u043c <code>await<\/code>.<\/p>\n<\/li>\n<li>\n<p>\u0412\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u0430\u044f \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u0430 <code>playwright<\/code> \u0438\u0437 \u043f\u043b\u0430\u0433\u0438\u043d\u0430 <a href=\"https:\/\/playwright.dev\/python\/docs\/test-runners\" rel=\"noopener noreferrer nofollow\">pytest-playwright<\/a> \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0435 \u043c\u043e\u0436\u0435\u0442, \u0442\u0430\u043a \u043a\u0430\u043a \u043e\u043d\u0430 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u0442 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439 API (<code>sync_playwright<\/code>). \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043c\u044b \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u043e \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u043c \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u0447\u0435\u0440\u0435\u0437 <code>async with async_playwright() as playwright:<\/code>. \u042d\u0442\u043e \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u0443\u0435\u0442 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e\u0435 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0440\u0435\u0441\u0443\u0440\u0441\u0430\u043c\u0438 \u0438 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u0435 \u0432\u0441\u0435\u0445 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0439 \u043f\u0440\u0438 \u0432\u044b\u0445\u043e\u0434\u0435 \u0438\u0437 \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u044b.<\/p>\n<\/li>\n<li>\n<p>\u0417\u0430\u043a\u0440\u044b\u0442\u0438\u0435 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430 (<code>browser.close()<\/code>), \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0442\u0440\u0435\u0439\u0441\u0438\u043d\u0433\u0430 (<code>context.tracing.stop()<\/code>) \u0438 \u0440\u0430\u0431\u043e\u0442\u0430 \u0441 \u0432\u0438\u0434\u0435\u043e (<code>page.video.path()<\/code>) \u0442\u0435\u043f\u0435\u0440\u044c \u0442\u043e\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u044e\u0442\u0441\u044f \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c <code>await<\/code>, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u044d\u0442\u0438 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u0432 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u043c API \u0442\u043e\u0436\u0435 \u043d\u0435 \u0431\u043b\u043e\u043a\u0438\u0440\u0443\u044e\u0442 \u043f\u043e\u0442\u043e\u043a.<\/p>\n<\/li>\n<li>\n<p>\u0424\u0438\u043a\u0441\u0442\u0443\u0440\u044b, \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044e\u0449\u0438\u0435 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b (<code>dashboard_page<\/code>, <code>registration_page<\/code>), \u043e\u0431\u044a\u044f\u0432\u043b\u0435\u043d\u044b \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u043c\u0438 \u043d\u0435 \u00ab\u0440\u0430\u0434\u0438 \u0433\u0430\u043b\u043e\u0447\u043a\u0438\u00bb, \u0430 \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u043e\u043d\u0438 \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e \u0437\u0430\u0432\u0438\u0441\u044f\u0442 \u043e\u0442 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0439 \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u044b <code>chromium_page<\/code>. Pytest \u0442\u0440\u0435\u0431\u0443\u0435\u0442, \u0447\u0442\u043e\u0431\u044b \u0432\u0441\u044f \u0446\u0435\u043f\u043e\u0447\u043a\u0430 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439 \u043e\u0441\u0442\u0430\u0432\u0430\u043b\u0430\u0441\u044c \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0439, \u0438\u043d\u0430\u0447\u0435 \u043e\u0436\u0438\u0434\u0430\u043d\u0438\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u0438\u0437 \u043a\u043e\u0440\u0443\u0442\u0438\u043d \u043f\u0440\u043e\u0441\u0442\u043e \u043d\u0435 \u0441\u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442.<\/p>\n<\/li>\n<\/ul>\n<p>\u0421 \u0442\u043e\u0447\u043a\u0438 \u0437\u0440\u0435\u043d\u0438\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0432 \u0442\u0435\u0441\u0442\u0430\u0445 \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u2014 \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u044b \u043f\u043e-\u043f\u0440\u0435\u0436\u043d\u0435\u043c\u0443 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b \u043f\u043e \u0438\u043c\u0435\u043d\u0438 \u0438 \u043f\u043e\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0432 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0439. \u041d\u043e \u00ab\u043f\u043e\u0434 \u043a\u0430\u043f\u043e\u0442\u043e\u043c\u00bb \u043e\u043d\u0438 \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442 \u0432 \u0441\u043e\u0431\u044b\u0442\u0438\u0439\u043d\u043e\u043c \u0446\u0438\u043a\u043b\u0435, \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0435\u043c\u043e\u043c <a href=\"https:\/\/github.com\/pytest-dev\/pytest-asyncio\" rel=\"noopener noreferrer nofollow\">pytest-asyncio<\/a>, \u0438 \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0435 \u0431\u043b\u043e\u043a\u0438\u0440\u0443\u044e\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435, \u0447\u0442\u043e \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e \u0437\u0430\u043c\u0435\u0442\u043d\u043e \u043f\u0440\u0438 \u0431\u043e\u043b\u044c\u0448\u043e\u043c \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0435 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0445 \u0432\u044b\u0437\u043e\u0432\u043e\u0432.<\/p>\n<h3>PageObject, PageComponent, PageFactory<\/h3>\n<p>\u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043c\u044b \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u043c \u043d\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 <a href=\"https:\/\/github.com\/microsoft\/playwright-python\/tree\/main\/playwright\/async_api\" rel=\"noopener noreferrer nofollow\">playwright.async_api<\/a>, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0430\u0434\u0430\u043f\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u0441\u044e \u0440\u0430\u0431\u043e\u0442\u0443 \u0441\u043e \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430\u043c\u0438: \u043d\u0430\u0447\u0438\u043d\u0430\u044f \u0441 \u0431\u0430\u0437\u043e\u0432\u044b\u0445 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 (PageFactory \u0438 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b), \u0434\u0430\u043b\u0435\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 (PageComponent), \u0438 \u0437\u0430\u0432\u0435\u0440\u0448\u0430\u044f \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u044b\u043c\u0438 \u043e\u0431\u044a\u0435\u043a\u0442\u0430\u043c\u0438 \u0441\u0442\u0440\u0430\u043d\u0438\u0446 (PageObject). \u0420\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u044d\u0442\u043e \u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0430\u0445, \u043d\u0430\u0447\u0438\u043d\u0430\u044f \u0441 \u0441\u0430\u043c\u043e\u0433\u043e \u043d\u0438\u0437\u043a\u043e\u0433\u043e \u0443\u0440\u043e\u0432\u043d\u044f \u2014 \u0431\u0430\u0437\u043e\u0432\u043e\u0433\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430.<\/p>\n<h4>PageFactory<\/h4>\n<p><strong>\u0421\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f:<\/strong> <a href=\"https:\/\/github.com\/Nikita-Filonov\/python-ui-tests\/blob\/main\/elements\/base_element.py\" rel=\"noopener noreferrer nofollow\">\/elements\/base_element.py<\/a><\/p>\n<pre><code class=\"python\">import allure from playwright.sync_api import Page, Locator, expect  from tools.logger import get_logger  logger = get_logger(\"BASE_ELEMENT\")   class BaseElement:     def __init__(self, page: Page, locator: str, name: str) -&gt; None:         self.page = page         self.name = name         self.locator = locator      @property     def type_of(self) -&gt; str:         return \"base element\"      def get_locator(self, nth: int = 0, **kwargs) -&gt; Locator:         locator = self.locator.format(**kwargs)         step = f'Getting locator with \"data-testid={locator}\" at index \"{nth}\"'          with allure.step(step):             logger.info(step)             return self.page.get_by_test_id(locator).nth(nth)      def click(self, nth: int = 0, **kwargs):         step = f'Clicking {self.type_of} \"{self.name}\"'          with allure.step(step):             locator = self.get_locator(nth, **kwargs)             logger.info(step)             locator.click()      def check_visible(self, nth: int = 0, **kwargs):         step = f'Checking that {self.type_of} \"{self.name}\" is visible'          with allure.step(step):             locator = self.get_locator(nth, **kwargs)             logger.info(step)             expect(locator).to_be_visible()      def check_have_text(self, text: str, nth: int = 0, **kwargs):         step = f'Checking that {self.type_of} \"{self.name}\" has text \"{text}\"'          with allure.step(step):             locator = self.get_locator(nth, **kwargs)             logger.info(step)             expect(locator).to_have_text(text) <\/code><\/pre>\n<p><strong>\u0410\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f<\/strong>: <a href=\"https:\/\/github.com\/Nikita-Filonov\/python-ui-tests-async\/blob\/main\/elements\/base_element.py\" rel=\"noopener noreferrer nofollow\">\/elements\/base_element.py<\/a><\/p>\n<pre><code class=\"python\">import allure from playwright.async_api import Page, Locator, expect  from tools.logger import get_logger  logger = get_logger(\"BASE_ELEMENT\")   class BaseElement:     def __init__(self, page: Page, locator: str, name: str) -&gt; None:         self.page = page         self.name = name         self.locator = locator      @property     def type_of(self) -&gt; str:         return \"base element\"      def get_locator(self, nth: int = 0, **kwargs) -&gt; Locator:         locator = self.locator.format(**kwargs)         step = f'Getting locator with \"data-testid={locator}\" at index \"{nth}\"'          with allure.step(step):             logger.info(step)             return self.page.get_by_test_id(locator).nth(nth)      async def click(self, nth: int = 0, **kwargs):         step = f'Clicking {self.type_of} \"{self.name}\"'          with allure.step(step):             locator = self.get_locator(nth, **kwargs)             logger.info(step)             await locator.click()      async def check_visible(self, nth: int = 0, **kwargs):         step = f'Checking that {self.type_of} \"{self.name}\" is visible'          with allure.step(step):             locator = self.get_locator(nth, **kwargs)             logger.info(step)             await expect(locator).to_be_visible()      async def check_have_text(self, text: str, nth: int = 0, **kwargs):         step = f'Checking that {self.type_of} \"{self.name}\" has text \"{text}\"'          with allure.step(step):             locator = self.get_locator(nth, **kwargs)             logger.info(step)             await expect(locator).to_have_text(text) <\/code><\/pre>\n<p>\u0412 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u0439 (\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0439) \u0432\u0435\u0440\u0441\u0438\u0438 \u043c\u0435\u0442\u043e\u0434\u044b, \u0442\u0430\u043a\u0438\u0435 \u043a\u0430\u043a <code>click<\/code>, <code>check_visible<\/code>, <code>check_have_text<\/code>, \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u043b\u0438\u0441\u044c \u0431\u043b\u043e\u043a\u0438\u0440\u0443\u044e\u0449\u0435. \u041f\u043e\u0441\u043b\u0435 \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438 \u043e\u043d\u0438 \u0441\u0442\u0430\u043b\u0438 <code>async def<\/code> \u0438 \u0432\u043d\u0443\u0442\u0440\u0438 \u0432\u044b\u0437\u044b\u0432\u0430\u044e\u0442 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0435 \u043c\u0435\u0442\u043e\u0434\u044b Playwright (<code>await locator.click()<\/code>, <code>await expect(locator).to_be_visible()<\/code>). \u042d\u0442\u043e \u0437\u043d\u0430\u0447\u0438\u0442, \u0447\u0442\u043e \u043a\u0430\u0436\u0434\u044b\u0439 \u0448\u0430\u0433 \u0442\u0435\u043f\u0435\u0440\u044c \u043e\u0442\u0434\u0430\u0451\u0442 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043e\u0431\u0440\u0430\u0442\u043d\u043e \u0432 \u0441\u043e\u0431\u044b\u0442\u0438\u0439\u043d\u044b\u0439 \u0446\u0438\u043a\u043b, \u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u043c\u043e\u0436\u0435\u0442 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430\u0442\u044c\u0441\u044f \u043d\u0430 \u0434\u0440\u0443\u0433\u0438\u0435 \u0437\u0430\u0434\u0430\u0447\u0438, \u043f\u043e\u043a\u0430 Playwright \u0436\u0434\u0451\u0442 \u043e\u0442\u0432\u0435\u0442\u0430 \u043e\u0442 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430. \u0418\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u043e\u0441\u0442\u0430\u043b\u0441\u044f \u043f\u0440\u0435\u0436\u043d\u0438\u043c (\u0441\u043d\u0430\u0440\u0443\u0436\u0438 \u0432\u0441\u0451 \u0442\u0430\u043a \u0436\u0435 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043a\u0430\u043a \u00ab\u043a\u043b\u0438\u043a\u043d\u0443\u0442\u044c\u00bb, \u00ab\u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c\u00bb), \u043d\u043e \u0442\u0435\u043f\u0435\u0440\u044c \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u043d\u0435 \u0431\u043b\u043e\u043a\u0438\u0440\u0443\u0435\u0442 \u043f\u043e\u0442\u043e\u043a.<\/p>\n<h4>PageComponent<\/h4>\n<p>\u0414\u0430\u043b\u0435\u0435 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430. \u0421\u0440\u0430\u0432\u043d\u0438\u043c, \u043a\u0430\u043a \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u043b\u0430 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044f \u0438 \u043a\u0430\u043a \u043e\u043d\u0430 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u0442\u0441\u044f \u043f\u043e\u0441\u043b\u0435 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0430 \u043d\u0430 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439 API.<\/p>\n<p><strong>\u0421\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f:<\/strong> <a href=\"https:\/\/github.com\/Nikita-Filonov\/python-ui-tests\/blob\/main\/components\/navbar_component.py\" rel=\"noopener noreferrer nofollow\">\/components\/navbar_component.py<\/a><\/p>\n<pre><code class=\"python\">import allure from playwright.sync_api import Page  from components.base_component import BaseComponent from elements.text import Text   class NavbarComponent(BaseComponent):     def __init__(self, page: Page):         super().__init__(page)          self.app_title = Text(page, 'navigation-navbar-app-title-text', 'App title')         self.welcome_title = Text(page, 'navigation-navbar-welcome-title-text', 'Welcome title')      @allure.step(\"Check visible navbar\")     def check_visible(self, username: str):         self.app_title.check_visible()         self.app_title.check_have_text('UI Course')          self.welcome_title.check_visible()         self.welcome_title.check_have_text(f'Welcome, {username}!') <\/code><\/pre>\n<p><strong>\u0410\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f:<\/strong> <a href=\"https:\/\/github.com\/Nikita-Filonov\/python-ui-tests-async\/blob\/main\/components\/navbar_component.py\" rel=\"noopener noreferrer nofollow\">\/components\/navbar_component.py<\/a><\/p>\n<pre><code class=\"python\">import allure from playwright.async_api import Page  from components.base_component import BaseComponent from elements.text import Text   class NavbarComponent(BaseComponent):     def __init__(self, page: Page):         super().__init__(page)          self.app_title = Text(page, 'navigation-navbar-app-title-text', 'App title')         self.welcome_title = Text(page, 'navigation-navbar-welcome-title-text', 'Welcome title')      @allure.step(\"Check visible navbar\")     async def check_visible(self, username: str):         await self.app_title.check_visible()         await self.app_title.check_have_text('UI Course')          await self.welcome_title.check_visible()         await self.welcome_title.check_have_text(f'Welcome, {username}!') <\/code><\/pre>\n<p>\u041a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0438 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b, \u0442\u043e\u0436\u0435 \u0441\u0442\u0430\u043b\u0438 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u043c\u0438. \u041c\u0435\u0442\u043e\u0434\u044b \u0432\u0440\u043e\u0434\u0435 <code>check_visible<\/code> \u0442\u0435\u043f\u0435\u0440\u044c \u043e\u0431\u044a\u044f\u0432\u043b\u0435\u043d\u044b \u0447\u0435\u0440\u0435\u0437 <code>async def<\/code>, \u0430 \u0432\u044b\u0437\u043e\u0432\u044b \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u044e\u0442\u0441\u044f \u0441 <code>await<\/code>. \u0413\u043b\u0430\u0432\u043d\u043e\u0435 \u043e\u0442\u043b\u0438\u0447\u0438\u0435: \u0435\u0441\u043b\u0438 \u0445\u043e\u0442\u044f \u0431\u044b \u043e\u0434\u0438\u043d \u043c\u0435\u0442\u043e\u0434 \u0432\u043d\u0443\u0442\u0440\u0438 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439, \u0432\u0441\u044f \u0446\u0435\u043f\u043e\u0447\u043a\u0430 \u0432\u044b\u0437\u043e\u0432\u043e\u0432 \u0434\u043e\u043b\u0436\u043d\u0430 \u0431\u044b\u0442\u044c \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0439. \u042d\u0442\u043e \u0437\u0430\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <code>await<\/code> \u0432 \u0442\u0435\u0441\u0442\u0430\u0445 \u0438 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0442\u044c \u0435\u0434\u0438\u043d\u043e\u043e\u0431\u0440\u0430\u0437\u0438\u0435 API.<\/p>\n<h4>PageObject<\/h4>\n<p>\u0418 \u043d\u0430\u043a\u043e\u043d\u0435\u0446 \u0440\u0430\u0437\u0431\u0435\u0440\u0451\u043c, \u043a\u0430\u043a \u0438\u0437\u043c\u0435\u043d\u044f\u044e\u0442\u0441\u044f \u0441\u0430\u043c\u0438 \u043e\u0431\u044a\u0435\u043a\u0442\u044b \u0441\u0442\u0440\u0430\u043d\u0438\u0446. \u0414\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u0432\u043e\u0437\u044c\u043c\u0451\u043c \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u043d\u043e\u0432\u043e\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0438 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c, \u043a\u0430\u043a \u043e\u043d\u0430 \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043f\u043e\u0434 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 <code>async\/await<\/code>.<\/p>\n<p><strong>\u0421\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f:<\/strong> <a href=\"https:\/\/github.com\/Nikita-Filonov\/python-ui-tests\/blob\/main\/pages\/registration_page.py\" rel=\"noopener noreferrer nofollow\">\/pages\/registration_page.py<\/a><\/p>\n<pre><code class=\"python\">import re  from playwright.sync_api import Page  from components.registration_form_component import RegistrationFormComponent from elements.button import Button from elements.link import Link from pages.base_page import BasePage   class RegistrationPage(BasePage):     def __init__(self, page: Page):         super().__init__(page)          self.registration_form = RegistrationFormComponent(page)          self.login_link = Link(page, \"registration-page-login-link\", \"Login\")         self.registration_button = Button(page, \"registration-page-registration-button\", \"Registration\")      def click_registration_button(self):         self.registration_button.click()         self.check_current_url(re.compile(\".*\/#\/dashboard\")) <\/code><\/pre>\n<p><strong>\u0410\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f:<\/strong> <a href=\"https:\/\/github.com\/Nikita-Filonov\/python-ui-tests-async\/blob\/main\/pages\/registration_page.py\" rel=\"noopener noreferrer nofollow\">\/pages\/registration_page.py<\/a><\/p>\n<pre><code class=\"python\">import re  from playwright.async_api import Page  from components.registration_form_component import RegistrationFormComponent from elements.button import Button from elements.link import Link from pages.base_page import BasePage   class RegistrationPage(BasePage):     def __init__(self, page: Page):         super().__init__(page)          self.registration_form = RegistrationFormComponent(page)          self.login_link = Link(page, \"registration-page-login-link\", \"Login\")         self.registration_button = Button(page, \"registration-page-registration-button\", \"Registration\")      async def click_registration_button(self):         await self.registration_button.click()         await self.check_current_url(re.compile(\".*\/#\/dashboard\")) <\/code><\/pre>\n<p>\u0422\u0435 \u0436\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u044e\u0442\u0441\u044f \u0438 \u043a PageObject: \u0435\u0441\u043b\u0438 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0438\u043b\u0438 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b, \u0435\u0451 \u043c\u0435\u0442\u043e\u0434\u044b \u0442\u043e\u0436\u0435 \u0434\u043e\u043b\u0436\u043d\u044b \u0431\u044b\u0442\u044c \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u043c\u0438 (<code>async def click_registration_button<\/code>). \u0411\u043e\u043b\u0435\u0435 \u0442\u043e\u0433\u043e, \u0431\u0430\u0437\u043e\u0432\u044b\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 (<code>check_current_url<\/code>) \u0438\u043b\u0438 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u044b \u043f\u043e \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430\u043c \u0442\u0430\u043a\u0436\u0435 \u0434\u043e\u043b\u0436\u043d\u044b \u0431\u044b\u0442\u044c \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u0430\u043d\u044b \u043d\u0430 async\u2011\u0432\u0430\u0440\u0438\u0430\u043d\u0442\u044b, \u0435\u0441\u043b\u0438 \u0432\u043d\u0443\u0442\u0440\u0438 \u043e\u043d\u0438 \u043e\u0431\u0440\u0430\u0449\u0430\u044e\u0442\u0441\u044f \u043a Playwright API.<\/p>\n<h4>\u0418\u0442\u043e\u0433<\/h4>\n<p>\u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u0438\u0445 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043e\u0441\u0442\u0430\u043b\u0430\u0441\u044c \u043f\u0440\u0435\u0436\u043d\u0435\u0439 (\u0435\u0441\u0442\u044c \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u2192 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u2192 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u2192 \u0442\u0435\u0441\u0442\u044b), \u043d\u043e \u0432\u0441\u044f \u0446\u0435\u043f\u043e\u0447\u043a\u0430 \u0432\u044b\u0437\u043e\u0432\u043e\u0432 \u0441\u0442\u0430\u043b\u0430 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0439. \u042d\u0442\u043e \u043a\u043b\u044e\u0447\u0435\u0432\u043e\u0439 \u043c\u043e\u043c\u0435\u043d\u0442: \u043d\u0435\u043b\u044c\u0437\u044f \u043f\u0440\u043e\u0441\u0442\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043e\u0434\u0438\u043d \u043c\u0435\u0442\u043e\u0434 <code>async<\/code> \u0438 \u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u043c\u0438 \u2014 \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0442\u043e\u043a, \u0432\u0441\u044f \u00ab\u0432\u0435\u0440\u0442\u0438\u043a\u0430\u043b\u044c\u00bb \u0432\u044b\u0437\u043e\u0432\u043e\u0432 \u0434\u043e\u043b\u0436\u043d\u0430 \u0431\u044b\u0442\u044c \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u0430\u043d\u0430 \u043d\u0430 <code>async<\/code>. \u041f\u0440\u0438 \u044d\u0442\u043e\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u043e\u0441\u0442\u0430\u0451\u0442\u0441\u044f \u043f\u0440\u0438\u0432\u044b\u0447\u043d\u044b\u043c: \u0432 \u0442\u0435\u0441\u0442\u0430\u0445 \u0432\u044b \u043f\u043e\u2011\u043f\u0440\u0435\u0436\u043d\u0435\u043c\u0443 \u043f\u0438\u0448\u0435\u0442\u0435 \u00ab\u043d\u0430\u0436\u0430\u0442\u044c \u043a\u043d\u043e\u043f\u043a\u0443, \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0442\u0435\u043a\u0441\u0442\u00bb, \u043d\u043e \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442\u0435 <code>await<\/code>, \u0438 \u0442\u0435\u0441\u0442\u044b \u0442\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0433\u0443\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c\u0441\u044f \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u0435\u0435 \u043f\u0440\u0438 \u0431\u043e\u043b\u044c\u0448\u043e\u043c \u0447\u0438\u0441\u043b\u0435 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439 \u0441 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043e\u043c.<\/p>\n<h3>\u0422\u0435\u0441\u0442\u044b<\/h3>\n<p>\u041f\u0435\u0440\u0435\u0434 \u0442\u0435\u043c \u043a\u0430\u043a \u043f\u0435\u0440\u0435\u0439\u0442\u0438 \u043a \u0441\u0430\u043c\u0438\u043c \u0442\u0435\u0441\u0442\u0430\u043c, \u043d\u0443\u0436\u043d\u043e \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e <code>pytest<\/code>. \u0412 \u0444\u0430\u0439\u043b\u0435 <a href=\"https:\/\/docs.pytest.org\/en\/stable\/reference\/customize.html\" rel=\"noopener noreferrer nofollow\">pytest.ini<\/a> \u043f\u043e\u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 <code>asyncio_mode = auto<\/code>, \u0447\u0442\u043e\u0431\u044b <a href=\"https:\/\/github.com\/pytest-dev\/pytest-asyncio\" rel=\"noopener noreferrer nofollow\">pytest-asyncio<\/a> \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u043b \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0435 \u0442\u0435\u0441\u0442\u044b. \u0422\u0430\u043a\u0436\u0435 \u0441\u0442\u043e\u0438\u0442 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443 <code>asyncio_default_fixture_loop_scope = function<\/code>, \u0447\u0442\u043e\u0431\u044b \u043a\u0430\u0436\u0434\u044b\u0439 \u0442\u0435\u0441\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u043b\u0441\u044f \u0432 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u043c \u0441\u043e\u0431\u044b\u0442\u0438\u0439\u043d\u043e\u043c \u0446\u0438\u043a\u043b\u0435, \u0438\u0437\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u043c \u043e\u0442 \u0434\u0440\u0443\u0433\u0438\u0445 \u0442\u0435\u0441\u0442\u043e\u0432.<\/p>\n<p><a href=\"https:\/\/github.com\/Nikita-Filonov\/python-ui-tests-async\/blob\/main\/pytest.ini\" rel=\"noopener noreferrer nofollow\">pytest.ini<\/a><\/p>\n<pre><code class=\"python\">[pytest] addopts = -s -v asyncio_mode = auto python_files = *_tests.py test_*.py python_classes = Test* python_functions = test_* asyncio_default_fixture_loop_scope = function markers =     regression: \u041c\u0430\u0440\u043a\u0438\u0440\u043e\u0432\u043a\u0430 \u0434\u043b\u044f \u0440\u0435\u0433\u0440\u0435\u0441\u0441\u0438\u043e\u043d\u043d\u044b\u0445 \u0442\u0435\u0441\u0442\u043e\u0432.     registration: \u041c\u0430\u0440\u043a\u0438\u0440\u043e\u0432\u043a\u0430 \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u043e\u0432, \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0445 \u0441 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0435\u0439 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439.<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0440\u0430\u0437\u0431\u0435\u0440\u0451\u043c, \u0447\u0442\u043e \u0438\u043c\u0435\u043d\u043d\u043e \u0438\u0437\u043c\u0435\u043d\u0438\u043b\u043e\u0441\u044c \u0432 \u0441\u0430\u043c\u0438\u0445 \u0442\u0435\u0441\u0442\u0430\u0445:<\/p>\n<p><strong>\u0421\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f:<\/strong> <a href=\"https:\/\/github.com\/Nikita-Filonov\/python-ui-tests\/blob\/main\/tests\/test_registration.py\" rel=\"noopener noreferrer nofollow\">\/tests\/test_registration.py<\/a><\/p>\n<pre><code class=\"python\">import allure import pytest  from pages.dashboard_page import DashboardPage from pages.registration_page import RegistrationPage from tools.routes import AppRoute   @pytest.mark.regression @pytest.mark.registration class TestRegistration:     @allure.title(\"Successful registration\")     def test_successful_registration(             self,             dashboard_page: DashboardPage,             registration_page: RegistrationPage     ):         registration_page.visit(AppRoute.REGISTRATION)         registration_page.registration_form.check_visible(email=\"\", username=\"\", password=\"\")         registration_page.registration_form.fill(             email=\"user@example.com\",             username=\"Playwright\",             password=\"qwerty\"         )         registration_page.click_registration_button()          dashboard_page.navbar.check_visible(\"Playwright\")         dashboard_page.dashboard_toolbar_view.check_visible()         dashboard_page.check_visible_scores_chart()         dashboard_page.check_visible_courses_chart()         dashboard_page.check_visible_students_chart()         dashboard_page.check_visible_activities_chart() <\/code><\/pre>\n<p><strong>\u0410\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f:<\/strong> <a href=\"https:\/\/github.com\/Nikita-Filonov\/python-ui-tests-async\/blob\/main\/tests\/test_registration.py\" rel=\"noopener noreferrer nofollow\">\/tests\/test_registration.py<\/a><\/p>\n<pre><code class=\"python\">import allure import pytest  from pages.dashboard_page import DashboardPage from pages.registration_page import RegistrationPage from tools.routes import AppRoute   @pytest.mark.asyncio @pytest.mark.regression @pytest.mark.registration class TestRegistration:     @allure.title(\"Successful registration\")     async def test_successful_registration(             self,             dashboard_page: DashboardPage,             registration_page: RegistrationPage     ):         await registration_page.visit(AppRoute.REGISTRATION)         await registration_page.registration_form.check_visible(email=\"\", username=\"\", password=\"\")         await registration_page.registration_form.fill(             email=\"user@example.com\",             username=\"Playwright\",             password=\"qwerty\"         )         await registration_page.click_registration_button()          await dashboard_page.navbar.check_visible(\"Playwright\")         await dashboard_page.dashboard_toolbar_view.check_visible()         await dashboard_page.check_visible_scores_chart()         await dashboard_page.check_visible_courses_chart()         await dashboard_page.check_visible_students_chart()         await dashboard_page.check_visible_activities_chart() <\/code><\/pre>\n<p>\u0412 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u0442\u0435\u0441\u0442 \u043f\u0440\u043e\u0441\u0442\u043e \u0432\u044b\u0437\u044b\u0432\u0430\u043b \u043c\u0435\u0442\u043e\u0434\u044b \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u0441\u0442\u0440\u0430\u043d\u0438\u0446. \u0412\u0441\u0435 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 (\u043f\u0435\u0440\u0435\u0445\u043e\u0434 \u043f\u043e \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0443, \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0444\u043e\u0440\u043c\u044b, \u043a\u043b\u0438\u043a \u043f\u043e \u043a\u043d\u043e\u043f\u043a\u0435, \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432) \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u043b\u0438\u0441\u044c \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0438 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u043b\u0438 \u043f\u043e\u0442\u043e\u043a \u0434\u043e \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f.<\/p>\n<p>\u0412 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435:<\/p>\n<ul>\n<li>\n<p>\u041c\u0435\u0442\u043e\u0434\u044b \u0442\u0435\u0441\u0442\u0430 \u0438 \u0432\u0441\u0435 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c\u044b\u0435 \u0438\u043c \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u0442\u0435\u043f\u0435\u0440\u044c \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0435, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0442\u0435\u0441\u0442\u043e\u0432\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u043e\u0431\u044a\u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043a\u0430\u043a <code>async def<\/code>, \u0430 \u0432\u0441\u0435 \u0432\u044b\u0437\u043e\u0432\u044b \u043c\u0435\u0442\u043e\u0434\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044e\u0442 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b, \u043e\u0431\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u044e\u0442\u0441\u044f \u0432 <code>await<\/code>.<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e\u044f\u0432\u0438\u043b\u0430\u0441\u044c \u043c\u0430\u0440\u043a\u0438\u0440\u043e\u0432\u043a\u0430 <code>@pytest.mark.asyncio<\/code>, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0441\u043e\u043e\u0431\u0449\u0430\u0435\u0442 <a href=\"https:\/\/docs.pytest.org\/en\/stable\/\" rel=\"noopener noreferrer nofollow\">pytest<\/a>, \u0447\u0442\u043e \u044d\u0442\u043e\u0442 \u0442\u0435\u0441\u0442 \u0434\u043e\u043b\u0436\u0435\u043d \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c\u0441\u044f \u0432\u043d\u0443\u0442\u0440\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u0439\u043d\u043e\u0433\u043e \u0446\u0438\u043a\u043b\u0430.<\/p>\n<\/li>\n<li>\n<p>\u0412\u0441\u0435 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u043c\u0438 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b (\u043f\u0435\u0440\u0435\u0445\u043e\u0434 \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443, \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0444\u043e\u0440\u043c\u044b, \u043d\u0430\u0436\u0430\u0442\u0438\u0435 \u043a\u043d\u043e\u043f\u043a\u0438, \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438) \u0442\u0435\u043f\u0435\u0440\u044c \u043d\u0435 \u0431\u043b\u043e\u043a\u0438\u0440\u0443\u044e\u0442 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u043f\u043e\u0442\u043e\u043a \u2014 \u0432\u043c\u0435\u0441\u0442\u043e \u044d\u0442\u043e\u0433\u043e \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u0432 <a href=\"https:\/\/docs.python.org\/3\/library\/asyncio-eventloop.html\" rel=\"noopener noreferrer nofollow\">event loop<\/a>, \u0447\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043f\u0440\u0438 \u0436\u0435\u043b\u0430\u043d\u0438\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0445 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0439 \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0435\u0441\u043b\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0442\u0430\u043a\u0438\u0445 \u0442\u0435\u0441\u0442\u043e\u0432).<\/p>\n<\/li>\n<\/ul>\n<p>\u0412\u0430\u0436\u043d\u043e \u043f\u043e\u0434\u0447\u0435\u0440\u043a\u043d\u0443\u0442\u044c, \u0447\u0442\u043e \u0441 \u0442\u043e\u0447\u043a\u0438 \u0437\u0440\u0435\u043d\u0438\u044f \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0438 \u0442\u0435\u0441\u0442\u0430 \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u0438\u0437\u043c\u0435\u043d\u0438\u043b\u043e\u0441\u044c: \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0439 \u043f\u043e-\u043f\u0440\u0435\u0436\u043d\u0435\u043c\u0443 \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442 \u0443\u0441\u043f\u0435\u0448\u043d\u0443\u044e \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432. \u041e\u0434\u043d\u0430\u043a\u043e \u0442\u0435\u043f\u0435\u0440\u044c \u0432\u0441\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u044e\u0442\u0441\u044f \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e \u0438 \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u044b \u0441 \u0434\u0440\u0443\u0433\u0438\u043c\u0438 async-\u0444\u0438\u043a\u0441\u0442\u0443\u0440\u0430\u043c\u0438 \u0438 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430\u043c\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u044b \u0430\u0434\u0430\u043f\u0442\u0438\u0440\u043e\u0432\u0430\u043b\u0438 \u0440\u0430\u043d\u0435\u0435.<\/p>\n<h3>\u0418\u0442\u043e\u0433<\/h3>\n<p>\u041d\u0435\u0441\u043c\u043e\u0442\u0440\u044f \u043d\u0430 \u043f\u0435\u0440\u0435\u0445\u043e\u0434 \u043d\u0430 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439 \u0441\u0442\u0438\u043b\u044c, \u0441\u0430\u043c \u0442\u0435\u0441\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0437\u0430 \u0442\u043e \u0436\u0435 \u0432\u0440\u0435\u043c\u044f, \u0447\u0442\u043e \u0438 \u0435\u0433\u043e \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044f. \u042d\u0442\u043e \u043e\u0436\u0438\u0434\u0430\u0435\u043c\u044b\u0439 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442: \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0439 \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 \u0448\u0430\u0433\u043e\u0432, \u043a\u0430\u0436\u0434\u044b\u0439 \u0438\u0437 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0433\u043e (\u043f\u0435\u0440\u0435\u0445\u043e\u0434 \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443, \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0444\u043e\u0440\u043c\u044b, \u043a\u043b\u0438\u043a, \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438), \u0438 \u043e\u043d\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u044e\u0442\u0441\u044f \u0441\u0442\u0440\u043e\u0433\u043e \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e.<\/p>\n<p>\u0410\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0441\u0442\u044c \u0432 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043d\u0435 \u0434\u0435\u043b\u0430\u0435\u0442 \u0442\u0435\u0441\u0442\u044b \u00ab\u043c\u0433\u043d\u043e\u0432\u0435\u043d\u043d\u043e \u0431\u044b\u0441\u0442\u0440\u044b\u043c\u0438\u00bb. \u0415\u0451 \u0437\u0430\u0434\u0430\u0447\u0430 \u0434\u0440\u0443\u0433\u0430\u044f \u2014 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0442\u044c \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u043e\u0441\u0442\u044c \u0441 \u0434\u0440\u0443\u0433\u0438\u043c\u0438 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u043c\u0438 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430\u043c\u0438 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0441 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u043c\u0438 API-\u043a\u043b\u0438\u0435\u043d\u0442\u0430\u043c\u0438 \u0438\u043b\u0438 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430\u043c\u0438), \u0447\u0442\u043e\u0431\u044b \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0435\u0434\u0438\u043d\u044b\u0439 \u0441\u043e\u0431\u044b\u0442\u0438\u0439\u043d\u044b\u0439 \u0446\u0438\u043a\u043b. \u042d\u0442\u043e \u043f\u043e\u043b\u0435\u0437\u043d\u043e, \u043a\u043e\u0433\u0434\u0430 \u0442\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u043c\u044b\u0439 \u043a\u043e\u0434 \u0441\u0430\u043c \u043f\u043e \u0441\u0435\u0431\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0432 async-\u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0435, \u043b\u0438\u0431\u043e \u043a\u043e\u0433\u0434\u0430 \u0442\u0435\u0441\u0442\u044b \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u044e\u0442 \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u044b\u0435 <a href=\"https:\/\/en.wikipedia.org\/wiki\/I\/O_bound\" rel=\"noopener noreferrer nofollow\">I\/O\u2011\u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438<\/a> \u0432\u043d\u0443\u0442\u0440\u0438 \u043e\u0434\u043d\u043e\u0433\u043e \u0442\u0435\u0441\u0442\u0430.<\/p>\n<p>\u0412 \u0441\u043b\u0443\u0447\u0430\u0435 \u0436\u0435 \u043a\u043b\u0430\u0441\u0441\u0438\u0447\u0435\u0441\u043a\u0438\u0445 UI-\u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0435\u0432, \u0433\u0434\u0435 \u0432\u0441\u0451 \u0441\u0442\u0440\u043e\u0438\u0442\u0441\u044f \u043a\u0430\u043a \u0446\u0435\u043f\u043e\u0447\u043a\u0430 \u0448\u0430\u0433\u043e\u0432 \u00ab\u043e\u0442\u043a\u0440\u044b\u0442\u044c \u2192 \u0432\u0432\u0435\u0441\u0442\u0438 \u0434\u0430\u043d\u043d\u044b\u0435 \u2192 \u043d\u0430\u0436\u0430\u0442\u044c \u043a\u043d\u043e\u043f\u043a\u0443 \u2192 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u00bb, \u0432\u044b\u0438\u0433\u0440\u044b\u0448 \u0432\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u2014 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0439 \u043e\u0441\u0442\u0430\u0451\u0442\u0441\u044f \u043b\u0438\u043d\u0435\u0439\u043d\u044b\u043c, \u0438 \u043a\u0430\u0436\u0434\u044b\u0439 \u0448\u0430\u0433 \u0434\u043e\u043b\u0436\u0435\u043d \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u044c\u0441\u044f \u043f\u0440\u0435\u0436\u0434\u0435, \u0447\u0435\u043c \u043d\u0430\u0447\u043d\u0451\u0442\u0441\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439.<\/p>\n<h3>API \u0430\u0432\u0442\u043e\u0442\u0435\u0441\u0442\u044b<\/h3>\n<p>\u0415\u0441\u043b\u0438 \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u0441 UI \u0442\u0435\u0441\u0442\u0430\u043c\u0438 \u043c\u044b \u0444\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u0434\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u043b\u0438\u0441\u044c \u043f\u043e\u0434 \u0443\u0436\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 <a href=\"https:\/\/github.com\/microsoft\/playwright-python\/tree\/main\/playwright\/async_api\" rel=\"noopener noreferrer nofollow\">\u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439 API Playwright<\/a>, \u0442\u043e \u0432 API \u0442\u0435\u0441\u0442\u0430\u0445 \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u044f \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0438\u043d\u0430\u044f: \u0438\u043c\u0435\u043d\u043d\u043e \u043d\u0430\u0448\u0438 API\u2011\u043a\u043b\u0438\u0435\u043d\u0442\u044b \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0442 \u0441\u0435\u0442\u044c\u044e \u0438 \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u044e\u0442 \u0431\u043e\u043b\u044c\u0448\u0443\u044e \u0447\u0430\u0441\u0442\u044c \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0442\u0435\u0441\u0442\u0430. \u0418 \u044d\u0442\u043e \u043a\u0430\u0436\u0435\u0442\u0441\u044f \u0431\u043e\u043b\u0435\u0435 \u043b\u043e\u0433\u0438\u0447\u043d\u044b\u043c \u043c\u0435\u0441\u0442\u043e\u043c \u0434\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u044f async\/await, \u0432\u0435\u0434\u044c \u0441\u0435\u0442\u0435\u0432\u044b\u0435 \u0432\u044b\u0437\u043e\u0432\u044b \u2014 \u044d\u0442\u043e \u0442\u0438\u043f\u0438\u0447\u043d\u044b\u0435 <a href=\"https:\/\/en.wikipedia.org\/wiki\/I\/O_bound\" rel=\"noopener noreferrer nofollow\">I\/O bound<\/a> \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438.<\/p>\n<p>\u041e\u0434\u043d\u0430\u043a\u043e \u0432\u0430\u0436\u043d\u043e \u043f\u043e\u043d\u0438\u043c\u0430\u0442\u044c, \u0447\u0442\u043e \u0441\u0430\u043c\u0430 \u043f\u043e \u0441\u0435\u0431\u0435 \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u044c \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432 \u043d\u0430 async \u0438 \u0437\u0430\u043c\u0435\u043d\u0430 HTTP\u2011\u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u043d\u0430 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u0443\u044e (\u0432 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 <a href=\"https:\/\/www.python-httpx.org\/async\/\" rel=\"noopener noreferrer nofollow\">httpx.AsyncClient<\/a>) \u043d\u0435 \u0434\u0435\u043b\u0430\u0435\u0442 \u0442\u0435\u0441\u0442\u044b \u00ab\u043c\u0430\u0433\u0438\u0447\u0435\u0441\u043a\u0438 \u0431\u044b\u0441\u0442\u0440\u044b\u043c\u0438\u00bb. \u0415\u0441\u043b\u0438 \u0442\u0435\u0441\u0442\u044b \u043f\u043e\u2011\u043f\u0440\u0435\u0436\u043d\u0435\u043c\u0443 \u0438\u0434\u0443\u0442 \u043e\u0434\u0438\u043d \u0437\u0430 \u0434\u0440\u0443\u0433\u0438\u043c (\u0430 <a href=\"https:\/\/docs.pytest.org\/en\/stable\/\" rel=\"noopener noreferrer nofollow\">pytest<\/a> \u0438\u043c\u0435\u043d\u043d\u043e \u0442\u0430\u043a \u0438\u0445 \u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442), \u0432\u044b\u0438\u0433\u0440\u044b\u0448 \u0432 \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u0438 \u043c\u043e\u0436\u0435\u0442 \u0438 \u043d\u0435 \u043f\u043e\u044f\u0432\u0438\u0442\u044c\u0441\u044f. \u0410\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439 \u043a\u043e\u0434 \u0432 \u044d\u0442\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043f\u043e\u043b\u0435\u0437\u0435\u043d \u043f\u0440\u0435\u0436\u0434\u0435 \u0432\u0441\u0435\u0433\u043e \u0434\u043b\u044f:<\/p>\n<ul>\n<li>\n<p>\u0441\u0438\u0442\u0443\u0430\u0446\u0438\u0439, \u043a\u043e\u0433\u0434\u0430 \u0441\u0430\u043c \u0442\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u043c\u044b\u0439 \u043a\u043e\u0434 \u0443\u0436\u0435 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, <a href=\"https:\/\/en.wikipedia.org\/wiki\/WebSocket\" rel=\"noopener noreferrer nofollow\">WebSocket<\/a> \u0438\u043b\u0438 <a href=\"https:\/\/en.wikipedia.org\/wiki\/Stream_processing\" rel=\"noopener noreferrer nofollow\">\u0441\u0442\u0440\u0438\u043c\u0438\u043d\u0433<\/a>);<\/p>\n<\/li>\n<li>\n<p>\u0441\u043b\u0443\u0447\u0430\u0435\u0432, \u043a\u043e\u0433\u0434\u0430 \u0432\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0439 <em>\u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u043e\u0434\u043d\u043e\u0433\u043e \u0442\u0435\u0441\u0442\u0430<\/em> \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043c\u043e\u0434\u0435\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432).<\/p>\n<\/li>\n<\/ul>\n<p>\u0412 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u043e\u043c \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0440\u0430\u0431\u043e\u0442\u044b \u043e\u0447\u0435\u043d\u044c \u043f\u043e\u0445\u043e\u0436\u0430 \u043d\u0430 UI: \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u044b \u0441\u0442\u0430\u043d\u043e\u0432\u044f\u0442\u0441\u044f \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u043c\u0438, HTTP\u2011\u043a\u043b\u0438\u0435\u043d\u0442\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442 <code>await<\/code>, \u0430 \u0442\u0435\u0441\u0442\u044b \u043f\u043e\u043c\u0435\u0447\u0430\u044e\u0442\u0441\u044f \u043c\u0430\u0440\u043a\u0435\u0440\u043e\u043c <code>@pytest.mark.asyncio<\/code>.<\/p>\n<p>\u041f\u043e\u043b\u043d\u044b\u0435 \u043f\u0440\u0438\u043c\u0435\u0440\u044b \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 API \u0442\u0435\u0441\u0442\u043e\u0432 \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043d\u0430\u0439\u0442\u0438 \u0432 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f\u0445:<\/p>\n<ul>\n<li>\n<p>\u0421\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f: <a href=\"https:\/\/github.com\/Nikita-Filonov\/python-api-tests\" rel=\"noopener noreferrer nofollow\">python-api-tests<\/a><\/p>\n<\/li>\n<li>\n<p>\u0410\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f: <a href=\"https:\/\/github.com\/Nikita-Filonov\/python-api-tests-async\" rel=\"noopener noreferrer nofollow\">python-api-tests-async<\/a><\/p>\n<\/li>\n<\/ul>\n<h3>API \u043a\u043b\u0438\u0435\u043d\u0442\u044b<\/h3>\n<p>\u0414\u0432\u0438\u0436\u043a\u043e\u043c API \u0442\u0435\u0441\u0442\u043e\u0432 \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f API\u2011\u043a\u043b\u0438\u0435\u043d\u0442\u044b. \u0418\u043c\u0435\u043d\u043d\u043e \u043e\u043d\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u044e\u0442 \u0441\u0435\u0442\u0435\u0432\u044b\u0435 \u0432\u044b\u0437\u043e\u0432\u044b \u0438, \u043a\u0430\u043a \u0441\u043b\u0435\u0434\u0441\u0442\u0432\u0438\u0435, \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f <a href=\"https:\/\/en.wikipedia.org\/wiki\/I\/O_bound\" rel=\"noopener noreferrer nofollow\"><strong>I\/O\u2011bound<\/strong><\/a> \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u044f\u043c\u0438. \u0422\u0430\u043a\u0438\u0435 \u0432\u044b\u0437\u043e\u0432\u044b \u043d\u0435 \u043d\u0430\u0433\u0440\u0443\u0436\u0430\u044e\u0442 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440, \u0430 \u0432 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u043c \u0436\u0434\u0443\u0442 \u043e\u0442\u0432\u0435\u0442\u0430 \u043e\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0430, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0438\u043c\u0435\u043d\u043d\u043e \u043d\u0430 \u043d\u0438\u0445 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0441\u0442\u044c \u0432\u043b\u0438\u044f\u0435\u0442 \u0431\u043e\u043b\u044c\u0448\u0435 \u0432\u0441\u0435\u0433\u043e.<\/p>\n<h4>BaseClient<\/h4>\n<p>\u041c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 <a href=\"https:\/\/www.python-httpx.org\/\" rel=\"noopener noreferrer nofollow\"><strong>HTTPX<\/strong><\/a>, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0443\u0436\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439 \u0440\u0435\u0436\u0438\u043c \u0440\u0430\u0431\u043e\u0442\u044b \u0447\u0435\u0440\u0435\u0437 \u043a\u043b\u0430\u0441\u0441 <a href=\"https:\/\/www.python-httpx.org\/async\/\" rel=\"noopener noreferrer nofollow\">AsyncClient<\/a>. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u0435\u0440\u0432\u044b\u043c \u0448\u0430\u0433\u043e\u043c \u0434\u043b\u044f \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438 \u043d\u0430 <a href=\"https:\/\/docs.python.org\/3\/library\/asyncio-task.html\" rel=\"noopener noreferrer nofollow\">async\/await<\/a> \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0430\u0434\u0430\u043f\u0442\u0430\u0446\u0438\u044f \u0431\u0430\u0437\u043e\u0432\u043e\u0433\u043e \u043a\u043b\u0438\u0435\u043d\u0442\u0430: \u043f\u0435\u0440\u0435\u0432\u043e\u0434 \u0435\u0433\u043e \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u043d\u0430 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0435 \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0433\u043e \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u0432\u043c\u0435\u0441\u0442\u043e \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0433\u043e.<\/p>\n<p><strong>\u0421\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f:<\/strong> <a href=\"https:\/\/github.com\/Nikita-Filonov\/python-api-tests\/blob\/main\/clients\/base_client.py\" rel=\"noopener noreferrer nofollow\">\/clients\/base_client.py<\/a><\/p>\n<pre><code class=\"python\">from typing import Any  import allure from httpx import Client, URL, Response, QueryParams from httpx._types import RequestData, RequestFiles  from clients.event_hooks import log_request_event_hook, log_response_event_hook from config import HTTPClientConfig   class BaseClient:     def __init__(self, client: Client):         self.client = client      @allure.step(\"Make GET request to {url}\")     def get(self, url: URL | str, params: QueryParams | None = None) -&gt; Response:         return self.client.get(url, params=params)      @allure.step(\"Make POST request to {url}\")     def post(             self,             url: URL | str,             json: Any | None = None,             data: RequestData | None = None,             files: RequestFiles | None = None     ) -&gt; Response:         return self.client.post(url, json=json, data=data, files=files)      @allure.step(\"Make PATCH request to {url}\")     def patch(self, url: URL | str, json: Any | None = None) -&gt; Response:         return self.client.patch(url, json=json)      @allure.step(\"Make DELETE request to {url}\")     def delete(self, url: URL | str) -&gt; Response:         return self.client.delete(url)   def get_http_client(config: HTTPClientConfig) -&gt; Client:     return Client(         timeout=config.timeout,         base_url=config.client_url,         event_hooks={             \"request\": [log_request_event_hook],             \"response\": [log_response_event_hook]         }     ) <\/code><\/pre>\n<p><strong>\u0410\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f:<\/strong> <a href=\"https:\/\/github.com\/Nikita-Filonov\/python-api-tests-async\/blob\/main\/clients\/base_client.py\" rel=\"noopener noreferrer nofollow\">\/clients\/base_client.py<\/a><\/p>\n<pre><code class=\"python\">from typing import Any  import allure from httpx import AsyncClient, URL, Response, QueryParams from httpx._types import RequestData, RequestFiles  from clients.event_hooks import log_request_event_hook, log_response_event_hook from config import HTTPClientConfig   class BaseClient:     def __init__(self, client: AsyncClient):         self.client = client      @allure.step(\"Make GET request to {url}\")     async def get(self, url: URL | str, params: QueryParams | None = None) -&gt; Response:         return await self.client.get(url, params=params)      @allure.step(\"Make POST request to {url}\")     async def post(             self,             url: URL | str,             json: Any | None = None,             data: RequestData | None = None,             files: RequestFiles | None = None     ) -&gt; Response:         return await self.client.post(url, json=json, data=data, files=files)      @allure.step(\"Make PATCH request to {url}\")     async def patch(self, url: URL | str, json: Any | None = None) -&gt; Response:         return await self.client.patch(url, json=json)      @allure.step(\"Make DELETE request to {url}\")     async def delete(self, url: URL | str) -&gt; Response:         return await self.client.delete(url)   def get_http_client(config: HTTPClientConfig) -&gt; AsyncClient:     return AsyncClient(         timeout=config.timeout,         base_url=config.client_url,         event_hooks={             \"request\": [log_request_event_hook],             \"response\": [log_response_event_hook]         }     ) <\/code><\/pre>\n<p>\u0412 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0438 <a href=\"https:\/\/www.python-httpx.org\/advanced\/clients\/\" rel=\"noopener noreferrer nofollow\">httpx.Client<\/a>, \u0430 \u0432\u044b\u0437\u043e\u0432\u044b \u043c\u0435\u0442\u043e\u0434\u043e\u0432 (<code>get<\/code>, <code>post<\/code>, <code>patch<\/code>, <code>delete<\/code>) \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u043b\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0442\u0435\u0441\u0442\u0430 \u0434\u043e \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u043e\u0442\u0432\u0435\u0442\u0430. \u0412 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438:<\/p>\n<ul>\n<li>\n<p>\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f <a href=\"https:\/\/www.python-httpx.org\/async\/\" rel=\"noopener noreferrer nofollow\">httpx.AsyncClient<\/a>, \u0438 \u0432\u0441\u0435 \u043c\u0435\u0442\u043e\u0434\u044b \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u0441\u0442\u0430\u043b\u0438 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u043c\u0438 (<code>async def \u2026<\/code>);<\/p>\n<\/li>\n<li>\n<p>\u043a\u0430\u0436\u0434\u044b\u0439 \u0441\u0435\u0442\u0435\u0432\u043e\u0439 \u0432\u044b\u0437\u043e\u0432 \u0442\u0435\u043f\u0435\u0440\u044c \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u0441 \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u043c \u0441\u043b\u043e\u0432\u043e\u043c <code>await<\/code>, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u0442\u044c <a href=\"https:\/\/docs.python.org\/3\/library\/asyncio-eventloop.html\" rel=\"noopener noreferrer nofollow\">event loop<\/a>;<\/p>\n<\/li>\n<li>\n<p>\u0444\u0430\u0431\u0440\u0438\u043a\u0430 \u043a\u043b\u0438\u0435\u043d\u0442\u0430 (<code>get_http_client<\/code>) \u0442\u0435\u043f\u0435\u0440\u044c \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439 \u043a\u043b\u0438\u0435\u043d\u0442, \u043d\u043e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u043e\u0432 \u043e\u0441\u0442\u0430\u0451\u0442\u0441\u044f \u043f\u0440\u0435\u0436\u043d\u0438\u043c \u2014 \u0441\u0438\u0433\u043d\u0430\u0442\u0443\u0440\u044b \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u043d\u0435 \u043c\u0435\u043d\u044f\u044e\u0442\u0441\u044f, \u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u043f\u043e\u0441\u043e\u0431 \u0432\u044b\u0437\u043e\u0432\u0430.<\/p>\n<\/li>\n<\/ul>\n<p>\u0411\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f \u044d\u0442\u043e\u043c\u0443 \u0442\u0435\u0441\u0442\u044b, \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0435 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u044d\u0442\u043e\u0433\u043e \u043a\u043b\u0438\u0435\u043d\u0442\u0430, \u043c\u043e\u0436\u043d\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u0432\u043d\u0443\u0442\u0440\u0438 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0433\u043e <a href=\"https:\/\/docs.python.org\/3\/library\/asyncio-eventloop.html\" rel=\"noopener noreferrer nofollow\">event loop<\/a> \u0431\u0435\u0437 \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u044b\u0432\u0430\u043d\u0438\u044f \u0432\u0441\u0435\u0439 \u0431\u0438\u0437\u043d\u0435\u0441\u2011\u043b\u043e\u0433\u0438\u043a\u0438.<\/p>\n<h4>Event hooks<\/h4>\n<p>\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u043c\u043e\u043c\u0435\u043d\u0442, \u043e \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043b\u0435\u0433\u043a\u043e \u0437\u0430\u0431\u044b\u0442\u044c \u2014 \u044d\u0442\u043e <a href=\"https:\/\/www.python-httpx.org\/advanced\/event-hooks\/\" rel=\"noopener noreferrer nofollow\">event hooks<\/a>. \u0412 HTTPX \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0434\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u043e\u0442\u0432\u0435\u0442\u0430. \u042d\u0442\u0438 \u0445\u0443\u043a\u0438 \u0442\u043e\u0436\u0435 \u043d\u0443\u0436\u043d\u043e \u0430\u0434\u0430\u043f\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0434 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u0443\u044e \u0440\u0430\u0431\u043e\u0442\u0443, \u0438\u043d\u0430\u0447\u0435 \u043e\u043d\u0438 \u043c\u043e\u0433\u0443\u0442 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 event loop.<\/p>\n<p><strong>\u0421\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f:<\/strong> <a href=\"https:\/\/github.com\/Nikita-Filonov\/python-api-tests\/blob\/main\/clients\/event_hooks.py\" rel=\"noopener noreferrer nofollow\">\/clients\/event_hooks.py<\/a><\/p>\n<pre><code class=\"python\">from httpx import Request, Response  from tools.logger import get_logger  logger = get_logger(\"HTTP_CLIENT\")   def log_request_event_hook(request: Request):     logger.info(f'Make {request.method} request to {request.url}')   def log_response_event_hook(response: Response):     logger.info(         f\"Got response {response.status_code} {response.reason_phrase} from {response.url}\"     ) <\/code><\/pre>\n<p><strong>\u0410\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f:<\/strong> <a href=\"https:\/\/github.com\/Nikita-Filonov\/python-api-tests-async\/blob\/main\/clients\/event_hooks.py\" rel=\"noopener noreferrer nofollow\">\/clients\/event_hooks.py<\/a><\/p>\n<pre><code class=\"python\">from httpx import Request, Response  from tools.logger import get_logger  logger = get_logger(\"HTTP_CLIENT\")   async def log_request_event_hook(request: Request):     logger.info(f'Make {request.method} request to {request.url}')   async def log_response_event_hook(response: Response):     logger.info(         f\"Got response {response.status_code} {response.reason_phrase} from {response.url}\"     ) <\/code><\/pre>\n<p>\u0412 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0445\u0443\u043a\u0438 <code>log_request_event_hook<\/code> \u0438 <code>log_response_event_hook<\/code> \u0431\u044b\u043b\u0438 \u043e\u0431\u044b\u0447\u043d\u044b\u043c\u0438 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u043c\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u044f\u043c\u0438. \u0422\u0435\u043f\u0435\u0440\u044c \u043e\u043d\u0438 \u043e\u0431\u044a\u044f\u0432\u043b\u0435\u043d\u044b \u0441 <code>async def<\/code>, \u0447\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e \u0438\u043d\u0442\u0435\u0433\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0441 <a href=\"https:\/\/www.python-httpx.org\/async\/\" rel=\"noopener noreferrer nofollow\">AsyncClient<\/a>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0442\u0430\u043a\u0436\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0432 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u043c \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0435. \u0424\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043b\u043e\u0433\u0438\u043a\u0430 \u0432\u043d\u0443\u0442\u0440\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u0439 \u043d\u0435 \u0438\u0437\u043c\u0435\u043d\u0438\u043b\u0430\u0441\u044c (\u043c\u044b \u043f\u043e\u2011\u043f\u0440\u0435\u0436\u043d\u0435\u043c\u0443 \u043f\u0440\u043e\u0441\u0442\u043e \u043b\u043e\u0433\u0438\u0440\u0443\u0435\u043c \u0441\u043e\u0431\u044b\u0442\u0438\u044f), \u043d\u043e \u0441\u0438\u0433\u043d\u0430\u0442\u0443\u0440\u0430 \u0434\u043e\u043b\u0436\u043d\u0430 \u0431\u044b\u0442\u044c \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0439, \u0447\u0442\u043e\u0431\u044b HTTPX \u043c\u043e\u0433 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e \u0438\u0445 \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c \u0432 <a href=\"https:\/\/docs.python.org\/3\/library\/asyncio-eventloop.html\" rel=\"noopener noreferrer nofollow\">event loop<\/a> \u0438 \u043d\u0435 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0434\u0440\u0443\u0433\u0438\u0445 \u043a\u043e\u0440\u0443\u0442\u0438\u043d.<\/p>\n<h4>OperationsClient<\/h4>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0430\u0434\u0430\u043f\u0442\u0430\u0446\u0438\u0438 \u0431\u0430\u0437\u043e\u0432\u043e\u0433\u043e \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u0438 \u0445\u0443\u043a\u043e\u0432 \u043c\u043e\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u0442\u044c \u043a \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u043c API\u2011\u043a\u043b\u0438\u0435\u043d\u0442\u0430\u043c. \u041d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 <code>OperationsClient<\/code> \u0432\u0438\u0434\u043d\u043e, \u0447\u0442\u043e \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0437\u0434\u0435\u0441\u044c \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u044b, \u043d\u043e \u0432\u0430\u0436\u043d\u044b: \u0432\u0441\u0435 \u0441\u0435\u0442\u0435\u0432\u044b\u0435 \u0432\u044b\u0437\u043e\u0432\u044b \u0442\u0435\u043f\u0435\u0440\u044c \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u044e\u0442\u0441\u044f \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e.<\/p>\n<p><strong>\u0421\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f:<\/strong> <a href=\"https:\/\/github.com\/Nikita-Filonov\/python-api-tests\/blob\/main\/clients\/operations_client.py\" rel=\"noopener noreferrer nofollow\">\/clients\/operations_client.py<\/a><\/p>\n<pre><code class=\"python\">import allure from httpx import Response  from clients.base_client import BaseClient, get_http_client from config import Settings from schema.operations import CreateOperationSchema, UpdateOperationSchema, OperationSchema from tools.routes import APIRoutes   class OperationsClient(BaseClient):     @allure.step(\"Get list of operations\")     def get_operations_api(self) -&gt; Response:         return self.get(APIRoutes.OPERATIONS)      @allure.step(\"Get operation by id {operation_id}\")     def get_operation_api(self, operation_id: int) -&gt; Response:         return self.get(f\"{APIRoutes.OPERATIONS}\/{operation_id}\")      @allure.step(\"Create operation\")     def create_operation_api(self, operation: CreateOperationSchema) -&gt; Response:         return self.post(             APIRoutes.OPERATIONS,             json=operation.model_dump(mode='json', by_alias=True)         )      @allure.step(\"Update operation by id {operation_id}\")     def update_operation_api(             self,             operation_id: int,             operation: UpdateOperationSchema     ) -&gt; Response:         return self.patch(             f\"{APIRoutes.OPERATIONS}\/{operation_id}\",             json=operation.model_dump(mode='json', by_alias=True, exclude_none=True)         )      @allure.step(\"Delete operation by id {operation_id}\")     def delete_operation_api(self, operation_id: int) -&gt; Response:         return self.delete(f\"{APIRoutes.OPERATIONS}\/{operation_id}\")      def create_operation(self) -&gt; OperationSchema:         request = CreateOperationSchema()         response = self.create_operation_api(request)         return OperationSchema.model_validate_json(response.text)   def get_operations_client(settings: Settings) -&gt; OperationsClient:     return OperationsClient(client=get_http_client(settings.fake_bank_http_client)) <\/code><\/pre>\n<p><strong>\u0410\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f:<\/strong> <a href=\"https:\/\/github.com\/Nikita-Filonov\/python-api-tests-async\/blob\/main\/clients\/operations_client.py\" rel=\"noopener noreferrer nofollow\">\/clients\/operations_client.py<\/a><\/p>\n<pre><code class=\"python\">import allure from httpx import Response  from clients.base_client import BaseClient, get_http_client from config import Settings from schema.operations import CreateOperationSchema, UpdateOperationSchema, OperationSchema from tools.routes import APIRoutes   class OperationsClient(BaseClient):     @allure.step(\"Get list of operations\")     async def get_operations_api(self) -&gt; Response:         return await self.get(APIRoutes.OPERATIONS)      @allure.step(\"Get operation by id {operation_id}\")     async def get_operation_api(self, operation_id: int) -&gt; Response:         return await self.get(f\"{APIRoutes.OPERATIONS}\/{operation_id}\")      @allure.step(\"Create operation\")     async def create_operation_api(self, operation: CreateOperationSchema) -&gt; Response:         return await self.post(             APIRoutes.OPERATIONS,             json=operation.model_dump(mode='json', by_alias=True)         )      @allure.step(\"Update operation by id {operation_id}\")     async def update_operation_api(             self,             operation_id: int,             operation: UpdateOperationSchema     ) -&gt; Response:         return await self.patch(             f\"{APIRoutes.OPERATIONS}\/{operation_id}\",             json=operation.model_dump(mode='json', by_alias=True, exclude_none=True)         )      @allure.step(\"Delete operation by id {operation_id}\")     async def delete_operation_api(self, operation_id: int) -&gt; Response:         return await self.delete(f\"{APIRoutes.OPERATIONS}\/{operation_id}\")      async def create_operation(self) -&gt; OperationSchema:         request = CreateOperationSchema()         response = await self.create_operation_api(request)         return OperationSchema.model_validate_json(response.text)   def get_operations_client(settings: Settings) -&gt; OperationsClient:     return OperationsClient(client=get_http_client(settings.fake_bank_http_client)) <\/code><\/pre>\n<ul>\n<li>\n<p>\u0412\u0441\u0435 \u043c\u0435\u0442\u043e\u0434\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0434\u0435\u043b\u0430\u044e\u0442 HTTP\u2011\u0437\u0430\u043f\u0440\u043e\u0441\u044b (<code>get_operations_api<\/code>, <code>get_operation_api<\/code>, <code>create_operation_api<\/code>, <code>update_operation_api<\/code>, <code>delete_operation_api<\/code>) \u0441\u0442\u0430\u043b\u0438 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u043c\u0438 \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442 <code>await<\/code> \u0434\u043b\u044f \u0432\u044b\u0437\u043e\u0432\u0430 \u0431\u0430\u0437\u043e\u0432\u044b\u0445 \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u043a\u043b\u0438\u0435\u043d\u0442\u0430.<\/p>\n<\/li>\n<li>\n<p>\u0412\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043c\u0435\u0442\u043e\u0434 <code>create_operation<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u043d\u0443\u0442\u0440\u0438 \u0441\u0435\u0431\u044f \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 API, \u0442\u0430\u043a\u0436\u0435 \u0441\u0442\u0430\u043b \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u043c \u0438 \u0436\u0434\u0451\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0441\u0435\u0442\u0435\u0432\u043e\u0433\u043e \u0432\u044b\u0437\u043e\u0432\u0430.<\/p>\n<\/li>\n<li>\n<p>\u0424\u0430\u0431\u0440\u0438\u043a\u0430 \u043a\u043b\u0438\u0435\u043d\u0442\u0430 <code>get_operations_client<\/code> \u043d\u0435 \u0438\u0437\u043c\u0435\u043d\u0438\u043b\u0430 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441, \u043d\u043e \u0442\u0435\u043f\u0435\u0440\u044c \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043a\u043b\u0438\u0435\u043d\u0442 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 <code>AsyncClient<\/code>.<\/p>\n<\/li>\n<\/ul>\n<p><strong>\u041a\u043b\u044e\u0447\u0435\u0432\u043e\u0439 \u043c\u043e\u043c\u0435\u043d\u0442:<\/strong> \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u0432 \u0442\u0435\u0441\u0442\u0430\u0445 \u043e\u0441\u0442\u0430\u0451\u0442\u0441\u044f \u043f\u043e\u0447\u0442\u0438 \u043f\u0440\u0435\u0436\u043d\u0438\u043c, \u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0442\u043e, \u0447\u0442\u043e \u0432\u0441\u0435 \u0432\u044b\u0437\u043e\u0432\u044b \u043d\u0443\u0436\u043d\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u0441 <code>await<\/code>. \u042d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043b\u0435\u0433\u043a\u043e \u043f\u0435\u0440\u0435\u0439\u0442\u0438 \u043d\u0430 \u043d\u043e\u0432\u044b\u0439 \u0440\u0435\u0436\u0438\u043c, \u043d\u0435 \u043c\u0435\u043d\u044f\u044f \u043e\u0431\u0449\u0443\u044e \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0443 \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u0433\u043e \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430.<\/p>\n<h3>\u0424\u0438\u043a\u0441\u0442\u0443\u0440\u044b<\/h3>\n<p>\u0422\u0430\u043a \u043a\u0430\u043a API\u2011\u043a\u043b\u0438\u0435\u043d\u0442 \u0442\u0435\u043f\u0435\u0440\u044c \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0430\u0434\u0430\u043f\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438 \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0435 \u0441 \u043d\u0438\u043c \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u044b. \u0412 \u043f\u0440\u043e\u0442\u0438\u0432\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0442\u0435\u0441\u0442\u044b \u043d\u0435 \u0441\u043c\u043e\u0433\u0443\u0442 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 <code>await<\/code>\u2011\u0432\u044b\u0437\u043e\u0432\u0430\u043c\u0438, \u0438 pytest \u0432\u044b\u0434\u0430\u0441\u0442 \u043e\u0448\u0438\u0431\u043a\u0443 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c, \u043a\u0430\u043a \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u044b, \u0447\u0442\u043e\u0431\u044b \u043e\u043d\u0438 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u043b\u0438 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0441\u0442\u044c.<\/p>\n<p><strong>\u0421\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f:<\/strong> <a href=\"https:\/\/github.com\/Nikita-Filonov\/python-api-tests\/blob\/main\/fixtures\/operations.py\" rel=\"noopener noreferrer nofollow\">\/fixtures\/operations.py<\/a><\/p>\n<pre><code class=\"python\">import pytest  from clients.operations_client import OperationsClient, get_operations_client from config import Settings from schema.operations import OperationSchema   @pytest.fixture def operations_client(settings: Settings) -&gt; OperationsClient:     return get_operations_client(settings)   @pytest.fixture def function_operation(operations_client: OperationsClient) -&gt; OperationSchema:     operation = operations_client.create_operation()     yield operation      operations_client.delete_operation_api(operation.id) <\/code><\/pre>\n<p><strong>\u0410\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f:<\/strong> <a href=\"https:\/\/github.com\/Nikita-Filonov\/python-api-tests-async\/blob\/main\/fixtures\/operations.py\" rel=\"noopener noreferrer nofollow\">\/fixtures\/operations.py<\/a><\/p>\n<pre><code class=\"python\">import pytest import pytest_asyncio  from clients.operations_client import OperationsClient, get_operations_client from config import Settings from schema.operations import OperationSchema   @pytest.fixture def operations_client(settings: Settings) -&gt; OperationsClient:     return get_operations_client(settings)   @pytest_asyncio.fixture async def function_operation(operations_client: OperationsClient) -&gt; OperationSchema:     operation = await operations_client.create_operation()     yield operation      await operations_client.delete_operation_api(operation.id) <\/code><\/pre>\n<p>\u041f\u043e\u0441\u043b\u0435 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0430 \u043d\u0430 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0435 API\u2011\u043a\u043b\u0438\u0435\u043d\u0442\u044b \u043d\u0430\u043c \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u043f\u043e\u0434\u0445\u043e\u0434 \u0438 \u043a \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u0430\u043c. \u0412 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u0430 <code>function_operation<\/code> \u0432\u044b\u0437\u044b\u0432\u0430\u043b\u0430 \u043c\u0435\u0442\u043e\u0434\u044b \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e, \u0438 \u0442\u0435\u0441\u0442\u044b \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u043b\u0438\u0441\u044c \u0432 \u043e\u0431\u044b\u0447\u043d\u043e\u043c \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u043c \u0440\u0435\u0436\u0438\u043c\u0435.<\/p>\n<p>\u0412 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u043d\u0435\u043c\u043d\u043e\u0433\u043e, \u043d\u043e \u043e\u043d\u0438 \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u0438\u0430\u043b\u044c\u043d\u044b:<\/p>\n<ul>\n<li>\n<p>\u0414\u043b\u044f \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u044b <code>function_operation<\/code> \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0434\u0435\u043a\u043e\u0440\u0430\u0442\u043e\u0440 <code>@pytest_asyncio.fixture<\/code> \u0432\u043c\u0435\u0441\u0442\u043e \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0433\u043e <code>@pytest.fixture<\/code>. \u042d\u0442\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u0441\u0430\u043c\u0430 \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u0430 \u0442\u0435\u043f\u0435\u0440\u044c \u043e\u0431\u044a\u044f\u0432\u043b\u0435\u043d\u0430 \u043a\u0430\u043a <code>async def<\/code> \u0438 \u0432\u043d\u0443\u0442\u0440\u0438 \u0441\u0435\u0431\u044f \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0435 \u043c\u0435\u0442\u043e\u0434\u044b \u043a\u043b\u0438\u0435\u043d\u0442\u0430.<\/p>\n<\/li>\n<li>\n<p>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0438 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0435 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u0442\u0435\u043f\u0435\u0440\u044c \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u044e\u0442\u0441\u044f \u0441 \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u043c \u0441\u043b\u043e\u0432\u043e\u043c <code>await<\/code>, \u0447\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043d\u0435 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u0442\u044c <a href=\"https:\/\/docs.python.org\/3\/library\/asyncio-eventloop.html\" rel=\"noopener noreferrer nofollow\">event loop<\/a>.<\/p>\n<\/li>\n<li>\n<p>\u0424\u0438\u043a\u0441\u0442\u0443\u0440\u0430 <code>operations_client<\/code> \u043e\u0441\u0442\u0430\u0451\u0442\u0441\u044f \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0439, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u043e\u043d\u0430 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0443\u0436\u0435 \u0433\u043e\u0442\u043e\u0432\u044b\u0439 \u043a\u043b\u0438\u0435\u043d\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0439 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438.<\/p>\n<\/li>\n<\/ul>\n<p><strong>\u041a\u043b\u044e\u0447\u0435\u0432\u0430\u044f \u0438\u0434\u0435\u044f: <\/strong>\u041c\u044b \u043d\u0435 \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u0432\u0441\u0435 \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u044b \u043f\u043e\u0434\u0440\u044f\u0434, \u0430 \u0442\u043e\u043b\u044c\u043a\u043e \u0442\u0435, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0443\u044e\u0442 \u0441 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u043c \u043a\u043e\u0434\u043e\u043c (\u0432 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0441 \u0432\u044b\u0437\u043e\u0432\u0430\u043c\u0438 API). \u0412\u0441\u0451 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u043e\u0435 \u043c\u043e\u0436\u0435\u0442 \u043e\u0441\u0442\u0430\u0432\u0430\u0442\u044c\u0441\u044f \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u043c, \u0447\u0442\u043e \u0443\u043f\u0440\u043e\u0449\u0430\u0435\u0442 \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u044e \u0438 \u0434\u0435\u043b\u0430\u0435\u0442 \u0435\u0451 \u043f\u043e\u0441\u0442\u0435\u043f\u0435\u043d\u043d\u043e\u0439.<\/p>\n<h3>\u0422\u0435\u0441\u0442\u044b<\/h3>\n<p>\u0422\u0430\u043a \u043a\u0430\u043a \u0442\u0435\u043f\u0435\u0440\u044c \u0438 \u043a\u043b\u0438\u0435\u043d\u0442, \u0438 \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u044b \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e, \u0442\u0435\u0441\u0442\u044b \u0442\u043e\u0436\u0435 \u043d\u0443\u0436\u043d\u043e \u0430\u0434\u0430\u043f\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c.<\/p>\n<p><strong>\u0421\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f:<\/strong> <a href=\"https:\/\/github.com\/Nikita-Filonov\/python-api-tests\/blob\/main\/tests\/test_operations.py\" rel=\"noopener noreferrer nofollow\">\/tests\/test_operations.py<\/a><\/p>\n<pre><code class=\"python\">from http import HTTPStatus  import allure import pytest  from clients.operations_client import OperationsClient from schema.operations import OperationsSchema, OperationSchema, CreateOperationSchema, UpdateOperationSchema from tools.assertions.base import assert_status_code from tools.assertions.operations import assert_operation, assert_create_operation from tools.assertions.schema import validate_json_schema   @pytest.mark.operations @pytest.mark.regression class TestOperations:     @allure.title(\"Get operations\")     def test_get_operations(self, operations_client: OperationsClient):         response = operations_client.get_operations_api()          assert_status_code(response.status_code, HTTPStatus.OK)         validate_json_schema(response.json(), OperationsSchema.model_json_schema())      @allure.title(\"Get operation\")     def test_get_operation(             self,             operations_client: OperationsClient,             function_operation: OperationSchema     ):         response = operations_client.get_operation_api(function_operation.id)         operation = OperationSchema.model_validate_json(response.text)          assert_status_code(response.status_code, HTTPStatus.OK)         assert_operation(operation, function_operation)          validate_json_schema(response.json(), operation.model_json_schema())      @allure.title(\"Create operation\")     def test_create_operation(self, operations_client: OperationsClient):         request = CreateOperationSchema()         response = operations_client.create_operation_api(request)         operation = OperationSchema.model_validate_json(response.text)          assert_status_code(response.status_code, HTTPStatus.CREATED)         assert_create_operation(operation, request)          validate_json_schema(response.json(), operation.model_json_schema())      @allure.title(\"Update operation\")     def test_update_operation(             self,             operations_client: OperationsClient,             function_operation: OperationSchema     ):         request = UpdateOperationSchema()         response = operations_client.update_operation_api(function_operation.id, request)         operation = OperationSchema.model_validate_json(response.text)          assert_status_code(response.status_code, HTTPStatus.OK)         assert_create_operation(operation, request)          validate_json_schema(response.json(), operation.model_json_schema())      @allure.title(\"Delete operation\")     def test_delete_operation(             self,             operations_client: OperationsClient,             function_operation: OperationSchema     ):         delete_response = operations_client.delete_operation_api(function_operation.id)         assert_status_code(delete_response.status_code, HTTPStatus.OK)          get_response = operations_client.get_operation_api(function_operation.id)         assert_status_code(get_response.status_code, HTTPStatus.NOT_FOUND) <\/code><\/pre>\n<p><strong>\u0410\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f:<\/strong> <a href=\"https:\/\/github.com\/Nikita-Filonov\/python-api-tests-async\/blob\/main\/tests\/test_operations.py\" rel=\"noopener noreferrer nofollow\">\/tests\/test_operations.py<\/a><\/p>\n<pre><code class=\"python\">from http import HTTPStatus  import allure import pytest  from clients.operations_client import OperationsClient from schema.operations import OperationsSchema, OperationSchema, CreateOperationSchema, UpdateOperationSchema from tools.assertions.base import assert_status_code from tools.assertions.operations import assert_operation, assert_create_operation from tools.assertions.schema import validate_json_schema   @pytest.mark.asyncio @pytest.mark.operations @pytest.mark.regression class TestOperations:     @allure.title(\"Get operations\")     async def test_get_operations(self, operations_client: OperationsClient):         response = await operations_client.get_operations_api()          assert_status_code(response.status_code, HTTPStatus.OK)         validate_json_schema(response.json(), OperationsSchema.model_json_schema())      @allure.title(\"Get operation\")     async def test_get_operation(             self,             operations_client: OperationsClient,             function_operation: OperationSchema     ):         response = await operations_client.get_operation_api(function_operation.id)         operation = OperationSchema.model_validate_json(response.text)          assert_status_code(response.status_code, HTTPStatus.OK)         assert_operation(operation, function_operation)          validate_json_schema(response.json(), operation.model_json_schema())      @allure.title(\"Create operation\")     async def test_create_operation(self, operations_client: OperationsClient):         request = CreateOperationSchema()         response = await operations_client.create_operation_api(request)         operation = OperationSchema.model_validate_json(response.text)          assert_status_code(response.status_code, HTTPStatus.CREATED)         assert_create_operation(operation, request)          validate_json_schema(response.json(), operation.model_json_schema())      @allure.title(\"Update operation\")     async def test_update_operation(             self,             operations_client: OperationsClient,             function_operation: OperationSchema     ):         request = UpdateOperationSchema()         response = await operations_client.update_operation_api(function_operation.id, request)         operation = OperationSchema.model_validate_json(response.text)          assert_status_code(response.status_code, HTTPStatus.OK)         assert_create_operation(operation, request)          validate_json_schema(response.json(), operation.model_json_schema())      @allure.title(\"Delete operation\")     async def test_delete_operation(             self,             operations_client: OperationsClient,             function_operation: OperationSchema     ):         delete_response = await operations_client.delete_operation_api(function_operation.id)         assert_status_code(delete_response.status_code, HTTPStatus.OK)          get_response = await operations_client.get_operation_api(function_operation.id)         assert_status_code(get_response.status_code, HTTPStatus.NOT_FOUND) <\/code><\/pre>\n<p>\u0413\u043b\u0430\u0432\u043d\u044b\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f:<\/p>\n<ol>\n<li>\n<p><strong>\u0410\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0442\u0435\u0441\u0442\u043e\u0432. <\/strong>\u041c\u0435\u0442\u043e\u0434\u044b \u043a\u043b\u0430\u0441\u0441\u0430 \u0442\u0435\u0441\u0442\u043e\u0432 \u0441\u0442\u0430\u043b\u0438 <code>async def<\/code>, \u0447\u0442\u043e\u0431\u044b \u0432\u043d\u0443\u0442\u0440\u0438 \u043d\u0438\u0445 \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043a\u043b\u044e\u0447\u0435\u0432\u043e\u0435 \u0441\u043b\u043e\u0432\u043e <code>await<\/code>. \u042d\u0442\u043e \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u0443\u0441\u043b\u043e\u0432\u0438\u0435: \u0431\u0435\u0437 \u043d\u0435\u0433\u043e \u043d\u0435\u043b\u044c\u0437\u044f \u0432\u044b\u0437\u0432\u0430\u0442\u044c \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0435 \u043c\u0435\u0442\u043e\u0434\u044b API\u2011\u043a\u043b\u0438\u0435\u043d\u0442\u0430 (<code>get_operations_api<\/code>, <code>create_operation_api<\/code> \u0438 \u0442.\u202f\u0434.).<\/p>\n<\/li>\n<li>\n<p><strong>\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043c\u0430\u0440\u043a\u0435\u0440\u0430 <\/strong><code><strong>@pytest.mark.asyncio<\/strong><\/code><strong>. <\/strong>\u042d\u0442\u043e\u0442 \u043c\u0430\u0440\u043a\u0435\u0440 \u0441\u043e\u043e\u0431\u0449\u0430\u0435\u0442 <a href=\"https:\/\/docs.pytest.org\/en\/stable\/\" rel=\"noopener noreferrer nofollow\">pytest<\/a>, \u0447\u0442\u043e \u0442\u0435\u0441\u0442 \u0434\u043e\u043b\u0436\u0435\u043d \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c\u0441\u044f \u0432 \u0441\u043e\u0431\u044b\u0442\u0438\u0439\u043d\u043e\u043c \u0446\u0438\u043a\u043b\u0435, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u043f\u043b\u0430\u0433\u0438\u043d <a href=\"https:\/\/github.com\/pytest-dev\/pytest-asyncio\" rel=\"noopener noreferrer nofollow\">pytest\u2011asyncio<\/a>. \u0411\u0435\u0437 \u043c\u0430\u0440\u043a\u0435\u0440\u0430 \u0442\u0435\u0441\u0442 \u0443\u043f\u0430\u0434\u0451\u0442 \u0441 \u043e\u0448\u0438\u0431\u043a\u043e\u0439 \u0432\u0438\u0434\u0430 \u00abRuntimeError: no running event loop\u00bb.<\/p>\n<\/li>\n<li>\n<p><strong>\u0410\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0435 \u0432\u044b\u0437\u043e\u0432\u044b API\u2011\u043a\u043b\u0438\u0435\u043d\u0442\u0430. <\/strong>\u0412\u0441\u0435 \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u043a \u043a\u043b\u0438\u0435\u043d\u0442\u0443 \u0442\u0435\u043f\u0435\u0440\u044c \u0441\u043e\u043f\u0440\u043e\u0432\u043e\u0436\u0434\u0430\u044e\u0442\u0441\u044f <code>await<\/code>, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u043c\u0435\u0442\u043e\u0434\u044b \u043a\u043b\u0438\u0435\u043d\u0442\u0430 (<code>get<\/code>, <code>post<\/code>, <code>patch<\/code>, <code>delete<\/code>) \u0438 \u0438\u0445 \u043e\u0431\u0451\u0440\u0442\u043a\u0438 \u0432 <code>OperationsClient<\/code> \u0441\u0442\u0430\u043b\u0438 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u043c\u0438. \u0421\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u043d\u0435 \u0431\u043b\u043e\u043a\u0438\u0440\u0443\u0435\u0442 <a href=\"https:\/\/docs.python.org\/3\/library\/asyncio-eventloop.html\" rel=\"noopener noreferrer nofollow\">event loop<\/a>, \u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b \u0432 \u043d\u0451\u043c \u043c\u043e\u0433\u0443\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c\u0441\u044f \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e.<\/p>\n<\/li>\n<li>\n<p><strong>\u041b\u043e\u0433\u0438\u043a\u0430 \u0442\u0435\u0441\u0442\u043e\u0432 \u043e\u0441\u0442\u0430\u043b\u0430\u0441\u044c \u043f\u0440\u0435\u0436\u043d\u0435\u0439. <\/strong>\u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043e\u0442\u0432\u0435\u0442\u043e\u0432 (<code>assert_status_code<\/code>, <code>validate_json_schema<\/code>, \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u0435 \u0441\u0445\u0435\u043c \u0438 \u0434\u0430\u043d\u043d\u044b\u0445) \u043d\u0435 \u0438\u0437\u043c\u0435\u043d\u0438\u043b\u0438\u0441\u044c \u2014 \u043e\u043d\u0438 \u043e\u0441\u0442\u0430\u044e\u0442\u0441\u044f \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u043c\u0438, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u044d\u0442\u043e \u043f\u0440\u043e\u0441\u0442\u043e \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u0432 \u043f\u0430\u043c\u044f\u0442\u0438. \u041c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0442\u043e, \u043a\u0430\u043a \u0432\u044b\u0437\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u043c\u0435\u0442\u043e\u0434\u044b \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u0438 \u043a\u0430\u043a \u0441\u0430\u043c \u0442\u0435\u0441\u0442 \u00ab\u043f\u043e\u0434\u0432\u0435\u0448\u0435\u043d\u00bb \u043a <a href=\"https:\/\/docs.python.org\/3\/library\/asyncio-eventloop.html\" rel=\"noopener noreferrer nofollow\">event loop<\/a>.<\/p>\n<\/li>\n<\/ol>\n<blockquote>\n<p><strong>\u0412\u0430\u0436\u043d\u043e:<\/strong> \u043a\u0430\u043a \u0438 \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u0441 UI\u2011\u0442\u0435\u0441\u0442\u0430\u043c\u0438, \u0432\u0440\u0435\u043c\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0442\u0435\u0441\u0442\u043e\u0432 \u043f\u0440\u0438 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0435 \u043d\u0430 <code>async\/await<\/code> \u043d\u0435 \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u0441\u044f \u00ab\u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u00bb. \u0410\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0441\u0442\u044c \u043d\u0443\u0436\u043d\u0430 \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u0442\u043e\u043c\u0443, \u0447\u0442\u043e \u0431\u0430\u0437\u043e\u0432\u044b\u0435 \u0432\u044b\u0437\u043e\u0432\u044b \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u0442\u0435\u043f\u0435\u0440\u044c \u0441\u0430\u043c\u0438 \u043f\u043e \u0441\u0435\u0431\u0435 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0435 (\u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442 \u0447\u0435\u0440\u0435\u0437 <a href=\"https:\/\/www.python-httpx.org\/async\/\" rel=\"noopener noreferrer nofollow\">httpx.AsyncClient<\/a>). \u0415\u0441\u043b\u0438 \u0431\u044b \u043a\u043b\u0438\u0435\u043d\u0442 \u043e\u0441\u0442\u0430\u0432\u0430\u043b\u0441\u044f \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u043c, \u043d\u0438\u043a\u0430\u043a\u043e\u0433\u043e \u0432\u044b\u0438\u0433\u0440\u044b\u0448\u0430 \u043f\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u043d\u0435 \u0431\u044b\u043b\u043e \u0431\u044b, \u0430 \u043d\u0430\u043e\u0431\u043e\u0440\u043e\u0442 \u2014 \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u043b\u0438 \u0431\u044b \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b (\u043d\u0435\u043b\u044c\u0437\u044f \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c \u0431\u043b\u043e\u043a\u0438\u0440\u0443\u044e\u0449\u0438\u0439 \u043a\u043e\u0434 \u0438\u0437 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0445 \u0442\u0435\u0441\u0442\u043e\u0432 \u0431\u0435\u0437 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u043e\u0431\u0451\u0440\u0442\u043e\u043a).<\/p>\n<\/blockquote>\n<h2>\u0414\u0435\u043b\u0430\u0435\u043c \u0432\u044b\u0432\u043e\u0434\u044b<\/h2>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c, \u043a\u043e\u0433\u0434\u0430 \u0443 \u043d\u0430\u0441 \u043f\u0435\u0440\u0435\u0434 \u0433\u043b\u0430\u0437\u0430\u043c\u0438 \u0435\u0441\u0442\u044c \u0434\u0432\u0430 \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u044b\u0445 \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u2014 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0435 \u0438 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0435 UI \u0438 API \u0442\u0435\u0441\u0442\u044b, \u2014 \u043c\u043e\u0436\u043d\u043e \u0442\u0440\u0435\u0437\u0432\u043e \u043e\u0446\u0435\u043d\u0438\u0442\u044c, \u0447\u0442\u043e \u0434\u0430\u0451\u0442 \u044d\u0442\u0430 \u00ab\u043c\u0430\u0433\u0438\u044f async\/await\u00bb \u043d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435.<\/p>\n<p>\u0421\u043a\u0430\u0436\u0443 \u0447\u0435\u0441\u0442\u043d\u043e: \u043d\u0438\u043a\u0430\u043a\u043e\u0433\u043e \u00ab\u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u043e\u0433\u043e \u0443\u0441\u043a\u043e\u0440\u0435\u043d\u0438\u044f\u00bb \u043c\u044b \u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438. \u042f \u043f\u0440\u043e\u0433\u043d\u0430\u043b \u043e\u0431\u0430 \u043d\u0430\u0431\u043e\u0440\u0430 \u0442\u0435\u0441\u0442\u043e\u0432 \u043d\u0430 CI\/CD, \u0438 \u043e\u043d\u0438 \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u043b\u0438\u0441\u044c \u0437\u0430 \u043e\u0434\u043d\u043e \u0438 \u0442\u043e \u0436\u0435 \u0432\u0440\u0435\u043c\u044f, \u0447\u0442\u043e \u0432 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0439, \u0447\u0442\u043e \u0432 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438. \u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0432 GitHub Actions:<\/p>\n<ul>\n<li>\n<p><a href=\"https:\/\/github.com\/Nikita-Filonov\/python-ui-tests\/actions\/runs\/16397820297\/job\/46332837242#step:5:86\" rel=\"noopener noreferrer nofollow\">\u041f\u0440\u043e\u0433\u043e\u043d \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0445 UI-\u0442\u0435\u0441\u0442\u043e\u0432:<\/a> 1 passed in 2.71s <\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/github.com\/Nikita-Filonov\/python-ui-tests-async\/actions\/runs\/16754371550\/job\/47432807902#step:5:87\" rel=\"noopener noreferrer nofollow\">\u041f\u0440\u043e\u0433\u043e\u043d \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0445 UI-\u0442\u0435\u0441\u0442\u043e\u0432:<\/a> 1 passed in 2.43s <\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/github.com\/Nikita-Filonov\/python-api-tests\/actions\/runs\/16399246680\/job\/46336253652#step:5:87\" rel=\"noopener noreferrer nofollow\">\u041f\u0440\u043e\u0433\u043e\u043d \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0445 API-\u0442\u0435\u0441\u0442\u043e\u0432:<\/a> 5 passed in 1.69s<\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/github.com\/Nikita-Filonov\/python-api-tests-async\/actions\/runs\/16753659441\/job\/47430266210#step:5:88\" rel=\"noopener noreferrer nofollow\">\u041f\u0440\u043e\u0433\u043e\u043d \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0445 API-\u0442\u0435\u0441\u0442\u043e\u0432:<\/a> 5 passed in 1.74s <\/p>\n<\/li>\n<\/ul>\n<h4>\u041f\u043e\u0447\u0435\u043c\u0443 \u0442\u0430\u043a?<\/h4>\n<p><a href=\"https:\/\/docs.python.org\/3\/library\/asyncio-task.html\" rel=\"noopener noreferrer nofollow\">Async\/await<\/a> \u2014 \u044d\u0442\u043e \u043d\u0435 \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0442\u0435\u0441\u0442\u043e\u0432. \u042d\u0442\u043e \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u043a\u043e\u043e\u043f\u0435\u0440\u0430\u0442\u0438\u0432\u043d\u043e\u0439 \u043c\u043d\u043e\u0433\u043e\u0437\u0430\u0434\u0430\u0447\u043d\u043e\u0441\u0442\u0438: \u043f\u043e\u043a\u0430 \u043e\u0434\u043d\u0430 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430 \u0436\u0434\u0451\u0442 <a href=\"https:\/\/en.wikipedia.org\/wiki\/I\/O_bound\" rel=\"noopener noreferrer nofollow\">I\/O<\/a> (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043e\u0442\u0432\u0435\u0442\u0430 \u043e\u0442 API), <a href=\"https:\/\/docs.python.org\/3\/library\/asyncio-eventloop.html\" rel=\"noopener noreferrer nofollow\">event loop<\/a> \u043c\u043e\u0436\u0435\u0442 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u043d\u0430 \u0434\u0440\u0443\u0433\u0443\u044e. \u041d\u043e \u0432\u0441\u0451 \u044d\u0442\u043e \u0432\u0441\u0451 \u0440\u0430\u0432\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 <strong>\u0432 \u043e\u0434\u043d\u043e\u043c \u043f\u043e\u0442\u043e\u043a\u0435<\/strong>, \u0430 Pytest \u043f\u043e \u0441\u0432\u043e\u0435\u0439 \u043f\u0440\u0438\u0440\u043e\u0434\u0435 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u0442\u0435\u0441\u0442\u044b \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e. \u0414\u0430\u0436\u0435 \u0435\u0441\u043b\u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043f\u043b\u0430\u0433\u0438\u043d\u044b, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0449\u0438\u0435 \u0433\u0440\u0443\u043f\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b \u0438 \u0438\u0441\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u0438\u0445 \u00ab\u043f\u0430\u043a\u0435\u0442\u0430\u043c\u0438\u00bb, \u0432\u0435\u0441\u044c \u043f\u0440\u043e\u0433\u043e\u043d \u043e\u0442 \u044d\u0442\u043e\u0433\u043e \u043d\u0435 \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u044b\u043c.<\/p>\n<p>\u041d\u0430 \u043f\u0435\u0440\u0432\u044b\u0439 \u0432\u0437\u0433\u043b\u044f\u0434 \u043a\u0430\u0436\u0435\u0442\u0441\u044f \u043b\u043e\u0433\u0438\u0447\u043d\u044b\u043c: <em>\u00ab\u041f\u0443\u0441\u0442\u044c \u0442\u0435\u0441\u0442\u044b \u0432 \u043c\u043e\u043c\u0435\u043d\u0442 \u043e\u0436\u0438\u0434\u0430\u043d\u0438\u044f \u043e\u0442\u0432\u0435\u0442\u0430 \u043e\u0442 \u043c\u0435\u0434\u043b\u0435\u043d\u043d\u043e\u0433\u043e \u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u044e\u0442 \u0434\u0440\u0443\u0433\u0438\u0435 \u0442\u0435\u0441\u0442\u044b\u00bb<\/em>. \u041d\u043e \u043d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435 \u044d\u0442\u043e \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u043f\u043e\u043b\u043d\u043e\u0439 \u043f\u0435\u0440\u0435\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430, \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u043f\u043b\u0430\u0433\u0438\u043d\u043e\u0432 \u0438 \u0436\u0438\u0437\u043d\u0438 \u0441 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f\u043c\u0438 \u043e\u0434\u043d\u043e\u0433\u043e <a href=\"https:\/\/docs.python.org\/3\/library\/asyncio-eventloop.html\" rel=\"noopener noreferrer nofollow\">event loop<\/a>. \u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u2014 \u0440\u043e\u0441\u0442 \u0447\u0438\u0441\u043b\u0430 \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0439, \u043d\u0435\u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u043e\u0441\u0442\u044c, \u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043e\u0442\u043b\u0430\u0434\u043a\u0438 \u0438 \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f. \u0412\u044b\u0438\u0433\u0440\u044b\u0448 (\u0435\u0441\u043b\u0438 \u043e\u043d \u0435\u0441\u0442\u044c) \u2014 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d \u0438 \u043f\u043e\u0447\u0442\u0438 \u043d\u0438\u043a\u043e\u0433\u0434\u0430 \u043d\u0435 \u043f\u0435\u0440\u0435\u043a\u0440\u044b\u0432\u0430\u0435\u0442 \u0441\u0442\u043e\u0438\u043c\u043e\u0441\u0442\u044c \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0438.<\/p>\n<p>\u0410 \u0435\u0441\u043b\u0438 \u043f\u043e\u0439\u0442\u0438 \u0435\u0449\u0451 \u0434\u0430\u043b\u044c\u0448\u0435 \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u043b\u0430\u0433\u0438\u043d\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0442\u0435\u0441\u0442\u043e\u0432 \u0432\u043d\u0443\u0442\u0440\u0438 \u043e\u0434\u043d\u043e\u0433\u043e <a href=\"https:\/\/docs.python.org\/3\/library\/asyncio-eventloop.html\" rel=\"noopener noreferrer nofollow\">event loop<\/a> (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, <a href=\"https:\/\/github.com\/czl9707\/pytest-asyncio-concurrent\" rel=\"noopener noreferrer nofollow\">pytest-asyncio-concurrent<\/a>), \u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u0441\u0442\u0440\u043e \u043e\u043a\u0430\u0437\u0430\u0442\u044c\u0441\u044f \u0432 \u0442\u0430\u043a \u043d\u0430\u0437\u044b\u0432\u0430\u0435\u043c\u043e\u043c <a href=\"https:\/\/ashnur.github.io\/async-hell\/\" rel=\"noopener noreferrer nofollow\"><em>async hell<\/em><\/a>. \u041a\u043e\u0433\u0434\u0430 \u0434\u0435\u0441\u044f\u0442\u043a\u0438 \u043a\u043e\u0440\u0443\u0442\u0438\u043d \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u0434\u0435\u0440\u0436\u0430\u0442 \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u0435 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f, \u043e\u0434\u043d\u043e \u043f\u043e\u0434\u0432\u0438\u0441\u0448\u0435\u0435 \u0438\u043b\u0438 \u043d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u043e\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0441\u043f\u043e\u0441\u043e\u0431\u043d\u043e \u00ab\u0437\u0430\u043c\u043e\u0440\u043e\u0437\u0438\u0442\u044c\u00bb \u0432\u0435\u0441\u044c \u043f\u043e\u0442\u043e\u043a. \u0414\u0438\u0430\u0433\u043d\u043e\u0441\u0442\u0438\u043a\u0430 \u043e\u0448\u0438\u0431\u043e\u043a \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u0432 \u043a\u043e\u0448\u043c\u0430\u0440, \u0430 \u043f\u0430\u0434\u0435\u043d\u0438\u0435 \u043e\u0434\u043d\u043e\u0439 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b \u043c\u043e\u0436\u0435\u0442 \u043e\u0431\u0440\u0443\u0448\u0438\u0442\u044c \u0432\u0441\u044e \u0433\u0440\u0443\u043f\u043f\u0443 \u0442\u0435\u0441\u0442\u043e\u0432 \u0441\u0440\u0430\u0437\u0443. <strong>\u0418\u0442\u043e\u0433:<\/strong> \u0440\u043e\u0441\u0442 \u043d\u0435\u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u0438 \u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0438, \u0430 \u0432\u044b\u0438\u0433\u0440\u044b\u0448 \u043f\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u043e\u0441\u0442\u0430\u0451\u0442\u0441\u044f \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u043c.<\/p>\n<h4>\u041a\u043e\u0433\u0434\u0430 async \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0443\u043c\u0435\u0441\u0442\u0435\u043d?<\/h4>\n<p>\u0422\u043e\u0433\u0434\u0430, \u043a\u043e\u0433\u0434\u0430 \u0432\u0430\u0448 \u0442\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u043c\u044b\u0439 \u043a\u043e\u0434 \u0438\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439: <a href=\"https:\/\/en.wikipedia.org\/wiki\/WebSocket\" rel=\"noopener noreferrer nofollow\">WebSocket<\/a>, <a href=\"https:\/\/grpc.io\/docs\/what-is-grpc\/core-concepts\/\" rel=\"noopener noreferrer nofollow\">gRPC streaming<\/a>, \u0441\u0432\u043e\u0439 <a href=\"https:\/\/docs.python.org\/3\/library\/asyncio-stream.html\" rel=\"noopener noreferrer nofollow\">asyncio-\u043a\u043b\u0438\u0435\u043d\u0442<\/a>, \u043a\u043e\u0433\u0434\u0430 \u0441\u0430\u043c\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0430\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0438\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0430 \u043d\u0430 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0439 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0435, \u0438\u043b\u0438 \u043a\u043e\u0433\u0434\u0430 \u043f\u0440\u043e\u0435\u043a\u0442 \u0441\u0430\u043c \u0436\u0438\u0432\u0451\u0442 \u0432 async-\u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0435. \u0412 \u0442\u0430\u043a\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043b\u043e\u0433\u0438\u0447\u043d\u043e \u043f\u0438\u0441\u0430\u0442\u044c \u0438 \u0442\u0435\u0441\u0442\u044b \u0432 \u0442\u043e\u043c \u0436\u0435 \u0441\u0442\u0438\u043b\u0435, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u0442\u044c <a href=\"https:\/\/docs.python.org\/3\/library\/asyncio-eventloop.html\" rel=\"noopener noreferrer nofollow\">event loop<\/a>. \u041d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c async \u00ab\u0440\u0430\u0434\u0438 \u0443\u0441\u043a\u043e\u0440\u0435\u043d\u0438\u044f\u00bb \u043d\u0430 \u043e\u0431\u044b\u0447\u043d\u044b\u0445 HTTP-\u0442\u0435\u0441\u0442\u0430\u0445 \u2014 \u044d\u0442\u043e \u0438\u043b\u043b\u044e\u0437\u0438\u044f \u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u043e\u0433\u043e \u043f\u0440\u0438\u0440\u043e\u0441\u0442\u0430.<\/p>\n<h4>\u0418\u0442\u043e\u0433\u043e<\/h4>\n<p>\u0415\u0441\u043b\u0438 \u0432\u0430\u0448\u0430 \u0446\u0435\u043b\u044c \u2014 \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u043f\u0440\u043e\u0433\u043e\u043d\u0430, \u0442\u043e async \u0432\u0430\u043c \u0435\u0451 \u043d\u0435 \u0434\u0430\u0441\u0442. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 \u043c\u043d\u043e\u0433\u043e\u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043d\u044b\u0439 \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u0438\u0437\u043c (<a href=\"https:\/\/github.com\/pytest-dev\/pytest-xdist\" rel=\"noopener noreferrer nofollow\">xdist<\/a>) \u0438\u043b\u0438 \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u0443\u0439\u0442\u0435 \u0441\u0430\u043c\u0438 \u0442\u0435\u0441\u0442\u044b \u0438 \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443. Async \u0432 \u0442\u0435\u0441\u0442\u0430\u0445 \u2014 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u0434\u043b\u044f \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u043e\u0441\u0442\u0438, \u0430 \u043d\u0435 \u0434\u043b\u044f \u0443\u0441\u043a\u043e\u0440\u0435\u043d\u0438\u044f.<\/p>\n<h2>\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/h2>\n<p>\u0410\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0441\u0442\u044c \u0432 \u0442\u0435\u0441\u0442\u0430\u0445 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043a\u0430\u043a \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0439 \u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442 \u0438 \u043c\u043e\u0436\u0435\u0442 \u043a\u0430\u0437\u0430\u0442\u044c\u0441\u044f \u00ab\u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u044b\u043c\u00bb \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u043c \u0443\u0441\u043a\u043e\u0440\u0438\u0442\u044c \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435. \u041d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435 \u044d\u0442\u043e \u043d\u0435 \u0442\u0430\u043a. \u0414\u0430, \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u0430\u0442\u044c UI \u0438 API \u0442\u0435\u0441\u0442\u044b \u043f\u043e\u0434 <a href=\"https:\/\/docs.python.org\/3\/library\/asyncio-task.html\" rel=\"noopener noreferrer nofollow\">async\/await<\/a>, \u0438 \u043e\u043d\u0438 \u0431\u0443\u0434\u0443\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e. \u041c\u044b \u0434\u0430\u0436\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u043f\u043b\u044e\u0441 \u0432 \u0442\u0435\u0445 \u0441\u043b\u0443\u0447\u0430\u044f\u0445, \u043a\u043e\u0433\u0434\u0430 \u0441\u0430\u043c \u043a\u043e\u0434, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u044b \u0442\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u043c, \u0438\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, <a href=\"https:\/\/websockets.readthedocs.io\/en\/stable\/\" rel=\"noopener noreferrer nofollow\">WebSocket-\u043a\u043b\u0438\u0435\u043d\u0442\u044b<\/a> \u0438\u043b\u0438 <a href=\"https:\/\/docs.python.org\/3\/library\/asyncio-stream.html\" rel=\"noopener noreferrer nofollow\">\u0441\u0442\u0440\u0438\u043c\u0438\u043d\u0433\u043e\u0432\u044b\u0435 API<\/a>). \u041d\u043e \u0432 \u043a\u043b\u0430\u0441\u0441\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u044f\u0445 \u2014 \u0432\u044b\u0437\u043e\u0432\u044b <a href=\"https:\/\/en.wikipedia.org\/wiki\/REST\" rel=\"noopener noreferrer nofollow\">REST API<\/a>, UI\u2011\u0442\u0435\u0441\u0442\u044b \u0447\u0435\u0440\u0435\u0437 Playwright \u2014 \u043f\u0440\u0438\u0440\u043e\u0441\u0442\u0430 \u043d\u0435\u0442.<\/p>\n<p>\u041f\u0440\u0438\u0447\u0438\u043d\u0430 \u043f\u0440\u043e\u0441\u0442\u0430: Pytest \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u0442\u0435\u0441\u0442\u044b \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e, \u0438 \u0434\u0430\u0436\u0435 \u0441 async\/await \u043e\u043d\u0438 \u0438\u0434\u0443\u0442 \u043e\u0434\u0438\u043d \u0437\u0430 \u0434\u0440\u0443\u0433\u0438\u043c. \u0427\u0442\u043e\u0431\u044b \u0440\u0435\u0430\u043b\u044c\u043d\u043e \u0443\u0441\u043a\u043e\u0440\u0438\u0442\u044c \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435, \u0447\u0430\u0449\u0435 \u0432\u0441\u0435\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442 <a href=\"https:\/\/github.com\/pytest-dev\/pytest-xdist\" rel=\"noopener noreferrer nofollow\">pytest-xdist<\/a>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0432\u043e\u0440\u043a\u0435\u0440\u043e\u0432 \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0445 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430\u0445 \u0438 \u0440\u0435\u0430\u043b\u044c\u043d\u043e \u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0443 \u043f\u043e <a href=\"https:\/\/ru.wikipedia.org\/wiki\/%D0%A6%D0%B5%D0%BD%D1%82%D1%80%D0%B0%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%BF%D1%80%D0%BE%D1%86%D0%B5%D1%81%D1%81%D0%BE%D1%80\" rel=\"noopener noreferrer nofollow\">\u044f\u0434\u0440\u0430\u043c \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440\u0430<\/a>.<\/p>\n<p>\u0410\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043e\u043f\u0440\u0430\u0432\u0434\u0430\u043d \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438 \u0442\u0430\u043a \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442 \u0432 async-\u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0435 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0432\u0435\u0441\u044c \u043a\u043e\u0434 \u043d\u0430 <a href=\"https:\/\/fastapi.tiangolo.com\/\" rel=\"noopener noreferrer nofollow\">FastAPI<\/a> \u0438\u043b\u0438 <a href=\"https:\/\/docs.aiohttp.org\/en\/stable\/\" rel=\"noopener noreferrer nofollow\">aiohttp<\/a>). \u0412 \u0442\u0430\u043a\u0438\u0445 \u0441\u043b\u0443\u0447\u0430\u044f\u0445 \u0442\u0435\u0441\u0442\u044b \u0431\u0443\u0434\u0443\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0435\u0441\u0442\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u0435\u0435, \u0430 \u043d\u0435 \u00ab\u043e\u0431\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0442\u044c \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0435 API \u0432 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0435 \u0432\u044b\u0437\u043e\u0432\u044b\u00bb. \u041d\u043e \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u044b\u0435 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0435 \u0442\u0435\u0441\u0442\u044b \u043d\u0430 async \u0442\u043e\u043b\u044c\u043a\u043e \u0440\u0430\u0434\u0438 \u0433\u0438\u043f\u043e\u0442\u0435\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u0443\u0441\u043a\u043e\u0440\u0435\u043d\u0438\u044f \u2014 \u0437\u0430\u0442\u0435\u044f \u0441\u043e\u043c\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u0430\u044f.<\/p>\n<p>\u0412 \u044d\u0442\u043e\u043c \u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u0435 \u043c\u044b \u043f\u043e\u043a\u0430\u0437\u0430\u043b\u0438:<\/p>\n<ul>\n<li>\n<p>\u043a\u0430\u043a \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u0430\u0442\u044c \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0439 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u043d\u0430 async\/await;<\/p>\n<\/li>\n<li>\n<p>\u0447\u0442\u043e \u044d\u0442\u043e \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0438 \u0438\u043d\u0442\u0435\u0433\u0440\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0441 <a href=\"https:\/\/docs.pytest.org\/en\/stable\/\" rel=\"noopener noreferrer nofollow\">Pytest<\/a> \u0438 <a href=\"https:\/\/allurereport.org\/\" rel=\"noopener noreferrer nofollow\">Allure<\/a>;<\/p>\n<\/li>\n<li>\n<p>\u0447\u0442\u043e \u0431\u0435\u0437 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043f\u0430\u0440\u0430\u0434\u0438\u0433\u043c\u044b \u0437\u0430\u043f\u0443\u0441\u043a\u0430 (<a href=\"https:\/\/github.com\/pytest-dev\/pytest-xdist\" rel=\"noopener noreferrer nofollow\">xdist<\/a>, <a href=\"https:\/\/github.com\/czl9707\/pytest-asyncio-concurrent\" rel=\"noopener noreferrer nofollow\">event-loop batching<\/a>) \u0443\u0441\u043a\u043e\u0440\u0435\u043d\u0438\u044f \u043d\u0435 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442.<\/p>\n<\/li>\n<\/ul>\n<p><strong>\u0418\u0442\u043e\u0433:<\/strong> <a href=\"https:\/\/docs.python.org\/3\/library\/asyncio-task.html\" rel=\"noopener noreferrer nofollow\">async\/await<\/a> \u0432 \u0442\u0435\u0441\u0442\u0430\u0445 \u2014 \u044d\u0442\u043e \u043d\u0435 \u0432\u043e\u043b\u0448\u0435\u0431\u043d\u0430\u044f \u043a\u043d\u043e\u043f\u043a\u0430 \u00ab\u0443\u0441\u043a\u043e\u0440\u0438\u0442\u044c \u0432\u0441\u0451\u00bb. \u042d\u0442\u043e \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u0434\u043b\u044f \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0437\u0430\u0434\u0430\u0447, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0438\u043c\u0435\u0435\u0442 \u0441\u043c\u044b\u0441\u043b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c, \u043a\u043e\u0433\u0434\u0430 \u0442\u043e\u0433\u043e \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430, \u0430 \u043d\u0435 \u0440\u0430\u0434\u0438 \u00ab\u043f\u043e\u043f\u0440\u043e\u0431\u043e\u0432\u0430\u0442\u044c \u043c\u043e\u0434\u043d\u044b\u0439 \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441\u00bb.<\/p>\n<p>\u0412\u0441\u0435 \u043f\u0440\u0438\u043c\u0435\u0440\u044b \u043a\u043e\u0434\u0430 \u0438 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u043f\u0440\u043e\u0433\u043e\u043d\u043e\u0432 CI\/CD \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b \u043d\u0430 \u043c\u043e\u0451\u043c GitHub:<\/p>\n<ul>\n<li>\n<p><a href=\"https:\/\/github.com\/Nikita-Filonov\/python-ui-tests\" rel=\"noopener noreferrer nofollow\">\u041f\u0440\u043e\u0435\u043a\u0442 \u0441 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u043c\u0438 UI \u0430\u0432\u0442\u043e\u0442\u0435\u0441\u0442\u0430\u043c\u0438<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/github.com\/Nikita-Filonov\/python-ui-tests-async\" rel=\"noopener noreferrer nofollow\">\u041f\u0440\u043e\u0435\u043a\u0442 \u0441 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u043c\u0438 UI \u0430\u0432\u0442\u043e\u0442\u0435\u0441\u0442\u0430\u043c\u0438<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/github.com\/Nikita-Filonov\/python-api-tests\" rel=\"noopener noreferrer nofollow\">\u041f\u0440\u043e\u0435\u043a\u0442 \u0441 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u043c\u0438 API \u0430\u0432\u0442\u043e\u0442\u0435\u0441\u0442\u0430\u043c\u0438<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/github.com\/Nikita-Filonov\/python-api-tests-async\" rel=\"noopener noreferrer nofollow\">\u041f\u0440\u043e\u0435\u043a\u0442 \u0441 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u043c\u0438 API \u0430\u0432\u0442\u043e\u0442\u0435\u0441\u0442\u0430\u043c\u0438<\/a><\/p>\n<\/li>\n<\/ul>\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\/933652\/\"> https:\/\/habr.com\/ru\/articles\/933652\/<\/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<h2>\u0412\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u0435<\/h2>\n<p>\u0418\u043d\u043e\u0433\u0434\u0430 \u043a\u0430\u0436\u0435\u0442\u0441\u044f, \u0447\u0442\u043e \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 <a href=\"https:\/\/docs.python.org\/3\/library\/asyncio-task.html\" rel=\"noopener noreferrer nofollow\">async\/await<\/a> \u0432 \u0442\u0435\u0441\u0442\u044b \u2014 \u044d\u0442\u043e \u043f\u043e\u0447\u0442\u0438 \u00ab\u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u044b\u0439 \u0441\u043f\u043e\u0441\u043e\u0431\u00bb \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0438\u0445 \u0431\u044b\u0441\u0442\u0440\u0435\u0435. \u041c\u044b \u0432\u0435\u0434\u044c \u0437\u043d\u0430\u0435\u043c, \u0447\u0442\u043e \u0442\u0435\u0441\u0442\u044b \u0447\u0430\u0441\u0442\u043e \u0442\u0440\u0430\u0442\u044f\u0442 \u0432\u0440\u0435\u043c\u044f \u043d\u0430 \u043e\u0436\u0438\u0434\u0430\u043d\u0438\u0435 \u043e\u0442\u0432\u0435\u0442\u043e\u0432 \u043e\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u0432 \u0438\u043b\u0438 UI\u2011\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439, \u0438 \u0432 \u0433\u043e\u043b\u043e\u0432\u0443 \u0441\u0440\u0430\u0437\u0443 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442 \u043c\u044b\u0441\u043b\u044c: \u00ab\u0410 \u0447\u0442\u043e, \u0435\u0441\u043b\u0438 \u043f\u043e\u043a\u0430 \u043e\u0434\u0438\u043d \u0442\u0435\u0441\u0442 \u0436\u0434\u0451\u0442 \u043e\u0442\u0432\u0435\u0442\u0430, \u0434\u0440\u0443\u0433\u043e\u0439 \u043d\u0430\u0447\u043d\u0451\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c\u0441\u044f?\u00bb \u041a\u0430\u0436\u0435\u0442\u0441\u044f \u043b\u043e\u0433\u0438\u0447\u043d\u044b\u043c, \u0447\u0442\u043e \u0442\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u0441\u044d\u043a\u043e\u043d\u043e\u043c\u0438\u0442\u044c \u043c\u0438\u043d\u0443\u0442\u044b, \u0430 \u0442\u043e \u0438 \u0434\u0435\u0441\u044f\u0442\u043a\u0438 \u043c\u0438\u043d\u0443\u0442 \u043f\u0440\u043e\u0433\u043e\u043d\u0430.<\/p>\n<p>\u041d\u043e \u043d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435 \u0432\u0441\u0451 \u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043d\u0435 \u0442\u0430\u043a \u043e\u0434\u043d\u043e\u0437\u043d\u0430\u0447\u043d\u043e. \u0410\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0441\u0442\u044c \u2014 \u044d\u0442\u043e \u043d\u0435 \u043c\u0430\u0433\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u043a\u043d\u043e\u043f\u043a\u0430, \u0434\u0435\u043b\u0430\u044e\u0449\u0430\u044f \u0442\u0435\u0441\u0442\u044b \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u044b\u043c\u0438 \u00ab\u043f\u043e \u0449\u0435\u043b\u0447\u043a\u0443\u00bb. <a href=\"https:\/\/docs.python.org\/3\/library\/asyncio-task.html\" rel=\"noopener noreferrer nofollow\">async\/await<\/a> \u0432 Python \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0432\u043d\u0443\u0442\u0440\u0438 \u043e\u0434\u043d\u043e\u0433\u043e \u043f\u043e\u0442\u043e\u043a\u0430 \u0438 \u043d\u0435 \u0441\u043e\u0437\u0434\u0430\u0451\u0442 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u0438\u0437\u043c\u0430. \u0414\u0430, \u043c\u043e\u0436\u043d\u043e \u0432\u044b\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b \u0442\u0430\u043a, \u0447\u0442\u043e \u043f\u043e\u043a\u0430 \u043e\u0434\u043d\u0430 \u0436\u0434\u0451\u0442 \u043e\u0442\u0432\u0435\u0442\u0430, \u0434\u0440\u0443\u0433\u0430\u044f \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c\u0441\u044f, \u0438 \u043d\u0430 \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u0438\u0445 \u0438\u0437\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u043f\u0440\u0438\u043c\u0435\u0440\u0430\u0445 \u044d\u0442\u043e \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0432\u043f\u0435\u0447\u0430\u0442\u043b\u044f\u044e\u0449\u0435. \u041d\u043e \u0432 \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445 \u0432\u0441\u0451 \u0441\u043b\u043e\u0436\u043d\u0435\u0435: \u043d\u0443\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u044b, \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b, \u043a\u043b\u0438\u0435\u043d\u0442\u044b, \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0442\u044c \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0435 \u0432\u0435\u0440\u0441\u0438\u0438 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a \u0438 \u043e\u0442\u043b\u0430\u0432\u043b\u0438\u0432\u0430\u0442\u044c \u043e\u0448\u0438\u0431\u043a\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0440\u0438 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u043c \u043f\u043e\u0434\u0445\u043e\u0434\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u043d\u0435 \u0432\u043e\u0437\u043d\u0438\u043a\u043b\u0438 \u0431\u044b.<\/p>\n<p>\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u0440\u0430\u0437\u0431\u0435\u0440\u0451\u043c, \u043a\u0430\u043a \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u044b\u0432\u0430\u043d\u0438\u0435 \u0430\u0432\u0442\u043e\u0442\u0435\u0441\u0442\u043e\u0432 \u043d\u0430 <a href=\"https:\/\/docs.python.org\/3\/library\/asyncio-task.html\" rel=\"noopener noreferrer nofollow\">async\/await<\/a>, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f <a href=\"https:\/\/www.python.org\/\" rel=\"noopener noreferrer nofollow\">Python<\/a> \u0438 <a href=\"https:\/\/docs.pytest.org\/en\/stable\/\" rel=\"noopener noreferrer nofollow\">Pytest<\/a>. \u0414\u043b\u044f UI \u0442\u0435\u0441\u0442\u043e\u0432 \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <a href=\"https:\/\/playwright.dev\/python\/\" rel=\"noopener noreferrer nofollow\">Playwright<\/a>, \u0434\u043b\u044f API \u2014 <a href=\"https:\/\/www.python-httpx.org\/\" rel=\"noopener noreferrer nofollow\">HTTPX<\/a>. \u041c\u044b \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c, \u043a\u0430\u043a\u0438\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043d\u0443\u0436\u043d\u043e \u0432\u043d\u043e\u0441\u0438\u0442\u044c \u0432 \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0439 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a, \u0447\u0442\u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0441 PageObject \u0438 API\u2011\u043a\u043b\u0438\u0435\u043d\u0442\u0430\u043c\u0438, \u043a\u0430\u043a \u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0442\u0435\u0441\u0442\u043e\u0432 \u0438 \u0444\u0438\u043a\u0441\u0442\u0443\u0440. \u0418 \u0447\u0442\u043e \u0432\u0430\u0436\u043d\u0435\u0435 \u2014 \u043c\u044b \u043e\u0431\u0441\u0443\u0434\u0438\u043c, \u043a\u043e\u0433\u0434\u0430 \u0442\u0430\u043a\u043e\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u0438\u043c\u0435\u0435\u0442 \u0441\u043c\u044b\u0441\u043b, \u0430 \u043a\u043e\u0433\u0434\u0430 \u043e\u043d \u0441\u043a\u043e\u0440\u0435\u0435 \u0441\u043e\u0437\u0434\u0430\u0451\u0442 \u043b\u0438\u0448\u043d\u0438\u0435 \u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u0438, \u0447\u0435\u043c \u0434\u0430\u0451\u0442 \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0439 \u0432\u044b\u0438\u0433\u0440\u044b\u0448.<\/p>\n<blockquote>\n<p>\u041e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u043e\u0442\u043c\u0435\u0447\u0443: \u0446\u0435\u043b\u044c \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0438 \u2014 \u043d\u0435 \u043f\u0440\u0438\u0437\u044b\u0432\u0430\u0442\u044c \u043a \u043c\u0430\u0441\u0441\u043e\u0432\u043e\u043c\u0443 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0443 \u043d\u0430 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0435 \u0442\u0435\u0441\u0442\u044b, \u0430 \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c, <strong>\u043a\u0430\u043a \u044d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c<\/strong> \u0438 <strong>\u0437\u0430\u0447\u0435\u043c \u0438\u043d\u043e\u0433\u0434\u0430 \u044d\u0442\u043e \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043d\u0443\u0436\u043d\u043e<\/strong>. \u041c\u044b \u043d\u0435 \u0431\u0443\u0434\u0435\u043c \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e \u043f\u043e\u0432\u0442\u043e\u0440\u044f\u0442\u044c \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u0433\u043e \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430 \u0441 \u043d\u0443\u043b\u044f (\u044d\u0442\u043e\u0442 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b \u0443\u0436\u0435 \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u043d \u0432 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u0445 \u0441\u0442\u0430\u0442\u044c\u044f\u0445), \u0430 \u0441\u043e\u0441\u0440\u0435\u0434\u043e\u0442\u043e\u0447\u0438\u043c\u0441\u044f \u043d\u0430 \u043e\u0442\u043b\u0438\u0447\u0438\u044f\u0445 \u043c\u0435\u0436\u0434\u0443 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0439 \u0438 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0435\u0439. <\/p>\n<\/blockquote>\n<p>\u0421\u0441\u044b\u043b\u043a\u0438 \u043d\u0430 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u044b \u0441 \u0431\u0430\u0437\u043e\u0432\u043e\u0439 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u043e\u0439 \u044f \u043e\u0441\u0442\u0430\u0432\u043b\u044e \u043d\u0438\u0436\u0435, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u0438 \u0436\u0435\u043b\u0430\u043d\u0438\u0438 \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u043f\u043e\u0433\u0440\u0443\u0437\u0438\u0442\u044c\u0441\u044f \u0432 \u0434\u0435\u0442\u0430\u043b\u0438:<\/p>\n<ul>\n<li>\n<p><a href=\"https:\/\/habr.com\/ru\/articles\/896936\/\" rel=\"noopener noreferrer nofollow\">UI \u0430\u0432\u0442\u043e\u0442\u0435\u0441\u0442\u044b \u043d\u0430 Python \u0441 \u0437\u0430\u043f\u0443\u0441\u043a\u043e\u043c \u043d\u0430 CI\/CD \u0438 Allure \u043e\u0442\u0447\u0435\u0442\u043e\u043c. PageObject, PageComponent, PageFactory<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/habr.com\/ru\/articles\/895452\/\" rel=\"noopener noreferrer nofollow\">API \u0430\u0432\u0442\u043e\u0442\u0435\u0441\u0442\u044b \u043d\u0430 Python \u0441 \u0437\u0430\u043f\u0443\u0441\u043a\u043e\u043c \u043d\u0430 CI\/CD \u0438 Allure \u043e\u0442\u0447\u0435\u0442\u043e\u043c<\/a><\/p>\n<\/li>\n<\/ul>\n<h2>\u0422\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0438<\/h2>\n<p>\u0414\u043b\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0445 \u0442\u0435\u0441\u0442\u043e\u0432 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u0438\u0432\u044b\u0447\u043d\u044b\u0435 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438 \u0432 \u043e\u0431\u044b\u0447\u043d\u044b\u0445 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0445 \u0442\u0435\u0441\u0442\u0430\u0445 \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u044e\u0442\u0441\u044f \u0435\u0436\u0435\u0434\u043d\u0435\u0432\u043d\u043e. \u041e\u0441\u043d\u043e\u0432\u043e\u0439, \u043a\u0430\u043a \u0438 \u043f\u0440\u0435\u0436\u0434\u0435, \u043e\u0441\u0442\u0430\u0451\u0442\u0441\u044f <a href=\"https:\/\/docs.pytest.org\/en\/stable\/\" rel=\"noopener noreferrer nofollow\">pytest<\/a> \u2014 \u043e\u043d \u0443\u0434\u043e\u0431\u0435\u043d, \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u044b, \u0440\u0430\u0441\u0448\u0438\u0440\u044f\u0435\u043c\u043e\u0441\u0442\u044c \u0438 \u0433\u0438\u0431\u043a\u0443\u044e \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446\u0438\u044e \u0442\u0435\u0441\u0442\u043e\u0432. \u0427\u0442\u043e\u0431\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0443 <a href=\"https:\/\/docs.python.org\/3\/library\/asyncio-task.html\" rel=\"noopener noreferrer nofollow\">async\/await<\/a>, \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u043f\u043b\u0430\u0433\u0438\u043d <a href=\"https:\/\/github.com\/pytest-dev\/pytest-asyncio\" rel=\"noopener noreferrer nofollow\">pytest-asyncio<\/a>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0443\u043c\u0435\u0435\u0442 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043a\u0430\u043a \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b \u0438 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u043c <a href=\"https:\/\/docs.python.org\/3\/library\/asyncio-eventloop.html\" rel=\"noopener noreferrer nofollow\">event loop<\/a> \u0432\u043d\u0443\u0442\u0440\u0438 Pytest.<\/p>\n<p>\u0414\u043b\u044f UI \u0442\u0435\u0441\u0442\u043e\u0432 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c Playwright. \u042d\u0442\u043e\u0442 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u0438\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043b\u0441\u044f \u0441 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u043e\u0439 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0433\u043e API, \u0447\u0442\u043e \u0443\u043f\u0440\u043e\u0449\u0430\u0435\u0442 \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u044e: \u0432\u043c\u0435\u0441\u0442\u043e \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0445 \u0432\u044b\u0437\u043e\u0432\u043e\u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430 \u0438 \u0441\u0442\u0440\u0430\u043d\u0438\u0446 (<a href=\"https:\/\/github.com\/microsoft\/playwright-python\/tree\/main\/playwright\/sync_api\" rel=\"noopener noreferrer nofollow\">playwright.sync_api<\/a>) \u043c\u044b \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u043c \u043d\u0430 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u0443\u044e \u0432\u0435\u0440\u0441\u0438\u044e (<a href=\"https:\/\/github.com\/microsoft\/playwright-python\/tree\/main\/playwright\/async_api\" rel=\"noopener noreferrer nofollow\">playwright.async_api<\/a>). \u0424\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438, \u044d\u0442\u043e \u043d\u0435 \u00ab\u0445\u0430\u043a\u0438\u00bb \u0438 \u043d\u0435 \u00ab\u043e\u0431\u0445\u043e\u0434\u043d\u044b\u0435 \u043f\u0443\u0442\u0438\u00bb, \u0430 \u0448\u0442\u0430\u0442\u043d\u044b\u0439 \u0441\u043f\u043e\u0441\u043e\u0431 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 Playwright.<\/p>\n<p>\u0414\u043b\u044f API \u0430\u0432\u0442\u043e\u0442\u0435\u0441\u0442\u043e\u0432 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 HTTPX, \u0443 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0443\u0436\u0435 \u0435\u0441\u0442\u044c \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u0430\u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0447\u0435\u0440\u0435\u0437 <a href=\"https:\/\/www.python-httpx.org\/async\/\" rel=\"noopener noreferrer nofollow\">AsyncClient<\/a>. \u042d\u0442\u043e \u0443\u043f\u0440\u043e\u0449\u0430\u0435\u0442 \u0437\u0430\u0434\u0430\u0447\u0443: \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u044b\u0432\u0430\u043d\u0438\u0435 \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u0441\u0432\u043e\u0434\u0438\u0442\u0441\u044f \u043a \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044e <code>async<\/code> \u0438 <code>await<\/code> \u0432 \u043c\u0435\u0442\u043e\u0434\u044b, \u0431\u0435\u0437 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0433\u043e\u0440\u043e\u0434\u0438\u0442\u044c \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u043e\u0431\u0451\u0440\u0442\u043a\u0438 \u0438\u043b\u0438 \u043f\u043e\u0434\u043c\u0435\u043d\u044f\u0442\u044c \u043d\u0438\u0437\u043a\u043e\u0443\u0440\u043e\u0432\u043d\u0435\u0432\u044b\u0439 \u0442\u0440\u0430\u043d\u0441\u043f\u043e\u0440\u0442.<\/p>\n<p>\u041e\u0441\u0442\u0430\u043b\u044c\u043d\u0430\u044f \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u0442\u0435\u0441\u0442\u043e\u0432 (\u0444\u0438\u043a\u0441\u0442\u0443\u0440\u044b, PageObject, \u043b\u043e\u0433\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435, \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u044f \u0441\u0445\u0435\u043c) \u043e\u0441\u0442\u0430\u0451\u0442\u0441\u044f \u043f\u0440\u0435\u0436\u043d\u0435\u0439. \u0415\u0441\u043b\u0438 \u0432\u044b \u0443\u0436\u0435 \u0437\u043d\u0430\u043a\u043e\u043c\u044b \u0441 \u043c\u043e\u0438\u043c\u0438 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u043c\u0438 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u0430\u043c\u0438 \u043f\u043e \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u044e \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430, \u0442\u043e \u0443\u0432\u0438\u0434\u0438\u0442\u0435, \u0447\u0442\u043e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043e\u0441\u0442\u0430\u0451\u0442\u0441\u044f \u043f\u0440\u0438\u0432\u044b\u0447\u043d\u043e\u0439 \u2014 \u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u043b\u0438\u0448\u044c \u0441\u043f\u043e\u0441\u043e\u0431 \u0432\u044b\u0437\u043e\u0432\u0430 \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u0438 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u043c\u0438 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430\u043c\u0438.<\/p>\n<p>\u041f\u043e\u0434\u0440\u043e\u0431\u043d\u043e \u0441\u0430\u043c \u043f\u043e\u0434\u0445\u043e\u0434 \u043a \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u044e UI \u0438 API \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u0432 \u043c\u044b \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u043b\u0438 \u0440\u0430\u043d\u0435\u0435:<\/p>\n<ul>\n<li>\n<p><a href=\"https:\/\/habr.com\/ru\/articles\/896936\/\" rel=\"noopener noreferrer nofollow\">UI \u0430\u0432\u0442\u043e\u0442\u0435\u0441\u0442\u044b \u043d\u0430 Python \u0441 \u0437\u0430\u043f\u0443\u0441\u043a\u043e\u043c \u043d\u0430 CI\/CD \u0438 Allure \u043e\u0442\u0447\u0435\u0442\u043e\u043c. PageObject, PageComponent, PageFactory<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/habr.com\/ru\/articles\/895452\/\" rel=\"noopener noreferrer nofollow\">API \u0430\u0432\u0442\u043e\u0442\u0435\u0441\u0442\u044b \u043d\u0430 Python \u0441 \u0437\u0430\u043f\u0443\u0441\u043a\u043e\u043c \u043d\u0430 CI\/CD \u0438 Allure \u043e\u0442\u0447\u0435\u0442\u043e\u043c<\/a><\/p>\n<\/li>\n<\/ul>\n<h2>UI \u0430\u0432\u0442\u043e\u0442\u0435\u0441\u0442\u044b<\/h2>\n<p>\u041d\u0430\u0447\u043d\u0451\u043c \u0441 UI \u0442\u0435\u0441\u0442\u043e\u0432 \u0438 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c, \u043a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439 \u043a\u043e\u0434 \u0432 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439.<\/p>\n<p>Playwright \u0432 \u044d\u0442\u043e\u043c \u043f\u043b\u0430\u043d\u0435 \u0441\u0438\u043b\u044c\u043d\u043e \u0443\u043f\u0440\u043e\u0449\u0430\u0435\u0442 \u0437\u0430\u0434\u0430\u0447\u0443: \u0438\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e \u043e\u043d \u0441\u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d \u043a\u0430\u043a \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u0430\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430, \u0438 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044f (<a href=\"https:\/\/github.com\/microsoft\/playwright-python\/tree\/main\/playwright\/sync_api\" rel=\"noopener noreferrer nofollow\">playwright.sync_api<\/a>) \u2014 \u044d\u0442\u043e \u0441\u043a\u043e\u0440\u0435\u0435 \u043e\u0431\u0451\u0440\u0442\u043a\u0430 \u043d\u0430\u0434 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u043c \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u043c API. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u0435\u0440\u0435\u0445\u043e\u0434 \u043a <a href=\"https:\/\/docs.python.org\/3\/library\/asyncio-task.html\" rel=\"noopener noreferrer nofollow\">async\/await<\/a> \u043d\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0440\u0430\u0434\u0438\u043a\u0430\u043b\u044c\u043d\u043e\u0439 \u043f\u0435\u0440\u0435\u0434\u0435\u043b\u043a\u0438 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430: \u0432\u044b \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0435\u0441\u044c \u043d\u0430 \u0434\u0440\u0443\u0433\u043e\u0439 \u043c\u043e\u0434\u0443\u043b\u044c (<a href=\"https:\/\/github.com\/microsoft\/playwright-python\/tree\/main\/playwright\/async_api\" rel=\"noopener noreferrer nofollow\">playwright.async_api<\/a>) \u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442\u0435 \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u0441\u043b\u043e\u0432\u0430 <code>async<\/code> \u0438 <code>await<\/code> \u0432 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u043c\u0435\u0441\u0442\u0430\u0445.<\/p>\n<p>\u041d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435 \u044d\u0442\u043e \u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442, \u0447\u0442\u043e \u043e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0442\u0435\u0441\u0442\u043e\u0432 \u043e\u0441\u0442\u0430\u0451\u0442\u0441\u044f \u043f\u0440\u0435\u0436\u043d\u0435\u0439: \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u044b, PageObject \u0438 PageComponent \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u044e\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u043f\u043e \u0442\u0435\u043c \u0436\u0435 \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u0430\u043c, \u043f\u0440\u043e\u0441\u0442\u043e \u0441\u0442\u0430\u043d\u043e\u0432\u044f\u0442\u0441\u044f \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u043c\u0438. \u042d\u0442\u043e\u0442 \u043c\u043e\u043c\u0435\u043d\u0442 \u0432\u0430\u0436\u0435\u043d, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u043c\u043d\u043e\u0433\u0438\u0435 \u043e\u0436\u0438\u0434\u0430\u044e\u0442, \u0447\u0442\u043e \u043f\u0440\u0438\u0434\u0451\u0442\u0441\u044f \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u00ab\u0432\u0441\u0451 \u0438 \u0441\u0440\u0430\u0437\u0443\u00bb. \u041d\u0430 \u0441\u0430\u043c\u043e\u043c \u0434\u0435\u043b\u0435 \u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u043f\u043e\u0441\u043e\u0431 \u0432\u044b\u0437\u043e\u0432\u0430 \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430 \u0438 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441\u043e \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430\u043c\u0438.<\/p>\n<p>\u041f\u043e\u043b\u043d\u044b\u0435 \u043f\u0440\u0438\u043c\u0435\u0440\u044b \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 UI \u0442\u0435\u0441\u0442\u043e\u0432 \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043d\u0430\u0439\u0442\u0438 \u0432 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f\u0445:<\/p>\n<ul>\n<li>\n<p>\u0421\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f: <a href=\"https:\/\/github.com\/Nikita-Filonov\/python-ui-tests\" rel=\"noopener noreferrer nofollow\">python-ui-tests<\/a><\/p>\n<\/li>\n<li>\n<p>\u0410\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f: <a href=\"https:\/\/github.com\/Nikita-Filonov\/python-ui-tests-async\" rel=\"noopener noreferrer nofollow\">python-ui-tests-async<\/a><\/p>\n<\/li>\n<\/ul>\n<h3>\u0424\u0438\u043a\u0441\u0442\u0443\u0440\u044b<\/h3>\n<p>\u041f\u0435\u0440\u0432\u043e\u0435, \u0447\u0442\u043e \u043d\u0443\u0436\u043d\u043e \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u043f\u0440\u0438 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0435 \u043d\u0430 <a href=\"https:\/\/docs.python.org\/3\/library\/asyncio-task.html\" rel=\"noopener noreferrer nofollow\">async\/await<\/a>, \u2014 \u044d\u0442\u043e \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u044b. \u0412 \u043e\u0431\u044b\u0447\u043d\u043e\u043c Pytest \u043e\u043d\u0438 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0435 \u0438 \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442 \u0432 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u043c \u043f\u043e\u0442\u043e\u043a\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f. \u0414\u043b\u044f \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0445 \u0442\u0435\u0441\u0442\u043e\u0432 \u043d\u0443\u0436\u0435\u043d \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0441\u043e\u0431\u044b\u0442\u0438\u0439\u043d\u044b\u0439 \u0446\u0438\u043a\u043b, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043f\u043b\u0430\u0433\u0438\u043d <a href=\"https:\/\/github.com\/pytest-dev\/pytest-asyncio\" rel=\"noopener noreferrer nofollow\">pytest-asyncio<\/a>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0443 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0445 \u0444\u0438\u043a\u0441\u0442\u0443\u0440 \u0438 \u0442\u0435\u0441\u0442\u043e\u0432.<\/p>\n<p><strong>\u0421\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f:<\/strong> <a href=\"https:\/\/github.com\/Nikita-Filonov\/python-ui-tests\/blob\/main\/fixtures\/pages.py\" rel=\"noopener noreferrer nofollow\">\/fixtures\/pages.py<\/a><\/p>\n<pre><code class=\"python\">import uuid  import allure import pytest from playwright.sync_api import Playwright, Page, expect  from config import Settings from pages.dashboard_page import DashboardPage from pages.registration_page import RegistrationPage   @pytest.fixture def chromium_page(playwright: Playwright, settings: Settings) -&gt; Page:     expect.set_options(timeout=settings.expect_timeout)      browser = playwright.chromium.launch(headless=settings.headless)     context = browser.new_context(         base_url=f\"{settings.app_url}\/\",         record_video_dir=settings.videos_dir     )     context.tracing.start(screenshots=True, snapshots=True, sources=True)      page = context.new_page()     yield page      tracing_file = settings.tracing_dir.joinpath(f'{uuid.uuid4()}.zip')     context.tracing.stop(path=tracing_file)     browser.close()      allure.attach.file(tracing_file, name='trace', extension='zip')     allure.attach.file(page.video.path(), name='video', attachment_type=allure.attachment_type.WEBM)   @pytest.fixture def dashboard_page(chromium_page: Page) -&gt; DashboardPage:     return DashboardPage(page=chromium_page)   @pytest.fixture def registration_page(chromium_page: Page) -&gt; RegistrationPage:     return RegistrationPage(page=chromium_page)<\/code><\/pre>\n<p><strong>\u0410\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f:<\/strong> <a href=\"https:\/\/github.com\/Nikita-Filonov\/python-ui-tests-async\/blob\/main\/fixtures\/pages.py\" rel=\"noopener noreferrer nofollow\">\/fixtures\/pages.py<\/a><\/p>\n<pre><code class=\"python\">import uuid  import allure import pytest_asyncio from playwright.async_api import Page, expect, async_playwright  from config import Settings from pages.dashboard_page import DashboardPage from pages.registration_page import RegistrationPage   @pytest_asyncio.fixture async def chromium_page(settings: Settings) -&gt; Page:     async with async_playwright() as playwright:         expect.set_options(timeout=settings.expect_timeout)          browser = await playwright.chromium.launch(headless=settings.headless)         context = await browser.new_context(             base_url=f\"{settings.app_url}\/\",             record_video_dir=settings.videos_dir         )         await context.tracing.start(screenshots=True, snapshots=True, sources=True)          page = await context.new_page()         yield page          video_file = await page.video.path()         tracing_file = settings.tracing_dir.joinpath(f'{uuid.uuid4()}.zip')         await context.tracing.stop(path=tracing_file)         await browser.close()          allure.attach.file(tracing_file, name='trace', extension='zip')         allure.attach.file(video_file, name='video', attachment_type=allure.attachment_type.WEBM)   @pytest_asyncio.fixture async def dashboard_page(chromium_page: Page) -&gt; DashboardPage:     return DashboardPage(page=chromium_page)   @pytest_asyncio.fixture async def registration_page(chromium_page: Page) -&gt; RegistrationPage:     return RegistrationPage(page=chromium_page) <\/code><\/pre>\n<p>\u0412 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0438 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 <code>pytest.fixture<\/code> \u0438 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439 Playwright API (<a href=\"https:\/\/github.com\/microsoft\/playwright-python\/tree\/main\/playwright\/sync_api\" rel=\"noopener noreferrer nofollow\">playwright.sync_api<\/a>). \u0417\u0430\u043f\u0443\u0441\u043a \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430, \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430 \u0438 \u043e\u0442\u043a\u0440\u044b\u0442\u0438\u0435 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u043b\u0438\u0441\u044c \u043f\u043e\u0448\u0430\u0433\u043e\u0432\u043e \u0438 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u043b\u0438 \u043f\u043e\u0442\u043e\u043a \u0434\u043e \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0448\u0430\u0433\u0430.<\/p>\n<p>\u0412 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u0432\u0441\u0451 \u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<ul>\n<li>\n<p>\u0412\u043c\u0435\u0441\u0442\u043e <code>pytest.fixture<\/code> \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f <code>pytest_asyncio.fixture<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043e\u0431\u044a\u044f\u0432\u0438\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u043a\u0430\u043a <code>async def<\/code>. \u042d\u0442\u043e \u0437\u043d\u0430\u0447\u0438\u0442, \u0447\u0442\u043e \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u0430 \u0441\u0430\u043c\u0430 \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u043e\u0439 \u0438 \u043c\u043e\u0436\u0435\u0442 \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0435 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u0431\u0435\u0437 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0438 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0433\u043e \u043f\u043e\u0442\u043e\u043a\u0430.<\/p>\n<\/li>\n<li>\n<p>\u0412\u043c\u0435\u0441\u0442\u043e <a href=\"https:\/\/github.com\/microsoft\/playwright-python\/tree\/main\/playwright\/sync_api\" rel=\"noopener noreferrer nofollow\">\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0433\u043e<\/a> API Playwright \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043c\u043e\u0434\u0443\u043b\u044c <a href=\"https:\/\/github.com\/microsoft\/playwright-python\/tree\/main\/playwright\/async_api\" rel=\"noopener noreferrer nofollow\">playwright.async_api<\/a>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0435 \u0432\u0435\u0440\u0441\u0438\u0438 \u0432\u0441\u0435\u0445 \u043c\u0435\u0442\u043e\u0434\u043e\u0432. \u0422\u0435\u043f\u0435\u0440\u044c \u0437\u0430\u043f\u0443\u0441\u043a \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430 (<code>launch<\/code>), \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430 (<code>new_context<\/code>) \u0438 \u043e\u0442\u043a\u0440\u044b\u0442\u0438\u0435 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b (<code>new_page<\/code>) \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u044e\u0442\u0441\u044f \u0441 \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u043c \u0441\u043b\u043e\u0432\u043e\u043c <code>await<\/code>.<\/p>\n<\/li>\n<li>\n<p>\u0412\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u0430\u044f \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u0430 <code>playwright<\/code> \u0438\u0437 \u043f\u043b\u0430\u0433\u0438\u043d\u0430 <a href=\"https:\/\/playwright.dev\/python\/docs\/test-runners\" rel=\"noopener noreferrer nofollow\">pytest-playwright<\/a> \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0435 \u043c\u043e\u0436\u0435\u0442, \u0442\u0430\u043a \u043a\u0430\u043a \u043e\u043d\u0430 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u0442 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439 API (<code>sync_playwright<\/code>). \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043c\u044b \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u043e \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u043c \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u0447\u0435\u0440\u0435\u0437 <code>async with async_playwright() as playwright:<\/code>. \u042d\u0442\u043e \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u0443\u0435\u0442 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e\u0435 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0440\u0435\u0441\u0443\u0440\u0441\u0430\u043c\u0438 \u0438 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u0435 \u0432\u0441\u0435\u0445 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0439 \u043f\u0440\u0438 \u0432\u044b\u0445\u043e\u0434\u0435 \u0438\u0437 \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u044b.<\/p>\n<\/li>\n<li>\n<p>\u0417\u0430\u043a\u0440\u044b\u0442\u0438\u0435 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430 (<code>browser.close()<\/code>), \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0442\u0440\u0435\u0439\u0441\u0438\u043d\u0433\u0430 (<code>context.tracing.stop()<\/code>) \u0438 \u0440\u0430\u0431\u043e\u0442\u0430 \u0441 \u0432\u0438\u0434\u0435\u043e (<code>page.video.path()<\/code>) \u0442\u0435\u043f\u0435\u0440\u044c \u0442\u043e\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u044e\u0442\u0441\u044f \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c <code>await<\/code>, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u044d\u0442\u0438 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u0432 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u043c API \u0442\u043e\u0436\u0435 \u043d\u0435 \u0431\u043b\u043e\u043a\u0438\u0440\u0443\u044e\u0442 \u043f\u043e\u0442\u043e\u043a.<\/p>\n<\/li>\n<li>\n<p>\u0424\u0438\u043a\u0441\u0442\u0443\u0440\u044b, \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044e\u0449\u0438\u0435 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b (<code>dashboard_page<\/code>, <code>registration_page<\/code>), \u043e\u0431\u044a\u044f\u0432\u043b\u0435\u043d\u044b \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u043c\u0438 \u043d\u0435 \u00ab\u0440\u0430\u0434\u0438 \u0433\u0430\u043b\u043e\u0447\u043a\u0438\u00bb, \u0430 \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u043e\u043d\u0438 \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e \u0437\u0430\u0432\u0438\u0441\u044f\u0442 \u043e\u0442 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0439 \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u044b <code>chromium_page<\/code>. Pytest \u0442\u0440\u0435\u0431\u0443\u0435\u0442, \u0447\u0442\u043e\u0431\u044b \u0432\u0441\u044f \u0446\u0435\u043f\u043e\u0447\u043a\u0430 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439 \u043e\u0441\u0442\u0430\u0432\u0430\u043b\u0430\u0441\u044c \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0439, \u0438\u043d\u0430\u0447\u0435 \u043e\u0436\u0438\u0434\u0430\u043d\u0438\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u0438\u0437 \u043a\u043e\u0440\u0443\u0442\u0438\u043d \u043f\u0440\u043e\u0441\u0442\u043e \u043d\u0435 \u0441\u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442.<\/p>\n<\/li>\n<\/ul>\n<p>\u0421 \u0442\u043e\u0447\u043a\u0438 \u0437\u0440\u0435\u043d\u0438\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0432 \u0442\u0435\u0441\u0442\u0430\u0445 \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u2014 \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u044b \u043f\u043e-\u043f\u0440\u0435\u0436\u043d\u0435\u043c\u0443 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b \u043f\u043e \u0438\u043c\u0435\u043d\u0438 \u0438 \u043f\u043e\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0432 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0439. \u041d\u043e \u00ab\u043f\u043e\u0434 \u043a\u0430\u043f\u043e\u0442\u043e\u043c\u00bb \u043e\u043d\u0438 \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442 \u0432 \u0441\u043e\u0431\u044b\u0442\u0438\u0439\u043d\u043e\u043c \u0446\u0438\u043a\u043b\u0435, \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0435\u043c\u043e\u043c <a href=\"https:\/\/github.com\/pytest-dev\/pytest-asyncio\" rel=\"noopener noreferrer nofollow\">pytest-asyncio<\/a>, \u0438 \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0435 \u0431\u043b\u043e\u043a\u0438\u0440\u0443\u044e\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435, \u0447\u0442\u043e \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e \u0437\u0430\u043c\u0435\u0442\u043d\u043e \u043f\u0440\u0438 \u0431\u043e\u043b\u044c\u0448\u043e\u043c \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0435 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0445 \u0432\u044b\u0437\u043e\u0432\u043e\u0432.<\/p>\n<h3>PageObject, PageComponent, PageFactory<\/h3>\n<p>\u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043c\u044b \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u043c \u043d\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 <a href=\"https:\/\/github.com\/microsoft\/playwright-python\/tree\/main\/playwright\/async_api\" rel=\"noopener noreferrer nofollow\">playwright.async_api<\/a>, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0430\u0434\u0430\u043f\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u0441\u044e<\/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-473527","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/473527","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=473527"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/473527\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=473527"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=473527"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=473527"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}