在各种浏览器中以各种分辨率测试长Web表单不仅非常必要,而且第三次或第四次测试是非常无聊且集中的过程。 因此,这正是它本身要求自动化的领域。 这就是我们所做的。
在有关Habr的这篇文章中,我们将介绍我们使用量角器,Zalenium和Selenium-grid工具测试大屏幕的经验。 我们如何逐步引入这些用于自动UI测试的工具,以及必须克服的困难。

我们创建并维护一个拥有7,000名活跃用户的系统。 他们最常使用以下浏览器:

以及以下屏幕分辨率:

每次发布新版本后,您都需要检查这些版本在这些浏览器和权限中的性能。
为了更好地理解UI测试在我们的情况下通常如何工作,请考虑一个简单的情况:测试密码恢复应用程序的功能。 因此,有两页。 在一个上,您需要指定一个用户名或邮件,其中一封信件将带有更改密码的链接。 发送完应用程序后,用户进入页面,确认一切顺利。
密码找回表
成功提交申请后重定向到的页面以简化形式测试此机制如下所示:

与代码相同的脚本:
it(' ', async function(): Promise<boolean | void> { await browser.get(browser.baseUrl); await element(by.name('EmailOrLogin')).sendKeys(userLogin); await element(by.buttonText('')).click(); const screenshot = await browser.takeScreenshot(); const canonicalScreenshotPath = < >; await compareScreenshot(screenshot, canonicalScreenshotPath); });
如您所见,测试代码看起来非常简单,实际上是重复了框图上显示的内容。
现在,我们展示了哪些工具可以方便地在不同的屏幕分辨率下实施该方案,以及我们遇到了哪些困难。
所选工具箱
从铬开始
对于测试自动化,我们选择了Protractor,这是一个用于测试Angular应用程序的e2e框架。 我们的应用程序仅在Angular上。 使用量角器,我们进行了两种类型的测试:
- 关于常规功能:打开一个应用程序提交表单,填写数据并发送一个应用程序,此后我们验证是否已重定向到所有应用程序的注册表。
- 屏幕截图测试:量角器使您可以随时拍摄屏幕截图。 使用一个单独的蓝收库,我们比较了两个屏幕截图:一个参考和一个真实的。 如果它们不匹配,则会立即创建一个屏幕快照,在屏幕快照上可以看到所有差异,就像在Git中一样。
例如,如果您继续解析上述示例。
带有无效链接消息的屏幕截图
参考和当前屏幕截图中的差异(按钮的文本和布局)以淡紫色突出显示如果页面包含动态变化的数据(例如日期或订单号),则需要屏蔽它们-这种功能在blue-harvest库中。 否则,比较屏幕截图将产生负面结果。
添加FF和其他权限
随着时间的流逝,我们对现有的UI测试系统的要求不断提高:
- 不仅在Chrome中运行测试,还在FF中运行测试,
- 进行屏幕截图测试不是针对一种分辨率,而是针对最受欢迎的分辨率,
- 并行运行测试。
因此,让我们在Chrome和FF中并行运行测试。
为此,在量角器功能配置中,将其替换为:
multiCapabilities: [ { shardTestFiles: true, maxInstances: 2, browserName: 'chrome' }, { shardTestFiles: true, maxInstances: 2, browserName: 'firefox' } ]
此处所有内容都是显而易见的,每个设置都应对此负责。 只值得关注
shardTestFiles: true
/** * If this is set to be true, specs will be shared by file (ie all files to be run by this set of capabilities will run in parallel). * Default is false. */
使用此标志,我们可以在multiCapabilities中指定的所有浏览器中并行启动所有规范。
specs参数隐藏在specs一词下,该词确定使用哪个模板搜索带有测试的文件。
exports.config = { ... specs: ['./e2e/**/*.spec.ts'], ... }
将所有测试分为几个规格文件的理论看起来很合逻辑。 并发对它们起作用(例如,为应用程序的每个功能创建一个规范文件)。
此外,在量角器中可以突出显示套件。
exports.config = { ... suites: { suite01: './e2e/**/suite01.*.spec.ts', suite02: './e2e/**/suite02.spec.ts', suite03: './e2e/**/suite03.spec.ts' }, ... }
从配置的这一部分可以看到,启动一个套件时,仅从一个规范文件运行测试。 如果您只想为应用程序的一部分运行测试,这可能很有用。
对于以不同分辨率测试应用程序,我们采用了以下方法。 作为实验权限,选择了最受欢迎的一种:1920x1080、1366x768、1440x10900、768x1024。 运行每个测试时,最初将执行所有必要的操作,然后执行一系列屏幕截图检查。

