Skip to content
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
28 changes: 17 additions & 11 deletions Examples/utilities/timeout.robot
Original file line number Diff line number Diff line change
@@ -1,30 +1,36 @@
*** Settings ***
Library PuppeteerLibrary
Test Setup Open browser to test page
Test Teardown Close Browser
Suite Teardown Close Puppeteer
Library PuppeteerLibrary

Suite Teardown Close Puppeteer
Test Setup Open browser to test page
Test Teardown Close All Browser


*** Variables ***
${DEFAULT_BROWSER} chrome
${HOME_PAGE_URL} http://127.0.0.1:7272/basic-html-elements.html
${DEFAULT_BROWSER} chrome
${HOME_PAGE_URL} http://127.0.0.1:7272/basic-html-elements.html


*** Test Cases ***
Default timeout
Set Timeout 3s
Run Keyword And Expect Error No new page has been open.* Wait for new window open

Timeout wait for new window open
${window count} = Get Window Count
Run Async Keywords
... Wait for new window open 5s AND
... Wait for new window open 5s AND
... Click Element id:open-new-tab

# Test timeout will not freeze script
# [Documentation] Target to test test timeout not freeze the script.
# [Timeout] 5s
# Run Keyword And Expect Error * Wait Until Page Contains Element id:open-new-tabx 6s


*** Keywords ***
Open browser to test page
${BROWSER} = Get variable value ${BROWSER} ${DEFAULT_BROWSER}
${BROWSER} = Get variable value ${BROWSER} ${DEFAULT_BROWSER}
${HEADLESS} = Get variable value ${HEADLESS} ${False}
&{options} = create dictionary headless=${HEADLESS}
&{options} = create dictionary headless=${HEADLESS}
Open browser ${HOME_PAGE_URL} browser=${BROWSER} options=${options}

28 changes: 18 additions & 10 deletions PuppeteerLibrary/__init__.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import asyncio
import os
import traceback
import warnings
import logging
import signal
import sys

import robot
from PuppeteerLibrary.keywords.checkbox import CheckboxKeywords
from typing import List
from PuppeteerLibrary.base.ipuppeteer_library import iPuppeteerLibrary
Expand Down Expand Up @@ -113,7 +116,7 @@ class PuppeteerLibrary(DynamicCore, iPuppeteerLibrary):
library_contexts: dict = {}

def __init__(self, disable_python_logging=True):

if disable_python_logging:
self._disable_python_logging()

Expand Down Expand Up @@ -151,7 +154,7 @@ def __init__(self, disable_python_logging=True):
@not_keyword
def get_current_library_context(self) -> iLibraryContext:
return self.current_libary_context

@not_keyword
async def set_current_library_context(self, context_name) -> iLibraryContext:
self.current_libary_context = self.library_contexts[context_name]
Expand Down Expand Up @@ -180,8 +183,8 @@ def create_library_context(self, alias: str, browser_type: str) -> iLibraryConte
library_context = self.library_factory.create(browser_type)
self.library_contexts[alias] = library_context
self.current_libary_context = library_context
return library_context
return library_context

@not_keyword
def remove_library_context(self, alias):
if alias not in self.library_contexts.keys():
Expand All @@ -190,7 +193,8 @@ def remove_library_context(self, alias):
del self.library_contexts[alias]
if self.current_libary_context == deleted_library_context:
if len(self.library_contexts) > 0:
self.current_libary_context = list(self.library_contexts.values())[-1]
self.current_libary_context = list(
self.library_contexts.values())[-1]
else:
self.current_libary_context = None

Expand All @@ -199,8 +203,16 @@ def run_keyword(self, name, args, kwargs):
self._running_keyword = name
try:
return DynamicCore.run_keyword(self, name, args, kwargs)
except robot.errors.TimeoutError:
logger.warn('Test timeout. Force stop puppeteer server')
# Force
self.loop.run_until_complete(
self.get_current_library_context().stop_server())
raise
except Exception:
if name.lower().replace(' ', '_') != 'capture_page_screenshot':
if name.lower().replace(' ', '_') == 'close_puppeteer' or name.lower().replace(' ', '_') == 'open_browser':
logger.warn('Can\'t close puppeteer...')
elif name.lower().replace(' ', '_') != 'capture_page_screenshot':
self.failure_occurred()
raise
finally:
Expand Down Expand Up @@ -229,7 +241,3 @@ def _disable_python_logging(self):

def _stop_execution_gracefully(self):
raise ExecutionFailed('Execution terminated by signal', exit=True)

