{"id":159,"date":"2023-11-24T14:33:57","date_gmt":"2023-03-10T16:00:24","guid":{"rendered":"https:\/\/www.silicloud.com\/zh\/blog\/index.php\/2023\/11\/30\/%e5%a6%82%e4%bd%95%e4%bd%bf%e7%94%a8playwright%e5%92%8cdocker%e8%bf%90%e8%a1%8c%e7%ab%af%e5%88%b0%e7%ab%af%e6%b5%8b%e8%af%95\/"},"modified":"2025-08-01T01:39:14","modified_gmt":"2025-07-31T17:39:14","slug":"%e5%a6%82%e4%bd%95%e4%bd%bf%e7%94%a8playwright%e5%92%8cdocker%e8%bf%90%e8%a1%8c%e7%ab%af%e5%88%b0%e7%ab%af%e6%b5%8b%e8%af%95","status":"publish","type":"post","link":"https:\/\/www.silicloud.com\/zh\/blog\/%e5%a6%82%e4%bd%95%e4%bd%bf%e7%94%a8playwright%e5%92%8cdocker%e8%bf%90%e8%a1%8c%e7%ab%af%e5%88%b0%e7%ab%af%e6%b5%8b%e8%af%95\/","title":{"rendered":"Playwright\u4e0eDocker\uff1a\u9ad8\u6548\u8fd0\u884c\u7aef\u5230\u7aef\u6d4b\u8bd5\u7684\u7ec8\u6781\u6307\u5357"},"content":{"rendered":"<h3>\u4ecb\u7ecd<\/p>\n<p>Playwright\u662f\u4e00\u4e2a\u51fa\u8272\u7684\u5de5\u5177\uff0c\u7528\u4e8e\u8de8\u6d4f\u89c8\u5668\u7684\u7aef\u5230\u7aef\u6d4b\u8bd5\uff0c\u5305\u62ecChromium\u3001Firefox\u548cWebkit\u3002\u7531\u4e8eWebkit\u662fSafari\u6d4f\u89c8\u5668\u7684\u6838\u5fc3\uff0cPlaywright\u7684\u8de8\u6d4f\u89c8\u5668\u529f\u80fd\u4f7f\u5176\u6210\u4e3a\u6d4b\u8bd5Web\u5e94\u7528\u7a0b\u5e8f\u7684\u4e0d\u9519\u9009\u62e9\u3002Playwright\u5177\u6709\u4e0e\u6d4f\u89c8\u5668\u7684\u81ea\u52a8\u652f\u6301\u4ea4\u4e92\u7684\u529f\u80fd\uff0c\u56e0\u6b64\u60a8\u65e0\u9700\u624b\u52a8\u5b89\u88c5\u7f51\u7edc\u9a71\u52a8\u7a0b\u5e8f\uff0c\u5e76\u4e14\u5b83\u652f\u6301\u591a\u79cd\u7f16\u7a0b\u8bed\u8a00\uff0c\u5982Java\u3001Python\u548cNodeJS\u3002Playwright\u7684\u7075\u6d3b\u6027\u610f\u5473\u7740\u5b83\u53ef\u4ee5\u7528\u4f5c\u7f51\u7edc\u6293\u53d6\u5de5\u5177\u6216\u7528\u4e8e\u7aef\u5230\u7aef\u6d4b\u8bd5\uff0c\u4ee5\u786e\u4fdd\u8f6f\u4ef6\u6ee1\u8db3\u5176\u8981\u6c42\u3002<\/p>\n<p>\u8981\u8fd0\u884cPlaywright\uff0c\u60a8\u9700\u8981\u4e00\u4e2a\u9002\u5f53\u7684\u73af\u5883\uff0c\u6bd4\u5982NodeJS\u8fd0\u884c\u65f6\u3001Playwright\u6838\u5fc3\u6846\u67b6\u6216Playwright\u6d4b\u8bd5\u8fd0\u884c\u5668\u3002\u60a8\u7684\u64cd\u4f5c\u7cfb\u7edf\u53ef\u80fd\u9700\u8981\u4f9d\u8d56\u9879\u6765\u652f\u6301Playwright\u3002Docker\u662f\u4e00\u4e2a\u5f00\u6e90\u7684\u5bb9\u5668\u5316\u5e73\u53f0\uff0c\u53ef\u4ee5\u4e3a\u60a8\u63d0\u4f9bPlaywright\u73af\u5883\uff0c\u8fd9\u6837\u60a8\u5c31\u4e0d\u9700\u8981\u4e3a\u4e0d\u540c\u7684\u64cd\u4f5c\u7cfb\u7edf\u521b\u5efa\u591a\u4e2a\u73af\u5883\u4e86\u3002<\/p>\n<p>\u5728\u672c\u6559\u7a0b\u4e2d\uff0c\u60a8\u5c06\u8bbe\u7f6e\u4e00\u4e2a\u73af\u5883\u6765\u4f7f\u7528Typescript\u548cPlaywright\u8fdb\u884c\u7aef\u5230\u7aef\u6d4b\u8bd5\uff0c\u5e76\u7f16\u5199\u548c\u6267\u884c\u6d4b\u8bd5\uff0c\u4ee5\u591a\u79cd\u5f62\u5f0f\u5bfc\u51fa\u6d4b\u8bd5\u62a5\u544a\uff0c\u5e76\u4f7f\u7528Docker\u90e8\u7f72\u6d4b\u8bd5\u3002\u901a\u8fc7\u672c\u6559\u7a0b\u7684\u6700\u540e\uff0c\u60a8\u5c06\u80fd\u591f\u4f7f\u7528Playwright\u8fdb\u884c\u81ea\u52a8\u5316\u6d4b\u8bd5\uff0c\u5e76\u5c06\u60a8\u7684\u6d4b\u8bd5\u96c6\u6210\u5230\u4f7f\u7528Docker\u5c01\u88c5\u7684\u73b0\u6709CI\/CD\u6d41\u6c34\u7ebf\u4e2d\u3002<\/p>\n<h2>\u5148\u51b3\u6761\u4ef6<\/p>\n<p>\u4e3a\u4e86\u8ddf\u968f\u672c\u6559\u7a0b\uff0c\u60a8\u5c06\u9700\u8981\uff1a<\/p>\n<ul class=\"post-ul\">\n<li>One Ubuntu 20.04 server with a sudo-enabled account set up by following the Ubuntu 20.04 initial server setup guide. You need a sudo-enabled account to install NodeJS and Docker on your server.<\/li>\n<li>Node.js set up on your server. If you are on Ubuntu 22.04, install the latest version of Node.js in How To Install Node.js on Ubuntu 20.04. For other operating systems, see the How to Install Node.js and Create a Local Development Environment series.<\/li>\n<li>Docker installed on your server, which you can set up by following Steps 1-4 in How To Install and Use Docker on Ubuntu 20.04. In Step 4, you will run docker run hello-world to ensure that Docker is properly installed and ready to use.<\/li>\n<li>Familiarity with end-to-end testing for web applications.<\/li>\n<li>Familiarity with Typescript for writing the test. If you would like to learn more about TypeScript, you can review the How To Code in TypeScript tutorial series.<\/li>\n<li>(Optional) Visual Studio Code, which has robust features support such as code navigation and compiler error warning when working in Typescript. This tutorial uses nano throughout.<\/li>\n<\/ul>\n<h2>\u7b2c\u4e00\u6b65 &#8211; \u51c6\u5907\u73af\u5883<\/p>\n<p>\u5728\u5b9e\u65bd\u7aef\u5230\u7aef\u6d4b\u8bd5\u4e4b\u524d\uff0c\u60a8\u5fc5\u987b\u51c6\u5907\u597dPlaywright\u9879\u76ee\u73af\u5883\u3002<\/p>\n<p>\u9996\u5148\uff0c\u4e3a\u8fd9\u4e2a\u9879\u76ee\u521b\u5efa\u4e00\u4e2a\u6587\u4ef6\u5939\u3002<\/p>\n<pre class=\"post-pre\"><code><ol><li data-prefix=\"$\"><span class=\"token function\">mkdir<\/span> playwright-with-docker\r\n<\/li><\/ol>\r\n<\/code><\/pre>\n<p>\u79fb\u52a8\u5230\u65b0\u6587\u4ef6\u5939\u4e2d\u3002<\/p>\n<pre class=\"post-pre\"><code><ol><li data-prefix=\"$\"><span class=\"token builtin class-name\">cd<\/span> playwright-with-docker\r\n<\/li><\/ol>\r\n<\/code><\/pre>\n<p>\u7136\u540e\u521d\u59cb\u5316\u4e00\u4e2a\u65b0\u7684\u8282\u70b9\u73af\u5883\u3002<\/p>\n<pre class=\"post-pre\"><code><ol><li data-prefix=\"$\"><span class=\"token function\">npm<\/span> init\r\n<\/li><\/ol>\r\n<\/code><\/pre>\n<p>\u60a8\u5c06\u88ab\u8981\u6c42\u63d0\u4f9b\u65b0\u9879\u76ee\u7684\u4fe1\u606f\uff0c\u5982\u9879\u76ee\u540d\u79f0\u3001\u7248\u672c\u3001\u5e94\u7528\u7a0b\u5e8f\u5165\u53e3\u4ee5\u53ca\u6d4b\u8bd5\u547d\u4ee4\u3002<\/p>\n<p>\u60a8\u5c06\u88ab\u63d0\u793a\u8f93\u5165\u4e0e\u65b0\u9879\u76ee\u76f8\u5173\u7684\u4ee5\u4e0b\u63d0\u793a\u7684\u7b54\u6848\u3002<\/p>\n<pre class=\"post-pre\"><code><div class=\"secondary-code-label\" title=\"Output\">Outputpackage name: (playwright-docker)\r\nversion: (1.0.0)\r\ndescription:\r\nentry point: (index.js)\r\ntest command:\r\ngit repository:\r\nkeywords:\r\nauthor:\r\nlicense: (ISC)\r\n<\/code><\/pre>\n<p>\u4f60\u4f1a\u770b\u5230\u7c7b\u4f3c\u8fd9\u6837\u7684\u7ed3\u679c<\/p>\n<pre class=\"post-pre\"><code><div class=\"secondary-code-label\" title=\"Output\">OutputThis utility will walk you through creating a package.json file.\r\nIt only covers the most common items, and tries to guess sensible defaults.\r\n\r\nSee `npm help init` for definitive documentation on these fields\r\nand exactly what they do.\r\n\r\nUse `npm install &lt;pkg&gt;` afterward to install a package and\r\nsave it as a dependency in the package.json file.\r\n\r\nPress ^C at any time to quit.\r\npackage name: (test) playwright-docker\r\nversion: (1.0.0)\r\ndescription: A project for using playwright for end-to-end testing purpose with docker for deployment\r\nentry point: (index.js)\r\ntest command:\r\ngit repository:\r\nkeywords:\r\nauthor: \r\nlicense: (ISC)\r\nAbout to write to \/<mark>your-path<\/mark>\/test\/package.json:\r\n\r\n{\r\n  \"name\": \"playwright-docker\",\r\n  \"version\": \"1.0.0\",\r\n  \"description\": \"A project for using playwright for end-to-end testing purpose with docker for deployment\",\r\n  \"main\": \"index.js\",\r\n  \"scripts\": {\r\n  \"test\": \"echo \\\"Error: no test specified\\\" &amp;&amp; exit 1\"\r\n  },\r\n  \"author\": \r\n  \"license\": \"ISC\"\r\n}\r\n\r\n\r\nIs this OK? (yes) yes\r\n<\/code><\/pre>\n<p>\u5728\u6dfb\u52a0\u5fc5\u8981\u7684\u4fe1\u606f\u4e4b\u540e\uff0c\u8f93\u5165\u201c\u662f\u201d\u6216\u6309\u56de\u8f66\u952e\u4ee5\u786e\u8ba4package.json\u6587\u4ef6\u7684\u8bbe\u7f6e\u3002<\/p>\n<p>\u63a5\u4e0b\u6765\uff0c\u4e3a\u9879\u76ee\u5b89\u88c5\u6240\u9700\u7684\u4f9d\u8d56\u9879\u3002<\/p>\n<pre class=\"post-pre\"><code><ol><li data-prefix=\"$\"><span class=\"token function\">npm<\/span> <span class=\"token function\">install<\/span> --save-dev playwright\r\n<\/li><li data-prefix=\"$\"><span class=\"token function\">npm<\/span> <span class=\"token function\">install<\/span> --save-dev typescript\r\n<\/li><\/ol>\r\n<\/code><\/pre>\n<p>\u8fd9\u4e9b\u547d\u4ee4\u4f1a\u5728\u793a\u4f8b\u9879\u76ee\u4e2d\u5b89\u88c5Playwright\u548cTypeScript\u3002\u4f7f\u7528&#8211;save-dev\u6807\u5fd7\u6765\u5b89\u88c5\u5bf9\u5e94\u7528\u7a0b\u5e8f\u8fd0\u884c\u5e76\u975e\u5fc5\u9700\u7684\u4f9d\u8d56\u9879\u3002<\/p>\n<p>\u63a5\u4e0b\u6765\uff0c\u5b89\u88c5 Node.JS \u7684\u7c7b\u578b\u5b9a\u4e49\u3002<\/p>\n<pre class=\"post-pre\"><code><ol><li data-prefix=\"$\"><span class=\"token function\">npm<\/span> <span class=\"token function\">install<\/span> --save-dev @types\/node\r\n<\/li><\/ol>\r\n<\/code><\/pre>\n<p>\u63a5\u4e0b\u6765\uff0c\u5b89\u88c5\u4e00\u4e2a\u7528\u4e8e\u5904\u7406TOML\u914d\u7f6e\u6587\u4ef6\u7684\u5e93\u3002<\/p>\n<pre class=\"post-pre\"><code><ol><li data-prefix=\"$\"><span class=\"token function\">npm<\/span> <span class=\"token function\">install<\/span> --save-dev toml\r\n<\/li><\/ol>\r\n<\/code><\/pre>\n<p>TOML\u662f\u5e94\u7528\u7a0b\u5e8f\u914d\u7f6e\u4e2d\u4f7f\u7528\u7684\u6587\u4ef6\u7c7b\u578b\u4e4b\u4e00\u3002.toml\u6587\u4ef6\u662f\u53ef\u8bfb\u7684\uff0c\u5141\u8bb8\u5e94\u7528\u7a0b\u5e8f\u5728\u4e0d\u5148\u8bfb\u53d6\u6587\u4ef6\u7684\u60c5\u51b5\u4e0b\u66f4\u65b0\u5176\u5185\u5bb9\u3002<\/p>\n<p>\u63a5\u4e0b\u6765\uff0c\u4e3a\u4e3b\u673a\u7cfb\u7edf\u5b89\u88c5Playwright\u6240\u4f9d\u8d56\u7684\u5e93\u3002<\/p>\n<pre class=\"post-pre\"><code><ol><li data-prefix=\"$\">npx playwright install-deps\r\n<\/li><\/ol>\r\n<\/code><\/pre>\n<p>\u5f53\u63d0\u793a\u65f6\uff0c\u8bf7\u8f93\u5165\u60a8\u7684sudo\u5bc6\u7801\u3002<\/p>\n<div class=\"post-conf-note\">\n<p class=\"post-note\">\n<p class=\"post-conf-desc\">Note<\/p>\n<div>\n<p>\u8bf7\u6ce8\u610f\uff1a\u5982\u679c\u60a8\u6536\u5230\u4e00\u6761\u6d88\u606f\uff0c\u8981\u6c42\u60a8\u5c06Node\u7248\u672c\u5347\u7ea7\u5230\u66f4\u9ad8\u7684\u7248\u672c\uff0c\u4f8b\u5982\uff1a<\/p>\n<p>\u8f93\u51fa\uff1a\u60a8\u6b63\u5728\u8fd0\u884cNode.js 10.19.0\u3002<\/p>\n<p>Playwright\u9700\u8981Node.js 12\u6216\u66f4\u9ad8\u7248\u672c\u3002<\/p>\n<p>\u8bf7\u66f4\u65b0\u60a8\u7684Node.js\u7248\u672c\u3002<\/p>\n<p>\u60a8\u53ef\u4ee5\u4f7f\u7528\u4ee5\u4e0b\u547d\u4ee4\u8fdb\u884c\u5347\u7ea7\uff1a<\/p>\n<pre class=\"post-pre\"><code>sudo npm cache clean -f\r\nsudo npm install -g n\r\nsudo n stable\r\n<\/code><\/pre>\n<p><code>npm cache clean -f<\/code> \u5c06\u5f3a\u5236\u6e05\u9664\u6240\u6709\u7f13\u5b58\uff0c\u800c <code>npm install -g n<\/code> \u548c <code>n stable<\/code> \u5c06\u5728\u60a8\u7684\u670d\u52a1\u5668\u4e0a\u5168\u5c40\u5b89\u88c5Node.js\u7684\u7a33\u5b9a\u7248\u672c\u3002\u8fd0\u884c\u8fd9\u4e9b\u547d\u4ee4\u540e\uff0c\u8bf7\u91cd\u65b0\u542f\u52a8\u670d\u52a1\u5668\u3002<\/p>\n<p>\u63a5\u4e0b\u6765\uff0c\u5b89\u88c5 Playwright \u6d4b\u8bd5\u8fd0\u884c\u5668\uff0c\u8fd9\u5c06\u5728\u672c\u6559\u7a0b\u7684\u540e\u7eed\u6b65\u9aa4\u4e2d\u7528\u5230\u3002<\/p>\n<pre class=\"post-pre\"><code><ol><li data-prefix=\"$\"><span class=\"token function\">npm<\/span> <span class=\"token function\">install<\/span> --save-dev @playwright\/test\r\n<\/li><\/ol>\r\n<\/code><\/pre>\n<p>\u6700\u540e\uff0c\u4e3a Playwright \u5b89\u88c5\u652f\u6301\u7684\u6d4f\u89c8\u5668\u3002<\/p>\n<pre class=\"post-pre\"><code><ol><li data-prefix=\"$\">npx playwright <span class=\"token function\">install<\/span>\r\n<\/li><\/ol>\r\n<\/code><\/pre>\n<p>\u901a\u8fc7\u8fd9\u4e2a\u547d\u4ee4\uff0c\u60a8\u53ef\u4ee5\u4f7f\u7528\u591a\u4e2a\u6d4f\u89c8\u5668\u6765\u8fd0\u884c\u60a8\u7684\u6d4b\u8bd5\u3002<\/p>\n<p>\u4e3a\u4e86\u51c6\u5907 TypeScript \u914d\u7f6e\u6587\u4ef6\uff0c\u8bf7\u4f7f\u7528 nano \u6216\u60a8\u559c\u6b22\u7684\u6587\u672c\u7f16\u8f91\u5668\u6253\u5f00 <code>tsconfig.json<\/code>\u3002<\/p>\n<pre class=\"post-pre\"><code><ol><li data-prefix=\"$\"><span class=\"token function\">sudo<\/span> <span class=\"token function\">nano<\/span> tsconfig.json\r\n<\/li><\/ol>\r\n<\/code><\/pre>\n<p>\u5f53\u524d\u6587\u4ef6\u4e3a\u7a7a\u3002\u8981\u4e3a\u8be5\u9879\u76ee\u66f4\u65b0\u6587\u4ef6\uff0c\u8bf7\u6dfb\u52a0\u4ee5\u4e0b\u4ee3\u7801\uff1a<\/p>\n<p><code>tsconfig.json<\/code> \u662f TypeScript \u914d\u7f6e\u6587\u4ef6\u7684\u7f29\u5199\u3002<\/p>\n<pre class=\"post-pre\"><code>{\r\n  \"compilerOptions\": {\r\n    \"strict\": true,\r\n    \"module\": \"commonjs\"\r\n  },\r\n  \"include\": [\"tests\"]\r\n}\r\n<\/code><\/pre>\n<p>\u4e00\u4e2a <code>tsconfig.json<\/code> \u6587\u4ef6\u544a\u8bc9 NodeJS \u8fd0\u884c\u65f6\u5f53\u524d\u76ee\u5f55\u662f\u4e00\u4e2a TypeScript \u9879\u76ee\u3002<code>compilerOptions<\/code> \u5217\u8868\u5217\u51fa\u4e86 NodeJS \u7f16\u8bd1\u8be5\u9879\u76ee\u6240\u9700\u7684\u6761\u4ef6\u3002<code>module<\/code> \u544a\u8bc9\u7f16\u8bd1\u5668\u5728\u7f16\u8bd1\u4e3a JavaScript \u65f6\u4f7f\u7528\u54ea\u79cd\u6a21\u5757\u8bed\u6cd5\u3002\u5c06 <code>strict<\/code> \u5b57\u6bb5\u8bbe\u7f6e\u4e3a <code>true<\/code> \u5c06\u542f\u7528\u5bf9 TypeScript \u4ee3\u7801\u7684\u7c7b\u578b\u68c0\u67e5\uff0c\u786e\u4fdd\u7c7b\u578b\u4e0e\u53d8\u91cf\u6216\u65b9\u6cd5\u7684\u6570\u636e\u503c\u5339\u914d\u3002<code>include<\/code> \u5c06\u663e\u793a\u5e94\u7528\u7a0b\u5e8f\u4e2d\u5305\u542b\u7684\u6587\u4ef6\u540d\u79f0\u6216\u6a21\u5f0f\u7684\u5217\u8868\u3002\u5728\u6b64\u60c5\u51b5\u4e0b\uff0c\u5e94\u7528\u7a0b\u5e8f\u5e94\u8be5\u5305\u62ec <code>tests<\/code> \u76ee\u5f55\u4e2d\u7684\u6240\u6709\u6587\u4ef6\u3002<\/p>\n<p>\u5b8c\u6210\u540e\u4fdd\u5b58\u5e76\u5173\u95ed\u6587\u4ef6\u3002<\/p>\n<p>\u5728\u8bbe\u7f6e\u597d\u73af\u5883\u4e4b\u540e\uff0c\u60a8\u73b0\u5728\u53ef\u4ee5\u5f00\u59cb\u6784\u5efa\u60a8\u7684\u6d4b\u8bd5\u4e86\u3002<\/p>\n<h2>\u7b2c\u4e8c\u6b65 \u2014 \u7f16\u5199\u6d4b\u8bd5<\/h2>\n<p>\u901a\u8fc7\u7b2c\u4e00\u6b65\u51c6\u5907\u7684 Playwright \u6d4b\u8bd5\u73af\u5883\uff0c\u60a8\u73b0\u5728\u5c06\u7f16\u5199\u4e09\u4e2a\u4e0e Silicon Cloud vServers \u9875\u9762\u76f8\u5173\u7684\u793a\u4f8b\u6d4b\u8bd5\u3002<\/p>\n<p>\u60a8\u5c06\u6784\u5efa\u7684 TypeScript \u6d4b\u8bd5\u5c06\u9a8c\u8bc1\u4ee5\u4e0b\u4e09\u9879\u5185\u5bb9\uff1a<\/p>\n<ul class=\"post-ul\">\n<li>\u9a8c\u8bc1\u6ce8\u518c Silicon Cloud \u8d26\u6237\u7684\u4e09\u79cd\u9009\u9879\uff1a\u4f7f\u7528\u7535\u5b50\u90ae\u4ef6\u6ce8\u518c\u3001\u4f7f\u7528 Google \u6ce8\u518c\u3001\u4f7f\u7528 Github \u6ce8\u518c\u3002<\/li>\n<li>\u9a8c\u8bc1 Silicon Cloud \u652f\u6301\u4e24\u79cd\u7c7b\u578b\u7684\u5957\u9910\uff1a\u57fa\u7840\u7248\u548c\u9ad8\u7ea7\u7248\u3002<\/li>\n<li>\u9a8c\u8bc1\u6709\u56db\u79cd\u57fa\u672c\u865a\u62df\u673a\u6210\u672c\uff1a1 CPU\u30012 CPU\u30014 CPU\u30018 CPU\u3002<\/li>\n<\/ul>\n<p>\u5c3d\u7ba1\u60a8\u53ef\u4ee5\u5728\u540c\u4e00\u4e2a\u6d4b\u8bd5\u6587\u4ef6\u4e2d\u8fdb\u884c\u6240\u6709\u4e09\u4e2a\u6d4b\u8bd5\uff0c\u4f46\u662f\u672c\u6559\u7a0b\u5c06\u4f7f\u7528\u4e09\u4e2a\u5355\u72ec\u7684\u6587\u4ef6\uff0c\u56e0\u4e3a\u6bcf\u4e2a\u6d4b\u8bd5\u90fd\u6709\u4e0d\u540c\u7684\u76ee\u7684\u3002<\/p>\n<p>\u521b\u5efa\u4e00\u4e2a\u540d\u4e3a <code>tests<\/code> \u7684\u65b0\u76ee\u5f55\uff0c\u7528\u4e8e\u5b58\u653e\u6240\u6709\u7684\u6d4b\u8bd5\u6587\u4ef6\u3002<\/p>\n<pre class=\"post-pre\"><code><span class=\"token function\">mkdir<\/span> tests\r\n<\/code><\/pre>\n<p>\u7136\u540e\u5bfc\u822a\u5230\u6d4b\u8bd5\u76ee\u5f55\uff1a<\/p>\n<pre class=\"post-pre\"><code><span class=\"token builtin class-name\">cd<\/span> tests\r\n<\/code><\/pre>\n<p>\u56e0\u4e3a\u60a8\u5c06\u8fdb\u884c\u4e09\u6b21\u5177\u6709\u4e0d\u540c\u76ee\u7684\u7684\u6d4b\u8bd5\uff0c\u6240\u4ee5\u60a8\u5c06\u5728\u6b64\u6b65\u9aa4\u4e2d\u521b\u5efa\u4e09\u4e2a\u5206\u522b\u4f4d\u4e8e\u9879\u76ee\u7684 <code>tests<\/code> \u76ee\u5f55\u5185\u7684\u72ec\u7acb\u6d4b\u8bd5\u6587\u4ef6\u3002<\/p>\n<ul class=\"post-ul\">\n<li><code>signUpMethods.spec.ts<\/code> \u5c06\u5b9e\u73b0\u9a8c\u8bc1\u7528\u6237\u6ce8\u518c\u652f\u6301\u65b9\u6cd5\u6570\u91cf\u7684\u6d4b\u8bd5\u3002<\/li>\n<li><code>multiplePackages.spec.ts<\/code> \u5c06\u5b9e\u73b0\u9a8c\u8bc1\u5ba2\u6237\u53ef\u9009\u62e9\u5957\u9910\u6570\u91cf\u7684\u6d4b\u8bd5\u3002<\/li>\n<li><code>pricingComparison.spec.ts<\/code> \u5c06\u9a8c\u8bc1\u57fa\u672c\u865a\u62df\u673a\u6210\u672c\u6570\u91cf\u7684\u6d4b\u8bd5\u3002<\/li>\n<\/ul>\n<div class=\"post-conf-note\">\n<p class=\"post-note\">\n<p class=\"post-conf-desc\">\u6ce8\u610f\uff1a<\/p>\n<\/div>\n<p>\u6d4b\u8bd5\u6587\u4ef6\u7684\u9ed8\u8ba4\u683c\u5f0f\u5c06\u4e3a <code>*.spec.ts<\/code>\uff08TypeScript \u9879\u76ee\uff09\u6216 <code>*.spec.js<\/code>\uff08JavaScript \u9879\u76ee\uff09\u3002<\/p>\n<p>\u6d4b\u8bd5\u7684\u914d\u7f6e\u6587\u4ef6\u5c06\u4f1a\u88ab\u547d\u540d\u4e3a <code>configTypes.ts<\/code>\uff0c\u5e76\u4e14\u4e5f\u4f1a\u88ab\u653e\u7f6e\u5728 <code>tests<\/code> \u76ee\u5f55\u4e2d\u3002\u5728\u8fd9\u4e2a\u6587\u4ef6\u4e2d\uff0c\u60a8\u5c06\u4f1a\u5b9a\u4e49\u7528\u4e8e\u4e0e\u591a\u4e2a\u6d4f\u89c8\u5668\u53ca\u5176\u9875\u9762\u8fdb\u884c\u4ea4\u4e92\u7684\u5168\u5c40\u53d8\u91cf\u3002\u60a8\u8fd8\u5c06\u4f1a\u5b9a\u4e49\u4e00\u4e9b\u6d4b\u8bd5\u4e2d\u4f7f\u7528\u7684\u914d\u7f6e\u6570\u503c\uff0c\u6bd4\u5982\u88ab\u6d4b\u8bd5\u5e94\u7528\u7684 URL\u3002\u672c\u6559\u7a0b\u5c06\u4f1a\u4f7f\u7528 <code>DIGITAL_OCEAN_URL<\/code> \u4f5c\u4e3a\u88ab\u6d4b\u8bd5\u7684 URL\u3002<\/p>\n<p>\u521b\u5efa <code>configTypes.ts<\/code> \u6587\u4ef6<\/p>\n<pre class=\"post-pre\"><code><ol><li data-prefix=\"$\"><span class=\"token function\">nano<\/span> configTypes.ts\r\n<\/li><\/ol>\r\n<\/code><\/pre>\n<p>\u5c06\u4ee5\u4e0b\u4ee3\u7801\u6dfb\u52a0\u5230\u5f53\u524d\u4e3a\u7a7a\u7684 <code>configTypes.ts<\/code> \u6587\u4ef6\u4e2d\u3002<\/p>\n<p><code>configTypes.ts<\/code> \u7684\u542b\u4e49\u662f\u201c\u914d\u7f6e\u7c7b\u578b\u6587\u4ef6\u201d\u3002<\/p>\n<\/div>\n<p>\u8fd9\u662f\u6587\u7ae0\u300a\u5982\u4f55\u4f7f\u7528Playwright\u548cDocker\u8fd0\u884c\u7aef\u5230\u7aef\u6d4b\u8bd5\u300b\u7684\u7b2c3\u90e8\u5206\uff08\u517110\u90e8\u5206\uff09\u3002<\/p>\n<pre class=\"post-pre\"><code><span class=\"token keyword\">import<\/span> <span class=\"token punctuation\">{<\/span> Browser<span class=\"token punctuation\">,<\/span> Page <span class=\"token punctuation\">}<\/span> <span class=\"token keyword\">from<\/span> <span class=\"token string\">\"playwright\"<\/span><span class=\"token punctuation\">;<\/span>\r\n\r\n<span class=\"token keyword\">import<\/span> fs <span class=\"token keyword\">from<\/span> <span class=\"token string\">'fs'<\/span><span class=\"token punctuation\">;<\/span>\r\n<span class=\"token keyword\">import<\/span> toml <span class=\"token keyword\">from<\/span> <span class=\"token string\">'toml'<\/span><span class=\"token punctuation\">;<\/span>\r\n<span class=\"token keyword\">const<\/span> config <span class=\"token operator\">=<\/span> toml<span class=\"token punctuation\">.<\/span><span class=\"token function\">parse<\/span><span class=\"token punctuation\">(<\/span>fs<span class=\"token punctuation\">.<\/span><span class=\"token function\">readFileSync<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">'.\/config.toml'<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">'utf-8'<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span>\r\n\r\n<span class=\"token keyword\">declare<\/span> global <span class=\"token punctuation\">{<\/span>\r\n  <span class=\"token keyword\">const<\/span> page<span class=\"token operator\">:<\/span> Page<span class=\"token punctuation\">;<\/span>\r\n  <span class=\"token keyword\">const<\/span> browser<span class=\"token operator\">:<\/span> Browser<span class=\"token punctuation\">;<\/span>\r\n  <span class=\"token keyword\">const<\/span> browserName<span class=\"token operator\">:<\/span> <span class=\"token builtin\">string<\/span><span class=\"token punctuation\">;<\/span>\r\n<span class=\"token punctuation\">}<\/span>\r\n\r\n<span class=\"token keyword\">export<\/span> <span class=\"token keyword\">default<\/span> <span class=\"token punctuation\">{<\/span>\r\n  <span class=\"token constant\">DIGITAL_OCEAN_URL<\/span><span class=\"token operator\">:<\/span> config<span class=\"token punctuation\">.<\/span>digital_ocean_url <span class=\"token operator\">??<\/span> <span class=\"token string\">''<\/span><span class=\"token punctuation\">,<\/span>\r\n  <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">;<\/span>\r\n<\/code><\/pre>\n<p>\u9996\u5148\uff0c\u4ece\u9879\u76ee\u4e3b\u76ee\u5f55\u4e0b\u7684<code>.\/config.toml<\/code>\u6587\u4ef6\u4e2d\u5bfc\u5165\u51fd\u6570\u4ee5\u8bfb\u53d6\u914d\u7f6e\u5185\u5bb9\u3002<\/p>\n<p>\u5728\u7aef\u5230\u7aef\u6d4b\u8bd5\u4e2d\uff0c\u60a8\u9700\u8981\u58f0\u660e\u7528\u4e8e\u521d\u59cb\u5316\u9875\u9762\u548c\u6d4f\u89c8\u5668\u5b9e\u4f8b\u7684\u5168\u5c40\u53d8\u91cf\uff0c\u5305\u62ec<code>page<\/code>\u3001<code>browser<\/code>\u548c<code>browserName<\/code>\u3002<\/p>\n<p>\u6700\u540e\uff0c\u60a8\u4f7f\u7528<code>digital_ocean_url<\/code>\u952e\u4ece<code>.\/config.toml<\/code>\u4e2d\u8bfb\u53d6\u7684\u503c\u5bfc\u51fa<code>DIGITAL_OCEAN_URL<\/code>\uff0c\u4ee5\u4fbf\u7a0d\u540e\u5728\u6d4b\u8bd5\u4e2d\u4f7f\u7528\u8fd9\u4e2a\u7f51\u5740\u3002<\/p>\n<p>\u5b8c\u6210\u540e\u4fdd\u5b58\u5e76\u5173\u95ed\u6587\u4ef6\u3002<\/p>\n<p>\u5bf9\u4e8e\u7b2c\u4e00\u6b21\u6d4b\u8bd5\uff0c\u8bf7\u4f7f\u7528nano\u6216\u60a8\u504f\u7231\u7684\u6587\u672c\u7f16\u8f91\u5668\u521b\u5efa\u5e76\u6253\u5f00<code>signUpMethods.spec.ts<\/code>\u6587\u4ef6\u3002<\/p>\n<pre class=\"post-pre\"><code><ol><li data-prefix=\"$\"><span class=\"token function\">nano<\/span> signUpMethods.spec.ts\r\n<\/li><\/ol>\r\n<\/code><\/pre>\n<p>\u5c06\u4ee5\u4e0b\u4ee3\u7801\u6dfb\u52a0\u5230\u7a7a\u6587\u4ef6\u4e2d\uff1a<\/p>\n<p><code>signUpMethods.spec.ts<\/code>\u7684\u4e2d\u6587\u672c\u5730\u5316\u5185\u5bb9\u3002<\/p>\n<p>\u8fd9\u662f\u6587\u7ae0\u300a\u5982\u4f55\u4f7f\u7528Playwright\u548cDocker\u8fd0\u884c\u7aef\u5230\u7aef\u6d4b\u8bd5\u300b\u7684\u7b2c4\u90e8\u5206\uff08\u517110\u90e8\u5206\uff09\u3002<\/p>\n<pre class=\"post-pre\"><code><span class=\"token keyword\">import<\/span> endpoint <span class=\"token keyword\">from<\/span> <span class=\"token string\">\".\/configTypes\"<\/span>\r\n<span class=\"token keyword\">import<\/span> <span class=\"token punctuation\">{<\/span> test<span class=\"token punctuation\">,<\/span> expect <span class=\"token punctuation\">}<\/span> <span class=\"token keyword\">from<\/span> <span class=\"token string\">'@playwright\/test'<\/span>\r\n\r\n<span class=\"token function\">test<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">\"\u671f\u671b\u6ce8\u518c\u9009\u9879\u67093\u4e2a\"<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token keyword\">async<\/span> <span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">{<\/span> page <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token operator\">=&gt;<\/span> <span class=\"token punctuation\">{<\/span>\r\n\r\n  <span class=\"token comment\">\/\/ \u5bfc\u822a\u5230Silicon Cloud\u7f51\u9875\u7684vServers\u4ea7\u54c1\u9875\u9762<\/span>\r\n  <span class=\"token keyword\">await<\/span> page<span class=\"token punctuation\">.<\/span><span class=\"token function\">goto<\/span><span class=\"token punctuation\">(<\/span>endpoint<span class=\"token punctuation\">.<\/span><span class=\"token constant\">DIGITAL_OCEAN_URL<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span>\r\n\r\n  <span class=\"token comment\">\/\/ \u7b49\u5f85\u9875\u9762\u52a0\u8f7d\u5b8c\u6210<\/span>\r\n  <span class=\"token keyword\">await<\/span> page<span class=\"token punctuation\">.<\/span><span class=\"token function\">waitForLoadState<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">'networkidle'<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span>\r\n\r\n  <span class=\"token comment\">\/\/ \u83b7\u53d6\u6ce8\u518c\u9009\u9879\u7684\u6570\u91cf<\/span>\r\n  <span class=\"token keyword\">const<\/span> number_subscriptions_allowed <span class=\"token operator\">=<\/span> <span class=\"token keyword\">await<\/span> page<span class=\"token punctuation\">.<\/span><span class=\"token function\">locator<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">'.SignupButtonsStyles__ButtonContainer-sc-yg5bly-0 &gt; a'<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span><span class=\"token function\">count<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span>\r\n\r\n  <span class=\"token comment\">\/\/ \u9a8c\u8bc1\u6570\u91cf\u662f\u5426\u7b49\u4e8e3<\/span>\r\n  <span class=\"token function\">expect<\/span><span class=\"token punctuation\">(<\/span>number_subscriptions_allowed<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span><span class=\"token function\">toBe<\/span><span class=\"token punctuation\">(<\/span><span class=\"token number\">3<\/span><span class=\"token punctuation\">)<\/span>\r\n<span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span>\r\n<\/code><\/pre>\n<p><code>signUpMethods.spec.ts<\/code> \u6587\u4ef6\u5305\u542b\u4e86\u6d4b\u8bd5\u4ee3\u7801\uff0c\u7528\u4e8e\u8bc4\u4f30vServers\u9875\u9762\u7684\u6ce8\u518c\u9009\u9879\u662f\u5426\u4e3a\u4e09\u4e2a\u3002\u5728\u524d\u4e24\u884c\uff0c\u60a8\u5bfc\u5165\u4e86 <code>test<\/code> \u548c <code>expect<\/code> \u65b9\u6cd5\u3002<\/p>\n<p>\u6d4b\u8bd5\u53ef\u4ee5\u5f02\u6b65\u6216\u540c\u6b65\u7f16\u5199\u3002\u4ee5\u5f02\u6b65\u65b9\u5f0f\u7f16\u5199\u6d4b\u8bd5\u53ef\u4ee5\u4f18\u5316\u6d4b\u8bd5\u901f\u5ea6\uff0c\u56e0\u4e3a\u60a8\u65e0\u9700\u7b49\u5f85\u6d4b\u8bd5\u7684\u6bcf\u4e2a\u6b65\u9aa4\u5b8c\u6210\u540e\u624d\u80fd\u6267\u884c\u4e0b\u4e00\u6b65\u3002\u5f53\u9700\u8981\u7b49\u5f85\u6b65\u9aa4\u5b8c\u6210\u540e\u518d\u8fdb\u884c\u4e0b\u4e00\u6b65\u64cd\u4f5c\u65f6\uff0c\u53ef\u4ee5\u4f7f\u7528\u201c<code>await<\/code>\u201d\u5173\u952e\u5b57\u3002\u7531\u4e8e\u8fd9\u91cc\u7684\u6b65\u9aa4\u6d89\u53ca\u7f51\u7edc\u4ea4\u4e92\uff0c\u6240\u4ee5\u5728\u6267\u884c\u64cd\u4f5c\u4e4b\u524d\u9700\u8981\u786e\u4fdd\u7528\u6237\u754c\u9762\u4e2d\u7684\u6bcf\u4e2a\u5143\u7d20\u90fd\u5df2\u663e\u793a\u51fa\u6765\uff0c\u8fd9\u5c31\u662f\u4e3a\u4ec0\u4e48\u5728\u8c03\u7528\u6bcf\u4e2a\u64cd\u4f5c\u4e4b\u524d\u90fd\u8981\u5305\u542b\u201c<code>await<\/code>\u201d\u65b9\u6cd5\u7684\u539f\u56e0\u3002<\/p>\n<p>\u6d4b\u8bd5\u5728 <code>test<\/code> \u5757\u4e2d\u5b9a\u4e49\uff0c\u5e76\u5305\u542b\u56db\u4e2a\u52a8\u4f5c\u3002\u7b2c\u4e00\u4e2a <code>await<\/code> \u5173\u952e\u5b57\u4f7f\u7528 <code>page.goto()<\/code> \u51fd\u6570\u544a\u8bc9\u6d4b\u8bd5\u5bfc\u822a\u5230\u5728 <code>configTypes.ts<\/code> \u6587\u4ef6\u4e2d\u5b9a\u4e49\u7684 <code>DIGITAL_OCEAN_URL<\/code>\u3002\u5c06\u5168\u5c40\u53d8\u91cf <code>page<\/code> \u653e\u5728 <code>async<\/code> \u58f0\u660e\u4e2d\uff0c\u8fd9\u6837\u60a8\u5c31\u53ef\u4ee5\u5728\u6574\u4e2a\u6d4b\u8bd5\u4e2d\u4f7f\u7528 <code>page<\/code> \u5b9e\u4f8b\uff0c\u800c\u65e0\u9700\u521d\u59cb\u5316\u5b83\u3002<\/p>\n<p>\u7b2c\u4e8c\u4e2a <code>await<\/code> \u5173\u952e\u5b57\u544a\u8bc9\u6d4b\u8bd5\u7b49\u5f85\u9875\u9762\u52a0\u8f7d\uff0c\u4f7f\u7528 <code>page.waitForLoadState()<\/code> \u51fd\u6570\u3002\u5982\u679c\u5b58\u5728\u672a\u5b8c\u6210\u7684API\u8c03\u7528\uff0c\u9875\u9762\u4e0a\u53ef\u80fd\u4f1a\u6709\u4e0d\u53ef\u7528\u7684\u5143\u7d20\uff0c\u5bfc\u81f4\u6d4b\u8bd5\u65e0\u6cd5\u627e\u5230\u8be5\u5143\u7d20\u800c\u5931\u8d25\u3002<\/p>\n<p>\u60a8\u4f7f\u7528 <code>page.locator()<\/code> \u51fd\u6570\u6765\u5b9a\u4e49 <code>number_subscriptions_allowed<\/code>\uff0c\u4ee5\u67e5\u627e\u6ce8\u518c\u9009\u9879\u7684\u6570\u91cf\u3002\u60a8\u901a\u8fc7CSS\u9009\u62e9\u5668\uff08\u5728\u672c\u4f8b\u4e2d\u4e3a\u6ce8\u518c\u6309\u94ae\uff09\u627e\u5230\u4e86\u6ce8\u518c\u9009\u9879\u7ec4\u4ef6\uff0c\u8fd9\u4f7f\u60a8\u80fd\u591f\u83b7\u53d6\u5b83\u5305\u542b\u7684\u5b50\u5143\u7d20\u7684\u6570\u91cf\u3002<\/p>\n<p>\u6700\u540e\uff0c\u4e00\u4e2a <code>expect<\/code> \u65b9\u6cd5\u5c06\u4f1a\u9a8c\u8bc1 <code>page.locator()<\/code> \u627e\u5230\u7684\u9009\u9879\u6570\u91cf\u4e0e\u9884\u671f\u8f93\u51fa\u7684 <code>3<\/code> \u76f8\u5339\u914d\u3002<\/p>\n<p>\u4fdd\u5b58\u5e76\u5173\u95ed\u6587\u4ef6\u3002<\/p>\n<p>\u63a5\u4e0b\u6765\uff0c\u60a8\u5c06\u7f16\u5199\u7b2c\u4e8c\u4e2a\u6d4b\u8bd5\u3002\u8bf7\u521b\u5efa\u5e76\u6253\u5f00 <code>multiplePackages.spec.ts<\/code> \u6587\u4ef6\u3002<\/p>\n<pre class=\"post-pre\"><code><ol><li data-prefix=\"$\"><span class=\"token function\">nano<\/span> multiplePackages.spec.ts\r\n<\/li><\/ol>\r\n<\/code><\/pre>\n<p>\u5728\u7a7a\u6587\u4ef6\u4e2d\uff0c\u6dfb\u52a0\u4ee5\u4e0b\u4ee3\u7801\uff1a<\/p>\n<p><code>multiplePackages.spec.ts<\/code><\/p>\n<pre class=\"post-pre\"><code><span class=\"token keyword\">import<\/span> endpoint <span class=\"token keyword\">from<\/span> <span class=\"token string\">\".\/configTypes\"<\/span>\r\n<span class=\"token keyword\">import<\/span> <span class=\"token punctuation\">{<\/span> test<span class=\"token punctuation\">,<\/span> expect <span class=\"token punctuation\">}<\/span> <span class=\"token keyword\">from<\/span> <span class=\"token string\">'@playwright\/test'<\/span>\r\n\r\n<span class=\"token function\">test<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">\"\u671f\u671b\u8ba2\u9605\u5957\u9910\u6570\u91cf\u4e3a3\"<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token keyword\">async<\/span> <span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">{<\/span> page <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token operator\">=&gt;<\/span> <span class=\"token punctuation\">{<\/span>\r\n\r\n  <span class=\"token comment\">\/\/ \u8bbf\u95ee Silicon Cloud \u7f51\u7ad9\u7684 vServers \u4ea7\u54c1\u9875\u9762<\/span>\r\n  <span class=\"token keyword\">await<\/span> page<span class=\"token punctuation\">.<\/span><span class=\"token function\">goto<\/span><span class=\"token punctuation\">(<\/span>endpoint<span class=\"token punctuation\">.<\/span><span class=\"token constant\">DIGITAL_OCEAN_URL<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span>\r\n\r\n  <span class=\"token comment\">\/\/ \u7b49\u5f85\u9875\u9762\u52a0\u8f7d\u5b8c\u6210<\/span>\r\n  <span class=\"token keyword\">await<\/span> page<span class=\"token punctuation\">.<\/span><span class=\"token function\">waitForLoadState<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">'networkidle'<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span>\r\n\r\n  <span class=\"token comment\">\/\/ \u83b7\u53d6\u8ba2\u9605\u5957\u9910\u7684\u6570\u91cf\uff08\u5e94\u4e3a2\u4e2a\uff1a\u57fa\u7840\u7248\u548c\u9ad8\u7ea7\u7248\uff09<\/span>\r\n  <span class=\"token keyword\">const<\/span> number_subscriptions_allowed <span class=\"token operator\">=<\/span> <span class=\"token keyword\">await<\/span> page<span class=\"token punctuation\">.<\/span><span class=\"token function\">locator<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">'.CPUInfoStyles__StyledLeftCpuInfo-sc-ooo7a2-4 &gt; div'<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span><span class=\"token function\">count<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span>\r\n\r\n  <span class=\"token comment\">\/\/ \u9a8c\u8bc1\u6570\u91cf\u662f\u5426\u7b49\u4e8e2<\/span>\r\n  <span class=\"token function\">expect<\/span><span class=\"token punctuation\">(<\/span>number_subscriptions_allowed<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span><span class=\"token function\">toBe<\/span><span class=\"token punctuation\">(<\/span><span class=\"token number\">2<\/span><span class=\"token punctuation\">)<\/span>\r\n<span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span>\r\n<\/code><\/pre>\n<p>\u8fd9\u90e8\u5206\u662f\u6587\u7ae0\u300a\u5982\u4f55\u4f7f\u7528Playwright\u548cDocker\u8fd0\u884c\u7aef\u5230\u7aef\u6d4b\u8bd5\u300b\u7684\u7b2c5\u8282\uff08\u517110\u8282\uff09\u3002<\/p>\n<p>\u4e0e <code>signUpMethods.spec.ts<\/code> \u6587\u4ef6\u7c7b\u4f3c\uff0c\u60a8\u5c06\u4ece Playwright \u4f9d\u8d56\u4e2d\u5bfc\u5165\u6d4b\u8bd5\u914d\u7f6e\u548c\u6d4b\u8bd5\u51fd\u6570\u3002<\/p>\n<p>\u5728\u6b64\u6d4b\u8bd5\u4e2d\uff0c\u60a8\u9996\u5148\u4f7f\u7528 <code>page.goto()<\/code> \u8bbf\u95ee <code>DIGITAL_OCEAN_URL<\/code>\u3002\u7136\u540e\uff0c\u60a8\u4f7f\u7528 <code>page.waitForLoadState('networkidle')<\/code> \u7b49\u5f85\u9875\u9762\u5b8c\u6210\u6240\u6709\u7f51\u7edc\u8bf7\u6c42\uff0c\u786e\u4fdd\u9875\u9762\u5b8c\u5168\u52a0\u8f7d\u3002<\/p>\n<p>\u63a5\u7740\uff0c\u60a8\u901a\u8fc7\u5b9a\u4f4d\u5668 <code>.CPUInfoStyles__StyledLeftCpuInfo-sc-ooo7a2-4 &gt; div<\/code> \u627e\u5230\u7f51\u9875\u4e2d\u8ba2\u9605\u7ec4\u4ef6\u7684\u5b50\u5143\u7d20\uff0c\u5e76\u5c06\u5176\u6570\u91cf\u5b58\u50a8\u5728 <code>number_subscriptions_allowed<\/code> \u53d8\u91cf\u4e2d\u3002<\/p>\n<p>\u6700\u540e\uff0c\u60a8\u4f7f\u7528 <code>expect(number_subscriptions_allowed).toBe(2)<\/code> \u5c06 <code>number_subscriptions_allowed<\/code> \u7684\u503c\u4e0e\u671f\u671b\u7684\u8f93\u51fa\u503c <code>2<\/code> \u8fdb\u884c\u6bd4\u8f83\uff0c\u4ee5\u9a8c\u8bc1\u8ba2\u9605\u5957\u9910\u7684\u6570\u91cf\u662f\u5426\u6b63\u786e\u3002<\/p>\n<p>\u5b8c\u6210\u4e0a\u8ff0\u64cd\u4f5c\u540e\uff0c\u8bf7\u4fdd\u5b58\u5e76\u5173\u95ed\u5f53\u524d\u6587\u4ef6\u3002<\/p>\n<p>\u7136\u540e\uff0c\u901a\u8fc7\u4ee5\u4e0b\u547d\u4ee4\u521b\u5efa\u5e76\u6253\u5f00 <code>pricingComparison.spec.ts<\/code> \u6587\u4ef6\uff0c\u7528\u4e8e\u5b9a\u4e49\u7b2c\u4e09\u4e2a\u6d4b\u8bd5\uff1a<\/p>\n<pre class=\"post-pre\"><code><ol><li data-prefix=\"$\"><span class=\"token function\">nano<\/span> pricingComparison.spec.ts\r\n<\/li><\/ol>\r\n<\/code><\/pre>\n<p>\u5c06\u4ee5\u4e0b\u4ee3\u7801\u6dfb\u52a0\u5230\u65b0\u521b\u5efa\u7684\u7a7a\u6587\u4ef6\u4e2d\uff1a<\/p>\n<pre class=\"post-pre\"><code><span class=\"token keyword\">import<\/span> endpoint <span class=\"token keyword\">from<\/span> <span class=\"token string\">\".\/configTypes\"<\/span>\r\n<span class=\"token keyword\">import<\/span> <span class=\"token punctuation\">{<\/span> test<span class=\"token punctuation\">,<\/span> expect <span class=\"token punctuation\">}<\/span> <span class=\"token keyword\">from<\/span> <span class=\"token string\">'@playwright\/test'<\/span>\r\n\r\n<span class=\"token function\">test<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">\"\u9884\u671f\u8ba2\u9605\u67093\u4e2a\u5957\u9910\"<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token keyword\">async<\/span> <span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">{<\/span> page <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token operator\">=&gt;<\/span> <span class=\"token punctuation\">{<\/span>\r\n\r\n  <span class=\"token comment\">\/\/ \u8bbf\u95eeSilicon Cloud\u7f51\u9875\u7684vServers\u4ea7\u54c1\u9875\u9762<\/span>\r\n  <span class=\"token keyword\">await<\/span> page<span class=\"token punctuation\">.<\/span><span class=\"token function\">goto<\/span><span class=\"token punctuation\">(<\/span>endpoint<span class=\"token punctuation\">.<\/span><span class=\"token constant\">DIGITAL_OCEAN_URL<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span>\r\n\r\n  <span class=\"token comment\">\/\/ \u7b49\u5f85\u9875\u9762\u52a0\u8f7d\u5b8c\u6210<\/span>\r\n  <span class=\"token keyword\">await<\/span> page<span class=\"token punctuation\">.<\/span><span class=\"token function\">waitForLoadState<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">'networkidle'<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span>\r\n\r\n  <span class=\"token comment\">\/\/ \u83b7\u53d6\u57fa\u672c\u865a\u62df\u673a\u914d\u7f6e\uff081 CPU, 2 CPU, 4 CPU, 8 CPU\uff09\u7684\u6570\u91cf<\/span>\r\n  <span class=\"token keyword\">const<\/span> number_subscriptions_allowed <span class=\"token operator\">=<\/span> <span class=\"token keyword\">await<\/span> page<span class=\"token punctuation\">.<\/span><span class=\"token function\">locator<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">'.PricingComparisonToolStyles__StyledCpuSelector-sc-1k0sndv-7 &gt; button'<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span><span class=\"token function\">count<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span>\r\n\r\n  <span class=\"token comment\">\/\/ \u9a8c\u8bc1\u6570\u91cf\u662f\u5426\u7b49\u4e8e4<\/span>\r\n  <span class=\"token function\">expect<\/span><span class=\"token punctuation\">(<\/span>number_subscriptions_allowed<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span><span class=\"token function\">toBe<\/span><span class=\"token punctuation\">(<\/span><span class=\"token number\">4<\/span><span class=\"token punctuation\">)<\/span>\r\n<span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span>\r\n<\/code><\/pre>\n<p>\u8be5\u6d4b\u8bd5\u4e2d\u7684\u5f02\u6b65\u51fd\u6570\u4f7f\u7528\u4e86\u4e0e\u524d\u51e0\u4e2a\u6d4b\u8bd5\u76f8\u540c\u7684 <code>page.goto()<\/code> URL \u548c <code>page.waitForLoadState()<\/code> \u65b9\u6cd5\u3002\u7531\u4e8e\u8be5\u6d4b\u8bd5\u4e0e vServers \u9875\u9762\u4e0a\u7684\u8ba2\u9605\u5957\u9910\u76f8\u5173\u8054\uff0c\u4ee3\u7801\u5757\u7684\u540e\u534a\u90e8\u5206\u8bbe\u7f6e\u4e86\u8be5\u6d4b\u8bd5\u3002<\/p>\n<p>\u5bf9\u4e8e\u6b64\u6d4b\u8bd5\uff0c\u60a8\u9700\u8981\u83b7\u53d6\u5b9a\u4ef7\u9009\u9879\u7ec4\u4ef6\u7684\u5b50\u5143\u7d20\u6570\u91cf\uff0c\u5e76\u5c06\u8be5\u503c\u5b58\u50a8\u5728 <code>number_subscriptions_allowed<\/code> \u53d8\u91cf\u4e2d\u3002\u60a8\u5c06\u9a8c\u8bc1 <code>number_subscriptions_allowed<\/code> \u7684\u503c\u5fc5\u987b\u7b49\u4e8e 4\uff08\u5f53\u524d\u652f\u6301\u7684\u8ba2\u9605\u6570\u91cf\uff09\u3002<\/p>\n<p>\u4fdd\u5b58\u5e76\u5173\u95ed\u6587\u4ef6\u3002<\/p>\n<p>\u5728\u60a8\u7684\u6d4b\u8bd5\u4e2d\uff0c\u60a8\u4f7f\u7528\u4e86\u6765\u81ea <code>configTypes.ts<\/code> \u7684 <code>DIGITAL_OCEAN_URL<\/code>\uff0c\u5e76\u4e14 <code>configTypes.ts<\/code> \u4ece <code>.\/config.toml<\/code> \u6587\u4ef6\u4e2d\u8bfb\u53d6\u4e86 <code>digital_ocean_url<\/code> \u7684\u503c\u3002<\/p>\n<p>\u73b0\u5728\uff0c\u60a8\u5c06\u5728\u9879\u76ee\u7684\u4e3b\u76ee\u5f55\u4e2d\u521b\u5efa <code>config.toml<\/code> \u6587\u4ef6\u3002\u5bfc\u822a\u5230\u4e3b\u76ee\u5f55\uff1a<\/p>\n<pre class=\"post-pre\"><code><ol><li data-prefix=\"$\"><span class=\"token builtin class-name\">cd<\/span> <span class=\"token punctuation\">..<\/span>\r\n<\/li><\/ol>\r\n<\/code><\/pre>\n<p>\u7136\u540e\u521b\u5efa <code>config.toml<\/code> \u6587\u4ef6\uff1a<\/p>\n<pre class=\"post-pre\"><code><ol><li data-prefix=\"$\"><span class=\"token function\">nano<\/span> config.toml\r\n<\/li><\/ol>\r\n<\/code><\/pre>\n<p>\u5c06\u4ee5\u4e0b\u5185\u5bb9\u590d\u5236\u5230 <code>config.toml<\/code> \u6587\u4ef6\u4e2d\uff1a<\/p>\n<div>config.toml \u914d\u7f6e\u6587\u4ef6<\/p>\n<pre class=\"post-pre\"><code><span class=\"token key property\">digital_ocean_url<\/span><span class=\"token punctuation\">=<\/span><span class=\"token string\">\"https:\/\/www.digitalocean.com\/products\/droplets\"<\/span>\r\n<\/code><\/pre>\n<p>\u4fdd\u5b58\u5e76\u5173\u95ed\u6587\u4ef6\u3002<\/p>\n<p>\u73b0\u5728\uff0c\u9879\u76ee\u7684\u76ee\u5f55\u6811\u5c06\u5982\u4e0b\u6240\u793a\uff1a<\/p>\n<div><img decoding=\"async\" src=\"https:\/\/cdn.silicloud.com\/blog-img\/blog\/img\/65646e19a4b2f92e6c728142\/109-0.png\" class=\"post-images\" alt=\"\u663e\u793a\u9879\u76ee\u4e2d\u6240\u6709\u6587\u4ef6\u7684\u76ee\u5f55\u6811\uff0c\u5305\u62ec\u5728\u6587\u4ef6\u5939\u4e2d\u521b\u5efa\u7684\u4e09\u4e2a TypeScript \u6587\u4ef6\" title=\"\"><\/div>\n<p>\u5728\u8fd9\u4e00\u6b65\u4e2d\uff0c\u60a8\u7f16\u5199\u4e86\u4e09\u4e2a\u5c06\u8981\u4f7f\u7528\u7684\u6d4b\u8bd5\u3002\u60a8\u8fd8\u5b9a\u4e49\u4e86\u6d4b\u8bd5\u6240\u4f9d\u8d56\u7684 <code>config.toml<\/code> \u6587\u4ef6\u3002\u60a8\u5c06\u5728\u4e0b\u4e00\u6b65\u6267\u884c\u8fd9\u4e9b\u6d4b\u8bd5\u3002<\/p>\n<h2>\u6b65\u9aa4\u4e09 &#8211; \u6267\u884c\u6d4b\u8bd5<\/h2>\n<p>\u53ef\u4ee5\u4f7f\u7528 Playwright \u6d4b\u8bd5\u8fd0\u884c\u5668\u5728\u547d\u4ee4\u884c\u754c\u9762\u4e0a\u8fdb\u884c\u591a\u79cd\u64cd\u4f5c\uff0c\u4f8b\u5982\u8fd0\u884c\u6240\u6709\u6d4f\u89c8\u5668\u7684\u6240\u6709\u6d4b\u8bd5\u3001\u7981\u7528\u5e76\u884c\u5904\u7406\u3001\u8fd0\u884c\u4e00\u7ec4\u6d4b\u8bd5\u6587\u4ef6\u4ee5\u53ca\u5728\u8c03\u8bd5\u6a21\u5f0f\u4e0b\u8fd0\u884c\u7b49\u7b49\u3002\u5728\u8fd9\u4e00\u6b65\u4e2d\uff0c\u60a8\u5c06\u4f7f\u7528\u6240\u6709\u6d4f\u89c8\u5668\u6765\u8fd0\u884c\u6d4b\u8bd5\u3002<\/p>\n<p>\u9996\u5148\uff0c\u8fd0\u884c\u6b64\u547d\u4ee4\uff1a<\/p>\n<pre class=\"post-pre\"><code><ol><li data-prefix=\"$\">npx playwright <span class=\"token builtin class-name\">test<\/span> <span class=\"token parameter variable\">--browser<\/span><span class=\"token operator\">=<\/span>all\r\n<\/li><\/ol>\r\n<\/code><\/pre>\n<p>\u60a8\u5e94\u8be5\u80fd\u591f\u770b\u5230\u5982\u4e0b\u6d4b\u8bd5\u7ed3\u679c\uff1a<\/p>\n<pre class=\"post-pre\"><code><div class=\"secondary-code-label\" title=\"\u8f93\u51fa\">\u8f93\u51fa\r\n<\/code><\/pre>\n<p>\u8fd9\u662f\u6587\u7ae0\u300a\u5982\u4f55\u4f7f\u7528Playwright\u548cDocker\u8fd0\u884c\u7aef\u5230\u7aef\u6d4b\u8bd5\u300b\u7684\u7b2c7\u90e8\u5206\uff08\u517110\u90e8\u5206\uff09\u3002<\/p>\n<pre class=\"post-pre\"><code>Running 9 tests using 1 worker\r\n\r\n  \u2713  [chromium] \u203a tests\/multiplePackages.spec.ts:4:1 \u203a Expect to have 3 packages for subscription (6s)\r\n  \u2713  [chromium] \u203a tests\/pricingComparison.spec.ts:4:1 \u203a Expect to have 3 packages for subscription (4s)\r\n  \u2713  [chromium] \u203a tests\/signUpMethods.spec.ts:4:1 \u203a Expect to have 3 options for signing up (3s)\r\n  \u2713  [firefox] \u203a tests\/multiplePackages.spec.ts:4:1 \u203a Expect to have 3 packages for subscription (9s)\r\n  \u2713  [firefox] \u203a tests\/pricingComparison.spec.ts:4:1 \u203a Expect to have 3 packages for subscription (5s)\r\n  \u2713  [firefox] \u203a tests\/signUpMethods.spec.ts:4:1 \u203a Expect to have 3 options for signing up (7s)\r\n  \u2713  [webkit] \u203a tests\/multiplePackages.spec.ts:4:1 \u203a Expect to have 3 packages for subscription (7s)\r\n  \u2713  [webkit] \u203a tests\/pricingComparison.spec.ts:4:1 \u203a Expect to have 3 packages for subscription (6s)\r\n  \u2713  [webkit] \u203a tests\/signUpMethods.spec.ts:4:1 \u203a Expect to have 3 options for signing up (6s)\r\n\r\n\r\n  9 passed (1m)\r\n<\/code><\/pre>\n<p>\u5bf9\u52fe\u8868\u793a\u5728\u4e09\u79cd\u6d4f\u89c8\u5668\uff08Chromium\u3001Firefox \u548c Webkit\uff09\u4e2d\u6240\u6709\u6d4b\u8bd5\u90fd\u5df2\u901a\u8fc7\u3002<\/p>\n<p>\u5de5\u4f5c\u8fdb\u7a0b\uff08worker\uff09\u6570\u91cf\u5c06\u53d6\u51b3\u4e8e\u5f53\u524d\u670d\u52a1\u5668\u4f7f\u7528\u7684\u6838\u5fc3\u6570\u91cf\u548c\u6d4b\u8bd5\u7684\u5f53\u524d\u914d\u7f6e\u3002\u60a8\u53ef\u4ee5\u901a\u8fc7\u5728<code>playwright.config.ts<\/code>\u6587\u4ef6\u4e2d\u8bbe\u7f6e\u5de5\u4f5c\u8fdb\u7a0b\u503c\u6765\u9650\u5236\u5176\u6570\u91cf\u3002\u6709\u5173\u6d4b\u8bd5\u914d\u7f6e\u7684\u66f4\u591a\u4fe1\u606f\uff0c\u8bf7\u9605\u8bfbPlaywright\u4ea7\u54c1\u6587\u6863\u3002<\/p>\n<p>Playwright\u6d4b\u8bd5\u8fd0\u884c\u5668\u4e3a\u6d4b\u8bd5\u62a5\u544a\u63d0\u4f9b\u4e86\u51e0\u4e2a\u9009\u9879\uff0c\u53ef\u4ee5\u96c6\u6210\u5230Jenkins\u6216CircleCI\u7b49CI\u5de5\u5177\u4e2d\u3002\u6709\u5173\u6d4b\u8bd5\u62a5\u544a\u7684\u66f4\u591a\u4fe1\u606f\uff0c\u8bf7\u53c2\u9605Playwright\u6d4b\u8bd5\u62a5\u544a\u6587\u6863\u9875\u9762\u3002<\/p>\n<p>\u5728\u672c\u6559\u7a0b\u4e2d\uff0c\u60a8\u5c06\u4f7f\u7528HTML\u62a5\u544a\u6587\u4ef6\u8fd0\u884c\u6d4b\u8bd5\uff0c\u8be5\u6587\u4ef6\u6bd4\u5728CLI\u4e2d\u67e5\u770b\u6d4b\u8bd5\u66f4\u6613\u8bfb\u3002<\/p>\n<p>\u8fd0\u884c\u6b64\u547d\u4ee4\u4ee5\u751f\u6210HTML\u6d4b\u8bd5\u62a5\u544a\uff1a<\/p>\n<pre class=\"post-pre\"><code><ol><li data-prefix=\"$\">npx playwright <span class=\"token builtin class-name\">test<\/span> <span class=\"token parameter variable\">--browser<\/span><span class=\"token operator\">=<\/span>all <span class=\"token parameter variable\">--reporter<\/span><span class=\"token operator\">=<\/span>html\r\n<\/li><\/ol>\r\n<\/code><\/pre>\n<p>\u60a8\u4f1a\u770b\u5230\u8fd9\u6837\u7684\u7ed3\u679c\uff1a<\/p>\n<pre class=\"post-pre\"><code><div class=\"secondary-code-label\" title=\"Output\">Output<\/div>Running 9 tests using 2 workers\r\n\r\n  9 passed (40s)\r\n\r\nTo open last HTML report run:\r\n\r\n  npx playwright show-report\r\n<\/code><\/pre>\n<p>\u8981\u67e5\u770bHTML\u62a5\u544a\uff0c\u8bf7\u8fd0\u884c\uff1a<\/p>\n<pre class=\"post-pre\"><code><ol><li data-prefix=\"$\">npx playwright show-report\r\n<\/li><\/ol>\r\n<\/code><\/pre>\n<p>\u60a8\u5c06\u4f1a\u770b\u5230\u8fd9\u6837\u7684\u8f93\u51fa\uff1a<\/p>\n<pre class=\"post-pre\"><code><div class=\"secondary-code-label\" title=\"Output\">Output<\/div>Serving HTML report at http:\/\/<mark>your_ip_address<\/mark>:9323. Press Ctrl+C to quit.\r\n<\/code><\/pre>\n<p>\u73b0\u5728\u60a8\u5e94\u8be5\u80fd\u591f\u901a\u8fc79323\u7aef\u53e3\u8bbf\u95ee\u60a8\u7684\u62a5\u544a\u4e86\u3002<\/p>\n<div class=\"post-conf-note\">\n<p class=\"post-note\">\n<p class=\"post-conf-desc\">\u6ce8\u610f\uff1a\u5982\u679c\u60a8\u662f\u8fdc\u7a0b\u8bbf\u95ee\u670d\u52a1\u5668\uff0c\u60a8\u9700\u8981\u5c06\u60a8\u7684\u8fdc\u7a0b\u670d\u52a1\u5668\u66b4\u9732\u7ed9\u5f53\u524d\u672c\u5730\u673a\u5668\uff0c\u624d\u80fd\u5728\u672c\u5730\u6d4f\u89c8\u5668\u4e2d\u67e5\u770b\u6d4b\u8bd5\u62a5\u544a\u3002\u5728\u60a8\u672c\u5730\u673a\u5668\u7684\u65b0\u7ec8\u7aef\u4f1a\u8bdd\u4e2d\u8fd0\u884c\u4ee5\u4e0b\u547d\u4ee4\uff1a<\/p>\n<pre><code>ssh -L 9323:localhost:9323 \u60a8\u7684\u975e\u6839\u7528\u6237@\u60a8\u7684\u670d\u52a1\u5668IP\r\n<\/code><\/pre>\n<p>SSH\u7aef\u53e3\u8f6c\u53d1\u5c06\u670d\u52a1\u5668\u7aef\u53e3\u8f6c\u53d1\u5230\u672c\u5730\u7aef\u53e3\u3002<code>-L 9323:localhost:9323<\/code> \u90e8\u5206\u8868\u793a\u672c\u5730\u673a\u5668\u4e0a\u76849323\u7aef\u53e3\u5c06\u8f6c\u53d1\u5230\u8fdc\u7a0b\u670d\u52a1\u5668\u7684\u540c\u4e00\u7aef\u53e3\u3002<\/p>\n<p>\u73b0\u5728\u60a8\u5e94\u8be5\u80fd\u591f\u901a\u8fc7\u5728\u672c\u5730\u673a\u5668\u4e0a\u7684\u6d4f\u89c8\u5668\u4e2d\u5bfc\u822a\u5230 <code>http:\/\/localhost:9323<\/code> \u6765\u67e5\u770b\u6d4b\u8bd5\u62a5\u544a\u3002<\/p>\n<\/div>\n<p>\u5f53\u62a5\u544a\u52a0\u8f7d\u5230\u6d4f\u89c8\u5668\u4e2d\u65f6\uff0c\u60a8\u4f1a\u53d1\u73b0\u6bcf\u4e2a\u6d4b\u8bd5\u90fd\u5728\u4e09\u4e2a\u6d4f\u89c8\u5668\u4e0a\u8fd0\u884c\uff1aChromium\u3001Firefox\u548cWebkit\u3002\u60a8\u5c06\u4e86\u89e3\u6bcf\u4e2a\u6d4f\u89c8\u5668\u4e0a\u6bcf\u4e2a\u6d4b\u8bd5\u8fd0\u884c\u6240\u82b1\u8d39\u7684\u65f6\u95f4\uff0c\u4ee5\u53ca\u6574\u4e2a\u6d4b\u8bd5\u6240\u82b1\u8d39\u7684\u65f6\u95f4\u3002<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/cdn.silicloud.com\/blog-img\/blog\/img\/65646e19a4b2f92e6c728142\/132-0.png\" class=\"post-images\" alt=\"Screencapture of the overall report, which is separated into the three different tests where each test displays the overall time the test took to run, as well as how long each browser's test took to run\" title=\"\"><\/p>\n<p>\u70b9\u51fb\u62a5\u544a\u540d\u79f0\u4ee5\u67e5\u770b\u8be6\u7ec6\u4fe1\u606f\u3002<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/cdn.silicloud.com\/blog-img\/blog\/img\/65646e19a4b2f92e6c728142\/134-0.png\" class=\"post-images\" alt=\"Screencapture of the report details for the test, which displays the length of time that each element of the test took\" title=\"\"><\/p>\n<p>\u5728\u8be6\u7ec6\u4fe1\u606f\u90e8\u5206\uff0c\u6d4b\u8bd5\u6267\u884c\u6b65\u9aa4\u9ed8\u8ba4\u4f1a\u5305\u62ecBefore Hooks\uff08\u524d\u7f6e\u94a9\u5b50\uff09\u548cAfter Hooks\uff08\u540e\u7f6e\u94a9\u5b50\uff09\u6b65\u9aa4\u3002Before Hooks\u90e8\u5206\u901a\u5e38\u7528\u4e8e\u521d\u59cb\u8bbe\u7f6e\uff0c\u4f8b\u5982\u767b\u5f55\u5230\u63a7\u5236\u53f0\u6216\u8bfb\u53d6\u6d4b\u8bd5\u6570\u636e\u3002\u5728\u6d4b\u8bd5\u6267\u884c\u4e4b\u540e\uff0cAfter Hooks\u90e8\u5206\u901a\u5e38\u4f1a\u6e05\u7406\u6d4b\u8bd5\u73af\u5883\u4e2d\u7684\u6d4b\u8bd5\u6570\u636e\u3002\u6bcf\u4e2a\u6b65\u9aa4\u90fd\u6709\u8be6\u7ec6\u7684\u8bf4\u660e\uff0c\u5305\u62ec\u4f7f\u7528<code>page.goto()<\/code>\u8bbf\u95eeURL\uff0c\u4f7f\u7528<code>page.waitForLoadState()<\/code>\u7b49\u5f85\u9875\u9762\u52a0\u8f7d\uff0c\u4f7f\u7528<code>locator.count()<\/code>\u8ba1\u7b97\u6ce8\u518c\u65b9\u6cd5\u7684\u6570\u91cf\uff0c\u5e76\u4f7f\u7528<code>expect.toBe<\/code>\u9a8c\u8bc1\u503c\u662f\u5426\u5339\u914d\u3002<\/p>\n<p>\u5728\u8fd9\u4e2a\u6b65\u9aa4\u4e2d\uff0c\u60a8\u8fd0\u884c\u4e86\u6240\u6709\u4e09\u4e2a\u6d4b\u8bd5\uff0c\u68c0\u67e5\u4e86\u5b83\u4eec\u7684\u901a\u8fc7\u72b6\u6001\uff0c\u5e76\u5728CLI\u548cHTML\u683c\u5f0f\u4e0b\u67e5\u770b\u4e86\u6d4b\u8bd5\u7ed3\u679c\u3002\u63a5\u4e0b\u6765\uff0c\u60a8\u5c06\u4f7f\u7528Docker\u81ea\u52a8\u5316\u8fd9\u4e9b\u6d4b\u8bd5\u3002<\/p>\n<h2>\u7b2c\u56db\u6b65 \u2014 \u4f7f\u7528Docker\u90e8\u7f72\u6d4b\u8bd5<\/h2>\n<p>\u5728\u5b9e\u65bd\u6d4b\u8bd5\u81ea\u52a8\u5316\u65f6\uff0c\u60a8\u53ef\u80fd\u4f1a\u9047\u5230\u73af\u5883\u95ee\u9898\u3002\u4e00\u4e9b\u6d4b\u8bd5\u5728\u6d4b\u8bd5\u5de5\u7a0b\u5e08\u7684\u672c\u5730\u673a\u5668\u4e0a\u6b63\u5e38\u8fd0\u884c\uff0c\u4f46\u5728\u96c6\u6210\u5230CI\/CD\u6d41\u7a0b\u4e2d\u65f6\u5931\u8d25\uff0c\u8fd9\u662f\u7531\u4e8e\u73af\u5883\u517c\u5bb9\u6027\u95ee\u9898\u9020\u6210\u7684\u3002\u4e3a\u4e86\u907f\u514d\u8fd9\u4e2a\u95ee\u9898\uff0c\u60a8\u53ef\u4ee5\u4f7f\u7528Docker\u5bb9\u5668\u6765\u8fd0\u884c\u81ea\u52a8\u5316\u6d4b\u8bd5\uff0c\u672c\u6b65\u9aa4\u5c06\u4e3a\u60a8\u8bbe\u7f6e\u3002\u5982\u679c\u4f7f\u7528Docker\u5728\u672c\u5730\u73af\u5883\u4e2d\u6d4b\u8bd5\u8fd0\u884c\u6b63\u5e38\uff0c\u90a3\u4e48\u5728CI\/CD\u6d41\u7a0b\u4e2d\u907f\u514d\u517c\u5bb9\u95ee\u9898\u7684\u53ef\u80fd\u6027\u5f88\u9ad8\u3002<\/p>\n<p>\u9996\u5148\uff0c\u60a8\u9700\u8981\u6253\u5f00 <code>package.json<\/code> \u6587\u4ef6\uff0c\u7136\u540e\u66f4\u65b0\u8be5\u6587\u4ef6\u4ee5\u6dfb\u52a0\u4e4b\u540e\u5728 Docker \u4e2d\u8fd0\u884c\u6240\u9700\u7684\u6d4b\u8bd5\u811a\u672c\u3002<\/p>\n<pre class=\"post-pre\"><code><ol><li data-prefix=\"$\"><span class=\"token function\">nano<\/span> package.json\r\n<\/li><\/ol>\r\n<\/code><\/pre>\n<p>\u5c06\u4e0b\u9762\u7684\u5185\u5bb9\u6dfb\u52a0\u5230<code>package.json<\/code>\u6587\u4ef6\u4e2d\u7684<code>scripts<\/code>\u90e8\u5206\u4e2d\uff1a<\/p>\n<p><code>package.json<\/code> \u6587\u4ef6<\/p>\n<pre class=\"post-pre\"><code>...\r\n <span class=\"token property\">\"scripts\"<\/span><span class=\"token operator\">:<\/span> <span class=\"token punctuation\">{<\/span>\r\n  <mark><span class=\"token property\">\"test\"<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">\"playwright test --browser=all\"<\/span><span class=\"token punctuation\">,<\/span><\/mark>\r\n  <mark><span class=\"token property\">\"test-html-report\"<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">\"playwright test --browser=all --reporter=html\"<\/span><span class=\"token punctuation\">,<\/span><\/mark>\r\n  <mark><span class=\"token property\">\"test-json-report\"<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">\"PLAYWRIGHT_JSON_OUTPUT_NAME=results.json playwright test --browser=chromium --reporter=json\"<\/span><\/mark>\r\n  <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">,<\/span>\r\n<\/code><\/pre>\n<p>\u5f53\u60a8\u9700\u8981\u5728HTML\u4e2d\u663e\u793a\u62a5\u544a\u5668\u8fd0\u884c\u6d4b\u8bd5\u65f6\uff0c\u5c06\u4f7f\u7528\u8fd9\u4e9b\u811a\u672c\u8fd0\u884c\u81ea\u5b9a\u4e49\u6d4b\u8bd5\uff0c\u800c\u4e0d\u662f\u8f93\u5165\u5b8c\u6574\u547d\u4ee4\u3002\u73b0\u5728\u60a8\u53ef\u4ee5\u8fd0\u884c\u4ee5\u4e0b\u547d\u4ee4\uff1a<\/p>\n<p>\u8fd9\u662f\u6587\u7ae0\u300a\u5982\u4f55\u4f7f\u7528Playwright\u548cDocker\u8fd0\u884c\u7aef\u5230\u7aef\u6d4b\u8bd5\u300b\u7684\u7b2c8\u90e8\u5206\uff08\u517110\u90e8\u5206\uff09\u3002<\/p>\n<p>\u5185\u5bb9\u7247\u6bb5\uff1a<\/p>\n<pre class=\"post-pre\"><code><ol><li><span class=\"token function\">npm<\/span> run test-html-report<\/li><\/ol><\/code><\/pre>\n<p>\u53d6\u800c\u4ee3\u4e4b\u7684\u662f\u5b8c\u6574\u7684\u547d\u4ee4\uff1a<\/p>\n<pre class=\"post-pre\"><code><ol><li>npx playwright <span class=\"token builtin class-name\">test<\/span> <span class=\"token parameter variable\">--browser<\/span><span class=\"token operator\">=<\/span>all <span class=\"token parameter variable\">--reporter<\/span><span class=\"token operator\">=<\/span>html<\/li><\/ol><\/code><\/pre>\n<p>\u4f60\u73b0\u5728\u7684<code>package.json<\/code>\u6587\u4ef6\u5c06\u4f1a\u662f\u8fd9\u6837\uff1a<\/p>\n<pre class=\"post-pre\"><code><span class=\"token punctuation\">{<\/span>\r\n  <span class=\"token property\">\"name\"<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">\"playwright-docker\"<\/span><span class=\"token punctuation\">,<\/span>\r\n  <span class=\"token property\">\"version\"<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">\"1.0.0\"<\/span><span class=\"token punctuation\">,<\/span>\r\n  <span class=\"token property\">\"description\"<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">\"\u4e00\u4e2a\u4f7f\u7528Playwright\u8fdb\u884c\u7aef\u5230\u7aef\u6d4b\u8bd5\u5e76\u7ed3\u5408Docker\u90e8\u7f72\u7684\u9879\u76ee\"<\/span><span class=\"token punctuation\">,<\/span>\r\n  <span class=\"token property\">\"main\"<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">\"index.js\"<\/span><span class=\"token punctuation\">,<\/span>\r\n  <span class=\"token property\">\"scripts\"<\/span><span class=\"token operator\">:<\/span> <span class=\"token punctuation\">{<\/span>\r\n  <span class=\"token property\">\"test\"<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">\"playwright test --browser=all\"<\/span><span class=\"token punctuation\">,<\/span>\r\n  <span class=\"token property\">\"test-html-report\"<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">\"playwright test --browser=all --reporter=html\"<\/span><span class=\"token punctuation\">,<\/span>\r\n  <span class=\"token property\">\"test-json-report\"<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">\"PLAYWRIGHT_JSON_OUTPUT_NAME=results.json playwright test --browser=chromium --reporter=json\"<\/span>\r\n  <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">,<\/span>\r\n  <span class=\"token property\">\"author\"<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">\"\"<\/span><span class=\"token punctuation\">,<\/span>\r\n  <span class=\"token property\">\"license\"<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">\"ISC\"<\/span><span class=\"token punctuation\">,<\/span>\r\n  <span class=\"token property\">\"devDependencies\"<\/span><span class=\"token operator\">:<\/span> <span class=\"token punctuation\">{<\/span>\r\n  <span class=\"token property\">\"@playwright\/test\"<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">\"^1.22.2\"<\/span><span class=\"token punctuation\">,<\/span>\r\n  <span class=\"token property\">\"@types\/node\"<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">\"^17.0.35\"<\/span><span class=\"token punctuation\">,<\/span>\r\n  <span class=\"token property\">\"playwright\"<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">\"^1.22.1\"<\/span><span class=\"token punctuation\">,<\/span>\r\n  <span class=\"token property\">\"toml\"<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">\"^3.0.0\"<\/span><span class=\"token punctuation\">,<\/span>\r\n  <span class=\"token property\">\"typescript\"<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">\"^4.6.4\"<\/span>\r\n  <span class=\"token punctuation\">}<\/span>\r\n<span class=\"token punctuation\">}<\/span>\r\n<\/code><\/pre>\n<p>\u4fdd\u5b58\u5e76\u5173\u95ed\u6587\u4ef6\u3002<\/p>\n<p>\u63a5\u4e0b\u6765\uff0c\u5728\u5f53\u524d\u76ee\u5f55\u4e0b\u521b\u5efa\u5e76\u6253\u5f00\u4e00\u4e2a<code>Dockerfile<\/code>\u6587\u4ef6\uff1a<\/p>\n<pre class=\"post-pre\"><code><ol><li><span class=\"token function\">nano<\/span> Dockerfile<\/li><\/ol><\/code><\/pre>\n<p>\u7136\u540e\u5c06\u4ee5\u4e0b\u5185\u5bb9\u6dfb\u52a0\u5230\u5176\u4e2d\uff1a<\/p>\n<div>Dockerfile-\u6784\u5efa\u6587\u4ef6<\/div>\n<p>\u8fd9\u662f\u6587\u7ae0\u300a\u5982\u4f55\u4f7f\u7528Playwright\u548cDocker\u8fd0\u884c\u7aef\u5230\u7aef\u6d4b\u8bd5\u300b\u7684\u7b2c9\u90e8\u5206\uff08\u517110\u90e8\u5206\uff09\u3002<\/p>\n<pre class=\"post-pre\"><code><span class=\"token comment\"># \u83b7\u53d6Node\u7248\u672c16\u7684\u57fa\u7840\u955c\u50cf<\/span>\r\n<span class=\"token instruction\"><span class=\"token keyword\">FROM<\/span> node:16<\/span>\r\n\r\n<span class=\"token comment\"># \u83b7\u53d6\u6700\u65b0\u7248\u672c\u7684Playwright<\/span>\r\n<span class=\"token instruction\"><span class=\"token keyword\">FROM<\/span> mcr.microsoft.com\/playwright:focal<\/span>\r\n \r\n<span class=\"token comment\"># \u8bbe\u7f6e\u5e94\u7528\u7a0b\u5e8f\u7684\u5de5\u4f5c\u76ee\u5f55<\/span>\r\n<span class=\"token instruction\"><span class=\"token keyword\">WORKDIR<\/span> \/app<\/span>\r\n \r\n<span class=\"token comment\"># \u8bbe\u7f6e\u73af\u5883\u53d8\u91cfPATH\u5230node_modules\/.bin<\/span>\r\n<span class=\"token instruction\"><span class=\"token keyword\">ENV<\/span> PATH \/app\/node_modules\/.bin:<span class=\"token variable\">$PATH<\/span><\/span>\r\n\r\n<span class=\"token comment\"># \u590d\u5236\u6240\u9700\u6587\u4ef6\u5230Docker\u955c\u50cf\u7684\/app\u6587\u4ef6\u5939<\/span>\r\n<span class=\"token instruction\"><span class=\"token keyword\">COPY<\/span> package.json \/app\/<\/span>\r\n<span class=\"token instruction\"><span class=\"token keyword\">COPY<\/span> tests\/ \/app\/tests\/<\/span>\r\n<span class=\"token instruction\"><span class=\"token keyword\">COPY<\/span> tsconfig.json \/app\/<\/span>\r\n<span class=\"token instruction\"><span class=\"token keyword\">COPY<\/span> config.toml \/app\/<\/span>\r\n\r\n<span class=\"token comment\"># \u83b7\u53d6\u8fd0\u884cPlaywright\u6240\u9700\u7684\u5e93<\/span>\r\n<span class=\"token instruction\"><span class=\"token keyword\">RUN<\/span> apt-get update &amp;&amp; apt-get -y install libnss3 libatk-bridge2.0-0 libdrm-dev libxkbcommon-dev libgbm-dev libasound-dev libatspi2.0-0 libxshmfence-dev<\/span>\r\n\r\n<span class=\"token comment\"># \u5728Node\u73af\u5883\u4e2d\u5b89\u88c5\u4f9d\u8d56<\/span>\r\n<span class=\"token instruction\"><span class=\"token keyword\">RUN<\/span> npm install<\/span>\r\n<\/code><\/pre>\n<p>\u9996\u5148\uff0c\u60a8\u9700\u8981\u83b7\u53d6Node\u7248\u672c16\u548cPlaywright\u7248\u672cfocal\u7684\u57fa\u7840\u955c\u50cf\uff0c\u5e76\u5c06\u5b83\u4eec\u6dfb\u52a0\u5230\u60a8\u7684Docker\u955c\u50cf\u4e2d\u3002\u6d4b\u8bd5\u8fd0\u884c\u9700\u8981Node\u548cPlaywright\u3002<\/p>\n<p>\u7136\u540e\uff0c\u5728\u5bb9\u5668\u4e2d\u8bbe\u7f6e\u9879\u76ee\u76ee\u5f55\u540d\u3002\u8fd9\u91cc\u662f<code>WORKDIR<\/code>\u3002\u5c06<code>WORKDIR \/app<\/code>\u8bbe\u7f6e\u4e3a\u5c06\u6240\u6709\u6587\u4ef6\u653e\u7f6e\u5728\u5bb9\u5668\u5185\u7684<code>\/app<\/code>\u76ee\u5f55\u4e2d\u3002<\/p>\n<p>\u60a8\u53ef\u4ee5\u4f7f\u7528<code>ENV PATH<\/code>\u6765\u8bbe\u7f6eDocker\u5bb9\u5668\u7684\u73af\u5883\u8def\u5f84\u3002\u5728\u6b64\u793a\u4f8b\u4e2d\uff0c\u60a8\u5c06\u5176\u8bbe\u7f6e\u4e3a<code>node_modules<\/code>\u76ee\u5f55\u3002<\/p>\n<p>\u63a5\u7740\uff0c\u60a8\u5c06\u6240\u6709\u5fc5\u8981\u7684\u6587\u4ef6\u590d\u5236\u5230Docker\u955c\u50cf\u7684<code>\/app<\/code>\u76ee\u5f55\u4e2d\u3002<\/p>\n<p>\u7531\u4e8ePlaywright\u8fd0\u884c\u9700\u8981\u4e00\u4e9b\u4f9d\u8d56\u9879\uff0c\u60a8\u8fd8\u9700\u8981\u5728Docker\u955c\u50cf\u4e2d\u5b89\u88c5\u8fd9\u4e9b\u4f9d\u8d56\u9879\u3002<\/p>\n<p>\u4fdd\u5b58\u5e76\u5173\u95ed\u6587\u4ef6\u3002<\/p>\n<p>\u63a5\u4e0b\u6765\uff0c\u60a8\u5c06\u4e3a\u81ea\u52a8\u5316\u9879\u76ee\u6784\u5efa\u955c\u50cf\u3002<\/p>\n<pre class=\"post-pre\"><code><ol><li data-prefix=\"$\"><span class=\"token function\">docker<\/span> build <span class=\"token parameter variable\">-t<\/span> playwright-docker <span class=\"token builtin class-name\">.<\/span>\r\n<\/li><\/ol>\r\n<\/code><\/pre>\n<p>Docker\u4f1a\u5728\u5f53\u524d\u76ee\u5f55\u4e2d\u627e\u5230Dockerfile\uff0c\u5e76\u6309\u7167\u5176\u4e2d\u7684\u6307\u4ee4\u6784\u5efa\u955c\u50cf\u3002\u4f7f\u7528<code>-t<\/code>\u6807\u8bb0\u4e3aDocker\u955c\u50cf\u6253\u4e0a<code>playwright-docker<\/code>\u7684\u6807\u7b7e\u3002\u901a\u8fc7\u4f7f\u7528\u201c.\u201d\u544a\u8bc9Docker\u5728\u5f53\u524d\u76ee\u5f55\u4e2d\u5bfb\u627eDockerfile\u3002\u60a8\u53ef\u4ee5\u67e5\u9605Docker\u4ea7\u54c1\u6587\u6863\u4ee5\u4e86\u89e3\u66f4\u591a\u6709\u5173\u6784\u5efaDocker\u955c\u50cf\u7684\u5185\u5bb9\u3002<\/p>\n<p>\u6784\u5efa\u7684\u8f93\u51fa\uff08\u7b80\u5316\u7248\uff09\u5c06\u7c7b\u4f3c\u4e8e\u4ee5\u4e0b\u5185\u5bb9\uff1a<\/p>\n<pre class=\"post-pre\"><code><div class=\"secondary-code-label\" title=\"Output\">\u8f93\u51fa<\/div>\u53d1\u9001\u6784\u5efa\u4e0a\u4e0b\u6587\u5230Docker\u5b88\u62a4\u8fdb\u7a0b  76.61MB\r\n...\r\n\u6dfb\u52a0\u4e866\u4e2a\u5305\uff0c\u5e76\u57286\u79d2\u5185\u5ba1\u8ba1\u4e867\u4e2a\u5305\r\n\r\n\u53d1\u73b00\u4e2a\u6f0f\u6d1e\r\n\u79fb\u9664\u4e2d\u95f4\u5bb9\u5668 87520d179fd1\r\n ---&gt; 433ae116d06a\r\n\u6210\u529f\u6784\u5efa 433ae116d06a\r\n\u6210\u529f\u6807\u8bb0 playwright-docker:latest\r\n<\/code><\/pre>\n<p>\u7531\u4e8e\u4f9d\u8d56\u51b2\u7a81\u6216\u521d\u59cb\u8bbe\u7f6e\u8fc7\u7a0b\u4e2d\u7f3a\u5c11\u4f9d\u8d56\uff0c\u8fd9\u4e9b\u6d4b\u8bd5\u53ef\u80fd\u65e0\u6cd5\u5728Windows\u6216macOS\u4e0a\u6b63\u786e\u8fd0\u884c\uff0c\u4f46\u4f7f\u7528Docker\u6765\u8fd0\u884c\u6d4b\u8bd5\u5e94\u8be5\u53ef\u4ee5\u89e3\u51b3\u8fd9\u4e9b\u73af\u5883\u914d\u7f6e\u95ee\u9898\u3002\u901a\u8fc7Docker\uff0c\u60a8\u7684\u57fa\u7840\u955c\u50cf\u5305\u542b\u4e86\u6240\u6709\u6240\u9700\u7684\u4f9d\u8d56\u9879\u3002\u53ea\u8981\u5b89\u88c5\u4e86Docker\uff0c\u8fd9\u4e9b\u6d4b\u8bd5\u5c31\u53ef\u4ee5\u5728\u4e0d\u540c\u7684\u64cd\u4f5c\u7cfb\u7edf\u4e0a\u8fd0\u884c\u3002<\/p>\n<p>\u68c0\u67e5Docker\u955c\u50cf\u662f\u5426\u6210\u529f\u521b\u5efa\u3002<\/p>\n<pre class=\"post-pre\"><code><ol><li data-prefix=\"$\"><span class=\"token function\">docker<\/span> image <span class=\"token function\">ls<\/span>\r\n<\/li><\/ol>\r\n<\/code><\/pre>\n<p>\u7ed3\u679c\u5e94\u8be5\u7c7b\u4f3c\u4e8e\u8fd9\u4e2a\uff1a<\/p>\n<pre class=\"post-pre\"><code><div class=\"secondary-code-label\" title=\"Output\">\u8f93\u51fa<\/div>REPOSITORY                  TAG     IMAGE ID    CREATED       SIZE\r\nplaywright-docker           latest  433ae116d06a   5 minutes ago   1.92GB\r\nmcr.microsoft.com\/playwright   focal  bb9872cfd272   2 days ago   1.76GB\r\nnode                        16      c6b745e900c7   6 days ago   907MB\r\n<\/code><\/pre>\n<p>\u60a8\u53ef\u4ee5\u770b\u5230<code>playwright-docker<\/code>\uff08\u6d4b\u8bd5\u955c\u50cf\uff09\u3001\u5fae\u8f6fPlaywright\u548cNode\u955c\u50cf\u3002\u60a8\u8fd8\u53ef\u4ee5\u4eceDocker\u5b89\u88c5\u5148\u51b3\u6761\u4ef6\u4e2d\u83b7\u53d6Ubuntu\u548chello-world\u955c\u50cf\u3002<\/p>\n<p>\u73b0\u5728\uff0c\u4f7f\u7528<code>docker run<\/code>\u547d\u4ee4\u5728\u60a8\u7684Docker\u5bb9\u5668\u4e2d\u8fd0\u884c\u6d4b\u8bd5\u547d\u4ee4\u3002<\/p>\n<pre class=\"post-pre\"><code><ol><li data-prefix=\"$\"><span class=\"token function\">docker<\/span> run <span class=\"token parameter variable\">-it<\/span> playwright-docker:latest <span class=\"token function\">npm<\/span> run <span class=\"token builtin class-name\">test<\/span>\r\n<\/li><\/ol>\r\n<\/code><\/pre>\n<p>\u5728\u6b64\u793a\u4f8b\u4e2d\uff0c<code>docker run<\/code>\u5c06\u4f7f\u7528\u6307\u5b9a\u7684\u547d\u4ee4\u8fd0\u884c<code>playwright-docker:latest<\/code> Docker\u955c\u50cf\u3002<code>docker run<\/code>\u9996\u5148\u4f1a\u542f\u52a8Docker\u5bb9\u5668\uff0c\u7136\u540e\u6267\u884c\u6240\u9700\u7684\u547d\u4ee4\u3002\u60a8\u53ef\u4ee5\u5728Docker\u4ea7\u54c1\u6587\u6863\u4e2d\u4e86\u89e3\u66f4\u591a\u4fe1\u606f\u3002<\/p>\n<p>\u7ed3\u679c\u5c06\u5982\u4e0b\u6240\u793a\uff1a<\/p>\n<pre class=\"post-pre\"><code><div class=\"secondary-code-label\" title=\"Output\">\u8f93\u51fa<\/div>\r\n<\/code><\/pre>\n<pre><code>playwright-docker@1.0.0 test\r\nplaywright test --browser=all\r\n\r\n\u8fd0\u884c9\u4e2a\u6d4b\u8bd5\uff0c\u4f7f\u75282\u4e2a\u5de5\u4f5c\u8fdb\u7a0b\r\n\r\n  \u2713  [chromium] \u203a tests\/pricingComparison.spec.ts:4:1 \u203a \u9884\u671f\u67094\u4e2a\u5b9a\u4ef7\u9009\u9879 (7\u79d2)\r\n  \u2713  [chromium] \u203a tests\/multiplePackages.spec.ts:4:1 \u203a \u9884\u671f\u8ba2\u9605\u67092\u4e2a\u5957\u9910 (8\u79d2)\r\n  \u2713  [chromium] \u203a tests\/signUpMethods.spec.ts:4:1 \u203a \u9884\u671f\u67093\u4e2a\u6ce8\u518c\u9009\u9879 (8\u79d2)\r\n  \u2713  [firefox] \u203a tests\/multiplePackages.spec.ts:4:1 \u203a \u9884\u671f\u8ba2\u9605\u67092\u4e2a\u5957\u9910 (9\u79d2)\r\n  \u2713  [firefox] \u203a tests\/pricingComparison.spec.ts:4:1 \u203a \u9884\u671f\u67094\u4e2a\u5b9a\u4ef7\u9009\u9879 (8\u79d2)\r\n  \u2713  [firefox] \u203a tests\/signUpMethods.spec.ts:4:1 \u203a \u9884\u671f\u67093\u4e2a\u6ce8\u518c\u9009\u9879 (5\u79d2)\r\n  \u2713  [webkit] \u203a tests\/multiplePackages.spec.ts:4:1 \u203a \u9884\u671f\u8ba2\u9605\u67092\u4e2a\u5957\u9910 (8\u79d2)\r\n  \u2713  [webkit] \u203a tests\/pricingComparison.spec.ts:4:1 \u203a \u9884\u671f\u67094\u4e2a\u5b9a\u4ef7\u9009\u9879 (10\u79d2)\r\n  \u2713  [webkit] \u203a tests\/signUpMethods.spec.ts:4:1 \u203a \u9884\u671f\u67093\u4e2a\u6ce8\u518c\u9009\u9879 (7\u79d2)\r\n\r\n\r\n  9\u4e2a\u6d4b\u8bd5\u901a\u8fc7 (41\u79d2)\r\n<\/code><\/pre>\n<p>\u6d4b\u8bd5\u73b0\u5728\u5df2\u5728Docker\u73af\u5883\u4e2d\u6210\u529f\u8fd0\u884c\u3002\u60a8\u53ef\u4ee5\u5b89\u5168\u5730\u5c06\u4ee3\u7801\u66f4\u65b0\u5230\u8fdc\u7a0b\u5b58\u50a8\u5e93\uff0c\u7cfb\u7edf\u7ba1\u7406\u5458\u53ef\u4ee5\u5c06\u81ea\u52a8\u5316\u6d4b\u8bd5\u96c6\u6210\u5230CI\/CD\u6d41\u7a0b\u4e2d\u3002<\/p>\n<p>\u60a8\u8fd8\u53ef\u4ee5\u5728\u8be5\u5b58\u50a8\u5e93\u4e2d\u67e5\u770b\u4e3a\u672c\u6587\u521b\u5efa\u7684\u6587\u4ef6\u3002<\/p>\n<h2>\u7ed3\u8bba<\/h2>\n<p>\u73b0\u5728\u60a8\u5df2\u7ecf\u5b66\u4f1a\u4e86\u5982\u4f55\u4f7f\u7528Playwright\u8fdb\u884c\u7aef\u5230\u7aef\u6d4b\u8bd5\uff0c\u5e76\u4f7f\u7528Docker\u90e8\u7f72\u8fd9\u4e9b\u6d4b\u8bd5\u3002\u8981\u4e86\u89e3\u66f4\u591a\u5173\u4e8ePlaywright\u7684\u4fe1\u606f\uff0c\u8bf7\u8bbf\u95ee<a href=\"https:\/\/playwright.dev\/docs\/\" target=\"_blank\">Playwright\u6587\u6863<\/a>\u3002<\/p>\n<p>\u60a8\u53ef\u4ee5\u9605\u8bfb\u6709\u5173<a href=\"https:\/\/www.docker.com\/blog\/\" target=\"_blank\">Docker\u751f\u6001\u7cfb\u7edf<\/a>\u7684\u5185\u5bb9\uff0c\u4ee5\u4e86\u89e3\u66f4\u591a\u5173\u4e8eDocker\u7684\u4fe1\u606f\u3002<a href=\"https:\/\/docs.docker.com\/\" target=\"_blank\">Docker\u4ea7\u54c1\u6587\u6863<\/a>\u8fd8\u63d0\u4f9b\u4e86\u4e00\u4e9b\u7f16\u5199Dockerfile\u7684\u6700\u4f73\u5b9e\u8df5\u548cDockerfile\u53c2\u8003\u6307\u5357\u3002\u4e3a\u4e86\u7ee7\u7eed\u4f7f\u7528Docker\u8fdb\u884c\u5de5\u4f5c\uff0c\u60a8\u53ef\u4ee5\u5c1d\u8bd5\u5176\u4ed6<a href=\"https:\/\/docs.docker.com\/get-started\/\" target=\"_blank\">Docker\u6559\u7a0b<\/a>\u3002<\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u4ecb\u7ecd Playwright\u662f\u4e00\u4e2a\u51fa\u8272\u7684\u5de5\u5177\uff0c\u7528\u4e8e\u8de8\u6d4f\u89c8\u5668\u7684\u7aef\u5230\u7aef\u6d4b\u8bd5\uff0c\u5305\u62ecChromium\u3001Firefox\u548cW [&hellip;]<\/p>\n","protected":false},"author":11,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[13,671,668,669,670],"class_list":["post-159","post","type-post","status-publish","format-standard","hentry","category-uncategorized","tag-docker","tag-e2e","tag-playwright","tag-669","tag-670"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v21.5 (Yoast SEO v21.5) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Playwright\u4e0eDocker\uff1a\u9ad8\u6548\u8fd0\u884c\u7aef\u5230\u7aef\u6d4b\u8bd5\u7684\u7ec8\u6781\u6307\u5357 - Blog - Silicon Cloud<\/title>\n<meta name=\"description\" content=\"\u63a2\u7d22\u5982\u4f55\u7ed3\u5408Playwright\u548cDocker\uff0c\u6784\u5efa\u7a33\u5b9a\u3001\u53ef\u91cd\u590d\u7684\u7aef\u5230\u7aef\u6d4b\u8bd5\u73af\u5883\u3002\u672c\u6307\u5357\u5c06\u8be6\u7ec6\u4ecb\u7ecd\u8bbe\u7f6e\u3001\u8fd0\u884c\u548c\u4f18\u5316\u6d4b\u8bd5\u6d41\u7a0b\uff0c\u52a9\u60a8\u63d0\u5347\u6d4b\u8bd5\u6548\u7387\u4e0e\u8d28\u91cf\u3002\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.silicloud.com\/zh\/blog\/\u5982\u4f55\u4f7f\u7528playwright\u548cdocker\u8fd0\u884c\u7aef\u5230\u7aef\u6d4b\u8bd5\/\" \/>\n<meta property=\"og:locale\" content=\"zh_CN\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Playwright\u4e0eDocker\uff1a\u9ad8\u6548\u8fd0\u884c\u7aef\u5230\u7aef\u6d4b\u8bd5\u7684\u7ec8\u6781\u6307\u5357\" \/>\n<meta property=\"og:description\" content=\"\u63a2\u7d22\u5982\u4f55\u7ed3\u5408Playwright\u548cDocker\uff0c\u6784\u5efa\u7a33\u5b9a\u3001\u53ef\u91cd\u590d\u7684\u7aef\u5230\u7aef\u6d4b\u8bd5\u73af\u5883\u3002\u672c\u6307\u5357\u5c06\u8be6\u7ec6\u4ecb\u7ecd\u8bbe\u7f6e\u3001\u8fd0\u884c\u548c\u4f18\u5316\u6d4b\u8bd5\u6d41\u7a0b\uff0c\u52a9\u60a8\u63d0\u5347\u6d4b\u8bd5\u6548\u7387\u4e0e\u8d28\u91cf\u3002\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.silicloud.com\/zh\/blog\/\u5982\u4f55\u4f7f\u7528playwright\u548cdocker\u8fd0\u884c\u7aef\u5230\u7aef\u6d4b\u8bd5\/\" \/>\n<meta property=\"og:site_name\" content=\"Blog - Silicon Cloud\" \/>\n<meta property=\"article:published_time\" content=\"2023-03-10T16:00:24+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-07-31T17:39:14+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/cdn.silicloud.com\/blog-img\/blog\/img\/65646e19a4b2f92e6c728142\/109-0.png\" \/>\n<meta name=\"author\" content=\"\u65b0, \u97f5\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"\u4f5c\u8005\" \/>\n\t<meta name=\"twitter:data1\" content=\"\u65b0, \u97f5\" \/>\n\t<meta name=\"twitter:label2\" content=\"\u9884\u8ba1\u9605\u8bfb\u65f6\u95f4\" \/>\n\t<meta name=\"twitter:data2\" content=\"3 \u5206\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.silicloud.com\/zh\/blog\/%e5%a6%82%e4%bd%95%e4%bd%bf%e7%94%a8playwright%e5%92%8cdocker%e8%bf%90%e8%a1%8c%e7%ab%af%e5%88%b0%e7%ab%af%e6%b5%8b%e8%af%95\/\",\"url\":\"https:\/\/www.silicloud.com\/zh\/blog\/%e5%a6%82%e4%bd%95%e4%bd%bf%e7%94%a8playwright%e5%92%8cdocker%e8%bf%90%e8%a1%8c%e7%ab%af%e5%88%b0%e7%ab%af%e6%b5%8b%e8%af%95\/\",\"name\":\"Playwright\u4e0eDocker\uff1a\u9ad8\u6548\u8fd0\u884c\u7aef\u5230\u7aef\u6d4b\u8bd5\u7684\u7ec8\u6781\u6307\u5357 - Blog - Silicon Cloud\",\"isPartOf\":{\"@id\":\"https:\/\/www.silicloud.com\/zh\/blog\/#website\"},\"datePublished\":\"2023-03-10T16:00:24+00:00\",\"dateModified\":\"2025-07-31T17:39:14+00:00\",\"author\":{\"@id\":\"https:\/\/www.silicloud.com\/zh\/blog\/#\/schema\/person\/4ba4019495123db3038fd0809e6959c9\"},\"description\":\"\u63a2\u7d22\u5982\u4f55\u7ed3\u5408Playwright\u548cDocker\uff0c\u6784\u5efa\u7a33\u5b9a\u3001\u53ef\u91cd\u590d\u7684\u7aef\u5230\u7aef\u6d4b\u8bd5\u73af\u5883\u3002\u672c\u6307\u5357\u5c06\u8be6\u7ec6\u4ecb\u7ecd\u8bbe\u7f6e\u3001\u8fd0\u884c\u548c\u4f18\u5316\u6d4b\u8bd5\u6d41\u7a0b\uff0c\u52a9\u60a8\u63d0\u5347\u6d4b\u8bd5\u6548\u7387\u4e0e\u8d28\u91cf\u3002\",\"breadcrumb\":{\"@id\":\"https:\/\/www.silicloud.com\/zh\/blog\/%e5%a6%82%e4%bd%95%e4%bd%bf%e7%94%a8playwright%e5%92%8cdocker%e8%bf%90%e8%a1%8c%e7%ab%af%e5%88%b0%e7%ab%af%e6%b5%8b%e8%af%95\/#breadcrumb\"},\"inLanguage\":\"zh-Hans\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.silicloud.com\/zh\/blog\/%e5%a6%82%e4%bd%95%e4%bd%bf%e7%94%a8playwright%e5%92%8cdocker%e8%bf%90%e8%a1%8c%e7%ab%af%e5%88%b0%e7%ab%af%e6%b5%8b%e8%af%95\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.silicloud.com\/zh\/blog\/%e5%a6%82%e4%bd%95%e4%bd%bf%e7%94%a8playwright%e5%92%8cdocker%e8%bf%90%e8%a1%8c%e7%ab%af%e5%88%b0%e7%ab%af%e6%b5%8b%e8%af%95\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"\u9996\u9875\",\"item\":\"https:\/\/www.silicloud.com\/zh\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Playwright\u4e0eDocker\uff1a\u9ad8\u6548\u8fd0\u884c\u7aef\u5230\u7aef\u6d4b\u8bd5\u7684\u7ec8\u6781\u6307\u5357\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.silicloud.com\/zh\/blog\/#website\",\"url\":\"https:\/\/www.silicloud.com\/zh\/blog\/\",\"name\":\"Blog - Silicon Cloud\",\"description\":\"\",\"inLanguage\":\"zh-Hans\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.silicloud.com\/zh\/blog\/#\/schema\/person\/4ba4019495123db3038fd0809e6959c9\",\"name\":\"\u65b0, \u97f5\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"zh-Hans\",\"@id\":\"https:\/\/www.silicloud.com\/zh\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/d484b6c6e4ae82e8a9efea989e1d2af46d9b6ef128101e63b18f559fca0ae627?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/d484b6c6e4ae82e8a9efea989e1d2af46d9b6ef128101e63b18f559fca0ae627?s=96&d=mm&r=g\",\"caption\":\"\u65b0, \u97f5\"},\"url\":\"https:\/\/www.silicloud.com\/zh\/blog\/author\/yunxin\/\"},{\"@type\":\"ImageObject\",\"inLanguage\":\"zh-Hans\",\"@id\":\"https:\/\/www.silicloud.com\/zh\/blog\/%e5%a6%82%e4%bd%95%e4%bd%bf%e7%94%a8playwright%e5%92%8cdocker%e8%bf%90%e8%a1%8c%e7%ab%af%e5%88%b0%e7%ab%af%e6%b5%8b%e8%af%95\/#local-main-organization-logo\",\"url\":\"\",\"contentUrl\":\"\",\"caption\":\"Blog - Silicon Cloud\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Playwright\u4e0eDocker\uff1a\u9ad8\u6548\u8fd0\u884c\u7aef\u5230\u7aef\u6d4b\u8bd5\u7684\u7ec8\u6781\u6307\u5357 - Blog - Silicon Cloud","description":"\u63a2\u7d22\u5982\u4f55\u7ed3\u5408Playwright\u548cDocker\uff0c\u6784\u5efa\u7a33\u5b9a\u3001\u53ef\u91cd\u590d\u7684\u7aef\u5230\u7aef\u6d4b\u8bd5\u73af\u5883\u3002\u672c\u6307\u5357\u5c06\u8be6\u7ec6\u4ecb\u7ecd\u8bbe\u7f6e\u3001\u8fd0\u884c\u548c\u4f18\u5316\u6d4b\u8bd5\u6d41\u7a0b\uff0c\u52a9\u60a8\u63d0\u5347\u6d4b\u8bd5\u6548\u7387\u4e0e\u8d28\u91cf\u3002","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.silicloud.com\/zh\/blog\/\u5982\u4f55\u4f7f\u7528playwright\u548cdocker\u8fd0\u884c\u7aef\u5230\u7aef\u6d4b\u8bd5\/","og_locale":"zh_CN","og_type":"article","og_title":"Playwright\u4e0eDocker\uff1a\u9ad8\u6548\u8fd0\u884c\u7aef\u5230\u7aef\u6d4b\u8bd5\u7684\u7ec8\u6781\u6307\u5357","og_description":"\u63a2\u7d22\u5982\u4f55\u7ed3\u5408Playwright\u548cDocker\uff0c\u6784\u5efa\u7a33\u5b9a\u3001\u53ef\u91cd\u590d\u7684\u7aef\u5230\u7aef\u6d4b\u8bd5\u73af\u5883\u3002\u672c\u6307\u5357\u5c06\u8be6\u7ec6\u4ecb\u7ecd\u8bbe\u7f6e\u3001\u8fd0\u884c\u548c\u4f18\u5316\u6d4b\u8bd5\u6d41\u7a0b\uff0c\u52a9\u60a8\u63d0\u5347\u6d4b\u8bd5\u6548\u7387\u4e0e\u8d28\u91cf\u3002","og_url":"https:\/\/www.silicloud.com\/zh\/blog\/\u5982\u4f55\u4f7f\u7528playwright\u548cdocker\u8fd0\u884c\u7aef\u5230\u7aef\u6d4b\u8bd5\/","og_site_name":"Blog - Silicon Cloud","article_published_time":"2023-03-10T16:00:24+00:00","article_modified_time":"2025-07-31T17:39:14+00:00","og_image":[{"url":"https:\/\/cdn.silicloud.com\/blog-img\/blog\/img\/65646e19a4b2f92e6c728142\/109-0.png"}],"author":"\u65b0, \u97f5","twitter_card":"summary_large_image","twitter_misc":{"\u4f5c\u8005":"\u65b0, \u97f5","\u9884\u8ba1\u9605\u8bfb\u65f6\u95f4":"3 \u5206"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/www.silicloud.com\/zh\/blog\/%e5%a6%82%e4%bd%95%e4%bd%bf%e7%94%a8playwright%e5%92%8cdocker%e8%bf%90%e8%a1%8c%e7%ab%af%e5%88%b0%e7%ab%af%e6%b5%8b%e8%af%95\/","url":"https:\/\/www.silicloud.com\/zh\/blog\/%e5%a6%82%e4%bd%95%e4%bd%bf%e7%94%a8playwright%e5%92%8cdocker%e8%bf%90%e8%a1%8c%e7%ab%af%e5%88%b0%e7%ab%af%e6%b5%8b%e8%af%95\/","name":"Playwright\u4e0eDocker\uff1a\u9ad8\u6548\u8fd0\u884c\u7aef\u5230\u7aef\u6d4b\u8bd5\u7684\u7ec8\u6781\u6307\u5357 - Blog - Silicon Cloud","isPartOf":{"@id":"https:\/\/www.silicloud.com\/zh\/blog\/#website"},"datePublished":"2023-03-10T16:00:24+00:00","dateModified":"2025-07-31T17:39:14+00:00","author":{"@id":"https:\/\/www.silicloud.com\/zh\/blog\/#\/schema\/person\/4ba4019495123db3038fd0809e6959c9"},"description":"\u63a2\u7d22\u5982\u4f55\u7ed3\u5408Playwright\u548cDocker\uff0c\u6784\u5efa\u7a33\u5b9a\u3001\u53ef\u91cd\u590d\u7684\u7aef\u5230\u7aef\u6d4b\u8bd5\u73af\u5883\u3002\u672c\u6307\u5357\u5c06\u8be6\u7ec6\u4ecb\u7ecd\u8bbe\u7f6e\u3001\u8fd0\u884c\u548c\u4f18\u5316\u6d4b\u8bd5\u6d41\u7a0b\uff0c\u52a9\u60a8\u63d0\u5347\u6d4b\u8bd5\u6548\u7387\u4e0e\u8d28\u91cf\u3002","breadcrumb":{"@id":"https:\/\/www.silicloud.com\/zh\/blog\/%e5%a6%82%e4%bd%95%e4%bd%bf%e7%94%a8playwright%e5%92%8cdocker%e8%bf%90%e8%a1%8c%e7%ab%af%e5%88%b0%e7%ab%af%e6%b5%8b%e8%af%95\/#breadcrumb"},"inLanguage":"zh-Hans","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.silicloud.com\/zh\/blog\/%e5%a6%82%e4%bd%95%e4%bd%bf%e7%94%a8playwright%e5%92%8cdocker%e8%bf%90%e8%a1%8c%e7%ab%af%e5%88%b0%e7%ab%af%e6%b5%8b%e8%af%95\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.silicloud.com\/zh\/blog\/%e5%a6%82%e4%bd%95%e4%bd%bf%e7%94%a8playwright%e5%92%8cdocker%e8%bf%90%e8%a1%8c%e7%ab%af%e5%88%b0%e7%ab%af%e6%b5%8b%e8%af%95\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"\u9996\u9875","item":"https:\/\/www.silicloud.com\/zh\/blog\/"},{"@type":"ListItem","position":2,"name":"Playwright\u4e0eDocker\uff1a\u9ad8\u6548\u8fd0\u884c\u7aef\u5230\u7aef\u6d4b\u8bd5\u7684\u7ec8\u6781\u6307\u5357"}]},{"@type":"WebSite","@id":"https:\/\/www.silicloud.com\/zh\/blog\/#website","url":"https:\/\/www.silicloud.com\/zh\/blog\/","name":"Blog - Silicon Cloud","description":"","inLanguage":"zh-Hans"},{"@type":"Person","@id":"https:\/\/www.silicloud.com\/zh\/blog\/#\/schema\/person\/4ba4019495123db3038fd0809e6959c9","name":"\u65b0, \u97f5","image":{"@type":"ImageObject","inLanguage":"zh-Hans","@id":"https:\/\/www.silicloud.com\/zh\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/d484b6c6e4ae82e8a9efea989e1d2af46d9b6ef128101e63b18f559fca0ae627?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/d484b6c6e4ae82e8a9efea989e1d2af46d9b6ef128101e63b18f559fca0ae627?s=96&d=mm&r=g","caption":"\u65b0, \u97f5"},"url":"https:\/\/www.silicloud.com\/zh\/blog\/author\/yunxin\/"},{"@type":"ImageObject","inLanguage":"zh-Hans","@id":"https:\/\/www.silicloud.com\/zh\/blog\/%e5%a6%82%e4%bd%95%e4%bd%bf%e7%94%a8playwright%e5%92%8cdocker%e8%bf%90%e8%a1%8c%e7%ab%af%e5%88%b0%e7%ab%af%e6%b5%8b%e8%af%95\/#local-main-organization-logo","url":"","contentUrl":"","caption":"Blog - Silicon Cloud"}]}},"_links":{"self":[{"href":"https:\/\/www.silicloud.com\/zh\/blog\/wp-json\/wp\/v2\/posts\/159","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.silicloud.com\/zh\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.silicloud.com\/zh\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.silicloud.com\/zh\/blog\/wp-json\/wp\/v2\/users\/11"}],"replies":[{"embeddable":true,"href":"https:\/\/www.silicloud.com\/zh\/blog\/wp-json\/wp\/v2\/comments?post=159"}],"version-history":[{"count":4,"href":"https:\/\/www.silicloud.com\/zh\/blog\/wp-json\/wp\/v2\/posts\/159\/revisions"}],"predecessor-version":[{"id":109635,"href":"https:\/\/www.silicloud.com\/zh\/blog\/wp-json\/wp\/v2\/posts\/159\/revisions\/109635"}],"wp:attachment":[{"href":"https:\/\/www.silicloud.com\/zh\/blog\/wp-json\/wp\/v2\/media?parent=159"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.silicloud.com\/zh\/blog\/wp-json\/wp\/v2\/categories?post=159"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.silicloud.com\/zh\/blog\/wp-json\/wp\/v2\/tags?post=159"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}