Protractor: chore (core): добавить улучшенное сообщение об ошибке для перенаправления на стороне клиента

Созданный на 28 окт. 2015  ·  49Комментарии  ·  Источник: angular/protractor

Если тест нажимает ссылку или что-то, что вызывает перенаправление за пределами browser.get или browser.refresh , то при следующем вызове waitForAngular пользователь, вероятно, столкнется с этим сообщением об ошибке ( поскольку мы не дождались загрузки Angular), что не очень помогает.

Пользователи должны быть проинформированы о том, что происходит не так, и о возможных решениях (например, с помощью browser.get или browser.refresh для исправления начальной загрузки).

debuggability

Самый полезный комментарий

@sjelin , пожалуйста, объясните, что можно сделать для решения этой проблемы?

Мой вариант использования: у меня есть тест, который вводит имя пользователя / пароль и нажимает кнопку входа в систему, которая перенаправляет на другую страницу при успешном входе в систему.

Все 49 Комментарий

@sjelin , пожалуйста, объясните, что можно сделать для решения этой проблемы?

Мой вариант использования: у меня есть тест, который вводит имя пользователя / пароль и нажимает кнопку входа в систему, которая перенаправляет на другую страницу при успешном входе в систему.

Если обе страницы являются страницами angular, вы должны просто добавить browser.refresh после загрузки новой страницы, чтобы решить проблему.

Мы работаем над функцией, чтобы сделать это лучше в будущем

Я уже неделю борюсь с этой проблемой. browser.refresh() не работает, если я выполняю POST.

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

На самом деле, я использую что-то вроде этого как обходной путь, когда я знаю, что будет перенаправление:

(function (expectedUrl, timeout) {
    var loaded = false;

    browser.wait(function () {
        browser.executeScript(function () {
            return {
                url: window.location.href,
                haveAngular: !!window.angular
            };
        }).then(function (obj) {
            loaded = (obj.url == expectedUrl && obj.haveAngular);
        });

        return loaded;
    }, timeout);
})(expectedUrl, timeout);

@tassoevan , отлично! Это то, что я ожидал от waitForAngular - подождите, пока будет доступен angular.

Когда транспортир запускается, он всегда переходит на baseUrl, а затем на мою тестовую страницу. Это считается перенаправлением, о котором вы говорите?

Не совсем @patrickliechty , я имею в виду, когда вы нажимаете ссылку (например, <a href='google.com'> ), и она направляет браузер на google.cm

@juliemr и @hankduan ушли, кто-нибудь уже работает над долгосрочным исправлением этого?

@sjelin , эта проблема все еще существует в транспортире 3.1.1. Я вижу, что

+1 для лучшего исправления. Попался в это сегодня, не зная, как надежно обойти это. Благодаря!

Имея такую ​​же проблему !!! спасибо @tassoevan за надежное исправление

+1 за исправление.

Я получил эту ошибку, выполнив element (). GetText () вне спецификаций (без возникновения browser.get ()) - пытался создать ярлык для вывода определенного div вне спецификаций. Превратил его в функцию, и все было хорошо.

Я получаю эту ошибку при работе с \ node_modules \ protractor \ example \ conf.js, конечно же, example conf.js всегда должен работать независимо от того ??

Есть ли обходной путь для людей, использующих Protractor без Angular?

@Overdrivr Вы можете установить browser.ignoreSynchronization = true; сказать Protractor не ждать Angular.

browser.ignoreSynchronization = true у меня работает, когда я переключаю окна.

ОК, но тогда U нужно установить browser.ignoreSynchronization = false;

Я получаю эту ошибку, и она содержит ссылку на эту проблему с github.

Вот что у меня есть:

/**
 * Waits for MR job to complete.
 * <strong i="7">@param</strong> {string} url The GET URL to kick off the map reduce job.
 * <strong i="8">@return</strong> {!webdriver.promise.Promise}
 */
