Подтвердить что ты не робот

Есть ли способ оптимизировать/ускорить отправку данных в пользовательский интерфейс с помощью Protractor?

У меня есть код, похожий на этот:

ExamPage.prototype.enterDetailsInputData = function (modifier) {
    page.sendKeys(this.modalExamName, 'Test Exam ' + modifier);
    page.sendKeys(this.modalExamVersionId, 'Test exam version ' + modifier);
    page.sendKeys(this.modalExamProductVersionId, 'Test exam product version ' + modifier);
    page.sendKeys(this.modalExamAudienceId, 'Test exam audience ' + modifier);
    page.sendKeys(this.modalExamPublishedId, '2014-06-1' + modifier);
    page.sendKeys(this.modalExamPriceId, '100' + modifier);
    page.sendKeys(this.modalExamDurationId, '6' + modifier);
};

Здесь функция page.sendKeys. Обратите внимание, что в настоящее время это не делает возврат promises или что-то в этом роде. Если функция не кодируется хорошо, я приветствую комментарии:

// page.sendkeys function
sendKeys(id: string, text: string) {
    element(by.id(id)).sendKeys(text);
} 

Я смотрю, как он медленно заполняет каждое поле на моем экране, а затем повторяет его снова и снова в следующих тестах.

Есть ли способ, которым это можно было бы оптимизировать, или мне нужно ждать, пока одно поле за другим заполнит и не будет жить с тестами, для выполнения которых требуется много времени?

Я предполагаю, что sendKeys - это обещание. Могу ли я, например, использовать AngularJS $q, чтобы выпустить все sendKeys одновременно, а затем использовать $q, чтобы дождаться их завершения?

4b9b3361

Ответ 1

Потенциальное решение Я думаю, что хотя бы немного хакера требуется независимо от того, как вы его оптимизируете - транспортир не дает вам этого. Как бы малая вспомогательная функция, подобная этой, соответствовала вашим потребностям? Что еще нужно для ускорения сторон text input с помощью ng-model s?

function setNgModelToString(element, value) {
    return element.getAttribute('ng-model').then(function (ngModel) {
        element.evaluate('$eval("' + ngModel + ' = \'' + value + '\'") && $digest()');
    });
}

Пример решения:

describe('angularjs homepage', function() {
  it('should have a title', function() {
    browser.get('http://juliemr.github.io/protractor-demo/');

    var inputString1 = '';
    var inputString2 = '';
    for (var i = 0; i < 1000; i++) {
        inputString1 += '1';
        inputString2 += '2';
    }

    /* Uncomment this to see it runs much much slower when you enter each key. */
    //element(by.model('second')).sendKeys(inputString1);   

    setNgModelToString(element(by.model('second')), inputString2);

    expect(element(by.model('second')).getAttribute('value')).toEqual(inputString2);
  });
});

Почему решение работает?

Вам нужно использовать $eval для переноса назначения, а не просто для назначения, поскольку evaluate не оценивает побочные эффекты (вложенная оценка, хотя... хе). Предполагая, что правка в выражениях angular then $digest() вызывается из &&; это приводит к сбою дайджеста, который вам необходимо обновить, поскольку вы устанавливаете значение из-за цикла дайджеста.

Мысли о решении:

Вся идея теста E2E заключается в "эмулировании" конечного пользователя, использующего ваше приложение. Это, возможно, не так, как отправка сообщений по одному, или копирование и вставка (поскольку вставка в элементы является допустимым способом ввода ввода, ее просто сложно настроить из-за вспышки и т.д., см. ниже).

