Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Have considered adding an IFrame context manager? #1407

chenqinggang001 started this conversation in Ideas
Discussion options

I find that I need to call switch_to_frame() and switch_to_default_content() frequently when THERE are too many iframes.

For example:

self.switch_to_frame("//iframe")
self.click("//button")
self.switch_to_default_content()
self.switch_to_frame("//iframe")
self.click("//button")
self.switch_to_default_content()

Have considered adding an IFrame context manager?Help us automatically call switch_to_default_content()

For example:

with self.switch_to_frame("//iframe"):
 self.click("//button")
You must be logged in to vote

Replies: 3 comments 2 replies

Comment options

There are a few ways to achieve this within BaseCase:

New method for the context manager: (Can't use the old method name without breaking backwards compatibility.)

 from contextlib import contextmanager
 @contextmanager
 def cm_switch_to_frame(self, frame, timeout=None):
 self.switch_to_frame(frame, timeout=timeout)
 yield
 self.switch_to_parent_frame()

New class:

 class Frame(object):
 def __init__(self, sb, frame, timeout=None):
 self.sb = sb
 self.frame = frame
 self.timeout = timeout
 def __enter__(self):
 self.sb.switch_to_frame(self.frame, timeout=self.timeout)
 def __exit__(self, type, value, traceback):
 self.sb.switch_to_parent_frame()

Here's an example test that combines both ways:

from seleniumbase import BaseCase
class FrameTests(BaseCase):
 def test_iframe_basics(self):
 self.open("https://seleniumbase.io/w3schools/iframes.html")
 with self.Frame(self, "iframeResult"):
 self.assert_text("HTML Iframes", "h2")
 with self.cm_switch_to_frame('[title*="Iframe"]'):
 self.assert_text("This page is displayed in an iframe", "h1")
 self.assert_text("Use CSS width & height to specify", "p")
 with self.cm_switch_to_frame('[title*="Iframe"]'):
 self.assert_text("seleniumbase.io/w3schools/iframes", "a")
 self.click("button#runbtn")
 self.switch_to_frame("iframeResult") # Go back inside 1st iframe
 self.highlight('iframe[title="Iframe Example"]')

I could theoretically implement this if useful. Thoughts?

You must be logged in to vote
0 replies
Comment options

I'm currently working on an optimal implementation for this. So far, two possible solutions:

 from contextlib import contextmanager
 
 @contextmanager
 def frame_switch(self, frame, timeout=None):
 """ Context Manager for switching into iframes.
 Usage example:
 with self.frame_switch("iframe"):
 # Perform actions here that should be done inside the iframe.
 # Automatically calls switch_to_parent_frame() after "with" block.
 """
 self.switch_to_frame(frame, timeout=timeout)
 yield
 self.switch_to_parent_frame()
 class FrameSwitch(object):
 """ Context Manager for switching into iframes.
 Usage example:
 with self.FrameSwitch(self, "iframe"):
 # Perform actions here that should be done inside the iframe.
 # Automatically calls switch_to_parent_frame() after "with" block.
 """
 def __init__(self, sb, frame=None, timeout=None):
 if not hasattr(sb, "browser"):
 message = "Incorrect usage of FrameSwitch()!\n"
 message += 'The first argument passed must be the sb "self".\n'
 message += "Here's an example of correct usage:\n"
 message += ' with self.FrameSwitch(self, "iframe"):\n'
 message += " # Perform actions for inside the iframe.\n"
 message += " # Automatically exits frame after the block.\n"
 raise Exception(message)
 if not frame:
 raise Exception('Value of "frame" cannot be None!')
 self.sb = sb
 sb.switch_to_frame(frame, timeout=timeout)
 def __enter__(self):
 pass # Moving this code to __init__() allows calls without "with".
 def __exit__(self, type, value, traceback):
 self.sb.switch_to_parent_frame()

Here's an example that uses both:

from seleniumbase import BaseCase
class FrameTests(BaseCase):
 def test_iframe_basics(self):
 self.open("https://seleniumbase.io/w3schools/iframes.html")
 with self.FrameSwitch(self, "iframeResult"):
 self.assert_text("HTML Iframes", "h2")
 with self.FrameSwitch(self, '[title*="Iframe"]'):
 self.assert_text("This page is displayed in an iframe", "h1")
 self.assert_text("Use CSS width & height to specify", "p")
 with self.frame_switch('[title*="Iframe"]'):
 self.assert_text("seleniumbase.io/w3schools/iframes", "a")
 self.click("button#runbtn")
 with self.frame_switch("iframeResult"): # Go back inside 1st iframe
 self.highlight('iframe[title="Iframe Example"]')

Each of the two solutions have their advantages and disadvantages. The FrameSwitch() class can be used without the with, but it also requires passing in an extra arg, self, for the method to work. The frame_switch() method must always be called with with, or nothing will happen.

You must be logged in to vote
2 replies
Comment options

@mdmintz I think frame_switch() is fine. When 'with' is not required:

switch_to_frame() 
...
switch_to_default_content()

Or a custom slot for the user,Simply override BaseCase after inheriting it, and then customize the methodswithneeds to use

Comment options

But customization should be hard

Comment options

You must be logged in to vote
0 replies
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Category
Ideas
Labels
None yet

AltStyle によって変換されたページ (->オリジナル) /