Managing IFrames With Germanium
IFrames are a feature that is widely used when implementing complex web applications, but it can cause serious problems and confusion when developing automated tests for such an application. Fortunately, Germanium makes also this part easy. There are two key function to use here:
One can use these functions in any place if that is needed but generally it is good to create an iframe switcher for your Application under test. There is a default one but it does not help a lot so it pays do define your own. You can read more here about it: http://www.germaniumhq.com/documentation/#__iframe_germanium_iframe_decorator So let’s customize the iframe switcher. The simplest way to do it is to specify a select_iframe function which will be automatically turned to a class behind the scenes by Germanium. Example of an iframe switcher follows:
def select_iframe(self, germanium, iframe_name): # This is something like a sanity check that we have a reasonable page here. # Such waits will not take any time if there is no problem such as slow connection. wait(Element('body'), timeout=custom_timeout) # Get to the default content of the page. germanium.switch_to_default_content() if iframe_name not in ["default"]: # Sanity check again. wait(Element('body'), timeout=custom_timeout) # We are going deeper so let’s check there is an iframe. wait(Element('iframe'), timeout=custom_timeout) if iframe_name in ["task"]: # Go into the first iframe you find. You have to adjust this to your app. # You also have to make sure the first iframe represents the “task” part. germanium.switch_to_frame(germanium.find_element_by_css_selector('iframe')) if iframe_name in ["first_editor", "second_editor"]: # Let’s say there are two iframes on the page for two different “editors”. # These “editor” iframes are inside the “task” iframe. germanium.switch_to_frame(germanium.find_element_by_css_selector('iframe')) # Sanity check once again. wait(Element('body'), timeout=custom_timeout) # There is at least one iframe wait(Element('iframe'), timeout=custom_timeout) # We expect there to be 2 iframes on the page. wait(lambda: len(Element('iframe').element_list()) == 2) iframe_list = Element('iframe').element_list() # Choose the right iframe and jump into it. if iframe_name == "first_editor": germanium.switch_to_frame(iframe_list) elif iframe_name == "second_editor": germanium.switch_to_frame(iframe_list) return iframe_name
Now we have the
select_iframe() nicely customized so we can use it to open
open_browser(browser=browser, wd=webdriver_browser, iframe_selector=select_iframe)
Now we can annotate our test steps with the proper iframe tag. Generally, one test step “happens” in one iframe so the annotation ensures the desired iframe is reached before the step starts executing.
def log_in_to_application(context, url, username='user', password='aaa'): # Just log url into the console for reference. log("Current URL: " + get_germanium().current_url) # Basic login. type_keys(username, Input("username")) type_keys(password, Css("input#password")) click(Button("Login"))) # Custom function. The function may be annotated and therefore may be executed in a different iframe. wait_for_application_to_load(context)
There may be situations where you would need to change iframe inside one test step for several actions. Of course you still want to use your custom select_iframe(). One way is to write a separate function and annotate it but this may be too bothersome. A better way may be to define function inside the original step and to call it.
def make_sure_the_current_page_test_page(context): assert "Test" in get_germanium().title def assert_in_iframe(): assert Text("Test").exists() assert_in_iframe()