使⽤selenium 操作 electron 应⽤

背景

近期的⾃动化测试项⽬中有个关于测试内部IM通信软件的需求,在了解到各个客户端的相应技术栈实现以后,在mac中的应⽤使⽤的是electron 技术,我们也对相应的技术进⾏调研,此⽂记录⼀下在关于electron应⽤的⾃动化测试。

electron 简介

electron利⽤Chromium和Node.js,为使⽤ JavaScript,HTML 和 CSS 构建跨平台的桌⾯应⽤程序,可以实现代码⼀次编译,多端运⾏的效果,可以⽣成mac app, windows exe等,但是它编译出来的⽂件由于包含Chromium,所以体积⼀般会⽐较⼤。

使⽤selenium操作Chrome浏览器

先确定⼀下系统中的chrome浏览器的版本,由于selenium 操作Chrome浏览器需要使⽤到ChromeDriver,不同版本的Chrome对应着不同的ChromeDriver,如果不对应的话可能会失败。

然后到
ChromeDriver - WebDriver for Chrome - Downloads 这⾥下载对应的ChromeDriver,国内的⽤户如果访问不了的话可以使⽤淘宝镜像源
https://npm.taobao.org/mirrors/chromedriver

from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import time
driver = webdriver.Chrome()
# webdriver.Chrome 在初始化的时候也可以指定chromedriver路径,这种对于系统中有多个版本的
chromedriver⾮常有⽤
# driver = webdriver.Chrome(executable_path="/Users/qihoo/Desktop/chromedriver94")
driver.get("https://www.google.com")
assert "Google" in driver.title
elem = driver.find_element_by_name("q")
elem.clear()
elem.send_keys("360")
elem.send_keys(Keys.RETURN)
assert "No results found." not in driver.page_source
driver.close()

使⽤selenium操作electron应⽤

想要使⽤ selenium 操作electron app, ⾸先要确认的是该app使⽤的是哪个版本的Chromium那么该如何确认electron应⽤的Chromium版本号呢?

function createWindow () {
   const win = new BrowserWindow({
      width: 800,
      height: 600,
      webPreferences: {
           preload: path.join(__dirname, 'preload.js'),
           nodeIntegration: true, contextIsolation: false //加上这个配置才可以在控制台使⽤process对象
         }
     })

selenium.common.exceptions.SessionNotCreatedException: Message: session not created:
This version of ChromeDriver only supports Chrome version 94
Current browser version is 80.0.3987.86 with binary path /Applications/360家.app/Contents/MacOS/360家

我们使⽤electron来创建⼀个mac 应⽤,代码使⽤官⽅提供的示例,

但是打包我这⾥和官⽅的不太⼀样。

mkdir electroltest
cd electrontest
npm init -y

npm install electron electron-packager electron-installer-dmg --save

    {
     "name": "electroltest",
     "version": "1.0.0",
     "description": "",
     "main": "main.js", //修改为main.js
     "scripts": {
          "test": "echo \"Error: no test specified\" && exit 1",
          "start": "electron .", // 添加⼀个启动指令
          "build": "electron-packager .", //添加打包指令
          "dmg": "electron-installer-dmg ./electroltest-darwin-x64/electroltest.app/
          electroltest" // 添加⽣成dmg指令
     },
     "author": "",
     "license": "ISC",
     "dependencies": {
          "electron": "^15.1.2",
          "electron-installer-dmg": "^3.0.0",
          "electron-packager": "^15.4.0"
          }
     }

const { app, BrowserWindow } = require('electron')
const path = require('path')
function createWindow () {
    const win = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
        preload: path.join(__dirname, 'preload.js')
    }
  })
  win.loadFile('index.html')
}
app.whenReady().then(() => {
    createWindow()
    app.on('activate', () => {
        if (BrowserWindow.getAllWindows().length === 0) {
         createWindow()
       }
    })
})
app.on('window-all-closed', () => {
    if (process.platform !== 'darwin') {
      app.quit()
    }
})

<!DOCTYPE html>
<html>
<head>
        <meta charset="UTF-8">
        <title>Hello YYX!</title>
        <meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafeinline';"/>
</head>
<body>
        <h1>Hello 360 质量效能 !</h1>
        <p>
                We are using Node.js <span id="node-version"></span>,
                Chromium <span id="chrome-version"></span>,
                and Electron <span id="electron-version"></span>.
        </p>
</body>
</html>

window.addEventListener('DOMContentLoaded', () => {
        const replaceText = (selector, text) => {
            const element = document.getElementById(selector)
            if (element) element.innerText = text
        }
        for (const type of ['chrome', 'node', 'electron']) {
           replaceText(`${type}-version`, process.versions[type])
        }
})

写完代码以后可以使⽤npm run start 看下效果,是否可以正常的显示electron应⽤

如果正常显示则可以进⾏打包操作

  1. 打包electron应⽤
npm run build #这⾥是由于在package.json中定义了build指令,如果没有定义也可以运⾏ npxelectron-packager

npm run dmg # 同build指令,这⾥也可以使⽤ npx electron-installer-dmg ./electroltestdarwin-x64/electroltest.app/ electroltest

接下来我们来写⼀个简单的测试,就是打开app,查看⼀下html,再跳转到google,输⼊⼀些⽂字,再点击搜素按钮

/Applications/electroltest.app/Contents/MacOS/electroltest

自己****根据安装的位置进行相应的修改

  1. 安装 selenium
pip install selenium

# -*- coding: utf-8 -*-
"""
-------------------------------------------------
     File Name:eletest
     Description : electrol⾃动化测试
     Author : qihoo
     date:2021/10/14
-------------------------------------------------
"""
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import time
options = webdriver.ChromeOptions()
options.binary_location = "/Applications/electroltest.app/Contents/MacOS/electroltest"
driver = webdriver.Chrome(chrome_options=options)
time.sleep(3)
print(driver.page_source)
driver.get("http://www.google.com")
elem = driver.find_element_by_name("q")
elem.clear()
elem.send_keys("360") # 这⾥也可以输⼊中⽂
elem.send_keys(Keys.RETURN)
driver.close()
driver.quit()

这⾥⽐较重要的是定义 options.binary_location 需要设置为 electron 应⽤的路径

使⽤selenium操作已经打开的electron应⽤

以上⽅式我们其实是重新打开了某个app, 但是更多的时候,我们是期望测试⼀个已经打开的app,试想⼀下如下的场景,某个app需要登录,登录的⽅式⼜⽐较复杂,扫码登录或者短信登录,或者有验证码,但是如果成功登录以后,⼀段时间以后再次打开就不会进⼊到登录界⾯,此时,我们不希望每次运⾏⽤例的时候,都重新登录,这时,我们就需要使⽤ selenium 来测试⼀个打开着的应⽤。

/Applications/electroltest.app/Contents/MacOS/electroltest --remote-debugging-port=9222

options = webdriver.ChromeOptions()
options.add_experimental_option("debuggerAddress", "127.0.0.1:9222") # 设置
debuggerAddress
driver = webdriver.Chrome(chrome_options=options)

总结

使⽤ selenium 测试 electron 应⽤的测试有⼏个总结

找到对应的 chromedriver;

通过 binary_location 参数设置app路径;

对于测试打开着的app, 需要在app启动的时候添加远程调试参数 --remote-debugging-port

参考文献

https://selenium-python-zh.readthedocs.io/en/latest/index.html#

https://www.sqlpy.com/blogs/894258980