Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: stop playwright when driver is closed #393

Merged
merged 1 commit into from
Jun 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading