Selenium/Python - Class name with spaces unable to local element - python

I'm having trouble locating an element. I'm trying to locate it and enter some data into the field. I notice that the class name has spaces and ID is generated automatically (compare these to other forms) so can't use the ID for the automation as I want to automate this to create new forms and will be using the 'Description' field every time.
Below is the html for the Description field, which I'm trying to locate.
<input size="15" maxlength="255" class="acitem description s-description ui-autocomplete-input" spinner="/assets/spinner-48c6e73f2bbe9ea753f7f8e5410541a8138d19d657ddd532b2765335ed3d62bf.gif" auto_complete="true" data-autocomplete-url="/items/auto_complete" data-autocomplete-renderer="item_autocomplete_renderer" data-autocomplete-delay="250" type="text" name="invoice[invoice_lines_attributes][68345][description]" id="invoice_invoice_lines_attributes_68345_description" autocomplete="off">
The codes that I'm using so far has failed.
test_1 = driver.find_element_by_css_selector('.acitem.description.s-description.ui-autocomplete-input')
test_1.send_keys("HELLO WORLD")
test_2 = driver.find_element_by_css_selector("input[class='acitem description s-description ui-autocomplete-input']")
test_2.send_keys("HELLO WORLD")
test_3 = Select(driver.find_element_by_xpath("//*[#class='acitem description s-description ui-autocomplete-input']"))
test_3.send_keys("HELLO WORLD")
Did I got the code wrong or is there some workaround with the class name that has spaces? Thanks.

Thanks for all your help. I solved by using start-with and contains.
Below is my code.
invc_desc =driver.find_element_by_xpath("//input[starts-with(#class,'acitem') and contains(#class,'s-description')]")
invc_desc.clear()
invc_desc.send_keys("HELLO WORLD")

Try with xpath
//input[starts-with(#id,'invoice_invoice_lines_attributes_')]

I almost all the cases, all the elements from the DOM can be accessed via XPATH.
In your case I would go with the following:
element = driver.find_element_by_xpath("//input[#id='acitem description s-description ui-autocomplete-input']")

Related

How to use Python Flask variables in Javascript

I have a Python variable whose value is a string of text and would like to edit that value via Javascript.
I have no idea how to go about doing this.
Attempts:
function changeValue(val) {
val = 'new text';
}
<textarea placeholder="some text">{{ changeValue({{ result }}) }}</textarea>
<textarea placeholder="some text">
{{ result }}
</textarea>
What I want: I have some text (result) being added and would like to check if the text is empty. If so, I want to show the placeholder text.
The issue: Although I can check if the value is empty, when I try to print that result out it reads none
Thanks to all!
You do not need to call the JavaScript function from the HTML file. There are several approaches you can take:
1. Store the variable in HTML metadata:
<meta id="result_var" data-result={{result}}>
And then get the data in JavaScript:
result = document.getElementById("result_var").value;
2. Keep the variable in the tag where it's supposed to be and get it from there in JavaScript:
<textarea placeholder="some text" id="result-var"> {{result}} </textarea>
And then get it in JavaScript:
let result = document.getElementById("result-var");
3. Query it from your API: You can create a route in your Flask app that returns JSON data with the variable you need and then get that data to your JavaScript file by sending a request to your API.
4. Jinja format: I've seen solutions that involve just using the variable as if it was a jinja variable in JavaScript like this: let result = JSON.parse('{{ result | tojson }}');. But I haven't been able to get this working properly, not sure why.
I hope this helps!

How to display HTML using LXML in Python

So what I am trying to achieve is really simple.
I want to call python test.py and would like to go to my local host and see the html result. However I keep getting an error ValueError: Invalid tag name u'<html><body><h1>Test!</h1></body></html>'
Below is my code. What's the problem here?
import lxml.etree as ETO
html = ETO.Element("<html><body><h1>Test!</h1></body></html>")
self.wfile.write(ETO.tostring(html, xml_declaration=False, pretty_print=True))
You have to create each element in turn, and put them in the structure that you want them to have:
html = ETO.Element('html')
body = ETO.SubElement(html, 'body')
h1 = ETO.SubElement(body, 'h1')
h1.text = 'Test!'
Then ETO.tostring(html) will return a bytestring that looks like this:
>>> ETO.tostring(html)
b'<html><body><h1>Test!</h1></body></html>'
Since you are reading an existing file, Element isn't useful here; try changing this
html = ETO.Element("<html><body><h1>Test!</h1></body></html>")
to this
html = ETO.fromstring("<html><body><h1>Test!</h1></body></html>")
and see if it works for you.

