I want to create a generic function that notifies on errors
I can't seem to find a way to get the css selector from an ElementFinder member
Here's my function:
static waitForElementToExist(elementFinder: ElementFinder): SeleniumPromise<any> {
return browser.wait(until.presenceOf(elementFinder),
jasmine.DEFAULT_TIMEOUT_INTERVAL,
MyErrors.elementNotFound(<get element selector string>));
};
so I can return a meaningful error like:
could not found the element '.class-selector'
can anyone point me to the right direction please? :-)
If you use latest protractor, try:
MyErrors.elementNotFound(elementFinder.locator().toString())
More detail, please look locator() api.
Related
Firstly, Karate UI automation is really awesome tool. I am kind of enjoying it while writing the UI tests using Karate. I ran into a situation where in, i was trying to fetch the shadowRoot elements. I read few similar posts related to javascript executor with karate and learnt that it is already answered. it is recommended to use driver.eval. But in Karate 0.9.5 there is no eval, it has script() or scriptAll(). I have gone through documentation couple of times to figure out how i can fetch element inside an element but no luck.
Using traditional selenium+java, we can fetch shadowRoot like this way:
something like shadowRoot which sits inside a parent element like div or body.
//downloads-manager is the tagname and under that downloads-manager, a shadowRoot element exists
The HTML looks like this. it is from chrome://downloads.
<downloads-manager>
#shadow-root(open)
</download-manager>
WebElement downloadManager =driver.findElement(By.tagName("downloads-manager");
WebElement shadowRoot= (WebElement)((JavaScriptExecutor)driver)
.executeScript("return arguments[0].shadowRoot",downloadManager);
So i tried the following in Karate UI
script("downloads-manager","return _.shadowRoot"); //js injection error
script('downloads-manager', "function(e){ return e.shadowRoot;}"); // same injection error as mentioned above.
def shadowRoot = locate("downloads-manager").script("function(e){return e.shadowRoot};"); //returns an empty string.
I bet there is a way to get this shadowRoot element using Karate UI but i am kind of running out of options and not able to figure out this.
Can someone please look into this & help me?
-San
Can you switch to XPath and see if that helps:
* def temp = script('//downloads-manager', '_.innerHTML')
Else please submit a sample in this format so we can debug: https://github.com/intuit/karate/tree/develop/examples/ui-test
EDIT: after you posted the link to that hangouts example in the comments, I figured out the JS that would work:
* driver 'http://html5-demos.appspot.com/hangouts'
* waitFor('#hangouts')
* def heading = script('hangout-module', "_.shadowRoot.querySelector('h1').textContent")
* match heading == 'Paul Irish'
It took some trial and error and fiddling with the DevTools console to figure this out. So the good news is that it is possible, you can use any JS you need, and you do need to know which HTML element to call .shadowRoot on.
EDIT: for other examples of JS in Karate: https://stackoverflow.com/a/60800181/143475
I have a fillInput() function that takes a selector and a value as parameters, then:
clear the the input via cy.get(selector).clear()
then fills the input value via cy.get(selector).type(value)
As far as I know, this is really some sort of anti-pattern and a cypress command should be the way to go.
So, reading about child commands, I came out with this command that should do the same as my fillInput() utility function:
Cypress.Commands.add('fillInput', {prevSubject: 'element'}, (subject, value) => {
subject.clear();
subject.type(value);
});
However, when I try this in a spec via:
cy.get('#my-selector').fillInput('my-value');
I get this error in the cypress browser console:
TypeError: subject.clear is not a function
In the docs, cy.get() is said to yield a DOM Element, and the {prevSubject: 'element'} should make subject to be the same type (as far as I understand this).
However, subject seems to be a different type and methods that work on elements like type() or ' clear()or ' should() does not work on child command subjects.
How can I get the subject of my child command to act as a Dom Element?
While investigating to post the question, I came up with a simple solution to this problem. The subject is an object which has a selector, so you can use that selector with cy.get(subject.selector) to get the Dom Element:
Cypress.Commands.add('fillInput', {prevSubject: 'element'}, (subject, value) => {
cy.get(subject.selector).clear().type(value);
});
I think this is not a lot of clear and more people may have this issue, so I leave my solution here.
Try to use
cy.wrap(subject)
For me that was the trick.
I have a window-box with two buttons 'add' and 'close'. I need to test below scenario:
When clicked on 'add' button it throws error and the window remains open. I need to click on 'close' button to proceed.
I used below code:
if(element(by.xpath("xpath_of_error_box")).isEnabled())
{
element(by.xpath("xpath_of_close_button")).click();
}
But it throws below error:
No element found using locator: By(xpath, xpath_of_error_box)
Is there any way to handle this?
According to the error, it seems that your xpath locator didn't match any element. And according to the additional clarification in the question you could try:
element(by.xpath("xpath_of_error_box")).isDisplayed().then(isDisplayed => {
if (isDisplayed) {
// do what you need when it is visible
} else {
// if not then proceed
}
});
As it was pointed out, isEnabled might not be the proper method you should use in this case. If it seems that the element you try to find is always present in the dom, you might better try to check for its visibility using isDisplay instead.
An advice. It's not a good idea to use xpath locators in your tests, because this ties them to the html DOM structire of the web page you are observing. As we know, the UI happens to change often, which would make your tests to brake often as well. Although this is of cource a personal preference, it is such until you end up with tons of brocken tests after a single small change in the html.
If you need to check if an element is present you can use the following code:
if (element(by.xpath("yourXpath")).isPresent())
But your problem is not on your if code, your problem is that the xpath your are searching doesn't exist.
isEnabled() and isPresent() returns promise (not boolean) and have to be resolved.
isEnabled() could be only used for <button>.
You can use XPath all the time, don't listen to anyone.
PS. Of course it would be glad to see your HTML to check the correctness of your XPath.
I'm using firebase to build a database application. I'm trying to get the firebase generated id of a particular document. The document is returned as a Promise, which returns a QuerySnapshot. A forEach loop pulls each QueryDocumentSnapshot out of the QuerySnapshot, so I'm working with the QueryDocumentSnapshot class. The documentation says that this class has the same API surface as the DocumentSnapshot class.
https://developers.google.com/android/reference/com/google/firebase/firestore/QueryDocumentSnapshot
Since the DocumentSnapshot class has a getId() method, I thought I'd use that.
searchBooks(){
this.booksSearched = true;
this.bookService.getBookList(this.authorName).get().then(bookListSnapshot =>{
this.bookList = [];
bookListSnapshot.forEach( snap =>{
this.bookList.push({
authorLastName: snap.data().authorLastName,
title: snap.data().title,
edition: snap.data().edition,
id: snap.getId() <-------ISSUE HERE-----------
});
return false;
});
});
}
However, I get this error.
property 'getId' does not exist on type 'QueryDocumentSnapshot'
Here is the code for the bookService
getBookList(authorLastName): firebase.firestore.Query{
return this.bookListRef.where("authorLastName", "==", authorLastName);
}
What's even more wild is when I tried change my code around. Instead of pulling the QueryDocumentSnapshots out using the forEach loop, I thought I would take advantage of the fact that bookListSnapShot is a QuerySnapshot and call its getDocuments() method. https://firebase.google.com/docs/reference/android/com/google/firebase/firestore/QuerySnapshot
This would return a list of DocumentSnapshots, possibly meaning that whatever inheritance issue with the getId() method could be avoided. However, when I tried, I got this error:
var documents = bookListSnapshot.getDocuments();
Property 'getDocuments' does not exist on type 'QuerySnapshot'
To me, it seems like the documentation is being contradicted by the errors the editor is throwing. Does anyone know what's going on?
Thank you for reading,
-Joel
You're writing code in JavaScript, but you're looking at API documentation for Android using Java. Here are the JavaScript API docs for DocumentSnapshot and QueryDocumentSnapshot. DocumentSnapshot has a property called id that you're looking for.
I need a way to try to click on an element, but if it is not there, the test should not fail.
Kind of an "fire and forget" click.
I want to do that directly in Selenese (or js, as for user-extensions.js) , and not in PHPUnit/JUnit.
I thought maybe of a "user-extensions"-function to do this, so i searched the openqa Site but i didn't find anything useful.
Update: My own first try: (not working)
Selenium.prototype.doClickAndForget= function(locator) {
this.page().click(locator));
return true;
};
Any Ideas on how to make it work?
May be you can create a wrapper for click(String) method in DefaultSelenium like
public void clickWithoutFail(String locator){
try{
selenium.click(locator);
}catch(SeleniumException ex){
}
}
Above wrapper method may solve your problem. It will ignore any errors occured during click on non-existent element.
You can avoid having try/catch block by checking the presence of the locator using isVisible() method.
Hope this helps.
I did it with "storeEval()" and pure js.
Either i got a valid link or i returned a mandatory element to "fake klick" on, so sel will not throw any errors.
Its a hack but i had "unpredefined" content on my site, so i needed a way to handle the possibilities.