Могу ли я делить свои тесты на отдельные спецификации, а затем называть их из другого или лучше использовать вспомогательные функции?
Только что началось с Protractor для тестирования E2E, и у меня возникли проблемы с структурой тестового случая.
Не уверен, могу ли я делить свои тесты на отдельные спецификации, а затем называть их из другого или как я могу использовать полезные вспомогательные функции для этого.
Я нахожу элементы ретранслятором, а затем я хотел бы сделать тесты для каждой операции для каждого элемента в репитере. Пример:
describe('tasty', function () {
'use strict';
var ptor;
beforeEach(function () {
ptor = protractor.getInstance();
ptor.get('http://localhost:8000/');
});
it('Should sample three tasty fruits of every kind on my shopping list.', function () {
ptor.findElement(protractor.By.className('fruitstore')).click();
var fruitshelves = ptor.findElements(protractor.By.repeater('fruit in fruits').column('header'));
fruitshelves.then(function(arr) {
for (var i=0;i<arr.length; i++) {
// Pick up three fruits of this kind from the shelf and put in shopping cart
// Should be listed on my shopping list
// Open the wallet
// Should have money
// Pay for the fruits and put it in your shopping bag
// Should be able to complete the transaction
// For each one of the fruits in your shopping bag
// Take a bite
// Should be tasty
}
});
});
});
Ответы
Ответ 1
Я пришел к этому вопросу, пытаясь найти способ использования вспомогательных функций между файлами spec в Protractor. В случае, если другие ищут то же самое, получается, так как Protractor работает только в Node, все, что вам нужно сделать, это var helpers = require('./your-helper-file')
.
Ответ 2
Основываясь на ответе @langliman, мне удалось добиться желаемого поведения.
Примечание login.spec.js
и Login.page.js
должны находиться в одной папке.
Файл Login.page.js:
var LoginPage = function (ptor) {
//following PageObject pattern define the functions here.
}
module.exports.getLoginPage = function (ptor) {
return new LoginPage(ptor);
};
файл login.spec.js:
(function () {
'use strict';
describe('login page', function () {
var ptor = protractor.getInstance();
var loginPageBuilder = require('./Login.page.js');
var loginPage = loginPageBuilder.getLoginPage(ptor);
it('should login as admin', function () {
loginPage.visit();
loginPage.enterUsername('user');
loginPage.enterPassword('password');
loginPage.login();
});
});
}());
Ответ 3
Если вы хотите использовать общие настройки и функции до/после, а также вспомогательные методы, одно из решений - потребовать проверки от вашего помощника spec вместо того, чтобы требовать от вашего помощника spec из тестов.
conf.js
exports.config = {
seleniumAddress: 'http://localhost:4444/wd/hub',
specs: ['e2e/spec.js']
}
э2э/spec.js
var chai = require('chai'),
homepage = require('./homepage.js'),
signin = require('./signin.js');
chai.should()
browser.baseUrl = 'http://localhost:3000'
homepage.test()
signin.test()
э2э/homepage.js
exports.test = function() {
describe('homepage', function() {
it('should have the right title', function() {
browser.get('/')
browser.getTitle().then(function(title){
title.should.eq('Home')
})
});
});
}
э2э/signin.js
exports.test = function() {
describe('signin', function() {
it('should have the right title', function() {
browser.get('/signin')
browser.getTitle().then(function(title){
title.should.eq('Sign in')
})
});
});
}
Ответ 4
Я тоже смотрю на то же самое, и в какой-то степени я надеялся, что у вас будет ответ для меня по этому вопросу.: -)
Сказав это, кажется, что транспортир достаточно новый, что никто не знает ответа, и, я думаю, это делает мой ответ таким же хорошим, как и следующие люди.
Во-первых, я использую нотацию объектов страницы, которая описана на странице начала работы транспортира, в нижней части: https://github.com/angular/protractor/blob/master/docs/getting-started.md
Это дает элемент модульности, мой взгляд здесь заключается в том, что я заканчиваю набором классов, по одному на страницу, которые абстрагируют некоторые детали. Так, например, у меня может быть класс "foo", который включает в себя абстракции, такие как "foo.get" и "foo.validate(id, name, otherData)". Это будет способ вывести повторяющийся код.
Бит, который я не разработал, заключается в том, как создать библиотеку модулей, а затем собрать их в один набор сценариев. У меня есть несколько мыслей:
- Основная проблема заключается в возможности включать файлы javascript друг в друга - что действительно не существует как возможность. Существуют сторонние библиотеки, которые я бы предпочел не использовать, и я не видел возможности использовать возможности модуля Angular для этого.
- Конечное тестирование конца 2 может сильно зависеть от порядка проведения тестов. Таким образом, один тест может создавать данные, другой тест может затем использовать эти данные. Например, если вам нужен тест, на котором регистрируются пользователи, вам может потребоваться тест, который регистрирует людей в первую очередь. Вероятно, вы не хотите размещать регистрацию в начале каждого теста, который вы запускаете. Таким образом, вы, вероятно, нуждаетесь в большом контроле над порядком ваших тестовых сценариев в любом случае
- Таким образом, один из вариантов - просто поместить все в один действительно большой файл. Что идет вразрез с тем, что мы все узнали в школе, но у меня на самом деле нет причин, которые бы не сработали. Затем вы можете писать функции и абстракции в своем сердце.
- Если вы последуете этому на следующем этапе, другой вариант состоит в том, чтобы написать серию файлов javascript со строгими соглашениями об именах, а затем использовать grunt для их конкатенации перед их выполнением. Так, например:
- Набор файлов с именем xxxx.page.scenario.js, которые содержат определения "объект страницы" - в основном вспомогательные методы для каждой страницы
- Набор файлов с именем xxxx.functions.scenario.js, который содержит общие компоненты ваших сценариев - так что, возможно, у вас есть набор регистраций и входа в систему, и вы делаете это в библиотечной функции
- Набор файлов с именем nnxx.scenarios.scenario.js, которые содержат сами скрипты. Они пронумерованы в начале (nn), поэтому мы можем связать их в надежной последовательности и тем самым контролировать, в каком порядке выполняются наши скрипты.
Я еще не говорю, что это хорошая идея, просто потому, что она по крайней мере внешне выглядит так, как будто она может работать, и даст желаемый результат. Моя главная забота заключается в том, что он чувствует себя хрупким - так как набор тестов растет в размерах, его, возможно, будет очень трудно поддерживать. Возможно, другим способом сделать это было бы вместо нумерации сценариев, чтобы вместо этого определять их как зависимости, и иметь что-то, что гарантирует, что какой-либо данный script запускается после любого script, он объявляет себя зависимым. Это могло бы позволить подмножество сценариев, так что вы могли бы сказать "запустите панель script", и инфраструктура будет знать, что для панели script требуется сначала запустить foo script, и, возможно, войти в систему script. Но это нормально, чтобы оставить все остальные скрипты.
ИЗМЕНИТЬ: Я вижу астролябию как потенциально хороший ответ здесь, похоже, что она явно позволяет вам модулизовать ваши тесты. https://github.com/stuplum/astrolabe. Я только что закончил с ней доказательство концепции, и, похоже, все, что я мог бы надеяться. Код для этого заканчивается чем-то вроде:
clubs.part.scenario.js:
/**
* Partial for the page objects associated with clubs
*/
var Page = require('astrolabe').Page;
module.exports = Page.create({
url: { value: 'UI/index.html#clubs' },
title: { get: function() { return this.findElement(this.by.id('title')); } },
description: { get: function() { return this.findElement(this.by.id('description')); } },
clubTableElement: { value: function(rowNum, columnBinding) {
return this.findElement(this.by.repeater('club in clubs').row(rowNum).column(columnBinding)); } }
}
);
clubs.scenario.js:
/**
* End to end tests for the club functionality
*/
var homePage = require('../home/home.part.scenario.js');
var clubsPage = require('./clubs.part.scenario.js');
describe( 'Navigate to club list page', function() {
it ( 'should allow navigation to the club list page', function() {
homePage.go();
expect(homePage.clubsLink.getText()).toEqual('Clubs');
homePage.clubsLink.click();
expect(clubsPage.title.getText()).toEqual('Club functions');
expect(clubsPage.description.getText()).toEqual('Soon this will show a list of all the clubs, based on information from the server');
expect(clubsPage.clubTableElement(0, 'name').getText()).toEqual('First club');
expect(clubsPage.clubTableElement(0, 'contact_officer').getText()).toEqual('A Person');
expect(clubsPage.clubTableElement(1, 'name').getText()).toEqual('Second club');
expect(clubsPage.clubTableElement(1, 'contact_officer').getText()).toEqual('J Jones');
});
it ( 'should allow us to go directly to the club list page', function() {
clubsPage.go();
expect(clubsPage.title.getText()).toEqual('Club functions');
expect(clubsPage.description.getText()).toEqual('Soon this will show a list of all the clubs, based on information from the server');
expect(clubsPage.clubTableElement(0, 'name').getText()).toEqual('First club');
expect(clubsPage.clubTableElement(0, 'contact_officer').getText()).toEqual('A Person');
expect(clubsPage.clubTableElement(1, 'name').getText()).toEqual('Second club');
expect(clubsPage.clubTableElement(1, 'contact_officer').getText()).toEqual('J Jones');
});
});
Я доволен этой структурой, она не делает все, кроме большинства вещей. Пример кода, который я предоставил, из учебника, над которым я работал некоторое время, с angularjs, который я обновляю для тестирования e2e и Rails 4 на данный момент, если вы хотите, чтобы контекст, который идет с этим: http://technpol.wordpress.com/2013/11/16/5-end-to-end-testing/