Skip to content

Commit

Permalink
playwright start by browser
Browse files Browse the repository at this point in the history
  • Loading branch information
jruizg23 committed Jul 8, 2024
1 parent 8604935 commit 0fbbe5a
Show file tree
Hide file tree
Showing 2 changed files with 281 additions and 11 deletions.
268 changes: 266 additions & 2 deletions toolium/config_driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import logging
import os
import re
from venv import create

from appium import webdriver as appiumdriver
from appium.options.common.base import AppiumOptions
Expand Down Expand Up @@ -66,10 +67,11 @@ def get_error_message_from_traceback(traceback):


class ConfigDriver(object):
def __init__(self, config, utils=None):
def __init__(self, config, utils=None, playwright=None):
self.logger = logging.getLogger(__name__)
self.config = config
self.utils = utils
self.playwright = playwright

def create_driver(self):
"""Create a selenium driver using specified config properties
Expand All @@ -91,6 +93,36 @@ def create_driver(self):
raise

return driver

def create_playwright_browser(self):
"""
Create a playwright browser using specified config properties
:returns: a new playwright browser o persistent browser context
"""
driver_type = self.config.get('Driver', 'type')
try:
self.logger.info("Creating playwright driver (type = %s)", driver_type)
return self._create_playwright_browser()
except Exception as exc:
error_message = get_error_message_from_exception(exc)
self.logger.error("%s driver can not be launched: %s", driver_type.capitalize(), error_message)
raise

def create_playwright_persistent_browser_context(self):
"""
Create a playwright persistent browser context using specified config properties
:returns: a new playwright persistent browser context
"""
driver_type = self.config.get('Driver', 'type')
try:
self.logger.info("Creating playwright persistent context (type = %s)", driver_type)
return self._create_playwright_persistent_browser_context()
except Exception as exc:
error_message = get_error_message_from_exception(exc)
self.logger.error("%s driver can not be launched: %s", driver_type.capitalize(), error_message)
raise

def _create_remote_driver(self):
"""Create a driver in a remote server
Expand Down Expand Up @@ -163,6 +195,77 @@ def _create_local_driver(self):
driver = driver_setup_method()

return driver

def _create_playwright_browser(self):
"""Create a browser in local machine using Playwright
:returns: a new browser Playwright
"""
driver_name = self.utils.get_driver_name()
if driver_name in ('android', 'ios', 'iphone'):
raise Exception('Playwright does not support mobile devices')
else:
if driver_name in ['chrome', 'chromium']:
browser = self._setup_playwright_chrome()
elif driver_name == 'firefox':
browser = self._setup_playwright_firefox()
elif driver_name in ['safari', 'webkit']:
browser = self._setup_playwright_webkit()
else:
raise Exception(f'Playwright does not support {driver_name} driver')
return browser

def _create_playwright_persistent_browser_context(self):
"""Create a browser in local machine using Playwright
:returns: a new persistent browser context Playwright
"""
driver_name = self.utils.get_driver_name()
if driver_name in ('android', 'ios', 'iphone'):
raise Exception('Playwright does not support mobile devices')
else:
if driver_name in ['chrome', 'chromium']:
browser_context = self._setup_playwright_persistent_chrome()
elif driver_name == 'firefox':
browser_context = self._setup_playwright_persistent_firefox()
elif driver_name in ['safari', 'webkit']:
browser_context = self._setup_playwright_persistent_webkit()
else:
raise Exception(f'Playwright does not support {driver_name} driver')
return browser_context

def get_playwright_context_options(self):
"""Get Playwright context options from properties file
:returns: Playwright context options
"""
context_options = {}
try:
for key, value in dict(self.config.items('PlaywrightContextOptions')).items():
self.logger.debug("Added Playwright context option: %s = %s", key, value)
context_options[key] = self._convert_property_type(value)
except NoSectionError:
pass
window_width = self.config.get_optional('Driver', 'window_width')
window_height = self.config.get_optional('Driver', 'window_height')
if window_width and window_height:
context_options['viewport'] = {'width': int(window_width), 'height': int(window_height)}
return context_options

def get_playwright_page_options(self):
"""Get Playwright page options from properties file
:returns: Playwright page options
"""
page_options = {}
try:
for key, value in dict(self.config.items('PlaywrightPageOptions')).items():
self.logger.debug("Added Playwright page option: %s = %s", key, value)
page_options[key] = self._convert_property_type(value)
except NoSectionError:
pass
return page_options


