How to use siblings() and closest() in Geb test - groovy

I am trying to write a script to click an icon which is a part of the table header. Each column in the table has this icon in it (ascending order and descending order sorting icons). I am using Geb to do this. Here is how I am trying to do it:
In my SortingSpec.groovy file:
header.closest("div.customSortDownLabel").click()
I also tried
header.siblings('div.customSortDownLabel').first().click()
In the SortingPage.groovy file:
header {
grid.$(class: 'div.customHeaderLabel', text: 'Country')
}
In my html:
<div>
<div class="customHeaderLabel">{{params.displayName}}</div>
<div *ngIf="params.enableSorting" (click)="onSortRequested('asc', $event)" [ngClass]="ascSort" class="customSortDownLabel">
<i class="fa fa-long-arrow-alt-down"></i></div>
<div *ngIf="params.enableSorting" (click)="onSortRequested('desc', $event)" [ngClass]="descSort" class="customSortUpLabel">
</div>
None of them worked for me. It is not able to find the selector. Any suggestions are appreciated.
Error I see is:
geb.error.RequiredPageContentNotPresent: The required page content 'header - SimplePageContent (owner: SortingGrid, args: [], value: null)' is not present

That error looks like header isn't matching. Assuming that grid matches, and you're using some Javascript framework like Angular to substitute 'Country' for params.displayName, I would guess that maybe Geb is failing to find header before 'Country' is substituted. So, I would try making header wait for it:
header(wait: true) { grid.$(class: 'div.customHeaderLabel', text: 'Country') }
By the way, closest() goes in the wrong direction, to an ancestor, but siblings() looks good.

siblings() didnt work for me but next() worked for me. next() grabs the next sibling elements of the current context elements.
Example:
1. header.next().click() clicks the very next sibling
header.next("div.customSortDownLabel").click() looks for the very next sibling with the matching selector of 'div.customSortDownLabel' and then clicks it.

Related

Find if text exist inside a nested Div, if yes print out the whole string, Selenium Python

