介绍

网页测试系列回顾

使用 Nightwatch 开始网页测试
探索如何使用 Nightwatch 开始网页测试,Nightwatch 是一个功能强大且无妥协的测试自动化框架。学习如何安装 Nightwatch,设置你的测试环境,并编写基本的端到端测试。

我们了解了如何使用 Nightwatch 设置测试环境,并成功编写了我们的第一个端到端测试。以下是快速回顾:
安装: npm init nightwatch
编写:  browser.navigateTo('/').assert.textEquals('h1', '<TEXT>')
运行: npx nightwatch test

本帖概览

检查文本不足以进行端到端测试,以确保网站和 Web 应用程序的可靠性。Web 由复杂的元素组成,涉及大量用户交互。在本教程中,我们将教你如何从我们编写的 第一个测试 开始,测试一些常见场景。

编写 Web 测试主要围绕以下 3 个组件展开:

  • 查找元素
  • 与元素交互
  • 测试元素及其属性

我们将涵盖测试的这三个主要方面,以便能够为以下场景编写测试。

  • 单击“开始使用”按钮,并验证我们是否已转到安装页面。
  • 单击“搜索”,键入查询“frame”,等待结果,按下向下箭头转到第二个结果,然后按回车键。验证我们是否已转到 .parentFrame() 文档页面。

你还可以观看本帖的 视频教程

查找 👀

网页测试的第一步是找到要测试的页面中的 DOM 元素。Nightwatch 允许你使用各种选择器来查找元素。最常见的方法是使用 CSS 选择器。你可以使用 .element.find() API 来实现。

除此之外,你还可以通过下面显示的各种其他方式在页面上搜索元素。在以下示例中,我们将使用 .find().findByText().findByPlaceholderText()。你可以了解有关此处提供的所有 选择器的更多信息

Element find APIs
元素查找 API
💡
为了在你的编辑器中获得建议,你可以安装我们的 VSCode 扩展

你还可以通过将所有查找 API 链接起来,在元素内部继续深入搜索。这确实让获取你想要的精确元素变得容易。

示例

browser.element.find('main').find('.hero').findByText('Get Started')

等待

有时,我们正在寻找的元素尚未准备好,可能需要等待它。一个很好的例子是在输入框中键入内容,然后等待结果填充。你可以使用 .waitUntil(<status>) API 来实现。

💡
API 参考

.find(<string>) - 字符串应为有效的 CSS 选择器

.findByText(<string>)

.findByPlaceholderText(<string>)

.waitUntil(<string>) - <string> 可以是以下任何一项:"visible""not.visible""selected""not.selected""enabled""not.enabled""disabled"

示例

// Find the element with class "DocSearch-Modal" and wait for it to be visible
browser.element.find('.DocSearch-Modal').waitUntil('visible')

现在我们已经了解了如何查找元素,我们可以继续与它交互。

交互 ✍️

下一步是与 Web 交互。最常见的场景是用户单击按钮或填写表单。当测试动态 Web 应用程序或网站时,测试的这一部分变得至关重要。

Nightwatch 通过元素交互 API browser.element.find().<interaction_api>() 帮助你模拟这些操作。以下是可以使用的交互 API:clear、click、dragAndDrop、sendKeys、setAttribute、setProperty、submit、update、upload、submitForm、updateValue、uploadFile、clickAndHold、doubleClick、rightClick 和 moveTo。

除此之外,你还可以使用 .perform() 执行 复杂的用户操作。但对于本博客的范围,我们只使用 .click().sendKeys()

💡
API 参考

.click() - 单击我们找到的元素

.sendKeys(<string | [...keycodes]>) - 要发送到所选元素的键盘输入

→ 参数:<string> 要作为键盘输入发送的文本。例如,.sendKeys("hello world!")

→ 参数:<[...keycodes]> 你还可以发送字符串和键代码列表,包括在 browser.keys.<special_key> 下找到的特殊键。例如,.sendKeys([browser.Keys.TAB, "hello", browser.Keys.ENTER])。你可以在此处找到 特殊键列表