function waitForMapReduceJobToComplete(url) {
  browser.ignoreSynchronization = true;
  browser.get(url);
  $('a[href*="/mapreduce"]').click();
  browser.wait(()=> {
    console.log('wait');
    return $('#auto-refresh').isPresent();
  });
  browser.controlFlow().execute(function() {
    console.log('after wait, before click');
  });
  browser.wait(()=> {
    console.log('isDisplayed');
    return $('#auto-refresh').isDisplayed();
  });
  $('#auto-refresh').click();
  browser.controlFlow().execute(function() {
    console.log('after click');
  });

  browser.wait(() => {
    return $('.status-box').isPresent().then((isPresent)=> {
      if(isPresent) {
        return hasClass($('.status-box'), 'status-done')
            .then((containsClass) => {
              if(!containsClass) {
                return browser.refresh().then(() => false);
              }
              return true;
            });
      }
      return browser.sleep(constants.BROWSER_WAIT_MS)
          .then(() => false);
    })
  });

  return browser.controlFlow().execute(function() {
    browser.ignoreSynchronization = false;
  });
}
  fit('mapreduce job is idempotent', function() {
    var subBuildingUrl = '/xyz/#all';
    var mapReduceJob = '/import/xyz/';
    helpers.waitForMapReduceJobToComplete(mapReduceJob);

    browser.get(subBuildingUrl);
    var tableView = new TableView();
    var originalCount = 0;
    tableView.count().then((cnt)=>{
      originalCount = cnt;
    });

    tableView.deleteRowNumber(1);
    browser.sleep(5000);
    browser.controlFlow().execute(function() {
      expect(tableView.count()).toBeLessThan(originalCount);
    });

    helpers.waitForMapReduceJobToComplete(mapReduceJob);
    browser.get(subBuildingUrl);
    browser.controlFlow().execute(function() {
      tableView = new TableView();
      expect(tableView.count()).toEqual(originalCount);
    });
  });

// Упорядочить
Тест запускается в приложении angular.
запускает задание mapreduce для URL-адреса, а не для приложения angular
возвращается в приложение angular для записи количества строк

// Действие
удаляет 1 запись
проверяет, происходит ли удаление

// Утвердить
запускает задание mapreduce для URL-адреса, а не для приложения angular
_fails_ во второй раз, прежде чем мы сможем подтвердить, что задание mapreduce воссоздает данные (такое же количество строк перед удалением).

Вот соответствующие данные журнала:

wait
after wait, before click
isDisplayed
isDisplayed
after click
[17:48:09] W/element - more than one element found for locator By(css selector, .status-box) - the first result will be used
[17:48:24] W/element - more than one element found for locator By(css selector, .status-box) - the first result will be used
[17:48:40] W/element - more than one element found for locator By(css selector, .status-box) - the first result will be used
[17:48:55] W/element - more than one element found for locator By(css selector, .status-box) - the first result will be used
wait
F

Failures:
  Message:
    Failed: Error while waiting for Protractor to sync with the page: "window.angular is undefined.  This could be either because this is a non-angular page or because your test involves client-side navigation, which can interfere with Protractor's bootstrapping.  See http://git.io/v4gXM for details"
  Stack:

Он всегда терпит неудачу во второй раз через waitForMapReduceJobToComplete в журнале ожидания.

Решение "задокументировано" здесь: https://github.com/angular/protractor/issues/2787

Внутри browser.wait вам нужно сбросить ignoreSynchronization. Я сделал это для всех browser.waits, где ignoreSynchronization уже было истинным.

  browser.wait(()=> {
    browser.ignoreSynchronization = true;
    return $('#auto-refresh').isPresent();
  });

Теперь мой тест пройден.

Есть ли у вас какое-либо решение для ожидания с использованием browser.ExpectedConditions?

Как будет выглядеть патч, если вы воспользуетесь этим кодом?

browser.wait(EC.visibilityOf(element), timeout, message);?

Благодаря!

@azachar, похоже, работает:

browser.wait(() => {
  browser.ignoreSynchronization = true;
  return EC.visibilityOf(element);
}, timeout, message);

Я не знаю, что происходит, по какой-то причине в этом блоке ignoreSynchronization остается ложным, пока вы не установите его принудительно. Я продолжил это в # 2787.

ОБНОВЛЕНИЕ: есть условия гонки, если вы устанавливаете / сбрасываете ignoreSynchronization , лучше поместите это в поток управления. См. №4061.

Я получаю это без ignoreSynchronization с чем-то вроде этого ....

