扫码阅读
手机扫码阅读

《PlayWright全解析——从入门到精通》-3

1268 2023-07-17

追踪查看

playwright默认情况下就开启了追踪机制,并定义在执行测试案例失败后的第一次重试时会记录追踪日志。

可以在配置文件playwright.config.ts中看到相关的配置信息:

1 2 3 4 5 6 7 
const config: PlaywrightTestConfig = {  // 不相关的省略  retries: process.env.CI ? 2 : 0, // 如果在CI环境,则有2次重试  use: {  trace: 'on-first-retry', // 在第一次重试时记录追踪日志  }, } 

在执行测试时,也可以通过命令行直接开启:

1 
npx playwright test --trace on 

开启trace后,执行完测试会生成一个trace.zip压缩包,可以在报告中查看:

trace报告也可以用命令行直接打开:

1 
npx playwright show-trace trace.zip 

如果不加trace.zip文件名,那会在弹出的页面中提示你指定trace文件或者直接将trace文件拖进当前的页面上。

打开trace文件可以看到如下信息:

详解PlayWright

配置文件说明

我们仔细拆解一下PlayWright的启动机制,当我们启动测试时,playwright会首先加载playwright.config.ts文件中定义的PlaywrightTestConfig对象,这个对象的设置分为全局参数设置和项目(project)参数设置,注意项目参数设置会覆盖全局设置。具体的内容我们后面会逐步提到。

而在执行case之前,我们定义的测试案例函数(还记得我们前面提过的,test方法所需要的两个参数的第二个,是一个函数式的参数吗?),它所传入的PlaywrightTestArgs & PlaywrightTestOptions & PlaywrightWorkerArgs & PlaywrightWorkerOptions这四个对象,其实都来自于配置文件中的全局参数以及项目参数的use属性的设置。

说到这里,可能没有什么直观的感觉,也不明白到底有什么用。没关系,我们先来看看playwright.config.ts文件中如何配置跟浏览器相关的属性。

playwright.config.ts文件中,配置use对象,就有关于浏览器相关的属性:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 
const config: PlaywrightTestConfig = {  // 其他内容略过   use: {  /*  browserName用于设置浏览器名称,这个名称一般在全局参数中不用配置,通常在`项目`(project)参数中设置,只可以有三个可选值:"chromium" 、"firefox"、"webkit",默认值为'chromium'。  */  browserName: 'chromium',  /*  defaultBrowserType用于设置默认浏览器,同上面的browserName类似,只是这个属性用于设置默认值。  */  defaultBrowserType: 'chromium',  /*  headless用于设置是否采用无头模式运行浏览器,默认值是true  */  headless: true,  /*  channel用于指定使用本机按照的浏览器,目前可以支持的值是"chrome","chrome-beta", "chrome-dev", "chrome-canary","msedge", "msedge-beta", "msedge-dev", "msedge-canary",需要注意的是,本机浏览器需要默认安装在本机上。如果不设置,则表示使用playwright自己下载的浏览器。  */  channel: 'chrome',  /*  启动浏览器的相关配置  */  launchOptions: {  /*  传给浏览器的参数,必须是浏览器所支持的命令行参数,比如chromium浏览器,可以参考http://peter.sh/experiments/chromium-command-line-switches  */  args: [  "--force-first-run",  ],  /*  和前面的channel是同一含义。  */  channel: 'chrome',  /*  是否在沙盒内运行,默认是false  */  chromiumSandbox: true,  /*  是否打开开发者工具,只对chromium浏览器有效,当设置为true时,之前设置的headless则无效。默认值为false  */  devtools: true,  /*  用于设置浏览器下载文件的目录  */  downloadsPath: '/temp/download/',  /*  指定浏览器的路径,一般不在全局配置中指定,而在项目配置中配置,一旦配置了浏览器的可执行文件的位置,那么就不会去找playwright自己默认下载的浏览器的位置了。  */  executablePath: '/app/Google Chrome/chrome',  /*  使用SIGHUP“挂起”(Hang Up)信号关闭浏览器,默认是true  */  handleSIGHUP: true,  /*  使用Ctrl+C信号关闭浏览器,默认是true  */  handleSIGINT: true,  /*  使用SIGTERM信号关闭浏览器,默认是true  */  handleSIGTERM: true,  /*  和前面的headless是同一含义。  */  headless: true,  /*  是否忽略playwright本身启动浏览器时后传递给浏览器的参数,默认是false  */  ignoreDefaultArgs: true,  /*  用于设置代理服务器  */  proxy: {  /*  HTTP和SOCKS代理都支持  */  server: 'http://myproxy.com:3128',  /*  指定哪些需要绕开代理,用逗号分开  */  bypass: ".com, chromium.org, .domain.com",  /*  代理用户名  */  username: "myname",  /*  代理密码  */  password: "123456",  },  /*  设置操作间隔的等待时间,用于减慢playwright执行的速度,单位是毫秒  */  slowMo: 200,  /*  等待浏览器启动的超时时间,单位为毫秒,默认值为30000毫秒(30秒)  */  timeout: 30000,  /*  用于设置追逐记录trace包的存放位置  */  tracesDir: 'traces',  },  /*  是否接受文件下载,默认值为true  */  acceptDownloads: true,  /*  设置知否绕开页面的内容安全策略(Content-Security-Policy)  */  bypassCSP: true,  /*  用于设置页面匹配的css的media属性,比如某些页面的css设置了media属性,来展示dark模式,那就可以不用手工去选择,而直接匹配上,可选的值为:'light'`, `'dark'`, `'no-preference'。默认值是'light'  */  colorScheme: 'dark',  /*  是否运行js脚本运行,默认值为true  */  javaScriptEnabled: true,  /*  设置浏览器本地语言  */  locale: 'zh-CN',  /*  设置浏览器获取的权限,权限可以参考https://playwright.dev/docs/api/class-browsercontext#browser-context-grant-permissions  */  permissions: ['geolocation', 'camera'],  /*  同前面的launchOptions中的proxy属性  */  proxy: {/*略*/},  /*  浏览器窗口的大小,默认值为1028*720  */  viewport: {  width: 1028,  height: 720,  },  /*  基础url地址。配置后,当使用page.goto("/foo")的时候,其实就会和baseUrl拼接成完整的地址。  */  baseURL: "https://www.baidu.com",  /*  浏览器上下文,在playwright工具的概念中,一个page,是运行在一个context上下文中的,所以这个context配置的值,会对所有在其中的page有影响。  */  contextOptions: {  /* 大部分属性和前面一样,此处略 */  },   },   projects: [  {  /* 其他属性略 */  use: {  /* 此处为配置单个项目的属性,和前面的全局的use属性其实是一样的,只不过这里配置的在当前这个项目中会覆盖全局属性 */  }  },  /* 其他类似的,略 */  ]   } 

虽然我在这里只列了和浏览器相关的设置属性,不过大家也都基本能看明白了,整个playwright的配置文件,其实分成了全局配置和项目配置,包含的属性是一样的,只不过项目配置会覆盖全局配置。

启动浏览器

根据我们在配置文件中的配置,playwright会将对应的浏览器启动起来。
在例子中,配置文件里面的projects属性配置了3个项目:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 
projects: [  {  name: 'chromium',  use: {  ...devices['Desktop Chrome'],  },  },   {  name: 'firefox',  use: {  ...devices['Desktop Firefox'],  },  },   {  name: 'webkit',  use: {  ...devices['Desktop Safari'],  },  }, ] 

所以我们会执行3个项目的测试,这三个项目名称分别叫”chromium”,”firefox”,”webkit”,每个项目都会独立去运行example中的两个测试案例,所以为何我们看到测试结果一共执行了6个测试,原因就在此处。

...devices['Desktop Chrome']表示引用了devices对象的’Desktop Chrome’的值,这是内置的一个常量,配置了浏览器默认值,除了’Desktop Chrome’,还有很多常量,我们来看下:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 
type Devices = {  "Blackberry PlayBook": DeviceDescriptor;  "Blackberry PlayBook landscape": DeviceDescriptor;  "BlackBerry Z30": DeviceDescriptor;  "BlackBerry Z30 landscape": DeviceDescriptor;  "Galaxy Note 3": DeviceDescriptor;  "Galaxy Note 3 landscape": DeviceDescriptor;  "Galaxy Note II": DeviceDescriptor;  "Galaxy Note II landscape": DeviceDescriptor;  "Galaxy S III": DeviceDescriptor;  "Galaxy S III landscape": DeviceDescriptor;  "Galaxy S5": DeviceDescriptor;  "Galaxy S5 landscape": DeviceDescriptor;  "Galaxy S8": DeviceDescriptor;  "Galaxy S8 landscape": DeviceDescriptor;  "Galaxy S9+": DeviceDescriptor;  "Galaxy S9+ landscape": DeviceDescriptor;  "Galaxy Tab S4": DeviceDescriptor;  "Galaxy Tab S4 landscape": DeviceDescriptor;  "iPad (gen 6)": DeviceDescriptor;  "iPad (gen 6) landscape": DeviceDescriptor;  "iPad (gen 7)": DeviceDescriptor;  "iPad (gen 7) landscape": DeviceDescriptor;  "iPad Mini": DeviceDescriptor;  "iPad Mini landscape": DeviceDescriptor;  "iPad Pro 11": DeviceDescriptor;  "iPad Pro 11 landscape": DeviceDescriptor;  "iPhone 6": DeviceDescriptor;  "iPhone 6 landscape": DeviceDescriptor;  "iPhone 6 Plus": DeviceDescriptor;  "iPhone 6 Plus landscape": DeviceDescriptor;  "iPhone 7": DeviceDescriptor;  "iPhone 7 landscape": DeviceDescriptor;  "iPhone 7 Plus": DeviceDescriptor;  "iPhone 7 Plus landscape": DeviceDescriptor;  "iPhone 8": DeviceDescriptor;  "iPhone 8 landscape": DeviceDescriptor;  "iPhone 8 Plus": DeviceDescriptor;  "iPhone 8 Plus landscape": DeviceDescriptor;  "iPhone SE": DeviceDescriptor;  "iPhone SE landscape": DeviceDescriptor;  "iPhone X": DeviceDescriptor;  "iPhone X landscape": DeviceDescriptor;  "iPhone XR": DeviceDescriptor;  "iPhone XR landscape": DeviceDescriptor;  "iPhone 11": DeviceDescriptor;  "iPhone 11 landscape": DeviceDescriptor;  "iPhone 11 Pro": DeviceDescriptor;  "iPhone 11 Pro landscape": DeviceDescriptor;  "iPhone 11 Pro Max": DeviceDescriptor;  "iPhone 11 Pro Max landscape": DeviceDescriptor;  "iPhone 12": DeviceDescriptor;  "iPhone 12 landscape": DeviceDescriptor;  "iPhone 12 Pro": DeviceDescriptor;  "iPhone 12 Pro landscape": DeviceDescriptor;  "iPhone 12 Pro Max": DeviceDescriptor;  "iPhone 12 Pro Max landscape": DeviceDescriptor;  "iPhone 12 Mini": DeviceDescriptor;  "iPhone 12 Mini landscape": DeviceDescriptor;  "iPhone 13": DeviceDescriptor;  "iPhone 13 landscape": DeviceDescriptor;  "iPhone 13 Pro": DeviceDescriptor;  "iPhone 13 Pro landscape": DeviceDescriptor;  "iPhone 13 Pro Max": DeviceDescriptor;  "iPhone 13 Pro Max landscape": DeviceDescriptor;  "iPhone 13 Mini": DeviceDescriptor;  "iPhone 13 Mini landscape": DeviceDescriptor;  "Kindle Fire HDX": DeviceDescriptor;  "Kindle Fire HDX landscape": DeviceDescriptor;  "LG Optimus L70": DeviceDescriptor;  "LG Optimus L70 landscape": DeviceDescriptor;  "Microsoft Lumia 550": DeviceDescriptor;  "Microsoft Lumia 550 landscape": DeviceDescriptor;  "Microsoft Lumia 950": DeviceDescriptor;  "Microsoft Lumia 950 landscape": DeviceDescriptor;  "Nexus 10": DeviceDescriptor;  "Nexus 10 landscape": DeviceDescriptor;  "Nexus 4": DeviceDescriptor;  "Nexus 4 landscape": DeviceDescriptor;  "Nexus 5": DeviceDescriptor;  "Nexus 5 landscape": DeviceDescriptor;  "Nexus 5X": DeviceDescriptor;  "Nexus 5X landscape": DeviceDescriptor;  "Nexus 6": DeviceDescriptor;  "Nexus 6 landscape": DeviceDescriptor;  "Nexus 6P": DeviceDescriptor;  "Nexus 6P landscape": DeviceDescriptor;  "Nexus 7": DeviceDescriptor;  "Nexus 7 landscape": DeviceDescriptor;  "Nokia Lumia 520": DeviceDescriptor;  "Nokia Lumia 520 landscape": DeviceDescriptor;  "Nokia N9": DeviceDescriptor;  "Nokia N9 landscape": DeviceDescriptor;  "Pixel 2": DeviceDescriptor;  "Pixel 2 landscape": DeviceDescriptor;  "Pixel 2 XL": DeviceDescriptor;  "Pixel 2 XL landscape": DeviceDescriptor;  "Pixel 3": DeviceDescriptor;  "Pixel 3 landscape": DeviceDescriptor;  "Pixel 4": DeviceDescriptor;  "Pixel 4 landscape": DeviceDescriptor;  "Pixel 4a (5G)": DeviceDescriptor;  "Pixel 4a (5G) landscape": DeviceDescriptor;  "Pixel 5": DeviceDescriptor;  "Pixel 5 landscape": DeviceDescriptor;  "Moto G4": DeviceDescriptor;  "Moto G4 landscape": DeviceDescriptor;  "Desktop Chrome HiDPI": DeviceDescriptor;  "Desktop Edge HiDPI": DeviceDescriptor;  "Desktop Firefox HiDPI": DeviceDescriptor;  "Desktop Safari": DeviceDescriptor;  "Desktop Chrome": DeviceDescriptor;  "Desktop Edge": DeviceDescriptor;  "Desktop Firefox": DeviceDescriptor; } 

这些不用多做解释吧,有浏览器,还有手机设备。

devices['Desktop Chrome']前面的三个点号...表示将devices['Desktop Chrome']对象“展平”,将其中的属性取出来作为use对象的属性。那么具体有哪些值呢?我这里举一个devices['Desktop Chrome']的例子:

1 2 3 4 5 6 7 8 9 
devices['Desktop Chrome'] = {  userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.5481.38 Safari/537.36',  viewport: { width: 1280, height: 720 },  screen: { width: 1920, height: 1080 },  deviceScaleFactor: 1,  isMobile: false,  hasTouch: false,  defaultBrowserType: 'chromium' } 

其实主要就是包含了userAgentviewportscreendeviceScaleFactorisMobilehasTouchdefaultBrowserType这七个属性。

这里有点奇怪,不能进行浏览器的最大化设置,只能通过设置viewport属性来设置打开的浏览器窗口大小。

chrome浏览器有个小技巧可以实现窗口最大化,那就是使用命令行参数传递给浏览器,做法是在launchOptions中设置args参数,值为['--start-maximized'],但是请注意,如果在macOS系统中,chromium无法正常最大化,并且viewport的设置也是失效的,可能是个bug。浏览器是否最大化并不会影响测试,除了极为个别的一些情况,所以请不用太在意这些问题。

PlayWright默认会启动自己下载的浏览器,默认情况下,PlayWright下载的浏览器放在如下的目录(和操作系统有关):

  • %USERPROFILE%\AppData\Local\ms-playwright —— Windows

  • ~/Library/Caches/ms-playwright —— MacOS

  • ~/.cache/ms-playwright —— Linux

当然,如果你在安装PlayWright内置的浏览器时没有安装在默认路径,也可以通过设置环境变量来制定到哪个目录去找浏览器,环境变量名字叫PLAYWRIGHT_BROWSERS_PATH,注意,这个路径指到相当于前面所说的ms-playwright这一层就可以。也就是说,ms-playwright里面的目录结构,还是必须和原来的一样,也就是必须像这样的:

1 2 3 4 
chromium-XXXXXX firefox-XXXX webkit-XXXX ffmpeg-XXXX 

指定其他的浏览器

表面看,PlayWright只支持Chrome、Firefox、Edge、Safari浏览器,但实际上,从他的下载的浏览器目录来看,因为他支持Chromium,所以实际上只要是使用了Chromium内核的浏览器,PlayWright都可以支持。

在这里,我举一个例子。比如我想使用本地的Bravo浏览器作为测试用的浏览器,那我可以通过executablePath属性来指定浏览器:

1 2 3 
launchOptions: {  executablePath: '/Applications/Brave Browser.app/Contents/MacOS/Brave Browser', }, 

此时执行测试,就会启动我们安装在本地这个位置的Bravo浏览器,由于Bravo浏览器也是Chromium内核,所以其他操作无区别。那么由此可以举一反三,像国内的360浏览器一样可以操作。

据实验,360浏览器某些版本不支持“无头模式”(headless),必须将headless参数设置成false才能正常启动。

原文链接: https://mp.weixin.qq.com/s?__biz=MzU5ODE2OTc1OQ==&mid=2247496365&idx=1&sn=d17887183efb7b132c5f57b1d7cbd982