nightwatch系列教程04——开发者指南:在测试中使用Page Object

本章内容翻译自http://nightwatchjs.org/guide#page-objectsjavascript

使用 Page Objects

Page Objects方法是一种流行的模式,经过将web应用程序的页面或页面片断包装为对象来编写端到端测试。页面对象的目的,是经过抽象出html的行为,让软件客户端能够像人同样的看见而且操做界面。关于Page Object,你能够在这里找到更详细的介绍。css


从0.7版本开始,Nightwatch为建立页面对象提供了加强的、更强大的接口,与之前的支持相比有了显著的改进。0.7以前建立的页面对象仍将继续工做,不过咱们建议升级到新版本。要使用新版本,Page Object必须包含 `elements` 或 `sections` 属性。不然,会按照旧版作处理。
html

配置 Page Object

简单地建立一个页面对象,只须要用描述页面的属性建立一个对象就能够了。每个页面对象都应该属于不一样的文件, Nightwatch将读取配置文件中page_objects属性定义的目录。java

page_objects也能够是一个文件夹数组,让你能够根据业务逻辑将页面对象分红不一样的组。web

Url 属性

你能够添加一个 url 属性来指定页面的url。你能够调用 navigate() 方法来跳转到对应的界面。api

URL 一般是个字符串:数组

module.exports = {
  url: 'http://google.com',
  elements: {}
};

他也能够是一个函数, 用来生成动态的连接。好比你想要支持不一样的测试环境的时候这就颇有用。你能够建立一个函数,他在页面的上下文中被调用:app

module.exports = {
  url: function() { 
    return this.api.launchUrl + '/login'; 
  },
  elements: {}
};

### 定义元素(elements)ide

多数状况下你都会在你的页面上定义元素,你的测试将会经过命令或者断言来与他交互。使用elements属性可让你的元素都定义在同一个地方。函数

Page Object 内部会自动等切换css和xpath,因此你不用在测试中手动调用 useXpath 或者 useCss 。默认的 locateStrategy 是css,但你仍能够指定xpath:

module.exports = {
  elements: {
    searchBar: { 
      selector: 'input[type=text]' 
    },
    submit: { 
      selector: '//[@name="q"]', 
      locateStrategy: 'xpath' 
    }
  }
};

若是你的elements都是使用同一种默认选择器策略的话,你可使用这种简写形式:

module.exports = {
  elements: {
    searchBar: 'input[type=text]'
  }
};

我的提示:上面的简写,我本人在项目中试过了,不起做用,并且报的错误也莫名其妙。若是你在使用中发现错误,不要使用简写形式试试

在调用元素命令或者断言的时候,elements 属性可让你使用 @ 做为前缀来引用定义的元素。

你也能够定义一个元素对象的数组:

var sharedElements = {
  mailLink: 'a[href*="mail.google.com"]'
};

module.exports = {
  elements: [
    sharedElements,
    { searchBar: 'input[type=text]' }
  ]
};

看一个包含 urlelements 属性的例子:

module.exports = {
  url: 'http://google.com',
  elements: {
    searchBar: { 
      selector: 'input[type=text]' 
    },
    submit: { 
      selector: '//[@name="q"]', 
      locateStrategy: 'xpath' 
    }
  }
};

测试文件能够这么写:

module.exports = {
  'Test': function (client) {
    var google = client.page.google();

    google.navigate()
      .assert.title('Google')
      .assert.visible('@searchBar')
      .setValue('@searchBar', 'nightwatch')
      .click('@submit');

    client.end();
  }
};

定义 Sections

有时候将页面划分为几部分(Section)也很是有用。Section有两个好处:

  • 在页面上提供了一个命名空间的层级
  • 提供元素级别的嵌套,即 Section 中的 elements 对应为它在的DOM中的子元素

使用 sections 属性来定义:

module.exports = {
  sections: {
    menu: {
      selector: '#gb',
      elements: {
        mail: {
          selector: 'a[href="mail"]'
        },
        images: {
          selector: 'a[href="imghp"]'
        }
      }
    }
  }
};

测试文件这么写:

module.exports = {
  'Test': function (client) {
    var google = client.page.google();
    google.expect.section('@menu').to.be.visible;

    var menuSection = google.section.menu;
    menuSection.expect.element('@mail').to.be.visible;
    menuSection.expect.element('@images').to.be.visible;

    menuSection.click('@mail');

    client.end();
  }
};


注意:section上每个命令(command)和断言(assertion,不是expect assertions)都返回其自身——链式返回。若是须要的话,你能够为复杂的DOM结构编写嵌套的section。

一个嵌套section的例子:

module.exports = {
  sections: {
    menu: {
      selector: '#gb',
      elements: {
        mail: {
          selector: 'a[href="mail"]'
        },
        images: {
          selector: 'a[href="imghp"]'
        }
      },
      sections: {
        apps: {
          selector: 'div.gb_pc',
          elements: {
            myAccount: {
              selector: '#gb192'
            },
            googlePlus: {
              selector: '#gb119'
            }
          }
        }
      }
    }
  }
};

在测试文件中使用嵌套section:

module.exports = {
  'Test': function (client) {
    var google = client.page.google();
    google.expect.section('@menu').to.be.visible;

    var menuSection = google.section.menu;
    var appSection = menuSection.section.apps;
    menuSection.click('@appSection');

    appSection.expect.element('@myAccount').to.be.visible;
    appSection.expect.element('@googlePlus').to.be.visible;

    client.end();
  }
};

编写命令(Command)

你能够在page object中使用 command 属性来添加命令。这是一个封装页面业务逻辑的一个有用的方式。
Nightwatch 将会调用页面上下文或者section的命令。客户端的命令(好比 pause)你可使用 this.api 来访问。为了链式调用,每一个命令函数都应该返回page对象或者section

在下面的案例中,这个命令用来封装点击提交按钮的逻辑:

var googleCommands = {
  submit: function() {
    this.api.pause(1000);
    return this.waitForElementVisible('@submitButton', 1000)
      .click('@submitButton')
      .waitForElementNotPresent('@submitButton');
  }
};

module.exports = {
  commands: [googleCommands],
  elements: {
    searchBar: {
      selector: 'input[type=text]'
    },
    submitButton: {
      selector: 'button[name=btnG]'
    }
  }
};

测试文件就简单多了:

module.exports = {
  'Test': function (client) {
    var google = client.page.google();
    google.setValue('@searchBar', 'nightwatch')
      .submit();

    client.end();
  }
};
相关文章
相关标签/搜索