Поиск…
замечания
Nightwatch предоставляет приемные и сквозные тесты для приложений Meteor с v0.5 дней и управляет миграциями от PHP до Spark to Blaze и React; и все основные платформы непрерывной интеграции. Дополнительную помощь можно найти в:
Документация API Nightwatch
Группа пользователей Nightwatch.js Google
Область приложения
На самом базовом уровне приемочные испытания - это, по сути, тестирование с использованием «черного ящика», которое в основном связано с тестированием входов и выходов замкнутой системы. Таким образом, для приемочного тестирования существуют три существенные особенности: поиск ресурса, чтение данных и запись данных. Когда дело доходит до браузеров и webapps, эти три функции в основном сводятся к следующему:
- Загрузите представление веб-страницы или приложения
- Осмотреть элементы пользовательского интерфейса (например, DOM)
- Запуск события / имитация взаимодействия с пользователем
Мы называем это площадью поверхности приложения. Поверхность - это то, что пользователь видит или испытывает. Это внешняя часть системы Blackbox. А поскольку пользователи взаимодействуют с современными веб-приложениями на видеоэкранах с помощью веб-браузеров, наше покрытие поверхности определяется универсальными локаторами ресурсов (URL-адресами) и видовыми экранами. Итак, наше первое прохождение начинается с того, что выглядит следующим образом:
module.exports = {
"Hello World" : function (client) {
client
// the location of our Meteor app
.url("http://localhost:3000")
// the size of the viewport
.resizeWindow(1024, 768)
// test app output
.verify.elementPresent('h1')
.verify.containsText('h1', "Welcome to Meteor!")
.verify.containsText('p', "You've pressed the button 0 times")
.verify.elementPresent('button')
// simulate user input
.click('button').pause(500)
// test app output again, to make sure input worked
.verify.containsText('p', "button 1 times")
// saving a copy of our viewport pixel grid
.saveScreenshot('tests/nightwatch/screenshots/homepage.png')
.end();
}
};
Пользовательские команды
Nightwatch поддерживает создание пользовательских команд, которые могут имитировать нажатия клавиш, щелчки мыши и другие входы. Пользовательская команда может быть привязана к другим командам Nightwatch, например:
module.exports = {
"Login App" : function (client) {
client
.url("http://localhost:3000")
.login("[email protected]", "janedoe123")
.end();
}
};
Чтобы включить это, определите команду в ./tests/nightwatch/commands/login
следующим образом:
exports.command = function(username, password) {
this
.verify.elementPresent('#login')
// we clear the input in case there's any data remaining from previous visits
.clearValue("#emailInput")
.clearValue("#passwordInput")
// we simulate key presses
.setValue("#emailInput", username)
.setValue("#passwordInput", password)
// and we simulate a mouse click
.click("#signInToAppButton").pause(1000)
return this; // allows the command to be chained.
};
Чтобы все это работало, вам нужно добавить атрибуты id
на свою страницу входа. На каком-то уровне он должен будет примерно выглядеть примерно так:
<template name="login">
<div id="login">
<input id="emailInput" name="email" type="email" />
<input id="passwordInput" name="password" type="password" />
<button id="#signInToAppButton">Sign In</button>
</div>
</template>
Проверка объектов Meteor на клиенте
Поскольку Nightwatch имеет доступ к консоли браузера, можно проверить объекты на стороне клиента, используя API .execute()
. В следующем примере мы проверяем объект Session для определенной переменной сеанса. Сначала начнем с создания файла ./tests/nightwatch/api/meteor/checkSession
, где мы будем хранить следующую команду:
// syncrhonous version; only works for checking javascript objects on client
exports.command = function(sessionVarName, expectedValue) {
var client = this;
this
.execute(function(data){
return Session.get(data);
}, [sessionVarName], function(result){
client.assert.ok(result.value);
if(expectedValue){
client.assert.equal(result.value, expectedValue);
}
})
return this;
};
Затем мы можем связать его так:
module.exports = {
"Check Client Session" : function (client) {
client
.url("http://localhost:3000")
.checkSession("currentUser", "Jane Doe")
.end();
}
};
Формы и типы ввода
Чтобы загрузить файл, вам сначала нужно создать каталог / data и добавить файл, который вы хотите загрузить.
tests/nightwatch/data/IM-0001-1001.dcm
Для вашей формы потребуется ввод с типом файла. (Некоторым людям не нравятся варианты стилизации, которые предоставляет этот вход, а общий шаблон - сделать этот ввод скрытым, а другой кнопкой на странице щелкнуть его по имени пользователя.)
<form id="myform">
<input type="file" id="fileUpload">
<input type="text" name="first_name">
<input type="text" name="last_name">
<input type="date" name="dob_month">
<input type="date" name="dob_day">
<input type="date" name="dob_year">
<input type="radio" name="gender" value="M">
<input type="radio" name="gender" value="F">
<input type="radio" name="gender" value="O">
<input type="select" name="hs_graduation_year">
<input type="text" name="city">
<input type="select" name="state">
<input type="submit" name="submit" value="Submit">
</form>
Затем ваши тесты должны будут использовать setValue () и разрешить путь к локальному файловому ресурсу.
module.exports = {
"Upload Study" : function (client) {
console.log(require('path').resolve(__dirname + '/../data' ));
var stringArray = "Chicago";
client
.url(client.globals.url)
.verify.elementPresent("form#myform")
// input[type="file"]
.verify.elementPresent("input#fileUpload")
.setValue('input#fileUpload', require('path').resolve(__dirname + '/../data/IM-0001-1001.dcm'))
// input[type="text"]
.setValue('input[name="first_name"]', 'First')
.setValue('input[name="last_name"]', 'Last')
// input[type="date"]
.click('select[name="dob_month"] option[value="3"]')
.click('select[name="dob_day"] option[value="18"]')
.click('select[name="dob_year"] option[value="1987"]')
// input[type="radio"]
.click('input[name="gender"][value="M"]')
// input[type="number"]
.click('select[name="hs_graduation_year"] option[value="2002"]')
// input[type="text"]
// sometimes Nightwatch will send text faster than the browser can handle
// which will cause skipping of letters. In such cases, we need to slow
// Nightwatch down; which we do by splitting our input into an array
// and adding short 50ms pauses between each letter
for(var i=0; i < userIdArray.length; i++) {
client.setValue('input[name="city"]', stringArray[i]).pause(50)
}
// input[type="select"]
// after an array input above, we need to resume our method chain...
client.click('select[name="state"] option[value="CA"]')
// input[type="number"]
.setValue('input[name="zip"]', '01234')
//input [ type="submit" ]
.click('button[type="submit"]')
.end();
}
};
Кредит Даниэлю Ринехарту за то, что он проиграл этот пример.
Компоненты и объекты страницы
Объекты страницы аналогичны пользовательским командам; за исключением того, что они представляют собой коллекции пользовательских команд, которые связаны с конкретным компонентом пользовательского интерфейса. Это очень хорошо работает с современным дизайном на основе компонентов, например, в React.
module.exports = {
url: 'http://localhost:3000/login',
commands: [{
login: function(email, password) {
return this
.clearValue('input[name="emailAddress"]')
.clearValue('input[name="password"]')
.setValue('input[name="emailAddress"]', email)
.setValue('input[name="password"]', password)
.verify.elementPresent('#loginButton')
.click("#loginButton");
},
clear: function() {
return this
.waitForElementVisible('@emailInput')
.clearValue('@emailInput')
.clearValue('@passInput')
.waitForElementVisible('@loginButton')
.click('@loginButton')
},
checkElementsRendered: function(){
return this
.verify.elementPresent("#loginPage")
.verify.elementPresent('input[name="emailAddress"]')
.verify.elementPresent('input[name="password"]')
},
pause: function(time, client) {
client.pause(time);
return this;
},
saveScreenshot: function(path, client){
client.saveScreenshot(path);
return this;
}
}],
elements: {
emailInput: {
selector: 'input[name=email]'
},
passInput: {
selector: 'input[name=password]'
},
loginButton: {
selector: 'button[type=submit]'
}
}
};
Единственное предостережение с использованием шаблона PageObject при тестировании компонентов заключается в том, что реализация прерывает поток цепочки метода, который обеспечивает встроенный verify.elementPresent
. verify.elementPresent
. Вместо этого вам нужно назначить объект страницы переменной и создать новую цепочку методов для каждой страницы. Разумная цена за последовательную и надежную модель для повторного использования кода.
module.exports = {
tags: ['accounts', 'passwords', 'users', 'entry'],
'User can sign up.': function (client) {
const signupPage = client.page.signupPage();
const indexPage = client.page.indexPage();
client.page.signupPage()
.navigate()
.checkElementsRendered()
.signup('Alice', 'Doe', '[email protected]', 'alicedoe')
.pause(1500, client);
indexPage.expect.element('#indexPage').to.be.present;
indexPage.expect.element('#authenticatedUsername').text.to.contain('Alice Doe');
},
}