端对端 自动化单元测试
- W3C WebDriver 标准
- 自动化启动浏览器、开启Tab页
- 测试单元用例
- 输出结果
浏览器自动化提要
W3C WebDriver API. 标准
浏览器 OpenApi : https://www.w3.org/TR/webdriver1/#list-of-endpoints
各浏览器 OpenApi 的实现
以下为各厂家对于浏览器 OpenApi的实现
https://www.selenium.dev/documentation/webdriver/getting_started/install_drivers/
Browser | Supported OS | Maintained by | Download | Issue Tracker |
---|---|---|---|---|
Chromium/Chrome | Windows/macOS/Linux | Downloads | Issues | |
Firefox | Windows/macOS/Linux | Mozilla | Downloads | Issues |
Edge | Windows/macOS | Microsoft | Downloads | Issues |
Internet Explorer | Windows | Selenium Project | Downloads | Issues |
Safari | macOS High Sierra and newer | Apple | Built in | Issues |
Chrome 为例
针对 不同的版本,具有不同的浏览器驱动,需要查看当前浏览器版本,再下载对应版本的驱动
如: 当前 Chrome 已是最新版本 版本 104.0.5112.101(正式版本) (arm64)
从下载地址(https://chromedriver.chromium.org/downloads)
下载对应一下版本号的的驱动即可
JS 模块 抹平各浏览的差异
JS模块是对于Api的使用且已经抹平各浏览器厂家API的差异
webdriver
https://www.npmjs.com/package/webdriver
npm i webdriver
WebdriverIO
https://www.npmjs.com/package/webdriverio
npm install webdriverio
selenium-webdriver
https://www.npmjs.com/package/selenium-webdriver
# 安装JS驱动
npm install selenium-webdriver
WebBriver 服务
本地服务
const { Builder } = require('selenium-webdriver');
const chrome = require('selenium-webdriver/chrome');
/**
* 获取驱动服务
* 浏览器驱动启动后,会挂载到一个端口上我们可以通过HTTP服务访问、操作浏览器
*/
const service = new chrome.ServiceBuilder('/Users/shang/Code/github/webdriver/chromedriver');
// 获取Chrome浏览器配置
const options = new chrome.Options();
// 浏览器参数设置
const arguments = [
'--disable-web-security', // 关闭浏览器安全设置,如:浏览器跨域
'--incognito', // 使用隐身模式
'--user-data-dir=/Users/shang/Downloads/chromeincognito' // 设置当前用户的工作目录
]
options.addArguments.apply(options, arguments);
(async () => {
const driver = await new Builder()
.setChromeOptions(options)
.forBrowser('chrome')
.setChromeService(service)
.build();
driver.getSession()
await driver.manage().setTimeouts({ implicit: 500 });
// 退出浏览器
// driver.quit()
})();
远端服务
启动远端服务
➜ webdriver ls
chromedriver index.js node_modules package-lock.json package.json
➜ webdriver ./chromedriver
Starting ChromeDriver 104.0.5112.79 (3cf3e8c8a07d104b9e1260c910efb8f383285dc5-refs/branch-heads/5112@{#1307}) on port 9515
Only local connections are allowed.
Please see https://chromedriver.chromium.org/security-considerations for suggestions on keeping ChromeDriver safe.
ChromeDriver was started successfully.
添加IP白名单
➜ webdriver ./chromedriver --allowed-ips='0.0.0.0'
Starting ChromeDriver 104.0.5112.79 (3cf3e8c8a07d104b9e1260c910efb8f383285dc5-refs/branch-heads/5112@{#1307}) on port 9515
Remote connections are allowed by an allowlist (0.0.0.0).
Please see https://chromedriver.chromium.org/security-considerations for suggestions on keeping ChromeDriver safe.
ChromeDriver was started successfully.
其他配置
➜ webdriver ./chromedriver --help
Usage: ./chromedriver [OPTIONS]
Options
--port=PORT port to listen on
--adb-port=PORT adb server port
--log-path=FILE write server log to file instead of stderr, increases log level to INFO
--log-level=LEVEL set log level: ALL, DEBUG, INFO, WARNING, SEVERE, OFF
--verbose log verbosely (equivalent to --log-level=ALL)
--silent log nothing (equivalent to --log-level=OFF)
--append-log append log file instead of rewriting
--replayable (experimental) log verbosely and don't truncate long strings so that the log can be replayed.
--version print the version number and exit
--url-base base URL path prefix for commands, e.g. wd/url
--readable-timestamp add readable timestamps to log
--enable-chrome-logs show logs from the browser (overrides other logging options)
--allowed-ips=LIST comma-separated allowlist of remote IP addresses which are allowed to connect to ChromeDriver
--allowed-origins=LIST comma-separated allowlist of request origins which are allowed to connect to ChromeDriver. Using `*` to allow any host origin is dangerous!
调用远端服务
const { Builder } = require('selenium-webdriver');
const chrome = require('selenium-webdriver/chrome');
/**
* 获取驱动服务
* 浏览器驱动启动后,会挂载到一个端口上我们可以通过HTTP服务访问、操作浏览器
*/
// const service = new chrome.ServiceBuilder('/Users/shang/Code/github/webdriver/chromedriver');
// 获取Chrome浏览器配置
const options = new chrome.Options();
// 浏览器参数设置
const arguments = [
'--disable-web-security', // 关闭浏览器安全设置,如:浏览器跨域
'--incognito', // 使用隐身模式
'--user-data-dir=/Users/shang/Downloads/chromeincognito' // 设置当前用户的工作目录
]
options.addArguments.apply(options, arguments);
(async () => {
const driver = await new Builder()
.usingServer("http://127.0.0.1:9515")
.setChromeOptions(options)
.forBrowser('chrome')
// .setChromeService(service)
.build();
driver.getSession()
await driver.manage().setTimeouts({ implicit: 500 });
// 退出浏览器
// driver.quit()
})();
配置端到端准备
以 selenium-webdriver 为例
安装依赖
浏览器安装
略过,chrome , Firefox, Edge
安装浏览器驱动
根据浏览器下载驱动
Chrome 安装
下载地址: https://chromedriver.chromium.org/downloads
104 版本平台区分
Linux: https://chromedriver.storage.googleapis.com/104.0.5112.79/chromedriver_linux64.zip
Mac64: https://chromedriver.storage.googleapis.com/104.0.5112.79/chromedriver_mac64.zip
Mac64M1: https://chromedriver.storage.googleapis.com/104.0.5112.79/chromedriver_mac64_m1.zip
配置
# 创建工作目录
npm inint -y
# 安装 selenium-webdriver ,当前为 4.4.0 版本
npm install --save-dev selenium-webdriver
示例:启动浏览器
Chrome 浏览器相关的参数,
https://blog.csdn.net/swe_ling/article/details/125811499?spm=1001.2014.3001.5502
const { Builder } = require('selenium-webdriver');
const chrome = require('selenium-webdriver/chrome');
/**
* 获取驱动服务
* 浏览器驱动启动后,会挂载到一个端口上我们可以通过HTTP服务访问、操作浏览器
*/
const service = new chrome.ServiceBuilder('/Users/shang/Code/github/webdriver/chromedriver');
// 获取Chrome浏览器配置
const options = new chrome.Options();
// 浏览器参数设置
const arguments = [
'--disable-web-security', // 关闭浏览器安全设置,如:浏览器跨域
'--incognito', // 使用隐身模式
'--user-data-dir=/Users/shang/Downloads/chromeincognito' // 设置当前用户的工作目录
]
options.addArguments.apply(options, arguments);
(async () => {
const driver = await new Builder()
.setChromeOptions(options)
.forBrowser('chrome')
.setChromeService(service)
.build();
driver.getSession()
await driver.manage().setTimeouts({ implicit: 500 });
// 退出浏览器
// driver.quit()
})();
功能操作
打开浏览器
打开浏览器或者 Tab 页
https://www.selenium.dev/documentation/webdriver/browser/windows/
driver.switchTo().newWindow()
创建多个Window
// 打开并切换到新的窗口
const windowHandle = await driver.switchTo().newWindow('window');
await driver.navigate().to('http://0.0.0.0:80')
// 打开并切换到新的窗口
const otherWindowHandle = await driver.switchTo().newWindow('window');
await driver.navigate().to('http://0.0.0.0:8080')
... ...
// 切换到 windowHandle 窗口
driver.switchTo().window(windowHandle);
// 切换到 otherWindowHandle 窗口
driver.switchTo().window(otherWindowHandle);
多个Tab页操作
创建新的Tab页,打开指定链接,并返回该Tab页的操作 句柄 (Tab标识符)
https://www.selenium.dev/documentation/webdriver/browser/windows/#switching-windows-or-tabs
async function getTap (url) {
await driver.switchTo().newWindow()
await driver.navigate().to(url)
const qqlWindowHandle = await driver.getWindowHandle();
return qqlWindowHandle
}
完整示例
// index.js
const { Builder } = require('selenium-webdriver');
const chrome = require('selenium-webdriver/chrome');
/**
* 获取驱动服务
* 浏览器驱动启动后,会挂载到一个端口上我们可以通过HTTP服务访问、操作浏览器
*/
const service = new chrome.ServiceBuilder('/Users/shang/Code/github/webdriver/chromedriver');
// 获取Chrome浏览器配置
const options = new chrome.Options();
options.setChromeLogFile('/Users/shang/Downloads/chrome.log');
//
const arguments = [
'--disable-web-security', // 关闭浏览器安全设置,如:浏览器跨域
// '--incognito', // 使用隐身模式
// '--user-data-dir=/Users/shang/Downloads/chromeincognito' // 设置当前用户的工作目录
]
options.addArguments.apply(options, arguments);
(async () => {
// 创建一个浏览器驱动
const driver = await new Builder()
.setChromeOptions(options)
.forBrowser('chrome')
.setChromeService(service)
.build()
async function getTap (url) {
await driver.switchTo().newWindow()
await driver.navigate().to(url)
const qqlWindowHandle = await driver.getWindowHandle();
return qqlWindowHandle
}
const qqWindowHandle = await getTap('https://www.qq.com')
const baiduWindowHandle = await getTap('https://www.baidu.com')
// 等待2秒
await new Promise((resolve) => { setTimeout(resolve, 2000) })
// 切换到 QQ 所在窗口
await driver.switchTo().window(qqWindowHandle);
// 执行JavaScript方法 所在窗口
await driver.executeScript(function (handle) {
console.log('output handle qq', handle, window.document.title)
}, qqWindowHandle)
// 等待2秒
await new Promise((resolve) => { setTimeout(resolve, 2000) })
// 切换到 百度 所在窗口
await driver.switchTo().window(baiduWindowHandle);
// 执行JavaScript方法 所在窗口
await driver.executeScript(function (handle) {
console.log('output handle baidu', handle, window.document.title)
}, qqWindowHandle)
await new Promise((resolve) => { setTimeout(resolve, 2000) })
// 退出浏览器
driver.quit()
})();
执行测试任务
node index.js
示例日志结果
[12369:259:0822/115042.778808:INFO:CONSOLE(306)] "每一个星球都有一个驱动核心,
每一种思想都有影响力的种子。
感受世界的温度,
年轻的你也能成为改变世界的动力,
百度珍惜你所有的潜力。
你的潜力,是改变世界的动力!
", source: https://pss.bdstatic.com/r/www/cache/static/protocol/https/global/js/all_async_search_098edf7.js (306)
[12369:259:0822/115042.778926:INFO:CONSOLE(306)] "%c百度2022校园招聘简历投递:https://talent.baidu.com/external/baidu/campus.html color:red", source: https://pss.bdstatic.com/r/www/cache/static/protocol/https/global/js/all_async_search_098edf7.js (306)
[12369:259:0822/115046.448069:INFO:CONSOLE(4)] "output handle qq CDwindow-2F3C312D42DF8A638BA8C5322A85B541 腾讯首页", source: (4)
[12369:259:0822/115049.493448:INFO:CONSOLE(4)] "output handle baidu CDwindow-2F3C312D42DF8A638BA8C5322A85B541 百度一下,你就知道", source: (4)
抛砖引玉
实现自动化测试
-
把要使用的方法通过 Demo 挂载到全局。
-
实现多用户多场景登录。
- 多tab页,
- 多window窗口,
- 多浏览器,
- 多设备,[ WebDriver Remote Server ]
-
通过调用 Demo 上挂载的 全局变量 实现具体的功能操作。