问题
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