{"id":461011,"date":"2025-05-26T09:09:38","date_gmt":"2025-05-26T09:09:38","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=461011"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=461011","title":{"rendered":"<span>\u041a\u0430\u043a \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0439 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0441 \u043d\u0443\u043b\u044f \u043d\u0430 Playwright<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u041c\u0435\u043d\u044f \u0437\u043e\u0432\u0443\u0442 \u0420\u043e\u043c\u0430\u043d. \u042f SDET-\u0441\u043f\u0435\u0446\u0438\u0430\u043b\u0438\u0441\u0442 \u0432 \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u0438 SimbirSoft. \u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043f\u043e\u0434\u0435\u043b\u044e\u0441\u044c \u0441\u0432\u043e\u0438\u043c \u043e\u043f\u044b\u0442\u043e\u043c \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u0433\u043e \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430 \u0441 \u043d\u0443\u043b\u044f \u0434\u043b\u044f \u043e\u0434\u043d\u043e\u0433\u043e \u0438\u0437 \u043d\u0430\u0448\u0438\u0445 \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432. \u041c\u0430\u0442\u0435\u0440\u0438\u0430\u043b \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043b\u0435\u0437\u0435\u043d \u0434\u043b\u044f \u043d\u0430\u0447\u0438\u043d\u0430\u044e\u0449\u0438\u0445 \u0438\u043b\u0438 \u0443\u0436\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u0438\u0441\u0442\u043e\u0432 \u0432 \u043e\u0431\u043b\u0430\u0441\u0442\u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0445\u043e\u0442\u044f\u0442 \u0431\u043e\u043b\u044c\u0448\u0435 \u0443\u0437\u043d\u0430\u0442\u044c:\u00a0<\/p>\n<p>\u2013 \u043e \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u0438 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u0438 \u0441 \u0441\u0430\u043c\u043e\u0433\u043e \u043d\u0430\u0447\u0430\u043b\u0430;\u00a0<\/p>\n<p>\u2013 \u043e \u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u044f\u0445, \u0441 \u043a\u043e\u0442\u043e\u0440\u044b\u043c\u0438 \u043c\u043e\u0436\u0435\u0442 \u0441\u0442\u043e\u043b\u043a\u043d\u0443\u0442\u044c\u0441\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0442\u043e\u0440;<\/p>\n<p>\u2013 \u043e\u0431 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430\u0445 \u0434\u043b\u044f \u043f\u043e\u0434\u0445\u043e\u0434\u044f\u0449\u0435\u0433\u043e \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u043f\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0445 \u043f\u0435\u0440\u0435\u0434 \u043d\u0438\u043c \u0437\u0430\u0434\u0430\u0447.<\/p>\n<p>\u0422\u0430\u043a\u0436\u0435 \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u044e \u0441\u0432\u043e\u044e \u0441\u0442\u0430\u0442\u044c\u044e \u0442\u0435\u043c \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u0438\u0441\u0442\u0430\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0443\u0436\u0435 \u043e\u0431\u043b\u0430\u0434\u0430\u044e\u0442 \u0431\u0430\u0437\u043e\u0432\u044b\u043c\u0438 \u0437\u043d\u0430\u043d\u0438\u044f\u043c\u0438 Python \u0438 Docker \u0438 \u0441\u0442\u0440\u0435\u043c\u044f\u0442\u0441\u044f \u0443\u0433\u043b\u0443\u0431\u0438\u0442\u044c \u0441\u0432\u043e\u0438 \u043d\u0430\u0432\u044b\u043a\u0438 \u0432 \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><strong>\u0421\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435<\/strong><\/p>\n<p><a href=\"#0\">\u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435<\/a><\/p>\n<p><a href=\"#1\">\u041e\u0431\u0437\u043e\u0440 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0439<\/a><\/p>\n<p><a href=\"#2\">\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b<\/a><\/p>\n<p><a href=\"#3\">\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/a><\/p>\n<p><a href=\"#4\">\u2022 Driver \u0438 BaseElement<\/a><\/p>\n<p><a href=\"#5\">\u2022 Page object<\/a><\/p>\n<p><a href=\"#6\">\u2022 UI-\u0442\u0435\u0441\u0442\u044b<\/a><\/p>\n<p><a href=\"#7\">\u2022 API-\u0442\u0435\u0441\u0442\u044b<\/a><\/p>\n<p><a href=\"#8\">\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/a><\/p>\n<p><a class=\"anchor\" name=\"0\" id=\"0\"><\/a><\/p>\n<p>\u0420\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0435\u043c\u044b\u0439 \u043f\u0440\u043e\u0435\u043a\u0442 \u2014 \u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u0430\u043c\u0438, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440\u0430\u043c \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u0442\u044c \u0437\u0430\u043d\u044f\u0442\u043e\u0441\u0442\u044c \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u043e\u0432, \u0438\u0445 \u043a\u043e\u043c\u043f\u0435\u0442\u0435\u043d\u0446\u0438\u0438 \u0438 \u0434\u0440\u0443\u0433\u0443\u044e \u043a\u043b\u044e\u0447\u0435\u0432\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e.<\/p>\n<p>\u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043f\u0440\u043e\u0435\u043a\u0442 \u0430\u043a\u0442\u0438\u0432\u043d\u043e \u0440\u0430\u0437\u0432\u0438\u0432\u0430\u043b\u0441\u044f \u0432 \u0442\u0435\u0447\u0435\u043d\u0438\u0435 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0433\u043e \u0433\u043e\u0434\u0430, \u0442\u043e QA-\u0441\u043f\u0435\u0446\u0438\u0430\u043b\u0438\u0441\u0442\u0443 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u043b\u043e\u0441\u044c \u0442\u0440\u0430\u0442\u0438\u0442\u044c \u0431\u043e\u043b\u044c\u0448\u0435 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u043d\u0430 \u043f\u0440\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u0440\u0435\u0433\u0440\u0435\u0441\u0441\u0438\u043e\u043d\u043d\u044b\u0445 \u0442\u0435\u0441\u0442\u043e\u0432 \u043f\u043e\u0441\u043b\u0435 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0440\u0435\u043b\u0438\u0437\u0430. \u0420\u0435\u0448\u0435\u043d\u0438\u0435 \u044d\u0442\u043e\u0439 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u0431\u044b\u043b\u043e \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0435\u043d\u043e \u043c\u043d\u0435. \u0417\u0430\u0434\u0430\u0447\u0430 \u043c\u043d\u0435 \u0441\u0440\u0430\u0437\u0443 \u043f\u043e\u043a\u0430\u0437\u0430\u043b\u0430\u0441\u044c \u0437\u0430\u043c\u0430\u043d\u0447\u0438\u0432\u043e\u0439, \u0432\u0435\u0434\u044c \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430 \u0441 \u043d\u0443\u043b\u044f \u2013 \u044d\u0442\u043e \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043f\u043e\u043f\u0440\u043e\u0431\u043e\u0432\u0430\u0442\u044c \u043d\u043e\u0432\u044b\u0435 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b, \u043f\u0440\u0438\u043e\u0431\u0440\u0435\u0441\u0442\u0438 \u043d\u043e\u0432\u044b\u0435 \u0437\u043d\u0430\u043d\u0438\u044f \u0438 \u043d\u0430\u0432\u044b\u043a\u0438. \u041d\u0435 \u0434\u043e\u043b\u0433\u043e \u0434\u0443\u043c\u0430\u044f, \u044f \u0432\u0437\u044f\u043b\u0441\u044f \u0437\u0430 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0445 \u0438\u0434\u0435\u0439.<\/p>\n<p>\u0417\u0430\u0434\u0430\u0447\u0430 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043d\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0441 \u0441\u0430\u043c\u043e\u0433\u043e \u043d\u0430\u0447\u0430\u043b\u0430 \u043e\u0431\u0435\u0449\u0430\u043b\u0430 \u0431\u044b\u0442\u044c \u043d\u0435\u043f\u0440\u043e\u0441\u0442\u043e\u0439: \u0434\u043e \u0442\u043e\u0433\u043e \u043a\u0430\u043a \u044f \u043f\u0440\u0438\u0441\u043e\u0435\u0434\u0438\u043d\u0438\u043b\u0441\u044f \u043a \u043a\u043e\u043c\u0430\u043d\u0434\u0435, \u0432\u0441\u044f \u0442\u0435\u0441\u0442\u043e\u0432\u0430\u044f \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f \u0445\u0440\u0430\u043d\u0438\u043b\u0430\u0441\u044c \u0438\u0441\u043a\u043b\u044e\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0432 \u0433\u043e\u043b\u043e\u0432\u0435 \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0433\u043e QA-\u0441\u043f\u0435\u0446\u0438\u0430\u043b\u0438\u0441\u0442\u0430. \u0421\u0438\u0441\u0442\u0435\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043d\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u043d\u0435 \u0431\u044b\u043b\u043e, \u043d\u043e\u0432\u044b\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u043b\u0441\u044f \u00ab\u043d\u0430 \u043b\u0435\u0442\u0443\u00bb. \u042d\u0442\u043e \u043f\u043e\u0440\u043e\u0436\u0434\u0430\u043b\u043e \u0440\u044f\u0434 \u0432\u043e\u043f\u0440\u043e\u0441\u043e\u0432: \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0438 \u0446\u0435\u043b\u0435\u0441\u043e\u043e\u0431\u0440\u0430\u0437\u043d\u043e \u043b\u0438 \u0432\u043d\u0435\u0434\u0440\u0435\u043d\u0438\u0435 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u0438 \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u043a\u0430\u043a \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u043a\u043e\u043c\u043f\u043b\u0435\u043a\u0441 \u0442\u0435\u0441\u0442-\u043a\u0435\u0439\u0441\u043e\u0432 \u0431\u0435\u0437 \u043d\u0430\u043b\u0438\u0447\u0438\u044f \u0444\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e\u0439 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 \u0438 \u043a\u0430\u043a\u043e\u0432\u044b \u043e\u0436\u0438\u0434\u0430\u043d\u0438\u044f \u043e\u0442 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u0438 \u0432 \u0446\u0435\u043b\u043e\u043c? \u0412\u0441\u0435 \u044d\u0442\u043e \u0432\u043e\u043f\u0440\u043e\u0441\u044b, \u043d\u0435 \u0438\u043c\u0435\u044e\u0449\u0438\u0435 \u043e\u0434\u043d\u043e\u0437\u043d\u0430\u0447\u043d\u043e\u0433\u043e \u043e\u0442\u0432\u0435\u0442\u0430.<\/p>\n<p>\u041e\u0431\u043e\u0441\u043d\u043e\u0432\u0430\u043d\u0438\u0435 \u0432\u043d\u0435\u0434\u0440\u0435\u043d\u0438\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u0438 \u043f\u043e\u0434\u043a\u0440\u0435\u043f\u043b\u044f\u0435\u0442\u0441\u044f \u0442\u0435\u043e\u0440\u0438\u0435\u0439 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0432 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 \u0441\u043b\u0443\u0447\u0430\u044f\u0445:<\/p>\n<ul>\n<li>\n<p>\u041f\u0440\u043e\u0435\u043a\u0442\u0443 \u0431\u043e\u043b\u044c\u0448\u0435 \u0433\u043e\u0434\u0430, \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u043e\u0431\u0448\u0438\u0440\u043d\u044b\u0439 \u043f\u0443\u043b \u0442\u0435\u0441\u0442-\u043a\u0435\u0439\u0441\u043e\u0432, \u043d\u0430 \u0438\u0445 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443 \u0443\u0445\u043e\u0434\u0438\u0442 \u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u0432\u0440\u0435\u043c\u044f.<\/p>\n<\/li>\n<li>\n<p>\u0412 \u043a\u043e\u043c\u0430\u043d\u0434\u0435 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432, \u0438 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0441\u043f\u043e\u0441\u043e\u0431\u0441\u0442\u0432\u0443\u0435\u0442 \u0432\u0435\u0440\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432 \u043a\u043e\u0434\u0435 \u043d\u0435 \u043f\u043e\u0432\u043b\u0438\u044f\u043b\u0438 \u043d\u0430 \u0447\u0443\u0436\u043e\u0439 \u043a\u043e\u0434.<\/p>\n<\/li>\n<li>\n<p>\u0422\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0440\u0430\u0437\u043d\u044b\u0445 \u0432\u0435\u0440\u0441\u0438\u0439 \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u0430.<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u043e\u0435\u043a\u0442 \u0445\u0430\u0440\u0430\u043a\u0442\u0435\u0440\u0438\u0437\u0443\u0435\u0442\u0441\u044f \u0447\u0430\u0441\u0442\u044b\u043c\u0438 \u0440\u0435\u043b\u0438\u0437\u0430\u043c\u0438 \u0438 \u043d\u0430 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044e \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u0437\u0430\u043d\u0438\u043c\u0430\u0435\u0442 \u043c\u043d\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438.<\/p>\n<\/li>\n<\/ul>\n<p>\u041f\u0440\u043e\u0435\u043a\u0442 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u043e\u0432\u0430\u043b \u0434\u0432\u0443\u043c \u0438\u0437 \u044d\u0442\u0438\u0445 \u043a\u0440\u0438\u0442\u0435\u0440\u0438\u0435\u0432: \u043e\u043d \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0437\u0440\u0435\u043b\u044b\u0439, \u0441 \u043a\u043e\u043c\u0430\u043d\u0434\u043e\u0439 \u0438\u0437 \u043f\u044f\u0442\u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432, \u0440\u0435\u043b\u0438\u0437\u044b \u0432\u044b\u0445\u043e\u0434\u044f\u0442 \u0435\u0436\u0435\u043d\u0435\u0434\u0435\u043b\u044c\u043d\u043e. \u0412\u043d\u0435\u0434\u0440\u0435\u043d\u0438\u0435 \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 \u0443\u0436\u0435 \u043d\u0430 \u0434\u0430\u043d\u043d\u043e\u043c \u044d\u0442\u0430\u043f\u0435 \u043f\u0440\u0438\u043d\u043e\u0441\u0438\u043b\u043e \u0443\u043b\u0443\u0447\u0448\u0435\u043d\u0438\u044f \u2013 \u044d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u043b\u043e \u0441\u043e\u043a\u0440\u0430\u0442\u0438\u0442\u044c \u0432\u0440\u0435\u043c\u044f \u043d\u0430 \u0440\u0435\u0433\u0440\u0435\u0441\u0441\u0438\u043e\u043d\u043d\u043e\u0435 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0438 \u0443\u043c\u0435\u043d\u044c\u0448\u0438\u0442\u044c \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u0438 \u043c\u0435\u0436\u0434\u0443 \u0432\u044b\u044f\u0432\u043b\u0435\u043d\u0438\u0435\u043c \u0434\u0435\u0444\u0435\u043a\u0442\u043e\u0432 \u0438 \u0438\u0445 \u0438\u0441\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435\u043c. \u0421\u044d\u043a\u043e\u043d\u043e\u043c\u043b\u0435\u043d\u043d\u043e\u0435 \u0432\u0440\u0435\u043c\u044f \u043d\u0430 \u0440\u0435\u0433\u0440\u0435\u0441\u0441\u0435 \u0441\u043e\u0441\u0442\u0430\u0432\u0438\u043b\u043e \u043e\u043a\u043e\u043b\u043e 5 \u0447\u0430\u0441\u043e\u0432, \u0430 \u0441 \u0443\u0447\u0435\u0442\u043e\u043c 85% \u043f\u043e\u043a\u0440\u044b\u0442\u0438\u044f \u0440\u0435\u0433\u0440\u0435\u0441\u0441\u0438\u043e\u043d\u043d\u043e\u0433\u043e \u043d\u0430\u0431\u043e\u0440\u0430 \u0442\u0435\u0441\u0442-\u043a\u0435\u0439\u0441\u043e\u0432 \u043e\u0441\u0442\u0430\u0432\u0448\u0438\u0435\u0441\u044f 15% \u0442\u0435\u0441\u0442-\u043a\u0435\u0439\u0441\u043e\u0432 \u043e\u043a\u0430\u0437\u0430\u043b\u0438\u0441\u044c \u0441\u043b\u0430\u0431\u043e \u043f\u043e\u0434\u0432\u0435\u0440\u0436\u0435\u043d\u044b \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u0438 \u0438 \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u043b\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c\u0441\u044f \u0432\u0440\u0443\u0447\u043d\u0443\u044e.<\/p>\n<p>\u041e\u0434\u043d\u0430\u043a\u043e \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u043c \u0430\u0441\u043f\u0435\u043a\u0442\u043e\u043c \u043e\u0441\u0442\u0430\u0432\u0430\u043b\u0441\u044f \u0432\u043e\u043f\u0440\u043e\u0441 \u043f\u043e\u043b\u044c\u0437\u044b \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u0438 \u0434\u043b\u044f \u0431\u0438\u0437\u043d\u0435\u0441\u0430: \u0435\u0441\u043b\u0438 \u043e\u0448\u0438\u0431\u043a\u0430 \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u0438\u0432\u0435\u0441\u0442\u0438 \u043a \u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u043c \u0444\u0438\u043d\u0430\u043d\u0441\u043e\u0432\u044b\u043c \u043f\u043e\u0442\u0435\u0440\u044f\u043c, \u0431\u0438\u0437\u043d\u0435\u0441 \u0431\u043e\u043b\u0435\u0435 \u0441\u043a\u043b\u043e\u043d\u0435\u043d \u043a \u0432\u043d\u0435\u0434\u0440\u0435\u043d\u0438\u044e \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u0438. \u0412 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0435 \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u2013 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u043b\u043e\u043c \u2013 \u0441\u0442\u043e\u0438\u043c\u043e\u0441\u0442\u044c \u043e\u0448\u0438\u0431\u043a\u0438 \u043d\u0435\u0432\u0435\u043b\u0438\u043a\u0430, \u043d\u043e \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0443\u0441\u043a\u043e\u0440\u0438\u0442\u044c \u0440\u0435\u0433\u0440\u0435\u0441\u0441\u0438\u043e\u043d\u043d\u043e\u0435 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0438 \u043e\u043f\u0440\u043e\u0431\u043e\u0432\u0430\u0442\u044c \u043d\u043e\u0432\u044b\u0435 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0438 \u0443\u0436\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u043b\u0430 \u0431\u043e\u043b\u044c\u0448\u0443\u044e \u0446\u0435\u043d\u043d\u043e\u0441\u0442\u044c.<\/p>\n<p>\u041f\u0435\u0440\u0432\u044b\u0435 \u0448\u0430\u0433\u0438 \u043a \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u0438 \u0432\u043a\u043b\u044e\u0447\u0430\u043b\u0438 \u043a\u043e\u043d\u0441\u0443\u043b\u044c\u0442\u0430\u0446\u0438\u0438 \u0441 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0449\u0438\u043a\u043e\u043c \u0438 \u0441\u0431\u043e\u0440 \u0442\u0435\u0441\u0442-\u043a\u0435\u0439\u0441\u043e\u0432, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0432 \u0440\u0435\u0433\u0440\u0435\u0441\u0441\u0435, \u0438\u0437 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0431\u044b\u043b\u0438 \u0432\u044b\u0431\u0440\u0430\u043d\u044b \u043a\u0430\u043d\u0434\u0438\u0434\u0430\u0442\u044b \u043d\u0430 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u044e.\u00a0\u0417\u0430\u0442\u0435\u043c \u044f \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u043b \u0438\u0441\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0435 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435, \u043c\u043e\u0434\u0435\u043b\u0438\u0440\u0443\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u0441 \u0442\u043e\u0447\u043a\u0438 \u0437\u0440\u0435\u043d\u0438\u044f \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440\u0430, \u0447\u0442\u043e \u043f\u0440\u0438\u0432\u0435\u043b\u043e \u043a \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044e \u0441\u043f\u0438\u0441\u043a\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0445 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0435\u0432, \u0432\u043a\u043b\u044e\u0447\u0430\u044f \u0442\u0430\u043a\u0438\u0435 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438, \u043a\u0430\u043a \u0432\u0445\u043e\u0434 \u0432 \u0441\u0438\u0441\u0442\u0435\u043c\u0443, \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0438 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u0430\u043c\u0438. \u042d\u0442\u043e \u043e\u0431\u043e\u0437\u043d\u0430\u0447\u0438\u043b\u043e \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0435 \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0434\u043b\u044f UI-\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f.<\/p>\n<p>\u0427\u0442\u043e \u043a\u0430\u0441\u0430\u0435\u0442\u0441\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f API-\u0447\u0430\u0441\u0442\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u044f \u0432\u0437\u044f\u043b \u0435\u0433\u043e \u0442\u0435\u043a\u0443\u0449\u0443\u044e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u044d\u0442\u0430\u043b\u043e\u043d\u043d\u043e\u0439. \u041d\u0430\u043b\u0438\u0447\u0438\u0435 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 Swagger \u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0443\u043f\u0440\u043e\u0441\u0442\u0438\u043b\u043e \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e\u0441\u0442\u0438 \u0440\u0430\u0431\u043e\u0442\u044b API. \u0412 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u0447\u0435\u0433\u043e \u0443 \u043c\u0435\u043d\u044f \u0431\u044b\u043b \u0441\u043f\u0438\u0441\u043e\u043a \u0432\u0441\u0435\u0445 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0445 API-\u043c\u0435\u0442\u043e\u0434\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u043e\u0434\u043f\u0430\u0434\u0430\u043b\u0438 \u043f\u043e\u0434 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u044e, \u0432\u043a\u043b\u044e\u0447\u0430\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443 \u043e\u0442\u0432\u0435\u0442\u043e\u0432 \u043d\u0430 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u044e \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u043e\u0448\u0438\u0431\u043e\u043a.<\/p>\n<p><a class=\"anchor\" name=\"1\" id=\"1\"><\/a><\/p>\n<h2>\u041e\u0431\u0437\u043e\u0440 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0439<\/h2>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0435\u0440\u0435\u0439\u0434\u0435\u043c \u043a \u043e\u0431\u0437\u043e\u0440\u0443 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u044f \u0432\u044b\u0431\u0440\u0430\u043b \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0434\u0435\u043d\u0438\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>\u041f\u0440\u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 \u043d\u0430 Python \u0431\u0435\u0437 Pytest \u0441 \u0435\u0433\u043e \u043e\u0431\u0448\u0438\u0440\u043d\u044b\u043c \u043d\u0430\u0431\u043e\u0440\u043e\u043c \u043a\u0438\u043b\u043b\u0435\u0440-\u0444\u0438\u0447\u0435\u0439 \u0442\u043e\u0447\u043d\u043e \u043d\u0435 \u043e\u0431\u043e\u0439\u0442\u0438\u0441\u044c. \u0411\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 \u0434\u043b\u044f UI-\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0434\u043e\u043b\u0433\u043e \u0442\u0430\u043a\u0436\u0435 \u0432\u044b\u0431\u0438\u0440\u0430\u0442\u044c \u043d\u0435 \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c, \u043a\u043e\u043b\u043b\u0435\u0433\u0438 \u0434\u0430\u0432\u043d\u043e \u0443\u0436\u0435 \u0440\u0430\u0441\u0445\u0432\u0430\u043b\u0438\u0432\u0430\u043b\u0438 Playwright. \u041f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0432 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043e\u0431\u0443\u0447\u0430\u044e\u0449\u0438\u0445 \u0432\u0438\u0434\u0435\u043e\u0440\u043e\u043b\u0438\u043a\u043e\u0432, \u044f \u0443\u0431\u0435\u0434\u0438\u043b\u0441\u044f \u0432 \u0435\u0433\u043e \u043c\u043e\u0449\u0438&#8230; \u0447\u0442\u043e \u0436, \u043d\u0430\u043a\u043e\u043d\u0435\u0446 \u0438 \u0443 \u043c\u0435\u043d\u044f \u043f\u043e\u044f\u0432\u0438\u043b\u0430\u0441\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0435\u0433\u043e \u043e\u043f\u0440\u043e\u0431\u043e\u0432\u0430\u0442\u044c. Playwright \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043a\u0430\u043a \u0434\u043b\u044f UI, \u0442\u0430\u043a \u0438 \u0434\u043b\u044f API-\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f. \u041d\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f GitLab, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0431\u0443\u0434\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c GitLab CI\/CD \u0434\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u043d\u0443 \u0438 \u0432 \u043a\u043e\u043d\u0435\u0447\u043d\u043e\u043c \u0441\u0447\u0435\u0442\u0435 \u0434\u043b\u044f \u0443\u043f\u0430\u043a\u043e\u0432\u043a\u0438 \u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u0433\u043e \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430 \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f Docker. \u0414\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u0437\u0430\u0434\u0435\u0439\u0441\u0442\u0432\u0443\u044e Faker, \u0434\u043b\u044f \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438 API-\u043e\u0442\u0432\u0435\u0442\u043e\u0432 \u0438 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u2014 Pydantic.<\/p>\n<p><a class=\"anchor\" name=\"2\" id=\"2\"><\/a><\/p>\n<h2>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b<\/h2>\n<p>\u041f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u0442\u044c \u043a \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044e \u0442\u0435\u0441\u0442\u043e\u0432, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0440\u0430\u0431\u043e\u0447\u0435\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435. \u0411\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c Docker, \u0432\u043e-\u043f\u0435\u0440\u0432\u044b\u0445, \u044d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0442\u044c \u0435\u0434\u0438\u043d\u043e\u043e\u0431\u0440\u0430\u0437\u0438\u0435 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f. \u041d\u0435 \u0432\u0430\u0436\u043d\u043e, \u043a\u0430\u043a\u043e\u0439 \u0431\u0440\u0430\u0443\u0437\u0435\u0440 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d \u0438\u043b\u0438 \u043d\u0430 \u043a\u0430\u043a\u043e\u0439 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442\u044c \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430, \u2013 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 Docker-\u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442 \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u043e\u0435 \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u043e\u0434\u043d\u0438\u0445 \u0438 \u0442\u0435\u0445 \u0436\u0435 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u043a\u0430\u043a \u043d\u0430 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0439 \u043c\u0430\u0448\u0438\u043d\u0435, \u0442\u0430\u043a \u0438 \u0432 \u0441\u0440\u0435\u0434\u0435 CI. \u041f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0431\u0430\u0437\u043e\u0432\u043e\u0433\u043e \u043e\u0431\u0440\u0430\u0437\u0430 Playwright \u043e\u0442 Microsoft \u0441 \u043f\u0440\u0435\u0434\u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043d\u044b\u043c\u0438 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430\u043c\u0438 \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u0438\u0437\u0431\u0430\u0432\u0438\u0442\u044c\u0441\u044f \u043e\u0442 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0442\u044c \u0438 \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0442\u044c \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u044b \u0432\u0440\u0443\u0447\u043d\u0443\u044e, \u0447\u0442\u043e \u0441\u044d\u043a\u043e\u043d\u043e\u043c\u0438\u0442 \u0432\u0440\u0435\u043c\u044f \u0438 \u043c\u0438\u043d\u0438\u043c\u0438\u0437\u0438\u0440\u0443\u0435\u0442 \u0432\u0435\u0440\u043e\u044f\u0442\u043d\u043e\u0441\u0442\u044c \u043e\u0448\u0438\u0431\u043e\u043a, \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0445 \u0441 \u043d\u0435\u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u043e\u0441\u0442\u044c\u044e \u0432\u0435\u0440\u0441\u0438\u0439. \u0412\u043e-\u0432\u0442\u043e\u0440\u044b\u0445, \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u0441\u044f \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u0432 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044f, \u043a \u043f\u0440\u0438\u043c\u0435\u0440\u0443, \u0438\u0437\u043c\u0435\u043d\u044f\u0442\u044c \u0442\u0435\u0441\u0442\u043e\u0432\u0443\u044e \u0441\u0440\u0435\u0434\u0443, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0431\u0443\u0434\u0443\u0442 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c\u0441\u044f \u0442\u0435\u0441\u0442\u044b.<\/p>\n<p>\u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u043c \u043a \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044e Dockerfile. \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u043e\u0431\u0440\u0430\u0437 Playwright \u043d\u0430 \u0431\u0430\u0437\u0435 Ubuntu. \u0412 \u043e\u0431\u0440\u0430\u0437 \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u044b \u043f\u0440\u0435\u0434\u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043d\u044b\u0435 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u044b \u0438 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043d\u044b\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438, \u0441\u0430\u043c Playwright \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e. \u041f\u0435\u0440\u0435\u0439\u0434\u0435\u043c \u043a \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f.<\/p>\n<p>\u0414\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e poetry. \u042d\u0442\u043e\u0442 \u043f\u0430\u043a\u0435\u0442\u043d\u044b\u0439 \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442 \u0431\u043e\u043b\u0435\u0435 \u0443\u0434\u043e\u0431\u043d\u043e\u0435 \u0438 \u0442\u043e\u0447\u043d\u043e\u0435 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044f\u043c\u0438 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0444\u0430\u0439\u043b\u0430 poetry.lock, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0444\u0438\u043a\u0441\u0438\u0440\u0443\u0435\u0442 \u0442\u043e\u0447\u043d\u044b\u0435 \u0432\u0435\u0440\u0441\u0438\u0438 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043d\u044b\u0445 \u043f\u0430\u043a\u0435\u0442\u043e\u0432 \u0438 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442 \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u044b\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043d\u0430 \u0432\u0441\u0435\u0445 \u0441\u0440\u0435\u0434\u0430\u0445. \u0422\u0430\u043a\u0436\u0435 \u0438\u0437 \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432 poetry \u043c\u043e\u0436\u043d\u043e \u0432\u044b\u0434\u0435\u043b\u0438\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c <strong>\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0440\u0430\u0437\u043d\u043e\u0433\u043e \u043d\u0430\u0431\u043e\u0440\u0430 \u043f\u0430\u043a\u0435\u0442\u043e\u0432 \u043d\u0430 \u043f\u0440\u043e\u0434\u0435 \u0438 \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0439 \u0441\u0440\u0435\u0434\u0435<\/strong> \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443 pytest \u043f\u0440\u044f\u043c\u043e \u0432 \u043a\u043e\u043d\u0444\u0438\u0433\u0435 poetry \u2014 poetry.toml \u0447\u0435\u0440\u0435\u0437 \u0434\u0438\u0440\u0435\u043a\u0442\u0438\u0432\u0443 [tool.pytest.<em>ini_<\/em>options]. \u041f\u0435\u0440\u0435\u0439\u0434\u0435\u043c \u043a\u00a0 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0435 Poetry \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a\u043e\u043c\u0430\u043d\u0434\u044b:<\/p>\n<pre><code>curl -sSL https:\/\/install.python-poetry.org | python -<\/code><\/pre>\n<p>\u00a0\u041f\u0440\u043e\u0432\u0435\u0440\u0438\u043c \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0443 \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440\u0430 \u043f\u0430\u043a\u0435\u0442\u043e\u0432 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a\u043e\u043c\u0430\u043d\u0434\u044b:  <\/p>\n<pre><code>poetry --version<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u0442\u044c \u043a \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044e \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u043a\u043e\u043c\u0430\u043d\u0434\u043e\u0439:  <\/p>\n<pre><code> poetry init<\/code><\/pre>\n<p>\u0421\u0438\u0441\u0442\u0435\u043c\u0430 \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0438\u0442 \u0432\u0432\u0435\u0441\u0442\u0438 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u0443\u044e \u0434\u043b\u044f \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f. \u041c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e, \u043d\u0430\u0436\u0438\u043c\u0430\u044f Enter. \u0414\u0430\u043b\u0435\u0435 \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0443\u044e\u0449\u0438\u0435 \u043d\u0430\u0441 \u043f\u0430\u043a\u0435\u0442\u044b \u043a\u043e\u043c\u0430\u043d\u0434\u043e\u0439:  <\/p>\n<pre><code>poetry add pytest-playwright pytest pydantic pydantic-settings faker<\/code><\/pre>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e \u043a\u0430\u043a \u043f\u0430\u043a\u0435\u0442\u044b \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043b\u0438\u0441\u044c \u0438 \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043b\u0441\u044f lock-\u0444\u0430\u0439\u043b, \u043f\u0435\u0440\u0435\u0439\u0434\u0435\u043c \u043a \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0435 Docker-\u043e\u0431\u0440\u0430\u0437\u0430 \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u0441\u043e\u0437\u0434\u0430\u0432 Dockerfile. \u0412\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043e\u043d \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:  <\/p>\n<pre><code>FROM mcr.microsoft.com\/playwright\/python:v1.49.0-noble   ARG DISPLAY ENV PYTHONUNBUFFERED=1 \\     PYTHONWARNINGS=ignore \\     POETRY_VIRTUALENVS_CREATE=false \\     POETRY_NO_INTERACTION=1 \\     PYTHONPATH=\"\/app:${PYTHONPATH}\" \\     DISPLAY=${DISPLAY}  ENV PATH=\"$POETRY_HOME\/bin:\/root\/.local\/bin:$PATH\" RUN pip install --upgrade pip RUN apt update &amp;&amp; apt install -y xvfb x11-utils --no-install-recommends curl \\  &amp;&amp; curl -sSL https:\/\/install.python-poetry.org | python - \\     &amp;&amp; pip install certifi --upgrade    WORKDIR \/app   COPY pyproject.toml poetry.lock \/app\/ RUN poetry install --no-interaction --no-ansi  RUN playwright install chrome COPY . \/app   CMD [\"sh\", \"-c\", \"while true; do sleep 3600; done\"]<\/code><\/pre>\n<p>\u041c\u043d\u043e\u0433\u043e\u0435 \u0438\u0437 \u044d\u0442\u043e\u0433\u043e Dockerfile \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u043c \u0434\u043b\u044f Python-\u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u0438 \u043d\u0430\u0432\u0435\u0440\u043d\u044f\u043a\u0430 \u0432\u0430\u043c \u0443\u0436\u0435 \u0432\u0441\u0442\u0440\u0435\u0447\u0430\u043b\u043e\u0441\u044c. \u041e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043c\u0441\u044f \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435.\u00a0<\/p>\n<p>Docker \u043d\u0435 \u0438\u043c\u0435\u0435\u0442 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0433\u043e GUI-\u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u044b\u0439 \u0434\u0438\u0441\u043f\u043b\u0435\u0439\u043d\u044b\u0439 \u0441\u0435\u0440\u0432\u0435\u0440 \u2013 Xvfb, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u043d\u0430\u043c \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u043e\u043a\u043d\u043e \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430 \u0438 Playwright \u043e\u0442\u043b\u0430\u0434\u0447\u0438\u043a \u0438\u0437 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430. \u042f \u0440\u0430\u0431\u043e\u0442\u0430\u044e \u043d\u0430 Linux, \u044d\u0442\u0430 OS \u043a\u0430\u043a \u0438 \u0434\u0440\u0443\u0433\u0438\u0435, \u043c\u043e\u0436\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u043c\u0438 \u0434\u0438\u0441\u043f\u043b\u0435\u044f\u043c\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043a\u0430\u043a \u0444\u0438\u0437\u0438\u0447\u0435\u0441\u043a\u0438\u043c, \u0442\u0430\u043a \u0438 \u0443\u0434\u0430\u043b\u0435\u043d\u043d\u044b\u043c (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0447\u0435\u0440\u0435\u0437 SSH). \u0412 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0434\u0438\u0441\u043f\u043b\u0435\u0439 \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u044b\u0439, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0435\u0433\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c, \u0434\u043e\u0431\u0430\u0432\u0438\u0432 \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u0443\u044e \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e DISPLAY. \u0412 Windows DISPLAY \u043a\u0430\u043a \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u0433\u0440\u0430\u0444\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u044b Windows \u043e\u0442\u043b\u0438\u0447\u0430\u0435\u0442\u0441\u044f \u043e\u0442 X Window System, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0445\u0430\u0440\u0430\u043a\u0442\u0435\u0440\u043d\u0430 \u0434\u043b\u044f Unix-\u043f\u043e\u0434\u043e\u0431\u043d\u044b\u0445 \u0441\u0438\u0441\u0442\u0435\u043c. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0442\u0430\u043a\u0443\u044e \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0443, \u043a\u0430\u043a <a href=\"https:\/\/mobaxterm.mobatek.net\/\">MobaXterm<\/a>.<\/p>\n<p>\u0414\u043b\u044f \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0445 \u0446\u0435\u043b\u0435\u0439 \u0431\u0443\u0434\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c Chrome, \u043d\u043e \u0442\u0430\u043a\u0436\u0435 \u043c\u043e\u0436\u043d\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c Firefox \u0438\u043b\u0438 Webkit. \u041f\u043e\u0441\u043b\u0435\u0434\u043d\u044f\u044f \u043a\u043e\u043c\u0430\u043d\u0434\u0430 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u0430 \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u043d\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0430\u043b\u0441\u044f \u043f\u0440\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0435, \u044d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0438\u0437\u043d\u0443\u0442\u0440\u0438 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430.<\/p>\n<p>\u00a0\u0427\u0442\u043e\u0431\u044b \u0443\u043f\u0440\u043e\u0441\u0442\u0438\u0442\u044c \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u043c, \u0441\u043e\u0437\u0434\u0430\u043c \u0444\u0430\u0439\u043b docker-compose.yml, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0439 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438. \u0412\u043e\u0442 \u043a\u0430\u043a \u043e\u043d \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442:<\/p>\n<pre><code class=\"yaml\">services:   tests:     restart: always     build:       context: .       dockerfile: .\/Dockerfile     volumes:       - .:\/app:delegated       - \/tmp\/.X11-unix:\/tmp\/.X11-unix     env_file:       - .env     network_mode: host<\/code><\/pre>\n<p>\u0412 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043d\u043e\u043c \u043a\u043e\u043d\u0444\u0438\u0433\u0435 \u043e\u043f\u0438\u0441\u0430\u043d \u0441\u0435\u0440\u0432\u0438\u0441 tests, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0439 \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0430\u0432\u0442\u043e\u0442\u0435\u0441\u0442\u043e\u0432 \u0432 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0435. \u0412 \u0434\u0438\u0440\u0435\u043a\u0442\u0438\u0432\u0435 build \u0437\u0430\u0434\u0430\u0451\u043c \u0442\u0435\u043a\u0443\u0449\u0443\u044e \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e\u0439 \u0434\u043b\u044f \u0441\u0431\u043e\u0440\u043a\u0438 \u0438 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u043f\u0443\u0442\u044c \u0434\u043e Dockerfile. \u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0434\u0438\u0440\u0435\u043a\u0442\u0438\u0432\u043e\u0439 volumes \u043c\u043e\u043d\u0442\u0438\u0440\u0443\u0435\u043c \u0442\u0435\u043a\u0443\u0449\u0443\u044e \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e \u0441 \u0445\u043e\u0441\u0442\u0430 \u0432 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e \/app \u0432\u043d\u0443\u0442\u0440\u0438 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430 \u0441 \u0444\u043b\u0430\u0433\u043e\u043c delegated. \u042d\u0442\u043e\u0442 \u0444\u043b\u0430\u0433 \u0443\u0441\u043a\u043e\u0440\u044f\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0443 \u043f\u0440\u0438 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u0438 \u0444\u0430\u0439\u043b\u043e\u0432, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044f IDE \u043e\u043f\u0435\u0440\u0430\u0442\u0438\u0432\u043d\u043e \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432\u043d\u0443\u0442\u0440\u0438 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430. \u0421 \u043f\u043e\u043c\u043e\u0449\u044c\u044e<strong> \/tmp\/.X11-unix:\/tmp\/.X11-unix<\/strong> \u043f\u0440\u043e\u043a\u0438\u0434\u044b\u0432\u0430\u0435\u043c \u0441\u043e\u043a\u0435\u0442 X11 \u0441 \u0445\u043e\u0441\u0442\u0430 \u0432 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440, \u044d\u0442\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0433\u0440\u0430\u0444\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u0441\u0435\u0440\u0432\u0435\u0440\u0430 Xvfb \u0432\u043d\u0443\u0442\u0440\u0438 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430. \u041f\u043e\u0441\u043b\u0435\u0434\u043d\u044f\u044f \u0434\u0438\u0440\u0435\u043a\u0442\u0438\u0432\u0430 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u0435\u0442\u0435\u0432\u043e\u0435 \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u043e \u0438\u043c\u0435\u043d \u0445\u043e\u0441\u0442\u0430, \u0447\u0442\u043e \u0443\u043f\u0440\u043e\u0449\u0430\u0435\u0442 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e \u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u0442\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0438 \u0442\u0435\u0441\u0442\u043e\u0432.<\/p>\n<p><a class=\"anchor\" name=\"3\" id=\"3\"><\/a><\/p>\n<h2>\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/h2>\n<p>\u041e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446\u0438\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0438\u0433\u0440\u0430\u0435\u0442 \u043a\u043b\u044e\u0447\u0435\u0432\u0443\u044e \u0440\u043e\u043b\u044c \u0432 \u0435\u0433\u043e \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0435, \u0447\u0438\u0442\u0430\u0435\u043c\u043e\u0441\u0442\u0438, \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0438 \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u0443\u0435\u043c\u043e\u0441\u0442\u0438. \u041f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0435\u0435.<\/p>\n<p>\u042f\u0434\u0440\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 framework. \u0412 \u043d\u0435\u0439 \u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u044b \u043c\u043e\u0434\u0443\u043b\u0438 \u0441 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435\u043c \u0431\u0430\u0437\u043e\u0432\u044b\u0445 \u0438 \u0441\u043f\u0438\u0441\u043a\u043e\u0432\u044b\u0445 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432, \u043e\u0431\u044a\u0435\u043a\u0442 Driver, \u0438 \u0431\u0430\u0437\u043e\u0432\u044b\u0435 \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u044b, \u0442\u0440\u0435\u0431\u0443\u044e\u0449\u0438\u0435\u0441\u044f \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b\u00a0 \u0442\u0435\u0441\u0442\u043e\u0432. \u042d\u0442\u0438 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u044b \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043f\u043e\u0437\u0436\u0435.\u00a0<\/p>\n<p>\u0412 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 common \u0440\u0430\u0441\u043f\u043e\u043b\u0430\u0433\u0430\u044e\u0442\u0441\u044f \u043e\u0431\u0449\u0438\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0432 \u043e\u0431\u043e\u0438\u0445 \u0432\u0438\u0434\u0430\u0445 \u0442\u0435\u0441\u0442\u043e\u0432 (API \u0438 UI). \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0437\u0434\u0435\u0441\u044c \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0439\u0442\u0438 API-\u043a\u043b\u0438\u0435\u043d\u0442, SSH-\u043a\u043b\u0438\u0435\u043d\u0442 \u0438 \u043c\u043e\u0434\u0435\u043b\u0438 Pydantic, \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u043d\u044b\u0435 \u0434\u043b\u044f \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438 \u0434\u0430\u043d\u043d\u044b\u0445, \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0445 \u043e\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0430, \u0442\u0430\u043a \u0438 \u0434\u043b\u044f \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<p>\u0412 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 ui \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u0441\u044f Page Object \u0438 \u043e\u0431\u044a\u0435\u043a\u0442\u044b \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432. \u0422\u0435\u0441\u0442\u044b \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u044b \u043f\u043e \u043c\u043e\u0434\u0443\u043b\u044f\u043c, \u0442\u0430\u043a\u0438\u0435 \u043a\u0430\u043a users \u0438 contacts. \u00a0<\/p>\n<p>\u0415\u0449\u0435 \u0440\u0430\u0437\u0434\u0435\u043b \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u043c\u043e\u0434\u0443\u043b\u044c models, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u044b \u043c\u043e\u0434\u0435\u043b\u0438 Pydantic. \u0421 \u0438\u0445 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0431\u0443\u0434\u0435\u043c \u043a\u0430\u043a \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435, \u0442\u0430\u043a \u0438 \u0432\u0430\u043b\u0438\u0434\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043e\u0442\u0432\u0435\u0442\u044b, \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0435 \u043e\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0430.<\/p>\n<p>\u0412 \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0435 ui \u043d\u0430\u0445\u043e\u0434\u044f\u0442\u0441\u044f \u0442\u0435\u0441\u0442\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u044e\u0442 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0441 \u0442\u043e\u0447\u043a\u0438 \u0437\u0440\u0435\u043d\u0438\u044f \u043a\u043e\u043d\u0435\u0447\u043d\u043e\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f. \u042d\u0442\u0438 \u0442\u0435\u0441\u0442\u044b \u0438\u043c\u0438\u0442\u0438\u0440\u0443\u044e\u0442 \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0435 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0438, \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0443\u044f \u0441 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u043c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u043e\u043c. \u041a\u0430\u043a \u0438 \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u0441 API-\u0442\u0435\u0441\u0442\u0430\u043c\u0438, \u043a\u0430\u0442\u0430\u043b\u043e\u0433 \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d \u043d\u0430 \u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u043c\u043e\u0434\u0443\u043b\u0438.<\/p>\n<p>\u0412 \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 \u043f\u0430\u043f\u043a\u0435 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0439 \u0444\u0430\u0439\u043b <a href=\"http:\/\/config.py\">config.py<\/a>, \u0433\u0434\u0435 \u0445\u0440\u0430\u043d\u044f\u0442\u0441\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u0432\u043a\u043b\u044e\u0447\u0430\u044f \u043f\u0443\u0442\u0438 \u043a \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u043c\u0443 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044e \u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0434\u043b\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0442\u0435\u0441\u0442\u043e\u0432. \u041e\u043f\u0438\u0441\u0430\u043d\u043d\u0430\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0431\u044b\u0441\u0442\u0440\u043e \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u044c \u043d\u0443\u0436\u043d\u044b\u0435 \u0442\u0435\u0441\u0442\u044b \u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u043d\u043e\u0432\u044b\u0435.<\/p>\n<pre><code>\u251c\u2500\u2500 api\/  # API \u0442\u0435\u0441\u0442\u044b \u043a\u043e\u043d\u0442\u0430\u043a\u0442\u043e\u0432 \u251c\u2500\u2500 common\/ \u2502   \u251c\u2500\u2500 api_client.py        # \u041a\u043b\u0438\u0435\u043d\u0442 \u0434\u043b\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 API \u2502   \u251c\u2500\u2500 db_client.py         # \u041a\u043b\u0438\u0435\u043d\u0442 \u0434\u043b\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 \u0431\u0430\u0437\u043e\u0439 \u0434\u0430\u043d\u043d\u044b\u0445 \u2502   \u251c\u2500\u2500 data_factory.py      # \u0424\u0430\u0431\u0440\u0438\u043a\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u2502   \u251c\u2500\u2500 utils.py             # \u0412\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438. \u2502   \u2514\u2500\u2500 models.py            # \u041c\u043e\u0434\u0435\u043b\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438 \/ \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u2502   \u2514\u2500\u2500 routes.py            # \u041c\u0430\u0440\u0448\u0440\u0443\u0442\u044b \u0434\u043b\u044f API \/ UI \u251c\u2500\u2500 resources  # \u041a\u043e\u043d\u0441\u0442\u0430\u043d\u0442\u044b \/ \u0441\u043a\u0440\u0438\u043f\u0442\u044b \/ sql \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u043e\u0432 \u251c\u2500\u2500 framework\/ \u2502   \u251c\u2500\u2500 ui\/ \u2502   \u2502   \u251c\u2500\u2500 driver.py  # \u0414\u0440\u0430\u0439\u0432\u0435\u0440 playwright \u2502   \u2502   \u251c\u2500\u2500 element.py  # \u0411\u0430\u0437\u043e\u0432\u044b\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441\u043e \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435\u0439 \u2502   \u2502   \u251c\u2500\u2500 list_elements.py  # \u0421\u043f\u0438\u0441\u043a\u043e\u0432\u044b\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441\u043e \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435\u0439 \u2502   \u2502   \u251c\u2500\u2500 fixtures.py  # \u0411\u0430\u0437\u043e\u0432\u044b\u0435 \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u044b \u251c\u2500\u2500 ui\/ \u2502   \u251c\u2500\u2500 pages\/ \u2502   \u2502   \u251c\u2500\u2500 components\/ \u2502   \u2502    \u2502   \u251c\u2500\u2500 user_dialog.py \u2502   \u2502    \u2502   \u251c\u2500\u2500 contact_dialog.py \u2502   \u2502   \u251c\u2500\u2500 contact_page.py \u2502   \u2502   \u251c\u2500\u2500 user_page.py \u2502   \u251c\u2500\u2500 fixtures.py \u2502   \u251c\u2500\u2500 tests\/ \u2502   \u2502   \u251c\u2500\u2500 test_contacts.py  # UI \u0442\u0435\u0441\u0442\u044b \u0434\u043b\u044f \u0440\u0430\u0437\u0434\u0435\u043b\u0430 \u0441\u0442\u0430\u0442\u0435\u0439 \u2502   \u2502   \u2514\u2500\u2500 test_users.py     # UI \u0442\u0435\u0441\u0442\u044b \u0434\u043b\u044f \u0440\u0430\u0437\u0434\u0435\u043b\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u251c\u2500\u2500 .env # \u041f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u251c\u2500\u2500 .env.example \u251c\u2500\u2500 .gitignore # \u0418\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u0434\u043b\u044f Git \u251c\u2500\u2500 .env # \u041f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u251c\u2500\u2500 config.py # \u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0439 \u0444\u0430\u0439\u043b \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u251c\u2500\u2500 conftest.py # \u041a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 conftest \u251c\u2500\u2500 docker-compose.yml  \u251c\u2500\u2500 Dockerfile  \u251c\u2500\u2500 .gitlab-ci.yml # \u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u0434\u043b\u044f CI\/CD \u043d\u0430 GitLab \u251c\u2500\u2500 poetry.lock  # \u0424\u0430\u0439\u043b \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0438 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439 Poetry \u251c\u2500\u2500 pyproject.toml  # \u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0444\u0430\u0439\u043b \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0434\u043b\u044f Poetry \u251c\u2500\u2500 pytest.ini # \u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0439 \u0444\u0430\u0439\u043b pytest \u2514\u2500\u2500 README.md<\/code><\/pre>\n<p><a class=\"anchor\" name=\"4\" id=\"4\"><\/a><\/p>\n<h3>Driver \u0438 BaseElement<\/h3>\n<p>\u041a\u0430\u043a \u0443\u0436\u0435 \u0431\u044b\u043b\u043e \u0443\u043f\u043e\u043c\u044f\u043d\u0443\u0442\u043e \u0440\u0430\u043d\u0435\u0435, \u043a\u043b\u0430\u0441\u0441\u044b BaseElement \u0438 Driver \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u043c\u0438 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430\u043c\u0438 \u043f\u0440\u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0438 UI-\u0442\u0435\u0441\u0442\u043e\u0432. \u0420\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0438\u0445 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435.<\/p>\n<p>\u0412 \u043e\u0442\u043b\u0438\u0447\u0438\u0435 \u043e\u0442 Selenium, Playwright \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u043e\u0431\u044a\u0435\u043a\u0442 Page, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0438\u043d\u043a\u0430\u043f\u0441\u0443\u043b\u0438\u0440\u0443\u0435\u0442 \u0432\u0441\u0451 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0441 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043e\u043c \u0438 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u043c\u0438 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u0432 \u043e\u0434\u043d\u043e\u043c \u043c\u0435\u0441\u0442\u0435. \u0427\u0442\u043e\u0431\u044b \u0441\u043e\u0431\u043b\u044e\u0441\u0442\u0438 \u043f\u0440\u0438\u043d\u0446\u0438\u043f separation of concerns (\u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0441\u0442\u0438), \u0431\u044b\u043b\u043e \u043f\u0440\u0438\u043d\u044f\u0442\u043e \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u0440\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u044c \u043b\u043e\u0433\u0438\u043a\u0443 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043e\u043c \u0438 \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<p>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<ul>\n<li>\n<p>\u00a0\u0421\u0438\u043d\u0433\u043b\u0442\u043e\u043d Driver \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043e\u043c: \u0435\u0433\u043e \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e, \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043e\u0432, \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043c\u0435\u0436\u0434\u0443 \u043d\u0438\u043c\u0438, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043d\u043e\u0432\u044b\u0445 \u0441\u0442\u0440\u0430\u043d\u0438\u0446.<\/p>\n<\/li>\n<li>\n<p>\u00a0\u041a\u043b\u0430\u0441\u0441 BaseElement \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u0431\u043e\u0439 \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0446\u0438\u044e \u043d\u0430\u0434 \u043b\u043e\u043a\u0430\u0442\u043e\u0440\u0430\u043c\u0438 \u0438 \u0438\u043d\u043a\u0430\u043f\u0441\u0443\u043b\u0438\u0440\u0443\u0435\u0442 \u043b\u043e\u0433\u0438\u043a\u0443 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u043c\u0438 \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435.<\/p>\n<\/li>\n<\/ul>\n<p>\u0411\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f \u0442\u0430\u043a\u043e\u043c\u0443 \u043f\u043e\u0434\u0445\u043e\u0434\u0443, \u043c\u044b \u0440\u0430\u0437\u0434\u0435\u043b\u044f\u0435\u043c \u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0441\u0442\u044c: Driver \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043e\u043c, \u0430 BaseElement \u2014 \u043b\u043e\u043a\u0430\u0442\u043e\u0440\u0430\u043c\u0438 \u0438 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f\u043c\u0438 \u0441 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u043c\u0438. \u042d\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442 \u043a\u043e\u0434 \u0431\u043e\u043b\u0435\u0435 \u0447\u0438\u0441\u0442\u044b\u043c, \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u043c\u044b\u043c \u0438 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u043c \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u0430\u043c SOLID.\u00a0<\/p>\n<pre><code class=\"python\">@dataclass class By:     LOCATOR = \"locator\"     TEXT = \"get_by_text\"     LABEL = \"get_by_label\"     TITLE = \"get_by_title\"     ALT_TEXT = \"get_by_alt_text\"     PLACEHOLDER = \"get_by_placeholder\"     TEST_ID = \"get_by_test_id\"   class BaseElement:     def __init__(         self,         search_by: str,         locator: str,         parent: Optional[Union[\"BaseElement\", Locator]] = None,         ignore_parent: bool = False,     ):         self.search_by = search_by         self.search_locator = locator         self.parent = parent         self.ignore_parent = ignore_parent      def __call__(self, *args, **kwargs):         if kwargs.get(\"parent\"):             self.parent = kwargs[\"parent\"]         self._locator_kwargs = kwargs         return self      def _get_locator(self) -&gt; Locator:         from framework.ui.driver import Driver          locator: Locator          if hasattr(self, \"_locator_kwargs\"):             formatted_locator = self.search_locator.format(**self._locator_kwargs)         elif hasattr(self, \"search_locator\"):             formatted_locator = self.search_locator         else:             formatted_locator = \"\"          driver = (             (                 self.parent._get_locator()                 if isinstance(self.parent, BaseElement)                 else self.parent             )             if (self.parent and not self.ignore_parent)             else Driver().get_driver()         )         resolve_method = getattr(driver, self.search_by)         locator = resolve_method(formatted_locator, exact=self.exact_text)         return locator         def chain(self, element: \"BaseElement\"):         element.parent = self         return element         def hover(self, **kwargs):         self._get_locator().hover(**kwargs)      def should_be_visible(self, should_visible: bool = True) -&gt; None:         locator = self._get_locator()         expect(locator).to_be_visible(visible=should_visible)      def click(self, timeout: int = 2000, force: bool = False):         self._get_locator().click(timeout=timeout, force=force)<\/code><\/pre>\n<p>\u0420\u0430\u0431\u043e\u0442\u0430 \u0441 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u043c\u0438 \u043d\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0443 \u0441 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u043c\u0438 \u0432 Selenium \u0441 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u043c\u0438 \u043e\u0442\u043b\u0438\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u043c\u0438 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u044f\u043c\u0438.<\/p>\n<p>\u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 \u0434\u043b\u044f \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0430 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430 \u043f\u0435\u0440\u0435\u0434\u0430\u044e\u0442\u0441\u044f \u0442\u0438\u043f \u043b\u043e\u043a\u0430\u0442\u043e\u0440\u0430, \u0438 \u043b\u043e\u043a\u0430\u0442\u043e\u0440. \u041c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0438\u0435 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u044b \u0432\u044b\u0433\u043b\u044f\u0434\u044f\u0442 \u0442\u0430\u043a:<\/p>\n<pre><code class=\"python\">BaseElement(By.LOCATOR, \"input[name='login']\") BaseElement(By.TEXT, \"\u0420\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044f\") BaseElement(By.TEST_ID, \"TopUserMenu\")<\/code><\/pre>\n<p>\u041f\u0440\u043e\u0446\u0435\u0441\u0441 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f Playwright-\u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0432 \u043c\u0435\u0442\u043e\u0434\u0435 getlocator. \u0412 \u043d\u0435\u043c \u043b\u043e\u043a\u0430\u0442\u043e\u0440 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0444\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u0439 \u0432\u0438\u0434, \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0441 \u0443\u0447\u0435\u0442\u043e\u043c \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u043d\u044b\u0445 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u0432, \u0438, \u0435\u0441\u043b\u0438 \u0443 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430 \u0435\u0441\u0442\u044c \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442, \u0442\u043e \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0440\u0435\u0437\u043e\u043b\u0432\u0438\u0442\u0441\u044f \u043b\u043e\u043a\u0430\u0442\u043e\u0440 \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0433\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430.<\/p>\n<p>\u0422\u0430\u043a\u0436\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u043c\u043e\u0436\u043d\u043e \u0441\u043e\u0435\u0434\u0438\u043d\u044f\u0442\u044c:<\/p>\n<pre><code class=\"python\">login_dialog = BaseElement(By.LOCATOR, \".Mui-popover\") login_dialog.chain(BaseElement(By.TEXT, \"\u0412\u043e\u0439\u0442\u0438\")).click()<\/code><\/pre>\n<p>\u0412 \u044d\u0442\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u0441\u044f \u043a\u043b\u0438\u043a \u043f\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0443 \u0441 \u0442\u0435\u043a\u0441\u0442\u043e\u043c \u00ab\u0412\u043e\u0439\u0442\u0438\u00bb, \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0432 DOM-\u0434\u0435\u0440\u0435\u0432\u0435 \u0434\u043e\u043b\u0436\u0435\u043d \u044f\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u043c \u0441 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u043e\u043c \u043a\u043b\u0430\u0441\u0441\u0430 \u201cMui-popover\u2019.<\/p>\n<pre><code class=\"python\">class Driver:    browser: Browser = None     @classmethod    def init_browser(cls, browser: BrowserType):        cls.browser = browser.launch(            channel=\"chrome\",            headless=base_settings.headless_mode,            slow_mo=300 if base_settings.demo_test else None,            args=(\"--start-maximized\", '--lang=ru-RU')        )      @classmethod     def new_workspace(cls) -&gt; None:         if cls.browser:         new_context = cls.browser.new_context(             ignore_https_errors=True,             locale=\"ru-RU\",            viewport={\"width\": 1920, \"height\": 1200},            timezone_id=\"Europe\/Moscow\",            storage_state=(                cls.auth_state_path)            ),        new_context.set_default_timeout(10000)        if cls.contexts:            # 1-9            new_context_name = (                f\"context_{int(tuple(cls.contexts.keys())[-1][-1])+1}\"            )        else:            new_context_name = \"context_1\"        page = new_context.new_page()        cls.contexts[new_context_name] = {            \"context\": new_context,            \"pages\": [page],            \"selected_page\": 1,        }    else:        raise Exception(\"Browser not initialized. Call init_browser first.\")     @classmethod    def get_driver(cls) -&gt; Page:        if cls.current_context is None:            raise ValueError(            \"Driver is not initialized, call Driver.new_workspace first.\"        )        context = cls._get_current_context_payload()        return context[\"pages\"][context[\"selected_page\"] - 1]<\/code><\/pre>\n<p>\u0414\u043b\u044f \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u044f \u044d\u0442\u0438\u0445 \u043a\u043b\u0430\u0441\u0441\u043e\u0432 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0437\u043d\u0430\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435: \u0432 Playwright \u0432 \u043e\u0442\u043b\u0438\u0447\u0438\u0438 \u043e\u0442 Selenium \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043e\u0431\u044a\u0435\u043a\u0442 page, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u044f\u0435\u0442 \u0432\u0441\u0451 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0441 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043e\u043c \u0438 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u043c\u0438 \u0432 \u043e\u0434\u043d\u043e\u0439 \u043e\u0431\u044a\u0435\u043a\u0442\u0435. \u0414\u043b\u044f \u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u044f \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u0443 separation of concern \u0431\u044b\u043b\u043e \u0440\u0435\u0448\u0435\u043d\u043e \u0447\u0451\u0442\u043a\u043e \u0440\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u044c \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0441 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043e\u043c \u0438 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u043c\u0438 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u043c\u0438. \u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u043e\u0431\u044a\u0435\u043a\u0442 Driver \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043e\u043c (\u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430, \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043e\u0432, \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043c\u0435\u0436\u0434\u0443 \u043d\u0438\u043c\u0438, \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 page), \u0430 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043e \u043b\u043e\u043a\u0430\u0442\u043e\u0440\u0435 \u0430\u0431\u0441\u0442\u0440\u0430\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0430 \u0432 \u043e\u0431\u044a\u0435\u043a\u0442\u0435 BaseElement. \u0412 \u0438\u0442\u043e\u0433\u0435, \u0440\u0430\u0431\u043e\u0442\u0430 \u0441 \u043b\u043e\u043a\u0430\u0442\u043e\u0440\u0430\u043c\u0438 \u043e\u0442\u0434\u0435\u043b\u0435\u043d\u0430 \u043e\u0442 \u0441\u0430\u043c\u043e\u0433\u043e \u0434\u0440\u0430\u0439\u0432\u0435\u0440\u0430:<\/p>\n<pre><code class=\"python\">@pytest.fixture(scope=\"session\") def start_session():    with sync_playwright() as pw:        Driver.init_browser(pw.chromium)        yield        Driver.close_browser()   @pytest.fixture(autouse=True) def launch_workspace(start_session):    Driver.new_workspace()    yield    Driver().close_contexts()<\/code><\/pre>\n<p>\u0424\u0438\u043a\u0441\u0442\u0443\u0440\u0430 start_session \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u0442 \u0431\u0440\u0430\u0443\u0437\u0435\u0440 \u0435\u0434\u0438\u043d\u043e\u0436\u0434\u044b \u043d\u0430 \u0432\u0441\u044e \u0442\u0435\u0441\u0442\u043e\u0432\u0443\u044e \u0441\u0435\u0441\u0441\u0438\u044e \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430 scope=\u201dsession\u201d. \u0412 \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u0435 launch_workspace \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f \u043d\u043e\u0432\u043e\u0435 \u201c\u0440\u0430\u0431\u043e\u0447\u0435\u0435 \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u043e\u201d \u043f\u0435\u0440\u0435\u0434 \u043d\u0430\u0447\u0430\u043b\u043e\u043c \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0442\u0435\u0441\u0442\u0430. \u041f\u043e\u0441\u043b\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u0442\u0435\u0441\u0442\u0430 (\u0432\u044b\u0445\u043e\u0434\u0430 \u0438\u0437 <code>yield<\/code>), \u0432\u0441\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0435 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u044b \u0437\u0430\u043a\u0440\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u043c\u0435\u0442\u043e\u0434\u043e\u043c Driver().close_contexts().<\/p>\n<p><a class=\"anchor\" name=\"5\" id=\"5\"><\/a><\/p>\n<h3>Page object<\/h3>\n<pre><code class=\"python\">def url(_url: str = None):    def inner(page):        page.url = f\"https:\/\/{base_settings.host}\/{_url}\"        return page     return inner  @url() class UserPage(BasePage):     login = Element(By.LOCATOR, \"input[name='login']\")     add_user_btn = Element(By.LOCATOR, \"\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c\")     create_user_btn = Element(By.LOCATOR, \"\u0421\u043e\u0437\u0434\u0430\u0442\u044c\")     login_btn = Element(By.TEXT, \"\u0412\u043e\u0439\u0442\u0438\")     password = Element(By.LOCATOR, \"input[name='password']\")     grid = Grid()     alert = Alert()      def login(self, login: str, password: str):         self.login.fill(login)         self.password.fill(password)      def add_user(self, name: str = Faker.name(), password: str = Faker.password()):         self.add_user_btn.click()         self.login.fill(name)         self.password.fill(password)         self.create_user_btn.click()<\/code><\/pre>\n<p>\u041d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0442\u0435\u0441\u0442\u043e\u0432 \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u043e\u0432\u0430\u043d\u043e \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043f\u0430\u0442\u0442\u0435\u0440\u043d\u0430<strong> Page object<\/strong>. \u041e\u0431\u044a\u0435\u043a\u0442 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u0438\u043c\u0435\u0435\u0442 \u0434\u0435\u043a\u043e\u0440\u0430\u0442\u043e\u0440 url, \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u044e\u0449\u0438\u0439 \u0447\u0430\u0441\u0442\u044c \u0430\u0434\u0440\u0435\u0441\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0438,\u00a0 \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u043d\u0430 \u0440\u0435\u0441\u0443\u0440\u0441, \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 \u044d\u0442\u043e\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435. \u0414\u0430\u043b\u0435\u0435 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043c\u0435\u0442\u043e\u0434\u0430 open \u043c\u043e\u0436\u043d\u043e \u043e\u0442\u043a\u0440\u044b\u0442\u044c \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443. \u0412 \u0440\u0430\u043c\u043a\u0430\u0445 page object \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u044e\u0442\u0441\u044f \u043b\u043e\u043a\u0430\u0442\u043e\u0440\u044b, \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b, \u0438 \u043c\u0435\u0442\u043e\u0434\u044b \u0440\u0430\u0431\u043e\u0442\u044b \u0441\u043e \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435\u0439. \u041a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0442 \u0441\u043e\u0431\u043e\u0439 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0435 \u0432\u0441\u043f\u043b\u044b\u0432\u0430\u044e\u0449\u0438\u0435 \u0434\u0438\u0430\u043b\u043e\u0433\u043e\u0432\u044b\u0435 \u043e\u043a\u043d\u0430 (\u043f\u043e\u043f-\u0430\u043f\u044b, \u0434\u0440\u043e\u0432\u0435\u0440\u044b \u0438 \u0442.\u0434), \u043b\u043e\u0433\u0438\u043a\u0430 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043a\u043e\u0442\u043e\u0440\u044b\u043c\u0438 \u043e\u043f\u0438\u0441\u0430\u043d\u0430 \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u043c \u043e\u0442 page \u043e\u0431\u044a\u0435\u043a\u0442\u0435, \u0438 \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u044e\u0442\u0441\u044f \u043d\u0430 \u0443\u0440\u043e\u0432\u043d\u0435 \u0441 \u043e\u0431\u044b\u0447\u043d\u044b\u043c\u0438 \u043b\u043e\u043a\u0430\u0442\u043e\u0440\u0430\u043c\u0438. \u041d\u043e \u043a \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430\u043c \u043c\u044b \u0432\u0435\u0440\u043d\u0435\u043c\u0441\u044f \u043f\u043e\u0437\u0436\u0435.<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u0442\u044c \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443 \u0434\u043b\u044f \u0435\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0432 \u0442\u0435\u0441\u0442\u0430\u0445. \u041d\u0430\u043f\u0438\u0448\u0435\u043c \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u0443 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b:<\/p>\n<pre><code class=\"python\">@pytest.fixture def user_page() -&gt; UserPage:    return Tasks()<\/code><\/pre>\n<p><a class=\"anchor\" name=\"6\" id=\"6\"><\/a><\/p>\n<h3>UI-\u0442\u0435\u0441\u0442\u044b<\/h3>\n<p>\u0421\u0435\u0439\u0447\u0430\u0441 \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u043f\u0435\u0440\u0435\u0439\u0442\u0438 \u043a \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044e \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u0442\u0435\u0441\u0442\u0430 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0440\u0430\u043d\u0435\u0435 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043b\u0435\u043d\u043d\u044b\u0445 \u0444\u0438\u043a\u0441\u0442\u0443\u0440. \u0414\u043b\u044f \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c Faker, \u043f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440\u044b \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u043c\u0438.<\/p>\n<pre><code class=\"python\">def test_login(user_page, api_client):    name, password = Faker.name(), Faker.password()    api_client.create_user({\"login\": name, \"password\": password})    user_page.open()    user_page.login(name, password)    user_page.grid(contains_text=name).should_be_visible()<\/code><\/pre>\n<p>\u0412 \u044d\u0442\u043e\u043c \u0442\u0435\u0441\u0442\u0435 \u043c\u044b \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Faker \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u043c \u0438\u043c\u044f \u0438 \u043f\u0430\u0440\u043e\u043b\u044c \u043d\u043e\u0432\u043e\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f, \u0430 \u0437\u0430\u0442\u0435\u043c \u0447\u0435\u0440\u0435\u0437 api_client \u0441\u043e\u0437\u0434\u0430\u0451\u043c \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0443\u044e \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u044c \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438. \u041f\u043e\u0441\u043b\u0435 \u043e\u0442\u043a\u0440\u044b\u0442\u0438\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438, \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c, \u0447\u0442\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0432\u043e\u0448\u0451\u043b \u0432 \u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u0438 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u0442\u0441\u044f \u0432 \u0441\u043f\u0438\u0441\u043a\u0435 \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435.<\/p>\n<p>\u041d\u0430\u043f\u0438\u0448\u0435\u043c \u0435\u0449\u0435 \u043e\u0434\u0438\u043d \u0442\u0435\u0441\u0442 \u043d\u0430 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u044e\u0437\u0435\u0440\u0430 \u0447\u0435\u0440\u0435\u0437 ui:<\/p>\n<pre><code class=\"python\">def test_login(request, user_page, api_client):    name, password = Faker.name(), Faker.password()        def cleanup():        api_client.delete_user(name)    request.addfinalizer(cleanup)     name, password = Faker.name(), Faker.password()       user_page.open()    user_page.login(name, password)    user_page.add_user(name, password)    user_page.grid(contains_text=name).should_be_visible()<\/code><\/pre>\n<p>\u0412 \u0434\u0430\u043d\u043d\u043e\u043c \u0442\u0435\u0441\u0442\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u0430 request. \u0412 pytest request \u2013 \u044d\u0442\u043e \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0439 \u043e\u0431\u044a\u0435\u043a\u0442-\u0444\u0438\u043a\u0441\u0442\u0443\u0440\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0441 \u0442\u0435\u043a\u0443\u0449\u0438\u043c \u0442\u0435\u0441\u0442\u043e\u043c \u0438 \u0435\u0433\u043e \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435\u043c. \u041c\u0435\u0442\u043e\u0434 request.addfinalizer(function) \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u0443\u0435\u0442 \u0444\u0443\u043d\u043a\u0446\u0438\u044e, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430 \u043f\u043e\u0441\u043b\u0435 \u043e\u043a\u043e\u043d\u0447\u0430\u043d\u0438\u044f \u0442\u0435\u0441\u0442\u0430, \u0432\u043d\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0442\u043e\u0433\u043e, \u043d\u0430 \u043a\u0430\u043a\u043e\u043c \u044d\u0442\u0430\u043f\u0435 \u043e\u043d \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u0441\u044f: \u043f\u0440\u043e\u0439\u0434\u0435\u0442 \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0438\u043b\u0438 \u0443\u043f\u0430\u0434\u0451\u0442 \u0438\u0437-\u0437\u0430 \u043e\u0448\u0438\u0431\u043a\u0438.<\/p>\n<p>\u041d\u0430\u043f\u0438\u0448\u0435\u043c \u0435\u0449\u0435 \u043e\u0434\u0438\u043d \u0442\u0435\u0441\u0442 \u043d\u0430 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443 \u043d\u0435\u0433\u0430\u0442\u0438\u0432\u043d\u043e\u0433\u043e \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u044f:<\/p>\n<pre><code class=\"python\">def test_create_user_with_invalid_password(user_page):     # \u041f\u0440\u0435\u0434\u043f\u043e\u043b\u043e\u0436\u0438\u043c, \u0447\u0442\u043e \u043d\u0430\u0448\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043d\u0435 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u043f\u0430\u0440\u043e\u043b\u0438 \u043a\u043e\u0440\u043e\u0447\u0435 6 \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432     name = Faker.name()     invalid_password = \"123\"      user_page.open()     user_page.add_user(name, invalid_password)          # \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c, \u0447\u0442\u043e \u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u0432\u044b\u0434\u0430\u043b\u0430 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043e\u0431 \u043e\u0448\u0438\u0431\u043a\u0435     user_page.should_have_error_message(\"\u041d\u0435\u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u044b\u0439 \u043f\u0430\u0440\u043e\u043b\u044c\")     # \u0422\u0430\u043a\u0436\u0435 \u0443\u0434\u043e\u0441\u0442\u043e\u0432\u0435\u0440\u0438\u043c\u0441\u044f, \u0447\u0442\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043d\u0435 \u043f\u043e\u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432 \u0441\u043f\u0438\u0441\u043a\u0435     user_page.grid(contains_text=name).should_not_be_visible()<\/code><\/pre>\n<p><a class=\"anchor\" name=\"7\" id=\"7\"><\/a><\/p>\n<h3>API-\u0442\u0435\u0441\u0442\u044b<\/h3>\n<p>\u0421 UI-\u0447\u0430\u0441\u0442\u044c\u044e \u043c\u044b \u0437\u0430\u043a\u043e\u043d\u0447\u0438\u043b\u0438, \u0442\u0435\u043f\u0435\u0440\u044c \u043f\u0435\u0440\u0435\u0439\u0434\u0435\u043c \u043a \u0431\u043e\u043b\u0435\u0435 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e\u0439 \u0438 \u043d\u0435\u043e\u0431\u044b\u0447\u043d\u043e\u0439 \u2013 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044e API. \u0414\u0430, \u0441 Playwright \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0438 \u0442\u0430\u043a\u043e\u0435. \u0421 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043d\u043e\u0433\u043e \u0432 Playwright \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u0430 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u043e \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u0443\u044e \u0447\u0430\u0441\u0442\u044c, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u0435\u0433\u043e \u0432\u043c\u0435\u0441\u0442\u043e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 requests \u0434\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432. \u0422\u0430\u043a\u0436\u0435 \u0443\u0434\u043e\u0431\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c API-\u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0434\u043b\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u043f\u0440\u0435\u0434\u0443\u0441\u043b\u043e\u0432\u0438\u0439 \u0432 UI-\u0442\u0435\u0441\u0442\u0430\u0445, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0445 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0435\u0439 \u0447\u0435\u0440\u0435\u0437 API-\u0437\u0430\u043f\u0440\u043e\u0441 \u0438 \u0438\u0445 \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0432 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u043c \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0438 UI-\u0442\u0435\u0441\u0442\u0430.<\/p>\n<p>\u042d\u0442\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u0442\u0441\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043e\u0431\u044a\u0435\u043a\u0442\u0430 APIRequestContext \u0438 \u0435\u0433\u043e \u043c\u0435\u0442\u043e\u0434\u043e\u0432. \u041e\u0431\u044a\u0435\u043a\u0442 APIRequestContext \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043c\u043e\u0449\u043d\u044b\u0439 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u043c\u0438\u043c\u043e \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \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, \u0447\u0442\u043e \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e \u043f\u043e\u043b\u0435\u0437\u043d\u043e \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0442\u0430\u043a\u0438\u0445 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0435\u0432, \u043a\u0430\u043a \u043e\u0448\u0438\u0431\u043a\u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0438\u043b\u0438 \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u0438 \u0441\u0435\u0442\u0438. \u041a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e, APIRequestContext \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u043c\u043e\u043a\u0438, \u0442\u043e \u0435\u0441\u0442\u044c \u043f\u043e\u0434\u043c\u0435\u043d\u044f\u0442\u044c \u043e\u0442\u0432\u0435\u0442\u044b \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u043d\u0430 \u0437\u0430\u0440\u0430\u043d\u0435\u0435 \u0437\u0430\u0434\u0430\u043d\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435. \u042d\u0442\u043e \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e \u043f\u043e\u043b\u0435\u0437\u043d\u043e \u0434\u043b\u044f \u0438\u0437\u043e\u043b\u044f\u0446\u0438\u0438 \u0442\u0435\u0441\u0442\u043e\u0432 \u043e\u0442 \u0432\u043d\u0435\u0448\u043d\u0438\u0445 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439 \u0438 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0435\u043d\u0438\u044f \u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f. \u041f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u043c \u043a \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044e \u0442\u0435\u0441\u0442\u043e\u0432.<\/p>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0431\u0430\u0437\u043e\u0432\u0443\u044e \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u0443 \u0434\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432:<\/p>\n<pre><code class=\"python\">@pytest.fixture(scope=\"session\") def request_context(playwright: Playwright) -&gt; Generator[APIRequestContext, None, None]:     context = playwright.request.new_context(base_url=base_settings.backend_url)     yield context     context.dispose()<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430 \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u0443 \u0441 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0435\u0439:  <\/p>\n<pre><code class=\"python\">@pytest.fixture(scope=\"session\") def api_context(request_context: APIRequestContext) -&gt; Generator[APIRequestContext, None, None]:     payload = AuthPayload(email=\"your_email\", password=\"your_password\").dict()     res = request_context.post(url=APIRoutes.AUTH, data=payload)     assert res.ok, res.json()     res_data = res.json()     assert \"token\" in res_data[\"user\"]      auth_context = request_context.new_context(         extra_http_headers={\"Authorization\": f\"Bearer {res_data['user']['token']}\"},     )     yield auth_context     auth_context.dispose()<\/code><\/pre>\n<p>\u00a0\u0413\u043e\u0442\u043e\u0432\u043e, \u0442\u0435\u043f\u0435\u0440\u044c \u0432\u0441\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u044d\u0442\u043e\u0439 \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u044b \u0431\u0443\u0434\u0443\u0442 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u043e\u0432\u0430\u043d\u044b.<\/p>\n<p>\u041d\u0430\u043f\u0438\u0448\u0435\u043c \u043f\u0435\u0440\u0432\u044b\u0439 \u0442\u0435\u0441\u0442 \u2013 \u043d\u0430 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0441\u0442\u0430\u0442\u044c\u0438. \u0421\u043f\u0435\u0440\u0432\u0430 \u043e\u043f\u0438\u0448\u0435\u043c Pydantic-\u043c\u043e\u0434\u0435\u043b\u044c:<\/p>\n<pre><code class=\"python\">class Author(BaseModel): username: str bio: str | None = None image: str | None = None following: bool followers_count: int = Field(..., alias=\"followersCount\")   class Article(BaseModel): slug: str | None = None title: str = Field(default_factory=lambda: fake.sentence(nb_words=10)) description: str = Field(default_factory=lambda: fake.sentence(nb_words=10)) body: str = Field(default_factory=lambda: fake.paragraph(nb_sentences=5)) tag: list[str] = Field(default_factory=lambda: [fake.tags()], alias=\"tagList\") updated_at: datetime | None = Field(default=None, alias=\"updatedAt\") created_at: datetime | None = Field(default=None, alias=\"createdAt\") author: Author | None = None favorited: bool | None = None favorites_count: int | None = Field(default=None, alias=\"favoritesCount\")   class ArticlePayload(BaseModel): article: Article<\/code><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c \u0432\u0441\u0435 \u0443\u0436\u0435 \u0437\u043d\u0430\u043a\u043e\u043c\u043e, \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u043c\u043e\u0434\u0435\u043b\u0438 Author \u0438 Article. \u0418\u0437 \u043d\u043e\u0432\u043e\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 alias \u0434\u043b\u044f \u043e\u0431\u044a\u0435\u043a\u0442\u0430 Field, \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u0435 \u0432 \u044d\u0442\u043e\u043c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u043b\u044f \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0438 \u0434\u0435\u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0434\u0430\u043d\u043d\u044b\u0445. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, followersCount \u0432 JSON \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d \u0432 followers_count \u0432 \u043d\u0430\u0448\u0435\u0439 \u043c\u043e\u0434\u0435\u043b\u0438. \u0422\u0430\u043a\u0436\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c ArticlePayload \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0442\u0435\u043b\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u0430, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043e\u0436\u0438\u0434\u0430\u0435\u0442 \u0441\u0435\u0440\u0432\u0435\u0440.<\/p>\n<p>\u041f\u0435\u0440\u0435\u0439\u0434\u0435\u043c \u043a \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044e \u043f\u0435\u0440\u0432\u043e\u0433\u043e API-\u0442\u0435\u0441\u0442\u0430:<\/p>\n<pre><code class=\"python\">def test_create_article(api_context, slug): article = Article() data = ArticlePayload(article=article).model_dump(     by_alias=True,     exclude={         \"article\": {             \"author\",             \"slug\",             \"updated\",             \"created_at\",             \"favorited\",             \"favorites_count\",         }     }, ) res = api_context.post(APIRoutes.ARTICLE, data=data) assert res.ok res = res.json() slug.append(res[\"article\"][\"slug\"]) try:     ArticlePayload(**res) except ValidationError as e:     pytest.fail(f\"Validation failed: {e}\")<\/code><\/pre>\n<p>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0440\u0430\u043d\u0435\u0435 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043d\u0443\u044e \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u0443, \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u0441\u043b\u043e\u0432\u0430\u0440\u044c data \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043c\u0435\u0442\u043e\u0434\u0430 model_dump, \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u0438\u0441\u043a\u043b\u044e\u0447\u0430\u0435\u043c \u043f\u043e\u043b\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0432 \u0437\u0430\u043f\u0440\u043e\u0441\u0435 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430 exclude. \u0422\u0430\u043a\u0436\u0435 \u0432 \u0442\u0435\u0441\u0442 \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u0430 \u0435\u0449\u0435 \u043e\u0434\u043d\u0430 \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u0430 slug, \u0441 \u0435\u0435 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u043c \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0438, \u0447\u0442\u043e\u0431\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0435\u0435 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u044c \u0432 \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0438\u0445 \u0442\u0435\u0441\u0442\u0430\u0445. \u0412\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043e\u043d\u0430 \u043d\u0435\u0437\u0430\u043c\u044b\u0441\u043b\u043e\u0432\u0430\u0442\u043e:  <\/p>\n<pre><code class=\"python\">@pytest.fixture(scope=\"session\") def ids(): id = [] yield ids<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u0442\u0435\u0441\u0442 \u043d\u0430 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f \u043a \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435. \u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u043e\u043f\u0438\u0448\u0435\u043c pydantic-\u043c\u043e\u0434\u0435\u043b\u044c \u0434\u043b\u044f \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f:  <\/p>\n<pre><code class=\"python\">class Comment(BaseModel): id: int body: str = Field(default_factory=lambda: fake.sentence(nb_words=10)) updated_at: datetime | None = Field(default=None, alias=\"updatedAt\") created_at: datetime | None = Field(default=None, alias=\"createdAt\") author: Author   class CommentPayload(BaseModel): comment: Comment<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0442\u0435\u0441\u0442:   <\/p>\n<pre><code class=\"python\">@allure.title(\"API: \u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f \u043a \u0441\u0442\u0430\u0442\u044c\u0435\") def test_add_comment_to_article(api_context, ids): data = CommentPayload().model_dump(     by_alias=True, exclude={\"comment\": {\"author\", \"updated_at\", \"created_at\"}} ) res = api_context.post(f\"{APIRoutes.ARTICLE}\/{ids[0]}\") assert res.ok try:     CommentPayload(**res) except ValidationError as e:     pytest.fail(f\"Validation failed: {e}\")<\/code><\/pre>\n<p>\u041f\u043e\u0441\u043b\u0435 \u043f\u0440\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0432\u0430\u0436\u043d\u043e \u043d\u0435 \u0437\u0430\u0431\u044b\u0432\u0430\u0442\u044c \u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445, \u043f\u0435\u0440\u0435\u0439\u0434\u0435\u043c \u043a \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044e \u0441\u0442\u0430\u0442\u044c\u0438 \u043f\u043e API, \u0437\u0430\u043e\u0434\u043d\u043e \u043f\u043e\u043a\u0440\u043e\u0435\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b:<\/p>\n<pre><code class=\"python\">def test_del_article(api_context, ids): res = api_context.delete(f\"{APIRoutes.ARTICLE}\/{ids[0]}\") assert res.ok res = res.json() assert \"Article deleted successfully\" in res[\"message\"][\"body\"][0]<\/code><\/pre>\n<p>\u041e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0433\u043e\u0442\u043e\u0432\u0430. \u041c\u044b \u043d\u0430\u043f\u0438\u0441\u0430\u043b\u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e UI- \u0438 API-\u0442\u0435\u0441\u0442\u043e\u0432, \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u0442\u044c \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0442\u0435\u0441\u0442\u043e\u0432 \u043f\u043e \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0438, \u0434\u0430\u043b\u0435\u0435 \u043f\u0435\u0440\u0435\u0439\u0434\u0435\u043c \u043a \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0435 \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b.<\/p>\n<p>\u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430 \u0434\u043b\u044f CI\/CD \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c GitLab. \u041f\u0435\u0440\u0435\u0439\u0434\u0435\u043c \u043a \u0435\u0433\u043e \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0435 \u0438 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043d\u043e\u0432\u044b\u0439 \u043f\u0440\u043e\u0435\u043a\u0442:<\/p>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/335\/f67\/903\/335f67903d915d26aa38830913dd0a41.png\" alt=\"\u0420\u0438\u0441 4. \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f\" title=\"\u0420\u0438\u0441 4. \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f\" width=\"624\" height=\"315\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/335\/f67\/903\/335f67903d915d26aa38830913dd0a41.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/335\/f67\/903\/335f67903d915d26aa38830913dd0a41.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption><em>\u0420\u0438\u0441 4. \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f<\/em><\/figcaption><\/div>\n<\/figure>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0443\u0436\u043d\u043e \u0437\u0430\u0434\u0430\u0442\u044c \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b:  <\/p>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/8ca\/a57\/42c\/8caa5742c6134596bae96e730304852b.png\" alt=\"\u0420\u0438\u0441 5. \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f\" title=\"\u0420\u0438\u0441 5. \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f\" width=\"624\" height=\"289\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/8ca\/a57\/42c\/8caa5742c6134596bae96e730304852b.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/8ca\/a57\/42c\/8caa5742c6134596bae96e730304852b.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption><em>\u0420\u0438\u0441 5. \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f<\/em><\/figcaption><\/div>\n<\/figure>\n<p>\u041d\u0430\u0436\u0438\u043c\u0430\u0435\u043c \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442. \u041d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0437\u0430\u043f\u0443\u0448\u0438\u0442\u044c \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 \u043f\u0440\u043e\u0435\u043a\u0442, GitLab \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442, \u0447\u0442\u043e \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0443\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043a\u043e\u043c\u0430\u043d\u0434\u044b:<\/p>\n<pre><code>git init --initial-branch=main git remote add origin https:\/\/gitlab.com\/&lt;username&gt;\/real-world-app-testing.git git add . git commit -m \"Initial commit\"  git push --set-upstream origin main<\/code><\/pre>\n<p>\u041f\u0440\u043e\u0435\u043a\u0442 \u0432\u044b\u0433\u0440\u0443\u0436\u0435\u043d \u0438 \u0433\u043e\u0442\u043e\u0432 \u043a \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0435 CI\/CD.  <\/p>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/f55\/be9\/607\/f55be960724071085aef73e2d6f3e225.png\" alt=\"\u0420\u0438\u0441 6. \u0420\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439\" title=\"\u0420\u0438\u0441 6. \u0420\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439\" width=\"1949\" height=\"1460\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/f55\/be9\/607\/f55be960724071085aef73e2d6f3e225.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/f55\/be9\/607\/f55be960724071085aef73e2d6f3e225.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption><em>\u0420\u0438\u0441 6. \u0420\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439<\/em><\/figcaption><\/div>\n<\/figure>\n<p>\u0414\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u043e\u0432 \u0442\u0435\u0441\u0442\u043e\u0432 \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 CI\/CD \u043d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f GitLab Runner. \u042d\u0442\u043e\u0442 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u043c \u0432 \u0441\u0438\u0441\u0442\u0435\u043c\u0435 \u043d\u0435\u043f\u0440\u0435\u0440\u044b\u0432\u043d\u043e\u0439 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438 \u0438 \u0434\u043e\u0441\u0442\u0430\u0432\u043a\u0438 \u0432 \u044d\u043a\u043e\u0441\u0438\u0441\u0442\u0435\u043c\u0435 GitLab. \u041e\u043d \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d \u0434\u043b\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0437\u0430\u0434\u0430\u043d\u0438\u0439 \u0438 \u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u044b \u0432 .gitlab-ci.yml \u0444\u0430\u0439\u043b\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430. \u0412 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043f\u043e\u0441\u043b\u0435 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043a\u043e\u043c\u043c\u0438\u0442\u0430 \u0440\u0430\u043d\u043d\u0435\u0440 \u0431\u0443\u0434\u0435\u0442 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0441\u043e\u0431\u0438\u0440\u0430\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442, \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0442\u0435\u0441\u0442\u044b \u0438 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u043e\u0442\u0447\u0435\u0442 \u043e \u043f\u0440\u043e\u0439\u0434\u0435\u043d\u043d\u044b\u0445 \u0442\u0435\u0441\u0442\u0430\u0445.<br \/>\u0414\u043b\u044f \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u044f \u043f\u0440\u043e\u0432\u0435\u0434\u0443 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443 \u0440\u0430\u043d\u043d\u0435\u0440\u0430 \u043d\u0430 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0439 \u043c\u0430\u0448\u0438\u043d\u0435 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0434\u043e\u043a\u0435\u0440\u0430. \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0440\u0430\u043d\u043d\u0435\u0440\u0430 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435 \u0431\u0443\u0434\u0435\u0442 \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e\u0439. \u0412\u043e\u0437\u044c\u043c\u0435\u043c \u043a\u043e\u043c\u0430\u043d\u0434\u0443 \u0434\u043b\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0440\u0430\u043d\u043d\u0435\u0440\u0430 \u0438\u0437 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 <a href=\"https:\/\/docs.gitlab.com\/runner\/install\/docker.html.\">GitLab.<\/a><\/p>\n<pre><code>docker run -d --name gitlab-runner --restart always \\   -v \/var\/run\/docker.sock:\/var\/run\/docker.sock \\   -v \/srv\/gitlab-runner\/config:\/etc\/gitlab-runner \\   gitlab\/gitlab-runner:latest<\/code><\/pre>\n<p>\u0420\u0430\u043d\u043d\u0435\u0440 \u0437\u0430\u043f\u0443\u0449\u0435\u043d, \u043d\u043e \u044d\u0442\u043e \u0435\u0449\u0435 \u043d\u0435 \u0432\u0441\u0435, \u0442\u0435\u043f\u0435\u0440\u044c \u0435\u0433\u043e \u043d\u0443\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u043c \u0434\u043b\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u043f\u0440\u043e\u0439\u0434\u0435\u043c \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438.<\/p>\n<p>\u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u043c \u044d\u0442\u0443 \u043a\u043e\u043c\u0430\u043d\u0434\u0443 \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438:<\/p>\n<pre><code>  docker exec -it gitlab-runner gitlab-runner register<\/code><\/pre>\n<p>\u0420\u0430\u043d\u043d\u0435\u0440 \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0438\u0442 \u043f\u0440\u043e\u0439\u0442\u0438 \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438, \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u0442\u043e\u043a\u0435\u043d, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u043f\u043e \u043f\u0443\u0442\u0438 Settings -&gt; CI\/CD \u0432\u043a\u043b\u0430\u0434\u043a\u0430 Runners.  <\/p>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/6c3\/82e\/93f\/6c382e93f173f3d70748e73310dbb772.png\" alt=\"\u0420\u0438\u0441. 7. \u0420\u0430\u043d\u043d\u0435\u0440\u044b \u043f\u0440\u043e\u0435\u043a\u0442\u0430  \" title=\"\u0420\u0438\u0441. 7. \u0420\u0430\u043d\u043d\u0435\u0440\u044b \u043f\u0440\u043e\u0435\u043a\u0442\u0430  \" width=\"565\" height=\"471\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/6c3\/82e\/93f\/6c382e93f173f3d70748e73310dbb772.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/6c3\/82e\/93f\/6c382e93f173f3d70748e73310dbb772.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption><em>\u0420\u0438\u0441. 7. \u0420\u0430\u043d\u043d\u0435\u0440\u044b \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/em>  <\/figcaption><\/div>\n<\/figure>\n<p>\u0422\u0430\u043a\u0436\u0435 \u043d\u0430 \u044d\u0442\u043e\u0439 \u0436\u0435 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043e\u0442\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u043e\u0431\u0449\u0435\u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0435 \u0440\u0430\u043d\u043d\u0435\u0440\u044b, \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0435 GitLab, \u0442\u0430\u043a \u043a\u0430\u043a \u0442\u0435\u043f\u0435\u0440\u044c \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u0441\u0432\u043e\u0439.<\/p>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/680\/a18\/2b4\/680a182b46275665df1deeef9fd2f354.png\" alt=\"\u0420\u0438\u0441 8. \u0420\u0430\u043d\u043d\u0435\u0440\u044b, \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c\u044b\u0435 GitLab\" title=\"\u0420\u0438\u0441 8. \u0420\u0430\u043d\u043d\u0435\u0440\u044b, \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c\u044b\u0435 GitLab\" width=\"615\" height=\"357\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/680\/a18\/2b4\/680a182b46275665df1deeef9fd2f354.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/680\/a18\/2b4\/680a182b46275665df1deeef9fd2f354.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption><em>\u0420\u0438\u0441 8. \u0420\u0430\u043d\u043d\u0435\u0440\u044b, \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c\u044b\u0435 GitLab<\/em><\/figcaption><\/div>\n<\/figure>\n<p>\u041f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u0435\u043c \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u0440\u0430\u043d\u043d\u0435\u0440\u0430: \u0432\u0441\u0435 \u043f\u043e\u043b\u044f \u043c\u043e\u0436\u043d\u043e \u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0442\u044c \u0441\u043e \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u043c\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f\u043c\u0438, \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u0442\u043e\u043a\u0435\u043d \u0438 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0435, \u0447\u0442\u043e \u043d\u0443\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0431\u0440\u0430\u0442\u044c, executor. \u0412 \u0440\u0430\u043c\u043a\u0430\u0445 GitLab-runner\u2019a \u2013 \u044d\u0442\u043e \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 \u0441\u0440\u0435\u0434\u0443, \u0433\u0434\u0435 \u0431\u0443\u0434\u0443\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c\u0441\u044f \u0437\u0430\u0434\u0430\u0447\u0438 (Jobs) \u043d\u0430\u0448\u0435\u0433\u043e \u0440\u0430\u043d\u043d\u0435\u0440\u0430. \u0412\u044b\u0431\u0438\u0440\u0430\u0435\u043c docker, \u0442\u0435\u043f\u0435\u0440\u044c \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043b\u0435\u043d\u043d\u0430\u044f \u0441\u0440\u0435\u0434\u0430 \u0434\u043b\u044f \u0441\u0431\u043e\u0440\u043a\u0438 \u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u043e\u0432 \u0438\u0437 \u0440\u0430\u043d\u043d\u0435\u0440\u0430. \u041d\u043e \u0435\u0441\u0442\u044c \u0435\u0449\u0435 \u043e\u0434\u0438\u043d \u0432\u0430\u0436\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442: \u0447\u0442\u043e\u0431\u044b \u0434\u0436\u043e\u0431\u044b \u043c\u043e\u0433\u043b\u0438 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0441 Docker \u043d\u0430 \u043d\u0430\u0448\u0435\u043c \u0445\u043e\u0441\u0442\u0435, \u043d\u0443\u0436\u043d\u043e \u0434\u0430\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u0434\u0435\u043c\u043e\u043d\u0443 \u0434\u043e\u043a\u0435\u0440\u0430. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0432 \u0444\u0430\u0439\u043b\u0435 \u0441 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u043c\u0438 \u0440\u0430\u043d\u043d\u0435\u0440\u0430 \u043f\u043e \u043f\u0443\u0442\u0438 \/etc\/giltab-runner\/config.toml (\u043f\u0443\u0442\u044c \u0432 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0435) \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0432 \u043c\u0430\u0441\u0441\u0438\u0432 volumes \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u201c\/var\/run\/docker.sock:\/var\/run\/docker.sock\u201d. \u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u043c\u044b \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u043b\u0438 \u0441\u043e\u043a\u0435\u0442 Docker\u2019a \u0441 \u0445\u043e\u0441\u0442\u0430 \u043a \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0443 \u0437\u0430\u0434\u0430\u0447\u0438.<\/p>\n<p>\u0413\u043e\u0442\u043e\u0432\u043e! \u0422\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0436\u0435\u043c \u043e\u0431\u043d\u043e\u0432\u0438\u0442\u044c \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443 \u0432 GitLab \u0438 \u0443\u0432\u0438\u0434\u0438\u043c \u043d\u0430\u0448 \u043d\u043e\u0432\u0435\u043d\u044c\u043a\u0438\u0439 \u0440\u0430\u043d\u043d\u0435\u0440, \u0443\u0440\u0430! \ud83d\ude42 \u0414\u043b\u044f \u0442\u043e\u0433\u043e \u0447\u0442\u043e\u0431\u044b \u0440\u0430\u043d\u043d\u0435\u0440 \u043d\u0430\u0447\u0430\u043b \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u0437\u0430\u0434\u0430\u0447\u0438, \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0444\u0430\u0439\u043b .gitlab-ci.yml \u0432 \u043a\u043e\u0440\u043d\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430. \u042d\u0442\u043e\u0442 \u0444\u0430\u0439\u043b \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u043c \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u043c \u0444\u0430\u0439\u043b\u043e\u043c \u0434\u043b\u044f \u0441\u0438\u0441\u0442\u0435\u043c\u044b CI\/CD. \u041e\u043d \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u0438 \u0438 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0438\u0440\u0443\u044e\u0442 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u044b \u043d\u0435\u043f\u0440\u0435\u0440\u044b\u0432\u043d\u043e\u0439 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043f\u043e\u0441\u043b\u0435 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043a\u043e\u043c\u043c\u0438\u0442\u0430 \u0438\u043b\u0438 \u0432 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u0438 \u0441 \u0437\u0430\u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u043f\u0440\u0430\u0432\u0438\u043b\u0430\u043c\u0438. \u041d\u0430\u043f\u0438\u0448\u0435\u043c \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e:<\/p>\n<pre><code class=\"yaml\">stages:   - build   - run   build test:   image: docker:latest   stage: build   script: - docker build -f Dockerfile.prod -t test_real_world_app:latest .   rules: - if: $CI_COMMIT_BRANCH == \"main\"   when: always   run test:   image: docker:latest   stage: run   before_script: - docker rm $(docker ps -aq) || true - docker run -d --rm --env-file .env --name test_real_world_app -p 8080:80 test_real_world_app:latest   script: - docker exec test_real_world_app pytest --color=yes   rules: - if: $CI_COMMIT_BRANCH == \"main\"   when: always<\/code><\/pre>\n<p>\u0424\u0430\u0439\u043b \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 \u0434\u0432\u0443\u0445 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0445 \u044d\u0442\u0430\u043f\u043e\u0432: \u0441\u0431\u043e\u0440\u043a\u0430 \u2018build\u2019 \u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0442\u0435\u0441\u0442\u043e\u0432 \u2018run\u2019. \u0412 \u043f\u0435\u0440\u0432\u043e\u043c \u044d\u0442\u0430\u043f\u0435 \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u043a\u043e\u043c\u0430\u043d\u0434\u0443 build \u0434\u043b\u044f \u0441\u0431\u043e\u0440\u043a\u0438 \u043e\u0431\u0440\u0430\u0437\u0430 \u0438\u0437 <a href=\"http:\/\/Dockerfile.prod\">Dockerfile.prod<\/a>, \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u043e\u0431\u0440\u0430\u0437 \u043c\u0430\u0440\u043a\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0442\u0435\u0433\u043e\u043c \u2018latest\u2019. \u0412\u043e \u0432\u0442\u043e\u0440\u043e\u043c \u044d\u0442\u0430\u043f\u0435 \u043f\u043e\u0434\u0433\u043e\u0442\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u00ab\u0447\u0438\u0441\u0442\u043e\u0435\u00bb \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0438 \u0438\u0437 \u0433\u043e\u0442\u043e\u0432\u043e\u0433\u043e \u043e\u0431\u0440\u0430\u0437\u0430 \u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c Docker-\u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440, \u0434\u0430\u043b\u0435\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u043c \u0442\u0435\u0441\u0442\u044b. \u0417\u0430\u0434\u0430\u043d\u0438\u044f CI\/CD \u0431\u0443\u0434\u0443\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0432 \u0442\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435, \u0435\u0441\u043b\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432\u043d\u0435\u0441\u0435\u043d\u044b \u0432 \u0432\u0435\u0442\u043a\u0443 main.<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u0439\u0442\u0438 \u043a \u0441\u0430\u043c\u043e\u0439 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u2013 \u043a \u0437\u0430\u043f\u0443\u0441\u043a\u0443 \u0442\u0435\u0441\u0442\u043e\u0432 \u0432 GitLab. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0434\u0435\u043b\u0430\u0435\u043c \u043a\u043e\u043c\u043c\u0438\u0442 \u0438 \u043f\u0443\u0448\u0438\u043c \u0432 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439, \u0432 \u0440\u0430\u0437\u0434\u0435\u043b\u0435 Build -&gt; Pipelines \u0432\u0438\u0434\u0438\u043c \u043f\u043e\u0445\u043e\u0436\u0443\u044e \u043a\u0430\u0440\u0442\u0438\u043d\u0443:<\/p>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/039\/a78\/f8b\/039a78f8b0d78637a9a1d6124a1d9af3.png\" alt=\"\u0420\u0438\u0441 9. \u0417\u0430\u043f\u0443\u0449\u0435\u043d\u043d\u044b\u0439 \u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d\" title=\"\u0420\u0438\u0441 9. \u0417\u0430\u043f\u0443\u0449\u0435\u043d\u043d\u044b\u0439 \u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d\" width=\"624\" height=\"79\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/039\/a78\/f8b\/039a78f8b0d78637a9a1d6124a1d9af3.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/039\/a78\/f8b\/039a78f8b0d78637a9a1d6124a1d9af3.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption><em>\u0420\u0438\u0441 9. \u0417\u0430\u043f\u0443\u0449\u0435\u043d\u043d\u044b\u0439 \u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d<\/em><\/figcaption><\/div>\n<\/figure>\n<p>\u041f\u0430\u0439\u043f\u043b\u0430\u0439\u043d \u0437\u0430\u043f\u0443\u0449\u0435\u043d. \u0414\u043e\u0436\u0438\u0434\u0430\u0435\u043c\u0441\u044f \u0441\u0431\u043e\u0440\u043a\u0438 \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u0433\u043e \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430, \u0430 \u0437\u0430\u0442\u0435\u043c \u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0441\u0430\u043c\u0438\u0445 \u0442\u0435\u0441\u0442\u043e\u0432.<\/p>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/eb2\/8d5\/7ed\/eb28d57edc884664a372431c7f180bb7.png\" alt=\"\u0420\u0438\u0441 10. \u041b\u043e\u0433\u0438 \u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d\u0430\" title=\"\u0420\u0438\u0441 10. \u041b\u043e\u0433\u0438 \u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d\u0430\" width=\"624\" height=\"315\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/eb2\/8d5\/7ed\/eb28d57edc884664a372431c7f180bb7.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/eb2\/8d5\/7ed\/eb28d57edc884664a372431c7f180bb7.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption><em>\u0420\u0438\u0441 10. \u041b\u043e\u0433\u0438 \u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d\u0430<\/em><\/figcaption><\/div>\n<\/figure>\n<p>\u0412 UI GitLab \u043f\u0435\u0440\u0435\u0439\u0434\u0435\u043c \u0432 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 \u0441\u0442\u0435\u0439\u0434\u0436. \u0412\u0438\u0434\u0438\u043c, \u0447\u0442\u043e \u0442\u0435\u0441\u0442\u044b \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u043f\u0440\u043e\u0439\u0434\u0435\u043d\u044b. \u041e\u0434\u043d\u0430\u043a\u043e \u0440\u0430\u0431\u043e\u0442\u0430 \u043d\u0430 \u044d\u0442\u043e\u043c \u043d\u0435 \u0437\u0430\u043a\u0430\u043d\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f. \u0417\u0435\u043b\u0435\u043d\u044b\u0435 \u043d\u0430\u0434\u043f\u0438\u0441\u0438 PASSED, \u043a\u043e\u043d\u0435\u0447\u043d\u043e, \u0445\u043e\u0440\u043e\u0448\u043e, \u043d\u043e \u044d\u0442\u043e\u0433\u043e \u044f\u0432\u043d\u043e \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e. \u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0448\u0430\u0433 \u2013 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043e\u0442\u0447\u0435\u0442\u043e\u0432 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Allure. \u042d\u0442\u043e\u0442 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0431\u043b\u0435\u0433\u0447\u0438\u0442 \u0432\u043e\u0441\u043f\u0440\u0438\u044f\u0442\u0438\u0435 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432, \u043d\u043e \u0438 \u043f\u043e\u0432\u044b\u0441\u0438\u0442 \u0438\u0445 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u044c. Allure-\u043e\u0442\u0447\u0435\u0442 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u0438\u0442 \u0432\u0441\u0435\u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u0439 \u0430\u043d\u0430\u043b\u0438\u0437 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432 \u0442\u0435\u0441\u0442\u043e\u0432: \u043e\u0442 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0438\u0441\u0442\u043e\u0440\u0438\u0438 \u0442\u0435\u0441\u0442\u043e\u0432 \u0434\u043e \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u0433\u043e \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0448\u0430\u0433\u043e\u0432 \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f \u043e\u0448\u0438\u0431\u043e\u043a. \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u0438\u0445, \u043a\u043e\u043c\u0430\u043d\u0434\u0430 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0441\u0442\u0440\u0435\u0435 \u0432\u044b\u044f\u0432\u043b\u044f\u0442\u044c \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u043d\u044b\u0435 \u043e\u0431\u043b\u0430\u0441\u0442\u0438 \u0432 \u0440\u0430\u0431\u043e\u0442\u0435 \u041f\u041e \u0438 \u0441\u0432\u043e\u0435\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u0443\u0441\u0442\u0440\u0430\u043d\u044f\u0442\u044c \u0438\u0445. \u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 Allure \u043a \u043d\u0430\u0448\u0435\u043c\u0443 CI-\u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d\u0443 \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u043d\u0430\u043c \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043e\u0442\u0447\u0435\u0442\u044b \u043f\u043e\u0441\u043b\u0435 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0442\u0435\u0441\u0442\u043e\u0432, \u0434\u0435\u043b\u0430\u044f \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0430\u043d\u0430\u043b\u0438\u0437\u0430 \u0435\u0449\u0435 \u0431\u043e\u043b\u0435\u0435 \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u044b\u043c.<\/p>\n<p>\u0411\u0443\u0434\u0435\u043c \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 \u0443\u0436\u0435 \u0437\u043d\u0430\u043a\u043e\u043c\u044b\u043c \u0444\u0430\u0439\u043b\u043e\u043c .gitlab-ci.yml. \u0414\u043b\u044f \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u043e\u0442\u0447\u0435\u0442\u0430 \u043d\u0443\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043d\u043e\u0432\u044b\u0439 \u044d\u0442\u0430\u043f report \u0432 \u043d\u0430\u0448 \u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c\u0441\u044f \u043f\u043e\u0441\u043b\u0435 \u043f\u0440\u043e\u0433\u043e\u043d\u0430 \u0442\u0435\u0441\u0442\u043e\u0432. \u0422\u0430\u043a\u0436\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043e\u0431\u043d\u043e\u0432\u0438\u0442\u044c \u043a\u043e\u043c\u0430\u043d\u0434\u0443 pytest, \u0434\u043e\u0431\u0430\u0432\u0438\u0432 \u0444\u043b\u0430\u0433 alluredir, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u043a\u0430\u0442\u0430\u043b\u043e\u0433, \u0433\u0434\u0435 Allure \u0434\u043e\u043b\u0436\u0435\u043d \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u044c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u0442\u0435\u0441\u0442\u043e\u0432.<\/p>\n<p>\u041f\u0440\u0438\u043b\u0430\u0433\u0430\u044e \u043a\u043e\u0434 \u0441\u043e \u0441\u0442\u0435\u0439\u0434\u0436\u0430\u043c\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u043e\u0434\u0432\u0435\u0440\u0433\u043b\u0438\u0441\u044c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f\u043c:<\/p>\n<pre><code class=\"yaml\">run test:   image: docker:latest   stage: run   before_script: - docker rm $(docker ps -aq) || true - docker run -d --rm --memory=\"500m\" --env-file .env --name test_real_world_app -p 8080:80 test_real_world_app:latest   script: - docker exec test_real_world_app pytest --color=yes --alluredir=\/allure-results   after_script: - docker cp test_real_world_app:\/allure-results .\/allure-results   rules: - if: $CI_COMMIT_BRANCH == \"main\"   when: always   generate report:   image: docker:latest   stage: report   script: - docker run --rm -v $(pwd)\/allure-results:\/allure-results -v $(pwd)\/allure-report:\/allure-report frankescobar\/allure-docker-service allure generate \/allure-results -o \/allure-report --clean   artifacts: paths:   - allure-report   rules: - if: $CI_COMMIT_BRANCH == \"main\"   when: always<\/code><\/pre>\n<p><a class=\"anchor\" name=\"8\" id=\"8\"><\/a><\/p>\n<h2>\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/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\u043e\u043b\u043d\u044b\u0439 \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0441 \u043d\u0443\u043b\u044f, \u0432\u043a\u043b\u044e\u0447\u0430\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0442\u0430\u043a\u0438\u0445 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0439 \u0438 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432, \u043a\u0430\u043a Playwright, Pytest \u0438 <a href=\"https:\/\/habr.com\/ru\/companies\/simbirsoft\/articles\/733486\/\">Allure<\/a>, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443 CI\/CD \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e GitLab. \u041e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u043b\u0438\u0441\u044c \u0441 \u0442\u0435\u043c, \u043a\u0430\u043a \u0432 \u0443\u0441\u043b\u043e\u0432\u0438\u044f\u0445 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u044f \u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u043b\u0430\u0434\u0438\u0442\u044c \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u0438 \u0442\u0435\u0441\u0442\u043e\u0432, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u0437\u043d\u0430\u043d\u0438\u044f \u0440\u0443\u0447\u043d\u043e\u0433\u043e \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0449\u0438\u043a\u0430 \u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0433\u043e \u043d\u0430\u0431\u043e\u0440\u0430 \u0442\u0435\u0441\u0442-\u043a\u0435\u0439\u0441\u043e\u0432 \u0438 \u0438\u0445 \u043f\u043e\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u0438.<\/p>\n<p>\u0422\u0430\u043a\u0436\u0435 \u043c\u044b \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043b\u0438 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0443 \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u0434\u043b\u044f \u043f\u0440\u043e\u0433\u043e\u043d\u0430 \u0442\u0435\u0441\u0442\u043e\u0432 \u0432 GitLab CI \u0441 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u043e\u0439 \u043e\u0442\u0447\u0435\u0442\u043e\u0432 Allure. \u041c\u044b \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u043b\u0438 \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u044b, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0442\u0435\u0441\u0442\u043e\u0432, \u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043b\u0438 \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0435 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0438 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c Playwright \u0432 \u0447\u0430\u0441\u0442\u0438 UI \u0438 API. \u041f\u043e\u043c\u0438\u043c\u043e \u044d\u0442\u043e\u0433\u043e \u043c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043b\u0438 \u043e\u043f\u0442\u0438\u043c\u0430\u043b\u044c\u043d\u0443\u044e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0449\u0443\u044e \u043d\u043e\u0432\u043e\u043c\u0443 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0442\u043e\u0440\u0443 \u0431\u044b\u0441\u0442\u0440\u043e \u043e\u0441\u0432\u043e\u0438\u0442\u044c\u0441\u044f \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0438 \u043d\u0430\u0447\u0430\u0442\u044c \u043f\u043e\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u043d\u043e\u0432\u044b\u043c\u0438 \u0442\u0435\u0441\u0442\u0430\u043c\u0438.<\/p>\n<p>\u0414\u0430\u043b\u0435\u0435 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u043b\u0438 \u0437\u0430\u043f\u0443\u0441\u043a \u043f\u0440\u043e\u0433\u043e\u043d\u0430 \u0442\u0435\u0441\u0442\u043e\u0432 \u0447\u0435\u0440\u0435\u0437 UI GitLab, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u043a\u0430\u043a QA-\u0441\u043f\u0435\u0446\u0438\u0430\u043b\u0438\u0441\u0442\u0443, \u0442\u0430\u043a \u0438 \u043b\u044e\u0431\u043e\u043c\u0443 \u0437\u0430\u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043e\u0432\u0430\u043d\u043d\u043e\u043c\u0443 \u043b\u0438\u0446\u0443 \u043f\u0440\u043e\u0433\u043d\u0430\u0442\u044c \u0442\u0435\u0441\u0442\u044b \u0438 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u043f\u0440\u043e\u0439\u0434\u0435\u043d\u043d\u044b\u0445 \u0442\u0435\u0441\u0442\u0430\u0445 \u0432 \u0432\u0438\u0434\u0435 Allure-\u043e\u0442\u0447\u0435\u0442\u043e\u0432.<\/p>\n<p>\u041d\u0435\u0441\u043c\u043e\u0442\u0440\u044f \u043d\u0430 \u0442\u043e, \u0447\u0442\u043e \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u2013 \u043d\u0435 \u043f\u0440\u043e\u0441\u0442\u0430\u044f \u0437\u0430\u0434\u0430\u0447\u0430 \u0438 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0443\u0441\u0438\u043b\u0438\u0439, \u043c\u044b \u043d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u043b\u0438, \u0447\u0442\u043e \u043e\u043d\u0430 \u0432\u043f\u043e\u043b\u043d\u0435 \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0438\u043c\u0430 \u0438 \u043f\u0440\u0438\u043d\u043e\u0441\u0438\u0442 \u043e\u0449\u0443\u0442\u0438\u043c\u044b\u0435 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b. <strong>\u041f\u043e\u0441\u043b\u0435 \u0435\u0435 \u0432\u043d\u0435\u0434\u0440\u0435\u043d\u0438\u044f \u0432\u0440\u0435\u043c\u044f \u043d\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0440\u0435\u0433\u0440\u0435\u0441\u0441\u0438\u043e\u043d\u043d\u043e\u0433\u043e \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0441\u043e\u043a\u0440\u0430\u0442\u0438\u043b\u043e\u0441\u044c \u0441 5 \u0447\u0430\u0441\u043e\u0432 \u0434\u043e 40 \u043c\u0438\u043d\u0443\u0442, \u0430 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0438\u0432\u0430\u0435\u043c\u044b\u0445 \u0431\u0430\u0433\u043e\u0432 \u043d\u0430 \u0440\u0430\u043d\u043d\u0438\u0445 \u0441\u0442\u0430\u0434\u0438\u044f\u0445 \u0443\u0432\u0435\u043b\u0438\u0447\u0438\u043b\u043e\u0441\u044c \u043d\u0430 40%.<\/strong> \u042d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u043b\u043e \u0432\u043d\u0435\u0434\u0440\u0438\u0442\u044c \u043d\u043e\u0432\u044b\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f<strong> \u0441 \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u043c\u0438 \u0440\u0438\u0441\u043a\u0430\u043c\u0438 \u0438 \u0443\u043b\u0443\u0447\u0448\u0438\u0442\u044c \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u043e \u0432\u044b\u043f\u0443\u0441\u043a\u0430\u0435\u043c\u043e\u0433\u043e \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u0430.<\/strong><\/p>\n<p><strong>\u0421\u043f\u0430\u0441\u0438\u0431\u043e \u0437\u0430 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435!<\/strong><\/p>\n<p><strong>\u0411\u043e\u043b\u044c\u0448\u0435 \u0430\u0432\u0442\u043e\u0440\u0441\u043a\u0438\u0445 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u043e\u0432 \u0434\u043b\u044f SDET-\u0441\u043f\u0435\u0446\u0438\u0430\u043b\u0438\u0441\u0442\u043e\u0432 \u043e\u0442 \u043c\u043e\u0438\u0445 \u043a\u043e\u043b\u043b\u0435\u0433 \u0447\u0438\u0442\u0430\u0439\u0442\u0435 \u0432 \u0441\u043e\u0446\u0441\u0435\u0442\u044f\u0445 SimbirSoft \u2013 <\/strong><a href=\"https:\/\/vk.com\/simbirsoft\"><strong>\u0412\u041a\u043e\u043d\u0442\u0430\u043a\u0442\u0435<\/strong><\/a><strong> \u0438 <\/strong><a href=\"https:\/\/t.me\/+hW2kOI83cYk2OTRi\"><strong>Telegram.<\/strong><\/a><\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/911344\/\"> https:\/\/habr.com\/ru\/articles\/911344\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u041c\u0435\u043d\u044f \u0437\u043e\u0432\u0443\u0442 \u0420\u043e\u043c\u0430\u043d. \u042f SDET-\u0441\u043f\u0435\u0446\u0438\u0430\u043b\u0438\u0441\u0442 \u0432 \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u0438 SimbirSoft. \u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043f\u043e\u0434\u0435\u043b\u044e\u0441\u044c \u0441\u0432\u043e\u0438\u043c \u043e\u043f\u044b\u0442\u043e\u043c \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u0433\u043e \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430 \u0441 \u043d\u0443\u043b\u044f \u0434\u043b\u044f \u043e\u0434\u043d\u043e\u0433\u043e \u0438\u0437 \u043d\u0430\u0448\u0438\u0445 \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432. \u041c\u0430\u0442\u0435\u0440\u0438\u0430\u043b \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043b\u0435\u0437\u0435\u043d \u0434\u043b\u044f \u043d\u0430\u0447\u0438\u043d\u0430\u044e\u0449\u0438\u0445 \u0438\u043b\u0438 \u0443\u0436\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u0438\u0441\u0442\u043e\u0432 \u0432 \u043e\u0431\u043b\u0430\u0441\u0442\u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0445\u043e\u0442\u044f\u0442 \u0431\u043e\u043b\u044c\u0448\u0435 \u0443\u0437\u043d\u0430\u0442\u044c:\u00a0<\/p>\n<p>\u2013 \u043e \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u0438 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u0438 \u0441 \u0441\u0430\u043c\u043e\u0433\u043e \u043d\u0430\u0447\u0430\u043b\u0430;\u00a0<\/p>\n<p>\u2013 \u043e \u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u044f\u0445, \u0441 \u043a\u043e\u0442\u043e\u0440\u044b\u043c\u0438 \u043c\u043e\u0436\u0435\u0442 \u0441\u0442\u043e\u043b\u043a\u043d\u0443\u0442\u044c\u0441\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0442\u043e\u0440;<\/p>\n<p>\u2013 \u043e\u0431 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430\u0445 \u0434\u043b\u044f \u043f\u043e\u0434\u0445\u043e\u0434\u044f\u0449\u0435\u0433\u043e \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u043f\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0445 \u043f\u0435\u0440\u0435\u0434 \u043d\u0438\u043c \u0437\u0430\u0434\u0430\u0447.<\/p>\n<p>\u0422\u0430\u043a\u0436\u0435 \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u044e \u0441\u0432\u043e\u044e \u0441\u0442\u0430\u0442\u044c\u044e \u0442\u0435\u043c \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u0438\u0441\u0442\u0430\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0443\u0436\u0435 \u043e\u0431\u043b\u0430\u0434\u0430\u044e\u0442 \u0431\u0430\u0437\u043e\u0432\u044b\u043c\u0438 \u0437\u043d\u0430\u043d\u0438\u044f\u043c\u0438 Python \u0438 Docker \u0438 \u0441\u0442\u0440\u0435\u043c\u044f\u0442\u0441\u044f \u0443\u0433\u043b\u0443\u0431\u0438\u0442\u044c \u0441\u0432\u043e\u0438 \u043d\u0430\u0432\u044b\u043a\u0438 \u0432 \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><strong>\u0421\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435<\/strong><\/p>\n<p><a href=\"#0\">\u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435<\/a><\/p>\n<p><a href=\"#1\">\u041e\u0431\u0437\u043e\u0440 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0439<\/a><\/p>\n<p><a href=\"#2\">\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b<\/a><\/p>\n<p><a href=\"#3\">\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/a><\/p>\n<p><a href=\"#4\">\u2022 Driver \u0438 BaseElement<\/a><\/p>\n<p><a href=\"#5\">\u2022 Page object<\/a><\/p>\n<p><a href=\"#6\">\u2022 UI-\u0442\u0435\u0441\u0442\u044b<\/a><\/p>\n<p><a href=\"#7\">\u2022 API-\u0442\u0435\u0441\u0442\u044b<\/a><\/p>\n<p><a href=\"#8\">\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/a><\/p>\n<p><a class=\"anchor\" name=\"0\" id=\"0\"><\/a><\/p>\n<p>\u0420\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0435\u043c\u044b\u0439 \u043f\u0440\u043e\u0435\u043a\u0442 \u2014 \u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u0430\u043c\u0438, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440\u0430\u043c \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u0442\u044c \u0437\u0430\u043d\u044f\u0442\u043e\u0441\u0442\u044c \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u043e\u0432, \u0438\u0445 \u043a\u043e\u043c\u043f\u0435\u0442\u0435\u043d\u0446\u0438\u0438 \u0438 \u0434\u0440\u0443\u0433\u0443\u044e \u043a\u043b\u044e\u0447\u0435\u0432\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e.<\/p>\n<p>\u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043f\u0440\u043e\u0435\u043a\u0442 \u0430\u043a\u0442\u0438\u0432\u043d\u043e \u0440\u0430\u0437\u0432\u0438\u0432\u0430\u043b\u0441\u044f \u0432 \u0442\u0435\u0447\u0435\u043d\u0438\u0435 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0433\u043e \u0433\u043e\u0434\u0430, \u0442\u043e QA-\u0441\u043f\u0435\u0446\u0438\u0430\u043b\u0438\u0441\u0442\u0443 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u043b\u043e\u0441\u044c \u0442\u0440\u0430\u0442\u0438\u0442\u044c \u0431\u043e\u043b\u044c\u0448\u0435 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u043d\u0430 \u043f\u0440\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u0440\u0435\u0433\u0440\u0435\u0441\u0441\u0438\u043e\u043d\u043d\u044b\u0445 \u0442\u0435\u0441\u0442\u043e\u0432 \u043f\u043e\u0441\u043b\u0435 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0440\u0435\u043b\u0438\u0437\u0430. \u0420\u0435\u0448\u0435\u043d\u0438\u0435 \u044d\u0442\u043e\u0439 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u0431\u044b\u043b\u043e \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0435\u043d\u043e \u043c\u043d\u0435. \u0417\u0430\u0434\u0430\u0447\u0430 \u043c\u043d\u0435 \u0441\u0440\u0430\u0437\u0443 \u043f\u043e\u043a\u0430\u0437\u0430\u043b\u0430\u0441\u044c \u0437\u0430\u043c\u0430\u043d\u0447\u0438\u0432\u043e\u0439, \u0432\u0435\u0434\u044c \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430 \u0441 \u043d\u0443\u043b\u044f \u2013 \u044d\u0442\u043e \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043f\u043e\u043f\u0440\u043e\u0431\u043e\u0432\u0430\u0442\u044c \u043d\u043e\u0432\u044b\u0435 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b, \u043f\u0440\u0438\u043e\u0431\u0440\u0435\u0441\u0442\u0438 \u043d\u043e\u0432\u044b\u0435 \u0437\u043d\u0430\u043d\u0438\u044f \u0438 \u043d\u0430\u0432\u044b\u043a\u0438. \u041d\u0435 \u0434\u043e\u043b\u0433\u043e \u0434\u0443\u043c\u0430\u044f, \u044f \u0432\u0437\u044f\u043b\u0441\u044f \u0437\u0430 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0445 \u0438\u0434\u0435\u0439.<\/p>\n<p>\u0417\u0430\u0434\u0430\u0447\u0430 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043d\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0441 \u0441\u0430\u043c\u043e\u0433\u043e \u043d\u0430\u0447\u0430\u043b\u0430 \u043e\u0431\u0435\u0449\u0430\u043b\u0430 \u0431\u044b\u0442\u044c \u043d\u0435\u043f\u0440\u043e\u0441\u0442\u043e\u0439: \u0434\u043e \u0442\u043e\u0433\u043e \u043a\u0430\u043a \u044f \u043f\u0440\u0438\u0441\u043e\u0435\u0434\u0438\u043d\u0438\u043b\u0441\u044f \u043a \u043a\u043e\u043c\u0430\u043d\u0434\u0435, \u0432\u0441\u044f \u0442\u0435\u0441\u0442\u043e\u0432\u0430\u044f \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f \u0445\u0440\u0430\u043d\u0438\u043b\u0430\u0441\u044c \u0438\u0441\u043a\u043b\u044e\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0432 \u0433\u043e\u043b\u043e\u0432\u0435 \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0433\u043e QA-\u0441\u043f\u0435\u0446\u0438\u0430\u043b\u0438\u0441\u0442\u0430. \u0421\u0438\u0441\u0442\u0435\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043d\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u043d\u0435 \u0431\u044b\u043b\u043e, \u043d\u043e\u0432\u044b\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u043b\u0441\u044f \u00ab\u043d\u0430 \u043b\u0435\u0442\u0443\u00bb. \u042d\u0442\u043e \u043f\u043e\u0440\u043e\u0436\u0434\u0430\u043b\u043e \u0440\u044f\u0434 \u0432\u043e\u043f\u0440\u043e\u0441\u043e\u0432: \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0438 \u0446\u0435\u043b\u0435\u0441\u043e\u043e\u0431\u0440\u0430\u0437\u043d\u043e \u043b\u0438 \u0432\u043d\u0435\u0434\u0440\u0435\u043d\u0438\u0435 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u0438 \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u043a\u0430\u043a \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u043a\u043e\u043c\u043f\u043b\u0435\u043a\u0441 \u0442\u0435\u0441\u0442-\u043a\u0435\u0439\u0441\u043e\u0432 \u0431\u0435\u0437 \u043d\u0430\u043b\u0438\u0447\u0438\u044f \u0444\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e\u0439 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 \u0438 \u043a\u0430\u043a\u043e\u0432\u044b \u043e\u0436\u0438\u0434\u0430\u043d\u0438\u044f \u043e\u0442 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u0438 \u0432 \u0446\u0435\u043b\u043e\u043c? \u0412\u0441\u0435 \u044d\u0442\u043e \u0432\u043e\u043f\u0440\u043e\u0441\u044b, \u043d\u0435 \u0438\u043c\u0435\u044e\u0449\u0438\u0435 \u043e\u0434\u043d\u043e\u0437\u043d\u0430\u0447\u043d\u043e\u0433\u043e \u043e\u0442\u0432\u0435\u0442\u0430.<\/p>\n<p>\u041e\u0431\u043e\u0441\u043d\u043e\u0432\u0430\u043d\u0438\u0435 \u0432\u043d\u0435\u0434\u0440\u0435\u043d\u0438\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u0438 \u043f\u043e\u0434\u043a\u0440\u0435\u043f\u043b\u044f\u0435\u0442\u0441\u044f \u0442\u0435\u043e\u0440\u0438\u0435\u0439 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0432 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 \u0441\u043b\u0443\u0447\u0430\u044f\u0445:<\/p>\n<ul>\n<li>\n<p>\u041f\u0440\u043e\u0435\u043a\u0442\u0443 \u0431\u043e\u043b\u044c\u0448\u0435 \u0433\u043e\u0434\u0430, \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u043e\u0431\u0448\u0438\u0440\u043d\u044b\u0439 \u043f\u0443\u043b \u0442\u0435\u0441\u0442-\u043a\u0435\u0439\u0441\u043e\u0432, \u043d\u0430 \u0438\u0445 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443 \u0443\u0445\u043e\u0434\u0438\u0442 \u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u0432\u0440\u0435\u043c\u044f.<\/p>\n<\/li>\n<li>\n<p>\u0412 \u043a\u043e\u043c\u0430\u043d\u0434\u0435 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432, \u0438 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0441\u043f\u043e\u0441\u043e\u0431\u0441\u0442\u0432\u0443\u0435\u0442 \u0432\u0435\u0440\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432 \u043a\u043e\u0434\u0435 \u043d\u0435 \u043f\u043e\u0432\u043b\u0438\u044f\u043b\u0438 \u043d\u0430 \u0447\u0443\u0436\u043e\u0439 \u043a\u043e\u0434.<\/p>\n<\/li>\n<li>\n<p>\u0422\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0440\u0430\u0437\u043d\u044b\u0445 \u0432\u0435\u0440\u0441\u0438\u0439 \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u0430.<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u043e\u0435\u043a\u0442 \u0445\u0430\u0440\u0430\u043a\u0442\u0435\u0440\u0438\u0437\u0443\u0435\u0442\u0441\u044f \u0447\u0430\u0441\u0442\u044b\u043c\u0438 \u0440\u0435\u043b\u0438\u0437\u0430\u043c\u0438 \u0438 \u043d\u0430 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044e \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u0437\u0430\u043d\u0438\u043c\u0430\u0435\u0442 \u043c\u043d\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438.<\/p>\n<\/li>\n<\/ul>\n<p>\u041f\u0440\u043e\u0435\u043a\u0442 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u043e\u0432\u0430\u043b \u0434\u0432\u0443\u043c \u0438\u0437 \u044d\u0442\u0438\u0445 \u043a\u0440\u0438\u0442\u0435\u0440\u0438\u0435\u0432: \u043e\u043d \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0437\u0440\u0435\u043b\u044b\u0439, \u0441 \u043a\u043e\u043c\u0430\u043d\u0434\u043e\u0439 \u0438\u0437 \u043f\u044f\u0442\u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432, \u0440\u0435\u043b\u0438\u0437\u044b \u0432\u044b\u0445\u043e\u0434\u044f\u0442 \u0435\u0436\u0435\u043d\u0435\u0434\u0435\u043b\u044c\u043d\u043e. \u0412\u043d\u0435\u0434\u0440\u0435\u043d\u0438\u0435 \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 \u0443\u0436\u0435 \u043d\u0430 \u0434\u0430\u043d\u043d\u043e\u043c \u044d\u0442\u0430\u043f\u0435 \u043f\u0440\u0438\u043d\u043e\u0441\u0438\u043b\u043e \u0443\u043b\u0443\u0447\u0448\u0435\u043d\u0438\u044f \u2013 \u044d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u043b\u043e \u0441\u043e\u043a\u0440\u0430\u0442\u0438\u0442\u044c \u0432\u0440\u0435\u043c\u044f \u043d\u0430 \u0440\u0435\u0433\u0440\u0435\u0441\u0441\u0438\u043e\u043d\u043d\u043e\u0435 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0438 \u0443\u043c\u0435\u043d\u044c\u0448\u0438\u0442\u044c \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u0438 \u043c\u0435\u0436\u0434\u0443 \u0432\u044b\u044f\u0432\u043b\u0435\u043d\u0438\u0435\u043c \u0434\u0435\u0444\u0435\u043a\u0442\u043e\u0432 \u0438 \u0438\u0445 \u0438\u0441\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435\u043c. \u0421\u044d\u043a\u043e\u043d\u043e\u043c\u043b\u0435\u043d\u043d\u043e\u0435 \u0432\u0440\u0435\u043c\u044f \u043d\u0430 \u0440\u0435\u0433\u0440\u0435\u0441\u0441\u0435 \u0441\u043e\u0441\u0442\u0430\u0432\u0438\u043b\u043e \u043e\u043a\u043e\u043b\u043e 5 \u0447\u0430\u0441\u043e\u0432, \u0430 \u0441 \u0443\u0447\u0435\u0442\u043e\u043c 85% \u043f\u043e\u043a\u0440\u044b\u0442\u0438\u044f \u0440\u0435\u0433\u0440\u0435\u0441\u0441\u0438\u043e\u043d\u043d\u043e\u0433\u043e \u043d\u0430\u0431\u043e\u0440\u0430 \u0442\u0435\u0441\u0442-\u043a\u0435\u0439\u0441\u043e\u0432 \u043e\u0441\u0442\u0430\u0432\u0448\u0438\u0435\u0441\u044f 15% \u0442\u0435\u0441\u0442-\u043a\u0435\u0439\u0441\u043e\u0432 \u043e\u043a\u0430\u0437\u0430\u043b\u0438\u0441\u044c \u0441\u043b\u0430\u0431\u043e \u043f\u043e\u0434\u0432\u0435\u0440\u0436\u0435\u043d\u044b \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u0438 \u0438 \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u043b\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c\u0441\u044f \u0432\u0440\u0443\u0447\u043d\u0443\u044e.<\/p>\n<p>\u041e\u0434\u043d\u0430\u043a\u043e \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u043c \u0430\u0441\u043f\u0435\u043a\u0442\u043e\u043c \u043e\u0441\u0442\u0430\u0432\u0430\u043b\u0441\u044f \u0432\u043e\u043f\u0440\u043e\u0441 \u043f\u043e\u043b\u044c\u0437\u044b \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u0438 \u0434\u043b\u044f \u0431\u0438\u0437\u043d\u0435\u0441\u0430: \u0435\u0441\u043b\u0438 \u043e\u0448\u0438\u0431\u043a\u0430 \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u0438\u0432\u0435\u0441\u0442\u0438 \u043a \u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u043c \u0444\u0438\u043d\u0430\u043d\u0441\u043e\u0432\u044b\u043c \u043f\u043e\u0442\u0435\u0440\u044f\u043c, \u0431\u0438\u0437\u043d\u0435\u0441 \u0431\u043e\u043b\u0435\u0435 \u0441\u043a\u043b\u043e\u043d\u0435\u043d \u043a \u0432\u043d\u0435\u0434\u0440\u0435\u043d\u0438\u044e \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u0438. \u0412 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0435 \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u2013 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u043b\u043e\u043c \u2013 \u0441\u0442\u043e\u0438\u043c\u043e\u0441\u0442\u044c \u043e\u0448\u0438\u0431\u043a\u0438 \u043d\u0435\u0432\u0435\u043b\u0438\u043a\u0430, \u043d\u043e \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0443\u0441\u043a\u043e\u0440\u0438\u0442\u044c \u0440\u0435\u0433\u0440\u0435\u0441\u0441\u0438\u043e\u043d\u043d\u043e\u0435 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0438 \u043e\u043f\u0440\u043e\u0431\u043e\u0432\u0430\u0442\u044c \u043d\u043e\u0432\u044b\u0435 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0438 \u0443\u0436\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u043b\u0430 \u0431\u043e\u043b\u044c\u0448\u0443\u044e \u0446\u0435\u043d\u043d\u043e\u0441\u0442\u044c.<\/p>\n<p>\u041f\u0435\u0440\u0432\u044b\u0435 \u0448\u0430\u0433\u0438 \u043a \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u0438 \u0432\u043a\u043b\u044e\u0447\u0430\u043b\u0438 \u043a\u043e\u043d\u0441\u0443\u043b\u044c\u0442\u0430\u0446\u0438\u0438 \u0441 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0449\u0438\u043a\u043e\u043c \u0438 \u0441\u0431\u043e\u0440 \u0442\u0435\u0441\u0442-\u043a\u0435\u0439\u0441\u043e\u0432, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0432 \u0440\u0435\u0433\u0440\u0435\u0441\u0441\u0435, \u0438\u0437 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0431\u044b\u043b\u0438 \u0432\u044b\u0431\u0440\u0430\u043d\u044b \u043a\u0430\u043d\u0434\u0438\u0434\u0430\u0442\u044b \u043d\u0430 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u044e.\u00a0\u0417\u0430\u0442\u0435\u043c \u044f \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u043b \u0438\u0441\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0435 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435, \u043c\u043e\u0434\u0435\u043b\u0438\u0440\u0443\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u0441 \u0442\u043e\u0447\u043a\u0438 \u0437\u0440\u0435\u043d\u0438\u044f \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440\u0430, \u0447\u0442\u043e \u043f\u0440\u0438\u0432\u0435\u043b\u043e \u043a \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044e \u0441\u043f\u0438\u0441\u043a\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0445 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0435\u0432, \u0432\u043a\u043b\u044e\u0447\u0430\u044f \u0442\u0430\u043a\u0438\u0435 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438, \u043a\u0430\u043a \u0432\u0445\u043e\u0434 \u0432 \u0441\u0438\u0441\u0442\u0435\u043c\u0443, \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0438 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u0430\u043c\u0438. \u042d\u0442\u043e \u043e\u0431\u043e\u0437\u043d\u0430\u0447\u0438\u043b\u043e \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0435 \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0434\u043b\u044f UI-\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f.<\/p>\n<p>\u0427\u0442\u043e \u043a\u0430\u0441\u0430\u0435\u0442\u0441\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f API-\u0447\u0430\u0441\u0442\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u044f \u0432\u0437\u044f\u043b \u0435\u0433\u043e \u0442\u0435\u043a\u0443\u0449\u0443\u044e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u044d\u0442\u0430\u043b\u043e\u043d\u043d\u043e\u0439. \u041d\u0430\u043b\u0438\u0447\u0438\u0435 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 Swagger \u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0443\u043f\u0440\u043e\u0441\u0442\u0438\u043b\u043e \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e\u0441\u0442\u0438 \u0440\u0430\u0431\u043e\u0442\u044b API. \u0412 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u0447\u0435\u0433\u043e \u0443 \u043c\u0435\u043d\u044f \u0431\u044b\u043b \u0441\u043f\u0438\u0441\u043e\u043a \u0432\u0441\u0435\u0445 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0445 API-\u043c\u0435\u0442\u043e\u0434\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u043e\u0434\u043f\u0430\u0434\u0430\u043b\u0438 \u043f\u043e\u0434 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u044e, \u0432\u043a\u043b\u044e\u0447\u0430\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443 \u043e\u0442\u0432\u0435\u0442\u043e\u0432 \u043d\u0430 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u044e \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u043e\u0448\u0438\u0431\u043e\u043a.<\/p>\n<p><a class=\"anchor\" name=\"1\" id=\"1\"><\/a><\/p>\n<h2>\u041e\u0431\u0437\u043e\u0440 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0439<\/h2>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0435\u0440\u0435\u0439\u0434\u0435\u043c \u043a \u043e\u0431\u0437\u043e\u0440\u0443 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u044f \u0432\u044b\u0431\u0440\u0430\u043b \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0434\u0435\u043d\u0438\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>\u041f\u0440\u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 \u043d\u0430 Python \u0431\u0435\u0437 Pytest \u0441 \u0435\u0433\u043e \u043e\u0431\u0448\u0438\u0440\u043d\u044b\u043c \u043d\u0430\u0431\u043e\u0440\u043e\u043c \u043a\u0438\u043b\u043b\u0435\u0440-\u0444\u0438\u0447\u0435\u0439 \u0442\u043e\u0447\u043d\u043e \u043d\u0435 \u043e\u0431\u043e\u0439\u0442\u0438\u0441\u044c. \u0411\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 \u0434\u043b\u044f UI-\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0434\u043e\u043b\u0433\u043e \u0442\u0430\u043a\u0436\u0435 \u0432\u044b\u0431\u0438\u0440\u0430\u0442\u044c \u043d\u0435 \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c, \u043a\u043e\u043b\u043b\u0435\u0433\u0438 \u0434\u0430\u0432\u043d\u043e \u0443\u0436\u0435 \u0440\u0430\u0441\u0445\u0432\u0430\u043b\u0438\u0432\u0430\u043b\u0438 Playwright. \u041f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0432 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043e\u0431\u0443\u0447\u0430\u044e\u0449\u0438\u0445 \u0432\u0438\u0434\u0435\u043e\u0440\u043e\u043b\u0438\u043a\u043e\u0432, \u044f \u0443\u0431\u0435\u0434\u0438\u043b\u0441\u044f \u0432 \u0435\u0433\u043e \u043c\u043e\u0449\u0438&#8230; \u0447\u0442\u043e \u0436, \u043d\u0430\u043a\u043e\u043d\u0435\u0446 \u0438 \u0443 \u043c\u0435\u043d\u044f \u043f\u043e\u044f\u0432\u0438\u043b\u0430\u0441\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0435\u0433\u043e \u043e\u043f\u0440\u043e\u0431\u043e\u0432\u0430\u0442\u044c. Playwright \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043a\u0430\u043a \u0434\u043b\u044f UI, \u0442\u0430\u043a \u0438 \u0434\u043b\u044f API-\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f. \u041d\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f GitLab, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0431\u0443\u0434\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c GitLab CI\/CD \u0434\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u043d\u0443 \u0438 \u0432 \u043a\u043e\u043d\u0435\u0447\u043d\u043e\u043c \u0441\u0447\u0435\u0442\u0435 \u0434\u043b\u044f \u0443\u043f\u0430\u043a\u043e\u0432\u043a\u0438 \u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u0433\u043e \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430 \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f Docker. \u0414\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u0437\u0430\u0434\u0435\u0439\u0441\u0442\u0432\u0443\u044e Faker, \u0434\u043b\u044f \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438 API-\u043e\u0442\u0432\u0435\u0442\u043e\u0432 \u0438 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u2014 Pydantic.<\/p>\n<p><a class=\"anchor\" name=\"2\" id=\"2\"><\/a><\/p>\n<h2>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b<\/h2>\n<p>\u041f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u0442\u044c \u043a \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044e \u0442\u0435\u0441\u0442\u043e\u0432, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0440\u0430\u0431\u043e\u0447\u0435\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435. \u0411\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c Docker, \u0432\u043e-\u043f\u0435\u0440\u0432\u044b\u0445, \u044d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0442\u044c \u0435\u0434\u0438\u043d\u043e\u043e\u0431\u0440\u0430\u0437\u0438\u0435 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f. \u041d\u0435 \u0432\u0430\u0436\u043d\u043e, \u043a\u0430\u043a\u043e\u0439 \u0431\u0440\u0430\u0443\u0437\u0435\u0440 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d \u0438\u043b\u0438 \u043d\u0430 \u043a\u0430\u043a\u043e\u0439 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442\u044c \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430, \u2013 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 Docker-\u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442 \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u043e\u0435 \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u043e\u0434\u043d\u0438\u0445 \u0438 \u0442\u0435\u0445 \u0436\u0435 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u043a\u0430\u043a \u043d\u0430 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0439 \u043c\u0430\u0448\u0438\u043d\u0435, \u0442\u0430\u043a \u0438 \u0432 \u0441\u0440\u0435\u0434\u0435 CI. \u041f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0431\u0430\u0437\u043e\u0432\u043e\u0433\u043e \u043e\u0431\u0440\u0430\u0437\u0430 Playwright \u043e\u0442 Microsoft \u0441 \u043f\u0440\u0435\u0434\u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043d\u044b\u043c\u0438 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430\u043c\u0438 \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u0438\u0437\u0431\u0430\u0432\u0438\u0442\u044c\u0441\u044f \u043e\u0442 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0442\u044c \u0438 \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0442\u044c \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u044b \u0432\u0440\u0443\u0447\u043d\u0443\u044e, \u0447\u0442\u043e \u0441\u044d\u043a\u043e\u043d\u043e\u043c\u0438\u0442 \u0432\u0440\u0435\u043c\u044f \u0438 \u043c\u0438\u043d\u0438\u043c\u0438\u0437\u0438\u0440\u0443\u0435\u0442 \u0432\u0435\u0440\u043e\u044f\u0442\u043d\u043e\u0441\u0442\u044c \u043e\u0448\u0438\u0431\u043e\u043a, \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0445 \u0441 \u043d\u0435\u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u043e\u0441\u0442\u044c\u044e \u0432\u0435\u0440\u0441\u0438\u0439. \u0412\u043e-\u0432\u0442\u043e\u0440\u044b\u0445, \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u0441\u044f \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u0432 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044f, \u043a \u043f\u0440\u0438\u043c\u0435\u0440\u0443, \u0438\u0437\u043c\u0435\u043d\u044f\u0442\u044c \u0442\u0435\u0441\u0442\u043e\u0432\u0443\u044e \u0441\u0440\u0435\u0434\u0443, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0431\u0443\u0434\u0443\u0442 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c\u0441\u044f \u0442\u0435\u0441\u0442\u044b.<\/p>\n<p>\u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u043c \u043a \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044e Dockerfile. \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u043e\u0431\u0440\u0430\u0437 Playwright \u043d\u0430 \u0431\u0430\u0437\u0435 Ubuntu. \u0412 \u043e\u0431\u0440\u0430\u0437 \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u044b \u043f\u0440\u0435\u0434\u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043d\u044b\u0435 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u044b \u0438 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043d\u044b\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438, \u0441\u0430\u043c Playwright \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e. \u041f\u0435\u0440\u0435\u0439\u0434\u0435\u043c \u043a \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f.<\/p>\n<p>\u0414\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e poetry. \u042d\u0442\u043e\u0442 \u043f\u0430\u043a\u0435\u0442\u043d\u044b\u0439 \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442 \u0431\u043e\u043b\u0435\u0435 \u0443\u0434\u043e\u0431\u043d\u043e\u0435 \u0438 \u0442\u043e\u0447\u043d\u043e\u0435 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044f\u043c\u0438 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0444\u0430\u0439\u043b\u0430 poetry.lock, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0444\u0438\u043a\u0441\u0438\u0440\u0443\u0435\u0442 \u0442\u043e\u0447\u043d\u044b\u0435 \u0432\u0435\u0440\u0441\u0438\u0438 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043d\u044b\u0445 \u043f\u0430\u043a\u0435\u0442\u043e\u0432 \u0438 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442 \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u044b\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043d\u0430 \u0432\u0441\u0435\u0445 \u0441\u0440\u0435\u0434\u0430\u0445. \u0422\u0430\u043a\u0436\u0435 \u0438\u0437 \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432 poetry \u043c\u043e\u0436\u043d\u043e \u0432\u044b\u0434\u0435\u043b\u0438\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c <strong>\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0440\u0430\u0437\u043d\u043e\u0433\u043e \u043d\u0430\u0431\u043e\u0440\u0430 \u043f\u0430\u043a\u0435\u0442\u043e\u0432 \u043d\u0430 \u043f\u0440\u043e\u0434\u0435 \u0438 \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0439 \u0441\u0440\u0435\u0434\u0435<\/strong> \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443 pytest \u043f\u0440\u044f\u043c\u043e \u0432 \u043a\u043e\u043d\u0444\u0438\u0433\u0435 poetry \u2014 poetry.toml \u0447\u0435\u0440\u0435\u0437 \u0434\u0438\u0440\u0435\u043a\u0442\u0438\u0432\u0443 [tool.pytest.<em>ini_<\/em>options]. \u041f\u0435\u0440\u0435\u0439\u0434\u0435\u043c \u043a\u00a0 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0435 Poetry \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a\u043e\u043c\u0430\u043d\u0434\u044b:<\/p>\n<pre><code>curl -sSL https:\/\/install.python-poetry.org | python -<\/code><\/pre>\n<p>\u00a0\u041f\u0440\u043e\u0432\u0435\u0440\u0438\u043c \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0443 \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440\u0430 \u043f\u0430\u043a\u0435\u0442\u043e\u0432 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a\u043e\u043c\u0430\u043d\u0434\u044b:  <\/p>\n<pre><code>poetry --version<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u0442\u044c \u043a \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044e \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u043a\u043e\u043c\u0430\u043d\u0434\u043e\u0439:  <\/p>\n<pre><code> poetry init<\/code><\/pre>\n<p>\u0421\u0438\u0441\u0442\u0435\u043c\u0430 \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0438\u0442 \u0432\u0432\u0435\u0441\u0442\u0438 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u0443\u044e \u0434\u043b\u044f \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f. \u041c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e, \u043d\u0430\u0436\u0438\u043c\u0430\u044f Enter. \u0414\u0430\u043b\u0435\u0435 \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0443\u044e\u0449\u0438\u0435 \u043d\u0430\u0441 \u043f\u0430\u043a\u0435\u0442\u044b \u043a\u043e\u043c\u0430\u043d\u0434\u043e\u0439:  <\/p>\n<pre><code>poetry add pytest-playwright pytest pydantic pydantic-settings faker<\/code><\/pre>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e \u043a\u0430\u043a \u043f\u0430\u043a\u0435\u0442\u044b \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043b\u0438\u0441\u044c \u0438 \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043b\u0441\u044f lock-\u0444\u0430\u0439\u043b, \u043f\u0435\u0440\u0435\u0439\u0434\u0435\u043c \u043a \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0435 Docker-\u043e\u0431\u0440\u0430\u0437\u0430 \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u0441\u043e\u0437\u0434\u0430\u0432 Dockerfile. \u0412\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043e\u043d \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:  <\/p>\n<pre><code>FROM mcr.microsoft.com\/playwright\/python:v1.49.0-noble   ARG DISPLAY ENV PYTHONUNBUFFERED=1 \\     PYTHONWARNINGS=ignore \\     POETRY_VIRTUALENVS_CREATE=false \\     POETRY_NO_INTERACTION=1 \\     PYTHONPATH=\"\/app:${PYTHONPATH}\" \\     DISPLAY=${DISPLAY}  ENV PATH=\"$POETRY_HOME\/bin:\/root\/.local\/bin:$PATH\" RUN pip install --upgrade pip RUN apt update &amp;&amp; apt install -y xvfb x11-utils --no-install-recommends curl \\  &amp;&amp; curl -sSL https:\/\/install.python-poetry.org | python - \\     &amp;&amp; pip install certifi --upgrade    WORKDIR \/app   COPY pyproject.toml poetry.lock \/app\/ RUN poetry install --no-interaction --no-ansi  RUN playwright install chrome COPY . \/app   CMD [\"sh\", \"-c\", \"while true; do sleep 3600; done\"]<\/code><\/pre>\n<p>\u041c\u043d\u043e\u0433\u043e\u0435 \u0438\u0437 \u044d\u0442\u043e\u0433\u043e Dockerfile \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u043c \u0434\u043b\u044f Python-\u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u0438 \u043d\u0430\u0432\u0435\u0440\u043d\u044f\u043a\u0430 \u0432\u0430\u043c \u0443\u0436\u0435 \u0432\u0441\u0442\u0440\u0435\u0447\u0430\u043b\u043e\u0441\u044c. \u041e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043c\u0441\u044f \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435.\u00a0<\/p>\n<p>Docker \u043d\u0435 \u0438\u043c\u0435\u0435\u0442 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0433\u043e GUI-\u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u044b\u0439 \u0434\u0438\u0441\u043f\u043b\u0435\u0439\u043d\u044b\u0439 \u0441\u0435\u0440\u0432\u0435\u0440 \u2013 Xvfb, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u043d\u0430\u043c \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u043e\u043a\u043d\u043e \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430 \u0438 Playwright \u043e\u0442\u043b\u0430\u0434\u0447\u0438\u043a \u0438\u0437 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430. \u042f \u0440\u0430\u0431\u043e\u0442\u0430\u044e \u043d\u0430 Linux, \u044d\u0442\u0430 OS \u043a\u0430\u043a \u0438 \u0434\u0440\u0443\u0433\u0438\u0435, \u043c\u043e\u0436\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u043c\u0438 \u0434\u0438\u0441\u043f\u043b\u0435\u044f\u043c\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043a\u0430\u043a \u0444\u0438\u0437\u0438\u0447\u0435\u0441\u043a\u0438\u043c, \u0442\u0430\u043a \u0438 \u0443\u0434\u0430\u043b\u0435\u043d\u043d\u044b\u043c (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0447\u0435\u0440\u0435\u0437 SSH). \u0412 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0434\u0438\u0441\u043f\u043b\u0435\u0439 \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u044b\u0439, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0435\u0433\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c, \u0434\u043e\u0431\u0430\u0432\u0438\u0432 \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u0443\u044e \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e DISPLAY. \u0412 Windows DISPLAY \u043a\u0430\u043a \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u0433\u0440\u0430\u0444\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u044b Windows \u043e\u0442\u043b\u0438\u0447\u0430\u0435\u0442\u0441\u044f \u043e\u0442 X Window System, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0445\u0430\u0440\u0430\u043a\u0442\u0435\u0440\u043d\u0430 \u0434\u043b\u044f Unix-\u043f\u043e\u0434\u043e\u0431\u043d\u044b\u0445 \u0441\u0438\u0441\u0442\u0435\u043c. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0442\u0430\u043a\u0443\u044e \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0443, \u043a\u0430\u043a <a href=\"https:\/\/mobaxterm.mobatek.net\/\">MobaXterm<\/a>.<\/p>\n<p>\u0414\u043b\u044f \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0445 \u0446\u0435\u043b\u0435\u0439 \u0431\u0443\u0434\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c Chrome, \u043d\u043e \u0442\u0430\u043a\u0436\u0435 \u043c\u043e\u0436\u043d\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c Firefox \u0438\u043b\u0438 Webkit. \u041f\u043e\u0441\u043b\u0435\u0434\u043d\u044f\u044f \u043a\u043e\u043c\u0430\u043d\u0434\u0430 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u0430 \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u043d\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0430\u043b\u0441\u044f \u043f\u0440\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0435, \u044d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0438\u0437\u043d\u0443\u0442\u0440\u0438 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430.<\/p>\n<p>\u00a0\u0427\u0442\u043e\u0431\u044b \u0443\u043f\u0440\u043e\u0441\u0442\u0438\u0442\u044c \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u043c, \u0441\u043e\u0437\u0434\u0430\u043c \u0444\u0430\u0439\u043b docker-compose.yml, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0439 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438. \u0412\u043e\u0442 \u043a\u0430\u043a \u043e\u043d \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442:<\/p>\n<pre><code class=\"yaml\">services:   tests:     restart: always     build:       context: .       dockerfile: .\/Dockerfile     volumes:       - .:\/app:delegated       - \/tmp\/.X11-unix:\/tmp\/.X11-unix     env_file:       - .env     network_mode: host<\/code><\/pre>\n<p>\u0412 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043d\u043e\u043c \u043a\u043e\u043d\u0444\u0438\u0433\u0435 \u043e\u043f\u0438\u0441\u0430\u043d \u0441\u0435\u0440\u0432\u0438\u0441 tests, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0439 \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0430\u0432\u0442\u043e\u0442\u0435\u0441\u0442\u043e\u0432 \u0432 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0435. \u0412 \u0434\u0438\u0440\u0435\u043a\u0442\u0438\u0432\u0435 build \u0437\u0430\u0434\u0430\u0451\u043c \u0442\u0435\u043a\u0443\u0449\u0443\u044e \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e\u0439 \u0434\u043b\u044f \u0441\u0431\u043e\u0440\u043a\u0438 \u0438 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u043f\u0443\u0442\u044c \u0434\u043e Dockerfile. \u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0434\u0438\u0440\u0435\u043a\u0442\u0438\u0432\u043e\u0439 volumes \u043c\u043e\u043d\u0442\u0438\u0440\u0443\u0435\u043c \u0442\u0435\u043a\u0443\u0449\u0443\u044e \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e \u0441 \u0445\u043e\u0441\u0442\u0430 \u0432 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e \/app \u0432\u043d\u0443\u0442\u0440\u0438 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430 \u0441 \u0444\u043b\u0430\u0433\u043e\u043c delegated. \u042d\u0442\u043e\u0442 \u0444\u043b\u0430\u0433 \u0443\u0441\u043a\u043e\u0440\u044f\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0443 \u043f\u0440\u0438 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u0438 \u0444\u0430\u0439\u043b\u043e\u0432, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044f IDE \u043e\u043f\u0435\u0440\u0430\u0442\u0438\u0432\u043d\u043e \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432\u043d\u0443\u0442\u0440\u0438 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430. \u0421 \u043f\u043e\u043c\u043e\u0449\u044c\u044e<strong> \/tmp\/.X11-unix:\/tmp\/.X11-unix<\/strong> \u043f\u0440\u043e\u043a\u0438\u0434\u044b\u0432\u0430\u0435\u043c \u0441\u043e\u043a\u0435\u0442 X11 \u0441 \u0445\u043e\u0441\u0442\u0430 \u0432 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440,<\/p>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-461011","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/461011","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=461011"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/461011\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=461011"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=461011"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=461011"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}