Unable to locate MatSnackBar element in protractor e2e test - javascript

I am not able to locate MatSnackBar element using protractor.
This is how I display snack bar.
const snackBarRef = this.snackBar.open('Book added.', 'Undo', {
duration: 300000
});
This is e2e test.
const snackBar = element(by.tagName('simple-snack-bar'));
browser.wait(ExpectedConditions.visibilityOf(snackBar), 30000);
element(by.tagName('simple-snack-bar')).getText().then(function (val) {
console.log(val);
expect(val).toEqual('Book added');
});
Test code fails with this error.
Error: Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.

Thanks for your message, #dplavcic.
The reason that my code didn't work is that snackbar was out of angular root. So I have to use browser.driver.findElement() instead of element(), and finally have solved the issue.
Something like:
public getSnackBar(): promise.Promise<string> {
const snackbar = browser.driver.wait(until.elementLocated(By.tagName('simple-snack-bar')), 10000);
return snackbar.getText();
}```

The time out is from the browser.wait of 30 second, so the application cannot find the elemnt with in that time . so increase the time out as :
add below property to your config file:
jasmineNodeOpts: {defaultTimeoutInterval: 40000}
About element not found
make sure elemnt is not inside iframe or shadown , if so , then switch to parent before accessing it
use promise chaining properly or use await instead
it('should find an element by text input model', async function() {
await browser.get('app/index.html#/form');
var username =element(by.model('username'));
await username.clear();
await username.sendKeys('Jane Doe');
var name = element(by.binding('username'));
expect(await name.getText()).toEqual('Jane Doe');
});

Related

"Undefined. Implement with the following snippet" protactor cucumber

Currently learning protractor, I am doing this parameter scenario where I want to the change the type of operation done in every run
my steps
const { Given, Then } = require('cucumber');
const { browser } = require('protractor');
const {expect} = require('chai')
Given("I open the {string} url", async function(url){
await browser.get(url)
})
Then("The title of the website is {string}", async function(name){
const pageTitle = await browser.getTitle();
return expect(pageTitle).to.be.equal(name);
})
Then("Wait {int} seconds", async function(timeInSeconds){
//element(by.model('first')).sendKeys(num)
await browser.sleep(timeInSeconds * 1000)
})
Then("with following variables {int} and {int}", async function(num1, num2){
await element(by.model('first')).sendKeys(num1);
await element(by.model('second')).sendKeys(num2);
})
Then('Select "(.*?)" and go', async function(op){
op.toUpperCase();
await element(by.model('operator')).element(by.css("option[value="+op+"]")).click();
await element(by.id('gobutton')).click()
await browser.sleep(3000)
//return expect(resultado).to.be.equal(res)
})
my feature file
#smoke
Feature: Home page validation
Scenario Outline: Scenario Outline name: Page title
Given I open the "https://juliemr.github.io/protractor-demo" url
Then The title of the website is "Super Calculator"
Then Wait 3 seconds
Then with following variables <num1> and <num2>
Then Select <operator> and go
Examples:
|num1|operator|num2|result|
|7|addition|2|9|
|2|division|2|4|
|4|modulo|2|6|
|3|multiplication|2|5|
|5|substraction|2|7|
? Then Select addition and go
Undefined. Implement with the following snippet:
Then('Select addition and go', function () {
// Write code here that turns the phrase above into concrete actions
return 'pending';
});
I am getting this message every time I run my code, I tried using regex because of this other question but it didn't fix anything, previously I was trying to use {string} and it didn't work out either
It was just missing something really simple
Then Select "<operator>" and go
Maybe the feature file path that you are running in your package.json file is not true

Page objects in Protractor / Jasmine cause error: Failed: Cannot read property 'sendKeys' of undefined

I'm trying to get page objects to work for Protractor and Jasmine, and I'm getting "Failed: Cannot read property 'sendKeys' of undefined" when I try to use page objects.
I have read similar posts but they do not provide any answers for me or the situation is too different to be of any help to me.
I've checked every character of the two files. It appears that the test cannot see the page object file for some reason. BTW Protractor is installed Globally so I don't need to include it in the script.
Everything was working prior to converting to using the "test_page.js" file instead of the hard-coded values.
This is from a tutorial where his code was working fine.
/superhero-tests/test/test_spec.js file
//require() is a notjs function - https://nodejs.org/en/knowledge/getting-started/what-is-require/
const TestPage = require("../page-objects/test.page")
//This file runs the browser and executes the script.
describe('Super Hero Page',function(){
var testPage
//Jasmine: Before each test case, do something
beforeEach(function(){
testPage = new TestPage()
//Protractor: For non-angular sites
browser.ignoreSynchronization = true
//Open URL
browser.get('file:///C:/projects/Protractor/Superhero/index.html')
})
//Jasmine: After each test case, do something
afterEach(function(){
//Timer to prevent immediate closure of the window
//browser.sleep(5000)
})
it('should load the correct URL',function(){
//Enter text into form fields
testPage.emailFld.sendKeys('a#b.com')
testPage.passwordFld.sendKeys('Test.123')
//Check some text in an element
expect(testPage.loginTitleTxt.getText()).toEqual('Welcome. Please Log In.')
//Check a HTML element's attribute
expect( testPage.emailFld.getAttribute('value')).toEqual('a#b.com')
//Non-precise matching - don't use with an empty string, will pass
//expect( testPage.loginTitleTxt.getText() ).toContain('Welcome.')
})
})
/superhero-tests/page-objects/test_page.js file
var TestPage = function(){}
TestPage.prototype = Object.create({},{
emailFld: { get: function(){ return element( by.id('loginEmail') ) } }, //this is a page object
passswordFld: { get: function(){ return element( by.id('loginPassword') ) } }, //this is a page object
loginTitleTxt: { get: function(){ return element( by.id('login-title') ) } } //this is a page object
})
module.exports = TestPage
I don't know what kind of tutorial would overcomplicate the logic so much. Try this
/superhero-tests/page-objects/test_page.js file
module.exports = function() {
this.emailFld = element( by.id('loginEmail') )
this.passswordFld = element( by.id('loginPassword') )
this.loginTitleTxt = element( by.id('login-title') )
}
Also keep in mind, the tutorial teaches you to outdated syntax of protractor 3 or 4, which is no longer used since protractor 7 was released a few years ago
In the end I found alternative Page Object code which works (tutorial linked below):
The page object:
var TestPage = (function () {
function TestPage() {
this.emailFld = element( by.id('loginEmail') )
this.passswordFld = element( by.id('loginPassword') )
this.loginTitleTxt = element( by.id('login-title') )
}
return TestPage;
})();
module.exports = TestPage;
The spec(test) file:
//Test for Login page
var TestPage = require("../page-objects/test.page")
//Appears in command line
describe('Login page tests', function(){
var test = new TestPage();
//Executed before the tests
beforeEach(function(){
//Protractor: For non-angular sites
browser.ignoreSynchronization = true
//Open URL
browser.get('file:///C:/projects/Protractor/Superhero/index.html')
})
//Executed after the tests
afterEach(function(){
//Timer so we can see what is going on
//browser.sleep(5000)
})
//The test statements themselves
it('should display all the Login page elements',function(){
//With page object
expect( test.emailFld.getAttribute('placeholder') ).toEqual('Enter email')
})
})
It seems to make better use of the initial function and then do the module.exports at the end. The only other difference I can see is that they used var not const in the test file, but I don't know this would change much.
https://teamgaslight.com/blog/getting-started-with-protractor-and-page-objects-for-angularjs-e2e-testing

TestCafe visibilityCheck does not wait for element to appear

I am trying to get TestCafe to wait for an element to appear in the dom. Currently I am using { visibilityCheck: true } but it does not seem to do anything and the test will time out and be considered a failure.
Goals:
Go to page
Wait for searchIconElement to load
Code:
fixture`Library /all`.page(page.libraryScreen).beforeEach(async t => {
await t.useRole(page.adminUser);
});
test('Search Bar', async t => {
const searchIcon = Selector('div').withAttribute('class', 'CampaignsPage-fab1');
const searchIconElement = searchIcon.with({ visibilityCheck: true })();
const microAppNameInput = Selector('input').withAttribute('placeholder', 'Search');
const microAppTitle = Selector('div').withAttribute('class', 'SetCard-title ').innerText;
await t
.click(searchIconElement)
.typeText(microAppNameInput, testMicroAppTitle)
.expect(microAppTitle)
.eql(testMicroAppTitle);
});
try adding timeout
const searchIconElement = searchIcon.with({ visibilityCheck: true }).with({ timeout: 10000 });
When a selector is passed to a test action as the target element's identifier, the target element should be visible regardless of the visibilityCheck option. If the target element becomes visible too late, you can try to increase the selector timeout.

Selenium-cucumber.js test failed to run while adding a BeforeScenario in hooks.js file

Framework using: selenium-cucumber-js.
I am trying to run the below selenium-cucumber-js test. I would like to run the loginApp() function as BeforeScenario written in hooks.js file. But while running the test, its throwing below error at the moment. Could someone please advise on how to resolve the problem.
`C:\Tests\cucumber\node_modules\cucumber\lib\cucumber\runtime\event_broadcaster.js:30 process.nextTick(function(){ throw error; }); // prevent swallow by unhandled rejection
TypeError: node_modules\cucumber\lib\cucumber\support_code\library.js:17 scenario.loginApp is not a function
at C:\Tests\cucumber\step-definitions\hooks.js:4:51
at _combinedTickCallback (internal/process/next_tick.js:73:7)
at process._tickCallback (internal/process/next_tick.js:104:9)
at Module.runMain (module.js:606:11)
at run (bootstrap_node.js:390:7)
at startup (bootstrap_node.js:150:9)`
/**/Feature:**
//cucumber/features
Feature: Login and look for the Register tab
Scenario: Check the register tab in application
When After login look for "Register" in navbar
//**lookfortab.js**
//cucumber/step-definitions
const expect = require('chai').expect;
module.exports = function() {
this.When(/^After login look for "([^"]*)" in navbar$/, function (registerText) {
let navText = By.css('div#nav>div>ul>li>a');
driver.wait(until.elementLocated(navText, 10000));
return driver.findElement(navText).getText().then(el => {
console.log("print text here:"+el);
const displayTxt = el;
expect(displayTxt).to.be.eql(registerText);
});
})
}
//login.js
//cucumber/page-objects
module.exports = {
loginApp(){
this.driver.helpers.loadPage('https://testingsite.com')
this.driver.findElement(by.id('HomeLogin_Username')).sendKeys("Tester");
this.driver.findElement(by.id('HomeLogin_Password')).sendKeys("SomePassword123");
let lgBtn = By.css('div#login-fields>div>button');
this.driver.findElement(lgBtn).click();
}
};
//hooks.js
//cucumber/step-definitions
module.exports = function () {
this.BeforeScenario(function(scenario, done) {
console.log('BeforeScenario: ' + scenario.loginApp());
done();
});
};
First of all, note that selenium-cucumber-js is using a rather old version of cucumber-js (1.3.3 vs 5.0.2 at the moment of writing this). Keep that in mind when you're consulting cucumber-js docs or looking for examples. Below, I'll be posting links to the cucumber-js#1.3.3 docs.
As for what's not working in your set up:
scenario object that is passed into your hooks doesn't have page objects attached to it. It only contains some meta info about the scenario and methods to get it. Here's a list of them: cucumber-js docs
If you want to reference the page objects from your hooks, you can use the global page as described here: Page objects - selenium-cucumber-js
Your loginApp() function probably still won't work because you're accessing webdriver as this.driver and helpers as this.driver.helpers. They're also globally defined by selenium-cucumber-js: Helpers
So, your hooks.js should look like this:
module.exports = function () {
this.BeforeScenario(function(scenario, done) {
console.log('BeforeScenario: ' + page.login.loginApp());
done();
});
};
And your login.js:
module.exports = {
loginApp(){
helpers.loadPage('https://example.com')
driver.findElement(by.id('HomeLogin_Username')).sendKeys("Tester");
driver.findElement(by.id('HomeLogin_Password')).sendKeys("SomePassword123");
let lgBtn = By.css('div#login-fields>div>button');
driver.findElement(lgBtn).click();
}
};

How can I wait for a condition?

I'm new on protractor, and I'm trying to implement an e2e test.
I don't know if this is the right way to do this, but...
The page that I want to test is not a full angular page based, so... I'm having some trouble.
On my first spec I have:
describe('should open contact page', function() {
var ptor = protractor.getInstance();
beforeEach(function(){
var Login = require('./util/Login');
new Login(ptor);
});
I have created this Login class, but after login I want to open the contact page, but protractor immediately try to find element before the page is fully loaded.
I've tried to use:
browser.driver.wait(function() {
expect(browser.findElement(by.xpath("//a[#href='#/contacts']")).isDisplayed());
ptor.findElement(by.xpath("//a[#href='#/contacts']")).click();
});
But it doesn't work... it always try to find the element before the page loads.
I tried this one too:
browser.driver.wait(function() {
expect(ptor.isElementPresent(by.xpath("//a[#href='#/contacts']")));
ptor.findElement(by.xpath("//a[#href='#/contacts']")).click();
});
I'm able to do that using browser.sleep(); but I don't think that is a good option. Any idea? On my login class I have:
ptor.ignoreSynchronization = true;
How can I wait for this #href='#/contacts before protractor tries to click on it?
Protractor 1.7.0 has also introduced a new feature: Expected Conditions.
There are several predefined conditions to explicitly wait for. In case you want to wait for an element to become present:
var EC = protractor.ExpectedConditions;
var e = element(by.id('xyz'));
browser.wait(EC.presenceOf(e), 10000);
expect(e.isPresent()).toBeTruthy();
See also:
Expected conditions in protractor
I finally find out...
var waitLoading = by.css('#loading.loader-state-hidden');
browser.wait(function() {
return ptor.isElementPresent(waitLoading);
}, 8000);
expect(ptor.isElementPresent(waitLoading)).toBeTruthy();
var openContact = by.xpath("//a[#href='#/contacts']");
element(openContact).click();
With this protractor could wait for that element until it loading page disappears.
Thanks for those who tried to help XD.
I had the same problem you were having for the longest time while using protractor. In my e2e test I start in a non angular app, then get into an angular portion, then get back out to a non angular portion. Made things tricky. The key is to understand promises and how they work. Here's some examples of my real world code in a functioning e2e test. Hoping this gives you an idea of how to structure your tests. Probably some bad practice in this code, please feel free to improve upon this, but I know that it works, maybe not the best way.
To get to angular I use
var ptor;
var events = require('events');
var eventEmitter = new events.EventEmitter();
var secondClick = require('./second-click');
beforeEach(function () {
browser.driver.get('http://localhost:8080/');
},10000);
it("should start the test", function () {
describe("starting", function () {
it("should find the link and start the test", function(){
var elementToFind = by.linkText('Start'); //what element we are looking for
browser.driver.isElementPresent(elementToFind).then(function(isPresent){
expect(isPresent).toBe(true); //the test, kind of redundant but it helps pass or fail
browser.driver.findElement(elementToFind).then(function(start){
start.click().then(function(){ //once we've found the element and its on the page click it!! :)
ptor = protractor.getInstance(); //pass down protractor and the events to other files so we can emit events
secondClick(eventEmitter, ptor); //this is your callback to keep going on to other actions or test in another file
});
});
});
});
});
},60000);
While in angular this code works
describe("type in a message ", function(){
it("should find and type in a random message", function(){
var elementToFind = by.css('form textarea.limited');
browser.driver.isElementPresent(elementToFind).then(function(isPresent){
element(elementToFind).sendKeys(randomSentence).then(function(){
console.log("typed in random message");
continueOn();
});
});
});
},15000);
After exiting angular
browser.driver.wait(function(){
console.log("polling for a firstName to appear");
return browser.driver.isElementPresent(by.name('firstName')).then(function(el){
return el === true;
});
}).
then(function(){
somefunctionToExecute()
});
Hope that gives some guidance and helps you out!
browser.driver.wait(function() {
return browser.driver.isElementPresent(by.xpath("//a[#href='#/contacts']"));
});
This works for me too (without the timeout param)..
for more information, see http://angular.github.io/protractor/#/api?view=webdriver.WebDriver.prototype.wait
Thanks to answers above, this was my simplified and updated usage
function waitFor (selector) {
return browser.wait(function () {
return browser.isElementPresent(by.css(selector));
}, 50000);
}
Have you tried putting the ng-app in the <html> tag (assuming this part of code is under your control)? This solved a lot of initialization timing problems for me.
Best way to use wait conditions in protractor that helps to show proper error message to particular element if test case failed
const EC = ExpectedConditions;
const ele = element(by.xpath(your xpath));
return browser.wait(EC.visibilityOf(ele),9000,'element not found').then(() => {
ele.click();
});
I'm surprised that nobody has added this solution. Basically, if you are using modal dialogues you often get an element visible and available to click but not being clickable due to the modal dialogue being in front of it. This happens because protractor moves faster than angular and is ready to click the next element while angular is still closing the modal.
I suggest using
public async clickElementBug(elementLocator: Locator) {
const elem = await element(elementLocator);
await browser.wait(
async function() {
try {
await elem.click();
return true;
} catch (error) {
return false;
}
},
this.TIMEOUT_MILLIS,
'Clicking of element failed: ' + elem
);
}
browser.wait may sound too ordinary, but it's not!
browser.wait is the way to go. Just pass a function to it that would have a condition which to wait for. For example wait until there is no loading animation on the page
let $animation = $$('.loading');
await browser.wait(
async () => (await animation.count()) === 0, // function; if returns true it stops waiting; can wait for anything in the world if you get creative with it
5000, // timeout
`message on timeout` // comment on error
);
Make sure to use await
You can also use existing library called ExpectedConditions that has lots of predefined conditions to wait for
You can't imagine what you can do with it...
A few of my favorite ones:
wait until the number of browser's tab's is 2
// wait until the number of browser's tab's is 2
await browser.wait(
async () => {
let tabCount = await browser.getAllWindowHandles();
return tabCount.length === 2;
},
5000,
'the url didnt open in a new window'
);
wait until the loading animation is gone for at last 750ms
// wait until the loading animation is gone for at last 750ms
await browser.wait(
async () => (await this.$$loadAnimations.count()) === 0 && !(await browser.sleep(750)) && (await this.$$loadAnimations.count()) === 0,
5000,
`waiting timeout`
);
wait for ANY number of elements to be present
// wait for any number of elements to be present
async waitForElements($elem, timeout = 120000, start = +new Date()) {
let conditions = [];
for (let i = 0; i < $elem.length; i++) {
conditions.push(ExpectedConditions.presenceOf($elem[i]));
}
await browser.wait(
ExpectedConditions.and(...conditions),
remainingTimeout(timeout, start),
`wait for all elements`
);
}
// and use
await waitForElements([
$usernameField,
$passwordFiend,
$submitButton
])

Categories

Resources