afterAll(function(){
    adminPage.header.logout();
    // FIXME: WTF why isn't even this working 100% of the time
    setTimeout(function(){
      expect(loginPage.isVisible()).toBeTruthy();
    }, 1000 )
  })

loginPage похоже, загружается через секунду, и этот setTimeout не помогает. browser.wait вроде немного помогает, но все равно не работает.

@tassoevan привет, чувак, не могли бы вы рассказать мне, как настроить этот browser.wait (), как ваше описание, и где его настроить

(function (expectedUrl, timeout) {
    var loaded = false;

    browser.wait(function () {
        browser.executeScript(function () {
            return {
                url: window.location.href,
                haveAngular: !!window.angular
            };
        }).then(function (obj) {
            loaded = (obj.url == expectedUrl && obj.haveAngular);
        });

        return loaded;
    }, timeout);
})(expectedUrl, timeout);

в angular (2) - убедитесь, что ваша спецификация начинается с browser.get ('/');

import { browser, element, by } from 'protractor';

it('should display message saying app works', () => {
    browser.get('/');

    let title = element(by.id('title')).getText();
    expect<any>(title).toEqual('cool');
});

После того, как смотреть на @tassoevan «s большой обходной пути и получать мои тесты переадресации работы, я решил поделиться своим решением машинописи и Angular2. Я поместил эту функцию в свой класс абстрактной страницы, но я думаю, что она может лучше подходить для объекта browser .

/**
  Wait for the page to make it to the next URL before continuing.
  A supplement to browser.waitForAngular() because protractor will continue control
  flow before navigation starts.

  Inputs:
    necessaryUrlFragment: a portion of the url that signifies you have successfully navigated
    timeout: the number of ms to wait before throwing an error. Defaults to the browsers default
      page timeout.
 */
waitForRedirect(necessaryUrlFragment: string, timeout: number = browser.getPageTimeout) {
  // Before we tell the browser to wait, assume it has not navigated
  let hasRedirected = false;

  // Passing a function to browser.wait() tells protractor to call that function repeatedly.
  // This function returns the closure variable hasRedirected, which will be set to true once the
  // necessaryUrlFragment has been found in the url
  browser.wait(() => {
    browser.getCurrentUrl()
      // Check to see if necessaryUrlFragment is in the current url
      .then(url => url.includes(necessaryUrlFragment))
      // Update our navigation status
      .then(hasNavigated => {
        hasRedirected = hasNavigated;
      });

    // Return our navigation status every time protractor asks for it - even if navigation is
    // not complete
    return hasRedirected;
  }, timeout);
}

Вот пример того, как я использовал его в тесте:

it('Should be able load the preferences page', () => {
  page.navigateToMarketing();
  page.clickButton('Manage Preferences');
  page.waitForRedirect('preferences/preferences');
  expect(page.getPageTitle()).toBe('MY PREFERENCES');
});

Моя страница входа не является страницей Angular js. Как только я вхожу в приложение, создается страница Angular js. Итак, я создал файл спецификации, как показано ниже:

описать ('Войти в приложение', function () {
var userID = element (by.name ('username'));
var password = element (by.name ('пароль'));
var logInButton = element (by.id ('Отправить'));

function loginToApplication (stringSSOID, stringPassword) {
userID.sendKeys (stringSSOID);
пароль.sendKeys (stringPassword);
logInButton.click ();

}

beforeEach (function () {
browser.ignoreSynchronisation = true;
browser.get (''); // который перейдет на страницу входа в приложение
});

it ('войти в приложение', function () {
loginToApplication ('77777', 'тест')
browser.ignoreSynchronisation = false
ожидать (browser.getTitle ()). toEqual ('Программное обеспечение');
});
});

Получение ниже сообщения об ошибке:
Ошибка: ошибка при ожидании синхронизации транспортира со страницей: "window.an"
gular не определено. Это может быть либо потому, что это не угловая страница, либо
потому что ваш тест включает в себя навигацию на стороне клиента, которая может мешать Prot
ractor's bootstrapping. Подробнее см. Http://git.io/v4gXM "

Привет, взгляните на http://www.protractortest.org/#/timeouts # how-to-disable-wait-for-angular
По сути, есть несколько способов войти в систему, используя страницу, отличную от Angular, но сначала попробуйте это показать в документации.
С уважением
Верблюд

