2015-09-25 19 views
13

Problem:działania przeglądarek niestandardowe w Kątomierz

W jednym z naszych testach mamy "long click"/"click and hold" functionality że możemy rozwiązać za pomocą:

browser.actions().mouseDown(element).perform(); 
browser.sleep(5000); 
browser.actions().mouseUp(element).perform(); 

Które chcielibyśmy idealnie rozwiązać w jednej linii, mając sleep() częścią łańcucha działań:

browser.actions().mouseDown(element).sleep(5000).mouseUp(element).perform(); 

Oczywiście, to nie będzie działać, ponieważ istnieje no "sleep" action.

Innym praktycznym przykładem może być "typowanie przypominające człowieka". Na przykład:

browser.actions().mouseMove(element).click() 
    .sendKeys("t").sleep(50) // we should randomize the delays, strictly speaking 
    .sendKeys("e").sleep(10) 
    .sendKeys("s").sleep(20) 
    .sendKeys("t") 
    .perform(); 

pamiętać, że są to tylko przykłady, kwestia ma być rodzajowy.

Pytanie:

Czy można przedłużyć browser.actions() sekwencji akcji i wprowadzenie akcji niestandardowych?


+1

wbijały źródło selenu o ile rozumiem, to nie byłoby możliwe, aby faktycznie rozszerzyć działania, chciałbym rozważyć utworzenie pewnego rodzaju opakowaniu jednostkowym jak @John Stennett zasugerował. Jeśli jesteś zainteresowany, mogę podać wyjaśnienie, dlaczego nie można tego zrobić (z mojego punktu widzenia, być może jest to możliwe). –

+0

@ Michael Radionov tak, bałem się, że zawijanie jest jedyną opcją (nie ma w tym nic złego). Byłbym wdzięczny za twój wgląd, twoje odpowiedzi są zawsze szczegółowe i pomocne. Poza tym mam nadzieję, że ten temat pomógłby mi nie tylko rozwiązać mój obecny problem, ale także innych, którzy mają podobne żądania. Dzięki! – alecxe

Odpowiedz

9

Tak, można rozszerzyć ramy powództw. Ale, ściśle mówiąc, dostając coś takiego:

browser.actions().mouseDown(element).sleep(5000).mouseUp(element).perform(); 

oznacza brudząc z wnętrzności selen jest. Więc, YMMV.

Należy pamiętać, że Protractor documentation odnosi się do webdriver.WebDriver.prototype.actions podczas objaśniania czynności, które uważam za znaczące, że nie modyfikuje ani nie dodaje do tego, co zapewnia Selenium.

Klasa obiektu zwrócona przez webdriver.WebDriver.prototype.actions to webdriver.ActionSequence. Metoda, która faktycznie powoduje wykonanie sekwencji, to webdriver.ActionSequence.prototype.perform. W domyślnej implementacji ta funkcja pobiera komendy, które zostały zarejestrowane, gdy wywołano .sendKeys() lub .mouseDown() i ma sterownik, z którym skojarzony jest ActionSequence, zaplanuj je w odpowiedniej kolejności. Więc dodanie .sleep metodę nie można tego zrobić w ten sposób:

webdriver.ActionSequence.prototype.sleep = function (delay) { 
    var driver = this.driver_; 
    driver.sleep(delay); 
    return this; 
}; 

przeciwnym razie sen się stanie poza kolejnością. To, co musisz zrobić, to efekt, który chcesz, aby został wykonany później.

Inną rzeczą do rozważenia jest to, że domyślnie .perform() oczekuje tylko wykonania webdriver.Command, które są poleceniami do wysłania do przeglądarki. Spanie nie jest jednym z takich poleceń. Tak więc .perform() musi zostać zmodyfikowany, aby obsłużyć to, co zamierzamy nagrać z .sleep(). W poniższym kodzie ustawiłem opcję .sleep() nagrywania funkcji i modyfikacji .perform() do obsługi funkcji oprócz webdriver.Command.

Oto, jak wygląda całość po złożeniu. Najpierw podałem przykład użycia selenu zapasów, a następnie dodałem łatki i przykład używając zmodyfikowanego kodu.

var webdriver = require('selenium-webdriver'); 
var By = webdriver.By; 
var until = webdriver.until; 
var chrome = require('selenium-webdriver/chrome'); 

// Do it using what Selenium inherently provides. 

var browser = new chrome.Driver(); 

browser.get("http://www.google.com"); 

browser.findElement(By.name("q")).click(); 
browser.actions().sendKeys("foo").perform(); 
browser.sleep(2000); 
browser.actions().sendKeys("bar").perform(); 
browser.sleep(2000); 

// Do it with an extended ActionSequence. 