from ._version import get_versions
__version__ = get_versions()['version']
del get_versions
34 changes: 21 additions & 13 deletions PuppeteerLibrary/keywords/browsermanagement.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import os
import shutil
from robot.api import logger
from PuppeteerLibrary.base.librarycomponent import LibraryComponent
from PuppeteerLibrary.base.robotlibcore import keyword
from PuppeteerLibrary.ikeywords.ibrowsermanagement_async import iBrowserManagementAsync
Expand Down Expand Up @@ -49,12 +50,13 @@ def open_browser(self, url, browser="chrome", alias=None, options={}):
"""
if options is None:
options = {}

self.info(url)
library_context = self.ctx.get_library_context_by_name(alias)
if library_context is None:
library_context = self.ctx.create_library_context(alias, browser)
self.loop.run_until_complete(self.ctx.set_current_library_context(alias))
self.loop.run_until_complete(
self.ctx.set_current_library_context(alias))
self.loop.run_until_complete(library_context.start_server(options))
self.loop.run_until_complete(library_context.create_new_page(options))
self.loop.run_until_complete(self.get_async_keyword_group().go_to(url))
Expand All @@ -63,7 +65,8 @@ def open_browser(self, url, browser="chrome", alias=None, options={}):
def close_window(self):
""" Close current browser tab/page
"""
self.loop.run_until_complete(self.ctx.get_current_library_context().close_window())
self.loop.run_until_complete(
self.ctx.get_current_library_context().close_window())

@keyword
def close_browser(self, alias=None):
Expand All @@ -78,15 +81,17 @@ def close_browser(self, alias=None):
def close_all_browser(self):
"""Close all browser
"""
library_contexts = self.ctx.get_all_library_context()
library_contexts = self.ctx.get_all_library_context()
for library_context in library_contexts:
self.loop.run_until_complete(library_context.close_browser_context())
self.loop.run_until_complete(
library_context.close_browser_context())

@keyword
def close_puppeteer(self):
library_contexts_dict = self.ctx.get_all_library_context_dict()
for key in list(library_contexts_dict.keys()):
self.loop.run_until_complete(library_contexts_dict[key].stop_server())
self.loop.run_until_complete(
library_contexts_dict[key].stop_server())
self.ctx.remove_library_context(key)

@keyword
Expand All @@ -113,13 +118,14 @@ def go_to(self, url):
@keyword
def reload_page(self):
"""Reload the current page"""
self.loop.run_until_complete(self.get_async_keyword_group().reload_page())
self.loop.run_until_complete(
self.get_async_keyword_group().reload_page())

@keyword
def get_window_count(self):
""" Get windows count
"""
return self.loop.run_until_complete(self.get_async_keyword_group().get_window_count())
return self.loop.run_until_complete(self.get_async_keyword_group().get_window_count())

@keyword
def wait_for_new_window_open(self, timeout=None):
Expand All @@ -131,7 +137,8 @@ def wait_for_new_window_open(self, timeout=None):
| Run Async Keywords | Click Element | id:view_conditions | AND |
| ... | `Wait For New Window Open` | | |
"""
self.loop.run_until_complete(self.get_async_keyword_group().wait_for_new_window_open(timeout))
self.loop.run_until_complete(
self.get_async_keyword_group().wait_for_new_window_open(timeout))

@keyword
def switch_window(self, locator='MAIN'):
Expand All @@ -142,7 +149,8 @@ def switch_window(self, locator='MAIN'):
- title="QAHive": window title. Page title will have have error if new tab have auto redirection
- url="https://qahive.com": url support regex Example: url=.*qahive.com
"""
self.loop.run_until_complete(self.get_async_keyword_group().switch_window(locator))
self.loop.run_until_complete(
self.get_async_keyword_group().switch_window(locator))

@keyword
def switch_browser(self, alias):
Expand Down Expand Up @@ -265,11 +273,12 @@ def delete_browser_storage_state(self, ref):
*Limitation* only support Playwright browser
"""
file_path = self.STATES_FOLDER +'/state-'+ ref + '.json'
file_path = self.STATES_FOLDER + '/state-' + ref + '.json'
if os.path.exists(file_path):
os.remove(file_path)
else:
self.warn('Can not delete the storate '+ref+' as it doesn\'t exists')
self.warn('Can not delete the storate ' +
ref+' as it doesn\'t exists')

@keyword
def delete_all_browser_storage_states(self):
Expand All @@ -281,4 +290,3 @@ def delete_all_browser_storage_states(self):
shutil.rmtree(self.STATES_FOLDER)
except OSError as e:
self.warn("Error: %s - %s." % (e.filename, e.strerror))

9 changes: 6 additions & 3 deletions PuppeteerLibrary/playwright/playwright_context.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import asyncio
from robot.api import logger
from PuppeteerLibrary.custom_elements.base_page import BasePage
from PuppeteerLibrary.playwright.custom_elements.playwright_page import PlaywrightPage
from PuppeteerLibrary.playwright.async_keywords.playwright_checkbox import PlaywrightCheckbox
Expand Down Expand Up @@ -75,7 +76,6 @@ async def start_server(self, options: dict = {}):
del merged_options['proxy']
self.browser = await self.playwright.chromium.launch(
headless=merged_options['headless'], proxy=proxy)
merged_options
elif self.browser_type == "webkit":
self.browser = await self.playwright.webkit.launch(
headless=merged_options['headless'])
Expand All @@ -85,7 +85,10 @@ async def start_server(self, options: dict = {}):
self.browser.accept_downloads = True

async def stop_server(self):
await self.playwright.stop()
try:
await asyncio.wait_for(self.playwright.stop(), timeout=5.0)
except Exception:
logger.warn('Can\'t stop server properly...')
self._reset_server_context()

def is_server_started(self) -> bool:
Expand Down Expand Up @@ -149,7 +152,7 @@ def get_browser_context(self):
async def close_browser_context(self):
if self.browser is not None:
try:
await asyncio.wait_for(self.browser.close(), timeout=3)
await asyncio.wait_for(self.browser.close(), timeout=5)
except asyncio.TimeoutError:
None
self._reset_context()
Expand Down