Я понимаю, что это уже долгое обсуждение, но это может кому-то помочь.

Такое сообщение об ошибке также может появиться, когда страница неожиданно перезагружается из-за необработанной ошибки, возникающей в компоненте Angular. Тот факт, что консоль браузера может не сохраняться , а также скорость выполнения тестов сделали мне довольно непростым понимание того, что происходит.

Так что, возможно, что-то можно было бы сделать в отношении сообщения об ошибке, поскольку вышеупомянутый случай сам по себе не является «навигацией на стороне клиента» :)

Привет @ArnaudPel

Tnx для дополнительной информации. Может быть, вы можете добавить PR, чтобы объяснить это в документации, если хотите?

В настоящее время я получаю эту ошибку при посещении нашей страницы входа в систему (обычная проблема):

Failed: Error while waiting for Protractor to sync with the page: "window.angular is undefined.  This could be either because this is a non-angular page or because your test involves client-side navigation, which can interfere with Protractor's bootstrapping.  See http://git.io/v4gXM for details"

Уловка ignoreSync , похоже, не помогает:

browser.ignoreSynchronization = true;
// do work here with browser.driver 
browser.ignoreSynchronization = false;

Ссылка находится здесь, в этой ветке, но что делать дальше, не совсем понятно.

Протестировано с помощью Protractor версий: 5.2.1, 5.1.1, 5.1.0, 5.0.0

@benjaminapetersen - Вы можете попробовать использовать waitForAngularEnabled вместо ignoreSynchronization . Я смотрю справочную страницу API для Protractor v5.1.2, и она больше не включает ignoreSynchronization , но просматривая CHANGELOG, я не вижу, когда это свойство было официально объявлено устаревшим ...

Я попробовал waitForAngularEnabled но все равно получаю ту же ошибку, что и @benjaminapetersen . Вот моя текущая конфигурация:

exports.config = {
    rootElement: 'app',
    baseUrl: 'http://localhost:1384/#/',
    framework: 'jasmine',
    seleniumAddress: 'http://localhost:4444/wd/hub',
    specs: ['./tests/e2e/*.js'],
    multiCapabilities: [{
      'browserName': 'firefox',
      //'browserName': 'chrome',
    }, 
  ],
  jasmineNodeOpts: {
    showColors: true
  },
}

//example test: 

describe('Overall navigation', function () {
  it('test link', function () {
     browser.get('http://localhost:1384/#/registrerprodukt');
  });
});

@thompsnm спасибо! Хотя похоже, что waitForAngularEnabled также устарел ....

@benjaminapetersen, что устаревший тег документа находится в свойстве ignoreSynchronization , а не в waitForAngularEnabled

waitForAngularEnabled у меня тоже не работает. Он работал с IgnoreSynchronization до обновления до Protractor 5. Мне нужно переключиться на iframe, отличный от Angular, и теперь я не могу. Пожалуйста, порекомендуйте. благодаря

@ seel93 Попробуйте прокомментировать rootElement: 'app' или попробуйте заменить его на rootElement: '*[ng-app]' .
Я только что установил последнюю версию транспортира и написал несколько спецификаций для приложения Angular 1.6.1 и, похоже, пока работает нормально. Я столкнулся с этим сообщением об ошибке, когда пытался войти в свое приложение, но сейчас использую такой подход:

onPrepare: function () {
    browser.driver.manage().timeouts().setScriptTimeout(60000);

    browser.driver.get('http://app.local.dev'+ '/login');
    browser.driver.findElement(by.id('user_login')).sendKeys('d','e','m', 'o');
    browser.driver.findElement(by.id('user_pass')).sendKeys('d','e','m', 'o');
    browser.driver.findElement(by.id('submit')).click();

    // Login takes some time, so wait until it's done.
    return browser.driver.wait(function() {
        return browser.driver.getCurrentUrl().then(function(url) {
            return /students\/agenda/.test(url);
        });
    }, 30000);
}

Примечание: у меня ng-app установлено в теге html

rootElement: '*[ng-app]' ? работает, чтобы просто искать страницу для любого узла? Не видел этого раньше.

Я только что решил свою проблему. 🥇 Основная причина: побочный эффект консоли разработчика

