{"id":356519,"date":"2024-05-20T23:31:26","date_gmt":"2024-05-20T23:31:26","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=356519"},"modified":"-0001-11-30T00:00:00","modified_gmt":"2024-05-20T23:31:26","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=356519","title":{"rendered":"<span>\u0414\u0435\u043b\u0430\u0435\u043c \u043f\u0440\u043e\u0441\u0442\u044b\u0435 \u043e\u0442\u0447\u0435\u0442\u044b \u0432 CI \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e GitLab Pages \u0434\u043b\u044f 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-1\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w780q1\/webt\/zv\/im\/vh\/zvimvhb0p-bh25fsqcva1enjvty.jpeg\" data-src=\"https:\/\/habrastorage.org\/webt\/zv\/im\/vh\/zvimvhb0p-bh25fsqcva1enjvty.jpeg\" data-blurred=\"true\"\/><\/div>\n<p>  \u041f\u0440\u0438\u0432\u0435\u0442, \u0425\u0430\u0431\u0440! \u042f \u0421\u0430\u0448\u0430 \u0410\u043b\u0435\u043a\u0441\u0435\u0435\u0432, \u0441\u0442\u0430\u0440\u0448\u0438\u0439 \u0438\u043d\u0436\u0435\u043d\u0435\u0440 \u043f\u043e \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044e \u0432 <a href=\"https:\/\/slc.tl\/mylpw\">Selectel<\/a>. \u041d\u0435\u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0432\u0440\u0435\u043c\u044f \u043d\u0430\u0437\u0430\u0434 \u043c\u044b \u0441\u0442\u043e\u043b\u043a\u043d\u0443\u043b\u0438\u0441\u044c \u0441 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u044c\u044e \u0440\u0435\u043e\u0440\u0433\u0430\u043d\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043e\u0442\u0447\u0435\u0442\u044b end-to-end-\u0442\u0435\u0441\u0442\u043e\u0432. \u0418\u0445 \u043f\u0440\u043e\u0433\u043e\u043d \u0441\u0442\u0430\u043b \u0437\u0430\u043d\u0438\u043c\u0430\u0442\u044c \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u043c\u043d\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438, \u043c\u044b \u0438\u0441\u043a\u0430\u043b\u0438 \u0441\u043f\u043e\u0441\u043e\u0431\u044b \u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u0438\u0445 \u0435\u0449\u0435 \u0431\u043e\u043b\u044c\u0448\u0435. \u041f\u043e\u0434 \u043a\u0430\u0442\u043e\u043c \u044f \u043f\u043e\u0434\u0435\u043b\u044e\u0441\u044c \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u043c, \u043a \u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443 \u043c\u044b \u0432 \u0438\u0442\u043e\u0433\u0435 \u043f\u0440\u0438\u0448\u043b\u0438. <\/p>\n<p>  \u0421\u0435\u0439\u0447\u0430\u0441 \u0443 \u043d\u0430\u0441 \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0442\u0435\u0441\u0442\u043e\u0432 \u0432 \u0440\u0430\u0437\u043d\u044b\u0445 \u0434\u0436\u043e\u0431\u0430\u0445 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c <code>shard=x\/y<\/code>, \u0430 \u043e\u0431\u0449\u0438\u0439 \u0440\u0435\u043f\u043e\u0440\u0442 \u043c\u044b \u043d\u0430\u0443\u0447\u0438\u043b\u0438\u0441\u044c \u0441\u043a\u043b\u0435\u0438\u0432\u0430\u0442\u044c \u0438\u0437 \u043e\u0442\u0447\u0435\u0442\u043e\u0432 \u0440\u0430\u0437\u043d\u044b\u0445 \u043f\u0440\u043e\u0433\u043e\u043d\u043e\u0432. \u0425\u043e\u0442\u0435\u043b \u0431\u044b \u043e\u0431\u0441\u0443\u0434\u0438\u0442\u044c \u044d\u0442\u043e \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u0432 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f\u0445. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u0432\u044b \u0440\u0435\u0448\u0430\u0435\u0442\u0435 \u043f\u043e\u0434\u043e\u0431\u043d\u0443\u044e \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443 \u0438\u043d\u0430\u0447\u0435. \u0412\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u043e\u043f\u0438\u0441\u0430\u043b \u0432 \u0432\u0438\u0434\u0435 \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u0438 \u043d\u0430 \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u043c \u0441\u0442\u0435\u043d\u0434\u0435, \u0442\u0430\u043a \u0447\u0442\u043e \u0441\u043c\u043e\u0436\u0435\u0442\u0435 \u043b\u0435\u0433\u043a\u043e \u043f\u043e\u0432\u0442\u043e\u0440\u0438\u0442\u044c \u0435\u0433\u043e \u0432 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0445 \u0446\u0435\u043b\u044f\u0445. <a name=\"habracut\"><\/a><\/p>\n<h2>\u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435<\/h2>\n<p>  \u0414\u043e\u043b\u0433\u043e\u0435 \u0432\u0440\u0435\u043c\u044f \u0434\u043b\u044f \u043f\u0440\u043e\u0433\u043e\u043d\u0430 \u0442\u0435\u0441\u0442\u043e\u0432 \u0432 GitLab CI \u043d\u0430\u043c \u0445\u0432\u0430\u0442\u0430\u043b\u043e \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u0445 (shared) \u0440\u0430\u043d\u043d\u0435\u0440\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0430\u043c \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u043b\u0438 \u043d\u0430\u0448\u0438 DevOps-\u0441\u043f\u0435\u0446\u0438\u0430\u043b\u0438\u0441\u0442\u044b. \u0414\u043b\u044f Playwright, \u0441 \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u043c\u044b \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u043c, \u0431\u044b\u043b\u043e \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e 5 vCPU \u0438 8 \u0413\u0411 RAM \u2014 \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 4-5 <a href=\"https:\/\/playwright.dev\/docs\/test-parallel%23worker-processes\">\u0432\u043e\u0440\u043a\u0435\u0440\u043e\u0432<\/a> \u0445\u0432\u0430\u0442\u0430\u043b\u043e.<\/p>\n<p>  \u0421\u043f\u0443\u0441\u0442\u044f \u0432\u0440\u0435\u043c\u044f \u043f\u0440\u043e\u0433\u043e\u043d \u0442\u0435\u0441\u0442\u043e\u0432 \u0441\u0442\u0430\u043b \u043f\u0435\u0440\u0435\u0432\u0430\u043b\u0438\u0432\u0430\u0442\u044c \u0437\u0430 30 \u043c\u0438\u043d\u0443\u0442 \u2014 \u043c\u044b \u043d\u0430\u0447\u0430\u043b\u0438 \u0438\u0441\u043a\u0430\u0442\u044c \u0441\u043f\u043e\u0441\u043e\u0431 \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u0438\u0442\u044c \u0442\u0435\u0441\u0442\u044b \u0435\u0449\u0435 \u0431\u043e\u043b\u044c\u0448\u0435. \u0418 \u0431\u044b\u043b\u0438 \u0430\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u043d\u044b\u0435 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0430\u043c \u043d\u0435 \u043f\u043e\u0434\u043e\u0448\u043b\u0438 \u043f\u043e \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u043c \u043f\u0440\u0438\u0447\u0438\u043d\u0430\u043c:<\/p>\n<ul>\n<li>\u041c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0432\u044b\u0434\u0435\u043b\u0438\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0435 \u0440\u0430\u043d\u043d\u0435\u0440\u044b \u0441 \u0431\u043e\u043b\u044c\u0448\u0438\u043c \u043b\u0438\u043c\u0438\u0442\u043e\u043c, \u043d\u043e \u043d\u0430 \u043c\u043e\u043c\u0435\u043d\u0442 \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432 \u043d\u0435 \u0431\u044b\u043b\u043e, \u0438\u0445 \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u0431\u044b \u0436\u0434\u0430\u0442\u044c. \u0411\u044b\u043b\u043e \u0443\u0434\u043e\u0431\u043d\u0435\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043e\u0431\u0449\u0438\u0435 \u0440\u0430\u043d\u043d\u0435\u0440\u044b. <\/li>\n<li>\u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u043c\u0435\u043d\u044c\u0448\u0435\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0442\u0435\u0441\u0442\u043e\u0432 \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u043d\u043e\u043c\u0443 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u0443 \u0431\u044b\u043b\u043e \u0441\u043b\u043e\u0436\u043d\u043e. Playwright \u0443\u043c\u0435\u0435\u0442 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0442\u0435\u0441\u0442\u044b \u043f\u043e \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044e, \u043d\u043e \u043d\u0435 \u043f\u043e \u043c\u0435\u0442\u0430\u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438. \u0410 \u0443 \u043d\u0430\u0441 \u0431\u044b\u043b\u0438 \u043e\u0447\u0435\u043d\u044c \u0434\u043b\u0438\u043d\u043d\u044b\u0435 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f \u0442\u0435\u0441\u0442\u043e\u0432, \u0442\u0430\u043a \u043c\u044b \u0438\u0445 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u043f\u043e \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430\u043c (\u0432 \u043e\u0434\u043d\u043e\u043c \u0442\u0435\u0441\u0442\u0435 \u0438\u0445 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0434\u043e 20). <\/li>\n<\/ul>\n<p>  \u041d\u0430\u0448\u0438\u043c \u0440\u0435\u0448\u0435\u043d\u0438\u0435\u043c \u0441\u0442\u0430\u043b\u043e \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0442\u0435\u0441\u0442\u043e\u0432 \u0432 \u0440\u0430\u0437\u043d\u044b\u0445 \u0434\u0436\u043e\u0431\u0430\u0445 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c <code>shard=x\/y<\/code>. \u0412 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u043f\u043e\u0434\u0435\u043b\u044e\u0441\u044c \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u0445\u0435\u043c\u043e\u0439 \u043e\u0442\u0447\u0435\u0442\u043e\u0432 e2e-\u0442\u0435\u0441\u0442\u043e\u0432 \u043d\u0430 Playwright \u043f\u0440\u0438 \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e\u043c \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0438 \u043d\u0430 \u0440\u0430\u0437\u043d\u044b\u0445 \u043d\u043e\u0434\u0430\u0445. \u041d\u043e \u0438 \u043f\u043e\u043a\u0430\u0436\u0443 \u0443\u043f\u0440\u043e\u0449\u0435\u043d\u043d\u0443\u044e \u0432\u0435\u0440\u0441\u0438\u044e \u043d\u0430\u0448\u0435\u0433\u043e CI, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0441\u043f\u043e\u0441\u043e\u0431 \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u044f\u0442\u044c HTML-\u043e\u0442\u0447\u0435\u0442 \u043e\u0442 Playwright-\u0442\u0435\u0441\u0442\u0430 \u0432 \u043e\u0434\u0438\u043d \u0431\u043e\u043b\u044c\u0448\u043e\u0439. \u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430\u0442\u044c\u0441\u044f \u043a\u0430\u0436\u0434\u044b\u0439 \u0440\u0430\u0437 \u043f\u043e \u0430\u0440\u0442\u0435\u0444\u0430\u043a\u0442\u0430\u043c \u043a\u0430\u0436\u0434\u043e\u0439 \u0434\u0436\u043e\u0431\u044b \u043d\u0435\u0443\u0434\u043e\u0431\u043d\u043e.<\/p>\n<p>  \u0418\u0442\u0430\u043a, \u043d\u0430\u0448 \u043f\u043b\u0430\u043d:<\/p>\n<ol>\n<li>\u0418\u043d\u0438\u0446\u0438\u0438\u0440\u0443\u0435\u043c Playwright-\u043f\u0440\u043e\u0435\u043a\u0442 \u0441 GitLab CI-\u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0435\u0439.<\/li>\n<li>\u0414\u0435\u043b\u0430\u0435\u043c \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0443 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u0432 Rocket.Chat \u043f\u043e\u0441\u043b\u0435 \u043f\u0440\u043e\u0433\u043e\u043d\u0430 \u0442\u0435\u0441\u0442\u043e\u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u043c \u0441\u043a\u0440\u0438\u043f\u0442\u043e\u043c.<\/li>\n<li>\u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0435\u0434\u0438\u043d\u043d\u044b\u0439 HTML-\u043e\u0442\u0447\u0435\u0442 \u0434\u043b\u044f \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u044b\u0445 \u0437\u0430\u043f\u0443\u0441\u043a\u043e\u0432.<\/li>\n<\/ol>\n<p>  <font color=\"#EB4247\"><\/p>\n<h2>\u041d\u0430\u0447\u0430\u043b\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0441 \u043f\u0440\u043e\u0441\u0442\u044b\u043c CI<\/h2>\n<p><\/font>  <\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/post_images\/720\/866\/768\/7208667688206d29a8a1ac0e7d600904.png\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/720\/866\/768\/7208667688206d29a8a1ac0e7d600904.png\"\/><\/div>\n<p>  <\/p>\n<h3>\u0422\u0435\u0441\u0442\u044b <\/h3>\n<p>  \u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043f\u0440\u043e\u0435\u043a\u0442 \u0432 Playwright. \u0423 \u043d\u0435\u0433\u043e \u0435\u0441\u0442\u044c \u043a\u043e\u043c\u0430\u043d\u0434\u0430 <code>init<\/code> \u0434\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u0440\u0430:<\/p>\n<pre><code class=\"bash\">npm init playwright@latest <\/code><\/pre>\n<p>  \u041d\u0430 \u0432\u044b\u0445\u043e\u0434\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u043f\u0430\u043f\u043a\u0438 tests \u0438 tests-example. \u0412 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0442\u0435\u0441\u0442\u044b \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u044e\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0432 \/tests, \u0442\u0430\u043a \u0447\u0442\u043e \u043f\u0435\u0440\u0435\u043c\u0435\u0441\u0442\u0438\u043c \u0442\u0435\u0441\u0442\u044b \u0438\u0437 test-example \u0432 tests \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u043c, \u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0443 \u043d\u0430\u0441 \u0442\u0435\u043f\u0435\u0440\u044c \u0442\u0435\u0441\u0442\u043e\u0432:<\/p>\n<pre><code class=\"bash\">npx playwright test --list \u2026 Total: 78 tests in 2 files <\/code><\/pre>\n<p>  \u0412\u0441\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u2014 \u0434\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u044d\u0442\u043e\u0433\u043e \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e. \u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u043c\u043e\u0434\u0438\u0444\u0438\u0446\u0438\u0440\u0443\u0435\u043c \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e \u043d\u0430\u0448\u0438\u0445 \u0442\u0435\u0441\u0442\u043e\u0432 \u0432 playwright.config.ts. \u0415\u0441\u043b\u0438 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e \u2014 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0440\u0435\u043f\u043e\u0440\u0442\u044b list \u0438 junit, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0443\u0431\u0435\u0440\u0435\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u044b firefox \u0438 webkit.<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u0418\u0442\u043e\u0433\u043e\u0432\u0430\u044f \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"javascript\">import { defineConfig, devices } from '@playwright\/test';  export default defineConfig({   testDir: '.\/tests',   \/* Run tests in files in parallel *\/   fullyParallel: true,   \/* Fail the build on CI if you accidentally left test.only in the source code. *\/   forbidOnly: !!process.env.CI,   \/* Retry on CI only *\/   retries: process.env.CI ? 2 : 0,   \/* Opt out of parallel tests on CI. *\/   workers: process.env.CI ? 3 : undefined,   \/* Reporter to use. See https:\/\/playwright.dev\/docs\/test-reporters *\/   reporter: [['html'], ['list'], ['junit', { outputFile: 'test_results.xml' }]],   \/* Shared settings for all the projects below. See https:\/\/playwright.dev\/docs\/api\/class-testoptions. *\/   \u2026   projects: [     {       name: 'chromium',       use: { ...devices['Desktop Chrome'] },     },      \/\/ {     \/\/   name: 'firefox',     \/\/   use: { ...devices['Desktop Firefox'] },     \/\/ },      \/\/ {     \/\/   name: 'webkit',     \/\/   use: { ...devices['Desktop Safari'] },     \/\/ }, }); <\/code><\/pre>\n<p>  <\/div>\n<\/p><\/div>\n<p>  \u041c\u044b \u0443\u0431\u0440\u0430\u043b\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u044b firefox \u0438 webkit, \u0442\u0430\u043a \u043a\u0430\u043a \u043e\u043d\u0438 \u043c\u043e\u0433\u0443\u0442 \u043f\u0440\u0438\u0432\u0435\u0441\u0442\u0438 \u043a \u043f\u0443\u0442\u0430\u043d\u0438\u0446\u0435 \u0432 junit-\u043e\u0442\u0447\u0435\u0442\u0430\u0445. \u0412 Playwright \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f \u0442\u0435\u0441\u0442\u043e\u0432 \u0432 \u0440\u0435\u043f\u043e\u0440\u0442\u0435 \u043d\u0435 \u0432\u043a\u043b\u044e\u0447\u0430\u044e\u0442 \u043f\u0440\u043e\u0435\u043a\u0442, \u0434\u043b\u044f \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043e\u043d\u0438 \u0431\u044b\u043b\u0438 \u0437\u0430\u043f\u0443\u0449\u0435\u043d\u044b. \u0418 \u043f\u0440\u0438 \u043f\u0430\u0440\u0441\u0438\u043d\u0433\u0435 junit-\u043e\u0442\u0447\u0435\u0442\u043e\u0432 78 \u0442\u0435\u0441\u0442\u043e\u0432 \u0432 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u043c \u043e\u0442\u0447\u0435\u0442\u0435 \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u044e\u0442\u0441\u044f \u0432 26. \u041f\u0440\u0438\u0447\u0438\u043d\u0430 \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0442\u0435\u0441\u0442\u043e\u0432 \u0441\u043e\u0432\u043f\u0430\u0434\u0430\u044e\u0442 \u2014 \u043a \u0441\u043b\u043e\u0432\u0443, \u043d\u0430 \u043e\u0431\u0449\u0435\u0435 \u0447\u0438\u0441\u043b\u043e \u0442\u0435\u0441\u0442\u043e\u0432 \u044d\u0442\u043e \u043d\u0435 \u0432\u043b\u0438\u044f\u0435\u0442.<\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/post_images\/aad\/bb3\/26e\/aadbb326e237c13aabd57333c55eeb81.png\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/aad\/bb3\/26e\/aadbb326e237c13aabd57333c55eeb81.png\"\/><\/div>\n<p>  <i>\u0412\u043e\u0442 \u0442\u0430\u043a \u044d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c. <\/i><\/p>\n<h3>CI<\/h3>\n<p>  \u0418\u0442\u0430\u043a, \u0443 \u0435\u0441\u0442\u044c \u043d\u0430\u0431\u043e\u0440 \u0442\u0435\u0441\u0442\u043e\u0432 \u0441 \u0440\u0430\u0437\u043d\u044b\u043c\u0438 \u0440\u0435\u043f\u043e\u0440\u0442\u0430\u043c\u0438 \u0438 \u0442\u0440\u0435\u043c\u044f \u0432\u043e\u0440\u043a\u0435\u0440\u0430\u043c\u0438 \u043d\u0430 \u043f\u043e\u0442\u043e\u043a \u0432 \u0431\u0443\u0434\u0443\u0449\u0435\u043c CI. \u041d\u0430\u0441\u0442\u0430\u043b\u043e \u0432\u0440\u0435\u043c\u044f \u043e\u043f\u0438\u0441\u0430\u0442\u044c \u043d\u0430\u0448 yml-\u0444\u0430\u0439\u043b \u0434\u043b\u044f GitLab CI:<\/p>\n<pre><code class=\"plaintext\">stages:   - tests e2e:   image: mcr.microsoft.com\/playwright:latest   stage: tests   parallel: 5   allow_failure: true   tags:     - kube-dev   script:     - npx playwright test --shard=$CI_NODE_INDEX\/$CI_NODE_TOTAL   artifacts:     paths:       - \"**\/test_results.xml\"       - \"**\/playwright-report\"     reports:       junit: \"**\/test_results.xml\" <\/code><\/pre>\n<p>  \u0414\u043b\u044f CI \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c GitLab, \u0442\u0430\u043a \u043a\u0430\u043a \u044d\u0442\u043e \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u043d\u0435\u043f\u0440\u0435\u0440\u044b\u0432\u043d\u043e\u0439 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438 \u0432 Selectel. \u041f\u0435\u0440\u0435\u0434 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435\u043c \u0444\u0430\u0439\u043b\u0430 gitlab-ci.yml \u043d\u0435 \u0437\u0430\u0431\u0443\u0434\u044c\u0442\u0435 <a href=\"https:\/\/docs.gitlab.com\/ee\/ci\/enable_or_disable_ci.html%23enable-cicd-in-a-project\">\u0430\u043a\u0442\u0438\u0432\u0438\u0440\u043e\u0432\u0430\u0442\u044c CI\/CD<\/a> \u0432 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 (\u0445\u043e\u0442\u044f \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u043e\u043d \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0432\u043a\u043b\u044e\u0447\u0435\u043d). <\/p>\n<p>  \u041d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0435\u0432 \u043f\u043e \u043f\u043e\u0432\u043e\u0434\u0443 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 CI:<\/p>\n<ul>\n<li>\u0412 \u043f\u043e\u043b\u0435 <code>image<\/code> \u0443\u043a\u0430\u0437\u0430\u043d\u0430 \u0441\u0430\u043c\u0430\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u044f\u044f \u0432\u0435\u0440\u0441\u0438\u044f \u043e\u0431\u0440\u0430\u0437\u0430, \u043d\u043e \u0441\u043e\u0432\u0435\u0442\u0443\u044e \u00ab\u0437\u0430\u043f\u0438\u043d\u0438\u0442\u044c\u00bb \u043d\u0430 \u0442\u0435\u043a\u0443\u0449\u0443\u044e. \u0412\u043d\u0435\u0437\u0430\u043f\u043d\u044b\u0435 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f Playwright \u043c\u043e\u0433\u0443\u0442 \u0447\u0442\u043e-\u043d\u0438\u0431\u0443\u0434\u044c \u0441\u043b\u043e\u043c\u0430\u0442\u044c \u2014 \u043e\u0442 screenshot-\u0442\u0435\u0441\u0442\u043e\u0432 \u0434\u043e \u0440\u0430\u043d\u0435\u0435 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430.<\/li>\n<li>\u0412 \u043f\u043e\u043b\u0435 <code>parallels<\/code> \u0443\u043a\u0430\u0437\u0430\u043d\u043e \u0447\u0438\u0441\u043b\u043e \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u044b\u0445 \u0434\u0436\u043e\u0431. \u0427\u0438\u0441\u043b\u043e 5 \u0432\u044b\u0431\u0440\u0430\u043d\u043e \u0434\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u0440\u0430, \u0432 \u0432\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u043d\u043e \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043b\u044e\u0431\u044b\u043c. <\/li>\n<li><code>tags<\/code> \u2014 \u0442\u0435\u0433 \u0434\u043b\u044f \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438. \u041f\u043e \u043d\u0435\u043c\u0443 GitLab \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442, \u043d\u0430 \u043a\u0430\u043a\u0438\u0445 \u0440\u0430\u043d\u043d\u0435\u0440\u0430\u0445 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0442\u0435\u0441\u0442\u044b. \u0422\u0435\u0433 <code>kube-dev<\/code> \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d \u043d\u0430\u043c \u0434\u043b\u044f \u0440\u0430\u0437\u043d\u044b\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432 \u0438 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043e\u0442\u0434\u0435\u043b\u043e\u043c DevOps-\u0438\u043d\u0436\u0435\u043d\u0435\u0440\u043e\u0432 Selectel. <\/li>\n<\/ul>\n<p>  \u041d\u0430 \u044d\u0442\u043e\u043c \u0448\u0430\u0433\u0435 \u043c\u044b \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u043e\u0432\u0430\u043b\u0438 \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u044b\u0439 \u0437\u0430\u043f\u0443\u0441\u043a \u043d\u0430\u0448\u0438\u0445 \u0442\u0435\u0441\u0442\u043e\u0432 \u0441 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430\u043c\u0438 \u0432 GitLab (\u0438\u0437 junit) \u0438 HTML-\u043e\u0442\u0447\u0435\u0442\u0430\u043c\u0438 \u0432 \u0430\u0440\u0442\u0435\u0444\u0430\u043a\u0442\u0430\u0445 \u043a\u0430\u0436\u0434\u043e\u0439 \u0434\u0436\u043e\u0431\u044b.<\/p>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u043c \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0443 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u0432 Rocket.Chat \u0432 \u043d\u0443\u0436\u043d\u043e\u043c \u043d\u0430\u043c \u0444\u043e\u0440\u043c\u0430\u0442\u0435.<\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/post_images\/eb4\/9e3\/ed6\/eb49e3ed6dc22f73cb59a6945936ceeb.png\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/eb4\/9e3\/ed6\/eb49e3ed6dc22f73cb59a6945936ceeb.png\"\/><\/div>\n<p>  \u0421\u0434\u0435\u043b\u0430\u0435\u043c \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0443 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u0432 \u0447\u0430\u0442 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0432\u0435\u0431\u0445\u0443\u043a\u043e\u0432. \u0414\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c Rocket.Chat (\u0432 \u043f\u043b\u0430\u043d\u0435 API \u043e\u043d \u043f\u043e\u0445\u043e\u0436 \u043d\u0430 Slack). \u041e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u044d\u0442\u0430\u043f \u0441 \u0440\u0435\u043f\u043e\u0440\u0442\u043e\u043c \u043c\u044b \u0432\u044b\u0431\u0440\u0430\u043b\u0438 \u043f\u043e \u0434\u0432\u0443\u043c \u043f\u0440\u0438\u0447\u0438\u043d\u0430\u043c:<\/p>\n<ol>\n<li>Playwright \u0434\u0435\u043b\u0438\u0442 \u0442\u0435\u0441\u0442\u044b \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u043c <code>\u2014shard<\/code> \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u043d\u0430 \u0440\u0430\u0432\u043d\u044b\u0435 \u0447\u0430\u0441\u0442\u0438, \u043d\u043e \u043f\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u044d\u0442\u0438 \u0447\u0430\u0441\u0442\u0438 \u043c\u043e\u0433\u0443\u0442 \u0441\u0438\u043b\u044c\u043d\u043e \u043e\u0442\u043b\u0438\u0447\u0430\u0442\u044c\u0441\u044f. \u0410 \u0434\u043b\u044f \u0440\u0435\u043f\u043e\u0440\u0442\u0430 \u043c\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0434\u043e\u0436\u0434\u0430\u0442\u044c\u0441\u044f \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u0432\u0441\u0435\u0445 \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u044b\u0445 \u0437\u0430\u043f\u0443\u0441\u043a\u043e\u0432.<\/li>\n<li>\u0415\u0441\u043b\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0441\u043a\u0440\u0438\u043f\u0442 \u043d\u0430 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u043c \u044d\u0442\u0430\u043f\u0435, \u043f\u043e\u0441\u043b\u0435 \u0432\u0441\u0435\u0445 \u0442\u0435\u0441\u0442\u043e\u0432 \u043c\u043e\u0436\u043d\u043e \u043d\u0435\u043f\u043b\u043e\u0445\u043e \u00ab\u043f\u043e\u043a\u043e\u0441\u0442\u044b\u043b\u0438\u0442\u044c\u00bb \u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0443 \u0440\u0435\u043f\u043e\u0440\u0442\u043e\u0432 \u0432 Jira, \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u0430\u0432\u0442\u043e\u0442\u0435\u0441\u0442\u043e\u0432 <a href=\"https:\/\/testengineer.ru\/nestabilnye-testy-pochemu-oni-sushchestvuyut-i-chto-s-nimi-delat\/\">\u043a\u0430\u0440\u0430\u043d\u0442\u0438\u043d\u0435<\/a>. \u0418\u043b\u0438 \u0441\u043a\u043b\u0435\u0439\u043a\u0443 HTML-\u043e\u0442\u0447\u0435\u0442\u043e\u0432, \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0443 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u0441 \u0441\u0441\u044b\u043b\u043a\u0430\u043c\u0438 \u043d\u0430 \u0440\u0435\u043f\u043e\u0440\u0442, \u0437\u0430\u043a\u0440\u044b\u0442\u0438\u0435 \u0442\u0435\u0441\u0442\u0440\u0430\u043d\u0430 \u0432 TMS (\u043f\u0440\u0438 \u043d\u0430\u043b\u0438\u0447\u0438\u0438 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438) \u0438 \u0434\u0440\u0443\u0433\u043e\u0435. \u041a\u043e\u043d\u0435\u0447\u043d\u043e, \u0435\u0441\u043b\u0438 \u043d\u0438\u0447\u0435\u0433\u043e \u044d\u0442\u043e\u0433\u043e \u043d\u0435 \u043d\u0443\u0436\u043d\u043e, \u0442\u043e \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e <a href=\"https:\/\/docs.gitlab.com\/ee\/user\/project\/integrations\/slack.html\">\u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044e<\/a> \u0438\u043b\u0438 <a href=\"https:\/\/docs.gitlab.com\/ee\/user\/project\/integrations\/webhooks.html\">\u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0443 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0432\u0435\u0431\u0445\u0443\u043a\u043e\u0432<\/a>.<\/li>\n<\/ol>\n<p>  \u0412\u0441\u044e \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043c\u043e\u0436\u043d\u043e \u0441\u0432\u0435\u0441\u0442\u0438 \u043a \u043f\u043b\u0430\u043d\u0443:<\/p>\n<ol>\n<li>\u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0432\u0435\u0431\u0445\u0443\u043a \u043e\u0442 \u0447\u0430\u0442\u0430 \u0438 <a href=\"https:\/\/docs.gitlab.com\/ee\/user\/project\/settings\/project_access_tokens.html%23scopes-for-a-project-access-token\">\u0442\u043e\u043a\u0435\u043d \u043d\u0430 \u0447\u0442\u0435\u043d\u0438\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/a> \u0432 <a href=\"https:\/\/docs.gitlab.com\/ee\/ci\/variables\/%23define-a-cicd-variable-in-the-ui\">\u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0432 GitLab CI<\/a>.<\/li>\n<li>\u041f\u0438\u0448\u0435\u043c \u0441\u043a\u0440\u0438\u043f\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f.<\/li>\n<li>\u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043d\u043e\u0432\u044b\u0439 stage \u0432 \u0444\u0430\u0439\u043b gitlab-ci.yml \u0441 \u0437\u0430\u043f\u0443\u0441\u043a\u043e\u043c \u0441\u043a\u0440\u0438\u043f\u0442\u0430.<\/li>\n<\/ol>\n<p>  \u0423\u0441\u043f\u0435\u0445!<\/p>\n<h3>\u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0442\u043e\u043a\u0435\u043d \u0438 \u0432\u0435\u0431\u0445\u0443\u043a<\/h3>\n<p>  \u0422\u043e\u043a\u0435\u043d \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043a\u0430\u043a <code>TOKEN<\/code>, \u0430 \u0432\u0435\u0431\u0445\u0443\u043a \u043e\u0442 \u0447\u0430\u0442\u0430 \u043a\u0430\u043a <code>ROCKET_WEBHOOK<\/code> \u0432 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f. \u041f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u0441\u0442\u043e\u0438\u0442 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432 \u043f\u0440\u043e\u0435\u043a\u0442 \u0446\u0435\u043b\u0438\u043a\u043e\u043c \u043f\u043e <a href=\"https:\/\/docs.gitlab.com\/ee\/ci\/variables\/%23for-a-project\">\u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u0438 \u043e\u0442 GitLab<\/a>.<\/p>\n<h3>\u041e\u0442\u043f\u0440\u0430\u0432\u043a\u0430 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0432 Rocket.Chat<\/h3>\n<p>  \u0421\u043a\u0440\u0438\u043f\u0442 \u0440\u0435\u0448\u0438\u043b \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043d\u0430 TypeScript \u0438 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0435 got, \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0432\u0441\u0435 \u0431\u0443\u0434\u0435\u0442 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e ts-node.<\/p>\n<pre><code class=\"bash\">npm i got ts-node <\/code><\/pre>\n<p>  \u041f\u0440\u043e\u0441\u0442\u043e \u0442\u0430\u043a \u0432\u0435\u0440\u0441\u0438\u0438 ts-node (10.9.1) \u0438 got (12.6.0) \u0432\u043c\u0435\u0441\u0442\u0435 \u043d\u0435 \u0437\u0430\u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442, \u0442\u0430\u043a \u0447\u0442\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0432 \u043a\u043e\u0440\u0435\u043d\u044c \u043f\u0440\u043e\u0435\u043a\u0442 tscofnig.json \u0438 \u043f\u043e\u043c\u0435\u043d\u044f\u0435\u043c package.json.<\/p>\n<p>  1. \u0421\u043e\u0437\u0434\u0430\u0435\u043c \u0444\u0430\u0439\u043b tsconfig.json:<\/p>\n<pre><code class=\"json\">{     \"compilerOptions\": {         \"module\": \"NodeNext\", \/\/ or ES2015, ES2020         \"moduleResolution\": \"no\"     },     \"ts-node\": {         \/\/ Tell ts-node CLI to install the --loader automatically         \"esm\": true     }, } <\/code><\/pre>\n<p>  2. \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u0432 package.json:<\/p>\n<pre><code class=\"json\">{ \u2026.   \"type\": \"module\", \u2026 } <\/code><\/pre>\n<p>  3. \u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0444\u0430\u0439\u043b \u0441\u043e \u0441\u043a\u0440\u0438\u043f\u0442\u043e\u043c:<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u0421\u043a\u0440\u0438\u043f\u0442 reportToChat.ts<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"javascript\">import got from 'got';  &lt;h3> predefined variables gitlab&lt;\/h3> const CI_API_V4_URL = process.env.CI_API_V4_URL const CI_PROJECT_ID = process.env.CI_PROJECT_ID; const CI_PIPELINE_URL = process.env.CI_PIPELINE_URL; const CI_PIPELINE_ID = process.env.CI_PIPELINE_ID;  &lt;h3> specific variable in CI&lt;\/h3> const ROCKET_WEBHOOK = process.env.ROCKET_WEBHOOK; const TOKEN_FOR_GET_GITLAB_REPORT = process.env.TOKEN; interface IGitlabResponse {   total_count: number;   failed_count: number;   skipped_count: number;   test_suites: object; } class Report implements IReport {   public total: number;   public failed: number;   public skipped: number;   constructor(response: IGitlabResponse) {     this.total = response.total_count;     this.failed = response.failed_count;     this.skipped = response.skipped_count;   } } interface IReport {   total: number;   failed: number;   skipped: number; } interface ISendRocketChat {   reportUrl: string,   report: IReport, } async function getGitlabReport(): Promise&lt;IReport> {   const headers = { 'PRIVATE-TOKEN': TOKEN_FOR_GET_GITLAB_REPORT };   const url = `${CI_API_V4_URL}\/projects\/${CI_PROJECT_ID}\/pipelines\/${CI_PIPELINE_ID}\/test_report`;   try {     const responseJson: IGitlabResponse = await got.get(url, { headers: headers }).json();     return new Report(responseJson);   } catch (error) {     throw new Error('\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u0440\u0435\u043f\u043e\u0440\u0442 \u0441 gitlab\\n' + error);   } }; async function sendRocketChatMessage(param: ISendRocketChat): Promise&lt;void> {   const resultMsg = param.report.failed === 0 ? '\u0423\u0441\u043f\u0435\u0448\u043d\u043e :white_check_mark:' : '\u041d\u0430\u0439\u0434\u0435\u043d\u044b \u043e\u0448\u0438\u0431\u043a\u0438 :sos:'   const payload = {     text:       `\u0421\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 [JUnit \u043e\u0442\u0447\u0451\u0442](${param.reportUrl})\\n` +       `${resultMsg}\\n` +       `\\`\\`\\`\\nTotal:   ${param.report.total}\\n` +       `Failed:  ${param.report.failed}\\n` +       `Skipped: ${param.report.skipped}\\n\\`\\`\\``   };   await got.post(ROCKET_WEBHOOK as string, { json: payload }); } async function main() {   const test_report = await getGitlabReport();   try {     await sendRocketChatMessage({       reportUrl: `${CI_PIPELINE_URL}\/test_report`,       report: test_report,     });   } catch (error) {     throw new Error('\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0432 Rocket.Chat\\n' + error);   } } main(); <\/code><\/pre>\n<p>  <\/div>\n<\/p><\/div>\n<p>  <\/p>\n<h3>\u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043d\u043e\u0432\u044b\u0439 stage GitLab CI<\/h3>\n<p>  \u041e\u0441\u0442\u0430\u0435\u0442\u0441\u044f \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0437\u0430\u043f\u0443\u0441\u043a \u043d\u0430\u0448\u0435\u0433\u043e \u0441\u043a\u0440\u0438\u043f\u0442\u0430 \u0441 \u0440\u0435\u043f\u043e\u0440\u0442\u0430\u043c\u0438 \u0432 gitlab-ci.yml \u043f\u043e\u0441\u043b\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0432\u0441\u0435\u0445 \u0442\u0435\u0441\u0442\u043e\u0432. \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043a\u0430\u043a \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0443\u044e \u0434\u0436\u043e\u0431\u0443, \u0447\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0434\u043e\u0436\u0438\u0434\u0430\u0442\u044c\u0441\u044f \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u0432\u0441\u0435\u0445 \u0437\u0430\u043f\u0443\u0449\u0435\u043d\u043d\u044b\u0445 \u0442\u0435\u0441\u0442\u043e\u0432:<\/p>\n<pre><code class=\"plaintext\">  reports:    image: mcr.microsoft.com\/playwright:latest    stage: report   needs: [e2e]   tags:     - kube-dev   before_script:     - npm i ts-node got   script:     - npx ts-node helpers\/reportToChat.ts <\/code><\/pre>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u0443 \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0435\u0441\u0442\u044c \u0440\u0435\u043f\u043e\u0440\u0442\u044b \u0441 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e\u043c \u0443\u043f\u0430\u0432\u0448\u0438\u0445 \u0438 \u043f\u0440\u043e\u0439\u0434\u0435\u043d\u043d\u044b\u0445 \u0442\u0435\u0441\u0442\u043e\u0432. \u041d\u043e HTML-\u043e\u0442\u0447\u0435\u0442\u044b \u0432\u0441\u0435 \u0435\u0449\u0435 \u0443 \u043a\u0430\u0436\u0434\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u0441\u0432\u043e\u0438 \u2014 \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u044d\u0442\u043e \u0438\u0441\u043f\u0440\u0430\u0432\u0438\u043c.<\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/post_images\/eb1\/ea9\/270\/eb1ea92704c7510c674735f39f46f558.png\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/eb1\/ea9\/270\/eb1ea92704c7510c674735f39f46f558.png\"\/><\/div>\n<p>  <a href=\"https:\/\/selectel.ru\/services\/dedicated\/auction\/?utm_source=habr.com&amp;utm_medium=referral&amp;utm_campaign=dedicated_article_gitlabci_031023_banner_048_ord\"><\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/au\/j4\/h4\/auj4h4dcfw4ipieenxqmazu-crc.png\" data-src=\"https:\/\/habrastorage.org\/webt\/au\/j4\/h4\/auj4h4dcfw4ipieenxqmazu-crc.png\"\/><\/div>\n<p><\/a><\/p>\n<p>  <font color=\"#EB4247\"><\/p>\n<h2>\u0415\u0434\u0438\u043d\u044b\u0439 HTML-\u043e\u0442\u0447\u0435\u0442<\/h2>\n<p><\/font>  <\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/post_images\/7a0\/37e\/d9c\/7a037ed9c2aa14220fb0b7731720f89a.png\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/7a0\/37e\/d9c\/7a037ed9c2aa14220fb0b7731720f89a.png\"\/><\/div>\n<p>  \u0418\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e \u0441\u043a\u043b\u0435\u0439\u043a\u0430 \u0440\u0435\u043f\u043e\u0440\u0442\u043e\u0432 \u0431\u044b\u043b\u0430 \u0441\u0434\u0435\u043b\u0430\u043d\u0430 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438, <a href=\"https:\/\/github.com\/anooprav7\/playwright-merge-html-reports\">playwright-merge-html-reports<\/a> \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043c\u044b \u043d\u0430\u0448\u043b\u0438 \u0431\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f<a href=\"https:\/\/github.com\/microsoft\/playwright\/issues\/10437\"> issue #10437<\/a>. \u041e\u0434\u043d\u0430\u043a\u043e \u0441 \u0432\u0435\u0440\u0441\u0438\u0438 <a href=\"https:\/\/playwright.dev\/docs\/release-notes%23version-137\">Playwright 1.37.0<\/a> \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u043c \u0438 \u0431\u043e\u043b\u0435\u0435 \u0443\u0434\u043e\u0431\u043d\u044b\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u043e\u043c. \u0412 \u043e\u0442\u043b\u0438\u0447\u0438\u0435 \u043e\u0442 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u0442\u0443\u0442 \u0440\u0435\u0448\u0435\u043d\u0430 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u0441\u043a\u043b\u0435\u0439\u043a\u0438 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u044c\u043d\u043e\u0433\u043e \u0447\u0438\u0441\u043b\u0430 \u0440\u0435\u043f\u043e\u0440\u0442\u043e\u0432.<\/p>\n<p>  \u0412\u0441\u0435, \u0447\u0442\u043e \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c, \u043c\u043e\u0436\u043d\u043e \u0440\u0430\u0437\u0431\u0438\u0442\u044c \u043d\u0430 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0433\u0440\u0443\u043f\u043f:<\/p>\n<ol>\n<li>\u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u043c playwright-test \u0434\u043e 1.37.0 \u0438\u043b\u0438 \u0432\u044b\u0448\u0435. \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c blob-\u0440\u0435\u043f\u043e\u0440\u0442<\/li>\n<li>\u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0432 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f Rocket.Chat \u0441\u0441\u044b\u043b\u043a\u0443 \u043d\u0430 \u0438\u0442\u043e\u0433\u043e\u0432\u044b\u0439 \u0440\u0435\u043f\u043e\u0440\u0442,<\/li>\n<li>\u0434\u043e\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u043c \u043d\u0430\u0448 CI \u0434\u043b\u044f \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u043e\u0431\u0449\u0435\u0433\u043e \u043e\u0442\u0447\u0435\u0442\u0430.<\/li>\n<\/ol>\n<p>  \u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u0443\u043a\u0430\u0436\u0435\u043c \u043d\u043e\u0432\u044b\u0439 \u0440\u0435\u043f\u043e\u0440\u0442\u0435\u0440 \u0432 playwright.config.ts \u0432\u043c\u0435\u0441\u0442\u043e HTML \u0438 \u0441\u0434\u0435\u043b\u0430\u0435\u043c blob-\u0440\u0435\u043f\u043e\u0440\u0442.<\/p>\n<pre><code class=\"json\">\/* Reporter to use. See https:\/\/playwright.dev\/docs\/test-reporters *\/   reporter: [['blob'], ['list'], ['junit', { outputFile: 'test_results.xml' }]], <\/code><\/pre>\n<p>  <\/p>\n<h3>\u0414\u043e\u0440\u0430\u0431\u043e\u0442\u0430\u0435\u043c \u0441\u043a\u0440\u0438\u043f\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f<\/h3>\n<p>  \u041d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0434\u043e\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0432 rocket-chat, \u0434\u043e\u0431\u0430\u0432\u0438\u0432 \u0432 \u043d\u0435\u0433\u043e \u0441\u0441\u044b\u043b\u043a\u0443 \u043d\u0430 HTML-\u043e\u0442\u0447\u0435\u0442. \u0412 \u0441\u0441\u044b\u043b\u043a\u0435 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043f\u0440\u043e\u0433\u043e\u043d\u0430 \u0431\u0443\u0434\u0435\u0442 \u043c\u0435\u043d\u044f\u0442\u044c\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e <i>JOB_ID. <\/i>\u0418\u0442\u043e\u0433\u043e\u0432\u044b\u0439 \u0432\u0438\u0434 \u043d\u0430\u0448\u0435\u0433\u043e \u0441\u043a\u0440\u0438\u043f\u0442\u0430 reportToChat.ts \u2014 \u043d\u0438\u0436\u0435. <\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u0421\u043a\u0440\u0438\u043f\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"javascript\">import got from 'got';   \/\/ predefined variables gitlab const CI_API_V4_URL = process.env.CI_API_V4_URL const CI_PROJECT_ID = process.env.CI_PROJECT_ID; const CI_PIPELINE_URL = process.env.CI_PIPELINE_URL; const CI_PIPELINE_ID = process.env.CI_PIPELINE_ID; const JOB_ID = process.env.CI_JOB_ID   \/\/ JOB_ID \u0434\u043b\u044f \u0441\u0441\u044b\u043b\u043a\u0438 \u043d\u0430 html \u043e\u0442\u0447\u0435\u0442 const PAGES_URL = process.env.CI_PAGES_URL?.replace(\/(?&lt;=[a-z])\\\/\/, '\/-\/')\/\/ PAGES_URL \u0442\u0430\u043a\u0436\u0435 \u0434\u043b\u044f \u0441\u0441\u044b\u043b\u043a\u0438 \u043d\u0430 html \u043e\u0442\u0447\u0435\u0442 \/\/ specific variable in CI const ROCKET_WEBHOOK = process.env.ROCKET_WEBHOOK; const TOKEN_FOR_GET_GITLAB_REPORT = process.env.TOKEN;  interface IGitlabResponse {   total_count: number;   failed_count: number;   skipped_count: number;   test_suites: object; }  class Report implements IReport {   public total: number;   public failed: number;   public skipped: number;   constructor(response: IGitlabResponse) {     this.total = response.total_count;     this.failed = response.failed_count;     this.skipped = response.skipped_count;   } }  interface IReport {   total: number;   failed: number;   skipped: number; }  interface ISendRocketChat {   reportUrl: string,   htmlURL: string,\/\/ \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0432 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0441\u0441\u044b\u043b\u043a\u0443 \u043d\u0430 html \u043e\u0442\u0447\u0435\u0442   report: IReport, }  async function getGitlabReport(): Promise&lt;IReport> {   const headers = { 'PRIVATE-TOKEN': TOKEN_FOR_GET_GITLAB_REPORT };   const url = `${CI_API_V4_URL}\/projects\/${CI_PROJECT_ID}\/pipelines\/${CI_PIPELINE_ID}\/test_report`;   try {     const responseJson: IGitlabResponse = await got.get(url, { headers: headers }).json();     return new Report(responseJson);   } catch (error) {     throw new Error('\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u0440\u0435\u043f\u043e\u0440\u0442 \u0441 gitlab\\n' + error);   } };  async function sendRocketChatMessage(param: ISendRocketChat): Promise&lt;void> {   const resultMsg = param.report.failed === 0 ? '\u0423\u0441\u043f\u0435\u0448\u043d\u043e :white_check_mark:' : '\u041d\u0430\u0439\u0434\u0435\u043d\u044b \u043e\u0448\u0438\u0431\u043a\u0438 :sos:'    const payload = {     text:       `\u0421\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 [JUnit \u043e\u0442\u0447\u0451\u0442](${param.reportUrl}) \u043d\u0430 [HTML](${param.htmlURL})\\n` + \/\/ \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0441\u0441\u044b\u043b\u043a\u0443 \u043d\u0430 \u043d\u0430\u0448 \u043e\u0442\u0447\u0435\u0442 \u0432 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435       `${resultMsg}\\n` +       `\\`\\`\\`\\nTotal:   ${param.report.total}\\n` +       `Failed:  ${param.report.failed}\\n` +       `Skipped: ${param.report.skipped}\\n\\`\\`\\``   };   await got.post(ROCKET_WEBHOOK as string, { json: payload }); }  async function main() {   const test_report = await getGitlabReport();   try {     await sendRocketChatMessage({       reportUrl: `${CI_PIPELINE_URL}\/test_report`,       htmlURL: `${PAGES_URL}\/-\/jobs\/${JOB_ID}\/artifacts\/playwright-report\/index.html`, \/\/ \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u043c \u0441\u0441\u044b\u043b\u043a\u0443 \u043d\u0430 HTML \u043e\u0442\u0447\u0435\u0442       report: test_report,     });   } catch (error) {     throw new Error('\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0432 Rocket.Chat\\n' + error);   } }  main(); <\/code><\/pre>\n<p>  <\/div>\n<\/p><\/div>\n<p>  \u0417\u0434\u0435\u0441\u044c \u0432\u0441\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0440\u0430\u0441\u0441\u0447\u0438\u0442\u0430\u043d\u044b \u043d\u0430 \u0440\u0430\u0431\u043e\u0442\u0443 \u0432 CI. \u0422\u0430\u043a \u0434\u0432\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f (<code>PAGES_URL<\/code> \u0438 <code>JOB_ID<\/code>) \u043d\u0443\u0436\u043d\u044b \u0434\u043b\u044f \u0441\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f URL \u0438 \u043e\u0442\u043a\u0440\u044b\u0442\u0438\u044f HTML-\u0440\u0435\u043f\u043e\u0440\u0442\u0430. \u0415\u0433\u043e \u0442\u0430\u043a\u0436\u0435 \u043c\u043e\u0436\u043d\u043e \u0432\u044b\u0433\u0440\u0443\u0436\u0430\u0442\u044c \u0432 \u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0435\u0435 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 \u0438 \u043d\u0435 \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043a\u0430\u043a \u0430\u0440\u0442\u0435\u0444\u0430\u043a\u0442 \u0441\u0431\u043e\u0440\u043a\u0438 \u2014 \u0442\u043e\u0433\u0434\u0430 \u0432 <code>htmlURL<\/code> \u0441\u0442\u043e\u0438\u0442 \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u0430\u0434\u0440\u0435\u0441 \u043e\u0442\u0447\u0435\u0442\u0430 \u0432\u043e \u0432\u043d\u0435\u0448\u043d\u0435\u043c \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435<\/p>\n<h3>\u041f\u0440\u0430\u0432\u0438\u043c \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e CI<\/h3>\n<p>  \u0412 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 CI \u043c\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0443\u0447\u0435\u0441\u0442\u044c \u043d\u043e\u0432\u044b\u0439 \u0430\u0440\u0442\u0435\u0444\u0430\u043a\u0442 \u2014 \u043f\u0430\u043f\u043a\u0443 blob-report, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0441\u043a\u043b\u0435\u0439\u043a\u0443 HTML-\u043e\u0442\u0447\u0435\u0442\u0430 \u0438\u0437 \u043d\u0430\u0431\u043e\u0440\u0430 blob-\u043e\u0442\u0447\u0435\u0442\u043e\u0432. \u0418\u0442\u043e\u0433\u043e\u0432\u044b\u0439 \u0432\u0438\u0434 \u043d\u0430\u0448\u0435\u0433\u043e \u0444\u0430\u0439\u043b\u0430 gitlab-ci.yml:<\/p>\n<pre><code class=\"plaintext\">stages:   - tests   - report e2e:   image: mcr.microsoft.com\/playwright:latest   stage: tests   parallel: 5   allow_failure: true   tags:     - kube-dev   before_script:     - npm i   script:     - npx playwright test --shard=$CI_NODE_INDEX\/$CI_NODE_TOTAL   artifacts:     when: always      expire_in: 1 week     paths:       - \"**\/test_results.xml\"       - \"**\/blob-report\"  # \u044d\u0442\u043e \u0435\u0449\u0435 \u043e\u0434\u0438\u043d \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u043e\u0442\u0447\u0435\u0442\u0430 \u0432 playwright     reports:       junit: \"**\/test_results.xml\" reports:   image: mcr.microsoft.com\/playwright:latest   stage: report   needs: [e2e]   tags:     - kube-dev   before_script:     - npm i ts-node got   script:     - npx playwright merge-reports --reporter=html .\/blob-report # \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0441\u043a\u043b\u0435\u0439\u043a\u0443 \u043e\u0442\u0447\u0435\u0442\u0430 \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u043e\u0439 \u0443\u0442\u0438\u043b\u0438\u0442\u043e\u0439     - npx ts-node helpers\/reportToChat.ts   artifacts:     when: always  # \u0442.\u043a. \u0442\u0435\u043f\u0435\u0440\u044c \u0432 \u0430\u0440\u0442\u0435\u0444\u0430\u043a\u0442\u0430\u0445 \u0445\u0440\u0430\u043d\u0438\u0442\u0441\u044f \u043e\u0442\u0447\u0435\u0442     expire_in: 1 week # \u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c \u0435\u0433\u043e \u043d\u0430 1 \u043d\u0435\u0434\u0435\u043b\u044e     paths:       - \"**\/blob-report\"       - \"**\/playwright-report\"  <\/code><\/pre>\n<p>  \u0412 \u0440\u0430\u043c\u043a\u0430\u0445 CI \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u043a\u043b\u0435\u0439\u043a\u0430 \u043e\u0442\u0447\u0435\u0442\u043e\u0432 \u043d\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u043c \u044d\u0442\u0430\u043f\u0435. \u042d\u0442\u043e \u0443\u0434\u043e\u0431\u043d\u0435\u0435 \u0443\u0442\u0438\u043b\u0438\u0442\u044b playwright-merge-html-reports. \u0414\u043b\u044f \u043d\u0435\u0435 \u043d\u0443\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0443\u0437\u043d\u0430\u0442\u044c \u043a\u043e\u043b-\u0432\u043e \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u044b\u0445 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0439 \u0442\u0435\u0441\u0442\u043e\u0432, \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c \u044d\u0442\u043e \u0432 <code>stage \"report\"<\/code> \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u043e\u0442\u0447\u0435\u0442\u043e\u0432 \u0432 \u0440\u0430\u0437\u043d\u044b\u0435 \u043f\u0430\u043f\u043a\u0438 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0439 \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u0438.<\/p>\n<p>  \u0418 \u0432\u043e\u0442, \u043d\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u043c \u044d\u0442\u0430\u043f\u0435 \u0443 \u043d\u0430\u0441 \u043f\u043e\u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0430\u0440\u0442\u0435\u0444\u0430\u043a\u0442 <code>\"**\/playwright-report\"<\/code>, \u0432\u043d\u0443\u0442\u0440\u0438 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0439 \u0435\u0434\u0438\u043d\u044b\u0439 \u043e\u0442\u0447\u0435\u0442. \u0410 \u0432 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f Rocket.Chat \u0442\u0435\u043f\u0435\u0440\u044c \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442\u0441\u044f \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u0435\u0434\u0438\u043d\u044b\u0439 \u043e\u0442\u0447\u0435\u0442:<\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/post_images\/5b1\/fc4\/825\/5b1fc4825138bab9d416dcd55283802f.png\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/5b1\/fc4\/825\/5b1fc4825138bab9d416dcd55283802f.png\"\/><\/div>\n<p>  <font color=\"#EB4247\"><\/p>\n<h2>\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/h2>\n<p><\/font>  <\/p>\n<blockquote><p>\u0418\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b \u043f\u043e <a href=\"https:\/\/github.com\/Belisckner\/playwright-report-example\">\u0441\u0441\u044b\u043b\u043a\u0435<\/a>. \u0414\u0435\u043b\u0430\u0439\u0442\u0435 \u0444\u043e\u0440\u043a \u0438 \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0439\u0442\u0435 \u0441\u0432\u043e\u0438 \u0443\u043b\u0443\u0447\u0448\u0435\u043d\u0438\u044f!<\/p><\/blockquote>\n<p>  \u041f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u044d\u0442\u043e\u0442 \u043a\u043e\u0434 \u043b\u0435\u0436\u0438\u0442 \u0432 \u043e\u0441\u043d\u043e\u0432\u0435 \u0442\u0435\u0441\u0442\u043e\u0432 \u043e\u0434\u043d\u043e\u0433\u043e \u0438\u0437 \u043d\u0430\u0448\u0438\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432. \u0417\u0430 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435\u043c \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u0443 \u043d\u0430\u0441 \u043e\u043f\u0438\u0441\u0430\u043d\u043e \u0431\u043e\u043b\u044c\u0448\u0435 \u0442\u0435\u0441\u0442\u043e\u0432. \u0422\u0430\u043a\u0436\u0435 \u043c\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u043b\u0438 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0434\u043b\u044f \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430 \u2014 \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0440\u0435\u043f\u043e\u0440\u0442\u0430 \u0432 Jira Issue \u0438 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044e \u0441 TMS Qase \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0433\u0438\u0431\u0440\u0438\u0434\u043d\u044b\u0445 \u0442\u0435\u0441\u0442-\u0440\u0430\u043d\u043e\u0432, \u0433\u0434\u0435 \u0447\u0430\u0441\u0442\u044c \u0442\u0435\u0441\u0442\u043e\u0432 \u043f\u0440\u043e\u0432\u043e\u0434\u0438\u0442\u0441\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438, \u0430 \u0447\u0430\u0441\u0442\u044c \u2014 \u0440\u0443\u043a\u0430\u043c\u0438.<\/p>\n<p>  \u0412 \u043f\u043b\u0430\u043d\u0430\u0445 \u2014 \u0432\u043d\u0435\u0434\u0440\u0438\u0442\u044c \u043f\u043e\u0434\u043e\u0431\u043d\u0443\u044e \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u0441 \u0435\u0434\u0438\u043d\u044b\u043c \u043e\u0442\u0447\u0435\u0442\u043e\u043c \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u043e\u0432 <a href=\"https:\/\/slc.tl\/mylpw\">\u0441\u0430\u0439\u0442\u0430<\/a> \u0438 <a href=\"http:\/\/my.selectel.ru\">\u043f\u0430\u043d\u0435\u043b\u0438 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f<\/a>. \u0422\u0430\u043a\u0436\u0435 \u0445\u043e\u0442\u0438\u043c \u043f\u043e\u043f\u0440\u043e\u0431\u043e\u0432\u0430\u0442\u044c \u0432\u044b\u0433\u0440\u0443\u0436\u0430\u0442\u044c HTML-\u0440\u0435\u043f\u043e\u0440\u0442\u044b \u0432\u043e \u0432\u043d\u0435\u0448\u043d\u0435\u0435 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 \u0441 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435\u043c \u0441\u043f\u0438\u0441\u043a\u0430 \u043e\u0442\u0447\u0435\u0442\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043d\u0435 \u043f\u0440\u0438\u0432\u044f\u0437\u0430\u043d\u043e \u043a GitLab CI, \u2014 \u043d\u0435\u043a\u0438\u0439 \u0430\u043d\u0430\u043b\u043e\u0433 Allure Server, \u043d\u043e \u0434\u043b\u044f playwright-html.<\/p>\n<p>  \u041c\u044b \u0442\u043e\u0447\u043d\u043e \u0434\u043e\u0439\u0434\u0435\u043c \u0434\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0445 \u04352\u0435-\u0442\u0435\u0441\u0442\u043e\u0432 \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u2014 \u0432\u0435\u0440\u043e\u044f\u0442\u043d\u043e, \u044d\u0442\u043e \u0431\u0443\u0434\u0443\u0449\u0430\u044f \u0442\u0435\u043c\u0430 \u0434\u043b\u044f \u0441\u0442\u0430\u0442\u044c\u0438. \u041e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u2014 \u0437\u0430\u043f\u0443\u0441\u043a \u043f\u043e \u043c\u0435\u0442\u0430\u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u0442\u0435\u0441\u0442\u043e\u0432 \u043f\u0440\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438 @playwright-test. \u0421\u0435\u0439\u0447\u0430\u0441 \u043e\u043d\u0430 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u0430 \u0442\u043e\u043b\u044c\u043a\u043e \u0432 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0438 \u0442\u0435\u0441\u0442\u0430. \u0421\u043b\u0435\u0434\u0438\u0442\u0435 \u0437\u0430 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f\u043c\u0438 \u0432 \u043d\u0430\u0448\u0435\u043c \u0431\u043b\u043e\u0433\u0435 \u043d\u0430 \u0425\u0430\u0431\u0440\u0435!<\/p>\n<p>  <font color=\"#EB4247\"><\/p>\n<h2>\u0414\u0440\u0443\u0433\u0438\u0435 \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u0435 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u044b<\/h2>\n<p><\/font>  <\/p>\n<ul>\n<li><a href=\"https:\/\/slc.tl\/t77ij\">\u041a\u0430\u043a \u043c\u044b \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043b\u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 OpenStack \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Rally \u0438 Tempest<\/a><\/li>\n<li><a href=\"https:\/\/slc.tl\/yt130\">\u041a\u0430\u043a \u043f\u0440\u043e\u0432\u0435\u0441\u0442\u0438 \u044e\u043d\u0438\u0442-\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0441 \u0411\u0414<\/a><\/li>\n<li><a href=\"https:\/\/slc.tl\/zit9d\">\u0424\u0435\u0440\u043c\u0430 \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u044b\u0445 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432 \u2014 \u043d\u043e\u0432\u044b\u0439 \u0441\u043f\u043e\u0441\u043e\u0431 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f Android-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439<\/a><\/li>\n<\/ul>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/765012\/\"> https:\/\/habr.com\/ru\/articles\/765012\/<\/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-1\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w780q1\/webt\/zv\/im\/vh\/zvimvhb0p-bh25fsqcva1enjvty.jpeg\" data-src=\"https:\/\/habrastorage.org\/webt\/zv\/im\/vh\/zvimvhb0p-bh25fsqcva1enjvty.jpeg\" data-blurred=\"true\"\/><\/div>\n<p>  \u041f\u0440\u0438\u0432\u0435\u0442, \u0425\u0430\u0431\u0440! \u042f \u0421\u0430\u0448\u0430 \u0410\u043b\u0435\u043a\u0441\u0435\u0435\u0432, \u0441\u0442\u0430\u0440\u0448\u0438\u0439 \u0438\u043d\u0436\u0435\u043d\u0435\u0440 \u043f\u043e \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044e \u0432 <a href=\"https:\/\/slc.tl\/mylpw\">Selectel<\/a>. \u041d\u0435\u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0432\u0440\u0435\u043c\u044f \u043d\u0430\u0437\u0430\u0434 \u043c\u044b \u0441\u0442\u043e\u043b\u043a\u043d\u0443\u043b\u0438\u0441\u044c \u0441 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u044c\u044e \u0440\u0435\u043e\u0440\u0433\u0430\u043d\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043e\u0442\u0447\u0435\u0442\u044b end-to-end-\u0442\u0435\u0441\u0442\u043e\u0432. \u0418\u0445 \u043f\u0440\u043e\u0433\u043e\u043d \u0441\u0442\u0430\u043b \u0437\u0430\u043d\u0438\u043c\u0430\u0442\u044c \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u043c\u043d\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438, \u043c\u044b \u0438\u0441\u043a\u0430\u043b\u0438 \u0441\u043f\u043e\u0441\u043e\u0431\u044b \u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u0438\u0445 \u0435\u0449\u0435 \u0431\u043e\u043b\u044c\u0448\u0435. \u041f\u043e\u0434 \u043a\u0430\u0442\u043e\u043c \u044f \u043f\u043e\u0434\u0435\u043b\u044e\u0441\u044c \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u043c, \u043a \u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443 \u043c\u044b \u0432 \u0438\u0442\u043e\u0433\u0435 \u043f\u0440\u0438\u0448\u043b\u0438. <\/p>\n<p>  \u0421\u0435\u0439\u0447\u0430\u0441 \u0443 \u043d\u0430\u0441 \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0442\u0435\u0441\u0442\u043e\u0432 \u0432 \u0440\u0430\u0437\u043d\u044b\u0445 \u0434\u0436\u043e\u0431\u0430\u0445 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c <code>shard=x\/y<\/code>, \u0430 \u043e\u0431\u0449\u0438\u0439 \u0440\u0435\u043f\u043e\u0440\u0442 \u043c\u044b \u043d\u0430\u0443\u0447\u0438\u043b\u0438\u0441\u044c \u0441\u043a\u043b\u0435\u0438\u0432\u0430\u0442\u044c \u0438\u0437 \u043e\u0442\u0447\u0435\u0442\u043e\u0432 \u0440\u0430\u0437\u043d\u044b\u0445 \u043f\u0440\u043e\u0433\u043e\u043d\u043e\u0432. \u0425\u043e\u0442\u0435\u043b \u0431\u044b \u043e\u0431\u0441\u0443\u0434\u0438\u0442\u044c \u044d\u0442\u043e \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u0432 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f\u0445. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u0432\u044b \u0440\u0435\u0448\u0430\u0435\u0442\u0435 \u043f\u043e\u0434\u043e\u0431\u043d\u0443\u044e \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443 \u0438\u043d\u0430\u0447\u0435. \u0412\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u043e\u043f\u0438\u0441\u0430\u043b \u0432 \u0432\u0438\u0434\u0435 \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u0438 \u043d\u0430 \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u043c \u0441\u0442\u0435\u043d\u0434\u0435, \u0442\u0430\u043a \u0447\u0442\u043e \u0441\u043c\u043e\u0436\u0435\u0442\u0435 \u043b\u0435\u0433\u043a\u043e \u043f\u043e\u0432\u0442\u043e\u0440\u0438\u0442\u044c \u0435\u0433\u043e \u0432 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0445 \u0446\u0435\u043b\u044f\u0445. <\/p>\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-356519","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/356519","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=356519"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/356519\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=356519"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=356519"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=356519"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}