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();
  }
};
相關文章
相關標籤/搜索