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
}
});
});
});
分度器のスペックファイル間でヘルパー関数を共有する方法を探してこの質問に行きました。他の人が同じものを探している場合、ProtractorはNodeで実行されているだけなので、必要なのはvar helpers = require('./your-helper-file')
だけです。
@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();
});
});
}());
共有セットアップと前後の関数、およびヘルパーメソッドが必要な場合、1つの解決策は、テストからスペックヘルパーを要求するのではなく、スペックヘルパーからテストを要求することです。
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')
})
});
});
}
私自身も同じことを考えていますが、この質問に対する回答があれば、ある程度期待していました。 :-)
そうは言っても、分度器は十分に新しいので、誰も答えを本当に知らないようです。それが私の答えを次の人と同じくらい良くしていると思います。
まず、分度器の開始ページの下部に記載されているページオブジェクト表記を使用しています: https://github.com/angular/protractor/blob/master/docs/getting-started。 md
これはモジュール性の要素を与えます。ここでの私の見解は、ページごとに1つずつ、詳細の一部を抽象化するクラスのセットになってしまうというものです。したがって、たとえば、「foo.get」や「foo.validate(id、name、otherData)」などの抽象化を含む「foo」クラスがあるとします。これは、繰り返されるコードを引き出す方法です。
私がまだ理解していないのは、モジュールのライブラリを作成し、それらを単一のシナリオセットにアセンブルする方法です。しかし、私はいくつかの考えを持っています:
これが良い考えだとはまだ言っていませんが、少なくとも表面的にはうまくいくように見え、望ましい結果が得られるというだけです。私の主な懸念は、それが壊れやすいと感じることです。そのため、テストスイートのサイズが大きくなると、保守が非常に困難になる可能性があります。おそらく、これを行う別の方法は、シナリオに番号を付ける代わりに、シナリオを依存関係として定義し、依存していると宣言したスクリプトの後に特定のスクリプトが実行されるようにすることです。これにより、スクリプトのサブセット化も可能になる可能性があります。つまり、「barスクリプトを実行する」と言うと、フレームワークは、barスクリプトで最初にfooスクリプトを実行し、ログインスクリプトを実行する必要があることを認識します。ただし、他のすべてのスクリプトを省略してもかまいません。
編集:私はここでアストロラーベが潜在的に良い答えだと思います、それはあなたがあなたのテストをモジュール化することを明示的に可能にするようです。 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/