Get all text wrapped by THEN if condition

html code
<div class=media>
<div class=11></div>
<div class=22></div>
<div class=media-content>
yes, this is the text<BR>
that i want to compare below
multiple line
</div>
</div>
<div class=media>
<div class=11></div>
<div class=22></div>
<div class=media-content>
and i want to compare above text multiple line
then if both same, i wanna break the loop
But it is not work
</div>
</div>
Succeeded to select first element (was checked by chropath)
driver.find_elements_by_xpath('//div[#class="media"][last()]//div[#class="media-content"]')
Succeeded to select second element (was checked by chropath)
driver.find_elements_by_xpath('//div[#class="media"][last()-1]//div[#class="media-content"]')
But both text was NOT same but always TRUE then break.
if driver.find_elements_by_xpath('//div[#class="media"][last()]//div[#class="media-content"]').gettext() == driver.find_elements_by_xpath('//div[#class="media"][last()-1]//div[#class="media-content"]').gettext():
break
Yes, it is not work.
I wanna compare the text(multi line) in both first and second element(#class=media-content)
If both multi-lined text was same, i wanna stop the loop.
But both text was NOT same as you see, but always become TRUE then STOPPED(break)
I am succeed to select item (*with last[], last[]-1)
But i don't why it works wrong.....
Is there anybody to troubleshoot my newbie code?
//text(), .gettext(), .text()
Try the below code.
items1=[item.text for item in driver.find_elements_by_xpath('//div[#class="media"][last()-1]//div[#class="media-content"]')]
items2=[item.text for item in driver.find_elements_by_xpath('//div[#class="media"][last()]//div[#class="media-content"]')]
if items1==items2:
print("pass")
else:
print("fail")
For me anser is (in case if where are more then one div[#class="media-content"] elements in singal div[#class="media"] node):
media_last = driver.find_elements_by_xpath('//div[#class="media"][last()]//div[#class="media-content"]')
media_last = [a.gettext() for a in media_last]
media_not_last =driver.find_elements_by_xpath('//div[#class="media"][last()-1]//div[#class="media-content"]')
media_not_last = [a.gettext() for a in media_not_last]
if media_last == media_not_last:
break
you can't get method gettext at the array of elements
or if you want get jast a singl element use find_element_by_xpath method
I tested the following using your html and I get the behaviour you expect:
from selenium import webdriver
driver = webdriver.Chrome()
driver.get(r'file:///<path to local html file>') # Used local html file for testing purposes
el1 = driver.find_elements_by_xpath('//div[#class="media"][last()]//div[#class="media-content"]')
el2 = driver.find_elements_by_xpath('//div[#class="media"][last()-1]//div[#class="media-content"]')
if el1[0].text == el2[0].text:
print('Yes')
else:
print('No')
One thing to understand is that driver.find_elements_by_path() returns a list object. So even though it appears you are targeting specific elements in your page, they are stored in list objects and you should refer to them that way if you wish to access the text of the elements.

Python - Selenium - Get Parent Class

I have a website http://demoqa.com/registration/
I have been trying to verify that when a user clicks on and then clicks off a required field such as username or phone number that the error "required field" appears when no data has been entered.
Does anyone have any idea how to verify this? I was thinking
phone = self.driver.find_element_by_xpath("//div[contains(.,'Phone Number')]")
and then from that using something like getError = phone.find_element_by_xpath() and using the (..) to try and move up to the parent class, but with no luck!
I thought it would have been easy but all the elements have the same class name. I suppose I could check for the text "this field is required" but I'd like to keep it neat and write a method so I can use it on each of the fields.
I've spent alot of today searching for it and trying different thing, so any help or ideas would be great.
Thanks!
Other Info:
I can tell you what happens before and after i click the field. My best guess at attacking this issue would be to verify the class name of the field "phone number" and then once clicked off, verify that the class name has changed. As you can see on top is before a click off and below is when the required field text appears
<div class="fieldset">
<label class="" for="phone_9">Phone Number</label>
<input id="phone_9" class="input_fields piereg_validate[required,custom[phone_international]]" type="text" value="" placeholder="" name="phone_9">
</div>
<div class="fieldset error">
<label class="" for="phone_9">Phone Number</label>
<input id="phone_9" class="input_fields
piereg_validate[required,custom[phone_international]]" type="text" value=""
placeholder="" name="phone_9">
<div class="legend_txt">
<span class="legend error">* This field is required</span>
</div>
</div>
I have my solution *i think
seeing how the "div class name" changes when the required message appears I have a solution. I first find the element, get it's parents name by going up one level using the (..), i verify it's as it should be named "fieldset". I think trigger the error message, and repeat the process but make sure the "fieldset" has changed to "fieldset error"
getElementBase = self.driver.find_element_by_id('phone_9')
getElementClassRoot = getElementBase.find_element_by_xpath('..')
getElementClassRootName = getElementClassRoot.get_attribute('class')
Try to use below piece of code:
from selenium.common.exceptions import NoSuchElementException
error = "* This field is required"
phone = driver.find_element_by_xpath("//div[label='Phone Number']")
phone_input = phone.find_element_by_tag_name("input")
phone_label = phone.find_element_by_tag_name("label")
phone_input.click()
phone_label.click()
try:
phone.find_element_by_xpath(".//span[#class='legend error' and .='%s']" % error)
except NoSuchElementException:
print("No error displayed")
This should allow you to click inside input, outside input and check that error appears
If you need to make an assertion:
result = True
try:
phone.find_element_by_xpath(".//span[#class='legend error' and .='%s']" % error)
except NoSuchElementException:
result = False
assert result, "No error displayed"

How to test (using unittest) the HTML output of a Django view?

I'm writing unit tests for my Django application. However, I don't know how to test the HTML output of a view.
Sometimes I might want to check if a specific element contains certain value, or how many of those elements are displayed, or things like that. How can I do such tests?
I would like a solution that uses unittest and django's own django.test.
I know I can use Selenium or Pyccuracy (which uses Selenium), but Selenium tests are quite slow because of the huge overhead of launching a browser. Also, unit tests work out-of-the-box with django-coverage package.
I've always found a combination of BeautifulSoup, and assertContains and assertFormError from TestCase's available assertions to do the trick.
These other answers are now out of date regarding assertions. The assertion assertHTMLEqual (since Django 1.4) takes care of things like ignoring whitespace, and ignoring the order of attributes.
For example (from the docs):
from django.test import TestCase
class MyTest(TestCase):
def test_some_html(self):
# A passing test that doesn't raise an AssertionError.
self.assertHTMLEqual(
'<input type="checkbox" checked="checked" id="id_accept_terms" />',
'<input id="id_accept_terms" type="checkbox" checked>'
)
In practice, one of the arguments to assertHTMLEqual would be dynamically generated.
Django's test framework is ideal for this.
Check the status code and content.
http://docs.djangoproject.com/en/1.2/topics/testing/#django.test.TestCase.assertContains
Check the template. http://docs.djangoproject.com/en/1.2/topics/testing/#django.test.TestCase.assertTemplateUsed
Also, it helps to use id="something" tags within your HTML to make it easier to find things when unit testing. We have tests like this.
def should_find_something( self ):
response= self.client.get( "/path/to/resource/pk/" )
self.assertContains( response, '<td id="pk">the pk string</td>', status_code=200 )
self.assertTemplateUsed( response, 'appropriate_page.html' )
Works nicely.
Have a look at Django with asserts - which uses lxml.
https://django-with-asserts.readthedocs.org/en/latest/
Here is the solution with BeautifulSoup:
import bs4 as bs
class HtmlTestMixin:
maxDiff = None
def assertElementContains(self, request_content, html_element="", html_selectors={}, element_text=""):
soup = bs.BeautifulSoup(request_content, "html.parser")
element = soup.find(html_element, **html_selectors)
soup_1 = bs.BeautifulSoup(element_text, "html.parser")
self.assertEqual(str(element.prettify()), soup_1.prettify())
It can be called like:
self.assertElementContains(
response.content,
"select",
{"id": "order-model"},
'''
<select name="order" id="order-model" class="form-select">
<option value="_score" >
Score
</option>
</select>
''',
)

Categories