-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Have considered adding an IFrame context manager? #1407
-
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")
Beta Was this translation helpful? Give feedback.
All reactions
Replies: 3 comments 2 replies
-
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?
Beta Was this translation helpful? Give feedback.
All reactions
-
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.
Beta Was this translation helpful? Give feedback.
All reactions
-
@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 methodswith
needs to use
Beta Was this translation helpful? Give feedback.
All reactions
-
But customization should be hard
Beta Was this translation helpful? Give feedback.
All reactions
-
Work is complete: https://github.com/seleniumbase/SeleniumBase/releases/tag/v3.5.1
Beta Was this translation helpful? Give feedback.
All reactions
-
👍 1