NightwatchJS 和 WebdriverIO 有什么区别?
What is the difference between NightwatchJS and WebdriverIO?
如标题所述,Nightwatch.js 和 Webdriver.io 有什么区别?
它们似乎具有相同的语法并且做几乎相同的事情。它们有何不同?
我需要在它们之间做出选择。
我已经多次使用这些工具编写了一个测试套件。
Webdriver.io 允许您编写测试用例 "from scratch" 并且可以很好地控制报告,例如,使用 slack npm 和其他包与 slack 集成。您需要了解或快速学习 node.js。除了与桌面浏览器配合良好外,它还与 Appium、Android Studio 和 Xcode 很好地集成,因此您可以 运行 在 Android 模拟器和 iOS 本地模拟器。您将需要安装这些东西并编写一些代码来告诉 Appium 使用哪些驱动程序,以及 select 功能等。
Nightwatch 是一个相当广泛的解决方案,它使用迭代器在测试失败时自动重试最多 3 次。 Nightwatch 对与 SauceLabs 等 VM 工具的集成提供了不错的支持,因此理论上您可以 运行 针对 700 多种不同 platform/browser/version 组合的测试用例 而无需编写代码来管理每个驱动程序 . Nightwatch 为您处理启动和关闭 selenium。虽然这最后一个听起来非常令人印象深刻,但实际上要达到和维持该测试覆盖率水平需要做大量工作。 Nightwatch 还具有相当内置的关注点分离,允许您定义自定义命令并在您的基础测试用例或单独测试中需要它们。您可以模块化测试的某些部分并导入它们,这样您就不必不断地重新编写登录测试以用于多种情况。此外,您可以使用自定义命令将 select 或作为键值对导入。
用过每一个我会这样总结:
webdriver.io: 如果您正在寻找更多的控制,一个非常自定义的解决方案并且您不需要迭代器,并且您有信心知道足以为 select 浏览器驱动程序、设置功能编写代码,并且您希望对报告进行自定义控制。
Nightwatch: 如果你想快速开始编写测试,要知道 运行 它们相对于特定的 platforms/browsers/versions 和将仍然允许您通过编写自定义命令来扩展测试的显着灵活性。
现在的另一个选择是 Dalek.js,它具有 Nightwatch 的简单脚本创建功能,但没有所有花里胡哨的东西。
在 运行ning nightwatch 之前,您可以在 Magellan.json 文件中配置浏览器,然后当您 运行 测试时调用浏览器,或一组浏览器 ( a "profile") 作为命令行参数,因此:
对于本地浏览器:
./node_modules/.bin/magellan --serial --browsers=chrome,firefox
假设您已经设置了一个 saucelabs 帐户并添加了您的用户名和访问密钥,您可以像这样调用浏览器配置文件:
./node_modules/.bin/magellan --serial --profile=myBrowsers
假设您在 Magellan.json 文件中设置了一个名为 myBrowsers 的配置文件,如下所示:
{
"profiles": {
"myBrowsers": [
{ "browser": "chrome_46_OS_X_10_10_Desktop" },
{ "browser": "firefox_42_Windows_2012_R2_Desktop" },
{ "browser": "safari_8_OS_X_10_10_Desktop" },
{ "browser": "safari_7_OS_X_10_9_Desktop" },
{ "browser": "safari_9_OS_X_10_11_Desktop" },
{ "browser": "IE_10_Windows_2012_Desktop" },
{ "browser": "IE_11_Windows_2012_R2_Desktop" },
{ "browser": "chrome_45_OS_X_10_8_Desktop" },
{ "browser": "chrome_45_OS_X_10_9_Desktop" },
{ "browser": "chrome_45_OS_X_10_10_Desktop" },
{ "browser": "chrome_45_OS_X_10_11_Desktop" },
{ "browser": "chrome_46_OS_X_10_10_Desktop" },
{ "browser": "chrome_45_Windows_10_Desktop" },
{ "browser": "chrome_45_Windows_2003_Desktop" },
{ "browser": "chrome_45_Windows_2008_Desktop" },
{ "browser": "chrome_45_Windows_2012_Desktop" },
{ "browser": "chrome_45_Windows_2012_R2_Desktop" },
{ "browser": "chrome_46_Windows_10_Desktop" },
{ "browser": "chrome_46_Windows_2003_Desktop" },
{ "browser": "chrome_46_Windows_2008_Desktop" },
{ "browser": "chrome_46_Windows_2012_Desktop" },
{ "browser": "chrome_46_Windows_2012_R2_Desktop" },
{ "browser": "firefox_42_OS_X_10_9_Desktop" },
{ "browser": "firefox_42_Windows_2012_R2_Desktop" },
{ "browser": "android_4_4_Linux_Samsung_Galaxy_S4_Emulator", "orientation": "portrait" },
{ "browser": "ipad_8_4_iOS_iPad_Simulator", "orientation": "landscape"},
{ "browser": "ipad_8_4_iOS_iPad_Simulator", "orientation": "landscape"},
{ "browser": "ipad_9_0_iOS_iPad_Simulator", "orientation": "landscape"},
{ "browser": "ipad_9_0_iOS_iPad_Simulator", "orientation": "portrait"},
{ "browser": "ipad_9_1_iOS_iPad_Simulator", "orientation": "landscape"},
{ "browser": "ipad_9_1_iOS_iPad_Simulator", "orientation": "portrait"},
{ "browser": "iphone_9_1_iOS_iPhone_Simulator", "orientation": "portrait"},
{ "browser": "iphone_9_1_iOS_iPhone_Simulator", "orientation": "landscape"}
]
}
}
一些更有用的(可选的)命令行参数:
切换 --serial 参数会导致测试执行被序列化,并带来更详细的测试体验,您可以在其中查看 return 在 运行 期间编辑的错误。 运行 等待测试完成也需要更长的时间。
添加 --sauce 参数一旦您的测试用例适用于本地计算机上存在的浏览器,您就可以利用 Sauce Labs 支持的(当前)760 种浏览器。继续将其粘贴到终端并点击 return:
./node_modules/.bin/magellan --serial --list_browsers
对于每个 device/browser 您想要测试的,您只需将列表添加到
执行脚本时,在 --browser= 之后将命令行选项列复制粘贴为逗号分隔值。注意:当 运行ning 没有 --sauce 时,你可以只使用
--browser=chrome 或 --browser=chrome,firefox
BREAKING IT DOWN:
使用不带 --sauce 但带 --serial 的 nightwatch 是一个很好的入门方式。
在你的脚本上工作,直到你验证了你想要检查的东西,当你确信所有的测试都应该通过时,运行 与 sauce labs 和你想要测试的主要浏览器一起做。一旦您确信涵盖了主要浏览器,您可以 运行 不用 --serial 来减少 运行 时间(在 Sauce Labs 上很有用,这会花钱)。
但足够的传教,你可以在这里找到你需要的关于 Saucelabs 的东西:
https://wiki.saucelabs.com/display/DOCS/The+Sauce+Labs+Cookbook+Home
对于 Nightwatch 的样板示例来执行规范的 hello world:try this boilerplater
更新:人们提出的几点以及自发布此消息后我想到的几点。
Webdriver.io:
由于没有迭代器,因此在测试执行期间从失败中恢复的能力较弱,这意味着失败更加明确。因为这完全是异步的,所以您可能会很头疼地追踪失败的确切根源。 您可能最终还必须为您创建的任何数据创建单独的拆卸脚本,以避免执行期间发生数据冲突。
Nightwatch.js:
由于迭代器允许您重试,因此您通常能够找到脚本失败的地方。这可以让您更快地找到缺陷,而不是专注于脚本失败的原因。关闭您的个人脚本也更容易。
更新 2:
Nightwatch 较短的测试是 useful/encouraged。因为迭代器在每次迭代执行前立即将测试文件读入内存,所以您可以非常直接地在迭代执行之间编辑测试。让我换一种说法:
您的守夜人套件:
test_1 starts
test_1 FAIL // because you made a trivial error in your test case
test-2 starts // while it is running, you make the change, save it
test-2 PASS
test_1 starts // the iteration starts * with your change! *
test_1 PASS
============= Suite Complete =============
Status: PASSED
Runtime: 2m 48.3s
Total tests: 2
Successful: 2 / 2
1 test(s) have retried: 1 time(s)
另一方面,使用 node/webdriver.io 设置 Slack webhooks 很容易。这意味着您可以将 node/webdriver.io 测试设置为在完成时向 Slack 报告。客户对此表示赞赏,因为在构建完成后,他们很快就会看到自动化的结果,例如:
✅ [client/product 名称的自动测试] Sprint ##.#.# 通过 [服务器 URL 或 IP 地址] 使用 OS X Firefox 59.0.2
❌ 使用 OS X Firefox 59.0.2[[client/product 名称的自动测试] Sprint ##.#.# 在 [服务器 URL 或 IP 地址] 上失败
更新 3(2017 年 8 月 6 日)
又花了一年半的时间每天都与这两者打交道,我想补充以下几点。
有类似数量的 NPM 包与每个包集成,但您会注意到关于 Nightwatch (4x) 的 Whosebug 问题要多得多。我相信这是因为 Webdriver.io 更像是一种自己动手的自动化测试方法 [这是我的观点,我欢迎 feedback/pushback]。使用它的人不会对如何使用它有疑问,他们会有关于技术的具体问题。
对于拥有丰富的 Selenium IDE 和扎实的 javascript 经验的人来说,Nightwatch 是一个更好的切入点。它有很多开箱即用的有用解决方案。我与 Dalek 的一点经验表明这同样是一个不错的选择。
具有更多 javascript 以及一些面向对象编程和 unix 经验的人可能会发现 Webdriver.io 更好。正如我目前正在做的那样,这只是构建您自己的自定义框架的一个很好的选择。如果您可以设想您希望如何进行初始化、流程控制和报告工作,并且愿意投入大量资金,那就很合适了。
下面有人问我更喜欢哪个,到目前为止,我更喜欢 Webdriver.io 进行广泛的 e2e 测试。虽然我经常为基于我们平台构建的大多数客户工作使用个性化的 Nightwatch 存储库,但随着我构建自己的 Webdriver.io 解决方案,这种情况在不久的将来可能会发生变化。
更新 4(2018 年 5 月 2 日)
已更新以明确控制 Selenium 和浏览器驱动程序以及添加一些有关使用 Appium 和 Xcode/Android Studio 的详细信息。
这个问题已经成为许多 web 自动化 POC and/or MVP 实现的一个真正的岔路口。我不希望它指示错误的方向!
因此,我觉得它需要更彻底的答案,范围更广(易于安装、依赖性、重要插件、服务、报告器、文档、支持和其他集成) 并希望交付比接受的答案更主观。
❒ TL;DR:(懒惰的人!)
➮ if you're a beginner, starting out with web automation, or you want to
build-up the test-coverage for a small/medium-sized web app,
then choose any of the two! (might as well do a coin-flip!) The differences between the two are very slim at a lower level. The
cracks become gaps only when you reach more complex challenges, later down the road.
➮ if you're looking into building a full-fledged, heavyweight
automation harness in order to assure the quality for a big corporate web app, or a massive web portal, then read the entire post (or take my advice & go WDIO!)
❒ 凭据:(什么推荐我在这方面有发言权?)
自 2013 年初以来,我一直在广泛使用 基于 NodeJS 的测试框架,担任过从入门级、高级到 QA 主管的各种 QA 自动化工程角色。我将总结我在这些框架和 Web 自动化方面的工作经验:
- WebdriverIO (+4 年)
- 守夜人(+2年)
- 构建、维护和扩展几个使用这些工具的框架,确保所有主要浏览器和环境(桌面和移动)的质量
- 在各种 meetups/conferences
进行了多次 WebdriverIO 和 NightwatchJS 演讲和演示
- 相当熟悉整个 NodeJS 测试环境(除了 WebdriverIO 和 Nightwatch,还使用过:WebdriverJS (original fork for WebdriverIO), Nightmare, Robot & as of recently, Puppeteer)。
❒ 推荐:如果你非要在两者之间挑一个执行一个POC,我推荐你通读整个答案。只有这样,你才能对整个画面有一个完整的看法。
❒ 项目详情:
.-------------.---------.-----------.----------.-------------.--------------.
| project | ⭐️stars | forks | issues| open PRs | updated |
:-------------+---------+-----------+----------+-------------+--------------:
| webdriverio | 5050 | 1450 | 68 | 6 | 12.Jul.2019 |
:-------------+---------+-----------+----------+-------------+--------------:
| nightwatch | 9450 | 930 | 116|⁺306| 15 | 01.Jul.2019 |
'-------------'---------'-----------'----------'-------------'--------------'
+ - 第二个值表示 Open Issues 的总和(open
label ) & 陈旧问题 ( stale
label, 238 of them )。如果你很好奇,(我知道我是!)stale
代表使用机器人打开一段时间不活动的工单的标签。 (这很可疑!)
❖ 浅显要点:(以上数字为个人解读,请持保留态度)
➮ ( Strength ) NightwatchJS is a more widely used solution (idea enforced by the total number of Github stars), it also rapidly gained notoriety after being integrated
and Evangelized upon by the QA teams in several big companies (e.g:
LinkedIn, AirBnB, GoPro, etc.)
➮ ( Strength ) Due to its robustness, modularity & extensibility, WebdriverIO boasts a higher number of forks. Recent integrations with a lot of popular & on demand services (e.g: ChromeDevTools, React & VisualRegression plugins) have also strengthened the testing community's trust in the solution
➮ ( Weakness ) Even though this isn't a tech-specific critique, I lately have become displeased with the constant unprofessionalism surrounding the NightwatchJS team. So, apart from the stale tickets, you can constantly find your perfectly valid BUG, suddenly closed, with little to no information. Sometimes, you get something funny like this.
➮ ( Opportunity ) The next two categories (Open Issues, Open PRs) are actually a true image of the commit-to-contributor ratio: NightwatchJS is mainly maintained by Andrei Rusu and a handful of others, while WebdriverIO stands out as a project led by main contributor Christian Bromann, and backed by a very active & effervescent community.
➮ ( Subjective ) Personally, I sometimes get the feeling that Nightwatch, as a web-automation framework, has been semi-shelved already and the main contributor is more interested in generating revenue from the users, than fixing the current issues. Don't get me wrong... I have nothing against marketing & promoting oneself, but I would much rather put effort back into the product & the respect for my active users, FIRST!
❒ 免责声明!
The following grades (on a scale of 1-5 ⭐️
) are my personal assessment after having worked extensively with both frameworks. They
don't reflect anything other than my own experience with the given
tools.
❒ 设置项目:
- WebdriverIO (
5/5 ⭐️
)
- NightwatchJS (
4.0/5 ⭐️
)
设置 WDIO、Nightwatch 或当今任何基于 NodeJS 的测试框架都非常简单:
➊ 安装包:
npm install --save webdriverio
// or
npm install --save nightwatch
➋ 安装并启动 Selenium 服务器包:
npm install --save-dev selenium-standalone
// don't forget to ...
cd ./node_modules/.bin
./selenium-standalone install
./selenium-standalone start
➌ 创建快速测试文件夹结构:
./
├── /test
| ├── /features (test-files go here)
| | └── test.js (your first test here)
| ├── /pages (page-objects go here)
| ├── /assets (everything goes in here)
| └── /custom_commands (custom methods go here)
└── package.json
➍ 生成配置文件(wdio.conf.js
,或nightwatch.conf.js
):
➮ ( Strength ) it's at this point that WebdriverIO gets an advantage, as it comes out-of-the-box with a custom-made CLI
wizard for an easy & straightforward configuration of the
wdio.conf.js
file (you can start the wizard via the wdio config
command)
➮ with Nightwatch, you have to copy-paste a mock nightwatch.conf.js
file from the Getting
Started section
➮ it's not that Nightwatch is lacking in this regard, just that I personally feel it leaves more room for interpretation on certain
aspects, such as what config keys are mandatory, what is
nightwatch.json
and how is it different than nightwatch.conf.js
,
etc. It just seems that after reading the initial config
documentation, I leave with more questions than answers.
❖ WebdriverIO 的 配置助手(CLI 向导):
❒ 写作 & 运行 我们的第一个测试:
- WebdriverIO (
5/5 ⭐️
)
- NightwatchJS (
4.5/5 ⭐️
)
好的,您现在终于设置了您的项目,您已经检查了所有软件依赖项,现在不是编写我们的第一个测试的时候了。当前步骤中的项目应如下所示:
./
├── /test
| ├── /features
| | └── test.js
| ├── /pages
| ├── /assets
| └── /custom_commands
├── wdio.conf.js or nightwatch.conf.js
└── package.json
我真的很喜欢并感谢 Nightwatch 和 WebdriverIO 在各自的主页上都有一些不错的、开箱即用的工作示例。 即插即用!
❖ NightwatchJS 示例:(测试Google 搜索伦勃朗)
module.exports = {
'Demo test Google' : function (client) {
client
.url('http://www.google.com')
.waitForElementVisible('body', 1000)
.assert.title('Google')
.assert.visible('input[type=text]')
.setValue('input[type=text]', 'rembrandt van rijn')
.waitForElementVisible('button[name=btnG]', 1000)
.click('button[name=btnG]')
.pause(1000)
.assert.containsText('ol#rso li:first-child',
'Rembrandt - Wikipedia')
.end();
}
};
❖ WebdriverIO 示例:(测试 DuckDuckGo 搜索 WebdriverIO)
❯wdio-v5
示例:
describe('DuckDuckGo - Search Test, () => {
it('Should test the DuckDuckGo search page', async () => {
await browser.url('https://duckduckgo.com/');
await browser.setValue('#search_form_input_homepage', 'WebdriverIO');
await $('#search_button_homepage').click();
//
const title = await browser.getTitle();
assert.equal(title, 'WebdriverIO at DuckDuckGo', `Checking the title ...`);
});
});
❯wdio-v4
示例:
const webdriverio = require('webdriverio');
const options = { desiredCapabilities: { browserName: 'chrome' } };
const client = webdriverio.remote(options);
client
.init()
.url('https://duckduckgo.com/')
.setValue('#search_form_input_homepage', 'WebdriverIO')
.click('#search_button_homepage')
.getTitle().then(function(title) {
console.log('Title is: ' + title);
// outputs: "Title is: WebdriverIO (Software) at DuckDuckGo"
})
.end();
当您想向某人展示快速测试框架部署或教授自动化课程并且您缺少测试手头工作的工作示例时,这会变得特别方便。
➮ ( Strength ) Right before writing your first test, WebdriverIO gives you a decision to make. Do you want to write your code
synchronously, or asynchronously? This offers immense flexibility, off the bat, letting you choose the way in which you
want to write your tests (using the sync
flag).
❗Note: This was a wdio-v4
specific feature! The new WebdriverIO implementation (wdio-v5
) focuses on a synchronous approach to test writing, whilst leveraging the asynchronous calls under the hood.
For the sake of maintaining a faithful representation of the old version, I'll keep the below examples, though they are no longer valid for wdio-v4
.
// By default WebdriverIO commands are executed in a synchronous way using
// the wdio-sync package. If you still want to run your tests in an async way
// e.g. using promises you can set the sync option to false.
sync: true,
❖ sync: true
例子:
describe('DuckDuckGo - Search Test, () => {
it('Should test the DuckDuckGo search page', () => {
browser.url('https://duckduckgo.com/');
browser.setValue('#search_form_input_homepage', 'WebdriverIO');
browser.click('#search_button_homepage');
const title = browser.getTitle();
console.log('Title is: ' + title);
});
});
❖ sync: false
例子:
describe('DuckDuckGo - Search Test, () => {
it('Should test the DuckDuckGo search page', () => {
return browser
.url('https://duckduckgo.com/')
.setValue('#search_form_input_homepage', 'WebdriverIO')
.click('#search_button_homepage')
.getTitle().then(function(title) {
console.log('Title is: ' + title)
// outputs: "Title is: WebdriverIO (Software) at DuckDuckGo"
});
});
});
❒ 页面对象:
- WebdriverIO (
5/5 ⭐️
)
- NightwatchJS (
5/5 ⭐️
)
现在几乎不可能讨论 网络自动化 并且不会以 page objects 的激烈讨论告终,它们的用处,它们的实现,或者一般的页面对象模型。
在我们深入探讨如何在这两个 NodeJS 测试框架中实现页面对象之前,我觉得我们必须了解 为什么? 我们正在使用它们。
WHY? (why are we using page-objects?)
There's a saying, don't reinvent the wheel, so I'm not going to.
Instead, I'll quote ThoughtWork's Martin
Fawler
who IMHO said it best:
"When you write tests against a web page, you need to refer to elements within that web page in order to click links and determine what's displayed. However, if you write tests that manipulate the HTML elements directly your tests will be brittle to changes in the UI. A page object wraps an HTML page, or fragment, with an application-specific API, allowing you to manipulate page elements without digging around in the HTML."
WHAT? (what do page-objects provide us with?)
- they create a separation of concern: test vs. page
- they create a high-level abstraction of the app
- they (should) contains all static information about the page
- they offer the ability to redesign the app w/o changing the tests
- they can represent any element (object) on the page, or the whole page itself
HOW? (how do we create such page-objects?)
Enough blabbering! Let's see how we can easily implement some
page-objects inside our test framework.
WebdriverIO 页面对象示例:
❖ page.js
(这是您的页面对象基础)
export default class Page {
open (path) {
browser.url(path);
// !Note: if you want to make sure your page was completely
// loaded, then maybe add some logic to wait for
// document.readyState = "complete", or "interactive"
// Use a /custom_command for this! Go D.R.Y. principle! RAWWWWR!
}
}
❖ form.page.js
(这是一个登录表单页面对象示例):
import Page from './page'
class FormPage extends Page {
//
// > define your elements here <
//
get username () { return $('#username') }
get password () { return $('#password') }
get submitButton () { return $('#login button[type=submit]') }
get flash () { return $('#flash') }
//
// > define or overwrite page methods here <
//
open () {
super.open('login')
}
submit () {
this.submitButton.click()
}
}
export default new FormPage()
NightwatchJS 页面对象示例:
❖ homepage.js
(这是主页页面对象示例):
const homepageCustomCommands = {
checkHomePage: function() {
this.api.perform((done) => {
//
// > do some homepage checks here <
//
});
return this;
}
};
const homepage = {
url() {
return `${this.api.globals.baseUrl}/homepage`;
},
elements: {
'generic': '#generic',
'elements': '#elements',
'gohere': '#gohere',
sections: {
header: {
selector: '#header',
elements: {
'these': '#these',
'are': '#are',
'your': '#your',
'selectors': '#selectors'
},
},
footer: {
selector: '#footer',
elements: {
// > footer selectors go here <
},
},
},
}
commands: [homepageCustomCommands]
};
module.exports = homepage;
❒ 文档与支持:
- WebdriverIO (
5/5 ⭐️
)
- NightwatchJS (
3/5 ⭐️
)
NightwatchJS 和 WebdriverIO 在文档方面都有很好的支持:
❯ WebdriverIO:Getting Started | API DOCs | Gitter Chat
❯ NightwatchJS:Getting Started | API DOCs
➮ ( Strength ) both projects have very clean & informative documentation to go along with great examples
➮ ( Opportunity ) as a remark, I sometimes found myself searching for solutions to one, or more Nightwatch feature issues, or framework limitations, only to find the solution on some back-alley gist, or backwater blog. I would be nice if such answers & contributions (like the feature PR submissions left open) would be centralized & documented
➮ ( Weakness ) I don't know for sure where the bottleneck resides regarding Nightwatch's slow development cycle & lackluster (at best) support for community BUGs, feature-requests, or even submitted PRs. In my eyes, this appears even more as a flaw in contrast to the vibrant development community around WDIO, or the helpful Gitter chat channel
❒待续...
❒ 报告
❒ CI/CD 系统集成
❒ 架构差异
如标题所述,Nightwatch.js 和 Webdriver.io 有什么区别?
它们似乎具有相同的语法并且做几乎相同的事情。它们有何不同?
我需要在它们之间做出选择。
我已经多次使用这些工具编写了一个测试套件。
Webdriver.io 允许您编写测试用例 "from scratch" 并且可以很好地控制报告,例如,使用 slack npm 和其他包与 slack 集成。您需要了解或快速学习 node.js。除了与桌面浏览器配合良好外,它还与 Appium、Android Studio 和 Xcode 很好地集成,因此您可以 运行 在 Android 模拟器和 iOS 本地模拟器。您将需要安装这些东西并编写一些代码来告诉 Appium 使用哪些驱动程序,以及 select 功能等。
Nightwatch 是一个相当广泛的解决方案,它使用迭代器在测试失败时自动重试最多 3 次。 Nightwatch 对与 SauceLabs 等 VM 工具的集成提供了不错的支持,因此理论上您可以 运行 针对 700 多种不同 platform/browser/version 组合的测试用例 而无需编写代码来管理每个驱动程序 . Nightwatch 为您处理启动和关闭 selenium。虽然这最后一个听起来非常令人印象深刻,但实际上要达到和维持该测试覆盖率水平需要做大量工作。 Nightwatch 还具有相当内置的关注点分离,允许您定义自定义命令并在您的基础测试用例或单独测试中需要它们。您可以模块化测试的某些部分并导入它们,这样您就不必不断地重新编写登录测试以用于多种情况。此外,您可以使用自定义命令将 select 或作为键值对导入。
用过每一个我会这样总结:
webdriver.io: 如果您正在寻找更多的控制,一个非常自定义的解决方案并且您不需要迭代器,并且您有信心知道足以为 select 浏览器驱动程序、设置功能编写代码,并且您希望对报告进行自定义控制。
Nightwatch: 如果你想快速开始编写测试,要知道 运行 它们相对于特定的 platforms/browsers/versions 和将仍然允许您通过编写自定义命令来扩展测试的显着灵活性。
现在的另一个选择是 Dalek.js,它具有 Nightwatch 的简单脚本创建功能,但没有所有花里胡哨的东西。
在 运行ning nightwatch 之前,您可以在 Magellan.json 文件中配置浏览器,然后当您 运行 测试时调用浏览器,或一组浏览器 ( a "profile") 作为命令行参数,因此:
对于本地浏览器:
./node_modules/.bin/magellan --serial --browsers=chrome,firefox
假设您已经设置了一个 saucelabs 帐户并添加了您的用户名和访问密钥,您可以像这样调用浏览器配置文件:
./node_modules/.bin/magellan --serial --profile=myBrowsers
假设您在 Magellan.json 文件中设置了一个名为 myBrowsers 的配置文件,如下所示:
{
"profiles": {
"myBrowsers": [
{ "browser": "chrome_46_OS_X_10_10_Desktop" },
{ "browser": "firefox_42_Windows_2012_R2_Desktop" },
{ "browser": "safari_8_OS_X_10_10_Desktop" },
{ "browser": "safari_7_OS_X_10_9_Desktop" },
{ "browser": "safari_9_OS_X_10_11_Desktop" },
{ "browser": "IE_10_Windows_2012_Desktop" },
{ "browser": "IE_11_Windows_2012_R2_Desktop" },
{ "browser": "chrome_45_OS_X_10_8_Desktop" },
{ "browser": "chrome_45_OS_X_10_9_Desktop" },
{ "browser": "chrome_45_OS_X_10_10_Desktop" },
{ "browser": "chrome_45_OS_X_10_11_Desktop" },
{ "browser": "chrome_46_OS_X_10_10_Desktop" },
{ "browser": "chrome_45_Windows_10_Desktop" },
{ "browser": "chrome_45_Windows_2003_Desktop" },
{ "browser": "chrome_45_Windows_2008_Desktop" },
{ "browser": "chrome_45_Windows_2012_Desktop" },
{ "browser": "chrome_45_Windows_2012_R2_Desktop" },
{ "browser": "chrome_46_Windows_10_Desktop" },
{ "browser": "chrome_46_Windows_2003_Desktop" },
{ "browser": "chrome_46_Windows_2008_Desktop" },
{ "browser": "chrome_46_Windows_2012_Desktop" },
{ "browser": "chrome_46_Windows_2012_R2_Desktop" },
{ "browser": "firefox_42_OS_X_10_9_Desktop" },
{ "browser": "firefox_42_Windows_2012_R2_Desktop" },
{ "browser": "android_4_4_Linux_Samsung_Galaxy_S4_Emulator", "orientation": "portrait" },
{ "browser": "ipad_8_4_iOS_iPad_Simulator", "orientation": "landscape"},
{ "browser": "ipad_8_4_iOS_iPad_Simulator", "orientation": "landscape"},
{ "browser": "ipad_9_0_iOS_iPad_Simulator", "orientation": "landscape"},
{ "browser": "ipad_9_0_iOS_iPad_Simulator", "orientation": "portrait"},
{ "browser": "ipad_9_1_iOS_iPad_Simulator", "orientation": "landscape"},
{ "browser": "ipad_9_1_iOS_iPad_Simulator", "orientation": "portrait"},
{ "browser": "iphone_9_1_iOS_iPhone_Simulator", "orientation": "portrait"},
{ "browser": "iphone_9_1_iOS_iPhone_Simulator", "orientation": "landscape"}
]
}
}
一些更有用的(可选的)命令行参数:
切换 --serial 参数会导致测试执行被序列化,并带来更详细的测试体验,您可以在其中查看 return 在 运行 期间编辑的错误。 运行 等待测试完成也需要更长的时间。
添加 --sauce 参数一旦您的测试用例适用于本地计算机上存在的浏览器,您就可以利用 Sauce Labs 支持的(当前)760 种浏览器。继续将其粘贴到终端并点击 return:
./node_modules/.bin/magellan --serial --list_browsers
对于每个 device/browser 您想要测试的,您只需将列表添加到 执行脚本时,在 --browser= 之后将命令行选项列复制粘贴为逗号分隔值。注意:当 运行ning 没有 --sauce 时,你可以只使用 --browser=chrome 或 --browser=chrome,firefox
BREAKING IT DOWN:
使用不带 --sauce 但带 --serial 的 nightwatch 是一个很好的入门方式。 在你的脚本上工作,直到你验证了你想要检查的东西,当你确信所有的测试都应该通过时,运行 与 sauce labs 和你想要测试的主要浏览器一起做。一旦您确信涵盖了主要浏览器,您可以 运行 不用 --serial 来减少 运行 时间(在 Sauce Labs 上很有用,这会花钱)。
但足够的传教,你可以在这里找到你需要的关于 Saucelabs 的东西: https://wiki.saucelabs.com/display/DOCS/The+Sauce+Labs+Cookbook+Home
对于 Nightwatch 的样板示例来执行规范的 hello world:try this boilerplater
更新:人们提出的几点以及自发布此消息后我想到的几点。
Webdriver.io:
由于没有迭代器,因此在测试执行期间从失败中恢复的能力较弱,这意味着失败更加明确。因为这完全是异步的,所以您可能会很头疼地追踪失败的确切根源。 您可能最终还必须为您创建的任何数据创建单独的拆卸脚本,以避免执行期间发生数据冲突。
Nightwatch.js: 由于迭代器允许您重试,因此您通常能够找到脚本失败的地方。这可以让您更快地找到缺陷,而不是专注于脚本失败的原因。关闭您的个人脚本也更容易。
更新 2:
Nightwatch 较短的测试是 useful/encouraged。因为迭代器在每次迭代执行前立即将测试文件读入内存,所以您可以非常直接地在迭代执行之间编辑测试。让我换一种说法: 您的守夜人套件:
test_1 starts
test_1 FAIL // because you made a trivial error in your test case
test-2 starts // while it is running, you make the change, save it
test-2 PASS
test_1 starts // the iteration starts * with your change! *
test_1 PASS
============= Suite Complete =============
Status: PASSED
Runtime: 2m 48.3s
Total tests: 2
Successful: 2 / 2
1 test(s) have retried: 1 time(s)
另一方面,使用 node/webdriver.io 设置 Slack webhooks 很容易。这意味着您可以将 node/webdriver.io 测试设置为在完成时向 Slack 报告。客户对此表示赞赏,因为在构建完成后,他们很快就会看到自动化的结果,例如:
✅ [client/product 名称的自动测试] Sprint ##.#.# 通过 [服务器 URL 或 IP 地址] 使用 OS X Firefox 59.0.2
❌ 使用 OS X Firefox 59.0.2[[client/product 名称的自动测试] Sprint ##.#.# 在 [服务器 URL 或 IP 地址] 上失败
更新 3(2017 年 8 月 6 日)
又花了一年半的时间每天都与这两者打交道,我想补充以下几点。
有类似数量的 NPM 包与每个包集成,但您会注意到关于 Nightwatch (4x) 的 Whosebug 问题要多得多。我相信这是因为 Webdriver.io 更像是一种自己动手的自动化测试方法 [这是我的观点,我欢迎 feedback/pushback]。使用它的人不会对如何使用它有疑问,他们会有关于技术的具体问题。
对于拥有丰富的 Selenium IDE 和扎实的 javascript 经验的人来说,Nightwatch 是一个更好的切入点。它有很多开箱即用的有用解决方案。我与 Dalek 的一点经验表明这同样是一个不错的选择。
具有更多 javascript 以及一些面向对象编程和 unix 经验的人可能会发现 Webdriver.io 更好。正如我目前正在做的那样,这只是构建您自己的自定义框架的一个很好的选择。如果您可以设想您希望如何进行初始化、流程控制和报告工作,并且愿意投入大量资金,那就很合适了。
下面有人问我更喜欢哪个,到目前为止,我更喜欢 Webdriver.io 进行广泛的 e2e 测试。虽然我经常为基于我们平台构建的大多数客户工作使用个性化的 Nightwatch 存储库,但随着我构建自己的 Webdriver.io 解决方案,这种情况在不久的将来可能会发生变化。
更新 4(2018 年 5 月 2 日)
已更新以明确控制 Selenium 和浏览器驱动程序以及添加一些有关使用 Appium 和 Xcode/Android Studio 的详细信息。
这个问题已经成为许多 web 自动化 POC and/or MVP 实现的一个真正的岔路口。我不希望它指示错误的方向!
因此,我觉得它需要更彻底的答案,范围更广(易于安装、依赖性、重要插件、服务、报告器、文档、支持和其他集成) 并希望交付比接受的答案更主观。
❒ TL;DR:(懒惰的人!)
➮ if you're a beginner, starting out with web automation, or you want to build-up the test-coverage for a small/medium-sized web app, then choose any of the two! (might as well do a coin-flip!) The differences between the two are very slim at a lower level. The cracks become gaps only when you reach more complex challenges, later down the road.
➮ if you're looking into building a full-fledged, heavyweight automation harness in order to assure the quality for a big corporate web app, or a massive web portal, then read the entire post (or take my advice & go WDIO!)
❒ 凭据:(什么推荐我在这方面有发言权?)
自 2013 年初以来,我一直在广泛使用 基于 NodeJS 的测试框架,担任过从入门级、高级到 QA 主管的各种 QA 自动化工程角色。我将总结我在这些框架和 Web 自动化方面的工作经验:
- WebdriverIO (+4 年)
- 守夜人(+2年)
- 构建、维护和扩展几个使用这些工具的框架,确保所有主要浏览器和环境(桌面和移动)的质量
- 在各种 meetups/conferences 进行了多次 WebdriverIO 和 NightwatchJS 演讲和演示
- 相当熟悉整个 NodeJS 测试环境(除了 WebdriverIO 和 Nightwatch,还使用过:WebdriverJS (original fork for WebdriverIO), Nightmare, Robot & as of recently, Puppeteer)。
❒ 推荐:如果你非要在两者之间挑一个执行一个POC,我推荐你通读整个答案。只有这样,你才能对整个画面有一个完整的看法。
❒ 项目详情:
.-------------.---------.-----------.----------.-------------.--------------.
| project | ⭐️stars | forks | issues| open PRs | updated |
:-------------+---------+-----------+----------+-------------+--------------:
| webdriverio | 5050 | 1450 | 68 | 6 | 12.Jul.2019 |
:-------------+---------+-----------+----------+-------------+--------------:
| nightwatch | 9450 | 930 | 116|⁺306| 15 | 01.Jul.2019 |
'-------------'---------'-----------'----------'-------------'--------------'
+ - 第二个值表示 Open Issues 的总和(open
label ) & 陈旧问题 ( stale
label, 238 of them )。如果你很好奇,(我知道我是!)stale
代表使用机器人打开一段时间不活动的工单的标签。 (这很可疑!)
❖ 浅显要点:(以上数字为个人解读,请持保留态度)
➮ ( Strength ) NightwatchJS is a more widely used solution (idea enforced by the total number of Github stars), it also rapidly gained notoriety after being integrated and Evangelized upon by the QA teams in several big companies (e.g: LinkedIn, AirBnB, GoPro, etc.)
➮ ( Strength ) Due to its robustness, modularity & extensibility, WebdriverIO boasts a higher number of forks. Recent integrations with a lot of popular & on demand services (e.g: ChromeDevTools, React & VisualRegression plugins) have also strengthened the testing community's trust in the solution
➮ ( Weakness ) Even though this isn't a tech-specific critique, I lately have become displeased with the constant unprofessionalism surrounding the NightwatchJS team. So, apart from the stale tickets, you can constantly find your perfectly valid BUG, suddenly closed, with little to no information. Sometimes, you get something funny like this.
➮ ( Opportunity ) The next two categories (Open Issues, Open PRs) are actually a true image of the commit-to-contributor ratio: NightwatchJS is mainly maintained by Andrei Rusu and a handful of others, while WebdriverIO stands out as a project led by main contributor Christian Bromann, and backed by a very active & effervescent community.
➮ ( Subjective ) Personally, I sometimes get the feeling that Nightwatch, as a web-automation framework, has been semi-shelved already and the main contributor is more interested in generating revenue from the users, than fixing the current issues. Don't get me wrong... I have nothing against marketing & promoting oneself, but I would much rather put effort back into the product & the respect for my active users, FIRST!
❒ 免责声明!
The following grades (
on a scale of 1-5 ⭐️
) are my personal assessment after having worked extensively with both frameworks. They don't reflect anything other than my own experience with the given tools.
❒ 设置项目:
- WebdriverIO (
5/5 ⭐️
) - NightwatchJS (
4.0/5 ⭐️
)
设置 WDIO、Nightwatch 或当今任何基于 NodeJS 的测试框架都非常简单:
➊ 安装包:
npm install --save webdriverio
// or
npm install --save nightwatch
➋ 安装并启动 Selenium 服务器包:
npm install --save-dev selenium-standalone
// don't forget to ...
cd ./node_modules/.bin
./selenium-standalone install
./selenium-standalone start
➌ 创建快速测试文件夹结构:
./
├── /test
| ├── /features (test-files go here)
| | └── test.js (your first test here)
| ├── /pages (page-objects go here)
| ├── /assets (everything goes in here)
| └── /custom_commands (custom methods go here)
└── package.json
➍ 生成配置文件(wdio.conf.js
,或nightwatch.conf.js
):
➮ ( Strength ) it's at this point that WebdriverIO gets an advantage, as it comes out-of-the-box with a custom-made CLI wizard for an easy & straightforward configuration of the
wdio.conf.js
file (you can start the wizard via thewdio config
command)➮ with Nightwatch, you have to copy-paste a mock
nightwatch.conf.js
file from the Getting Started section➮ it's not that Nightwatch is lacking in this regard, just that I personally feel it leaves more room for interpretation on certain aspects, such as what config keys are mandatory, what is
nightwatch.json
and how is it different thannightwatch.conf.js
, etc. It just seems that after reading the initial config documentation, I leave with more questions than answers.
❖ WebdriverIO 的 配置助手(CLI 向导):
❒ 写作 & 运行 我们的第一个测试:
- WebdriverIO (
5/5 ⭐️
) - NightwatchJS (
4.5/5 ⭐️
)
好的,您现在终于设置了您的项目,您已经检查了所有软件依赖项,现在不是编写我们的第一个测试的时候了。当前步骤中的项目应如下所示:
./
├── /test
| ├── /features
| | └── test.js
| ├── /pages
| ├── /assets
| └── /custom_commands
├── wdio.conf.js or nightwatch.conf.js
└── package.json
我真的很喜欢并感谢 Nightwatch 和 WebdriverIO 在各自的主页上都有一些不错的、开箱即用的工作示例。 即插即用!
❖ NightwatchJS 示例:(测试Google 搜索伦勃朗)
module.exports = {
'Demo test Google' : function (client) {
client
.url('http://www.google.com')
.waitForElementVisible('body', 1000)
.assert.title('Google')
.assert.visible('input[type=text]')
.setValue('input[type=text]', 'rembrandt van rijn')
.waitForElementVisible('button[name=btnG]', 1000)
.click('button[name=btnG]')
.pause(1000)
.assert.containsText('ol#rso li:first-child',
'Rembrandt - Wikipedia')
.end();
}
};
❖ WebdriverIO 示例:(测试 DuckDuckGo 搜索 WebdriverIO)
❯wdio-v5
示例:
describe('DuckDuckGo - Search Test, () => {
it('Should test the DuckDuckGo search page', async () => {
await browser.url('https://duckduckgo.com/');
await browser.setValue('#search_form_input_homepage', 'WebdriverIO');
await $('#search_button_homepage').click();
//
const title = await browser.getTitle();
assert.equal(title, 'WebdriverIO at DuckDuckGo', `Checking the title ...`);
});
});
❯wdio-v4
示例:
const webdriverio = require('webdriverio');
const options = { desiredCapabilities: { browserName: 'chrome' } };
const client = webdriverio.remote(options);
client
.init()
.url('https://duckduckgo.com/')
.setValue('#search_form_input_homepage', 'WebdriverIO')
.click('#search_button_homepage')
.getTitle().then(function(title) {
console.log('Title is: ' + title);
// outputs: "Title is: WebdriverIO (Software) at DuckDuckGo"
})
.end();
当您想向某人展示快速测试框架部署或教授自动化课程并且您缺少测试手头工作的工作示例时,这会变得特别方便。
➮ ( Strength ) Right before writing your first test, WebdriverIO gives you a decision to make. Do you want to write your code synchronously, or asynchronously? This offers immense flexibility, off the bat, letting you choose the way in which you want to write your tests (using the
sync
flag).❗Note: This was a
wdio-v4
specific feature! The new WebdriverIO implementation (wdio-v5
) focuses on a synchronous approach to test writing, whilst leveraging the asynchronous calls under the hood. For the sake of maintaining a faithful representation of the old version, I'll keep the below examples, though they are no longer valid forwdio-v4
.
// By default WebdriverIO commands are executed in a synchronous way using
// the wdio-sync package. If you still want to run your tests in an async way
// e.g. using promises you can set the sync option to false.
sync: true,
❖ sync: true
例子:
describe('DuckDuckGo - Search Test, () => {
it('Should test the DuckDuckGo search page', () => {
browser.url('https://duckduckgo.com/');
browser.setValue('#search_form_input_homepage', 'WebdriverIO');
browser.click('#search_button_homepage');
const title = browser.getTitle();
console.log('Title is: ' + title);
});
});
❖ sync: false
例子:
describe('DuckDuckGo - Search Test, () => {
it('Should test the DuckDuckGo search page', () => {
return browser
.url('https://duckduckgo.com/')
.setValue('#search_form_input_homepage', 'WebdriverIO')
.click('#search_button_homepage')
.getTitle().then(function(title) {
console.log('Title is: ' + title)
// outputs: "Title is: WebdriverIO (Software) at DuckDuckGo"
});
});
});
❒ 页面对象:
- WebdriverIO (
5/5 ⭐️
) - NightwatchJS (
5/5 ⭐️
)
现在几乎不可能讨论 网络自动化 并且不会以 page objects 的激烈讨论告终,它们的用处,它们的实现,或者一般的页面对象模型。
在我们深入探讨如何在这两个 NodeJS 测试框架中实现页面对象之前,我觉得我们必须了解 为什么? 我们正在使用它们。
WHY? (why are we using page-objects?)
There's a saying, don't reinvent the wheel, so I'm not going to. Instead, I'll quote ThoughtWork's Martin Fawler who IMHO said it best:
"When you write tests against a web page, you need to refer to elements within that web page in order to click links and determine what's displayed. However, if you write tests that manipulate the HTML elements directly your tests will be brittle to changes in the UI. A page object wraps an HTML page, or fragment, with an application-specific API, allowing you to manipulate page elements without digging around in the HTML."
WHAT? (what do page-objects provide us with?)
- they create a separation of concern: test vs. page
- they create a high-level abstraction of the app
- they (should) contains all static information about the page
- they offer the ability to redesign the app w/o changing the tests
- they can represent any element (object) on the page, or the whole page itself
HOW? (how do we create such page-objects?)
Enough blabbering! Let's see how we can easily implement some page-objects inside our test framework.
WebdriverIO 页面对象示例:
❖ page.js
(这是您的页面对象基础)
export default class Page {
open (path) {
browser.url(path);
// !Note: if you want to make sure your page was completely
// loaded, then maybe add some logic to wait for
// document.readyState = "complete", or "interactive"
// Use a /custom_command for this! Go D.R.Y. principle! RAWWWWR!
}
}
❖ form.page.js
(这是一个登录表单页面对象示例):
import Page from './page'
class FormPage extends Page {
//
// > define your elements here <
//
get username () { return $('#username') }
get password () { return $('#password') }
get submitButton () { return $('#login button[type=submit]') }
get flash () { return $('#flash') }
//
// > define or overwrite page methods here <
//
open () {
super.open('login')
}
submit () {
this.submitButton.click()
}
}
export default new FormPage()
NightwatchJS 页面对象示例:
❖ homepage.js
(这是主页页面对象示例):
const homepageCustomCommands = {
checkHomePage: function() {
this.api.perform((done) => {
//
// > do some homepage checks here <
//
});
return this;
}
};
const homepage = {
url() {
return `${this.api.globals.baseUrl}/homepage`;
},
elements: {
'generic': '#generic',
'elements': '#elements',
'gohere': '#gohere',
sections: {
header: {
selector: '#header',
elements: {
'these': '#these',
'are': '#are',
'your': '#your',
'selectors': '#selectors'
},
},
footer: {
selector: '#footer',
elements: {
// > footer selectors go here <
},
},
},
}
commands: [homepageCustomCommands]
};
module.exports = homepage;
❒ 文档与支持:
- WebdriverIO (
5/5 ⭐️
) - NightwatchJS (
3/5 ⭐️
)
NightwatchJS 和 WebdriverIO 在文档方面都有很好的支持:
❯ WebdriverIO:Getting Started | API DOCs | Gitter Chat
❯ NightwatchJS:Getting Started | API DOCs
➮ ( Strength ) both projects have very clean & informative documentation to go along with great examples
➮ ( Opportunity ) as a remark, I sometimes found myself searching for solutions to one, or more Nightwatch feature issues, or framework limitations, only to find the solution on some back-alley gist, or backwater blog. I would be nice if such answers & contributions (like the feature PR submissions left open) would be centralized & documented
➮ ( Weakness ) I don't know for sure where the bottleneck resides regarding Nightwatch's slow development cycle & lackluster (at best) support for community BUGs, feature-requests, or even submitted PRs. In my eyes, this appears even more as a flaw in contrast to the vibrant development community around WDIO, or the helpful Gitter chat channel
❒待续...
❒ 报告
❒ CI/CD 系统集成
❒ 架构差异