Skip to content

Commit

Permalink
feat: stop playwright when driver is closed (#393)
Browse files Browse the repository at this point in the history
  • Loading branch information
rgonalo authored Jun 11, 2024
1 parent d9b3435 commit 8604935
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 23 deletions.
16 changes: 6 additions & 10 deletions toolium/behave/environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,12 @@ def create_and_configure_wrapper(context):
# Configure wrapper
context.driver_wrapper.configure(context.config_files, behave_properties=behave_properties)

# Activate behave async context to execute playwright
if (context.driver_wrapper.config.get_optional('Driver', 'web_library') == 'playwright'
and context.driver_wrapper.async_loop is None):
use_or_create_async_context(context)
context.driver_wrapper.async_loop = context.async_context.loop

# Copy config object
context.toolium_config = context.driver_wrapper.config

Expand Down Expand Up @@ -227,12 +233,6 @@ def after_scenario(context, scenario):
DriverWrappersPool.close_drivers(scope='function', test_name=scenario.name,
test_passed=scenario.status in ['passed', 'skipped'], context=context)

# Stop playwright
if context.toolium_config.get_optional('Driver', 'web_library') == 'playwright' and hasattr(context, 'playwright'):
# TODO: reuse driver like in close_drivers
loop = context.async_context.loop
loop.run_until_complete(context.playwright.stop())

# Save test status to be updated later
if jira_test_status:
add_jira_status(get_jira_key_from_scenario(scenario), jira_test_status, jira_test_comment)
Expand Down Expand Up @@ -289,10 +289,6 @@ def start_driver(context, no_driver):
:param context: behave context
:param no_driver: True if this is an api test and driver should not be started
"""
if context.toolium_config.get_optional('Driver', 'web_library') == 'playwright':
# Activate behave async context to execute playwright
use_or_create_async_context(context)
context.driver_wrapper.async_loop = context.async_context.loop
create_and_configure_wrapper(context)
if not no_driver:
connect_wrapper(context)
53 changes: 41 additions & 12 deletions toolium/driver_wrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ class DriverWrapper(object):
remote_node_video_enabled = False #: True if the remote grid node has the video recorder enabled
logger = None #: logger instance
async_loop = None #: async loop for playwright tests
playwright = None #: playwright instance
playwright_browser = None #: playwright browser instance

# Configuration and output files
config_properties_filenames = None #: configuration filenames separated by commas
Expand All @@ -70,6 +72,9 @@ def __init__(self):
default_wrapper = DriverWrappersPool.get_default_wrapper()
self.config = default_wrapper.config.deepcopy()
self.logger = default_wrapper.logger
self.async_loop = default_wrapper.async_loop
self.playwright = default_wrapper.playwright
self.playwright_browser = default_wrapper.playwright_browser
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 @@ -204,18 +209,25 @@ def configure(self, tc_config_files, is_selenium_test=True, behave_properties=No
self.configure_visual_baseline()

def connect(self):
"""Set up the selenium driver and connect to the server
"""Set up the driver and connect to the server
:returns: selenium or playwright driver
"""
if not self.config.get('Driver', 'type') or self.config.get('Driver', 'type') in ['api', 'no_driver']:
return None

if self.async_loop:
# Connect playwright driver
self.driver = self.connect_playwright(self.async_loop)
return self.driver
self.connect_playwright()
else:
self.connect_selenium()

return self.driver

def connect_selenium(self):
"""Set up selenium driver
:returns: selenium driver
"""
self.driver = ConfigDriver(self.config, self.utils).create_driver()

# Save session id and remote node to download video after the test execution
Expand Down Expand Up @@ -244,20 +256,37 @@ def connect(self):
# Set implicitly wait timeout
self.utils.set_implicitly_wait()

return self.driver

def connect_playwright(self, async_loop):
def connect_playwright(self):
"""Set up the playwright page
It is a sync method because it is called from sync behave initialization method
:returns: playwright page
"""
# TODO: should playwright and browser be saved in driver_wrapper?
playwright = async_loop.run_until_complete(async_playwright().start())
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')
browser = async_loop.run_until_complete(playwright.chromium.launch(headless=headless_mode))
page = async_loop.run_until_complete(browser.new_page())
return page
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())

async def connect_playwright_new_page(self):
"""Set up and additional playwright driver creating a new context and page in current browser 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()
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())
else:
# Stop selenium driver
self.driver.quit()

def resize_window(self):
"""Resize and move browser window"""
Expand Down
2 changes: 1 addition & 1 deletion toolium/driver_wrappers_pool.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ def stop_drivers(cls, maintain_default=False):
if not driver_wrapper.driver:
continue
try:
driver_wrapper.driver.quit()
driver_wrapper.stop()
except Exception as e:
driver_wrapper.logger.warning(
"Capture exceptions to avoid errors in teardown method due to session timeouts: \n %s" % e)
Expand Down

0 comments on commit 8604935

Please sign in to comment.