Другие потенциальные решения:

  • Копировать и вставить: создать элемент, ввести текст, скопировать его, вставить текст, отправляющий Ctrl + V в целевой элемент. Это может потребовать выполнения кучи фантазийных ножек, таких как использование Flash (подвергая системный буфер обмена рискам безопасности) и "скопируйте его", щелкнув невидимую флеш-плеер. См. executeScript для оценки функций на цели, чтобы у вас был доступ к переменным типа window, если вам это нужно.

  • Распараллеливание ваших тестов. Прочтите официальный документ здесь и найдите "осколок", а затем "несколько". Если вы в основном обеспокоены продолжительностью всей вашей тестовой коллекции, а не отдельными тестами, масштабирование вашего счета в браузере - это, вероятно, путь. Однако есть хорошая вероятность, что вы TDD-ing или что-то в этом роде, поэтому нужно, чтобы каждый тест работал быстрее.

Ответ 2

Вы можете сделать следующее -

ExamPage.prototype.enterDetailsInputData = function (modifier) {
var arr=[
{id:this.modalExamName, text:'Test Exam ' + modifier},
{id:this.modalExamVersionId, text:'Test exam version ' + modifier },
{id:this.modalExamProductVersionId, text:'Test exam product version ' + modifier},
{id:this.modalExamAudienceId,text:'Test exam audience ' + modifier},
{id:this.modalExamPublishedId, text:'2014-06-1' + modifier},
{id:this.modalExamPriceId, text:'100' + modifier},
{this.modalExamDurationId, text:'6' + modifier}
];
var Q = require('q'),
    promises = [];
for (var i = 0; i < arr.length; i++) {
    promises.push(page.sendKeys(arr[i].id, arr[i].text));
}

Q.all(promises).done(function () {
    //do here whatever you want
});

};

sendKeys возвращает обещание по умолчанию. См. Здесь https://github.com/angular/protractor/blob/master/docs/api.md#api-webdriver-webelement-prototype-sendkeys

sendKeys(id: string, text: string) {
    return element(by.id(id)).sendKeys(text);
} 

Ответ 3

Если вы действительно хотите ускорить процесс манипулирования DOM любым способом (включая заполнение форм данных), один из вариантов, который следует учитывать, заключается в использовании: browser.executeScript или browser.executeAsyncScript. В таком случае webdriver позволяет браузеру выполнить script сам по себе - единственные накладные расходы - отправить тело script в браузер, поэтому я не думаю, что может быть что-то быстрее.

Из того, что я вижу, вы определяете элементы DOM на id, чтобы он плавно работал с подходом, который я предлагаю.

Вот его эшафот - протестировал его, и он отлично работает:

browser.get('someUrlToBeTested');
browser.waitForAngular();
browser.executeScript(function(param1, param2, param3){

        // form doc: arguments may be a boolean, number, string, or webdriver.WebElement
        // here all are strings: param1 = "someClass", param2 = "someId", param3 = "someModifier"
        var el1 = document.getElementsByClassName(param1)[0];
        var el2 = document.getElementById(param2);

        el1.setAttribute('value', 'yoohoo ' + param3);
        el2.setAttribute('value', 'hooyoo ' + param3);

        // depending on your context it will probably
        // be needed to manually digest the changes
        window.angular.element(el1).scope().$apply();


},'someClass', 'someId', 'someModifier')

небольшое примечание: если вы пройдете webdriver.WebElement в качестве одного из своих аргументов, оно будет сбрасываться до соответствующего DOM element.

Ответ 4

Я также использовал browser.executeScript. Но мне не нужно было использовать $apply waitForAngular

Я добавляю script при запуске тестов E2E и помещаю функцию в глобальную область действия, не волнуйтесь об этом только во время тестов E2E, и вы можете использовать пространство имен, если хотите.

'use strict';
function fastSendKeys(testId, value) {
    //test id is just an attribute we add in our elements
    //you can use whatever selector you want, test-id is just easy and repeatable
    var element = jQuery('[test-id=' + '"' + testId + '"' + ']');
    element.val(value);
    element.trigger('input');
}

Затем в вашем транспортирте проверьте что-то вроде этого (в объекте страницы):

this.enterText = function (testId, value) {
        var call = 'fastSendKeys(' + '"' + testId + '"' + ',' + '"' + value + '"' + ')';
        console.log('call is ', call);
        browser.executeScript(call);
    };