I'm testing a django app with selenium, and one of my pages uses the jquery ui tabs element. One of the tabs contains a simple table listing some users, and is loaded via ajax. When using the app, the tab works just fine, but when automating the test with selenium, the tab doesn't appear to load it's content!
I'm writing the tests myself in python. At first, I was using the click method of selenium RC, but as I -painfully- learned from a previous test, that is rather buggy when it comes to anchor tags, so I resorted to the solution I used before: the wait_for_condition method and explicitly called the tab click event (and even the load event!) and nevertheless the tab was still not working!
I'm in despair here, the majority of my tests depend on that page and almost half of them are on that table, but, alas, it seems selenium is screwing up the javascript!
(I have other tests in the class, and they run just fine, so nothing weird is going on at the server level, it seems to be a problem caused by selenium in the client side)
My test code is similar to this:
class TestMyApp(TransactionTestCase):
urls = 'myapp.test_urls'
def setUp(self):
self.verificationErrors = []
self.selenium = selenium("localhost", 4444, "*chrome", "http://localhost:8000/")
self.selenium.start()
#self.selenium.set_speed(2000)
self.selenium.window_maximize()
def test_users_list(self):
"""Test that an app's users are correctly listed"""
sel = self.selenium
users = []
for u in range(settings.FREE_USER_LIMIT/2):
users.append(self.app.users.create(name="testUser_%s"%uuid4()))
sel.open("/")
sel.wait_for_page_to_load("30000")
sel.wait_for_condition('selenium.browserbot.getCurrentWindow().jQuery("#tabs").tabs("select",1);\
selenium.browserbot.getCurrentWindow().jQuery("#tabs").tabs("load",1);',
3000)
for user in users:
try: self.failUnless(sel.is_text_present(user.name))
except AssertionError, e: self.verificationErrors.append(str(e))
try: self.failUnless(sel.is_text_present(str(user.added.date())))
except AssertionError, e: self.verificationErrors.append(str(e))
def tearDown(self):
self.selenium.stop()
self.assertEqual([], self.verificationErrors)
This could be a few things. It could be that Selenium is having trouble clicking the anchor but I actually haven't heard of that trouble and it sounds less likely. It sounds like the click() method returns OK, it doesn't give you "element not found", right? When you do the click the jquery tab javascript just isn't doing what's expected. In my experience this usually comes down to the same issue -- since Selenium executes very quickly, when javascript is rendering portions of the page and effecting the DOM continuously sometimes when Selenium goes to interact with dynamically generated parts of the page (say to click this tab), the piece it's interacting with depends on some other piece that actually hasn't fully loaded yet. It's probably microseconds away from fully loading in fact, but selenium is too fast. You already understand this of course, you have the right idea with the wait_for condition looking for the tabs to be loaded. My guess would be it's probably just not long enough. You have to find some evaluation to make that says the whole UI tabs thing is loaded and rendered. Does the tabs API have some callbacks you can add to set a "done loading" variable or does it expose a variable like that? Barring figuring out what the proper expression is to find the point in time when the UI tabs are actually ready to be clicked, which possibly could be tricky, you can resort to outright pauses to make sure the part of the page is ready to go before you interact with it. I see no problem in sleep(2), or even sleep(5), etc. in the code if it's necessary to get it to work. One way you can test that this is really what's going on is by firing up the scenario in the interactive interpreter (gotta love Python, beats the pants off of doing this in Java). Paste the code in line by line to get to the trouble point, or comment out the selenium.stop() call in your teardown method and any test code after the trouble point, so it leaves the selenium window open and exits. Then instantiate a selenium object in the interactive interpretter and hijack the open session:
selenium = selenium("localhost", 4444, "*chrome", "http://localhost:8000/")
selenium.sessionId = "0asdd234234023424foo" #Get this from the Se window
...to get interactive control of the window. Then you can see about making the selenium.click() or make selenium.get_eval('...js...') calls to investigate the javascript landscape at that point in time. My guess is when you do this, the click() will actually work fine when you type it in, because by the time you get the session loaded and get around to typing in selenium.click('blah_tab_locator'), the tab guts will all be loaded and ready to go. It's just that when Python is making the calls it does it way too fast for the browser when there are these dynamic renderings going on. If the click works fine when you do it manually through selenium like this, then you know it's a timing issue. Find that proper wait_for_condition or condescend to a python sleep(). Otherwise, if the click continues to not work when you do this, then it's probably a problem with the locator being used. The tab UI has a click or a mouseup or a focus or some kind of event handler on some part of the tab structure, maybe it's just about finding the right part of the tab to click or the right event to fire. If it isn't that then it perhaps could be as you mention some kind of strange interaction between Selenium and Jquery UI, but that would surprise me and I'd be curious to know. Poke around with get_eval() to see what's going on in the javascript if so. It sounds like a timing issue to me though.
Related
I'm trying to refresh a webpage using F5 key. I know I can use:
self.page.reload()
But this is not a good solution for my problem. How to make the page to be refreshed using the F5 key? My code doesn't refresh the page and I don't know why.
self.page.keyboard.press('F5')
afaik, playwright uses a virtual keyboard and does not exactly send the same signal as a real keyboard to the browser application.
consider going native and using something closer to kernel like pyautogui, after you've focused you window:
import pyautogui
pyautogui.press('f5')
As you said we have page.keyboard.press('F5'). But it does not do what you want, I've tried several other examples but nothing.
Maybe this is enough for you?
page.evaluate('window.location.reload();')
Or
page.evaluate('location.reload();')
As you can see we are forcing the reload by evaluating a javascript.
Yes...it is a little bit tricky, so probably you will need to even force a time.sleep(2) after that, and trust me, I hate time.sleep() but this is an special situation.
I hope it helps.
Try to make it a bit slower like a human does by injecting delay parameter as follows:
self.page.keyboard.press('F5',delay=100)
Update!
keyboard.press('F5' with page.reload() method is really refreshing the browsed page. You can try whether it works or not.
You can justify the below real example:
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch(headless=False,slow_mo=1000)
context = browser.new_context(viewport={"width": 1920, "height": 1080})
page = context.new_page()
page.goto('https://workspace.google.com/marketplace/search/word')
page.keyboard.press('F5',delay=1000)
page.reload()
playwright-python doc
I am logging into a website using my own credentials, but 2FA is active. Therefore, I need a way to "pause" the script until I manually click the button with my mouse.
Note that the button is always clickable, so using an explicit wait like element_to_be_clickable obviously will not work.
I know how to do this with input() via command prompt, but I would rather deal with the browser manually since the rest of the script also requires manual browser interaction.
I also know that I could wait until the script detects a certain number of inputted characters, but I do not like this approach because typos.
I know I could use an explicit wait in order to detect something on the following page, but I want to avoid this way in case I ever need to step away from the keyboard before submitting the data. However, I could set an unreasonably long wait period e.g. WebDriver(driver, 999999999), but this approach seems super hacky.
Any ideas?
Here is a solution that may not work for everybody. Poll the URL...
poll_rate = 1
current_url = driver.current_url
while driver.current_url == current_url:
time.sleep(poll_rate)
Can anybody come up with a better solution?!
I am shocked that it is almost impossible to detect user input in a practical manner.
When I try to run any kind of code using winium, it will open the app, but then won't execute any of the code afterwards. It's not as if it throws up an error, it just hangs there and won't move on.
I Am using Python 3.7 on a Windows 10 PC.
I have tried the two 'magic' examples that are listed on the github wiki page for Winium, but even that doesn't work. I am able to use selenium to do automated web testing, so I don't think the selenium module is the issue. I have tried importing the time module and making it sleep for 10 seconds in between lines but this has no effect on the outcome.
from selenium import webdriver
driver = webdriver.Remote(
command_executor='http://localhost:9999',
desired_capabilities={
"debugConnectToRunningApp": 'false',
"app": r"C:/windows/system32/calc.exe"
})
# THIS IS WHERE IT SEEMS TO PAUSE INDEFINITELY
window = driver.find_element_by_class_name('CalcFrame')
view_menu_item = window.find_element_by_id('MenuBar').find_element_by_name('View')
view_menu_item.click()
view_menu_item.find_element_by_name('Scientific').click()
view_menu_item.click()
view_menu_item.find_element_by_name('History').click()
window.find_element_by_id('132').click()
window.find_element_by_id('93').click()
window.find_element_by_id('134').click()
window.find_element_by_id('97').click()
window.find_element_by_id('138').click()
window.find_element_by_id('121').click()
driver.close()
I would expect it to press the corresponding buttons, but it doesn't seem to do anything except open the calculator app.
I think this example is written for an older version of calculator. In Windows 10, the "Scientific" button is under the Menu button.
You'll have to find the menu button, click it, and then look for the element "Scientific" in the list.
Also, the numeric values for your arithmatic case are not correct. Pick up a UI inspector tool (inspect.exe, uispy, etc...) to make sure you are targeting the elements correctly.
I'm using Python with Selenium 2.44. When the test fails, I can't just uncomment all the code before the failure when debugging it, because the driver will not be declared for the browser. Therefore, whenever I try fixing something, I always have to open a new browser in the test case. This is rather... slow since I have to login, which adds an additional 30 seconds (not devastating, but annoying). I want to know if there's a way for me to just continue a session, or do something that allows me to start the test midway through (so if I have the webpage open already, I can just immediately start clicking things rather than opening a new browser). Is this possible?
For example, if I had something along the lines of:
driver = webdriver.Firefox()
driver.get("google.com")
driver.find_element_by_xpath("//input[#id='gbqfq']").send_keys("cats" + Keys.RETURN)
This should open Firefox, go to google, and search for cats. Pretend like there's a ton of stuff you have to do before you can actually make it to the google page, though. Now if it were to fail on the search for cats, the only way I would be able to test to see if I fixed the code would be to rerun the test (webdriver.Firefox() would open a new browser). Rather than that, assuming I'd still have google open, I'd like the selenium test to just start off on the previous browser and google page (therefore saying the first step in the code would be the send_keys("cats")). Is this possible?
I think that this was a similar question, but it didn't get checked off as answered: How to resume browser session or use existing browser window with Selenium-Python?
This one also seems similar, only pertaining to Java: How do I rerun Selenium 2.0 (webdriver) tests on the same browser?
Thanks.
Look into pdb: https://docs.python.org/2/library/pdb.html
Placing this in your code will stop the progression of the test as is until you tell it to continue in your shell.
Using your code snippit:
from pdb import set_trace
driver = webdriver.Firefox()
driver.get("google.com")
set_trace()
driver.find_element_by_xpath("//input[#id='gbqfq']").send_keys("cats" + Keys.RETURN)
will stop your execution after getting the url, allow you to tinker, and then continue from where the test left off.
Alternatively, while debugging, you can just remove the driver.quit() statement, wherever it happens to be, which will keep the browser open wherever your assertion failed. But if you're using a framework like Django with the LiveTestServer Client, you won't have access to browse the site further. pdb will allow you to keep the test server active.
I am currently using the Python Webkit DOM Bindings to interact with a website programmatically and that's working for me.
The only problem is that it insists on opening a GTK window to display the page. Has somebody figured out a way to prevent it from opening a window? I.e. to use it in a headless way?
I'm initializing the view like this:
wv = pywebkitgtk.WebView(1024, 768, url=url)
which implicitly opens the GTK window and then I have an onload event-handler to manipulate the DOM.
I first thought of subclassing WebView, but that's not possible because it is a compiled class.
Any other ideas?
I'm the developer responsible for pythonwebkit, and I have a great deal of expertise covering these areas across several platforms. Realistically, you really, really want a completely "headless" WebKit port. In pythonwebkit that actually shouldn't be too hard to do, as there are only three "entry point" functions (one for window, one for document, and one for XMLHTTPRequest).
Really, somebody should do a proper "completely headless" port of WebKit. There already is an example program which is pretty close in WebKit's source tree, maybe that will get you started.
I've been using PyQT. PyQTWebView runs on Webkit and works great. Check out Ghost.py to get started, or use PyQT's API directly. Runs fully headless, and supports a decently recent build of Webkit.
You could try using Xvfb. I like using the command line and setting my display manually, but if you don't like that you could use this: http://cgoldberg.github.io/xvfbwrapper/
Can you get a handle to the GTK window and then call window.hide()? Otherwise, you might just have to use the full Webkit library.
Create a window and add the webview there, and never show the window..
I have webviews running without showing them, and can call a show_all if I need to show them.
web_view = pywebkitgtk.WebView()
window = gtk.Window(gtk.WINDOW_TOPLEVEL)
sw = gtk.ScrolledWindow(hadjustment=None, vadjustment=None)
sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_NEVER)
sw.add(web_view)
window.add(sw)
#window.show_all()