我们连接IE和全尺寸屏幕截图
不幸的是,我们获得的屏幕截图测试仅在页面的最初可见部分有效。 并且,如果页面上存在滚动,则下面的所有内容对于经过的版式仍未开发。
除此之外,我们还需要支持尚未针对我们的测试设计的IE。 我们开始寻找在IE中运行测试并拍摄完整屏幕截图的适当机会。

我们确定了两个解决方案:
Zalenium和
Selenium-Grid 。 我们省略了对其中一个拥有什么的描述,并告诉他们在任何一种解决方案中都发现/未发现的内容。
Zalenium :此解决方案在Docker容器中运行,并且在主容器之后又出现了N个其他容器-启动浏览器。 允许您在docker
docker run
期间指定screenWidth,screenHeight并获取屏幕尺寸,例如1920x6000。 不支持IE。
两种浏览器,屏幕尺寸为1920x6000Selenium-grid: IE中的测试非常容易开始。
缺点:无法设置任何大小的浏览器窗口大小。
总计:Zalenium + Selenium-grid我们选择了一堆Zalenium + Selenium-grid:通过Zalenium,决定在Chrome和FF中运行测试,并通过Selenium-grid检查IE中应用程序的最低性能。
在过程中遇到什么有趣的事情
1.使用formControlName作为元素定位器使用formControlName上的搜索,您可以轻松地在表单上搜索必填字段,并用测试数据填充它们。 由formControlName定位的不是内置的,但添加起来很容易:
exports.config = { ... onPrepare() { require('ts-node').register({ project: 'e2e/tsconfig.e2e.json' }); jasmine.getEnv().addReporter(new specReporter({ spec: { displayStacktrace: true } })); addFormControlNameLocator(protractor); } ... } function addFormControlNameLocator(protractor) { protractor.by.addLocator('formControlName', function(value, optParentElement) { var using = optParentElement || document; return using.querySelectorAll('[formControlName="' + value + '"]'); }); }
2.量角器中全局和本地安装的webdriver-manager的工作差异在系统中安装Protractor时(官方文档建议在全球范围内安装Protractor),除了测试框架本身外,我们还获得了已安装的webdriver-manager,它为浏览器提供了运行测试的驱动程序,从而解决了问题之一。
转到项目文件夹并执行webdriver-manager更新后,将下载Chrome,FF,IE的驱动程序。 之后,在开始测试时,他们捕获了错误:
No update-config.json found. Run 'webdriver-manager update' to download binaries.
我们意识到,如果在npm脚本中打包webdriver-manager更新,该错误就会消失:
{ ... scripts:{ “webdriver-update”: “webdriver-manager update” } ... }
并通过
npm run webdriver-update
,驱动程序源和上述update-config.json都进入项目文件夹。
3.通过docker-compose运行ZaleniumZalenium文档随附docker
docker run
命令和docker-compose文件的示例。 一切都像魔术般起飞。 我们通过docker-compose文件启动时遇到的唯一问题
/var/run/docker.sock is not a valid windows path
。 解决方案在
这里 。
4.量角器的元素可见性在我们的实验过程中,有一段时间我们面临着刺穿页面上某些菜单的任务,即 转到菜单的每个页面并截图。

