How to report angular pending requests on protractor timeouts? - javascript

I've been working on some protractor tests lately and from time to time some of my tests randomly fail with the following error:
DEBUG - WebDriver session successfully started with capabilities { caps_:
{ platform: 'LINUX',
acceptSslCerts: true,
javascriptEnabled: true,
browserName: 'chrome',
chrome: { userDataDir: '/tmp/.com.google.Chrome.czw4dR' },
rotatable: false,
locationContextEnabled: true,
mobileEmulationEnabled: false,
'webdriver.remote.sessionid': '3afc09d9-d06d-4c99-a788-d1118093c08d',
version: '40.0.2214.111',
takesHeapSnapshot: true,
cssSelectorsEnabled: true,
databaseEnabled: false,
handlesAlerts: true,
browserConnectionEnabled: false,
nativeEvents: true,
webStorageEnabled: true,
applicationCacheEnabled: false,
takesScreenshot: true } }
Started
token: a62e88d34991f4eef0894102e004e92032857700
.F...........................
Failures:
1) login form filled should fail on wrong credentials
Message:
Failed: Timed out waiting for Protractor to synchronize with the page after 11 seconds. Please see https://github.com/angular/protractor/blob/master/docs/faq.md
Looking at protractor documentation this error usually happens when there are pending $http requests or i'm using $timeout for something. I've tried setting a longer timeout for my tests(minutes) but it hasn't helped. My latest idea has been to report what requests are pending so i made the following Jasmine Reporter:
var AngulaRequestsReporter = function(dir){
dir = (dir || '/tmp/protractors/');
this.requests = function(testDescription) {
var fname = testDescription.replace(/\s/g, '_') + '.pending_requests';
mkdirp(dir);
browser.executeScript(function(){
try{
var $http = angular.injector(["ng"]).get("$http");
return $http.pendingRequests;
}catch(e){
return [];
}
}).then(function(pendingRequests){
var stream = fs.createWriteStream(path.join(dir, fname));
stream.write(util.inspect(pendingRequests, {showHidden: false, depth: null}));
stream.end();
});
};
return this;
};
// takes screenshot on each failed spec (including timeout)
AngulaRequestsReporter.prototype = {
specDone: function(result) {
if (result.status !== 'passed') {
this.requests(result.description );
}
}
};
However the result is always an empty []. Have you guys had this problem before and if so how did you solve it? Also, is there anything i can make to improve this reporter?

Related

Mail listener on nodejs not disconnecting

I'm currently using mail-listener5 package to assert the number of emails in the Inbox of an email address.
My test framework is nightwatchjs.
Currently, my command script to get the number of emails from the email address inbox (titled getInboxEmails) is;
var {MailListener} = require('mail-listener5');
exports.command = function() {
this.perform(function(done) {
var mailListener = new MailListener({
username: '##########outlook.com',
password: '#########',
host: 'imap-mail.outlook.com',
port: 993,
tls: true,
connTimeout: 10000,
authTimeout: 5000,
tlsOptions: { rejectUnauthorized: false },
mailbox: 'Inbox',
searchFilter: ['ALL'],
markSeen: true,
fetchUnreadOnStart: false,
attachments: false,
});
mailListener.start();
mailListener.on('server:connected', function() {});
mailListener.on('mailbox', function(mailbox) {
var totalInboxMessages = (mailbox.messages.total);
console.log('Total number of Inbox emails: ', totalInboxMessages);
});
// mailListener.on('server:disconnected', function() {
// });
// mailListener.stop();
done();
});
};
And my nightwatchjs test script looks like this;
module.exports = {
'getting emails...': function (browser) {
browser.getInboxEmails();
},
'bfs': function (browser) {
browser.url('https://www.motorcyclenews.com/bikes-for-sale/****');
*...assertions, etc*
},
'closing the browser': function (browser) {
browser.browserEnd();
},
};
When I run this nightwatchjs script, the following is outputted;
however, the browser doesn't close.
I kind of expected this, as in my getInboxEmails command script included;
// mailListener.on('server:disconnected', function() {
// });
// mailListener.stop();
However, when I uncommented these two commands, I didn't get the number of emails displayed (but the test/browser correctly 'shut down'.
So the output was now;
So it appears that the number of emails is correctly displayed when the disconnect and stop are omitted, but the test doesn't cease.
And when the disconnect and stop are added, the number of emails is not displayed but the test finishes correctly.
And what I'd like to do is list the number of emails and for the test to end.
Any help would be greatly appreciated.
Yo need to init your mail listener in beforeAll part
and stop that in afterAll
the problem in your example is that your stop is reached in the init part so your mailbox listener will never be raised
mailListener.on('mailbox', function(mailbox) {
var totalInboxMessages = (mailbox.messages.total);
console.log('Total number of Inbox emails: ', totalInboxMessages);
});
Just do some staff as below
let mailListener ;
jest.beforeAll(() => {
mailListener = new MailListener({
username: '##########outlook.com',
password: '#########',
host: 'imap-mail.outlook.com',
port: 993,
tls: true,
connTimeout: 10000,
authTimeout: 5000,
tlsOptions: { rejectUnauthorized: false },
mailbox: 'Inbox',
searchFilter: ['ALL'],
markSeen: true,
fetchUnreadOnStart: false,
attachments: false,
});
mailListener.start();
mailListener.on('server:connected', function() {});
mailListener.on('mailbox', function(mailbox) {
var totalInboxMessages = (mailbox.messages.total);
console.log('Total number of Inbox emails: ', totalInboxMessages);
});
});
and finally in the end part of your tests
jest.afterAll(() => {
mailListener.stop();
});
wish this help

