Back in my day (pre-AJAX, etc.)… a common design layout method was to use frames to load navigate around. And there are a lot of sites from that era still operating just fine behind corporate firewalls that haven’t been refreshed.

Nor should the be, really.

But this does pose a bit of a problem, well, more nuisance, when dealing with WebDriver since you have to switch context to a frame before it can be used. This means crawling through frames. A lot. Using Page Objects though, we can hide all of this chaos using something like this towards the top of your PO heirarchy.

<pre lang="python">def switch_to_frame(self, frame_name=None):
  if not frame_name:
    self.driver.switch_to_default_context()
    return

  if frame_name == "main_frame":
    self.switch_to_default_context()
    f = self.driver.find_element(By.CSS_SELECTOR, 'frame[name="main_frame"]')
    self.driver.switch_to_frame(f)
  elif frame_name == "top_frame":
    self.switch_to_frame('main_frame')
    f = self.driver.find_element(By.CSS_SELECTOR, 'frame[name="top_frame"]')
    self.driver.switch_to_frame(f)
  elif frame_name == "search_frame":
    self.switch_to_frame('main_frame')
    f = self.driver.find_element(By.CSS_SELECTOR, 'frame[name="search_frame"]')
    self.driver.switch_to_frame(f)
  else:
    raise UnknownFrameException('% is not a known frame.' % frame_name)

I’ve had to use this pattern a couple times recently and I employ it even if there is only one frame to switch to in the app since there is only one … until a second appears and its easier to add to an existing method than refactor a whole bunch of page objects.

Its also been pretty bomb-proof on Firefox, but I have one client where the level of nesting is pretty impressive and we can make it hang Chrome predictably. I suspect that is more due to a bug[s] in the chomedriver than anything else since doing the script manually works just fine.