Protractor: chore(core):为客户端重定向添加更好的错误消息

创建于 2015-10-28  ·  49评论  ·  资料来源: angular/protractor

如果测试单击链接或导致browser.getbrowser.refresh之外的重定向的内容,则下次调用waitForAngular ,用户可能会遇到此错误消息( (因为我们没有等待Angular加载),这不是很有帮助。

应该告知用户出了什么问题以及潜在的解决方法(例如,使用browser.getbrowser.refresh来修复引导程序)。

debuggability

最有用的评论

@sjelin您能否再解释一下如何解决此问题?

我的用例:我有一个输入用户名/密码并单击“登录”按钮的测试,该测试将在成功登录后重定向到另一个页面。

所有49条评论

@sjelin您能否再解释一下如何解决此问题?

我的用例:我有一个输入用户名/密码并单击“登录”按钮的测试,该测试将在成功登录后重定向到另一个页面。

如果两个页面都是有角度的页面,则只需在新页面加载后添加browser.refresh即可解决问题

我们正在开发一项功能,以使将来更好

我已经为这个问题苦苦挣扎了一个星期。 如果我正在执行POST,则browser.refresh()不起作用。

请记住,这很好,谢谢。 现在,您可以通过在客户端重定向发生后仅等待几百毫秒的测试来缓解问题。 这将阻止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 ,量角器

+1可获得更好的修复。 今天不知道如何可靠地解决它。 谢谢!

有同样的问题!!! 感谢@tassoevan提供了可靠的修复程序

+1修复。

我通过在规范外执行element()。getText()(没有发生browser.get())而遇到此错误-试图为规范外的特定div的输出创建快捷方式。 把它变成一个功能,一切都很好。

我在针对\ node_modules \ protractor \ example \ conf.js运行时收到此错误,无论如何,示例conf.js都应始终有效?

对于使用不带Angular的量角器的人,有解决方法吗?

@Overdrivr您可以设置browser.ignoreSynchronization = true; 告诉量角器不要等待Angular。

当我切换Windows时,browser.ignoreSynchronization = true对我有用。

OK,但是随后您需要设置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);
    });
  });

//安排
测试从有角度的应用程序开始。
在URL而不是角度应用程序上启动mapreduce作业
返回角度应用程序以记录行数

//法案
删除1条记录
确认发生删除

//断言
在URL而不是角度应用程序上启动mapreduce作业
_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 :

在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);

角形(2)-确保您的规格以w / 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的出色解决方法并使我的重定向测试正常工作之后,我认为我将共享我的TypeScript和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页面就会创建。 所以我创建了如下的spec文件:

describe('登录到应用程序',function(){
var userID = element(by.name('username'));
var password = element(by.name('password'));
var logInButton = element(by.id('Submit'));

函数loginToApplication(stringSSOID,stringPassword){
userID.sendKeys(stringSSOID);
password.sendKeys(stringPassword);
logInButton.click();

}

beforeEach(function(){
browser.ignoreSynchronisation = true;
browser.get(''); //将导航到应用程序的登录页面
});

it('已登录到应用程序',function(){
loginToApplication('77777','test')
browser.ignoreSynchronisation = false
Expect(browser.getTitle())。toEqual('Software');
});
});

出现以下错误消息:
失败:等待量角器与页面同步时出错:“ window.an
gular未定义。 这可能是因为这是一个非角度页面,或者
因为您的测试涉及客户端导航,这可能会干扰Prot
拖拉机的自举。 有关详细信息,请参见http://git.io/v4gXM

大家好,看看http://www.protractortest.org/#/timeouts#how-to-disable-waiting-for-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;

该链接位于此线程处,但是下一步不很清楚。

使用量角器版本进行测试:5.2.1、5.1.1、5.1.0、5.0.0

@benjaminapetersen-您可以尝试使用waitForAngularEnabled代替ignoreSynchronization 。 我正在查看Protractor v5.1.2的API参考页面,它不再包含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已弃用的doc标签位于ignoreSynchronization属性上,而不是waitForAngularEnabled

waitForAngularEnabled也不适合我。 在升级到Protractor 5之前,它可以与IgnoreSynchronization一起使用。我需要切换到非Angular iframe,但现在不能。 请指教。 谢谢

@ 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);
}

注意:我在html标记上设置了ng-app

rootElement: '*[ng-app]' ? 可以只在页面上搜索任何节点? 没看过这个。

我刚刚解决了我的问题。 🥇根本原因:开发人员控制台的副作用

我遇到了这个问题,对我来说,解决方法最终是在我的package.json中更改为量角器“ ^ 5.3.2”

我有一个常规的登录页面,然后重定向到角度页面。

所以我不完全知道它是如何工作或为什么工作的,因为我对角度和角度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连接ECONNREFUSED 127.0.0.1:4444来自:任务:WebDriver.getCurrentUrl()

我通过在规范外执行element()。getText()(没有发生browser.get())而遇到此错误-试图为规范外的特定div的输出创建快捷方式。 把它变成一个功能,一切都很好。

它适用于任何事物,您不能在“ it”之外使用多个“ element()。anyfunction()”。
很难找到答案...

在量角器中从一个网页切换到另一个网页时出错:

失败:等待量角器与页面同步时出错:“未定义angularJS可测试性和角度可测试性。这可能是因为这是非角度页面,或者因为您的测试涉及客户端导航,这可能会干扰量角器的引导程序。有关详细信息,请参见http://git.io/v4gXM

代码是:
var url = browser.params.login.Url;
browser.get(URL +'/#!/ app / manage-users');

我突然开始出现此错误,这是我的CT生成的。 我注意到此错误仅在无头的Firefox上发生,而在Linux上的无头的Chrome上运行良好。 我从Firefox v69升级到了最新版本(目前为v72.0.2),从而解决了此问题。

browser.ignoreSynchronization已被弃用,不应使用。 如原始帖子所述,使用browser.get似乎可以解决此问题。

如果要以可以随意禁用和启用waitForAngularEnabled的方式使用它,则需要在设置waitForAngularEnabled(true)之后使用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:错误:等待量角器与页面同步时发生错误:“ angularJS可测试性和角度可测试性均未定义。这可能是因为这是一个非角度页面,或者是因为您的测试涉及客户端导航,可能会干扰量角器的引导。有关详细信息,请参见http://git.io/v4gXM"_

但是仅当尝试通过VS Code调试器或chrome inspector调试进行调试时(两种情况均遵循此处的说明,https://www.protractortest.org/#/debugging)。

这是我在VSCode中的launch.json配置。

{
    "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 等级