Test failing only in headless chrome

I have some integration tests using wdio, they are all passing. However, when I run them in headless chrome, one of these tests fails. I get this error:
1) Reset password by submitting a new password "before all" hook:
element ("#identifierNext") still not existing after 15000ms
The problem is in this line of code:
browser.waitForExist('#identifierNext');
Which is weird, because I am using the waitForExist(<element id>) in other tests as well and they pass even in headless chrome. I also tried to increase the waitFor limit up to 30000ms, but it fails anyway.
This is my wdio config:
exports.config = {
specs: [
'./test/pageobjects/**/reset_password.spec.js'
],
maxInstances: 1,
capabilities: [{
maxInstances: 1,
browserName: 'chrome',
'goog:chromeOptions': {
args: ['--headless', '--disable-gpu', '--window-size=1280,800', '--no-sandbox', '--disable-dev-shm-usage']
}
}],
sync: true,
logLevel: 'silent',
coloredLogs: true,
deprecationWarnings: true,
bail: 0,
screenshotPath: './errorShots/',
baseUrl: 'http://127.0.0.1:3000',
waitforTimeout: 10000,
connectionRetryTimeout: 90000,
connectionRetryCount: 3,
services: ['selenium-standalone'],
framework: 'mocha',
reporters: ['spec'],
mochaOpts: {
ui: 'bdd',
timeout: 30000
},
}
When I remove headless from chromeOptions, this test passes normally. Any ideas why this happens?
EDIT: this is my reset_password.spec.js file:
describe ('Reset password by submitting a new password', function(){
//test fails in this before function
before(function(){
browser.url(ResetPassword.token_url(valid_email, email_password));
});
it ('Password reset without passwords', function(){
.
.
.
})
});
And my reset_password.page.js file:
const Page = require('./page');
class ResetPassword extends Page {
get email() {
return $('input[type="text"]');
}
get url() {
return browser.getUrl();
}
open() {
super.open('/reset-password');
}
get signIn(){
browser.waitForExist('*=Sign in');
return $('*=Sign in');
}
get enterEmail(){
browser.waitForExist('input[type="email"]');
return $('input[type="email"]');
}
get submitEmail(){
//this fails in headless mode
browser.waitForExist('#identifierNext');
return $('#identifierNext');
}
get enterPassword(){
browser.waitForExist('#password > div.aCsJod.oJeWuf > div > div.Xb9hP > input');
return $('#password > div.aCsJod.oJeWuf > div > div.Xb9hP > input');
}
get submitPassword(){
browser.waitForExist('#passwordNext');
return $('#passwordNext');
}
get tokenEmail(){
browser.waitForExist('span[email="profiq.ldap#gmail.com"]');
return $$('span[email="profiq.ldap#gmail.com"]');
}
get tokenURL(){
browser.waitForExist('a[id*=reset_link]');
const links = $$('a[id*=reset_link]');
return links[links.length-1].getAttribute('href');
}
token_url(email, password){
browser.url('https://www.google.com/gmail/about/#');
this.signIn.click();
browser.switchTab(browser.getTabIds()[1]);
this.enterEmail.setValue(email);
this.submitEmail.click();
this.enterPassword.setValue(password);
this.submitPassword.click();
this.tokenEmail[1].click();
browser.pause(3000);
return this.tokenURL;
}
}
module.exports = ResetPassword;
I found the problem. Gmail displays differently in different browsers. I took a screenshot using browser.saveScreenshot('screenshot.jpg'); just before the test fails, and it shows that the page looked different (was in my local language instead of english and had different appearance and buttons). So this is the reason why the test could not find the button with given identifier.

IOS: "Failed: Method is not implemented" error when I tried to perform some touch actions

I am testing Hybrid app and I tried to perform some touch actions on iOS like doubleTap and tapAndHold on WebView. And I get "Failed: Method is not implemented" error.
I tried the below code :
browser.switchTo().frame(0);
return browser.touchActions().doubleTap(element).perform();
But when I try
return browser.touchActions().tap(element).perform();
everything is ok.
For Android this code works fine.
Appium: 1.7.1
Protractor: 5.1.2
webdriver-manager 12.0.6.
MacOS High Sierra
So how can I perform this touch actions on iOS?
conf.js:
var wd = require('wd'),
wdBridge = require('wd-bridge')(require('protractor'), wd);
const config = {
sync: false,
seleniumAddress: 'http://localhost:4723/wd/hub',
capabilities: {
browserName: '',
appiumVersion: "1.7.1",
deviceName: "iPhone 8",
deviceOrientation: "portrait",
platformName: "iOS",
platformVersion: "11.0",
app:"",
bundleId:'',
launchTimeout: 20000,
webviewConnectRetries: 1,
autoAcceptAlerts: true,
autoWebview: true,
waitForAppScript: 'true',
nativeInstrumentsLib:'false',
showIOSLog:'false',
newCommandTimeout: 5000
},
framework: 'jasmine2',
allScriptsTimeout: 1500000,
jasmineNodeOpts: {
showColors: true,
print: function () {
},
isVerbose: true,
includeStackTrace: true,
defaultTimeoutInterval: 1500000
},
suites: {
smoke: ['./automation/smoke/*.js'],
},
beforeLaunch: function () {
return new Promise(function (resolve) {
reporter.beforeLaunch(resolve);
});
},
onPrepare: function () {
wdBridge.initFromProtractor(exports.config);
browser.ignoreSynchronization = true;
browser.wBridge=wdBridge;
browser.getProcessedConfig()
.then(function (config) {
browser.appPackage = config.capabilities.appPackage;
browser.bundleId = config.capabilities.bundleId;
browser.deviceProperties = config.capabilities.deviceProperties;
browser.platformname = config.capabilities.platformName;
var iOSProperties = {'identifier': browser.bundleId},
androidProperties = {'identifier': browser.appPackage},
params = browser.platformname.toLowerCase() === 'iOS' ? androidProperties : iOSProperties;
browser.ignoreSynchronization = true;
wdBrowser.currentContext().then(function(context) {
console.log('#context');
console.log(context);
});
});
},
useAllAngular2AppRoots: true,
restartBrowserBetweenTests: false
};
exports.config = config;
There is no doubleTap function in wd project, so the error you get is expected to see.
If you check appium server commands for doubleTap, you will notice that for wd client code is the same to tap code, so it really looks like doubleTap is not supported by wd yet
So far I see 2 options:
1) Play more with existing functions in wd touch actions, e.g. try
const location = await element.getLocation()
const action = new wd.TouchAction()
action.press({x: location.x, y: location.y})
.release()
.press({x: location.x, y: location.y})
.release()
await browser.performTouchAction(action)
2) Implement doubleTap in wd project looking into examples from java or python client.

Protractor doesn't wait for page to load before moving to next it block in firefox

I'm facing a problem working with protractor along with firefox.
In my test i first direct the browser to a login page and after entering user and password i do another browser.get action that refers me to a different page.
Both the login page and the second page are non-angular pages.
The issue i'm facing is that firefox doesn't wait for the initial page to load and right away tries to do the redirect action.
I tried firefox versions: 27.0.1, 28.0, 42.0, 45.0.1 and 46.0.1 (all 32bit versions) all versions shows the same behavior.
The webdriver-manager version is 10.0.4, selenium webdriver version is 2.53, os win8.1 64 bit and protractor version is 3.1.1.
When running the same test on chrome browser the test run as it should, it waits for the login to finish and only then it goes to the next it block that performs the browser.get action.
My conf file:
var HtmlScreenshotReporter = require('protractor-jasmine2-screenshot-reporter');
var path = require('path');
exports.config = {
framework: 'jasmine2',
seleniumAddress: 'http://localhost:4444/wd/hub',
specs: ['multiTestRun.js'],
getPageTimeout: 60000,
rootElement: '[ng-app]',
jasmineNodeOpts: {
showColors: true,
defaultTimeoutInterval: 10000000,
isVerbose: true,
includeStackTrace: true
},
params: {
test: 'Regression',
resources: 3,
locations: 4,
skills: 2,
services: 0,
useNameSpace: 0
},
capabilities: {
'browserName': 'firefox'
},
onPrepare: function(){
var dest = path.normalize('./Results');
browser.manage().timeouts().setScriptTimeout(120000);
jasmine.getEnv().addReporter(
new HtmlScreenshotReporter({
dest: dest,
filename: 'my-report.html',
showQuickLinks: true,
reportOnlyFailedSpecs: false,
captureOnlyFailedSpecs: true,
restartBrowserBetweenTests: true
})
);
global.isAngularSite = function(flag){
browser.ignoreSynchronization = !flag;
};
browser.driver.manage().window().maximize();
}
};
My code file:
describe('test', function () {
beforeEach(function(){
isAngularSite(false);
}, 60000);
it('it1', function () {
browser.get('https://example.com/');
element(By.id('username')).clear();
element(By.id('username')).sendKeys('sanu#field.com');
element(By.id('password')).clear();
element(By.id('password')).sendKeys('1234.org');
element(By.id('Login')).click();
});
it('it2', function () {
browser.get('https://example.com/SecondPage');
browser.get('https://example.com/SecondPage');
browser.executeScript('return RemoteActions;')
.then(function(remoteAction) {
console.log('remoteAction.doAction');
console.log(remoteAction.doAction);
browser.executeAsyncScript(function(remoteAction) {
var callback = arguments[arguments.length - 1];
Visualforce.remoting.Manager.invokeAction(remoteAction.doAction, function (res, ev) {
callback(res);
}, { buffer: false, escape: false, timeout: 10000 });
},remoteAction).then(function(res) {
console.log(res);
});
});
});
any advice ?
Since these are not angular pages, and you are turning off synchronization, you will have to tell webdriver how to wait for something to happen after clicking the login button before performing the next action.
In this example, you can wait for the login button to no longer be present, so that you know it is ready to navigate to the next page.
element(By.id('Login')).click();
browser.wait(function() {
element(By.id('Login')).isDisplayed().then(function(loginButtonIsDisplayed) {
// break out of the loop by returning 'true' when the login button is not displayed
return !loginButtonIsDisplayed;
), browser.getPageTimeout, 'after clicking the login button, the next page did not load within ' + browser.getPageTimeout + 's'};
browser.get('https://example.com/SecondPage');
browser.getPageTimeout is a protractor timeout that is set to 10 seconds by default

Unable to retrieve email information in protractor

Referencing the information from the question Fetching values from email in protractor test case, I am still unable to reference the emails. In my test case, the 'expect' is not getting executed for some unknown reason to me.
Also if I use the line,
browser.controlFlow().await(getLastEmail()).then(...)
There is a 'browser.controlFlow(...).await is not a function error'
conf.js
var MailListener = require("mail-listener2")
exports.config = {
framework: 'jasmine2',
specs: ['./test.js'],
jasmineNodeOpts: { defaultTimeoutInterval: 360000 },
allScriptsTimeout: 60000,
onPrepare: function () {
var mailListener = new MailListener({
username: "username",
password: "password",
host: "imapPort",
port: 993, // imap port
secure: true,
tls: true,
tlsOptions: { rejectUnauthorized: false },
mailbox: "INBOX", // mailbox to monitor
searchFilter: ["UNSEEN", "FLAGGED"], // the search filter being used after an IDLE notification has been retrieved
markSeen: true, // all fetched email willbe marked as seen and not fetched next time
fetchUnreadOnStart: true, // use it only if you want to get all unread email on lib start. Default is `false`,
mailParserOptions: {streamAttachments: true}, // options to be passed to mailParser lib.
attachments: true, // download attachments as they are encountered to the project directory
attachmentOptions: { directory: "attachments/" } // specify a download directory for attachments
})
mailListener.start()
mailListener.on("server:connected", function(){
console.log("Mail listener initialized")
})
mailListener.on("error", function(err){
console.log(err)
})
mailListener.on("server:disconnected", function(){
console.log("imapDisconnected")
})
global.mailListener = mailListener
},
onCleanUp: function () {
mailListener.stop()
}
}
The test case:
describe('Email Testing', function () {
it('should login with a registration code sent to an email', function () {
//this line causes a 'browser.controlFlow(...).await is not a function' error
// browser.controlFlow().await(getLastEmail()).then(function (email) {
getLastEmail().then(function (email) {
// The expect does not get executed as it should fail
expect(email.subject).toEqual('My Subject')
})
})
})
function getLastEmail () {
var deferred = protractor.promise.defer()
console.log('Waiting for an email...')
mailListener.on('mail', function (mail) {
console.log('No Console Log Here!')
deferred.fulfill(mail)
})
return deferred.promise
}
I am not certain what I am missing in my test case to be able to read the subject or body of the email?
Ran into the same issue today. Turns out the API for the webdriver and ControlFlow has been updated and await has been changed to wait. Yeah, subtle difference. See the new API reference here: https://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/lib/promise_exports_ControlFlow.html
To schedule a task for the wait condition, change your code to look like this:
browser.controlFlow().wait(getLastEmail()).then(...)
you would basically have to wrap that asynchronous code inside of a promise and the pass that promise/function into the flow.execute()
var flow = protractor.promise.controlFlow();
flow.execute( getLastEmail() ).then(function(email){
text = email.text
});

Categories

Resources