示例

// Find the button "Get Started" and click it
browser.element.findByText('Get Started').click()

// Find the input box with placeholder "Search docs" and type "frame"
browser.element.findByPlaceholderText('Search docs').sendKeys('frame')

// Press the down arrow and press Enter
browser.element.findByPlaceholderText('Search docs').sendKeys([browser.Keys.ARROW_DOWN, browser.Keys.ENTER])

现在我们已经了解了如何与元素交互,我们可以继续验证其各个方面。

断言 ✅

最后一步是测试我们正在寻找的内容是否与网页上存在的内容相匹配。这涉及获取我们需要的元素的属性并对其进行验证。

查找属性

最常测试的元素方面是其文本、属性(包括类)和值(对于输入元素)。这可以通过 .getText().getAttribute().getValue() 来实现。你可以阅读有关所有 元素状态的更多信息

测试

找到所需的值后,下一步是对其进行测试。测试可以根据以下三种方法,写得尽可能松散或严格:equalscontainsmatches

💡
.assert.equals(<str>) - 接受一个字符串,并检查它是否完全相同。

.assert.contains(<str>) - 接受一个字符串,并检查输入是否作为子字符串存在。

.assert.matches(<regex>) - 接受一个正则表达式作为输入,并根据它进行验证。

示例

// Check if the h1 text contains "Install Nightwatch"
browser.element.find('h1').getText().assert.contains('Install Nightwatch')

// Check if the "autocomplete" attribute of the input box is exactly "off"
browser.element.findByPlaceholderText('Filter by title').getAttribute('autocomplete').assert.equals('off')
💡
你可以使用 .verify 而不是 .assert 来记录失败并继续执行测试中的其他断言。

否定

要检查某个内容是否“不”等于或“不”包含,只需在 .assert 之后添加一个 .not 即可。

// Check if the h1 does not text contains "Selenium"
browser.element.find('h1').getText().assert.not.contains('Selenium')

元素状态

你可以在 .assert 之后使用 .visible().present().selected().enabled() 来断言元素的状态。这与我们在 等待 部分中早期了解的 .waitUntil 状态非常相似,可以互换使用。

// Check if the element with class "DocSearch-Dropdown-Container" is present
browser.element.find('.DocSearch-Dropdown-Container').assert.present()

文档状态

你可以在 browser.assert.url[Contains/Matches/Equals](<string>)browser.assert.title[Contains/Matches/Equals](<string>) 中断言文档的标题和 URL。

// Check if the title contains "Getting Started"
browser.assert.titleContains('Getting Started')
💡
Nightwatch 会自动重试失败的断言,最多持续半秒,这可以在 nightwatch.json 文件中的 globals 对象中进行配置。阅读更多

将它们组合在一起 🧩

通过我们目前所学的一切,让我们为这两种场景编写测试。

场景: 单击“开始使用”后,应导向安装页面

代码

  it('Should lead to the installation page on click of Get Started', function (browser) {
    browser.navigateTo('/')
    browser.element.findByText('Get Started').click()
    browser.element.findByPlaceholderText('Filter by title').waitUntil('visible')
    browser.element.find('h1').getText().assert.equals('Install Nightwatch')
    browser.assert.titleEquals('Getting Started | Developer Guide | Nightwatch.js')
    browser.assert.urlContains('nightwatchjs.org/guide/quickstarts')
    browser.element.findByPlaceholderText('Filter by title')
      .getAttribute('autocomplete').assert.equals('off')
    ;
    browser.end()
  })

解释

首先,我们使用 .navigateTo('/') 导航到主页。这是可能的,因为之前,在 项目设置 中,我们将项目的 base_url 设置为 Nightwatch 主页。你可以在 nightwatch.conf.js 文件中对其进行编辑。导航后,我们找到带有文本“开始使用”的按钮并单击它。对于前端路由链接且不重新加载页面的情况,建议等待操作完成。在这里,我们将等待左侧搜索栏变得可见。然后,我们将通过断言标题、URL 和 h1 元素来检查安装页面。我们还将断言搜索栏的“autocomplete”属性,以展示属性断言。