def _get_capabilities_from_driver_type(self):
"""Extract browserVersion and platformName from driver type and add them to capabilities
Expand Down Expand Up @@ -295,6 +398,69 @@ def _add_firefox_extensions(self, driver):
except NoSectionError:
pass

def _setup_playwright_firefox(self):
"""Setup Playwright Firefox browser
:returns: a new Playwright Firefox browser
"""
headless_mode = self.config.getboolean_optional('Driver', 'headless')
arguments = []
preferences = {}
self._add_playwright_firefox_arguments(arguments)
# Note: Playwright does not support Firefox extensions
self._add_playwright_firefox_preferences(preferences)
browser_options = self._get_playwright_browser_options()
browser_options = self._update_dict(browser_options, {'args': arguments})
browser_options = self._update_dict(browser_options, {'firefox_user_prefs': preferences})
return self.playwright.firefox.launch(
headless=headless_mode,
**browser_options
)

def _setup_playwright_persistent_firefox(self):
"""Setup Playwright Firefox persistent browser context
:returns: a new Playwright Firefox persistent browser context
"""
headless_mode = self.config.getboolean_optional('Driver', 'headless')
arguments = []
preferences = {}
self._add_playwright_firefox_arguments(arguments)
# Note: Playwright does not support Firefox extensions
self._add_playwright_firefox_preferences(preferences)
context_options = self.get_playwright_context_options()
context_options = self._update_dict(context_options, {'args': arguments})
context_options = self._update_dict(context_options, {'firefox_user_prefs': preferences})
return self.playwright.firefox.launch_persistent_context(
headless=headless_mode,
**context_options
)

def _add_playwright_firefox_arguments(self, arguments):
"""Add Firefox arguments from properties file prepared for Playwright
:param arguments: Firefox arguments object
"""
try:
for pref, pref_value in dict(self.config.items('FirefoxArguments')).items():
pref_value = '={}'.format(pref_value) if pref_value else ''
self.logger.debug("Added Firefox argument: %s%s", pref, pref_value)
arguments.append('--{}{}'.format(pref, self._convert_property_type(pref_value)))
except NoSectionError:
pass

def _add_playwright_firefox_preferences(self, preferences):
"""Add Firefox preferences from properties file prepared for Playwright
:param preferences: Firefox preferences object
"""
try:
for pref, pref_value in dict(self.config.items('FirefoxPreferences')).items():
self.logger.debug("Added Firefox preference: %s = %s", pref, pref_value)
preferences[pref] = self._convert_property_type(pref_value)
except NoSectionError:
pass

@staticmethod
def _convert_property_type(value):
"""Converts the string value in a boolean, integer or string
Expand Down Expand Up @@ -361,6 +527,80 @@ def _get_chrome_options(self, capabilities={}):
self._update_dict(options.capabilities, capabilities)

return options

def _get_playwright_browser_options(self):
"""
Get Playwright browser options from properties file
:returns: Playwright browser options
"""
browser_options = {}
try:
for key, value in dict(self.config.items('PlaywrightBrowserOptions')).items():
self.logger.debug("Added Playwright Browser option: %s = %s", key, value)
browser_options[key] = self._convert_property_type(value)
except NoSectionError:
pass
return browser_options

def _setup_playwright_chrome(self):
"""
Setup Playwright Chrome browser
:returns: a new Playwright Chrome browser
"""
headless_mode = self.config.getboolean_optional('Driver', 'headless')
arguments = []
self._add_playwright_chrome_arguments(arguments)
self._add_playwright_chrome_extensions(arguments)
browser_options = self._get_playwright_browser_options()
browser_options = self._update_dict(browser_options, {'args': arguments})
return self.playwright.chromium.launch(
headless=headless_mode,
**browser_options
)

def _setup_playwright_persistent_chrome(self):
"""
Setup Playwright Chrome persistent browser context
:returns: a new Playwright Chrome persistent browser context
"""
headless_mode = self.config.getboolean_optional('Driver', 'headless')
arguments = []
self._add_playwright_chrome_arguments(arguments)
self._add_playwright_chrome_extensions(arguments)
context_options = self.get_playwright_context_options()
context_options = self._update_dict(context_options, {'args': arguments})
return self.playwright.chromium.launch_persistent_context(
headless=headless_mode,
**context_options
)

def _add_playwright_chrome_arguments(self, arguments):
"""Add Chrome arguments from properties file prepared for Playwright
:param arguments: Chrome arguments object
"""
try:
for pref, pref_value in dict(self.config.items('ChromeArguments')).items():
pref_value = '={}'.format(pref_value) if pref_value else ''
self.logger.debug("Added Chrome argument: %s%s", pref, pref_value)
arguments.append('--{}{}'.format(pref, self._convert_property_type(pref_value)))
except NoSectionError:
pass

