protractor - trabajo - ¿Puedo dividir mis pruebas en especificaciones separadas y luego llamarlas desde otra o es mejor usar las funciones de ayuda?
vacaciones laborales en colombia 2017 (4)
Basándome en la respuesta de @langliman, he logrado lograr el comportamiento deseado.
Tenga en cuenta que login.spec.js
y Login.page.js
deben estar ubicados en la misma carpeta.
Login.page.js archivo:
var LoginPage = function (ptor) {
//following PageObject pattern define the functions here.
}
module.exports.getLoginPage = function (ptor) {
return new LoginPage(ptor);
};
Archivo 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();
});
});
}());
Acabo de comenzar con Protractor para las pruebas E2E y estoy teniendo algunos problemas con la estructura del caso de prueba.
No estoy seguro si puedo dividir mis pruebas en especificaciones separadas y luego llamarlas desde otra o cómo puedo hacer buenas funciones de ayuda para manejar esto.
Estoy encontrando elementos por un repetidor y luego me gustaría hacer pruebas para cada una de las operaciones para cada uno de los elementos en el repetidor. Algo así como esto:
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
}
});
});
});
En caso de que desee una configuración compartida y funciones de antes / después, así como métodos de ayuda, una solución es requerir las pruebas de su asistente de especificaciones en lugar de requerir su asistente de especificaciones de las pruebas.
conf.js
exports.config = {
seleniumAddress: ''http://localhost:4444/wd/hub'',
specs: [''e2e/spec.js'']
}
e2e / 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()
e2e / 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'')
})
});
});
}
e2e / 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'')
})
});
});
}
Llegué a esta pregunta en busca de una forma de compartir las funciones de ayuda entre los archivos de especificaciones en Protractor. En caso de que otros estén buscando lo mismo, resulta que, dado que Protractor solo se está ejecutando en Node, todo lo que necesita hacer es var helpers = require(''./your-helper-file'')
.
Yo mismo estoy viendo lo mismo, y hasta cierto punto esperaba que tuvieras una respuesta para mí en esta pregunta. :-)
Dicho esto, parece que el transportador es lo suficientemente nuevo como para que nadie sepa realmente la respuesta, y supongo que eso hace que mi respuesta sea tan buena como la de las siguientes personas.
En primer lugar, estoy usando la notación de objeto de página que se describe en la página de inicio del transportador, hacia la parte inferior: https://github.com/angular/protractor/blob/master/docs/getting-started.md
Esto da un elemento de modularidad, mi opinión aquí es que termino con un conjunto de clases, una por página, que resumen algunos de los detalles. Entonces, por ejemplo, podría tener una clase "foo", que incluye en ella abstracciones como "foo.get" y "foo.validate (id, name, otherData)". Esta sería una manera de sacar el código repetido.
Lo que no he resuelto es cómo crear una biblioteca de módulos y luego ensamblarlos en un único conjunto de escenarios. Aunque tengo algunos pensamientos:
- El problema subyacente es la capacidad de incluir archivos javascript entre sí, lo que realmente no existe como una capacidad. Hay bibliotecas de terceros, que preferiría no usar, y no he visto una manera de usar la capacidad del módulo de Angular para hacer esto.
- La prueba de fin 2 final puede ser muy dependiente del orden de las pruebas. Entonces, una prueba puede crear datos, otra prueba puede usar esos datos. Como ejemplo, si desea una prueba que registra a las personas, es posible que necesite una prueba que registre a las personas primero. Probablemente no quiera poner el registro en el frente de cada prueba que ejecute. Como tal, probablemente necesite mucho control sobre el orden de sus escenarios de prueba de todos modos
- Como tal, una opción es poner todo en un archivo realmente grande. Lo que va en contra de todo lo que todos aprendimos en la escuela, pero no he encontrado una razón que no funcionara. Entonces puedes escribir funciones y abstracciones a tu contenido de corazones.
- Si sigue eso a la siguiente etapa, otra opción es escribir una serie de archivos javascript con convenciones de nomenclatura estrictas y luego usar grunt para concatenarlos antes de ejecutarlos. Así por ejemplo:
- Un conjunto de archivos llamado xxxx.page.scenario.js, que contiene las definiciones de "objeto de página" - básicamente métodos auxiliares para cada página
- Un conjunto de archivos llamado xxxx.functions.scenario.js, que contiene componentes comunes de sus escenarios, por lo que quizás tenga un conjunto de acciones de registro e inicio de sesión y lo convierta en una función de biblioteca.
- Un conjunto de archivos llamado nnxx.scenarios.scenario.js, que contienen los scripts reales. Estos están numerados al inicio (el nn), por lo que podemos concatenarlos en una secuencia confiable y así controlar qué orden se ejecutan nuestros scripts
Todavía no estoy diciendo que esta sea una buena idea, solo que al menos superficialmente parece que podría funcionar y daría el resultado deseado. Mi principal preocupación es que se siente frágil, por lo que a medida que el conjunto de pruebas aumenta de tamaño, tal vez sea muy difícil de mantener. Quizás otra forma de hacer esto sería, en lugar de numerar los escenarios, definirlos como dependencias y tener algo que garantice que cualquier secuencia de comandos se ejecute después de cualquier secuencia de comandos de la que se declare que depende. Tal vez eso permitiría también la subconjunto de los scripts, así que podría decir "ejecutar el script de barras" y el marco de trabajo sabría que el script de barras necesita que el script foo se ejecute primero, y quizás el script de inicio de sesión. Pero está bien dejar todos los demás scripts.
EDITAR: veo astrolabio como potencialmente una buena respuesta aquí, parece que explícitamente le permite modularizar sus pruebas. https://github.com/stuplum/astrolabe . Acabo de completar una prueba de concepto, y parece que hace todo lo que puedo esperar. El código para ello termina algo como:
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'');
});
});
Estoy bastante contento con esta estructura, no hace todo, pero hace la mayoría de las cosas. El código de muestra que proporcioné es del tutorial en el que he estado trabajando durante un tiempo con angularjs, que estoy actualizando para e2e testing y Rails 4 en este momento, si desea el contexto que acompaña a eso: http://technpol.wordpress.com/2013/11/16/5-end-to-end-testing/