💡
browser.end() 会关闭浏览器窗口。以关闭浏览器来结束测试是一种良好的做法。
场景: 应允许搜索并显示正确的结果

代码

  it('Should allow search and show correct results', function (browser) {
    browser.navigateTo('/')
    browser.element.find('#docsearch').click()
    browser.element.find('.DocSearch-Modal').waitUntil('visible')
    
    const search_input = browser.element.findByPlaceholderText('Search docs') 
    search_input.sendKeys('frame')
    browser.element.find('.DocSearch-Dropdown-Container').assert.present()
    search_input.sendKeys([browser.Keys.ARROW_DOWN, browser.Keys.ENTER])

    browser.element.find('h1').getText().assert.contains('.frameParent')
    browser.end()
  })

解释

我们将导航到主页,找到搜索图标并单击它。我们将等待模态框打开并变得可见。然后,我们在搜索输入栏中键入文本“frame”。我们通过检查 ".DocSearch-Dropdown-Container" 的存在来等待结果加载,结果加载后,我们将按下向下箭头并回车。这将导向第二个结果 .frameParent() 的文档,我们验证 h1 文本以确认。

最终文件

最终的 home.spec.js 应如下所示。

describe('Nighwatch homepage', function () {
    
  it('Should have the correct title', function(browser) {
    browser
      .navigateTo('/')
      .assert.textEquals('h1', 'Introducing Nightwatch v3')
      .end()
    ;
  })
    
  it('Should lead to the installation page on click of Get Started', function (browser) {
    browser.navigateTo('/')
    browser.element.findByText('Get Started').click()
    browser.element.findByPlaceholderText('Filter by title').waitUntil('visible')
    browser.element.find('h1').getText().assert.equals('Install Nightwatch')
    browser.assert.titleEquals('Getting Started | Developer Guide | Nightwatch.js')
    browser.assert.urlContains('nightwatchjs.org/guide/quickstarts')
    browser.element.findByPlaceholderText('Filter by title')
      .getAttribute('autocomplete').assert.equals('off')
    ;
    browser.end()
  })

  it('Should allow search and show correct results', function (browser) {
    browser.navigateTo('/')
    browser.element.find('#docsearch').click()
    browser.element.find('.DocSearch-Modal').waitUntil('visible')
    
    const search_input = browser.element.findByPlaceholderText('Search docs') 
    search_input.sendKeys('frame')
    browser.element.find('.DocSearch-Dropdown-Container').assert.present()
    search_input.sendKeys([browser.Keys.ARROW_DOWN, browser.Keys.ENTER])

    browser.element.find('h1').getText().assert.contains('.frameParent')
    browser.end()
  })

})

让我们使用我们在上一帖中了解的相同命令来运行测试。

npx nightwatch test

浏览器完成测试后,输出应如下所示。

Test output
测试输出
💡
祝贺! 你的测试已通过。

接下来

网页测试中的高级技术和场景

今天你学习了如何使用这三种技术(查找、交互和断言)来测试 Web 上的常见用例。在我们网页测试系列的下一章中,我们将学习网页测试中的高级技术,例如测试钩子、多标签交互、iFrames、复制/粘贴、使用 async/await、执行客户端 JS、模拟地理位置、处理 Shadow DOM、操作 API 等。敬请关注我们即将发布的有关网页测试中的高级技术和场景的文章。

加入我们的社区 💬

如果你有任何问题,请随时访问我们的 Discord 服务器 并打个招呼。我们的社区随时为您提供支持,分享见解,并协助您解决任何与测试相关的疑问。我们欢迎您积极参与,并期待在我们的 Discord 社区中与您建立联系。您也可以通过 Twitter 与我们联系。

祝您测试愉快! 🎉

视频教程

Basics of Writing Nightwatch Web Tests - Video Tutorial
编写 Nightwatch 网页测试的基础知识 - 视频教程