webdriver.ActionSequence.prototype.sleep = function (delay) { 
    var driver = this.driver_; 
    // This just records the action in an array. this.schedule_ is part of 
    // the "stock" code. 
    this.schedule_("sleep", function() { driver.sleep(delay); }); 
    return this; 
}; 

webdriver.ActionSequence.prototype.perform = function() { 
    var actions = this.actions_.slice(); 
    var driver = this.driver_; 
    return driver.controlFlow().execute(function() { 
     actions.forEach(function(action) { 
      var command = action.command; 
      // This is a new test to distinguish functions, which 
      // require handling one way and the usual commands which 
      // require a different handling. 
      if (typeof command === "function") 
       // This puts the command in its proper place within 
       // the control flow that was created above 
       // (driver.controlFlow()). 
       driver.flow_.execute(command); 
      else 
       driver.schedule(command, action.description); 
     }); 
    }, 'ActionSequence.perform'); 
}; 

browser.get("http://www.google.com"); 

browser.findElement(By.name("q")).click(); 
browser.actions().sendKeys("foo") 
    .sleep(2000) 
    .sendKeys("bar") 
    .sleep(2000) 
    .perform(); 
browser.quit(); 

W moim realizacji .perform() Mam zastąpił goog... funkcje Kod selen korzysta z stanie JavaScript.

+1

Nice find! Zgłębiłem próbę dodania niestandardowego polecenia, ale to nie jest takie proste, ponieważ executor używa tylko zarejestrowanych poleceń, a API do dodawania nowego polecenia jest ukrywane przez 'selenium-webdriver '. Myślę, że wiedza o tym, jak działa przepływ kontrolny, jest niezbędna w tego rodzaju sprawach. –

2

myślę, że możliwe jest rozszerzenie funkcji browser.actions() ale to obecnie ponad moim poziomie umiejętności tak będę leżał na drogę, że wziąłbym aby rozwiązać ten problem. Polecam skonfigurować obiekt strony "HelperFunctions.js", który będzie zawierał wszystkie te globalne funkcje pomocnicze. W tym pliku można wyświetlić listę funkcji browser i odnosić się do niego w wielu testach z całym kodem w jednym miejscu.

Jest to kod dla pliku „HelperFunctions.js”, polecam konfigurowania:

var HelperFunctions = function() { 
    this.longClick = function(targetElement) { 
     browser.actions().mouseDown(targetElement).perform(); 
     browser.sleep(5000); 
     browser.actions().mouseUp(targetElement).perform(); 
    }; 
}; 

module.exports = new HelperFunctions(); 

Następnie w teście można odwoływać plik Helper tak:

var HelperFunctions = require('../File_Path_To/HelperFunctions.js'); 

describe('Example Test', function() { 
    beforeEach(function() { 
     this.helperFunctions = HelperFunctions; 

     browser.get('http://www.example.com/'); 
    }); 

    it('Should test something.', function() { 
     var Element = element(by.className('targetedClassName')); 
     this.helperFunctions.longClick(Element); 
    }); 
}); 

W moim pakiecie testowym mam kilka plików pomocniczych i są one przywoływane przez wszystkie moje testy.

2

Mam bardzo małą wiedzę na temat selenu lub kątomierza, ale dam mu szansę.

ta zakłada, że ​​

browser.actions().mouseDown(element).mouseUp(element).perform(); 

obowiązuje składnia problemu, a jeśli tak to wtedy najprawdopodobniej rade

browser.action().sleep = function(){ 
    browser.sleep.apply(this, arguments); 
    return browser.action() 
} 
4

Oto, co zrobiłem (na podstawie idealnej odpowiedzi @ Louis'a).

umieścić następujące do onPrepare() w config kątomierz:

// extending action sequences 
protractor.ActionSequence.prototype.sleep = function (delay) { 
    var driver = this.driver_; 
    this.schedule_("sleep", function() { driver.sleep(delay); }); 
    return this; 
}; 

protractor.ActionSequence.prototype.perform = function() { 
    var actions = this.actions_.slice(); 
    var driver = this.driver_; 
    return driver.controlFlow().execute(function() { 
     actions.forEach(function(action) { 
      var command = action.command; 
      if (typeof command === "function") 
       driver.flow_.execute(command); 
      else 
       driver.schedule(command, action.description); 
     }); 
    }, 'ActionSequence.perform'); 
}; 

protractor.ActionSequence.prototype.clickAndHold = function (elm) { 
    return this.mouseDown(elm).sleep(3000).mouseUp(elm); 
}; 

Teraz musisz sleep() i clickAndHold() przeglądarki czynności dostępne. Przykład użycia:

browser.actions().clickAndHold(element).perform(); 
Powiązane problemy