У меня была эта проблема, и исправление для меня заключалось в замене транспортира "^ 5.3.2" в моем package.json

У меня есть обычная страница входа, а затем я перенаправляю на страницу angular.

Поэтому я точно не знаю, как и почему это работает, потому что я новичок в angular и angular e2e, но у меня это заработало, когда я дважды использовал browser.waitForAngularEnabled(false); .

logIn() {
    const email = 'test';
    const password = 'test';

    browser.waitForAngularEnabled(false);
    browser.get('/login');

    element(by.id('username')).sendKeys(email);
    element(by.id('password')).sendKeys(password);
    element(by.css('[type="submit"]')).click();

    return browser.wait(function() {
        browser.waitForAngularEnabled(false);
        return browser.getCurrentUrl().then(function(url) {
            browser.waitForAngularEnabled(true);
            return /dashboard/.test(url);
        });
    }, 5000);
}

Надеюсь, поможет.

Последнее решение почти работает для меня, если только я не получу ошибку после прохождения теста:
Ошибка: ECONNREFUSED connect ECONNREFUSED 127.0.0.1:4444 От: Задача: WebDriver.getCurrentUrl ()

Я получил эту ошибку, выполнив element (). GetText () вне спецификаций (без возникновения browser.get ()) - пытался создать ярлык для вывода определенного div вне спецификаций. Превратил его в функцию, и все было хорошо.

Он работает для чего угодно, вы не можете использовать более одного элемента 'element (). Anyfunction ()' вне 'it'.
Нашел на собственном горьком опыте ...

Получена ошибка при переключении с одной веб-страницы на другую в транспортире:

Не удалось: ошибка при ожидании синхронизации Protractor со страницей: «как тестируемость angularJS, так и тестируемость angular не определены. Это может быть связано либо с тем, что это не-угловая страница, либо потому, что ваш тест включает навигацию на стороне клиента, которая может мешать работе Protractor. начальная загрузка. Подробнее см. http://git.io/v4gXM "

код:
var url = browser.params.login.Url;
browser.get (url + '/ #! / app / manage-users');

Я начал получать эту ошибку внезапно, мои сборки CT. Я заметил, что эта ошибка возникает только в Firefox без головы и отлично работает с Chrome без головы в Linux. Я обновился с Firefox v69 до последней версии (на данный момент v72.0.2), которая устранила эту проблему.

browser.ignoreSynchronization устарело и не должно использоваться. Как указано в исходном сообщении, использование browser.get похоже, решает проблему.

Если вы хотите использовать его таким образом, чтобы вы могли отключать и включать waitForAngularEnabled по желанию, вам нужно использовать browser.get после установки waitForAngularEnabled(true) . Например:

// do things on your Angular application

waitForAngularEnabled(false)

// do things on non-angular page

waitForAngularEnabled(true)
browser.get('/home') // this is a page from your Angular application

browser.get блокируется, пока не загрузится страница Angular.

В настоящее время я получаю эту ошибку:

_Exception: ошибка: ошибка при ожидании синхронизации Protractor со страницей: «тестируемость angularJS и тестируемость angular не определены. Это может быть связано либо с тем, что это не угловая страница, либо потому, что ваш тест включает навигацию на стороне клиента, которая может мешать загрузке Protractor. Подробности см. на http://git.io/v4gXM "_

Но только при попытке отладки через отладчик VS Code или отладку инспектора Chrome (следуйте инструкциям здесь для обоих случаев https://www.protractortest.org/#/debugging).

Вот моя конфигурация launch.json в VSCode.

{
    "version": "0.2.0",
    "configurations": [
        {
            "type": "node",
            "request": "launch",
            "name": "E2E Test",
            "skipFiles": [
                "<node_internals>/**"
            ],
            "program": "${workspaceFolder}\\node_modules\\protractor\\bin\\protractor",
            "args": ["${workspaceFolder}\\e2e\\protractor.conf.js"],
            "outFiles": [
                "${workspaceFolder}/e2e/**/*.js",
                "${workspaceFolder}/src/**/*.js"
            ]
        }
    ]
}

Возможно, я что-то неправильно настроил. Любая помощь приветствуется, пытаться написать их, не имея возможности правильно отладить, безумно сложно.

Была ли эта страница полезной?
0 / 5 - 0 рейтинги