{"id":362931,"date":"2024-05-21T01:45:22","date_gmt":"2024-05-21T01:45:22","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=362931"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=362931","title":{"rendered":"<span>\u041a\u0430\u043a \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442 \u043f\u043e \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u0438 \u043d\u0430 Python, Pytest \u0438 Playwright \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0437\u0430\u043f\u0443\u0441\u043a \u0430\u0432\u0442\u043e\u0442\u0435\u0441\u0442\u043e\u0432 \u0432 CI \u0441 \u043d\u0443\u043b\u044f<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/678\/795\/bd4\/678795bd4764f7fbabb78cf2c098b1da.png\" width=\"1920\" height=\"1080\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/678\/795\/bd4\/678795bd4764f7fbabb78cf2c098b1da.png\"\/><\/figure>\n<p>\u041f\u0440\u0438\u0432\u0435\u0442, \u0425\u0430\u0431\u0440! \u041c\u0435\u043d\u044f \u0437\u043e\u0432\u0443\u0442 \u0410\u043b\u0435\u043a\u0441\u0430\u043d\u0434\u0440 \u0411\u0435\u0445\u0442\u0435\u0440\u0435\u0432, \u044f \u0440\u0430\u0431\u043e\u0442\u0430\u044e QA-\u0438\u043d\u0436\u0435\u043d\u0435\u0440\u043e\u043c \u0432 \u0423\u0447\u0438.\u0440\u0443. \u041d\u0435 \u0442\u0430\u043a \u0434\u0430\u0432\u043d\u043e \u043f\u0435\u0440\u0435\u0434 \u043d\u0430\u043c\u0438 \u0432\u0441\u0442\u0430\u043b\u0430 \u0437\u0430\u0434\u0430\u0447\u0430 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0430 \u0441 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 Selenium \u043d\u0430 \u043d\u043e\u0432\u0443\u044e \u0438 \u043c\u043e\u0449\u043d\u0443\u044e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 Playwright. \u0418 \u0442\u043e\u0433\u0434\u0430 \u044f \u0440\u0435\u0448\u0438\u043b \u0432\u0437\u044f\u0442\u044c \u043d\u0430\u0448 \u043f\u0440\u043e\u0435\u043a\u0442 \u043d\u0430 Selenium \u0438 \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u0430\u0442\u044c \u0435\u0433\u043e \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c Playwright. <\/p>\n<p>\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u043f\u043e\u0441\u0442\u0430\u0440\u0430\u044e\u0441\u044c \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043d\u0430 Python, Pytest \u0438 Playwright \u0441 \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0435\u043c \u043f\u0430\u0442\u0442\u0435\u0440\u043d\u0430 Page Object, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043e\u0441\u0442\u0430\u0432\u043b\u044e \u0448\u0430\u0431\u043b\u043e\u043d yml, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0430\u0432\u0442\u043e\u0442\u0435\u0441\u0442\u044b \u0432 CI<\/p>\n<p>\u0412\u0430\u0436\u043d\u043e: \u0434\u0430\u043d\u043d\u0430\u044f \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0430 \u043f\u043e\u0434 MacOS, \u0438 \u043e\u043d\u0430 \u043f\u0440\u0435\u0434\u0443\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0435\u0442, \u0447\u0442\u043e \u0443 \u0432\u0430\u0441 \u0443\u0436\u0435 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0430 IDE \u0438 Python. \u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e PyCharm, Python 3.11 \u0438 \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0439 \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b \u0432 MacOS.<\/p>\n<h2>\u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438  Playwright<\/h2>\n<p>Playwright \u2014 \u044d\u0442\u043e \u043d\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442, \u0430 \u043c\u043e\u0449\u043d\u043e\u0435 \u0441\u0440\u0435\u0434\u0441\u0442\u0432\u043e \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439, \u0434\u0430\u044e\u0449\u0435\u0435 \u0448\u0438\u0440\u043e\u043a\u0438\u0439 \u043d\u0430\u0431\u043e\u0440 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0435\u0439 \u0434\u043b\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 \u0442\u0430\u043a\u0438\u043c\u0438 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430\u043c\u0438, \u043a\u0430\u043a Chrome, Firefox \u0438 WebKit.\u00a0<\/p>\n<p>Playwright \u2014 \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043d\u043e\u0432\u044b\u0439 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u0434\u043b\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f, \u043d\u043e \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u043e\u043d\u0430 \u043e\u0431\u043b\u0430\u0434\u0430\u0435\u0442 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u043c\u0438 \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u0430\u043c\u0438 \u043f\u043e \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044e \u0441 Selenium, \u0442\u0430\u043a\u0438\u043c\u0438 \u043a\u0430\u043a:<\/p>\n<ul>\n<li>\n<p>\u0412\u044b\u0441\u043e\u043a\u0430\u044f \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c.<\/p>\n<\/li>\n<li>\n<p>\u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u0441\u0435\u0442\u0435\u0432\u044b\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b.<\/p>\n<\/li>\n<li>\n<p>\u0413\u0438\u0431\u043a\u043e\u0441\u0442\u044c: \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u0431\u043e\u043b\u044c\u0448\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u044f\u0437\u044b\u043a\u043e\u0432.<\/p>\n<\/li>\n<li>\n<p>\u0423\u0434\u043e\u0431\u0441\u0442\u0432\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f: \u0432 \u043d\u0435\u0439 \u043f\u0440\u0435\u0434\u0443\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u044b \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0435 \u043e\u0436\u0438\u0434\u0430\u043d\u0438\u044f \u0434\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0446\u0435\u043b\u0435\u0432\u044b\u0445 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439 \u0441 \u0432\u0435\u0431-\u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u043c\u0438, \u0430 \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 expect \u0443\u043f\u0440\u043e\u0449\u0430\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0443 \u0441 \u0430\u0441\u0441\u0435\u0440\u0442\u0430\u043c\u0438.<\/p>\n<\/li>\n<\/ul>\n<p><strong>\u0421\u043d\u0438\u0437\u0443 \u043f\u0440\u0438\u0432\u0435\u0434\u0435\u043d\u0430 \u043f\u043e\u0448\u0430\u0433\u043e\u0432\u0430\u044f \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f.<\/strong><\/p>\n<details class=\"spoiler\">\n<summary>1. \u0421\u043e\u0437\u0434\u0430\u0435\u043c \u0438 \u043a\u043b\u043e\u043d\u0438\u0440\u0443\u0435\u043c \u043f\u0443\u0441\u0442\u043e\u0439 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u0441 Git. (\u042d\u0442\u043e\u0442 \u0448\u0430\u0433 \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u043e\u043f\u0443\u0441\u0442\u0438\u0442\u044c, \u0435\u0441\u043b\u0438 \u0445\u043e\u0442\u0438\u0442\u0435 \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e).<\/summary>\n<div class=\"spoiler__content\">\n<p>\u0412\u043e\u0439\u0434\u0438\u0442\u0435 \u0432 \u0441\u0432\u043e\u0439 \u0430\u043a\u043a\u0430\u0443\u043d\u0442 \u043d\u0430 Git (\u0435\u0441\u043b\u0438 \u0443 \u0432\u0430\u0441 \u0435\u0433\u043e \u043d\u0435\u0442, \u043d\u0443\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f). \u041f\u043e\u0441\u043b\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0439 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u043d\u0430\u0436\u043c\u0438\u0442\u0435 \u043d\u0430 \u0441\u0432\u043e\u044e \u0430\u0432\u0430\u0442\u0430\u0440\u043a\u0443 \u0432 \u043f\u0440\u0430\u0432\u043e\u043c \u0432\u0435\u0440\u0445\u043d\u0435\u043c \u0443\u0433\u043b\u0443 \u0438 \u0432\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u0440\u0430\u0437\u0434\u0435\u043b <strong>Your repositories<\/strong> \u0432 \u0432\u044b\u043f\u0430\u0434\u0430\u044e\u0449\u0435\u043c \u043c\u0435\u043d\u044e.<\/p>\n<p>\u0414\u0430\u043b\u0435\u0435 \u043d\u0430\u0436\u043c\u0438\u0442\u0435 \u043a\u043d\u043e\u043f\u043a\u0443 <strong>New<\/strong> \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435 \u0432\u0430\u0448\u0438\u0445 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0435\u0432. \u041d\u0430 \u043e\u0442\u043a\u0440\u044b\u0432\u0448\u0435\u0439\u0441\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435 \u0443\u043a\u0430\u0436\u0438\u0442\u0435 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, pw_autotests) \u0438 \u0435\u0433\u043e \u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u044c (public \u0438\u043b\u0438 private) \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0432\u0430\u0448\u0438\u0445 \u043f\u0440\u0435\u0434\u043f\u043e\u0447\u0442\u0435\u043d\u0438\u0439.\u00a0<\/p>\n<p>\u0414\u0430\u043b\u0435\u0435 \u043d\u0430\u0436\u043c\u0438\u0442\u0435 \u043a\u043d\u043e\u043f\u043a\u0443 <strong>Create repository<\/strong>. \u041f\u043e\u0441\u043b\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f \u0432\u044b \u0443\u0432\u0438\u0434\u0438\u0442\u0435 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443 \u0441 \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f\u043c\u0438 \u043f\u043e \u0435\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044e. \u0412\u0430\u0436\u043d\u043e, \u0447\u0442\u043e \u0437\u0434\u0435\u0441\u044c \u0440\u0430\u0437\u043c\u0435\u0449\u0430\u0435\u0442\u0441\u044f URL \u043d\u0430\u0448\u0435\u0433\u043e \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/20b\/1c8\/5f4\/20b1c85f40bd245212f79cc61cea13dc.png\" alt=\"(\u0420\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 URL \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f)\" title=\"(\u0420\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 URL \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f)\" width=\"1920\" height=\"591\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/20b\/1c8\/5f4\/20b1c85f40bd245212f79cc61cea13dc.png\"\/><\/p>\n<div><figcaption><em>(\u0420\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 URL \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f)<\/em><\/figcaption><\/div>\n<\/figure>\n<p>\u0427\u0442\u043e\u0431\u044b \u043a\u043b\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u0430\u0448 \u043f\u0443\u0441\u0442\u043e\u0439 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u043d\u0430 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u0443\u044e \u043c\u0430\u0448\u0438\u043d\u0443:<\/p>\n<ol>\n<li>\n<p>\u043e\u0442\u043a\u0440\u043e\u0439\u0442\u0435 \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b (\u0438\u043b\u0438 \u043a\u043e\u043c\u0430\u043d\u0434\u043d\u0443\u044e \u0441\u0442\u0440\u043e\u043a\u0443);<\/p>\n<\/li>\n<li>\n<p>\u043f\u0435\u0440\u0435\u0439\u0434\u0438\u0442\u0435 \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u043a\u043e\u043c\u0430\u043d\u0434\u044b <em>cd<\/em> \u0432 \u0442\u043e\u0442 \u0440\u0430\u0437\u0434\u0435\u043b, \u043a\u0443\u0434\u0430 \u0432\u044b \u0445\u043e\u0442\u0438\u0442\u0435, \u0447\u0442\u043e\u0431\u044b \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u043b\u0441\u044f \u0432\u0430\u0448 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, <em>cd Desktop<\/em>);<\/p>\n<\/li>\n<li>\n<p>\u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u0435 \u043a\u043e\u043c\u0430\u043d\u0434\u0443 <em>git clone<\/em>, \u043f\u0440\u0438\u043b\u043e\u0436\u0438\u0432 \u0441\u0441\u044b\u043b\u043a\u0443 <a href=\"https:\/\/github.com\/your-username\/repository-name.git\"><u>https:\/\/github.com\/your-username\/repository-name.git<\/u><\/a><\/p>\n<\/li>\n<\/ol>\n<p>\u0414\u0430\u043b\u0435\u0435, \u0435\u0441\u043b\u0438 \u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u043f\u043e\u043f\u0440\u043e\u0441\u0438\u0442 \u0432\u0432\u0435\u0441\u0442\u0438 \u043b\u043e\u0433\u0438\u043d \u0438 \u043f\u0430\u0440\u043e\u043b\u044c \u043e\u0442 Git, \u0442\u043e \u0432\u0432\u0435\u0434\u0438\u0442\u0435 \u0438\u0445 \u2014 \u0438 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u0431\u0443\u0434\u0435\u0442 \u0441\u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d \u043d\u0430 \u0432\u0430\u0448 \u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440.<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>2. \u0421\u043e\u0437\u0434\u0430\u0435\u043c \u043f\u0440\u043e\u0435\u043a\u0442 \u0432 PyCharm.<\/summary>\n<div class=\"spoiler__content\">\n<p>\u0415\u0441\u043b\u0438 \u0432\u044b \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u043b\u0438 \u043f\u0443\u043d\u043a\u0442 1, \u043e\u0442\u043a\u0440\u043e\u0439\u0442\u0435 PyCharm \u0438 \u043d\u0430\u0436\u043c\u0438\u0442\u0435 \u043d\u0430 \u043a\u043d\u043e\u043f\u043a\u0443 <strong>Open<\/strong> \u0438 \u043e\u0442\u043a\u0440\u043e\u0439\u0442\u0435 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u044b \u043a\u043b\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043b\u0438 \u0441 Git, \u0435\u0441\u043b\u0438 \u043d\u0435\u0442, \u0442\u043e\u0433\u0434\u0430\u00a0 \u043d\u0430\u0436\u043c\u0438\u0442\u0435 \u043d\u0430 \u043a\u043d\u043e\u043f\u043a\u0443 <strong>New Project<\/strong>.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/9de\/4c4\/1f0\/9de4c41f0daf33ff2861ff2ba68497fc.png\" alt=\"(\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043d\u043e\u0432\u043e\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430)\" title=\"(\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043d\u043e\u0432\u043e\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430)\" width=\"1920\" height=\"591\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/9de\/4c4\/1f0\/9de4c41f0daf33ff2861ff2ba68497fc.png\"\/><\/p>\n<div><figcaption><em>(\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043d\u043e\u0432\u043e\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430)<\/em><\/figcaption><\/div>\n<\/figure>\n<p>\u0412 \u043f\u043e\u043b\u0435 <strong>New environment using<\/strong> \u0432\u044b\u0431\u0435\u0440\u0438\u0442\u0435 <strong>Virtualenv<\/strong>. \u041f\u043e\u043b\u0435 <strong>Location<\/strong> \u0437\u0430\u043f\u043e\u043b\u043d\u0438\u0442\u0441\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u2014 \u0433\u043b\u0430\u0432\u043d\u043e\u0435, \u0447\u0442\u043e\u0431\u044b \u043f\u0443\u0442\u044c \u0431\u044b\u043b \u0443\u043a\u0430\u0437\u0430\u043d \u0442\u0430\u043a\u043e\u0439 \u0436\u0435, \u043a\u0430\u043a \u0438 \u0432 \u043f\u043e\u043b\u0435<strong> Location<\/strong> \u0432\u044b\u0448\u0435, \u0442\u043e\u043b\u044c\u043a\u043e \u0441 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435\u043c <strong>\/venv<\/strong>.<\/p>\n<p>\u0414\u0430\u043b\u0435\u0435 \u0432 <strong>Base interpreter<\/strong> \u0432\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043d\u044b\u0439 \u043d\u0430 \u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440\u0435 <strong>Python 3.11<\/strong>. \u0421\u043d\u0438\u043c\u0438\u0442\u0435 \u0433\u0430\u043b\u043e\u0447\u043a\u0443 \u0441 <strong>Create a main.py welcome script<\/strong>, \u043e\u043d \u043d\u0435 \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f, \u0438 \u043d\u0430\u0436\u043c\u0438\u0442\u0435 \u043d\u0430 \u043a\u043d\u043e\u043f\u043a\u0443 <strong>Create<\/strong>.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/418\/81b\/ad6\/41881bad658623ce6b125272fa0c9a71.png\" width=\"1920\" height=\"1080\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/418\/81b\/ad6\/41881bad658623ce6b125272fa0c9a71.png\"\/><\/figure>\n<p>\u0412\u044b \u0443\u0432\u0438\u0434\u0438\u0442\u0435, \u0447\u0442\u043e \u043e\u0442\u043a\u0440\u044b\u043b\u0441\u044f \u043d\u043e\u0432\u044b\u0439 \u043f\u0443\u0441\u0442\u043e\u0439 \u043f\u0440\u043e\u0435\u043a\u0442.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/376\/c28\/cc9\/376c28cc91cdf40aa83eb4657bd4186c.png\" width=\"1920\" height=\"1080\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/376\/c28\/cc9\/376c28cc91cdf40aa83eb4657bd4186c.png\"\/><\/figure>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>3. \u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0438 Playwright \u0432 \u043d\u0430\u0448\u0435\u043c \u043d\u043e\u0432\u043e\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435.<\/summary>\n<div class=\"spoiler__content\">\n<p>\u0414\u043b\u044f \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044f\u043c\u0438 \u0438 \u0438\u0445 \u0432\u0435\u0440\u0441\u0438\u044f\u043c\u0438 \u043d\u0443\u0436\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0444\u0430\u0439\u043b <strong>requirements.txt<\/strong> \u0432 \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 \u043f\u0430\u043f\u043a\u0435 \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043a\u043b\u0438\u043a\u043d\u0438\u0442\u0435 \u043f\u0440\u0430\u0432\u043e\u0439 \u043a\u043d\u043e\u043f\u043a\u043e\u0439 \u043c\u044b\u0448\u0438 \u043f\u043e \u043d\u0430\u0448\u0435\u0439 \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 \u043f\u0430\u043f\u043a\u0435 (\u0432 \u043b\u0435\u0432\u043e\u043c \u0432\u0435\u0440\u0445\u043d\u0435\u043c \u0443\u0433\u043b\u0443). \u041e\u0442\u043a\u0440\u043e\u0435\u0442\u0441\u044f \u043c\u0435\u043d\u044e, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043d\u0443\u0436\u043d\u043e \u0432\u044b\u0431\u0440\u0430\u0442\u044c <strong>New\u2192File<\/strong>, \u0432\u0432\u0435\u0441\u0442\u0438 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0444\u0430\u0439\u043b\u0430: requirements.txt \u2014 \u0438 \u043d\u0430\u0436\u0430\u0442\u044c Enter.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/93e\/a14\/d7f\/93ea14d7fd985850d31be4586061bf0c.png\" width=\"1920\" height=\"1054\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/93e\/a14\/d7f\/93ea14d7fd985850d31be4586061bf0c.png\"\/><\/figure>\n<p>\u0414\u0430\u043b\u0435\u0435 \u0434\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u0432 \u0444\u0430\u0439\u043b <strong>requirements.txt<\/strong> \u0441\u043f\u0438\u0441\u043e\u043a \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0445 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a \u0438 \u0438\u0445 \u0432\u0435\u0440\u0441\u0438\u0439:<\/p>\n<pre><code class=\"python\">pytest playwright requests qase-pytest==4.2.0 python-dotenv<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043e\u0442\u043a\u0440\u043e\u0439\u0442\u0435 \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b \u0432 PyCharm \u0438 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0435 \u043d\u0430\u0448\u0438 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043a\u043e\u043c\u0430\u043d\u0434\u043e\u0439: <em>python3 -m pip install -r requirements.txt<\/em>.<\/p>\n<p>\u0415\u0441\u043b\u0438 \u043f\u043e \u043a\u0430\u043a\u043e\u0439-\u0442\u043e \u043f\u0440\u0438\u0447\u0438\u043d\u0435 \u043d\u0435 \u0441\u0440\u0430\u0431\u043e\u0442\u0430\u043b\u043e, \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u043a\u043e\u043c\u0430\u043d\u0434\u0443 <em>pip3 install -r requirements.txt<\/em>.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/ff5\/57c\/9ba\/ff557c9baa0eed98665c3f0b54fe8b0b.png\" width=\"1920\" height=\"705\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/ff5\/57c\/9ba\/ff557c9baa0eed98665c3f0b54fe8b0b.png\"\/><\/figure>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0434\u0440\u0430\u0439\u0432\u0435\u0440\u044b \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043e\u0432, Playwright \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0438\u0445 \u0434\u043b\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430\u043c\u0438. \u0414\u043b\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0434\u0440\u0430\u0439\u0432\u0435\u0440\u043e\u0432 \u0432\u0432\u043e\u0434\u0438\u043c \u0432 \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b\u0435 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u043a\u043e\u043c\u0430\u043d\u0434\u0443: <em>playwright install<\/em>.\u00a0<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u0448 \u043f\u0440\u043e\u0435\u043a\u0442 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d \u0434\u043b\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f Playwright.<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>4. \u0421\u043e\u0437\u0434\u0430\u0435\u043c \u0442\u0435\u043b\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430.<\/summary>\n<div class=\"spoiler__content\">\n<p>\u0414\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u0432 \u043a\u043e\u0440\u043d\u0435\u0432\u0443\u044e \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0444\u0430\u0439\u043b\u043e\u0432:<\/p>\n<ul>\n<li>\n<p>conftest.py \u2014 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u0430\u043c\u0438.<\/p>\n<\/li>\n<li>\n<p>README.md \u2014 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430.<\/p>\n<\/li>\n<li>\n<p>.gitignore \u2014 \u0432 \u043d\u0435\u043c \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u0444\u0430\u0439\u043b\u044b \u0438 \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 Git \u0431\u0443\u0434\u0435\u0442 \u0438\u0433\u043d\u043e\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u0438 \u043f\u0443\u0448\u0435 \u0432 master. \u042d\u0442\u043e \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u043d\u0435 \u0437\u0430\u0441\u043e\u0440\u044f\u0442\u044c \u043d\u0430\u0448 \u043f\u0440\u043e\u0435\u043a\u0442 \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u043c\u0438 \u0438 \u043d\u0435\u043d\u0443\u0436\u043d\u044b\u043c\u0438 \u0444\u0430\u0439\u043b\u0430\u043c\u0438.<\/p>\n<\/li>\n<li>\n<p>pytest.ini \u2014 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0439 \u0444\u0430\u0439\u043b. \u042f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e \u0435\u0433\u043e \u0434\u043b\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0445 \u043c\u0430\u0440\u043a\u0435\u0440\u043e\u0432 \u0438 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438 \u0441 \u043f\u043b\u0430\u0433\u0438\u043d\u0430\u043c\u0438 \u0438 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f\u043c\u0438. (\u041f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u043c\u0430\u0440\u043a\u0435\u0440\u043e\u0432 \u0443\u0434\u043e\u0431\u043d\u043e \u0440\u0430\u0437\u0434\u0435\u043b\u044f\u0442\u044c \u0430\u0432\u0442\u043e\u0442\u0435\u0441\u0442\u044b, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043d\u0430 smoke \u0438 \u0440\u0435\u0433\u0440\u0435\u0441\u0441\u0438\u043e\u043d\u043d\u044b\u0435 \u2014 \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u0438 \u043f\u0440\u043e\u0433\u043e\u043d\u044f\u0442\u044c\u0441\u044f \u0431\u0443\u0434\u0443\u0442 \u043d\u0443\u0436\u043d\u044b\u0435 \u043d\u0430\u043c \u0442\u0435\u0441\u0442\u044b). <\/p>\n<\/li>\n<\/ul>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/ded\/de0\/2ae\/dedde02aefb84090b7a803af9be7663c.png\" width=\"1920\" height=\"893\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/ded\/de0\/2ae\/dedde02aefb84090b7a803af9be7663c.png\"\/><\/figure>\n<p>\u0421\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u0434\u043b\u044f \u0444\u0430\u0439\u043b\u0430 <strong>.gitignore<\/strong> \u044f \u0443\u0436\u0435 \u0437\u0430\u0440\u0430\u043d\u0435\u0435 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u043b: \u0432\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u0435\u0440\u0435\u0439\u0442\u0438 \u043f\u043e <a href=\"https:\/\/github.com\/emptyzee\/base_playwright_project\/blob\/main\/.gitignore\"><u>\u0441\u0441\u044b\u043b\u043a\u0435<\/u><\/a>, \u0441\u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0435\u0433\u043e \u0438 \u043f\u0435\u0440\u0435\u043d\u0435\u0441\u0442\u0438 \u0432 \u0441\u0432\u043e\u0439 \u043f\u0440\u043e\u0435\u043a\u0442 \u0432 \u0444\u0430\u0439\u043b \u0441 \u044d\u0442\u0438\u043c \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c.<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0437\u0430\u043f\u043e\u043b\u043d\u0438\u043c \u0444\u0430\u0439\u043b <strong>pytest.ini<\/strong>:<\/p>\n<pre><code class=\"python\">[pytest] markers =     regression: run regression tests addopts = -v -s<\/code><\/pre>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/c57\/6ab\/f59\/c576abf594e185164d54b8abe1fc9ba3.png\" width=\"1920\" height=\"896\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/c57\/6ab\/f59\/c576abf594e185164d54b8abe1fc9ba3.png\"\/><\/figure>\n<p>\u0427\u0442\u043e\u0431\u044b \u0431\u044b\u043b\u043e \u0443\u0434\u043e\u0431\u043d\u0435\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u043d\u0430\u0434 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u043c, \u0441\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u0430\u043f\u043e\u043a \u0432 \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438:<\/p>\n<ul>\n<li>\n<p>Locators \u2014 \u0442\u0443\u0442 \u0431\u0443\u0434\u0443\u0442 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u044c\u0441\u044f \u043b\u043e\u043a\u0430\u0442\u043e\u0440\u044b \u0434\u043b\u044f \u0440\u0430\u0437\u043d\u044b\u0445 \u0441\u0442\u0440\u0430\u043d\u0438\u0446.<\/p>\n<\/li>\n<li>\n<p>data \u2014 \u0442\u0443\u0442 \u0431\u0443\u0434\u0443\u0442 \u0445\u0440\u0430\u043d\u0438\u0442\u044c\u0441\u044f \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435, \u043a\u043e\u043d\u0441\u0442\u0430\u043d\u0442\u044b, \u0430\u0441\u0441\u0435\u0440\u0442\u044b.<\/p>\n<\/li>\n<li>\n<p>fixtures \u2014 \u0442\u0443\u0442 \u0431\u0443\u0434\u0443\u0442 \u0440\u0430\u0441\u043f\u043e\u043b\u0430\u0433\u0430\u0442\u044c\u0441\u044f \u043c\u043e\u0434\u0443\u043b\u0438 \u0441 \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u0430\u043c\u0438 Pytest.<\/p>\n<\/li>\n<li>\n<p>pages \u2014 \u0437\u0434\u0435\u0441\u044c \u0431\u0443\u0434\u0443\u0442 \u0445\u0440\u0430\u043d\u0438\u0442\u044c\u0441\u044f \u0444\u0430\u0439\u043b\u044b \u0441 \u043c\u0435\u0442\u043e\u0434\u0430\u043c\u0438 \u0434\u043b\u044f \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 \u0432\u0435\u0431-\u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b.<\/p>\n<\/li>\n<li>\n<p>tests \u2014 \u0437\u0434\u0435\u0441\u044c \u0431\u0443\u0434\u0443\u0442 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u044c\u0441\u044f \u0430\u0432\u0442\u043e\u0442\u0435\u0441\u0442\u044b.<\/p>\n<\/li>\n<\/ul>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/d1f\/cb2\/eb4\/d1fcb2eb42ffe8a13b28af364419e023.png\" width=\"1920\" height=\"879\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/d1f\/cb2\/eb4\/d1fcb2eb42ffe8a13b28af364419e023.png\"\/><\/figure>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0437\u0430\u043f\u043e\u043b\u043d\u0438\u0442\u0435 \u0444\u0430\u0439\u043b <strong>conftest.py<\/strong>:<\/p>\n<pre><code class=\"python\">pytest_plugins = [     'fixtures.page' ]<\/code><\/pre>\n<p>\u0422\u0443\u0442 \u043d\u0443\u0436\u043d\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u043f\u0443\u0442\u044c, \u043e\u0442\u043a\u0443\u0434\u0430 \u0434\u043e\u043b\u0436\u043d\u044b \u043f\u043e\u0434\u0433\u0440\u0443\u0436\u0430\u0442\u044c\u0441\u044f \u043c\u043e\u0434\u0443\u043b\u0438 \u0441 \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u0430\u043c\u0438 (\u0434\u043b\u044f \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430 \u043c\u043e\u0434\u0443\u043b\u0438 \u0441 \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u0430\u043c\u0438 \u043b\u0443\u0447\u0448\u0435 \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0439 \u043f\u0430\u043f\u043a\u0435).<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>5. \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043c\u043e\u0434\u0443\u043b\u044c page. <\/summary>\n<div class=\"spoiler__content\">\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0432 \u043f\u0430\u043f\u043a\u0435 fixtures \u0441\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u0444\u0430\u0439\u043b <strong>page.py<\/strong>.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/95e\/78f\/4ae\/95e78f4aed2dc8462eb32a4c31466315.png\" width=\"1920\" height=\"1080\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/95e\/78f\/4ae\/95e78f4aed2dc8462eb32a4c31466315.png\"\/><\/figure>\n<p>\u0423 \u043c\u0435\u043d\u044f \u0443\u0436\u0435 \u0437\u0430\u0433\u043e\u0442\u043e\u0432\u043b\u0435\u043d \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u044b\u0439 \u043c\u043e\u0434\u0443\u043b\u044c page, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0430\u0432\u0442\u043e\u0442\u0435\u0441\u0442\u044b \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430\u0445 Chrome, Firefox \u0438 Chrome \u043d\u0430 \u0443\u0434\u0430\u043b\u0435\u043d\u043d\u043e\u043c \u0441\u0435\u0440\u0432\u0435\u0440\u0435. \u0412\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u0435\u0440\u0435\u0439\u0442\u0438 \u043f\u043e \u0441\u0441\u044b\u043b\u043a\u0435 \u0432 <a href=\"https:\/\/github.com\/emptyzee\/base_playwright_project\/blob\/main\/fixtures\/page.py\"><u>\u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439<\/u><\/a> \u0438 \u0441\u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u043c\u043e\u0434\u0443\u043b\u044f <strong>page.py <\/strong>\u043a \u0441\u0435\u0431\u0435 \u0432 \u043f\u0440\u043e\u0435\u043a\u0442. <\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/109\/94c\/d28\/10994cd28f3d54cbe8fe4b1e0c274945.png\" width=\"1920\" height=\"1080\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/109\/94c\/d28\/10994cd28f3d54cbe8fe4b1e0c274945.png\"\/><\/figure>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>6. \u0421\u043e\u0437\u0434\u0430\u0435\u043c \u043c\u043e\u0434\u0443\u043b\u044c \u0441 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u043c\u0438 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f.<\/summary>\n<div class=\"spoiler__content\">\n<p>\u0412 \u044d\u0442\u043e\u043c \u0440\u0430\u0437\u0434\u0435\u043b\u0435 \u043f\u043e\u043a\u0430\u0436\u0443, \u043a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u0443\u043f\u0440\u043e\u0441\u0442\u0438\u0442\u044c \u0440\u0430\u0431\u043e\u0442\u0443 \u0441 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f\u043c\u0438. \u0414\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u044f \u0432\u0437\u044f\u043b \u0441\u0430\u0439\u0442-\u043f\u0435\u0441\u043e\u0447\u043d\u0438\u0446\u0443 <a href=\"https:\/\/saucedemo.com\/\"><u>https:\/\/saucedemo.com<\/u><\/a>, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0442\u0430\u043c \u0435\u0441\u0442\u044c \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f \u2014 \u0430 \u044d\u0442\u043e \u0445\u043e\u0440\u043e\u0448\u0430\u044f \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u043c\u043e\u0434\u0443\u043b\u044c \u0441 \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u043e\u0439 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c \u043f\u0435\u0440\u0435\u0434 \u0437\u0430\u043f\u0443\u0441\u043a\u043e\u043c \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0445 \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0439.\u00a0<\/p>\n<p>\u041d\u043e \u044d\u0442\u043e \u043c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0434\u0430\u043b\u044c\u0448\u0435, \u0430 \u0441\u0435\u0439\u0447\u0430\u0441 \u0432\u0435\u0440\u043d\u0435\u043c\u0441\u044f \u043a \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f. \u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0441\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u0432 \u043f\u0430\u043f\u043a\u0435 data \u0444\u0430\u0439\u043b \u0441 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c <strong>environment.py.<\/strong><\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/0ff\/a8b\/680\/0ffa8b68076d3b0c85683d3e5122ebb6.png\" width=\"1920\" height=\"1080\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/0ff\/a8b\/680\/0ffa8b68076d3b0c85683d3e5122ebb6.png\"\/><\/figure>\n<p>\u0418 \u0434\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u0432 \u043d\u0435\u0433\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u043a\u043e\u0434:<\/p>\n<pre><code class=\"python\">import os  class Environment:     SHOT = 'shot'     PROD = 'prod'      URLS = {         SHOT: 'https:\/\/example.ru\/',         PROD: 'https:\/\/saucedemo.com\/'     }      def __init__(self):         try:             self.env = os.getenv('ENV')         except KeyError:             self.env = self.PROD      def get_base_url(self):         if self.env in self.URLS:             return self.URLS[self.env]         else:             raise Exception(f\"Unknown value of ENV variable {self.env}\")  host = Environment()<\/code><\/pre>\n<p>\u041a\u043b\u0430\u0441\u0441 Environment \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435\u043c \u0438 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u0431\u0430\u0437\u043e\u0432\u043e\u0433\u043e URL \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f. \u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u0435\u0441\u043b\u0438 \u0432\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0433\u043d\u0430\u0442\u044c \u0432\u0430\u0448\u0438 \u0430\u0432\u0442\u043e\u0442\u0435\u0441\u0442\u044b \u043d\u0430 \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u043c \u0438\u043b\u0438 \u043f\u0440\u043e\u0434\u043e\u0432\u043e\u043c \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0438, \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u043e\u0434\u0441\u0442\u0430\u0432\u044c\u0442\u0435 \u0441\u0432\u043e\u0438 urls \u0432 \u0441\u043b\u043e\u0432\u0430\u0440\u0435 URLS \u0438 \u0443\u043a\u0430\u0436\u0438\u0442\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435 ENV=prod \u0438\u043b\u0438 ENV=shot \u0447\u0435\u0440\u0435\u0437 \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b \u0432 PyCharm \u043a\u043e\u043c\u0430\u043d\u0434\u043e\u0439 export ENV=prod (\u0434\u043b\u044f MacOS).<\/p>\n<p>\u041d\u043e \u044f \u0441\u043e\u0432\u0435\u0442\u0443\u044e \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0432\u0441\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u0438\u0437 \u0444\u0430\u0439\u043b\u0430 <strong>.env<\/strong> \u043f\u0443\u0442\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 <strong>python-dotenv<\/strong>. \u0412\u044b \u0435\u0435, \u043a\u0441\u0442\u0430\u0442\u0438, \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043b\u0438 \u0432 \u0441\u0430\u043c\u043e\u043c \u043d\u0430\u0447\u0430\u043b\u0435! \ud83d\ude42<\/p>\n<p>\u041e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f:<\/p>\n<ul>\n<li>\n<p>\u0421\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u0432 \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 \u0444\u0430\u0439\u043b \u0441 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c <strong>.env<\/strong>.<\/p>\n<\/li>\n<li>\n<p>\u041d\u0430\u043f\u0438\u0448\u0438\u0442\u0435 \u0432 \u044d\u0442\u043e\u043c \u0432 \u0444\u0430\u0439\u043b\u0435 ENV=prod (\u0435\u0441\u043b\u0438 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e \u043d\u0443\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u043d\u0430 \u0448\u043e\u0442\u0435, \u0442\u043e \u0432\u043c\u0435\u0441\u0442\u043e prod \u043d\u0430\u043f\u0438\u0448\u0438\u0442\u0435 shot).<\/p>\n<\/li>\n<\/ul>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/663\/488\/dfb\/663488dfb0c7de604a32f46e6a19becd.png\" width=\"1920\" height=\"847\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/663\/488\/dfb\/663488dfb0c7de604a32f46e6a19becd.png\"\/><\/figure>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c, \u0447\u0442\u043e\u0431\u044b \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u043f\u043e\u0434\u0433\u0440\u0443\u0436\u0430\u043b\u0438\u0441\u044c \u043f\u0440\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u0430\u0432\u0442\u043e\u0442\u0435\u0441\u0442\u043e\u0432, \u0432\u043d\u0435\u0441\u0438\u0442\u0435 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0438\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432 \u0444\u0430\u0439\u043b <strong>conftest.py<\/strong>. \u041e\u0442\u043a\u0440\u043e\u0439\u0442\u0435 \u0435\u0433\u043e \u0438 \u0434\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u0442\u0443\u0434\u0430 \u043a\u043e\u0434: <\/p>\n<pre><code class=\"python\">from dotenv import load_dotenv   load_dotenv() <\/code><\/pre>\n<p>\u042d\u0442\u043e \u043d\u0443\u0436\u043d\u043e, \u0447\u0442\u043e\u0431\u044b \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f (\u0442\u0430\u043a\u0438\u0435 \u043a\u0430\u043a \u043b\u043e\u0433\u0438\u043d\u044b, \u043f\u0430\u0440\u043e\u043b\u0438, api tokens) \u043d\u0435 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0441\u044c \u0432 \u043a\u043e\u0434\u0435, \u0430 \u043f\u043e\u0434\u0433\u0440\u0443\u0436\u0430\u043b\u0438\u0441\u044c \u0438\u0437 \u0444\u0430\u0439\u043b\u0430 <strong>.env<\/strong>. \u042d\u0442\u043e \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u0445 \u043f\u0440\u043e\u0433\u043e\u043d\u043e\u0432; \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0447\u0435\u0440\u0435\u0437 CI \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u0445\u0440\u0430\u043d\u0438\u0442\u044c\u0441\u044f \u0438 \u043f\u043e\u0434\u0442\u044f\u0433\u0438\u0432\u0430\u0442\u044c\u0441\u044f \u0438\u0437 git-secrets.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/b25\/66d\/ff3\/b2566dff3a47fa9c31d6ff4db0fa5d7a.png\" width=\"1920\" height=\"826\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/b25\/66d\/ff3\/b2566dff3a47fa9c31d6ff4db0fa5d7a.png\"\/><\/figure>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>7. \u0421\u043e\u0437\u0434\u0430\u0435\u043c \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0439 \u043a\u043b\u0430\u0441\u0441 base \u0434\u043b\u044f \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 \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430\u0445 \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439.<\/summary>\n<div class=\"spoiler__content\">\n<p>\u0421\u0435\u0439\u0447\u0430\u0441 \u043f\u043e\u043a\u0430\u0436\u0443, \u043a\u0430\u043a \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0438 \u0437\u0430\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0431\u0430\u0437\u043e\u0432\u044b\u0439 \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0439 \u043c\u043e\u0434\u0443\u043b\u044c base. \u0412 \u043d\u0435\u043c \u0445\u0440\u0430\u043d\u044f\u0442\u0441\u044f \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043c\u0435\u0442\u043e\u0434\u044b, \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0441 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u043c\u0438 \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430\u0445 \u0432\u0435\u0431-\u0441\u0430\u0439\u0442\u043e\u0432.<\/p>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0432 \u043f\u0430\u043f\u043a\u0435 pages \u0441\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u0444\u0430\u0439\u043b <strong>base.py<\/strong>.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/421\/fca\/efc\/421fcaefcd3b2c878b7cf2d4a282b0e9.png\" width=\"1920\" height=\"1080\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/421\/fca\/efc\/421fcaefcd3b2c878b7cf2d4a282b0e9.png\"\/><\/figure>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0437\u0430\u043f\u043e\u043b\u043d\u0438\u0442\u0435 \u0435\u0433\u043e \u043a\u043e\u0434\u043e\u043c.<\/p>\n<ul>\n<li>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u0439\u0442\u0435 \u043a\u043b\u0430\u0441\u0441\u044b Page, TimeoutError, Response \u0438\u0437 \u043c\u043e\u0434\u0443\u043b\u044f<strong> playwright.sync_api<\/strong>; \u043a\u043b\u0430\u0441\u0441 host \u0438\u0437 \u0440\u0430\u043d\u0435\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u043e\u0433\u043e \u043c\u043e\u0434\u0443\u043b\u044f environment.<\/p>\n<\/li>\n<\/ul>\n<pre><code class=\"python\">from playwright.sync_api import Page, TimeoutError, Response from data.environment import host<\/code><\/pre>\n<ul>\n<li>\n<p>\u0421\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u0441\u0430\u043c \u043a\u043b\u0430\u0441\u0441 Base \u0438 \u0434\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 \u043a\u043b\u0430\u0441\u0441\u0430, \u0443 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0431\u0443\u0434\u0435\u0442 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u043d\u0430 \u0432\u0445\u043e\u0434 \u043a\u043b\u0430\u0441\u0441 Page \u0438\u0437 \u043c\u043e\u0434\u0443\u043b\u044f\u00a0 <strong>playwright.sync_api<\/strong>. \u041f\u043e\u0442\u043e\u043c \u0441\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u0432\u043d\u0443\u0442\u0440\u0438 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0430 \u043a\u043b\u0430\u0441\u0441\u0430 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 \u043a\u043b\u0430\u0441\u0441\u0430 Page, \u0447\u0442\u043e\u0431\u044b \u043e\u043d \u0431\u044b\u043b \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0432\u043e \u0432\u0441\u0435\u0445 \u043c\u0435\u0442\u043e\u0434\u0430\u0445 \u043a\u043b\u0430\u0441\u0441\u0430 Base, \u0447\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u043d\u0430\u043c \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u043d\u0430 \u0432\u0435\u0431-\u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430\u0445.<\/p>\n<\/li>\n<\/ul>\n<pre><code class=\"python\">class Base:     def __init__(self, page: Page):         self.page = page<\/code><\/pre>\n<p>\u0414\u0430\u043b\u0435\u0435 \u043d\u0443\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043c\u0435\u0442\u043e\u0434\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0440\u0438\u0433\u043e\u0434\u044f\u0442\u0441\u044f \u0434\u043b\u044f \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u043f\u0440\u043e\u0441\u0442\u043e\u0433\u043e e2e-\u0430\u0432\u0442\u043e\u0442\u0435\u0441\u0442\u0430 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u0430-\u043f\u0435\u0441\u043e\u0447\u043d\u0438\u0446\u044b. \u0412\u043e\u043e\u0431\u0449\u0435, \u044f \u043d\u0430\u043f\u0438\u0441\u0430\u043b \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043c\u043d\u043e\u0433\u043e \u0440\u0430\u0437\u043d\u044b\u0445 \u043c\u0435\u0442\u043e\u0434\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0440\u0438\u0433\u043e\u0434\u044f\u0442\u0441\u044f \u0432\u0430\u043c \u0432 \u0431\u0443\u0434\u0443\u0449\u0435\u043c. \u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0437\u0430\u0431\u0440\u0430\u0442\u044c \u0438\u0445 \u0438\u0437 \u043c\u043e\u0435\u0433\u043e <a href=\"https:\/\/github.com\/emptyzee\/base_playwright_project\/blob\/main\/pages\/base.py\">\u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f<\/a> \u043d\u0430 Git \u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432 \u0444\u0430\u0439\u043b <strong>base.py<\/strong>.<\/p>\n<p>\u0420\u0430\u0437\u0431\u0435\u0440\u0443 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u0438\u0437 \u043d\u0438\u0445.<\/p>\n<p><strong>\u041c\u0435\u0442\u043e\u0434 open <\/strong>\u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0435\u0442 \u043f\u0435\u0440\u0435\u0445\u043e\u0434 \u043d\u0430 \u0432\u0435\u0431-\u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443:<\/p>\n<pre><code class=\"python\">def open(self, uri) -> Response | None:     return self.page.goto(f\"{host.get_base_url()}{uri}\",      wait_until='domcontentloaded')<\/code><\/pre>\n<p><strong>\u041c\u0435\u0442\u043e\u0434 input<\/strong> \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0435\u0442 \u0432\u0432\u043e\u0434 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u0432 \u043f\u043e\u043b\u0435 \u0432\u0432\u043e\u0434\u0430:<\/p>\n<pre><code class=\"python\">def input(self, locator, data: str) -> None:      self.page.locator(locator).fill(data)<\/code><\/pre>\n<p><strong>\u041c\u0435\u0442\u043e\u0434 click <\/strong>\u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0435\u0442 \u043a\u043b\u0438\u043a \u043f\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0443:<\/p>\n<pre><code class=\"python\">def click(self, locator) -> None: #     self.page.click(locator)<\/code><\/pre>\n<p><strong>\u041c\u0435\u0442\u043e\u0434 get_text<\/strong> \u0434\u043e\u0441\u0442\u0430\u0435\u0442 \u0442\u0435\u043a\u0441\u0442 \u0438\u0437 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430 \u043f\u043e \u043b\u043e\u043a\u0430\u0442\u043e\u0440\u0443:<\/p>\n<pre><code class=\"python\">def get_text(self, element) -> str: #         return self.page.locator(element).text_content()<\/code><\/pre>\n<p><strong>\u041c\u0435\u0442\u043e\u0434 click_element_by_index<\/strong> \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043a\u043b\u0438\u043a\u043d\u0443\u0442\u044c \u043d\u0430 \u043d\u0443\u0436\u043d\u044b\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442, \u0443\u043a\u0430\u0437\u0430\u0432 \u0435\u0433\u043e \u0438\u043d\u0434\u0435\u043a\u0441 (\u0435\u0441\u043b\u0438 \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435 \u0435\u0441\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u0441 \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u044b\u043c \u043b\u043e\u043a\u0430\u0442\u043e\u0440\u043e\u043c):<\/p>\n<pre><code class=\"python\">def click_element_by_index(self, selector: str, index: int):     self.page.locator(selector).nth(index).click()<\/code><\/pre>\n<p><strong>\u041c\u0435\u0442\u043e\u0434 input_value_by_index<\/strong> \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043a\u043b\u0438\u043a\u043d\u0443\u0442\u044c \u043d\u0430 \u043d\u0443\u0436\u043d\u043e\u0435 \u043f\u043e\u043b\u0435 \u0441 \u0438\u043d\u043f\u0443\u0442\u043e\u043c, \u0443\u043a\u0430\u0437\u0430\u0432 \u0435\u0433\u043e \u0438\u043d\u0434\u0435\u043a\u0441:<\/p>\n<pre><code class=\"python\"> def input_value_by_index(self, selector: str, index: int, data: str): #\u0432\u0432\u043e\u0434\u0438\u043c \u0434\u0430\u043d\u043d\u044b\u0435 \u0432 \u043d\u0443\u0436\u043d\u044b\u0435 \u043f\u043e\u043b\u044f \u043f\u043e \u0438\u043d\u0434\u0435\u043a\u0441\u0443     self.page.locator(selector).nth(index).fill(data)<\/code><\/pre>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/265\/937\/cef\/265937cef090832eac9653a6a318cbc7.png\" width=\"1920\" height=\"1080\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/265\/937\/cef\/265937cef090832eac9653a6a318cbc7.png\"\/><\/figure>\n<p>\u0418\u0442\u0430\u043a, \u0432\u044b \u0441\u043e\u0437\u0434\u0430\u043b\u0438 \u043a\u043b\u0430\u0441\u0441 Base \u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u043b\u0438 \u0432 \u043d\u0435\u0433\u043e \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043c\u0435\u0442\u043e\u0434\u044b, \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0431\u0443\u0434\u0435\u0442\u0435 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0441 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u043c\u0438 \u043d\u0430 \u0432\u0435\u0431-\u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430\u0445.\u00a0<\/p>\n<p>\u041a\u043b\u0430\u0441\u0441 Base \u0431\u0443\u0434\u0435\u0442 \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u043c \u043a\u043b\u0430\u0441\u0441\u043e\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u043d\u0430\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u0440\u0443\u0433\u0438\u043c\u0438 \u043a\u043b\u0430\u0441\u0441\u0430\u043c\u0438: \u0438\u043d\u0430\u0447\u0435 \u0433\u043e\u0432\u043e\u0440\u044f, \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u0432\u0435\u0431-\u0441\u0430\u0439\u0442\u0430 \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u043c\u043e\u0434\u0443\u043b\u044c \u0438 \u043a\u043b\u0430\u0441\u0441 \u0432 \u043d\u0435\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0430\u0441\u043b\u0435\u0434\u0443\u044e\u0442 \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0439 \u043a\u043b\u0430\u0441\u0441 Base.\u00a0<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>8. \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043c\u043e\u0434\u0443\u043b\u044c \u0441 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u043c\u0438 \u0430\u0441\u0441\u0435\u0440\u0442\u0430\u043c\u0438.<\/summary>\n<div class=\"spoiler__content\">\n<p>\u0412 \u044d\u0442\u043e\u043c \u0440\u0430\u0437\u0434\u0435\u043b\u0435 \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443, \u043a\u0430\u043a \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u043c\u043e\u0434\u0443\u043b\u044c, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0445\u0440\u0430\u043d\u044f\u0442\u0441\u044f \u043c\u0435\u0442\u043e\u0434\u044b \u0441 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u043c\u0438 \u0430\u0441\u0441\u0435\u0440\u0442\u0430\u043c\u0438. \u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0432 \u043f\u0430\u043f\u043a\u0435 data \u0441\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u0444\u0430\u0439\u043b <strong>assertions.py<\/strong>.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/42f\/bcc\/aea\/42fbccaea3220c5b133f0823a237c690.png\" width=\"1920\" height=\"1080\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/42f\/bcc\/aea\/42fbccaea3220c5b133f0823a237c690.png\"\/><\/figure>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u044d\u0442\u043e\u0442 \u043c\u043e\u0434\u0443\u043b\u044c \u043d\u0443\u0436\u043d\u043e \u0437\u0430\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u043a\u043e\u0434\u043e\u043c. \u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u0439\u0442\u0435 \u0432\u0441\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438:<\/p>\n<pre><code class=\"python\">from playwright.sync_api import Page from data.environment import host from playwright.sync_api import expect from pages.base import Base<\/code><\/pre>\n<p>\u0421\u0442\u043e\u0438\u0442 \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u0438\u043c\u043f\u043e\u0440\u0442 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 expect. \u041e\u043d\u0430 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u043e\u0431\u0448\u0438\u0440\u043d\u044b\u0439 \u043d\u0430\u0431\u043e\u0440 \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0445 \u0430\u0441\u0441\u0435\u0440\u0442\u043e\u0432 \u0438 \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u0443\u0441\u043b\u043e\u0432\u0438\u0439 \u0432 \u0445\u043e\u0434\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0430\u0432\u0442\u043e\u0442\u0435\u0441\u0442\u043e\u0432.<\/p>\n<p>\u0414\u0430\u043b\u0435\u0435 \u0441\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u043a\u043b\u0430\u0441\u0441 Assertions, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u043d\u0430\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u044c \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0439 \u043a\u043b\u0430\u0441\u0441 Base. \u0414\u043b\u044f \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e\u0439 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0433\u043e \u043a\u043b\u0430\u0441\u0441\u0430 \u0438 \u0435\u0433\u043e \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u043e\u0432 \u0438 \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u0434\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 \u043a\u043b\u0430\u0441\u0441\u0430 \u0438 \u0432\u044b\u0437\u043e\u0432\u0438\u0442\u0435 \u0432 \u043d\u0435\u043c \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u044e <strong>Python super()<\/strong>, \u0447\u0435\u0440\u0435\u0437 \u043d\u0435\u0435 \u2014 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0433\u043e \u043a\u043b\u0430\u0441\u0441\u0430 Base, \u0437\u0430\u0442\u0435\u043c \u043f\u0435\u0440\u0435\u0434\u0430\u0439\u0442\u0435 \u0435\u043c\u0443 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442 page.<\/p>\n<pre><code class=\"python\">class Assertions(Base):     def __init__(self, page: Page) -> None:         super().__init__(page)<\/code><\/pre>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/2c3\/200\/fd5\/2c3200fd587174635a0393f959dbb81b.png\" width=\"1920\" height=\"718\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/2c3\/200\/fd5\/2c3200fd587174635a0393f959dbb81b.png\"\/><\/figure>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043c\u0435\u0442\u043e\u0434\u044b \u0441 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u043c\u0438 \u0430\u0441\u0441\u0435\u0440\u0442\u0430\u043c\u0438: \u0438\u0445 \u044f \u0442\u043e\u0436\u0435 \u0437\u0430\u0440\u0430\u043d\u0435\u0435 \u0443\u0436\u0435 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u043b \u0432 <a href=\"https:\/\/github.com\/emptyzee\/base_playwright_project\/blob\/main\/data\/assertions.py\"><u>\u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438<\/u><\/a>. \u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0441\u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438\u0445 \u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043a \u0441\u0435\u0431\u0435 \u0432 \u043f\u0440\u043e\u0435\u043a\u0442.<\/p>\n<p>\u0422\u0435, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0440\u0438\u0433\u043e\u0434\u044f\u0442\u0441\u044f \u0434\u043b\u044f \u043f\u0440\u043e\u0431\u043d\u043e\u0433\u043e \u0430\u0432\u0442\u043e\u0442\u0435\u0441\u0442\u0430, \u044f \u043e\u043f\u0438\u0448\u0443 \u043d\u0438\u0436\u0435:<\/p>\n<p><strong>check_url<\/strong> \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442, \u0447\u0442\u043e \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043d\u0430 \u043d\u0443\u0436\u043d\u043e\u0439 \u043d\u0430\u043c \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435:<\/p>\n<pre><code class=\"python\">    def check_URL(self, uri, msg):         expect(self.page).to_have_url(f\"{host.get_base_url()}{uri}\", timeout=10000), msg<\/code><\/pre>\n<p><strong>check_presence<\/strong> \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442, \u0447\u0442\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u043f\u0440\u0438\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435 (\u0435\u0441\u043b\u0438 \u0435\u0441\u0442\u044c \u2014 \u0442\u043e assert True).<\/p>\n<pre><code class=\"python\">    def check_presence(self, locator, msg):         loc = self.page.locator(locator)         expect(loc).to_be_visible(visible=True, timeout=12000), msg<\/code><\/pre>\n<p><strong>check_absence<\/strong> \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442, \u0447\u0442\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435 (\u0435\u0441\u043b\u0438 \u043d\u0435\u0442 \u2014 \u0442\u043e assert True).<\/p>\n<pre><code class=\"python\">    def check_absence(self, locator, msg):         loc = self.page.locator(locator)         expect(loc).to_be_hidden(timeout=700), msg<\/code><\/pre>\n<p><strong>have_text<\/strong> \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442, \u0447\u0442\u043e \u0443 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430 \u043d\u0443\u0436\u043d\u044b\u0439 \u0442\u0435\u043a\u0441\u0442.<\/p>\n<pre><code class=\"python\">    def have_text(self, locator, text: str, msg):         loc = self.page.locator(locator)         expect(loc).to_have_text(text), msg<\/code><\/pre>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/ae8\/ea8\/fe5\/ae8ea8fe504d1fb6ecf0cf5961f86f0a.png\" width=\"1920\" height=\"1080\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/ae8\/ea8\/fe5\/ae8ea8fe504d1fb6ecf0cf5961f86f0a.png\"\/><\/figure>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>9. \u041f\u0438\u0448\u0435\u043c \u043f\u0435\u0440\u0432\u044b\u0439 \u0430\u0432\u0442\u043e\u0442\u0435\u0441\u0442 \u043d\u0430 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044e.<\/summary>\n<div class=\"spoiler__content\">\n<p>\u0412 \u044d\u0442\u043e\u043c \u0440\u0430\u0437\u0434\u0435\u043b\u0435 \u044f \u043f\u043e\u043a\u0430\u0436\u0443, \u043a\u0430\u043a \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0430\u0432\u0442\u043e\u0442\u0435\u0441\u0442 \u0434\u043b\u044f \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u043d\u0430 \u0441\u0430\u0439\u0442\u0435-\u043f\u0435\u0441\u043e\u0447\u043d\u0438\u0446\u0435 <a href=\"https:\/\/saucedemo.com\/\"><u>https:\/\/www.saucedemo.com<\/u><\/a>. (\u0410 \u0432 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c \u0440\u0430\u0437\u0434\u0435\u043b\u0435 \u043c\u044b \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u043c\u0435\u0442\u043e\u0434 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u043e\u0439, \u0447\u0442\u043e\u0431\u044b \u0432 \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0435\u0435 \u043f\u0435\u0440\u0435\u0434 \u0437\u0430\u043f\u0443\u0441\u043a\u043e\u043c \u0434\u0440\u0443\u0433\u0438\u0445 \u0430\u0432\u0442\u043e\u0442\u0435\u0441\u0442\u043e\u0432).\u00a0<\/p>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0441\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043c\u043e\u0434\u0443\u043b\u0438:<\/p>\n<ul>\n<li>\n<p>\u0444\u0430\u0439\u043b auth.py \u0432 \u043f\u0430\u043f\u043a\u0435 Locators;<\/p>\n<\/li>\n<li>\n<p>\u0444\u0430\u0439\u043b constants.py \u0432 \u043f\u0430\u043f\u043a\u0435 data;<\/p>\n<\/li>\n<li>\n<p>\u0444\u0430\u0439\u043b main_page.py \u0432 \u043f\u0430\u043f\u043a\u0435 pages;<\/p>\n<\/li>\n<li>\n<p>\u0444\u0430\u0439\u043b test_auth.py \u0432 \u043f\u0430\u043f\u043a\u0435 Tests<strong>.<\/strong><\/p>\n<\/li>\n<\/ul>\n<p>\u041d\u0443\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043f\u0440\u0435\u0444\u0438\u043a\u0441 test_ \u0432 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0444\u0430\u0439\u043b\u0430, \u0447\u0442\u043e\u0431\u044b Pytest \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0438\u0432\u0430\u043b \u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u043b \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0432 \u043c\u043e\u0434\u0443\u043b\u0435 \u043a\u0430\u043a \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0435 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0438. \u042d\u0442\u043e \u0441\u0432\u044f\u0437\u0430\u043d\u043e \u0441 \u0441\u043e\u0433\u043b\u0430\u0448\u0435\u043d\u0438\u044f\u043c\u0438 \u0438 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u0430\u043c\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 Pytest \u0434\u043b\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u0442\u0435\u0441\u0442\u043e\u0432.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/db0\/513\/0be\/db05130bea626101c865392515ad00f0.png\" width=\"1920\" height=\"1080\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/db0\/513\/0be\/db05130bea626101c865392515ad00f0.png\"\/><\/figure>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0443\u0436\u043d\u043e \u0432 \u0441\u0432\u0435\u0436\u0435\u0441\u043e\u0437\u0434\u0430\u043d\u043d\u043e\u043c \u0444\u0430\u0439\u043b\u0435 <strong>test_auth.py<\/strong> \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043a\u043b\u0430\u0441\u0441 Auth \u0438 \u043f\u043e\u0434\u043e\u0431\u0440\u0430\u0442\u044c \u043b\u043e\u043a\u0430\u0442\u043e\u0440\u044b \u0434\u043b\u044f \u0444\u043e\u0440\u043c\u044b \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438. \u041e\u0442\u043a\u0440\u043e\u0439\u0442\u0435 \u0441\u0430\u0439\u0442-\u043f\u0435\u0441\u043e\u0447\u043d\u0438\u0446\u0443 <a href=\"https:\/\/saucedemo.com\/\"><u>https:\/\/saucedemo.com<\/u><\/a>, \u043d\u0430\u0432\u0435\u0434\u0438\u0442\u0435 \u043c\u044b\u0448\u043a\u0443 \u043d\u0430 \u043f\u043e\u043b\u0435 \u0438\u043d\u043f\u0443\u0442\u0430 <strong>username<\/strong> \u0438 \u043d\u0430\u0436\u043c\u0438\u0442\u0435 \u043f\u0440\u0430\u0432\u0443\u044e \u043a\u043d\u043e\u043f\u043a\u0443 \u043c\u044b\u0448\u0438. \u0412 \u043f\u043e\u044f\u0432\u0438\u0432\u0448\u0435\u043c\u0441\u044f \u043e\u043a\u043d\u0435 \u0432\u044b\u0431\u0435\u0440\u0438\u0442\u0435 <strong>\u041f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043a\u043e\u0434<\/strong><em>.<\/em><\/p>\n<p>\u0423 \u0432\u0430\u0441 \u043e\u0442\u043a\u0440\u043e\u0435\u0442\u0441\u044f \u043f\u0430\u043d\u0435\u043b\u044c \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u043d\u0430 \u0432\u043a\u043b\u0430\u0434\u043a\u0435 Elements \u0441 \u0432\u044b\u0434\u0435\u043b\u0435\u043d\u043d\u043e\u0439 \u0447\u0430\u0441\u0442\u044c\u044e html-\u0440\u0430\u0437\u043c\u0435\u0442\u043a\u0438 \u0434\u043b\u044f \u0438\u043d\u043f\u0443\u0442\u0430 Username.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/9d6\/9f7\/4a3\/9d69f74a39d0f806a72b6ef57cfc695e.png\" width=\"1920\" height=\"1080\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/9d6\/9f7\/4a3\/9d69f74a39d0f806a72b6ef57cfc695e.png\"\/><\/figure>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u0436\u043c\u0438\u0442\u0435 <strong>command + F<\/strong>, \u0447\u0442\u043e\u0431\u044b \u043e\u0442\u043a\u0440\u044b\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0443 \u043f\u043e\u0438\u0441\u043a\u0430 \u043f\u043e html-\u0440\u0430\u0437\u043c\u0435\u0442\u043a\u0435 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b.\u00a0<\/p>\n<p>\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u0432 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u043c \u044f \u0431\u0443\u0434\u0443 \u0437\u0430\u0432\u044f\u0437\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0430 Data attributes, \u0442\u0430\u043a \u043a\u0430\u043a \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 \u0441\u0430\u0439\u0442\u0430 \u0438\u0445 \u043d\u0430\u043c \u043e\u0441\u0442\u0430\u0432\u0438\u043b\u0438. \u0412\u043e\u043e\u0431\u0449\u0435, Data attributes \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0441\u0430\u043c\u044b\u043c \u043b\u0443\u0447\u0448\u0438\u043c \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u043c \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u043d\u0430 \u043d\u0438\u0445 \u0437\u0430\u0432\u044f\u0437\u0430\u0442\u044c \u0430\u0432\u0442\u043e\u0442\u0435\u0441\u0442\u044b: \u0441 \u043d\u0438\u043c\u0438 \u043b\u0435\u0433\u0447\u0435 \u0434\u043e\u0431\u0438\u0442\u044c\u0441\u044f \u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u0442\u0435\u0441\u0442\u043e\u0432, \u0442\u0430\u043a \u043a\u0430\u043a \u043c\u0430\u043b\u043e\u0432\u0435\u0440\u043e\u044f\u0442\u043d\u043e, \u0447\u0442\u043e \u043e\u043d\u0438 \u043c\u043e\u0433\u0443\u0442 \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c\u0441\u044f.\u00a0<\/p>\n<p>\u0412\u043e\u043e\u0431\u0449\u0435, \u043f\u043e \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438, \u044f \u0441\u0442\u0430\u0440\u0430\u044e\u0441\u044c \u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c\u0443 \u043f\u0440\u0438\u043e\u0440\u0438\u0442\u0435\u0442\u0443 \u043b\u043e\u043a\u0430\u0442\u043e\u0440\u043e\u0432:\u00a0<\/p>\n<ul>\n<li>\n<p>\u041d\u0430 \u043f\u0435\u0440\u0432\u043e\u043c \u043c\u0435\u0441\u0442\u0435 \u2014 Data attributes.<\/p>\n<\/li>\n<li>\n<p>\u041d\u0430 \u0432\u0442\u043e\u0440\u043e\u043c \u2014 CSS-\u0441\u0435\u043b\u0435\u043a\u0442\u043e\u0440\u044b.<\/p>\n<\/li>\n<li>\n<p>\u041d\u0430 \u0442\u0440\u0435\u0442\u044c\u0435\u043c \u2014 XPath (\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e \u043f\u0440\u0438 \u0431\u043e\u043b\u0435\u0435 \u0441\u043b\u043e\u0436\u043d\u044b\u0445 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u044f\u0445 \u043f\u043e\u0438\u0441\u043a\u0430, \u043a\u0430\u043a \u043e\u0434\u0438\u043d \u0438\u0437 \u043f\u0440\u0438\u043c\u0435\u0440\u043e\u0432 \u2014 \u0435\u0441\u043b\u0438 \u0445\u043e\u0447\u0443 \u043f\u0440\u0438\u0432\u044f\u0437\u0430\u0442\u044c\u0441\u044f \u043a \u043a\u0430\u043a\u043e\u043c\u0443-\u0442\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0443 \u043f\u043e \u0442\u0435\u043a\u0441\u0442\u0443).<\/p>\n<\/li>\n<\/ul>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e, \u043a\u0430\u043a \u0432\u044b \u043d\u0430\u0436\u0430\u043b\u0438 \u043d\u0430<strong> command + F<\/strong>, \u0443 \u0432\u0430\u0441 \u043e\u0442\u043a\u0440\u044b\u043b\u0430\u0441\u044c \u0441\u0442\u0440\u043e\u043a\u0430 \u043f\u043e\u0438\u0441\u043a\u0430 \u043f\u043e html-\u0440\u0430\u0437\u043c\u0435\u0442\u043a\u0435 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b. \u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u0432 \u0441\u0442\u0440\u043e\u043a\u0435 \u043f\u043e\u0438\u0441\u043a\u0430 <strong>data-test=&#8217;username&#8217;<\/strong> \u2014 \u044d\u0442\u043e \u0438 \u0435\u0441\u0442\u044c Data attribute. \u041d\u0430\u0436\u043c\u0438\u0442\u0435 Enter \u2014 \u0438 \u0432\u044b \u0443\u0432\u0438\u0434\u0438\u0442\u0435, \u0447\u0442\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0432\u044b\u0434\u0435\u043b\u0438\u043b\u0441\u044f.\u00a0<\/p>\n<p>\u0421\u043a\u043e\u043f\u0438\u0440\u0443\u0439\u0442\u0435 \u0435\u0433\u043e, \u0437\u0430\u0442\u0435\u043c \u0441\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u0432 \u0441\u0432\u043e\u0435\u043c \u0444\u0430\u0439\u043b\u0435 <strong>test_auth.py<\/strong> \u0438 \u0432 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u043e\u043c \u043a\u043b\u0430\u0441\u0441\u0435 Auth \u043d\u043e\u0432\u044b\u0439 \u0430\u0442\u0440\u0438\u0431\u0443\u0442 USERNAME_INPUT = &#171;[data-test=&#8217;username&#8217;]&#187;. \u0410\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u044c\u0442\u0435 PASSWORD_INPUT \u0438 LOGIN_BTN.<\/p>\n<p>\u041f\u043e\u043b\u0443\u0447\u0438\u0442\u044c\u0441\u044f \u0434\u043e\u043b\u0436\u043d\u043e \u0442\u0430\u043a.<\/p>\n<pre><code class=\"python\"> class Auth:     USERNAME_INPUT = \"[data-test = 'username']\"     PASSWORD_INPUT = \"[data-test='password']\"     LOGIN_BTN = \"[data-test='login-button']\"<\/code><\/pre>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/8e4\/3e9\/6f4\/8e43e96f46daf873bb75909a43082da8.png\" width=\"1920\" height=\"627\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/8e4\/3e9\/6f4\/8e43e96f46daf873bb75909a43082da8.png\"\/><\/figure>\n<p>\u0414\u0430\u043b\u0435\u0435 \u0432 \u0444\u0430\u0439\u043b <strong>constants.py<\/strong> \u0434\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u043a\u043e\u0434:<\/p>\n<pre><code class=\"python\">import os  class Constants:     try:         login = os.getenv('AUTH_LOGIN')         password = os.getenv('AUTH_PASSWORD')     except KeyError:         print(\"LOGIN OR PW WASN'T FOUND\")<\/code><\/pre>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/c91\/4f7\/897\/c914f78977b23cb4c0e1ec49c8c72c73.png\" width=\"1920\" height=\"731\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/c91\/4f7\/897\/c914f78977b23cb4c0e1ec49c8c72c73.png\"\/><\/figure>\n<p>\u042d\u0442\u043e \u043d\u0443\u0436\u043d\u043e, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0435 \u043a\u0440\u0435\u0434\u044b \u0432 \u043a\u043e\u0434\u0435. \u041b\u043e\u0433\u0438\u043d \u0438 \u043f\u0430\u0440\u043e\u043b\u044c \u043f\u0440\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u0434\u0442\u044f\u0433\u0438\u0432\u0430\u0442\u044c\u0441\u044f \u0438\u0437 \u0444\u0430\u0439\u043b\u0430 <strong>.env<\/strong>, \u0430 \u043f\u0440\u0438 \u0443\u0434\u0430\u043b\u0435\u043d\u043d\u043e\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u2014 \u0438\u0437 \u043f\u0430\u043f\u043e\u043a secrets.\u00a0<\/p>\n<p>\u0417\u043d\u0430\u0447\u0438\u0442, \u043d\u0443\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043b\u043e\u0433\u0438\u043d \u0438 \u043f\u0430\u0440\u043e\u043b\u044c \u0432 \u0444\u0430\u0439\u043b <strong>.env<\/strong>:<\/p>\n<pre><code class=\"python\">AUTH_LOGIN = standard_user AUTH_PASSWORD = secret_sauce<\/code><\/pre>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/da7\/b06\/5c0\/da7b065c0e1e0b1bca92bc3536d4ab3a.png\" width=\"1920\" height=\"949\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/da7\/b06\/5c0\/da7b065c0e1e0b1bca92bc3536d4ab3a.png\"\/><\/figure>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0430\u0442\u044c \u043a \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044e \u043c\u043e\u0434\u0443\u043b\u044f <strong>main_page.py<\/strong>. \u042f \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443, \u043a\u0430\u043a \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043c\u0435\u0442\u043e\u0434, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u044c \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044e \u0447\u0435\u0440\u0435\u0437 \u0444\u043e\u0440\u043c\u0443 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438.\u00a0<\/p>\n<p>\u0414\u043e\u0431\u0430\u0432\u0438\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u043a\u043e\u0434:<\/p>\n<pre><code class=\"python\">from pages.base import Base from data.constants import Constants from Locators.auth import Auth from data.assertions import Assertions from playwright.sync_api import Page  class Main(Base):     def __init__(self, page: Page) -> None:         super().__init__(page)         self.assertion = Assertions(page)      def user_login(self):         self.open(\"\")         self.input(Auth.USERNAME_INPUT, Constants.login)         self.input(Auth.PASSWORD_INPUT, Constants.password)         self.click(Auth.LOGIN_BTN)         self.assertion.check_URL(\"inventory.html\", \"Wrong URL\")<\/code><\/pre>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/f19\/b64\/f66\/f19b64f66110335d11aae6bc681ecf6e.png\" width=\"1920\" height=\"984\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/f19\/b64\/f66\/f19b64f66110335d11aae6bc681ecf6e.png\"\/><\/figure>\n<p>\u0412 \u043c\u0435\u0442\u043e\u0434\u0435 <em>self.open(&#171;&#187;)<\/em> \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0430 &#171;&#187; \u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442, \u0447\u0442\u043e \u043c\u044b \u043d\u0435 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u043c \u043d\u0438\u043a\u0430\u043a\u043e\u0439 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 uri \u043a \u0431\u0430\u0437\u043e\u0432\u043e\u043c\u0443 url. \u0414\u0440\u0443\u0433\u0438\u043c\u0438 \u0441\u043b\u043e\u0432\u0430\u043c\u0438, \u043c\u044b \u043f\u0440\u043e\u0441\u0442\u043e \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u043c \u0431\u0430\u0437\u043e\u0432\u044b\u0439 url \u2014 <a href=\"https:\/\/www.saucedemo.com\/\"><u>https:\/\/www.saucedemo.com<\/u><\/a>.\u00a0<\/p>\n<p>\u0412 \u043a\u043e\u043d\u0446\u0435 \u044f \u0442\u0430\u043a\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u0438\u043b \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443 \u043d\u0430 \u0442\u043e, \u0447\u0442\u043e \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f \u043f\u0440\u043e\u0448\u043b\u0430 \u0443\u0441\u043f\u0435\u0448\u043d\u043e. \u042d\u0442\u043e \u0438\u043c\u0435\u043d\u043d\u043e \u043f\u0440\u0438\u043c\u0435\u0440, \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443 \u043c\u043e\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043a\u0430\u043a\u0443\u044e \u0445\u043e\u0442\u0438\u0442\u0435.<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c, \u0447\u0442\u043e\u0431\u044b \u0430\u0432\u0442\u043e\u0442\u0435\u0441\u0442 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u043b\u0441\u044f, \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u043e\u043f\u0438\u0441\u0430\u0442\u044c \u0435\u0433\u043e \u0432 \u043c\u043e\u0434\u0443\u043b\u0435 <strong>test_auth.py<\/strong>. \u0414\u043e\u0431\u0430\u0432\u0438\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u043a\u043e\u0434:<\/p>\n<pre><code class=\"python\">import pytest from pages.main_page import Main   @pytest.mark.smoke class TestLogin:     def test_user_login(self, browser):         m = Main(browser)         m.user_login()<\/code><\/pre>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/890\/8fc\/5d6\/8908fc5d63ca630f3c911f7a7d3e7f54.png\" width=\"1920\" height=\"723\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/890\/8fc\/5d6\/8908fc5d63ca630f3c911f7a7d3e7f54.png\"\/><\/figure>\n<p>\u042d\u0442\u043e\u0442 \u0442\u0435\u0441\u0442 \u043f\u043e\u043c\u0435\u0447\u0435\u043d \u043c\u0430\u0440\u043a\u043e\u0439 <strong>smoke<\/strong> \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0440\u0430\u0437\u0431\u0438\u0442\u044c \u0430\u0432\u0442\u043e\u0442\u0435\u0441\u0442\u044b \u043d\u0430 \u0440\u0430\u0437\u043d\u044b\u0435 \u0431\u043b\u043e\u043a\u0438 \u0438, \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u0438, \u043f\u0440\u043e\u0433\u043e\u043d\u044f\u0442\u044c \u043d\u0443\u0436\u043d\u044b\u0435.\u00a0<\/p>\n<p>\u0422\u0430\u043a\u0436\u0435 \u0431\u044b\u043b \u0441\u043e\u0437\u0434\u0430\u043d \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 \u043a\u043b\u0430\u0441\u0441\u0430 \u0441 \u0433\u043b\u0430\u0432\u043d\u043e\u0439 \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u043e\u0439 browser, \u0430 \u0434\u0430\u043b\u044c\u0448\u0435 \u0432\u044b\u0437\u0432\u0430\u043d \u043c\u0435\u0442\u043e\u0434 <em>user_login()<\/em> \u0438\u0437 \u043c\u043e\u0434\u0443\u043b\u044f <strong>main_page.py<\/strong>.\u00a0<\/p>\n<p>\u041e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0430\u0432\u0442\u043e\u0442\u0435\u0441\u0442. \u041d\u043e \u0434\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0432 \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b\u0435 PyCharm \u043d\u0443\u0436\u043d\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043a\u043e\u043c\u0430\u043d\u0434\u0443 <em>cd Tests<\/em>, \u0447\u0442\u043e\u0431\u044b \u043f\u0435\u0440\u0435\u0439\u0442\u0438 \u0432 \u043f\u0430\u043f\u043a\u0443 \u0441 \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u043c \u043c\u043e\u0434\u0443\u043b\u0435\u043c.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/8cb\/f2c\/3d1\/8cbf2c3d151a8b1b357ca6bdbb44ee0f.png\" width=\"1920\" height=\"389\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/8cb\/f2c\/3d1\/8cbf2c3d151a8b1b357ca6bdbb44ee0f.png\"\/><\/figure>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0432 \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b\u0435 PyCharm \u043d\u0430\u043f\u0438\u0448\u0438\u0442\u0435 \u043a\u043e\u043c\u0430\u043d\u0434\u0443 \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0430\u0432\u0442\u043e\u0442\u0435\u0441\u0442\u0430 <em>pytest -s test_auth.py<\/em> \u0438 \u043d\u0430\u0436\u043c\u0438\u0442\u0435 Enter. \u0424\u043b\u0430\u0433 <em>-s<\/em> \u043d\u0430\u043c \u0442\u0443\u0442 \u043d\u0443\u0436\u0435\u043d \u0434\u043b\u044f \u0432\u044b\u0432\u043e\u0434\u0430 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0438 \u0442\u0435\u0441\u0442\u043e\u0432. \u0414\u043e\u043b\u0436\u0435\u043d \u043f\u043e\u044f\u0432\u0438\u0442\u044c\u0441\u044f \u0441\u0442\u0430\u0442\u0443\u0441 PASSED, \u044d\u0442\u043e \u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442, \u0447\u0442\u043e \u0442\u0435\u0441\u0442 \u043f\u0440\u043e\u0448\u0435\u043b \u0443\u0441\u043f\u0435\u0448\u043d\u043e.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/a72\/743\/ce0\/a72743ce0d1a859572d822848d1f41c0.png\" width=\"1920\" height=\"655\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/a72\/743\/ce0\/a72743ce0d1a859572d822848d1f41c0.png\"\/><\/figure>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>10. \u041f\u0438\u0448\u0435\u043c \u0432\u0442\u043e\u0440\u043e\u0439 \u0430\u0432\u0442\u043e\u0442\u0435\u0441\u0442.<\/summary>\n<div class=\"spoiler__content\">\n<p>\u0412 \u044d\u0442\u043e\u043c \u0440\u0430\u0437\u0434\u0435\u043b\u0435 \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443, \u043a\u0430\u043a \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043f\u0440\u043e\u0441\u0442\u0435\u043d\u044c\u043a\u0438\u0439 e2e-\u0442\u0435\u0441\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u0432 \u0441\u0435\u0431\u044f \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044e, \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0432 \u043a\u043e\u0440\u0437\u0438\u043d\u0443 \u0442\u043e\u0432\u0430\u0440\u0430 \u0438 \u0441\u043e\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u0435 \u043f\u043e\u043a\u0443\u043f\u043a\u0438.\u00a0<\/p>\n<p>\u0414\u043b\u044f \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430 \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0438\u0437 \u0442\u0435\u0441\u0442\u0430 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u0443, \u0447\u0442\u043e\u0431\u044b \u0431\u044b\u043b\u043e \u043b\u0435\u0433\u0447\u0435 \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c \u0435\u0435 \u043f\u0435\u0440\u0435\u0434 \u0437\u0430\u043f\u0443\u0441\u043a\u043e\u043c \u0434\u0440\u0443\u0433\u0438\u0445 \u0430\u0432\u0442\u043e\u0442\u0435\u0441\u0442\u043e\u0432.<\/p>\n<p>\u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0432 \u043f\u0430\u043f\u043a\u0435 fixtures \u0441\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u0444\u0430\u0439\u043b \u0441 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c user_auth.py\u0438 \u0434\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u0442\u0443\u0434\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u043a\u043e\u0434:<\/p>\n<pre><code class=\"python\">import pytest from pages.main_page import Main   @pytest.fixture(scope='class') def user_login(browser):     m = Main(browser)     m.user_login()<\/code><\/pre>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/d51\/2da\/e14\/d512dae144615f46add76c987d17593c.png\" width=\"1920\" height=\"906\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/d51\/2da\/e14\/d512dae144615f46add76c987d17593c.png\"\/><\/figure>\n<p>\u0427\u0442\u043e\u0431\u044b Pytest \u043f\u043e\u0434\u0433\u0440\u0443\u0436\u0430\u043b \u0434\u0430\u043d\u043d\u0443\u044e \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u0443, \u043f\u0435\u0440\u0435\u0439\u0434\u0438\u0442\u0435 \u0432 \u0444\u0430\u0439\u043b conftest \u0438 \u0434\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u043f\u0443\u0442\u044c \u0434\u043e \u043d\u0435\u0435:<\/p>\n<pre><code class=\"python\">pytest_plugins = [     'fixtures.page',     'fixtures.user_auth' ]<\/code><\/pre>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/5b4\/08f\/15c\/5b408f15cc7527e810f7ea627f2ecbf2.png\" width=\"1920\" height=\"901\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/5b4\/08f\/15c\/5b408f15cc7527e810f7ea627f2ecbf2.png\"\/><\/figure>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0430\u0442\u044c \u043a \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044e \u0441\u0430\u043c\u043e\u0433\u043e \u0430\u0432\u0442\u043e\u0442\u0435\u0441\u0442\u0430. \u0412 \u044d\u0442\u043e\u0442 \u0440\u0430\u0437 \u0434\u043b\u044f \u0433\u043b\u0430\u0432\u043d\u043e\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u044f \u043f\u043e\u043a\u0430\u0436\u0443, \u043a\u0430\u043a \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c CSS-\u0441\u0435\u043b\u0435\u043a\u0442\u043e\u0440\u044b, \u0438 \u0447\u0442\u043e \u0434\u0435\u043b\u0430\u0442\u044c, \u0435\u0441\u043b\u0438 \u0435\u0441\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u0441 \u043e\u0434\u043d\u0438\u043c \u043b\u043e\u043a\u0430\u0442\u043e\u0440\u043e\u043c.\u00a0<\/p>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435 \u043f\u0440\u043e\u0435\u043a\u0442 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u043c\u0438 \u043c\u043e\u0434\u0443\u043b\u044f\u043c\u0438:<\/p>\n<ul>\n<li>\n<p>\u0412 \u043f\u0430\u043f\u043a\u0435 Locators \u0441\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u0434\u0432\u0430 \u0444\u0430\u0439\u043b\u0430: \u043f\u0435\u0440\u0432\u044b\u0439 \u2014 \u0441 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c <strong>market_page.py<\/strong>, \u0432\u0442\u043e\u0440\u043e\u0439 \u2014 \u0441 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c <strong>basket_page.py<\/strong>.<\/p>\n<\/li>\n<li>\n<p>\u0412 \u043f\u0430\u043f\u043a\u0435 pages \u0441\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u0444\u0430\u0439\u043b \u0441 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c <strong>market_main_page.py<\/strong>.<\/p>\n<\/li>\n<li>\n<p>\u0412 \u043f\u0430\u043f\u043a\u0435 Tests \u0441\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u0444\u0430\u0439\u043b \u0441 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c <strong>test_buy_product.py<\/strong>.<\/p>\n<\/li>\n<\/ul>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/e84\/ae2\/164\/e84ae2164895087fa3db012a9e900c4c.png\" width=\"1920\" height=\"1080\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/e84\/ae2\/164\/e84ae2164895087fa3db012a9e900c4c.png\"\/><\/figure>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0432\u0435\u0440\u043d\u0438\u0442\u0435\u0441\u044c \u043d\u0430 \u0441\u0430\u0439\u0442-\u043f\u0435\u0441\u043e\u0447\u043d\u0438\u0446\u0443 <a href=\"https:\/\/www.saucedemo.com\/\"><u>https:\/\/www.saucedemo.com<\/u><\/a> \u0438 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0443\u0439\u0442\u0435\u0441\u044c. \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 \u043b\u043e\u0433\u0438\u043d standard_user, \u043f\u0430\u0440\u043e\u043b\u044c secret_sauce.<\/p>\n<p>\u041d\u0430 \u043e\u0442\u043a\u0440\u044b\u0432\u0448\u0435\u0439\u0441\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435 \u0432\u044b \u0443\u0432\u0438\u0434\u0438\u0442\u0435 \u043a\u0430\u0440\u0442\u043e\u0447\u043a\u0438 \u0442\u043e\u0432\u0430\u0440\u043e\u0432. \u0412\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u043d\u0430\u0432\u0435\u0441\u0442\u0438 \u043c\u044b\u0448\u043a\u043e\u0439 \u043d\u0430 \u043a\u043d\u043e\u043f\u043a\u0443 <strong>Add to cart<\/strong>, \u043d\u0430\u0436\u0430\u0442\u044c \u043f\u0440\u0430\u0432\u0443\u044e \u043a\u043d\u043e\u043f\u043a\u0443 \u043c\u044b\u0448\u0438 \u0438 \u0432\u044b\u0431\u0440\u0430\u0442\u044c <strong>\u041f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043a\u043e\u0434<\/strong>.\u00a0<\/p>\n<p>\u0414\u0430\u043b\u0435\u0435 \u043d\u0430\u0436\u043c\u0438\u0442\u0435 <strong>command + F<\/strong>, \u0447\u0442\u043e\u0431\u044b \u0432\u044b\u0437\u0432\u0430\u0442\u044c \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u0443\u044e \u0441\u0442\u0440\u043e\u043a\u0443 \u043f\u043e html-\u0440\u0430\u0437\u043c\u0435\u0442\u043a\u0435 \u0438 \u0432\u0432\u0435\u0434\u0438\u0442\u0435 \u0432 \u043d\u0435\u0435 <em>button.btn<\/em>. \u0412\u044b \u0443\u0432\u0438\u0434\u0438\u0442\u0435, \u0447\u0442\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u0441 \u0442\u0430\u043a\u0438\u043c \u043b\u043e\u043a\u0430\u0442\u043e\u0440\u043e\u043c \u0446\u0435\u043b\u044b\u0445 \u0448\u0435\u0441\u0442\u044c. \u0417\u043d\u0430\u0447\u0438\u0442, \u043d\u0443\u0436\u043d\u043e \u043e\u0431\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u043a \u043d\u0443\u0436\u043d\u043e\u043c\u0443 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0443 \u043f\u043e \u0438\u043d\u0434\u0435\u043a\u0441\u0443.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/9c3\/108\/5c4\/9c31085c48bd5f6a70d5d484918aa5d6.png\" width=\"1920\" height=\"1048\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/9c3\/108\/5c4\/9c31085c48bd5f6a70d5d484918aa5d6.png\"\/><\/figure>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0435\u0440\u0435\u0439\u0434\u0438\u0442\u0435 \u0432 \u0444\u0430\u0439\u043b <strong>market_page.py<\/strong>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u043f\u0430\u043f\u043a\u0435 Locators, \u0438 \u0434\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u0442\u0443\u0434\u0430 \u043a\u043e\u0434:<\/p>\n<pre><code class=\"python\">class Market:   ADD_TO_CART = \"button.btn\"   FOLLOW_TO_BASKET = \"[id='shopping_cart_container']\"<\/code><\/pre>\n<p>\u0414\u0430\u043b\u0435\u0435 \u0434\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u0432 \u043a\u043e\u0440\u0437\u0438\u043d\u0443 \u043b\u044e\u0431\u043e\u0439 \u0442\u043e\u0432\u0430\u0440. \u0417\u0430\u0442\u0435\u043c \u0432 \u043f\u0440\u0430\u0432\u043e\u043c \u0432\u0435\u0440\u0445\u043d\u0435\u043c \u0443\u0433\u043b\u0443 \u043d\u0430\u0436\u043c\u0438\u0442\u0435 \u043d\u0430 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0442\u0435\u043b\u0435\u0436\u043a\u0438, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0444\u043b\u043e\u0443 \u0441 \u043d\u0430\u0436\u0430\u0442\u0438\u0435\u043c \u043d\u0430 \u043a\u043d\u043e\u043f\u043a\u0443 checkout, \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435\u043c \u0444\u043e\u0440\u043c\u044b \u0438 \u043e\u0444\u043e\u0440\u043c\u043b\u0435\u043d\u0438\u0435\u043c \u043f\u043e\u043a\u0443\u043f\u043a\u0438.\u00a0<\/p>\n<p>\u042f \u0443\u0436\u0435 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u043b \u0432\u0441\u0435 \u043d\u0443\u0436\u043d\u044b\u0435 \u043b\u043e\u043a\u0430\u0442\u043e\u0440\u044b, \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0438\u0445 \u0432 \u0444\u0430\u0439\u043b <strong>basket_page.py<\/strong> \u0432 \u043f\u0430\u043f\u043a\u0435 Locators:<\/p>\n<pre><code class=\"python\">class Basket:     CHECKOUT_BTN = \"[data-test='checkout']\"     FIRST_NAME = \"[data-test='firstName']\"     LAST_NAME = \"[data-test='lastName']\"     ZIP = \"[data-test='postalCode']\"     CNT_BTN = \"[data-test='continue']\"     FINISH_BTN = \"[data-test='finish']\"     FINAL_TEXT = \"\/\/span[text()='Checkout: Complete!']\"<\/code><\/pre>\n<p>\u0414\u0430\u043b\u0435\u0435 \u0434\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u043c\u0435\u0442\u043e\u0434\u044b \u0432 \u0444\u0430\u0439\u043b <strong>market_main_page.py<\/strong> \u0432 \u043f\u0430\u043f\u043a\u0435 pages \u0434\u043b\u044f \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:<\/p>\n<pre><code class=\"python\">from pages.base import Base from Locators.basket_page import Basket from Locators.market_page import Market from data.assertions import Assertions from playwright.sync_api import Page   class MarketPage(Base):     def init(self, page: Page):         super().init(page)         self.assertions = Assertions(page)     def add_to_cart(self):          self.click_element_by_index(Market.ADD_TO_CART, 0)         self.click(Market.FOLLOW_TO_BASKET)      def checkout(self):          self.click(Basket.CHECKOUT_BTN)         self.input(Basket.FIRST_NAME, \"Ivan\")         self.input(Basket.LAST_NAME, \"Ivanov\")         self.input(Basket.ZIP, \"123456\")         self.click(Basket.CNT_BTN)         self.click(Basket.FINISH_BTN)         self.assertions.have_text(Basket.FINAL_TEXT, \"Checkout: Complete!\", \"no\")&lt;\/code>&lt;\/pre>&lt;p><\/code><\/pre>\n<p>\u0414\u0430\u043b\u0435\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0437\u0430\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0444\u0430\u0439\u043b <strong>test_buy_product.py <\/strong>\u0432 \u043f\u0430\u043f\u043a\u0435 Tests \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043a\u043e\u0434\u043e\u043c:<\/p>\n<pre><code class=\"python\">@pytest.mark.regression @pytest.mark.usefixtures('user_login') class TestBuyProduct:     def test_buy_product(self, browser):         p = MarketPage(browser)         p.add_to_cart()         p.checkout()<\/code><\/pre>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/28b\/cc6\/2bc\/28bcc62bc0fcef23cc7e342158f4e642.png\" width=\"1920\" height=\"1056\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/28b\/cc6\/2bc\/28bcc62bc0fcef23cc7e342158f4e642.png\"\/><\/figure>\n<p>\u041a\u0430\u043a \u0432\u044b \u0432\u0438\u0434\u0438\u0442\u0435, \u0432 \u043a\u043e\u0434\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0430 \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u0430 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u043e\u043c \u043a\u043e\u043c\u0430\u043d\u0434\u044b <em><a class=\"mention\" href=\"\/users\/pytest\">@pytest<\/a>.mark.usefixtures(&#8216;user_login&#8217;)<\/em> \u2014 \u043e\u043d\u0430 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c\u0441\u044f \u0434\u043e \u043d\u0430\u0448\u0435\u0439 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438.\u00a0<\/p>\n<p>\u041f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u0432 \u044d\u0442\u043e\u043c \u0443\u0431\u0435\u0434\u0438\u0442\u044c\u0441\u044f, \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0432 \u0430\u0432\u0442\u043e\u0442\u0435\u0441\u0442. \u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u0432 \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b PyCharm \u043a\u043e\u043c\u0430\u043d\u0434\u0443 <em>pytest -s test_buy_product.py <\/em>\u0438 \u043d\u0430\u0436\u043c\u0438\u0442\u0435 Enter.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/d97\/6ed\/163\/d976ed163fd7b4437d3a1b1643cacb73.png\" width=\"1920\" height=\"823\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/d97\/6ed\/163\/d976ed163fd7b4437d3a1b1643cacb73.png\"\/><\/figure>\n<p>\u041e\u0446\u0435\u043d\u0438\u0442\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u0435 \u0430\u0432\u0442\u043e\u0442\u0435\u0441\u0442\u043e\u0432. \u0415\u0441\u043b\u0438 \u0447\u0442\u043e-\u0442\u043e \u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u0441\u044f, \u0441\u0440\u0430\u0432\u043d\u0438\u0442\u0435 \u0441 <a href=\"https:\/\/github.com\/emptyzee\/base_playwright_project\"><u>\u043c\u043e\u0438\u043c \u0438\u0442\u043e\u0433\u043e\u0432\u044b\u043c \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0435\u043c<\/u><\/a>.<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>11. \u041d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u043c CI.<\/summary>\n<div class=\"spoiler__content\">\n<p><em>\u041f\u0440\u0435\u0434\u0443\u0441\u043b\u043e\u0432\u0438\u0435: \u041f\u0435\u0440\u0435\u0434 \u043f\u0440\u043e\u0447\u0442\u0435\u043d\u0438\u0435\u043c \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0440\u0430\u0437\u0434\u0435\u043b\u0430 \u0437\u0430\u043f\u0443\u0448\u0442\u0435 \u0438\u0442\u043e\u0433\u043e\u0432\u044b\u0439 \u043f\u0440\u043e\u0435\u043a\u0442 \u043a \u0441\u0435\u0431\u0435 \u043d\u0430 Git.\u00a0<\/em><\/p>\n<p>\u0412 \u044d\u0442\u043e\u043c \u0440\u0430\u0437\u0434\u0435\u043b\u0435 \u043c\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0435 \u043a\u0440\u0435\u0434\u044b (\u043b\u043e\u0433\u0438\u043d, \u043f\u0430\u0440\u043e\u043b\u044c) \u0432 git-secrets \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u043c CI, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0430\u0432\u0442\u043e\u0442\u0435\u0441\u0442 \u043d\u0430 \u0443\u0434\u0430\u043b\u0435\u043d\u043d\u043e\u043c \u0441\u0435\u0440\u0432\u0435\u0440\u0435.<\/p>\n<p>\u041f\u0435\u0440\u0432\u043e\u0435, \u0447\u0442\u043e \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0443\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u2014 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043b\u043e\u0433\u0438\u043d \u0438 \u043f\u0430\u0440\u043e\u043b\u044c \u0432 git-secrets. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043f\u0435\u0440\u0435\u0439\u0434\u0438\u0442\u0435 \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443 \u0441\u0432\u043e\u0435\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043d\u0430 Git \u0438 \u043d\u0430\u0436\u043c\u0438\u0442\u0435 \u043d\u0430 \u043a\u043d\u043e\u043f\u043a\u0443 Settings.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/017\/370\/4d7\/0173704d7efa844a978a32b775e8035e.png\" width=\"1920\" height=\"832\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/017\/370\/4d7\/0173704d7efa844a978a32b775e8035e.png\"\/><\/figure>\n<p>\u041d\u0430 \u043e\u0442\u043a\u0440\u044b\u0432\u0448\u0435\u0439\u0441\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435 \u0441\u043b\u0435\u0432\u0430, \u0432 \u0440\u0430\u0437\u0434\u0435\u043b\u0435 Security, \u043d\u0430\u0436\u043c\u0438\u0442\u0435 \u043d\u0430 <strong>Secrets and variables<\/strong> \u0438 \u0432 \u0432\u044b\u043f\u0430\u0434\u0430\u0448\u043a\u0435 \u0432\u044b\u0431\u0435\u0440\u0438\u0442\u0435 <strong>Actions<\/strong>.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/d08\/a0c\/773\/d08a0c7733eb0fe4c07483e2b6bed9d9.png\" width=\"1920\" height=\"1080\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/d08\/a0c\/773\/d08a0c7733eb0fe4c07483e2b6bed9d9.png\"\/><\/figure>\n<p>\u0417\u0430\u0442\u0435\u043c \u043d\u0430 \u043e\u0442\u043a\u0440\u044b\u0432\u0448\u0435\u0439\u0441\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435 \u043d\u0430\u0436\u043c\u0438\u0442\u0435 \u043d\u0430 \u0437\u0435\u043b\u0435\u043d\u0443\u044e \u043a\u043d\u043e\u043f\u043a\u0443 <strong>New repository secret<\/strong>.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/dc3\/07f\/92c\/dc307f92cc0c42532126b73b5b041ceb.png\" width=\"1920\" height=\"1061\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/dc3\/07f\/92c\/dc307f92cc0c42532126b73b5b041ceb.png\"\/><\/figure>\n<p>\u0417\u0430\u043f\u043e\u043b\u043d\u0438\u0442\u0435 \u043f\u043e\u043b\u0435 Name: AUTH_LOGIN, \u2014 \u043f\u043e\u043b\u0435 Secret: standart_user, \u2014 \u0437\u0430\u0442\u0435\u043c \u043d\u0430\u0436\u043c\u0438\u0442\u0435 \u043a\u043d\u043e\u043f\u043a\u0443 <strong>Add secret<\/strong>.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/554\/a4f\/b70\/554a4fb703fa925ed8abf3d82592d931.png\" width=\"1920\" height=\"948\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/554\/a4f\/b70\/554a4fb703fa925ed8abf3d82592d931.png\"\/><\/figure>\n<p>\u0410\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u0432\u0442\u043e\u0440\u043e\u0439 <strong>New repository secret<\/strong>. \u0417\u0430\u043f\u043e\u043b\u043d\u0438\u0442\u0435 \u043f\u043e\u043b\u0435 Name: AUTH_PASSWORD, \u2014 \u043f\u043e\u043b\u0435 Secret: secret_sauce, \u2014 \u0437\u0430\u0442\u0435\u043c \u043d\u0430\u0436\u043c\u0438\u0442\u0435 \u043a\u043d\u043e\u043f\u043a\u0443 <strong>Add secret<\/strong>.<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0443 \u0432\u0430\u0441 \u0435\u0441\u0442\u044c \u0434\u0432\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0432 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 secrets, \u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0445\u0440\u0430\u043d\u044f\u0442\u0441\u044f \u043b\u043e\u0433\u0438\u043d \u0438 \u043f\u0430\u0440\u043e\u043b\u044c \u043e\u0442 \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u0439 \u0443\u0447\u0435\u0442\u043a\u0438.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/2b0\/b3f\/e25\/2b0b3fe25ff4e06077057a097c8bcc80.png\" width=\"1920\" height=\"841\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/2b0\/b3f\/e25\/2b0b3fe25ff4e06077057a097c8bcc80.png\"\/><\/figure>\n<p>\u0414\u0430\u043b\u0435\u0435 \u0434\u043b\u044f \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f CI \u0432\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0437\u0430\u0439\u0442\u0438 \u0432 \u0441\u0432\u043e\u0439 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u0438 \u043a\u043b\u0438\u043a\u043d\u0443\u0442\u044c \u043f\u043e \u043a\u043d\u043e\u043f\u043a\u0435 <strong>Actions<\/strong>.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/12d\/52f\/f14\/12d52ff149d49168de83319f79d152b3.png\" width=\"1920\" height=\"512\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/12d\/52f\/f14\/12d52ff149d49168de83319f79d152b3.png\"\/><\/figure>\n<p>\u041d\u0430 \u043e\u0442\u043a\u0440\u044b\u0432\u0448\u0435\u0439\u0441\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435 \u043a\u043b\u0438\u043a\u043d\u0438\u0442\u0435 <strong>Configure<\/strong> \u0432 \u0440\u0430\u0437\u0434\u0435\u043b\u0435 <strong>Publish Python Package<\/strong>.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/b22\/08c\/356\/b2208c356ccf3d95c61b1ae36f61147c.png\" width=\"1920\" height=\"1008\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/b22\/08c\/356\/b2208c356ccf3d95c61b1ae36f61147c.png\"\/><\/figure>\n<p>\u041d\u0430 \u043d\u043e\u0432\u043e\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435 \u0443\u0434\u0430\u043b\u0438\u0442\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0435\u043d\u043d\u043e\u0433\u043e workflow \u0438 \u043f\u043e\u043c\u0435\u043d\u044f\u0439\u0442\u0435 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0443 yml-\u0444\u0430\u0439\u043b\u0430 \u043d\u0430 <strong>regression.yml<\/strong>.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/709\/6ae\/bd3\/7096aebd393253814962873cfd4b3072.png\" width=\"1920\" height=\"685\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/709\/6ae\/bd3\/7096aebd393253814962873cfd4b3072.png\"\/><\/figure>\n<p>\u0417\u0430\u0442\u0435\u043c \u0441\u043a\u043e\u043f\u0438\u0440\u0443\u0439\u0442\u0435 \u0438 \u043f\u0435\u0440\u0435\u043d\u0435\u0441\u0438\u0442\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 CI, \u043f\u0440\u0438\u0432\u0435\u0434\u0435\u043d\u043d\u044b\u0435 \u043d\u0438\u0436\u0435, \u0432 yml-\u0444\u0430\u0439\u043b, \u0438 \u043d\u0430\u0436\u043c\u0438\u0442\u0435 \u043a\u043d\u043e\u043f\u043a\u0443 <strong>Commit changes<\/strong>.<\/p>\n<pre><code class=\"python\">name: TestRegression  on:   #push: {} #  schedule: #    - cron: '0 22 * * *'    workflow_dispatch:     inputs:       environment:         required: true         default: \"prod\"         description: \"Set environment, e.g. `ENV=prod or ENV=shot`\"       arguments:         required: false         default: \"-m regression\"         description: \"pytest additional arguments, e.g. `-m regression`\"   jobs:   playwright:     name: Regression tests     runs-on: ubuntu-latest     container:       image: mcr.microsoft.com\/playwright\/python:v1.41.0-jammy     env:       AUTH_LOGIN: ${{ secrets.AUTH_LOGIN }}       AUTH_PASSWORD: ${{ secrets.AUTH_PASSWORD }}     strategy:       matrix:         browser: [remote_chrome]     outputs:       env_name: ${{ steps.pytest.outputs.env_name }}     steps:       - uses: actions\/checkout@v3       - name: Set up Python         uses: actions\/setup-python@v4         with:           python-version: '3.11'       - name: Install dependencies         run: python3 -m pip install -r requirements.txt       - run: |           if [ \"${{github.event_name}}\" = \"schedule\" ]; then             export args=\"-m regression\"             export ENV=\"prod\"           else             export ENV='${{github.event.inputs.environment}}'             export args='${{github.event.inputs.arguments}}'           fi             echo \"::set-output name=env_name::${ENV:-prod}\"             pytest ${args} --bn ${{ matrix.browser }}<\/code><\/pre>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/2c6\/9ca\/342\/2c69ca342d1c1107bc12e3eebf7a0364.png\" width=\"1920\" height=\"1079\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/2c6\/9ca\/342\/2c69ca342d1c1107bc12e3eebf7a0364.png\"\/><\/figure>\n<p>\u0420\u0430\u0437\u0434\u0435\u043b <strong>on<\/strong> \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 \u0441\u043e\u0431\u044b\u0442\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c workflow.\u00a0<\/p>\n<p>\u0415\u0441\u043b\u0438 \u0432\u044b \u0445\u043e\u0442\u0438\u0442\u0435, \u0447\u0442\u043e\u0431\u044b \u0432\u0430\u0448\u0438 \u0442\u0435\u0441\u0442\u044b \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u043b\u0438\u0441\u044c \u0432 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u043e\u0435 \u0432\u0440\u0435\u043c\u044f, \u0442\u043e \u0440\u0430\u0441\u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0438\u0440\u0443\u0439\u0442\u0435 \u0440\u0430\u0437\u0434\u0435\u043b schedule \u0438 \u043f\u043e\u0434\u0431\u0435\u0440\u0438\u0442\u0435 \u043d\u0443\u0436\u043d\u043e\u0435 \u0432\u0440\u0435\u043c\u044f \u0447\u0435\u0440\u0435\u0437 \u0441\u0435\u0440\u0432\u0438\u0441 <a href=\"https:\/\/crontab.guru\/\"><u>cronitor<\/u><\/a> (\u0438 \u0440\u0430\u0437\u0434\u0435\u043b push \u0442\u043e\u0436\u0435, \u0435\u0441\u043b\u0438 \u0445\u043e\u0442\u0438\u0442\u0435, \u0447\u0442\u043e\u0431\u044b \u0442\u0435\u0441\u0442\u044b \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u043b\u0438\u0441\u044c \u043f\u0440\u0438 \u043f\u0443\u0448\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u0432 \u0432\u0430\u0448 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u043d\u0430 Git).\u00a0<\/p>\n<p><strong>workflow_dispatch<\/strong> \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u043d\u0430\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c workflow \u0432\u0440\u0443\u0447\u043d\u0443\u044e. \u0420\u0430\u0437\u0434\u0435\u043b <strong>jobs <\/strong>\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442, \u043a\u0430\u043a\u0438\u0435 \u0448\u0430\u0433\u0438 \u0434\u043e\u043b\u0436\u043d\u044b \u0431\u044b\u0442\u044c \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u044b \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 workflow, \u0447\u0442\u043e\u0431\u044b \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0430\u0432\u0442\u043e\u0442\u0435\u0441\u0442\u044b \u0441 \u043c\u0435\u0442\u043a\u043e\u0439 <strong>regression<\/strong>. \u0415\u0441\u043b\u0438 \u0432\u044b \u0437\u0430\u0445\u043e\u0442\u0438\u0442\u0435 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0442\u0435\u0441\u0442\u044b \u0441 \u0434\u0440\u0443\u0433\u043e\u0439 \u043c\u0435\u0442\u043a\u043e\u0439, \u043f\u0440\u043e\u0441\u0442\u043e \u0437\u0430\u043c\u0435\u043d\u0438\u0442\u0435 \u043c\u0435\u0442\u043a\u0443 <strong>regression<\/strong> \u0432 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u0430\u0445 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043d\u0430 \u043d\u0443\u0436\u043d\u0443\u044e \u0432\u0430\u043c.<\/p>\n<p>\u0414\u043b\u044f \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441\u043d\u043e\u0432\u0430 \u043a\u043b\u0438\u043a\u043d\u0438\u0442\u0435 \u043f\u043e \u043a\u043d\u043e\u043f\u043a\u0435 <strong>Actions<\/strong>, \u0438 \u043d\u0430 \u043e\u0442\u043a\u0440\u044b\u0432\u0448\u0435\u0439\u0441\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435 \u043a\u043b\u0438\u043a\u043d\u0438\u0442\u0435 \u043f\u043e \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u043e\u043c\u0443 \u043d\u0430\u043c\u0438 workflow. <\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/ff8\/665\/343\/ff86653437031db74bcbfca93b2c486d.png\" width=\"1920\" height=\"976\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/ff8\/665\/343\/ff86653437031db74bcbfca93b2c486d.png\"\/><\/figure>\n<p>\u0417\u0430\u0442\u0435\u043c \u043a\u043b\u0438\u043a\u043d\u0438\u0442\u0435 \u043f\u043e \u043a\u043d\u043e\u043f\u043a\u0435 <strong>Run workflow<\/strong>.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/bf1\/cc3\/0ba\/bf1cc30ba57727fa89554b5a87b118ee.png\" width=\"1920\" height=\"1121\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/bf1\/cc3\/0ba\/bf1cc30ba57727fa89554b5a87b118ee.png\"\/><\/figure>\n<p>\u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e workflow \u0434\u043e\u043b\u0436\u0435\u043d \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c\u0441\u044f.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/ce4\/bd1\/5cf\/ce4bd15cff445c8b3226afe547bda2e0.png\" width=\"1920\" height=\"524\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/ce4\/bd1\/5cf\/ce4bd15cff445c8b3226afe547bda2e0.png\"\/><\/figure>\n<p>\u041c\u043e\u0436\u043d\u043e \u0437\u0430\u0439\u0442\u0438 \u0432 \u043d\u0435\u0433\u043e \u0438 \u043a\u043b\u0438\u043a\u043d\u0443\u0442\u044c \u043f\u043e Job\u2019e, \u0447\u0442\u043e\u0431\u044b \u0441\u043b\u0435\u0434\u0438\u0442\u044c \u0437\u0430 \u0432\u0441\u0435\u043c\u0438 \u044d\u0442\u0430\u043f\u0430\u043c\u0438 workflow.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/b72\/bbe\/42d\/b72bbe42d3c7f8c8a42919df06e93a53.png\" width=\"1920\" height=\"814\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/b72\/bbe\/42d\/b72bbe42d3c7f8c8a42919df06e93a53.png\"\/><\/figure>\n<p>\u0414\u043e\u043b\u0436\u043d\u043e \u043f\u043e\u044f\u0432\u0438\u0442\u0441\u044f \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0435 \u043e\u0431 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u043c \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u0438 \u0430\u0432\u0442\u043e\u0442\u0435\u0441\u0442\u0430.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/df3\/065\/3f4\/df30653f4c522a7168cd09a8e281f4a6.png\" width=\"1920\" height=\"842\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/df3\/065\/3f4\/df30653f4c522a7168cd09a8e281f4a6.png\"\/><\/figure>\n<\/p>\n<\/div>\n<\/details>\n<h2>\u0412\u044b\u0432\u043e\u0434\u044b<\/h2>\n<p>\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043b\u0438 \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043f\u043e \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u0438 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c Python, Pytest \u0438 Playwright. \u041c\u044b \u043d\u0430\u0447\u0430\u043b\u0438 \u0441 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0445 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439, \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0431\u0430\u0437\u043e\u0432\u043e\u0439 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f. \u0417\u0430\u0442\u0435\u043c \u043c\u044b \u0448\u0430\u0433 \u0437\u0430 \u0448\u0430\u0433\u043e\u043c \u0441\u043e\u0437\u0434\u0430\u043b\u0438 \u0430\u0432\u0442\u043e\u0442\u0435\u0441\u0442\u044b, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u043f\u0430\u0442\u0442\u0435\u0440\u043d Page Object \u2014 \u044d\u0442\u043e \u0441\u0434\u0435\u043b\u0430\u043b\u043e \u043d\u0430\u0448 \u043a\u043e\u0434 \u0431\u043e\u043b\u0435\u0435 \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u044b\u043c \u0438 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u043b\u043e \u0435\u0433\u043e \u043b\u0435\u0433\u043a\u043e\u0441\u0442\u044c \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0438.<\/p>\n<p>\u041e\u0434\u043d\u0430\u043a\u043e \u0433\u043b\u0430\u0432\u043d\u043e\u0439 \u0446\u0435\u043d\u043d\u043e\u0441\u0442\u044c\u044e \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0438 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438 \u0430\u0432\u0442\u043e\u0442\u0435\u0441\u0442\u043e\u0432 \u0432 \u0432\u0430\u0448\u0443 CI-\u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0443. \u041c\u044b \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043b\u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443 CI \u0434\u043b\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0442\u0435\u0441\u0442\u043e\u0432, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u0440\u0430\u0437\u043d\u044b\u0435 \u0442\u0440\u0438\u0433\u0433\u0435\u0440\u044b \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u0438.\u00a0<\/p>\n<p>\u041c\u044b \u0442\u0430\u043a\u0436\u0435 \u0432\u044b\u044f\u0432\u0438\u043b\u0438 \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f Playwright \u043f\u0435\u0440\u0435\u0434 Selenium. \u0413\u0438\u0431\u043a\u043e\u0441\u0442\u044c, \u0432\u044b\u0441\u043e\u043a\u0430\u044f \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0438 \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0434\u0435\u043b\u0430\u044e\u0442 Playwright \u043e\u0442\u043b\u0438\u0447\u043d\u044b\u043c \u0432\u044b\u0431\u043e\u0440\u043e\u043c \u0434\u043b\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f.<\/p>\n<p>\u041d\u0430\u0434\u0435\u044e\u0441\u044c, \u0447\u0442\u043e \u044d\u0442\u0430 \u0441\u0442\u0430\u0442\u044c\u044f \u0431\u044b\u043b\u0430 \u0432\u0430\u043c \u043f\u043e\u043b\u0435\u0437\u043d\u0430, \u0441\u043f\u0430\u0441\u0438\u0431\u043e \u0437\u0430 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435! \u0412 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u0440\u0430\u0437\u0431\u0435\u0440\u0443 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044e \u0441 tms qase.io \u0438 \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443, \u043a\u0430\u043a \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0435\u0435 \u0432 CI workflow.<\/p>\n<hr\/>\n<p>\u0421\u0435\u0439\u0447\u0430\u0441 \u0432 \u043d\u0430\u0448\u0443 \u043a\u043e\u043c\u0430\u043d\u0434\u0443 \u043c\u044b \u0438\u0449\u0435\u043c \u0434\u0432\u0443\u0445 \u0438\u043d\u0436\u0435\u043d\u0435\u0440\u043e\u0432 \u043f\u043e \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044e. \u0415\u0441\u043b\u0438 \u0445\u043e\u0447\u0435\u0448\u044c \u0440\u0430\u0437\u0432\u0438\u0432\u0430\u0442\u044c \u0448\u043a\u043e\u043b\u044c\u043d\u044b\u0439 EdTech \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 \u043d\u0430\u043c\u0438, <a href=\"https:\/\/careers.uchi.ru\/remote#development?utm_source=habr&amp;utm_medium=links&amp;utm_campaign=pr_QA_tutorial\">\u043f\u0440\u0438\u0441\u043e\u0435\u0434\u0438\u043d\u044f\u0439\u0441\u044f<\/a>! <\/p>\n<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/780614\/\"> https:\/\/habr.com\/ru\/articles\/780614\/<\/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<figure class=\"full-width\"><\/figure>\n<p>\u041f\u0440\u0438\u0432\u0435\u0442, \u0425\u0430\u0431\u0440! \u041c\u0435\u043d\u044f \u0437\u043e\u0432\u0443\u0442 \u0410\u043b\u0435\u043a\u0441\u0430\u043d\u0434\u0440 \u0411\u0435\u0445\u0442\u0435\u0440\u0435\u0432, \u044f \u0440\u0430\u0431\u043e\u0442\u0430\u044e QA-\u0438\u043d\u0436\u0435\u043d\u0435\u0440\u043e\u043c \u0432 \u0423\u0447\u0438.\u0440\u0443. \u041d\u0435 \u0442\u0430\u043a \u0434\u0430\u0432\u043d\u043e \u043f\u0435\u0440\u0435\u0434 \u043d\u0430\u043c\u0438 \u0432\u0441\u0442\u0430\u043b\u0430 \u0437\u0430\u0434\u0430\u0447\u0430 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0430 \u0441 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 Selenium \u043d\u0430 \u043d\u043e\u0432\u0443\u044e \u0438 \u043c\u043e\u0449\u043d\u0443\u044e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 Playwright. \u0418 \u0442\u043e\u0433\u0434\u0430 \u044f \u0440\u0435\u0448\u0438\u043b \u0432\u0437\u044f\u0442\u044c \u043d\u0430\u0448 \u043f\u0440\u043e\u0435\u043a\u0442 \u043d\u0430 Selenium \u0438 \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u0430\u0442\u044c \u0435\u0433\u043e \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c Playwright. <\/p>\n<p>\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u043f\u043e\u0441\u0442\u0430\u0440\u0430\u044e\u0441\u044c \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043d\u0430 Python, Pytest \u0438 Playwright \u0441 \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0435\u043c \u043f\u0430\u0442\u0442\u0435\u0440\u043d\u0430 Page Object, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043e\u0441\u0442\u0430\u0432\u043b\u044e \u0448\u0430\u0431\u043b\u043e\u043d yml, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0430\u0432\u0442\u043e\u0442\u0435\u0441\u0442\u044b \u0432 CI<\/p>\n<p>\u0412\u0430\u0436\u043d\u043e: \u0434\u0430\u043d\u043d\u0430\u044f \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0430 \u043f\u043e\u0434 MacOS, \u0438 \u043e\u043d\u0430 \u043f\u0440\u0435\u0434\u0443\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0435\u0442, \u0447\u0442\u043e \u0443 \u0432\u0430\u0441 \u0443\u0436\u0435 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0430 IDE \u0438 Python. \u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e PyCharm, Python 3.11 \u0438 \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0439 \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b \u0432 MacOS.<\/p>\n<h2>\u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438  Playwright<\/h2>\n<p>Playwright \u2014 \u044d\u0442\u043e \u043d\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442, \u0430 \u043c\u043e\u0449\u043d\u043e\u0435 \u0441\u0440\u0435\u0434\u0441\u0442\u0432\u043e \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439, \u0434\u0430\u044e\u0449\u0435\u0435 \u0448\u0438\u0440\u043e\u043a\u0438\u0439 \u043d\u0430\u0431\u043e\u0440 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0435\u0439 \u0434\u043b\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 \u0442\u0430\u043a\u0438\u043c\u0438 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430\u043c\u0438, \u043a\u0430\u043a Chrome, Firefox \u0438 WebKit.\u00a0<\/p>\n<p>Playwright \u2014 \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043d\u043e\u0432\u044b\u0439 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u0434\u043b\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f, \u043d\u043e \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u043e\u043d\u0430 \u043e\u0431\u043b\u0430\u0434\u0430\u0435\u0442 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u043c\u0438 \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u0430\u043c\u0438 \u043f\u043e \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044e \u0441 Selenium, \u0442\u0430\u043a\u0438\u043c\u0438 \u043a\u0430\u043a:<\/p>\n<ul>\n<li>\n<p>\u0412\u044b\u0441\u043e\u043a\u0430\u044f \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c.<\/p>\n<\/li>\n<li>\n<p>\u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u0441\u0435\u0442\u0435\u0432\u044b\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b.<\/p>\n<\/li>\n<li>\n<p>\u0413\u0438\u0431\u043a\u043e\u0441\u0442\u044c: \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u0431\u043e\u043b\u044c\u0448\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u044f\u0437\u044b\u043a\u043e\u0432.<\/p>\n<\/li>\n<li>\n<p>\u0423\u0434\u043e\u0431\u0441\u0442\u0432\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f: \u0432 \u043d\u0435\u0439 \u043f\u0440\u0435\u0434\u0443\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u044b \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0435 \u043e\u0436\u0438\u0434\u0430\u043d\u0438\u044f \u0434\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0446\u0435\u043b\u0435\u0432\u044b\u0445 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439 \u0441 \u0432\u0435\u0431-\u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u043c\u0438, \u0430 \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 expect \u0443\u043f\u0440\u043e\u0449\u0430\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0443 \u0441 \u0430\u0441\u0441\u0435\u0440\u0442\u0430\u043c\u0438.<\/p>\n<\/li>\n<\/ul>\n<p><strong>\u0421\u043d\u0438\u0437\u0443 \u043f\u0440\u0438\u0432\u0435\u0434\u0435\u043d\u0430 \u043f\u043e\u0448\u0430\u0433\u043e\u0432\u0430\u044f \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f.<\/strong><\/p>\n<details class=\"spoiler\">\n<summary>1. \u0421\u043e\u0437\u0434\u0430\u0435\u043c \u0438 \u043a\u043b\u043e\u043d\u0438\u0440\u0443\u0435\u043c \u043f\u0443\u0441\u0442\u043e\u0439 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u0441 Git. (\u042d\u0442\u043e\u0442 \u0448\u0430\u0433 \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u043e\u043f\u0443\u0441\u0442\u0438\u0442\u044c, \u0435\u0441\u043b\u0438 \u0445\u043e\u0442\u0438\u0442\u0435 \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e).<\/summary>\n<div class=\"spoiler__content\">\n<p>\u0412\u043e\u0439\u0434\u0438\u0442\u0435 \u0432 \u0441\u0432\u043e\u0439 \u0430\u043a\u043a\u0430\u0443\u043d\u0442 \u043d\u0430 Git (\u0435\u0441\u043b\u0438 \u0443 \u0432\u0430\u0441 \u0435\u0433\u043e \u043d\u0435\u0442, \u043d\u0443\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f). \u041f\u043e\u0441\u043b\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0439 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u043d\u0430\u0436\u043c\u0438\u0442\u0435 \u043d\u0430 \u0441\u0432\u043e\u044e \u0430\u0432\u0430\u0442\u0430\u0440\u043a\u0443 \u0432 \u043f\u0440\u0430\u0432\u043e\u043c \u0432\u0435\u0440\u0445\u043d\u0435\u043c \u0443\u0433\u043b\u0443 \u0438 \u0432\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u0440\u0430\u0437\u0434\u0435\u043b <strong>Your repositories<\/strong> \u0432 \u0432\u044b\u043f\u0430\u0434\u0430\u044e\u0449\u0435\u043c \u043c\u0435\u043d\u044e.<\/p>\n<p>\u0414\u0430\u043b\u0435\u0435 \u043d\u0430\u0436\u043c\u0438\u0442\u0435 \u043a\u043d\u043e\u043f\u043a\u0443 <strong>New<\/strong> \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435 \u0432\u0430\u0448\u0438\u0445 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0435\u0432. \u041d\u0430 \u043e\u0442\u043a\u0440\u044b\u0432\u0448\u0435\u0439\u0441\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435 \u0443\u043a\u0430\u0436\u0438\u0442\u0435 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, pw_autotests) \u0438 \u0435\u0433\u043e \u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u044c (public \u0438\u043b\u0438 private) \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0432\u0430\u0448\u0438\u0445 \u043f\u0440\u0435\u0434\u043f\u043e\u0447\u0442\u0435\u043d\u0438\u0439.\u00a0<\/p>\n<p>\u0414\u0430\u043b\u0435\u0435 \u043d\u0430\u0436\u043c\u0438\u0442\u0435 \u043a\u043d\u043e\u043f\u043a\u0443 <strong>Create repository<\/strong>. \u041f\u043e\u0441\u043b\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f \u0432\u044b \u0443\u0432\u0438\u0434\u0438\u0442\u0435 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443 \u0441 \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f\u043c\u0438 \u043f\u043e \u0435\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044e. \u0412\u0430\u0436\u043d\u043e, \u0447\u0442\u043e \u0437\u0434\u0435\u0441\u044c \u0440\u0430\u0437\u043c\u0435\u0449\u0430\u0435\u0442\u0441\u044f URL \u043d\u0430\u0448\u0435\u0433\u043e \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f.<\/p>\n<figure class=\"full-width\">\n<div><figcaption><em>(\u0420\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 URL \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f)<\/em><\/figcaption><\/div>\n<\/figure>\n<p>\u0427\u0442\u043e\u0431\u044b \u043a\u043b\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u0430\u0448 \u043f\u0443\u0441\u0442\u043e\u0439 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u043d\u0430 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u0443\u044e \u043c\u0430\u0448\u0438\u043d\u0443:<\/p>\n<ol>\n<li>\n<p>\u043e\u0442\u043a\u0440\u043e\u0439\u0442\u0435 \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b (\u0438\u043b\u0438 \u043a\u043e\u043c\u0430\u043d\u0434\u043d\u0443\u044e \u0441\u0442\u0440\u043e\u043a\u0443);<\/p>\n<\/li>\n<li>\n<p>\u043f\u0435\u0440\u0435\u0439\u0434\u0438\u0442\u0435 \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u043a\u043e\u043c\u0430\u043d\u0434\u044b <em>cd<\/em> \u0432 \u0442\u043e\u0442 \u0440\u0430\u0437\u0434\u0435\u043b, \u043a\u0443\u0434\u0430 \u0432\u044b \u0445\u043e\u0442\u0438\u0442\u0435, \u0447\u0442\u043e\u0431\u044b \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u043b\u0441\u044f \u0432\u0430\u0448 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, <em>cd Desktop<\/em>);<\/p>\n<\/li>\n<li>\n<p>\u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u0435 \u043a\u043e\u043c\u0430\u043d\u0434\u0443 <em>git clone<\/em>, \u043f\u0440\u0438\u043b\u043e\u0436\u0438\u0432 \u0441\u0441\u044b\u043b\u043a\u0443 <a href=\"https:\/\/github.com\/your-username\/repository-name.git\"><u>https:\/\/github.com\/your-username\/repository-name.git<\/u><\/a><\/p>\n<\/li>\n<\/ol>\n<p>\u0414\u0430\u043b\u0435\u0435, \u0435\u0441\u043b\u0438 \u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u043f\u043e\u043f\u0440\u043e\u0441\u0438\u0442 \u0432\u0432\u0435\u0441\u0442\u0438 \u043b\u043e\u0433\u0438\u043d \u0438 \u043f\u0430\u0440\u043e\u043b\u044c \u043e\u0442 Git, \u0442\u043e \u0432\u0432\u0435\u0434\u0438\u0442\u0435 \u0438\u0445 \u2014 \u0438 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u0431\u0443\u0434\u0435\u0442 \u0441\u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d \u043d\u0430 \u0432\u0430\u0448 \u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440.<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>2. \u0421\u043e\u0437\u0434\u0430\u0435\u043c \u043f\u0440\u043e\u0435\u043a\u0442 \u0432 PyCharm.<\/summary>\n<div class=\"spoiler__content\">\n<p>\u0415\u0441\u043b\u0438 \u0432\u044b \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u043b\u0438 \u043f\u0443\u043d\u043a\u0442 1, \u043e\u0442\u043a\u0440\u043e\u0439\u0442\u0435 PyCharm \u0438 \u043d\u0430\u0436\u043c\u0438\u0442\u0435 \u043d\u0430 \u043a\u043d\u043e\u043f\u043a\u0443 <strong>Open<\/strong> \u0438 \u043e\u0442\u043a\u0440\u043e\u0439\u0442\u0435 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u044b \u043a\u043b\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043b\u0438 \u0441 Git, \u0435\u0441\u043b\u0438 \u043d\u0435\u0442, \u0442\u043e\u0433\u0434\u0430\u00a0 \u043d\u0430\u0436\u043c\u0438\u0442\u0435 \u043d\u0430 \u043a\u043d\u043e\u043f\u043a\u0443 <strong>New Project<\/strong>.<\/p>\n<figure class=\"full-width\">\n<div><figcaption><em>(\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043d\u043e\u0432\u043e\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430)<\/em><\/figcaption><\/div>\n<\/figure>\n<p>\u0412 \u043f\u043e\u043b\u0435 <strong>New environment using<\/strong> \u0432\u044b\u0431\u0435\u0440\u0438\u0442\u0435 <strong>Virtualenv<\/strong>. \u041f\u043e\u043b\u0435 <strong>Location<\/strong> \u0437\u0430\u043f\u043e\u043b\u043d\u0438\u0442\u0441\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u2014 \u0433\u043b\u0430\u0432\u043d\u043e\u0435, \u0447\u0442\u043e\u0431\u044b \u043f\u0443\u0442\u044c \u0431\u044b\u043b \u0443\u043a\u0430\u0437\u0430\u043d \u0442\u0430\u043a\u043e\u0439 \u0436\u0435, \u043a\u0430\u043a \u0438 \u0432 \u043f\u043e\u043b\u0435<strong> Location<\/strong> \u0432\u044b\u0448\u0435, \u0442\u043e\u043b\u044c\u043a\u043e \u0441 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435\u043c <strong>\/venv<\/strong>.<\/p>\n<p>\u0414\u0430\u043b\u0435\u0435 \u0432 <strong>Base interpreter<\/strong> \u0432\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043d\u044b\u0439 \u043d\u0430 \u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440\u0435 <strong>Python 3.11<\/strong>. \u0421\u043d\u0438\u043c\u0438\u0442\u0435 \u0433\u0430\u043b\u043e\u0447\u043a\u0443 \u0441 <strong>Create a main.py welcome script<\/strong>, \u043e\u043d \u043d\u0435 \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f, \u0438 \u043d\u0430\u0436\u043c\u0438\u0442\u0435 \u043d\u0430 \u043a\u043d\u043e\u043f\u043a\u0443 <strong>Create<\/strong>.<\/p>\n<figure class=\"full-width\"><\/figure>\n<p>\u0412\u044b \u0443\u0432\u0438\u0434\u0438\u0442\u0435, \u0447\u0442\u043e \u043e\u0442\u043a\u0440\u044b\u043b\u0441\u044f \u043d\u043e\u0432\u044b\u0439 \u043f\u0443\u0441\u0442\u043e\u0439 \u043f\u0440\u043e\u0435\u043a\u0442.<\/p>\n<figure class=\"full-width\"><\/figure>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>3. \u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0438 Playwright \u0432 \u043d\u0430\u0448\u0435\u043c \u043d\u043e\u0432\u043e\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435.<\/summary>\n<div class=\"spoiler__content\">\n<p>\u0414\u043b\u044f \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044f\u043c\u0438 \u0438 \u0438\u0445 \u0432\u0435\u0440\u0441\u0438\u044f\u043c\u0438 \u043d\u0443\u0436\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0444\u0430\u0439\u043b <strong>requirements.txt<\/strong> \u0432 \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 \u043f\u0430\u043f\u043a\u0435 \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043a\u043b\u0438\u043a\u043d\u0438\u0442\u0435 \u043f\u0440\u0430\u0432\u043e\u0439 \u043a\u043d\u043e\u043f\u043a\u043e\u0439 \u043c\u044b\u0448\u0438 \u043f\u043e \u043d\u0430\u0448\u0435\u0439 \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 \u043f\u0430\u043f\u043a\u0435 (\u0432 \u043b\u0435\u0432\u043e\u043c \u0432\u0435\u0440\u0445\u043d\u0435\u043c \u0443\u0433\u043b\u0443). \u041e\u0442\u043a\u0440\u043e\u0435\u0442\u0441\u044f \u043c\u0435\u043d\u044e, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043d\u0443\u0436\u043d\u043e \u0432\u044b\u0431\u0440\u0430\u0442\u044c <strong>New\u2192File<\/strong>, \u0432\u0432\u0435\u0441\u0442\u0438 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0444\u0430\u0439\u043b\u0430: requirements.txt \u2014 \u0438 \u043d\u0430\u0436\u0430\u0442\u044c Enter.<\/p>\n<figure class=\"full-width\"><\/figure>\n<p>\u0414\u0430\u043b\u0435\u0435 \u0434\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u0432 \u0444\u0430\u0439\u043b <strong>requirements.txt<\/strong> \u0441\u043f\u0438\u0441\u043e\u043a \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0445 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a \u0438 \u0438\u0445 \u0432\u0435\u0440\u0441\u0438\u0439:<\/p>\n<pre><code class=\"python\">pytest playwright requests qase-pytest==4.2.0 python-dotenv<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043e\u0442\u043a\u0440\u043e\u0439\u0442\u0435 \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b \u0432 PyCharm \u0438 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0435 \u043d\u0430\u0448\u0438 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043a\u043e\u043c\u0430\u043d\u0434\u043e\u0439: <em>python3 -m pip install -r requirements.txt<\/em>.<\/p>\n<p>\u0415\u0441\u043b\u0438 \u043f\u043e \u043a\u0430\u043a\u043e\u0439-\u0442\u043e \u043f\u0440\u0438\u0447\u0438\u043d\u0435 \u043d\u0435 \u0441\u0440\u0430\u0431\u043e\u0442\u0430\u043b\u043e, \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u043a\u043e\u043c\u0430\u043d\u0434\u0443 <em>pip3 install -r requirements.txt<\/em>.<\/p>\n<figure class=\"full-width\"><\/figure>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0434\u0440\u0430\u0439\u0432\u0435\u0440\u044b \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043e\u0432, Playwright \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0438\u0445 \u0434\u043b\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430\u043c\u0438. \u0414\u043b\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0434\u0440\u0430\u0439\u0432\u0435\u0440\u043e\u0432 \u0432\u0432\u043e\u0434\u0438\u043c \u0432 \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b\u0435 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u043a\u043e\u043c\u0430\u043d\u0434\u0443: <em>playwright install<\/em>.\u00a0<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u0448 \u043f\u0440\u043e\u0435\u043a\u0442 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d \u0434\u043b\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f Playwright.<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>4. \u0421\u043e\u0437\u0434\u0430\u0435\u043c \u0442\u0435\u043b\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430.<\/summary>\n<div class=\"spoiler__content\">\n<p>\u0414\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u0432 \u043a\u043e\u0440\u043d\u0435\u0432\u0443\u044e \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0444\u0430\u0439\u043b\u043e\u0432:<\/p>\n<ul>\n<li>\n<p>conftest.py \u2014 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u0430\u043c\u0438.<\/p>\n<\/li>\n<li>\n<p>README.md \u2014 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430.<\/p>\n<\/li>\n<li>\n<p>.gitignore \u2014 \u0432 \u043d\u0435\u043c \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u0444\u0430\u0439\u043b\u044b \u0438 \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 Git \u0431\u0443\u0434\u0435\u0442 \u0438\u0433\u043d\u043e\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u0438 \u043f\u0443\u0448\u0435 \u0432 master. \u042d\u0442\u043e \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u043d\u0435 \u0437\u0430\u0441\u043e\u0440\u044f\u0442\u044c \u043d\u0430\u0448 \u043f\u0440\u043e\u0435\u043a\u0442 \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u043c\u0438 \u0438 \u043d\u0435\u043d\u0443\u0436\u043d\u044b\u043c\u0438 \u0444\u0430\u0439\u043b\u0430\u043c\u0438.<\/p>\n<\/li>\n<li>\n<p>pytest.ini \u2014 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0439 \u0444\u0430\u0439\u043b. \u042f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e \u0435\u0433\u043e \u0434\u043b\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0445 \u043c\u0430\u0440\u043a\u0435\u0440\u043e\u0432 \u0438 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438 \u0441 \u043f\u043b\u0430\u0433\u0438\u043d\u0430\u043c\u0438 \u0438 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f\u043c\u0438. (\u041f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u043c\u0430\u0440\u043a\u0435\u0440\u043e\u0432 \u0443\u0434\u043e\u0431\u043d\u043e \u0440\u0430\u0437\u0434\u0435\u043b\u044f\u0442\u044c \u0430\u0432\u0442\u043e\u0442\u0435\u0441\u0442\u044b, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043d\u0430 smoke \u0438 \u0440\u0435\u0433\u0440\u0435\u0441\u0441\u0438\u043e\u043d\u043d\u044b\u0435 \u2014 \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u0438 \u043f\u0440\u043e\u0433\u043e\u043d\u044f\u0442\u044c\u0441\u044f \u0431\u0443\u0434\u0443\u0442 \u043d\u0443\u0436\u043d\u044b\u0435 \u043d\u0430\u043c \u0442\u0435\u0441\u0442\u044b). <\/p>\n<\/li>\n<\/ul>\n<figure class=\"full-width\"><\/figure>\n<p>\u0421\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u0434\u043b\u044f \u0444\u0430\u0439\u043b\u0430 <strong>.gitignore<\/strong> \u044f \u0443\u0436\u0435 \u0437\u0430\u0440\u0430\u043d\u0435\u0435 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u043b: \u0432\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u0435\u0440\u0435\u0439\u0442\u0438 \u043f\u043e <a href=\"https:\/\/github.com\/emptyzee\/base_playwright_project\/blob\/main\/.gitignore\"><u>\u0441\u0441\u044b\u043b\u043a\u0435<\/u><\/a>, \u0441\u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0435\u0433\u043e \u0438 \u043f\u0435\u0440\u0435\u043d\u0435\u0441\u0442\u0438 \u0432 \u0441\u0432\u043e\u0439 \u043f\u0440\u043e\u0435\u043a\u0442 \u0432 \u0444\u0430\u0439\u043b \u0441 \u044d\u0442\u0438\u043c \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c.<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0437\u0430\u043f\u043e\u043b\u043d\u0438\u043c \u0444\u0430\u0439\u043b <strong>pytest.ini<\/strong>:<\/p>\n<pre><code class=\"python\">[pytest] markers =     regression: run regression tests addopts = -v -s<\/code><\/pre>\n<figure class=\"full-width\"><\/figure>\n<p>\u0427\u0442\u043e\u0431\u044b \u0431\u044b\u043b\u043e \u0443\u0434\u043e\u0431\u043d\u0435\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u043d\u0430\u0434 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u043c, \u0441\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u0430\u043f\u043e\u043a \u0432 \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438:<\/p>\n<ul>\n<li>\n<p>Locators \u2014 \u0442\u0443\u0442 \u0431\u0443\u0434\u0443\u0442 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u044c\u0441\u044f \u043b\u043e\u043a\u0430\u0442\u043e\u0440\u044b \u0434\u043b\u044f \u0440\u0430\u0437\u043d\u044b\u0445 \u0441\u0442\u0440\u0430\u043d\u0438\u0446.<\/p>\n<\/li>\n<li>\n<p>data \u2014 \u0442\u0443\u0442 \u0431\u0443\u0434\u0443\u0442 \u0445\u0440\u0430\u043d\u0438\u0442\u044c\u0441\u044f \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435, \u043a\u043e\u043d\u0441\u0442\u0430\u043d\u0442\u044b, \u0430\u0441\u0441\u0435\u0440\u0442\u044b.<\/p>\n<\/li>\n<li>\n<p>fixtures \u2014 \u0442\u0443\u0442 \u0431\u0443\u0434\u0443\u0442 \u0440\u0430\u0441\u043f\u043e\u043b\u0430\u0433\u0430\u0442\u044c\u0441\u044f \u043c\u043e\u0434\u0443\u043b\u0438 \u0441 \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u0430\u043c\u0438 Pytest.<\/p>\n<\/li>\n<li>\n<p>pages \u2014 \u0437\u0434\u0435\u0441\u044c \u0431\u0443\u0434\u0443\u0442 \u0445\u0440\u0430\u043d\u0438\u0442\u044c\u0441\u044f \u0444\u0430\u0439\u043b\u044b \u0441 \u043c\u0435\u0442\u043e\u0434\u0430\u043c\u0438 \u0434\u043b\u044f \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 \u0432\u0435\u0431-\u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b.<\/p>\n<\/li>\n<li>\n<p>tests \u2014 \u0437\u0434\u0435\u0441\u044c \u0431\u0443\u0434\u0443\u0442 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u044c\u0441\u044f \u0430\u0432\u0442\u043e\u0442\u0435\u0441\u0442\u044b.<\/p>\n<\/li>\n<\/ul>\n<figure class=\"full-width\"><\/figure>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0437\u0430\u043f\u043e\u043b\u043d\u0438\u0442\u0435 \u0444\u0430\u0439\u043b <strong>conftest.py<\/strong>:<\/p>\n<pre><code class=\"python\">pytest_plugins = [     'fixtures.page' ]<\/code><\/pre>\n<p>\u0422\u0443\u0442 \u043d\u0443\u0436\u043d\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u043f\u0443\u0442\u044c, \u043e\u0442\u043a\u0443\u0434\u0430 \u0434\u043e\u043b\u0436\u043d\u044b \u043f\u043e\u0434\u0433\u0440\u0443\u0436\u0430\u0442\u044c\u0441\u044f \u043c\u043e\u0434\u0443\u043b\u0438 \u0441 \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u0430\u043c\u0438 (\u0434\u043b\u044f \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430 \u043c\u043e\u0434\u0443\u043b\u0438 \u0441 \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u0430\u043c\u0438 \u043b\u0443\u0447\u0448\u0435 \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0439 \u043f\u0430\u043f\u043a\u0435).<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>5. \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043c\u043e\u0434\u0443\u043b\u044c page. <\/summary>\n<div class=\"spoiler__content\">\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0432 \u043f\u0430\u043f\u043a\u0435 fixtures \u0441\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u0444\u0430\u0439\u043b <strong>page.py<\/strong>.<\/p>\n<figure class=\"full-width\"><\/figure>\n<p>\u0423 \u043c\u0435\u043d\u044f \u0443\u0436\u0435 \u0437\u0430\u0433\u043e\u0442\u043e\u0432\u043b\u0435\u043d \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u044b\u0439 \u043c\u043e\u0434\u0443\u043b\u044c page, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0430\u0432\u0442\u043e\u0442\u0435\u0441\u0442\u044b \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430\u0445 Chrome, Firefox \u0438 Chrome \u043d\u0430 \u0443\u0434\u0430\u043b\u0435\u043d\u043d\u043e\u043c \u0441\u0435\u0440\u0432\u0435\u0440\u0435. \u0412\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u0435\u0440\u0435\u0439\u0442\u0438 \u043f\u043e \u0441\u0441\u044b\u043b\u043a\u0435 \u0432 <a href=\"https:\/\/github.com\/emptyzee\/base_playwright_project\/blob\/main\/fixtures\/page.py\"><u>\u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439<\/u><\/a> \u0438 \u0441\u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u043c\u043e\u0434\u0443\u043b\u044f <strong>page.py <\/strong>\u043a \u0441\u0435\u0431\u0435 \u0432 \u043f\u0440\u043e\u0435\u043a\u0442. <\/p>\n<figure class=\"full-width\"><\/figure>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>6. \u0421\u043e\u0437\u0434\u0430\u0435\u043c \u043c\u043e\u0434\u0443\u043b\u044c \u0441 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u043c\u0438 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f.<\/summary>\n<div class=\"spoiler__content\">\n<p>\u0412 \u044d\u0442\u043e\u043c \u0440\u0430\u0437\u0434\u0435\u043b\u0435 \u043f\u043e\u043a\u0430\u0436\u0443, \u043a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u0443\u043f\u0440\u043e\u0441\u0442\u0438\u0442\u044c \u0440\u0430\u0431\u043e\u0442\u0443 \u0441 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f\u043c\u0438. \u0414\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u044f \u0432\u0437\u044f\u043b \u0441\u0430\u0439\u0442-\u043f\u0435\u0441\u043e\u0447\u043d\u0438\u0446\u0443 <a href=\"https:\/\/saucedemo.com\/\"><u>https:\/\/saucedemo.com<\/u><\/a>, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0442\u0430\u043c \u0435\u0441\u0442\u044c \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f \u2014 \u0430 \u044d\u0442\u043e \u0445\u043e\u0440\u043e\u0448\u0430\u044f \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u043c\u043e\u0434\u0443\u043b\u044c \u0441 \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u043e\u0439 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c \u043f\u0435\u0440\u0435\u0434 \u0437\u0430\u043f\u0443\u0441\u043a\u043e\u043c \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0445 \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0439.\u00a0<\/p>\n<p>\u041d\u043e \u044d\u0442\u043e \u043c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0434\u0430\u043b\u044c\u0448\u0435, \u0430 \u0441\u0435\u0439\u0447\u0430\u0441 \u0432\u0435\u0440\u043d\u0435\u043c\u0441\u044f \u043a \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f. \u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0441\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u0432 \u043f\u0430\u043f\u043a\u0435 data \u0444\u0430\u0439\u043b \u0441 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c <strong>environment.py.<\/strong><\/p>\n<figure class=\"full-width\"><\/figure>\n<p>\u0418 \u0434\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u0432 \u043d\u0435\u0433\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u043a\u043e\u0434:<\/p>\n<pre><code class=\"python\">import os  class Environment:     SHOT = 'shot'     PROD = 'prod'      URLS = {         SHOT: 'https:\/\/example.ru\/',         PROD: 'https:\/\/saucedemo.com\/'     }      def __init__(self):         try:             self.env = os.getenv('ENV')         except KeyError:             self.env = self.PROD      def get_base_url(self):         if self.env in self.URLS:             return self.URLS[self.env]         else:             raise Exception(f\"Unknown value of ENV variable {self.env}\")  host = Environment()<\/code><\/pre>\n<p>\u041a\u043b\u0430\u0441\u0441 Environment \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435\u043c \u0438 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u0431\u0430\u0437\u043e\u0432\u043e\u0433\u043e URL \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f. \u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u0435\u0441\u043b\u0438 \u0432\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0433\u043d\u0430\u0442\u044c \u0432\u0430\u0448\u0438 \u0430\u0432\u0442\u043e\u0442\u0435\u0441\u0442\u044b \u043d\u0430 \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u043c \u0438\u043b\u0438 \u043f\u0440\u043e\u0434\u043e\u0432\u043e\u043c \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0438, \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u043e\u0434\u0441\u0442\u0430\u0432\u044c\u0442\u0435 \u0441\u0432\u043e\u0438 urls \u0432 \u0441\u043b\u043e\u0432\u0430\u0440\u0435 URLS \u0438 \u0443\u043a\u0430\u0436\u0438\u0442\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435 ENV=prod \u0438\u043b\u0438 ENV=shot \u0447\u0435\u0440\u0435\u0437 \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b \u0432 PyCharm \u043a\u043e\u043c\u0430\u043d\u0434\u043e\u0439 export ENV=prod (\u0434\u043b\u044f MacOS).<\/p>\n<p>\u041d\u043e \u044f \u0441\u043e\u0432\u0435\u0442\u0443\u044e \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0432\u0441\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u0438\u0437 \u0444\u0430\u0439\u043b\u0430 <strong>.env<\/strong> \u043f\u0443\u0442\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 <strong>python-dotenv<\/strong>. \u0412\u044b \u0435\u0435, \u043a\u0441\u0442\u0430\u0442\u0438, \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043b\u0438 \u0432 \u0441\u0430\u043c\u043e\u043c \u043d\u0430\u0447\u0430\u043b\u0435! \ud83d\ude42<\/p>\n<p>\u041e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f:<\/p>\n<ul>\n<li>\n<p>\u0421\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u0432 \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 \u0444\u0430\u0439\u043b \u0441 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c <strong>.env<\/strong>.<\/p>\n<\/li>\n<li>\n<p>\u041d\u0430\u043f\u0438\u0448\u0438\u0442\u0435 \u0432 \u044d\u0442\u043e\u043c \u0432 \u0444\u0430\u0439\u043b\u0435 ENV=prod (\u0435\u0441\u043b\u0438 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e \u043d\u0443\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u043d\u0430 \u0448\u043e\u0442\u0435, \u0442\u043e \u0432\u043c\u0435\u0441\u0442\u043e prod \u043d\u0430\u043f\u0438\u0448\u0438\u0442\u0435 shot).<\/p>\n<\/li>\n<\/ul>\n<figure class=\"full-width\"><\/figure>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c, \u0447\u0442\u043e\u0431\u044b \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u043f\u043e\u0434\u0433\u0440\u0443\u0436\u0430\u043b\u0438\u0441\u044c \u043f\u0440\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u0430\u0432\u0442\u043e\u0442\u0435\u0441\u0442\u043e\u0432, \u0432\u043d\u0435\u0441\u0438\u0442\u0435 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0438\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432 \u0444\u0430\u0439\u043b <strong>conftest.py<\/strong>. \u041e\u0442\u043a\u0440\u043e\u0439\u0442\u0435 \u0435\u0433\u043e \u0438 \u0434\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u0442\u0443\u0434\u0430 \u043a\u043e\u0434: <\/p>\n<pre><code class=\"python\">from dotenv import load_dotenv   load_dotenv() <\/code><\/pre>\n<p>\u042d\u0442\u043e \u043d\u0443\u0436\u043d\u043e, \u0447\u0442\u043e\u0431\u044b \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f (\u0442\u0430\u043a\u0438\u0435 \u043a\u0430\u043a \u043b\u043e\u0433\u0438\u043d\u044b, \u043f\u0430\u0440\u043e\u043b\u0438, api tokens) \u043d\u0435 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0441\u044c \u0432 \u043a\u043e\u0434\u0435, \u0430 \u043f\u043e\u0434\u0433\u0440\u0443\u0436\u0430\u043b\u0438\u0441\u044c \u0438\u0437 \u0444\u0430\u0439\u043b\u0430 <strong>.env<\/strong>. \u042d\u0442\u043e \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u0445 \u043f\u0440\u043e\u0433\u043e\u043d\u043e\u0432; \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0447\u0435\u0440\u0435\u0437 CI \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u0445\u0440\u0430\u043d\u0438\u0442\u044c\u0441\u044f \u0438 \u043f\u043e\u0434\u0442\u044f\u0433\u0438\u0432\u0430\u0442\u044c\u0441\u044f \u0438\u0437 git-secrets.<\/p>\n<figure class=\"full-width\"><\/figure>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>7. \u0421\u043e\u0437\u0434\u0430\u0435\u043c \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0439 \u043a\u043b\u0430\u0441\u0441 base \u0434\u043b\u044f \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 \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430\u0445 \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439.<\/summary>\n<div class=\"spoiler__content\">\n<p>\u0421\u0435\u0439\u0447\u0430\u0441 \u043f\u043e\u043a\u0430\u0436\u0443, \u043a\u0430\u043a \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0438 \u0437\u0430\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0431\u0430\u0437\u043e\u0432\u044b\u0439 \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0439 \u043c\u043e\u0434\u0443\u043b\u044c base. \u0412 \u043d\u0435\u043c \u0445\u0440\u0430\u043d\u044f\u0442\u0441\u044f \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043c\u0435\u0442\u043e\u0434\u044b, \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0441 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u043c\u0438 \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430\u0445 \u0432\u0435\u0431-\u0441\u0430\u0439\u0442\u043e\u0432.<\/p>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0432 \u043f\u0430\u043f\u043a\u0435 pages \u0441\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u0444\u0430\u0439\u043b <strong>base.py<\/strong>.<\/p>\n<figure class=\"full-width\"><\/figure>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0437\u0430\u043f\u043e\u043b\u043d\u0438\u0442\u0435 \u0435\u0433\u043e \u043a\u043e\u0434\u043e\u043c.<\/p>\n<ul>\n<li>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u0439\u0442\u0435 \u043a\u043b\u0430\u0441\u0441\u044b Page, TimeoutError, Response \u0438\u0437 \u043c\u043e\u0434\u0443\u043b\u044f<strong> playwright.sync_api<\/strong>; \u043a\u043b\u0430\u0441\u0441 host \u0438\u0437 \u0440\u0430\u043d\u0435\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u043e\u0433\u043e \u043c\u043e\u0434\u0443\u043b\u044f environment.<\/p>\n<\/li>\n<\/ul>\n<pre><code class=\"python\">from playwright.sync_api import Page, TimeoutError, Response from data.environment import host<\/code><\/pre>\n<ul>\n<li>\n<p>\u0421\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u0441\u0430\u043c \u043a\u043b\u0430\u0441\u0441 Base \u0438 \u0434\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 \u043a\u043b\u0430\u0441\u0441\u0430, \u0443 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0431\u0443\u0434\u0435\u0442 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u043d\u0430 \u0432\u0445\u043e\u0434 \u043a\u043b\u0430\u0441\u0441 Page \u0438\u0437 \u043c\u043e\u0434\u0443\u043b\u044f\u00a0 <strong>playwright.sync_api<\/strong>. \u041f\u043e\u0442\u043e\u043c \u0441\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u0432\u043d\u0443\u0442\u0440\u0438 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0430 \u043a\u043b\u0430\u0441\u0441\u0430 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 \u043a\u043b\u0430\u0441\u0441\u0430 Page, \u0447\u0442\u043e\u0431\u044b \u043e\u043d \u0431\u044b\u043b \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0432\u043e \u0432\u0441\u0435\u0445 \u043c\u0435\u0442\u043e\u0434\u0430\u0445 \u043a\u043b\u0430\u0441\u0441\u0430 Base, \u0447\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u043d\u0430\u043c \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u043d\u0430 \u0432\u0435\u0431-\u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430\u0445.<\/p>\n<\/li>\n<\/ul>\n<pre><code class=\"python\">class Base:     def __init__(self, page: Page):         self.page = page<\/code><\/pre>\n<p>\u0414\u0430\u043b\u0435\u0435 \u043d\u0443\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043c\u0435\u0442\u043e\u0434\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0440\u0438\u0433\u043e\u0434\u044f\u0442\u0441\u044f \u0434\u043b\u044f \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u043f\u0440\u043e\u0441\u0442\u043e\u0433\u043e e2e-\u0430\u0432\u0442\u043e\u0442\u0435\u0441\u0442\u0430 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u0430-\u043f\u0435\u0441\u043e\u0447\u043d\u0438\u0446\u044b. \u0412\u043e\u043e\u0431\u0449\u0435, \u044f \u043d\u0430\u043f\u0438\u0441\u0430\u043b \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043c\u043d\u043e\u0433\u043e \u0440\u0430\u0437\u043d\u044b\u0445 \u043c\u0435\u0442\u043e\u0434\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0440\u0438\u0433\u043e\u0434\u044f\u0442\u0441\u044f \u0432\u0430\u043c \u0432 \u0431\u0443\u0434\u0443\u0449\u0435\u043c. \u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0437\u0430\u0431\u0440\u0430\u0442\u044c \u0438\u0445 \u0438\u0437 \u043c\u043e\u0435\u0433\u043e <a href=\"https:\/\/github.com\/emptyzee\/base_playwright_project\/blob\/main\/pages\/base.py\">\u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f<\/a> \u043d\u0430 Git \u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432 \u0444\u0430\u0439\u043b <strong>base.py<\/strong>.<\/p>\n<p>\u0420\u0430\u0437\u0431\u0435\u0440\u0443 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u0438\u0437 \u043d\u0438\u0445.<\/p>\n<p><strong>\u041c\u0435\u0442\u043e\u0434 open <\/strong>\u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0435\u0442 \u043f\u0435\u0440\u0435\u0445\u043e\u0434 \u043d\u0430 \u0432\u0435\u0431-\u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443:<\/p>\n<pre><code class=\"python\">def open(self, uri) -> Response | None:     return self.page.goto(f\"{host.get_base_url()}{uri}\",      wait_until='domcontentloaded')<\/code><\/pre>\n<p><strong>\u041c\u0435\u0442\u043e\u0434 input<\/strong> \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0435\u0442 \u0432\u0432\u043e\u0434 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u0432 \u043f\u043e\u043b\u0435 \u0432\u0432\u043e\u0434\u0430:<\/p>\n<pre><code class=\"python\">def input(self, locator, data: str) -> None:      self.page.locator(locator).fill(data)<\/code><\/pre>\n<p><strong>\u041c\u0435\u0442\u043e\u0434 click <\/strong>\u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0435\u0442 \u043a\u043b\u0438\u043a \u043f\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0443:<\/p>\n<pre><code class=\"python\">def click(self, locator) -> None: #     self.page.click(locator)<\/code><\/pre>\n<p><strong>\u041c\u0435\u0442\u043e\u0434 get_text<\/strong> \u0434\u043e\u0441\u0442\u0430\u0435\u0442 \u0442\u0435\u043a\u0441\u0442 \u0438\u0437 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430 \u043f\u043e \u043b\u043e\u043a\u0430\u0442\u043e\u0440\u0443:<\/p>\n<pre><code class=\"python\">def get_text(self, element) -> str: #         return<\/code><\/pre>\n<\/div>\n<\/details>\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-362931","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/362931","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=362931"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/362931\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=362931"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=362931"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=362931"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}