i'm very new to selenium(3.141.0) and python3, and i got a problem that couldn't figure it out.
The html looks similar to this
<div class='a'>
<div>
<p><b>ABC</b></p>
<p><b>ABC#123</b></p>
<p><b>XYZ</b></p>
<div>
</div>
I want selenium to find if # exist inside that div, (can not target the paragraph only element because sometime the text i want to extract is inside different element BUT it's always inside that <div class='a'>) If # exist => print the whole <p><b>ABC#123</b></p> (or sometime <div>ABC#123<div> )
To find an element with contained text, you must use an XPath. From what you are describing, it looks like you want the locator
//div[#class='a']//*[contains(text(),'#')]
^ a DIV with class 'a'
^ that has a descendant element that contains the text '#' within itself or a descendant
The code would look something like
for e in driver.find_elements(By.XPATH, "//div[#class='a']//*[contains(text(),'#')]"):
print(e.get_attribute('outerHTML')
and it will print all instances of <b>ABC#123</b>, <div>ABC#123</div>, or <p>ABC#123</p>, whichever exists

Scrapy parse is returning an empty array, regardles of yield

I am brand new to Scrapy, and I could use a hint here. I realize that there are quite a few similar questions, but none of them seem to fix my problem. I have the following code written for a simple web scraper:
import scrapy
from ScriptScraper.items import ScriptItem
class ScriptScraper(scrapy.Spider):
name = "script_scraper"
allowed_domains = ["https://proplay.ws"]
start_urls = ["https://proplay.ws/dramas/"]
def parse(self, response):
for column in response.xpath('//div[#class="content-column one_fourth"]'):
text = column.xpath('//p/b/text()').extract()
item = ScriptItem()
item['url'] = "test"
item['title'] = text
yield item
I will want to do some more involved scraping later, but right now, I'm just trying to get the scraper to return anything at all. The HTML for the site I'm trying to scrape looks like this:
<div class="content-column one_fourth">
::before
<p>
<b>
All dramas
<br>
(in alphabetical
<br>
order):
</b>
</p>
...
</div>
and I am running the following command in the Terminal:
scrapy parse --spider=script_scraper -c parse_ITEM -d 2 https://proplay.ws/dramas/
According to my understanding of Scrapy, the code I have written should be yielding the text "All dramas"; however, it is yielding an empty array instead. Can anyone give me a hint as to why this is not producing the expected yield? Again, I apologize for the repetitive question.
your XPath expressions are not exactly as you want to extract data. If you want the first column's first-row item. Then your XPath expression should be.
item = {}
item['text'] = response.xpath ('//div[#class="content-column one_fourth"][1]/p[1]/b/text()').extract()[0].
The function extract() will return all the matches for the expression, it returns an array. If you want the first you should use extract()[0] or extract_first().
Go through this page https://devhints.io/xpath to get more knowledge related to Xpath.

How to scrape email address out of a string?

How do I get the email address from this html snippet?
As there are thousand of leads like this in a certain webpage and the text within it is not always found as it is seen here.
The only common thing is the email address located in the first position.
How can I get the email address and ignore the rest?
These are the elements:
<div class="gm_popup"><div class="gm_name">Adel Outfitters</div><div class="gm_address">1221 W 4th St</div><div class="gm_location">Adel, Georgia 31620<div style="display:none" class="w3-address-country">United States</div></div><div class="gm_phone"><span class="gm_phone_label">P:</span> 229-896-7105</div><div class="gm_email">adeloutfitters#yahoo.com<div><div class="gm_website">https://www.facebook.com/pages/Adel-Outfitters/132735763434461</div><br><a target="_blank" class="directions-link" href="http://maps.google.com/?saddr=+&daddr=1221+W 4th St, Adel, Georgia, 31620">Directions<span class="w3-arrow">different stuffs</span></a></div></div></div>
What I tried:
Set post = html.getElementsByClassName("gm_email")(0)
MsgBox post.innerText
The result:
adeloutfitters#yahoo.com
https://www.facebook.com/pages/Adel-Outfitters/132735763434461
Directionsdifferent stuffs
Expected output:
adeloutfitters#yahoo.com
The closing </div> tag is further down which is why you are getting the extra text. Can you chop off anything after a new line? Or check each word in the string and save the one with "#" in it? Bad way of going about it, but it would probably work...

Jade Template - SELECT OPTION with for

select(id="xxx", name="xxxyyy")
- for(var i = 1;i<10;i++){
option(value="#{i}") Some value for #{i}
- }
but it generates the following HTML
<select id="xxxx" name "xxxyyy"></select>
<option value="1">Some value for 1</option>
....
I've tried to include the select inside the for loop and it works as expected (it generates 10 select drop controls with one item on each one of them).
What am I missing here?
I think you've got your indentation messed up. Jade is like coffeescript, in that indentation is significant and donates nesting. See here. So that the Jade engine knows that your option loop should be within the select tag, the option loop needs to be indented from the select statement, whereas you've got yours level with the select statement.
select(id="xxx", name="xxxyyy")
-for(var i = 1;i<10;i++){
option(value="#{i}") Some value for #{i}
-}

changing the font color in a computed field using javascript

How to change the font color of Hello alone in "Hello World" using javascript/some other method?
I tried the following code,
var s= session.getCommonUserName()
s.fontcolor("green")
"Hello"+" "+ s.toUpperCase()
where i tried to change just the color of the username alone. But it failed.
I wouldn't bother to send down unformatted HTML to the client and then let the client do the JavaScript work. You create a computed field and give it the data type HTML (that keeps HTML you create intact) and use SSJS. So no JS needs to execute at the client side:
var cu = session.getCommonUserName();
return "Hello"+" <span style=\"color : green\">"+ cu.toUpperCase()+"</span>";
Don't forget to cross your t, dot your i and finish a statement with a semicolon :-)
If you want to do it with client java script, then you must do something like this:
dojo.style("html_element_id", "color", "green");
So in your case you can have have something like:
<p><span id="span1">Hello</span> World.</p>
Or you can do it directly if you don't need to change it with CJS:
<p><span style="color:green">Hello</span> World</p>
one way to do it is to wrap your 'hello' in a html span and then change the color of that span.
<span id='myspan'>hello</span> world
javascript code:
document.getElementById('myspan').style.color='green';
Went old school on this one...
Say you want to put your formatted text in a div
<div id="test">
</div>
Then you need the following javascript to do so:
div = document.getElementById("test");
hello = document.createElement("span");
hello.innerHTML = "Hello"
hello.style.color = "green";
div.appendChild(hello);
div.appendChild(document.createTextNode(" world!"));

Resources