def _add_playwright_chrome_extensions(self, arguments):
"""Add Chrome extensions from properties file
:param arguments: Chrome options object
"""
try:
for pref, pref_value in dict(self.config.items('ChromeExtensions')).items():
self.logger.debug("Added Chrome extension: %s = %s", pref, pref_value)
arguments.append('--load-extension={}'.format(pref_value))
except NoSectionError:
pass

def _add_chrome_options(self, options, option_name):
"""Add Chrome options from properties file
Expand Down Expand Up @@ -427,7 +667,7 @@ def _update_dict(self, initial, update, initial_key=None):
:param initial: initial dict to be updated
:param update: new dict
:param initial_key: update only one key in initial dicts
:return: merged dict
:returns: merged dict
"""
for key, value in update.items():
if initial_key is None or key == initial_key:
Expand Down Expand Up @@ -458,6 +698,30 @@ def _get_safari_options(self, capabilities={}):
self._add_capabilities_from_properties(capabilities, 'Capabilities')
self._update_dict(options.capabilities, capabilities)
return options

def _setup_playwright_webkit(self):
"""Setup Playwright Webkit browser
:returns: a new Playwright Webkit browser
"""
headless_mode = self.config.getboolean_optional('Driver', 'headless')
browser_options = self._get_playwright_browser_options()
return self.playwright.webkit.launch(
headless=headless_mode,
**browser_options
)

def _setup_playwright_persistent_webkit(self):
"""Setup Playwright Webkit persistent browser context
:returns: a new Playwright Webkit persistent browser context
"""
headless_mode = self.config.getboolean_optional('Driver', 'headless')
context_options = self.get_playwright_context_options()
return self.playwright.webkit.launch_persistent_context(
headless=headless_mode,
**context_options
)

def _setup_explorer(self):
"""Setup Internet Explorer webdriver
Expand Down
24 changes: 15 additions & 9 deletions toolium/driver_wrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ class DriverWrapper(object):
async_loop = None #: async loop for playwright tests
playwright = None #: playwright instance
playwright_browser = None #: playwright browser instance
playwright_context = None #: playwright context instance

# Configuration and output files
config_properties_filenames = None #: configuration filenames separated by commas
Expand All @@ -75,6 +76,7 @@ def __init__(self):
self.async_loop = default_wrapper.async_loop
self.playwright = default_wrapper.playwright
self.playwright_browser = default_wrapper.playwright_browser
self.playwright_context = default_wrapper.playwright_context
self.config_properties_filenames = default_wrapper.config_properties_filenames
self.config_log_filename = default_wrapper.config_log_filename
self.output_log_filename = default_wrapper.output_log_filename
Expand Down Expand Up @@ -264,26 +266,30 @@ def connect_playwright(self):
"""
async_loop = self.async_loop
self.playwright = async_loop.run_until_complete(async_playwright().start())
# TODO: select browser from config
headless_mode = self.config.getboolean_optional('Driver', 'headless')
self.playwright_browser = async_loop.run_until_complete(self.playwright.chromium.launch(headless=headless_mode))
self.driver = async_loop.run_until_complete(self.playwright_browser.new_page())

# In case of using a persistent context this property must be set and a BrowserContext is returned instead of a Browser
user_data_dir = self.config.get_optional('PlaywrightContextOptions', 'user_data_dir', None)
if user_data_dir:
self.playwright_context = async_loop.run_until_complete(ConfigDriver(self.config, self.utils, self.playwright).create_playwright_persistent_browser_context())
else:
self.playwright_browser = async_loop.run_until_complete(ConfigDriver(self.config, self.utils, self.playwright).create_playwright_browser())
self.playwright_context = async_loop.run_until_complete(self.playwright_browser.new_context(**ConfigDriver(self.config, self.utils, self.playwright).get_playwright_context_options()))
self.driver = async_loop.run_until_complete(self.playwright_context.new_page(**ConfigDriver(self.config, self.utils, self.playwright).get_playwright_page_options()))

async def connect_playwright_new_page(self):
"""Set up and additional playwright driver creating a new context and page in current browser instance
"""Set up and additional playwright driver creating a new page in current browser and context instance
It is an async method to be called from async steps or page objects
:returns: playwright driver
"""
context = await self.playwright_browser.new_context()
self.driver = await context.new_page()
"""
self.driver = await self.playwright_context.new_page(**ConfigDriver(self.config, self.utils).get_playwright_page_options())
return self.driver

def stop(self):
"""Stop selenium or playwright driver"""
if self.async_loop:
# Stop playwright driver
self.async_loop.run_until_complete(self.driver.close())
self.async_loop.run_until_complete(self.playwright_context.close())
else:
# Stop selenium driver
self.driver.quit()
Expand Down

0 comments on commit 0fbbe5a

Please sign in to comment.