在处理了列表的第一个元素之后,测试开始下降,抛出一个错误,即在某些坐标上没有可单击的东西。 事实证明,无论列表中的所有元素都是最初选择的,在我们真正看不见它们之后,它们在量角器的眼中都消失了。
我们通过设置足够的屏幕宽度解决了该问题,从而使菜单在单击其下一个元素之前重新出现。
5. IE(Selenium-grid)中的分辨率更改您还记得,我们在Chrome和FF中微调了屏幕分辨率的变化。 在IE中,我们仅捕获了以下错误:
Failed: java.io.IOException: Server returned HTTP response code: 405 for URL: http://localhost:21800/session/8d14426d-6483-4bbf-90b3-2a3ed46ebe9b/window/size
。
经过长时间的调试,有可能发现错误恰好在代码尝试执行的那一刻发生:
browser.driver.manage().window().setSize(x, y)
。 如果尝试执行
browser.driver.manage().window().setPosition(x, y)
,则将捕获相同的错误,仅大小会更改为位置。 这导致我们这样一个事实,即在IE中运行测试时无法控制屏幕分辨率。 解决此问题的方法是拐杖,您必须用拐杖覆盖代码,以免在运行IE时更改分辨率\位置。
6. Zalenium和WebSocket在本地收集了所有障碍之后,决定将Zalenium纳入公司基础架构。 打开容器,注册DNS,现在每个人都可以在Zalenium中运行测试,只需在其Protractor配置中指定容器的路径即可。 美丽吧? 但事实确实如此。
在这种情况下,一切都已部署到Linux机器上,使用Nginx作为服务器。 装有Zalenium的容器没有问题,随后又有N个容器用于启动浏览器,但是...无法与其建立连接。 很容易发现父容器正试图通过WebSocket协议与浏览器的容器进行通信,而Nginx默认情况下无法做到这一点。 治疗非常简单。
location / { proxy_pass some_url; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection “upgrade”; }
9.硒网格的启动要运行Selenium-Grid,我们需要:
- 硒服务器
- IE驱动程序,可通过webdriver-manager更新--ie32轻松获得。
服务器启动:
java -jar selenium-server-standalone.jar -role hub -hubConfig selenium-server-config.json
selenium-server-config.json { "host": "127.0.0.1", "maxSessions": 5, "port": 4445, "cleanupCycle": 5000, "timeout": 300000, "newSessionWaitTimeout": -1, "servlets": [], "prioritizer": null, "capabilityMatcher": "org.openqa.grid.internal.utils.DefaultCapabilityMatcher", "throwOnCapabilityNotPresent": true, "nodePolling": 180000, "platform": "WINDOWS" }
启动IE驱动程序:
java -Dwebdriver.ie.driver=< > -jar selenium-server-standalone.jar -role node -nodeConfig .\\ie-driver-config.json
ie-driver-config.json { "capabilities": [ { "browserName": "internet explorer", "maxInstances": 1, "platform": "WINDOWS", "webdriver.ie.driver": "C:/Program Files (x86)/Internet Explorer/iexplore.exe" } ], "cleanUpCycle": 2000, "timeout": 30000, "port": -1, "role": "node", "hub": "http://127.0.0.1:4445/grid/register/", "register": true, "maxSessions": 5 }
启动服务器时和驱动程序的集线器URL'e中,请注意使用相同的端口。 作为量角器配置中的seleniumAddress,我们使用
http://127.0.0.1:4445/wd/hub
。
结论
因此,我们解决了任务,每次发布新版本后,我们都可以检查它们在这些浏览器和分辨率下的性能。
如何将测试集成到工作流中
重要的是要理解,仅仅提高整个基础架构来运行测试和编写测试还不够。 您需要考虑如何在日常生活中使用它们。
我们没有在CI中实施UI测试,因为 它们的执行时间足够长,以允许自己等待每次构建的执行。
要测试应用程序的本地版本或安装在其中一个测试环境(内部或客户)上,只需在Protractor'a配置中更改baseUrl就足够了。 因此,开发人员和测试人员都可以运行测试。
开发人员-在开发新功能的过程中,例如需要针对应用程序的本地版本运行测试时。 质量检查专家-例如,在部署到产品后进行烟雾测试,或在进行一系列重构后在顶部进行检查。
最后,我们要强调:- 请记住,UI测试不会使您免于进行详细的手动测试的麻烦。 自动化只能覆盖整个区域。
- 明智地使用自动化,主要用于烟雾测试。 涵盖所有内容是没有意义的-它既昂贵又难以保持最新
- 简单地写。 如果您的UI测试看起来很复杂,则说明您做错了。 打败并按照指示使用(请参阅第2点)
我们相信,轻松完成UI测试自动化是好的。 因此,请在评论中与我们分享您的观察和成功的工具。
来自我们的有用链接: