ScriptTimeoutError while testing angular material dropdown e2e - testing

I have this test case
it("should have list", async () => {
// wait until list populated
browser.wait(protractor.until.elementLocated(by.css(COMPONENT_CSS.ITEM)));
console.log("First...............");
try {
await componentPage.toggleDD();
} catch (err) {
console.log("err", err);
}
console.log("Second...............");
const count = await componentPage.getCount();
console.log("count", count);
expect(count).toBe(this.COUNT);
await componentPage.toggleDD();
});
and here is toggleDD
async toggleDD(): Promise<any> {
const _dropdown = await element(by.id(this.CSS.DD_ID));
await _dropdown.click();
}
but this shows
err ScriptTimeoutError: script timeout
(Session info: chrome=84.0.4147.135)
(Driver info: chromedriver=84.0.4147.30 (48b3e868b4cc0aa7e8149519690b6f6949e110a8-refs/branch-heads/4147#{#310}),platform=Windows NT 6.3.9600 x86_64)
at Object.checkLegacyResponse (E:\PROJECTS\NewProject\node_modules\selenium-webdriver\lib\error.js:546:15)
at parseHttpResponse (E:\PROJECTS\NewProject\node_modules\selenium-webdriver\lib\http.js:509:13)
at E:\PROJECTS\NewProject\node_modules\selenium-webdriver\lib\http.js:441:30
at processTicksAndRejections (internal/process/task_queues.js:94:5)
From: Task: Protractor.waitForAngular() - Locator: By(css selector, *[id="my-dropdown"])
and fails the test case, I have tried putting await before browser.wait, tried by.xpath, by.id, by.css to get dropdown.
I tried it in debug mode, elements are present on DOM but somehow it is not getting the element.
Checked other element to get for each element it is showing
- Failed: script timeout
(Session info: chrome=84.0.4147.135)
(Driver info: chromedriver=84.0.4147.30 (48b3e868b4cc0aa7e8149519690b6f6949e110a8-refs/branch-heads/4147#{#310}),platform=Windows NT 6.3.9600 x86_64)
I tried
<div id="dummyId">Hello</div>
with this div by
const _divText = await element(by.id("dummyId")).getText();
even for this I am getting scripttimeout err
More Info
Here is beforeAll
beforeAll(async () => {
componentPage = new HomePage();
helperService = new HelperService();
COMPONENT_CSS = componentPage.CSS;
await helperService.navigate(helperService.PAGE_URL.HOME);
try {
await helperService.skipIntro();
} catch (err) {
console.error("Intro element not found");
}
// browser.waitForAngular();
});
and protractor.conf.js
// Protractor configuration file, see link for more information
// https://github.com/angular/protractor/blob/master/lib/config.ts
const { SpecReporter } = require("jasmine-spec-reporter");
exports.config = {
allScriptsTimeout: 50000,
specs: [
"./src/login/login.component.e2e-spec.ts",
"./src/home/home.component.e2e-spec.ts",
],
capabilities: {
"browserName": "chrome"
},
directConnect: true,
baseUrl: "http://localhost:4200/",
framework: "jasmine",
jasmineNodeOpts: {
showColors: true,
defaultTimeoutInterval: 1000000,
print: function () {
}
},
onPrepare() {
require("ts-node").register({
project: require("path").join(__dirname, "./tsconfig.e2e.json")
});
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
}
};

Looking at the error, it appears that the element is not displayed before you want to interact with it. until.elementLocated appears to call into findElements and return the first element.
See https://github.com/SeleniumHQ/selenium/blob/trunk/javascript/node/selenium-webdriver/lib/until.js#L241
This means that it will return it if it is in the DOM but doesn't mean that it will be displayed or enabled to click. The isDisplayed call explicitly checks that the element is displayed.
See https://github.com/SeleniumHQ/selenium/blob/trunk/javascript/node/selenium-webdriver/lib/webdriver.js#L2296
Maybe instead do something like this?
it("should have list", async () => {
// wait until list populated
await browser.wait(async () => {
return element(by.css(COMPONENT_CSS.ITEM)).isDisplayed();
}, 10000); // wait 10 seconds, make sure your protractor suite does not time out.

Related

Protractor - How to use tags on Jasmine for e2e testning

I'm having some issues where I am stuck on what to do to be able to tag different tests that I want to run.
The tests that I want is only required at the end where I want to be able to tag which payment I would like to pay which is Mastercard, Visa or Amex. I do have a test that does the details page such as writing users information, choose shipment but then at the end I do have multiply options that I would like to test pending on what I want to test:
paymentPage.js
describe('Payment page', function () {
paymentPage = new PaymentPage();
// The details page is accessible by the specified URL
it(`Credit Card - Has a form that can receive user data`, async function () {
await paymentPage.creditCardPayment();
});
//Visa
it('Enets payment', async function () {
//TODO
});
//Amex
it('Enets payment', async function () {
//TODO
});
});
As you can see there is 3 options that I would like to test so whenever I do etc "protractor e2e run mastercard" so that means it should run the first test case, if I choose visa then do the second test case and skip the rest basically.
However I do have couple of tests that executes before coming to the payment page but they all need to do the same for each payment so meaning that all test cases before payment needs to do exactly the same thing everytime (So I guess we just need to do tags at the payment to let the script know which payment to choose)?
How can I do a sort of tagging or maybe someone has another solution that is better? That I can be able to choose what payment provider I want to run
edit:
exports.config = {
capabilities: {
browserName: 'chrome',
chromeOptions: {
args: [
'incognito', 'disable-extensions', 'start-maximized', 'disable-infobars', '--window-size=1920,1080'
]
},
loggingPrefs: { browser: 'ALL' },
platform: 'ANY',
version: ''
},
specs: [
'pagesDesktop/testPage.js',
'pagesDesktop/paymentPage.js'
],
jasmineNodeOpts: {
reporter: "mochawesome",
defaultTimeoutInterval: 60000
},
SELENIUM_PROMISE_MANAGER: false,
framework: 'jasmine',
params: {
cardType: {
}
}
};
describe('Payment page', function () {
paymentPage = new PaymentPage();
console.log(browser.params.cardType);
if (browser.params.cardType === "mastercard") {
// The details page is accessible by the specified URL
it(`Credit Card - Has a form that can receive user data`, async function () {
await paymentPage.creditCardPayment();
});
}
just add if/else logic
describe('Payment page', function () {
paymentPage = new PaymentPage();
// The details page is accessible by the specified URL
it(`Credit Card - Has a form that can receive user data`, async function () {
await paymentPage.creditCardPayment();
});
if (browser.params.cardType === 'visa') {
it('Enets payment', async function () {
//TODO
});
} else if (browser.params.cardType === 'amex') {
//Amex
it('Enets payment', async function () {
//TODO
});
}
});
You can read how to parameterize teste here How can I use command line arguments in Angularjs Protractor?, or here
https://medium.com/#nicklee1/making-your-protractor-tests-data-driven-e3c9e2a5e4e7

Spectron with mocha and chai does not work

I am trying to write a tests with Spectron for our Electron App, but I am running into problems with the setup. I use the classical setup with chai. I have one file which contains setup code:
const path = require("path");
const { Application } = require("spectron");
module.exports = {
initialiseSpectron: () => {
let electronPath = path.join(__dirname, "../../node_modules", ".bin", "electron");
if (process.platform == "win32") {
electronPath += ".cmd";
}
return new Application({
path: electronPath,
args: [path.join(__dirname, "../index.ts"), path.join(__dirname, "../../package.json")],
env: {
ELECTRON_ENABLE_LOGGING: true,
ELECTRON_ENABLE_STACK_DUMPING: true,
NODE_ENV: "development"
},
startTimeout: 10000,
chromeDriverLogPath: "../chromedriverlog.txt"
});
},
sleep: time => new Promise(resolve => setTimeout(resolve, time))
};
And then the test itself:
const chaiAsPromised = require("chai-as-promised");
const chai = require("chai");
chai.should();
chai.use(chaiAsPromised);
const testHelper = require("./initialise");
const app = testHelper.initialiseSpectron();
// Setup Promises and start Application
before(() => app.start());
// Tear down App after Tests are finished
after(() => {
if (app && app.isRunning()) {
return app.stop();
}
});
describe("Login", () => {
it("opens a window", function() {
return app.client
.waitUntilWindowLoaded()
.getWindowCount()
.should.eventually.equal(1);
});
it("tests the title", () =>
app.client
.waitUntilWindowLoaded()
.getTitle()
.should.eventually.equal("VIPFY"));
});
My problem is that I always get this error:
1) "before all" hook in "{root}"
0 passing (2s)
1 failing
1) "before all" hook in "{root}":
Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves.
So it looks like the App does not start. But that is not true. The App Window opens, but it seems like the test does not recognize that. I have already tried changing the path using all kinds of syntax. But nothing worked. What am I missing?
Have you tried to increase the timeout for mocha?
Sometimes I had it fail first time, then worked on the second try.
See a working sample here with Electron 6:
https://github.com/florin05/electron-spectron-example

Slack integration only works on onPrepare, but not in onComplete, afterLaunch?

I am hooking my protractor tests with Slack, the idea is to send a message on a slack room if the test started and once it's done.
However, I can only successfully send messages to slack during onPrepare. But not in afterLanch or even in onComplete.
I tried to do a simple console.log in the afterLaunch and onComplete so I know it works. The only thing that's confusing me is why it does not send the message in slack AFTER the test is done.
If there is a better way of doing this, please tell me your ideas. Right now, this is the best i've got.
Please see my code:
let SpecReporter = require('jasmine-spec-reporter').SpecReporter;
var webRep = require('jasmine-slack-reporter');
var Jasmine2HtmlReporter = require('protractor-jasmine2-html-reporter');
var SlackWebhook = require('slack-webhook');
var slack = new SlackWebhook('my-webhook-url');
exports.config = {
capabilities: {
'browserName' : 'chrome',
},
seleniumAddress: 'http://localhost:4446/wd/hub',
specs: ['./smoke-test/loginAccountType.js'],
onPrepare: function () {
browser.ignoreSynchronization = true,
slack.send({
text: "Test is starting",
channel: '#test-report'
}),
jasmine.getEnv().addReporter(new SpecReporter({
spec: {
displayStacktrace: true
}
})),
jasmine.getEnv().addReporter(
new Jasmine2HtmlReporter({
savePath: './reports',
takeScreenshotsOnlyOnFailures: true,
})
);
},
afterLaunch: function () {
slack.send({
text: "Test is Done",
channel: '#test-report'
})
},
jasmineNodeOpts: {
// Default time to wait in ms before a test fails.
defaultTimeoutInterval: 100000,
print: function() {},
},
};
It seems like your slack.send() is async?
Try to return promise from your afterLanch/onComplete - in this case protractor will wait for this promise to resolve before killing node.js process.
I never worked with slack-webhook package. But what i see in documentation - .send() is returning promise. Try to return it from your afterLaunch/onComplete:
afterLaunch: function () {
return slack.send({
text: "Test is Done",
channel: '#test-report'
})
},
In addition to #Xotabu4 his answer.
According to the docs the send is async, so do a return;
But also catch the error, just to check what fails, see below.
return slack.send('some text')
.then(function(res) {
// succesful request
})
.catch(function(err) {
// handle request error
})
Hope it helps

ProtractorJS: Error while waiting for Protractor to sync with the page: "Could not find testability for element."

I'm trying to end-to-end test my Angular 2 project with ProtractorJS.
When I run protractor conf.js in my console, I get:
Failed: Error while waiting for Protractor to sync with the page: "Could not
find testability for element."
Inside the config file:
exports.config = {
seleniumAddress: "http://localhost:4444/wd/hub",
framework:"jasmine2",
capabilities: {"browserName": "chrome"},
specs: ["todo-spec.js"]
};
My root component:
<section>
<h1>Employee Payroll Information Directory</h1>
<employee-searchform></employee-searchform>
</section>
This is the test I'm trying to run:
describe('modal component', function () {
it('should output the employee and delete it from the array', function () {
browser.get('http://localhost:80/Fourth/Fourth/');
var searchField = element(by.className('.ng-valid'));
searchField.click();
searchField.sendKeys('Skye');
searchField.getText().then(function (text) {
console.log(text);
});
var employeeListItem = element(by.id('employee-list'));
});
});
This is what I get on the webDriver Selenium server:
23:57:25.816 INFO - Done: [execute async script: try { return (function (rootSel
ector, callback) {
var el = document.querySelector(rootSelector);
try {
if (window.getAngularTestability) {
window.getAngularTestability(el).whenStable(callback);
return;
}
if (!window.angular) {
throw new Error('angular could not be found on the window');
}
if (angular.getTestability) {
angular.getTestability(el).whenStable(callback);
} else {
if (!angular.element(el).injector()) {
throw new Error('root element (' + rootSelector + ') has no injector.' +
' this may mean it is not inside ng-app.');
}
angular.element(el).injector().get('$browser').
notifyWhenNoOutstandingRequests(callback);
}
} catch (err) {
callback(err.message);
}
}).apply(this, arguments); }
catch(e) { throw (e instanceof Error) ? e : new Error(e); }, [body]]
23:57:25.899 INFO - Executing: [delete session: 35adb055-eee3-419e-b3c1-461b65b4
18aa])
23:57:29.157 INFO - Done: [delete session: 35adb055-eee3-419e-b3c1-461b65b418aa]
You should point Protractor to the element housing the Angular app. This can be done by setting the rootElement in your protractor config:
rootElement: 'app',
if you use By.className() you no need to mention "." in front of your class name. You can simply use By.className("ng-valid")

How to test an Electron app with selenium webdriver

I have read the documentation and I have followed the tutorial step by step and I only have managed to run the app.
Documentation: http://electron.atom.io/docs/tutorial/using-selenium-and-webdriver/
The connection with chromedriver I cannot make it work, when I launch the test and try click a simple button I get this:
Error: ChromeDriver did not start within 5000ms at Error (native)
at node_modules/spectron/lib/chrome-driver.js:58:25 at
Request._callback (node_modules/spectron/lib/chrome-driver.js:116:45)
at Request.self.callback
(node_modules/spectron/node_modules/request/request.js:200:22) at
Request.
(node_modules/spectron/node_modules/request/request.js:1067:10) at
IncomingMessage.
(node_modules/spectron/node_modules/request/request.js:988:12) at
endReadableNT (_stream_readable.js:913:12) at _combinedTickCallback
(internal/process/next_tick.js:74:11) at process._tickCallback
(internal/process/next_tick.js:98:9)
My code:
"use strict";
require("co-mocha");
var Application = require('spectron').Application;
var assert = require('assert');
const webdriver = require('selenium-webdriver');
const driver = new webdriver.Builder()
.usingServer('http://127.0.0.1:9515')
.withCapabilities({
chromeOptions: {
binary: "./appPath/app"
}
})
.forBrowser('electron')
.build();
describe('Application launch', function () {
this.timeout(100000);
var app;
beforeEach(function () {
app = new Application({
path: "./appPath/app"
});
return app.start();
});
afterEach(function () {
if (app && app.isRunning()) {
return app.stop();
}
});
it('click a button', function* () {
yield driver.sleep(5000);
yield driver.findElement(webdriver.By.css(".classSelector")).click();
});
});
Thanks and sorry for my English.
I recommend you to use Spectron. which is a less painful way of testing your electron app. in my opinion perfect combination is using it with Ava test framework, which allows the concurrently test.
async & await is also another big win. which allows you to have so clean test cases.
and also if you have a test which needs to happen serial, you can use test.serial
test.serial('login as new user', async t => {
let app = t.context.app
app = await loginNewUser(app)
await util.screenshotCreateOrCompare(app, t, 'new-user-mission-view-empty')
})
test.serial('Can Navigate to Preference Page', async t => {
let app = t.context.app
await app.client.click('[data-test="preference-button"]')
await util.screenshotCreateOrCompare(app, t, 'new-user-preference-page-empty')
})
and just for reference; my helper test cases.
test.before(async t => {
app = util.createApp()
app = await util.waitForLoad(app, t)
})
test.beforeEach(async t => {
t.context.app = app
})
test.afterEach(async t => {
console.log('test complete')
})
// CleanUp
test.after.always(async t => {
// This runs after each test and other test hooks, even if they
failed
await app.client.localStorage('DELETE', 'user')
console.log('delete all files')
const clean = await exec('rm -rf /tmp/DesktopTest')
await clean.stdout.on('data', data => {
console.log(util.format('clean', data))
})
await app.client.close()
await app.stop()
})
util function,
// Returns a promise that resolves to a Spectron Application once the app has loaded.
// Takes a Ava test. Makes some basic assertions to verify that the app loaded correctly.
function createApp (t) {
return new Application({
path: path.join(__dirname, '..', 'node_modules', '.bin',
'electron' + (process.platform === 'win32' ? '.cmd' : '')),
// args: ['-r', path.join(__dirname, 'mocks.js'), path.join(__dirname, '..')],
env: {NODE_ENV: 'test'},
waitTimeout: 10e3
})
}
First off, Spectron (which is a wrapper for WebdriverIO) and WebdriverJS (which is part of Selenium-Webdriver) are two different frameworks, you only need to use one of them for your tests.
If you are using WebdriverJS, then you need to run ./node_modules/.bin/chromedriver in this step: http://electron.atom.io/docs/tutorial/using-selenium-and-webdriver/#start-chromedriver
I could get ChromeDriver working by adding a proxy exception in my terminal.
export {no_proxy,NO_PROXY}="127.0.0.1"