Protractor - button click calls the callback sooner than desired

*爱你&永不变心* 提交于 2019-12-10 10:13:10

问题


I have a protractor test for login page, that submits creds and checks if index page is loaded. I am passing a callback function to the button click's then function, assuming the callback will be invoked after the promise returned by click function is resolved.

var protractor = require('protractor')
describe('E2E: main page', function() {
  beforeEach(function() {
    browser.get('http://localhost:8001/login.html/');
  });
  it("login in the portal", function(){
    var d = protractor.promise.defer();
    element(by.model('loginParams.email')).sendKeys('saravana0209@r.com');
    element(by.model('loginParams.password')).sendKeys('password');
    element(by.name('normalLogin')).click().then(function(){
        //it crashes here before selecting the sub menu item
        element(by.xpath('//a[@title="subMenuItem"]')).click()
        console.log("sub-menu item has been chosen in the ribbon")
        setTimeout(function() { d.fulfill('ok')}, 50000)
    })
    expect(d).toBe('ok');
  })
});

But the callback is getting invoked, when the page loading is in progress and it crashes the test, since the element with title, subMenuItem is still not loaded. Error is,

Error: Failed: invalid selector: Unable to locate an element with the xpath expression //a[@title="Venues"] because of the following error:
TypeError: Failed to execute 'createNSResolver' on 'Document': parameter 1 is not of type 'Node'.

回答1:


You can wait for submenu to be visible before making a click:

var EC = protractor.ExpectedConditions;

element(by.name('normalLogin')).click().then(function() {
    var subMenu = element(by.xpath('//a[@title="subMenuItem"]'));

    browser.wait(EC.visibilityOf(subMenu), 5000);
    subMenu.click();

    console.log("sub-menu item has been chosen in the ribbon");
    setTimeout(function() { d.fulfill('ok')}, 50000);
});

Since, it looks like all of the problems are coming from the manual angular bootstraping, you would have to use browser.driver.get():

If your page does manual bootstrap Protractor will not be able to load your page using browser.get. Instead, use the base webdriver instance - browser.driver.get. This means that Protractor does not know when your page is fully loaded, and you may need to add a wait statement to make sure your tests avoid race conditions.

Which could lead to something like:

element(by.name('normalLogin')).click(); 
browser.sleep(3000); 
browser.driver.get("index.html");

Login, let it log you in by having a delay (sleep is bad, yeah) and manually get the index page after.


You can also work with a disabled synchronization between protractor and angular by setting the browser.ignoreSynchronization = true;, but this have a lot of drawbacks - you would have to start using Explicit Waits (browser.wait()) a lot. You can though try to play around with this flag and set it temporarily to true before loading a page and set back to false after.




回答2:


Have you tried this?:

 element(by.name('normalLogin')).click()
    browser.wait(function() {
      return browser.driver.isElementPresent(by.xpath('//a[@title="Venues"]'))
    }).then(function(){
         var venueLink = by.xpath('//a[@title="Venues"]')
         browser.driver.isElementPresent(venueLink).then(function(){
           console.log("tenant login process successful")
           element(venueLink).click()
        })
    });

Protractor works asynchronously, so

var venueLink = by.xpath('//a[@title="Venues"]')

will be executed while

browser.wait(function() {
      return browser.driver.isElementPresent(by.xpath('//a[@title="Venues"]'))
    })


来源:https://stackoverflow.com/questions/31498207/protractor-button-click-calls-the-callback-sooner-than-desired

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!