Skip to content
This repository has been archived by the owner on Sep 16, 2021. It is now read-only.

Commit

Permalink
Introduced window manager (#38)
Browse files Browse the repository at this point in the history
  • Loading branch information
jrbenny35 authored and davehunt committed Jan 11, 2017
1 parent 428e457 commit 2e111e3
Show file tree
Hide file tree
Showing 10 changed files with 169 additions and 87 deletions.
22 changes: 22 additions & 0 deletions foxpuppet/expected.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.


class new_browser_window_is_opened(object):
"""
An expectation for checking that a new window is found after requesting
it to be opened
:returns: A BrowserWindow Object
"""

def __init__(self, selenium, handles):
self.selenium = selenium
self.handles = handles

def __call__(self, *args, **kwargs):
handles = list(set(self.selenium.window_handles) - set(self.handles))
if len(handles) == 1:
from .windows.browser import BrowserWindow
return BrowserWindow(self.selenium, handles[0])
11 changes: 7 additions & 4 deletions foxpuppet/foxpuppet.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.

from .browser.window import BrowserWindow
from .windows import Windows

from .windows import WindowManager


class FoxPuppet(object):
""" Class that sets up the api for interacting with the Firefox browser.
"""

def __init__(self, selenium):
self.selenium = selenium
self.browser = BrowserWindow(selenium)
self.windows = Windows(selenium)
self.window_manager = WindowManager(selenium)
# Need to ensure the first window is a browser window
self.browser = self.window_manager.windows[0]
45 changes: 0 additions & 45 deletions foxpuppet/windows.py

This file was deleted.

7 changes: 7 additions & 0 deletions foxpuppet/windows/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.

from .base import BaseWindow # noqa
from .browser import BrowserWindow # noqa
from .window_manager import WindowManager # noqa
35 changes: 35 additions & 0 deletions foxpuppet/windows/base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.

from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait


class BaseWindow(object):

_document_element = (By.CSS_SELECTOR, ':root')

def __init__(self, selenium, handle):
self.selenium = selenium
self.handle = handle
self.wait = WebDriverWait(self.selenium, timeout=10)

@property
def document_element(self):
""" Returns the inner DOM window element.
:returns: DOM window element.
"""

return self.selenium.find_element(*self._document_element)

def close(self):
"""Closes the window"""
self.switch_to()
self.selenium.close()

def switch_to(self):
"""Switches to the window"""

self.selenium.switch_to.window(self.handle)
43 changes: 28 additions & 15 deletions foxpuppet/browser/window.py → foxpuppet/windows/browser.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,43 +2,56 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.

from foxpuppet.windows import Windows

from selenium.webdriver.common.by import By

from foxpuppet.expected import new_browser_window_is_opened
from foxpuppet.windows import BaseWindow


class BrowserWindow(BaseWindow):

"""Representation of a browser window."""

class BrowserWindow(object):
_file_menu_button_locator = (By.ID, 'file-menu')
_file_menu_private_window_locator = (By.ID, 'menu_newPrivateWindow')
_file_menu_new_window_button_locator = (By.ID, 'menu_newNavigator')
_nav_bar_locator = (By.ID, 'nav-bar')
_tab_browser_locator = (By.ID, 'tabbrowser-tabs')

def __init__(self, selenium, *args, **kwargs):
self.selenium = selenium
self._windows = Windows(selenium)

@property
def is_private(self):
"""Returns True if this is a Private Browsing window."""

self.selenium.set_context('chrome')
return self.selenium.execute_script("""
self.switch_to()
with self.selenium.context('chrome'):
return self.selenium.execute_script(
"""
Components.utils.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
let chromeWindow = arguments[0].ownerDocument.defaultView;
return PrivateBrowsingUtils.isWindowPrivate(chromeWindow);
""", self._windows.window_element)
self.selenium.set_context('content')
""", self.document_element)

def open_window(self, private=False):
self.selenium.set_context('chrome')
self.selenium.find_element(*self._file_menu_button_locator).click()
with self._windows.wait_for_new_window():
"""Opens a new browser window
:param private: Optional parameter to open a private browsing window.
Defaults to False.
"""

handles_before = self.selenium.window_handles
self.switch_to()

with self.selenium.context('chrome'):
# Opens private or non-private window
self.selenium.find_element(*self._file_menu_button_locator).click()
if private:
self.selenium.find_element(
*self._file_menu_private_window_locator).click()
else:
self.selenium.find_element(
*self._file_menu_new_window_button_locator).click()
self.selenium.set_context('content')

return self.wait.until(
new_browser_window_is_opened(self.selenium, handles_before),
message="No new browser window opened")
19 changes: 19 additions & 0 deletions foxpuppet/windows/window_manager.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.


class WindowManager(object):

def __init__(self, selenium):
self.selenium = selenium

@property
def windows(self):
"""
Sets all current window handles to appropriate window instances
:returns: A list of BrowserWindow Instances
"""
from foxpuppet.windows.browser import BrowserWindow
return [BrowserWindow(self.selenium, handle)
for handle in self.selenium.window_handles]
6 changes: 5 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,18 @@

from setuptools import setup


setup(name='FoxPuppet',
use_scm_version=True,
description='Firefox user interface testing model for use with Selenium',
long_description=open('README.rst').read(),
author='Firefox Test Engineering',
author_email='firefox-test-engineering@mozilla.com',
url='https://github.com/mozilla/FoxPuppet',
packages=['foxpuppet'],
packages=[
'foxpuppet',
'foxpuppet.windows'
],
install_requires=['selenium>=3.0.1'],
setup_requires=['setuptools_scm'],
license='Mozilla Public License 2.0 (MPL 2.0)',
Expand Down
9 changes: 9 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.

import pytest

from foxpuppet import FoxPuppet


@pytest.fixture
def foxpuppet(selenium):
return FoxPuppet(selenium)
59 changes: 37 additions & 22 deletions tests/test_browser_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,40 @@
# You can obtain one at http://mozilla.org/MPL/2.0/.


from foxpuppet import FoxPuppet


class TestBrowserModel(object):

def test_new_private_window(self, selenium):
"""Tests opening a new private browsing window via menu"""
foxpuppet = FoxPuppet(selenium)
foxpuppet.browser.open_window(private=True)
assert len(foxpuppet.windows.all) == 2
assert foxpuppet.browser.is_private is False
foxpuppet.windows.focus(foxpuppet.windows.all[1])
assert foxpuppet.browser.is_private is True

def test_open_new_window(self, selenium):
"""Tests opening a new window via menu"""
foxpuppet = FoxPuppet(selenium)
foxpuppet.browser.open_window(private=False)
assert len(foxpuppet.windows.all) == 2
assert foxpuppet.browser.is_private is False
foxpuppet.windows.focus(foxpuppet.windows.all[1])
assert foxpuppet.browser.is_private is False
def test_initial_browser_window(foxpuppet):
"""Tests initial state of browser windows"""
assert len(foxpuppet.window_manager.windows) == 1
assert foxpuppet.browser is not None
assert not foxpuppet.browser.is_private


def test_new_private_window(foxpuppet):
"""Tests opening a new private browsing window via menu"""
new_browser = foxpuppet.browser.open_window(private=True)
assert new_browser is not foxpuppet.browser
assert new_browser.is_private
assert len(foxpuppet.window_manager.windows) == 2


def test_open_new_window(foxpuppet):
"""Tests opening a new window via menu"""
new_browser = foxpuppet.browser.open_window(private=False)
assert new_browser is not foxpuppet.browser
assert not new_browser.is_private
assert len(foxpuppet.window_manager.windows) == 2


def test_close_window(foxpuppet):
"""Tests closing a window"""
new_browser = foxpuppet.browser.open_window()
new_browser.close()
assert len(foxpuppet.window_manager.windows) == 1


def test_switch_to(foxpuppet, selenium):
"""Test Switch to function"""
foxpuppet.browser.open_window()

# Switch to originally window opened by pytest
foxpuppet.browser.switch_to()
assert foxpuppet.browser.handle == selenium.current_window_handle

0 comments on commit 2e111e3

Please sign in to comment.