Skip to content

Commit 481717b

Browse files
authored
Fixed script freeze if test timeout occur (#164)
* Fixed script freeze if test timeout occur * Update close puppeteer timeout to 5 sec * Update close browser to 5 sec Co-authored-by: Atthaboon Sanurt <[email protected]>
1 parent 6f9bb93 commit 481717b

File tree

4 files changed

+62
-37
lines changed

4 files changed

+62
-37
lines changed

Examples/utilities/timeout.robot

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,36 @@
11
*** Settings ***
2-
Library PuppeteerLibrary
3-
Test Setup Open browser to test page
4-
Test Teardown Close Browser
5-
Suite Teardown Close Puppeteer
2+
Library PuppeteerLibrary
3+
4+
Suite Teardown Close Puppeteer
5+
Test Setup Open browser to test page
6+
Test Teardown Close All Browser
67

78

89
*** Variables ***
9-
${DEFAULT_BROWSER} chrome
10-
${HOME_PAGE_URL} http://127.0.0.1:7272/basic-html-elements.html
10+
${DEFAULT_BROWSER} chrome
11+
${HOME_PAGE_URL} http://127.0.0.1:7272/basic-html-elements.html
1112

1213

1314
*** Test Cases ***
1415
Default timeout
1516
Set Timeout 3s
1617
Run Keyword And Expect Error No new page has been open.* Wait for new window open
17-
18+
1819
Timeout wait for new window open
1920
${window count} = Get Window Count
2021
Run Async Keywords
21-
... Wait for new window open 5s AND
22+
... Wait for new window open 5s AND
2223
... Click Element id:open-new-tab
2324

25+
# Test timeout will not freeze script
26+
# [Documentation] Target to test test timeout not freeze the script.
27+
# [Timeout] 5s
28+
# Run Keyword And Expect Error * Wait Until Page Contains Element id:open-new-tabx 6s
29+
30+
2431
*** Keywords ***
2532
Open browser to test page
26-
${BROWSER} = Get variable value ${BROWSER} ${DEFAULT_BROWSER}
33+
${BROWSER} = Get variable value ${BROWSER} ${DEFAULT_BROWSER}
2734
${HEADLESS} = Get variable value ${HEADLESS} ${False}
28-
&{options} = create dictionary headless=${HEADLESS}
35+
&{options} = create dictionary headless=${HEADLESS}
2936
Open browser ${HOME_PAGE_URL} browser=${BROWSER} options=${options}
30-

PuppeteerLibrary/__init__.py

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
import asyncio
22
import os
3+
import traceback
34
import warnings
45
import logging
56
import signal
67
import sys
8+
9+
import robot
710
from PuppeteerLibrary.keywords.checkbox import CheckboxKeywords
811
from typing import List
912
from PuppeteerLibrary.base.ipuppeteer_library import iPuppeteerLibrary
@@ -113,7 +116,7 @@ class PuppeteerLibrary(DynamicCore, iPuppeteerLibrary):
113116
library_contexts: dict = {}
114117

115118
def __init__(self, disable_python_logging=True):
116-
119+
117120
if disable_python_logging:
118121
self._disable_python_logging()
119122

@@ -151,7 +154,7 @@ def __init__(self, disable_python_logging=True):
151154
@not_keyword
152155
def get_current_library_context(self) -> iLibraryContext:
153156
return self.current_libary_context
154-
157+
155158
@not_keyword
156159
async def set_current_library_context(self, context_name) -> iLibraryContext:
157160
self.current_libary_context = self.library_contexts[context_name]
@@ -180,8 +183,8 @@ def create_library_context(self, alias: str, browser_type: str) -> iLibraryConte
180183
library_context = self.library_factory.create(browser_type)
181184
self.library_contexts[alias] = library_context
182185
self.current_libary_context = library_context
183-
return library_context
184-
186+
return library_context
187+
185188
@not_keyword
186189
def remove_library_context(self, alias):
187190
if alias not in self.library_contexts.keys():
@@ -190,7 +193,8 @@ def remove_library_context(self, alias):
190193
del self.library_contexts[alias]
191194
if self.current_libary_context == deleted_library_context:
192195
if len(self.library_contexts) > 0:
193-
self.current_libary_context = list(self.library_contexts.values())[-1]
196+
self.current_libary_context = list(
197+
self.library_contexts.values())[-1]
194198
else:
195199
self.current_libary_context = None
196200

@@ -199,8 +203,16 @@ def run_keyword(self, name, args, kwargs):
199203
self._running_keyword = name
200204
try:
201205
return DynamicCore.run_keyword(self, name, args, kwargs)
206+
except robot.errors.TimeoutError:
207+
logger.warn('Test timeout. Force stop puppeteer server')
208+
# Force
209+
self.loop.run_until_complete(
210+
self.get_current_library_context().stop_server())
211+
raise
202212
except Exception:
203-
if name.lower().replace(' ', '_') != 'capture_page_screenshot':
213+
if name.lower().replace(' ', '_') == 'close_puppeteer' or name.lower().replace(' ', '_') == 'open_browser':
214+
logger.warn('Can\'t close puppeteer...')
215+
elif name.lower().replace(' ', '_') != 'capture_page_screenshot':
204216
self.failure_occurred()
205217
raise
206218
finally:
@@ -229,7 +241,3 @@ def _disable_python_logging(self):
229241

230242
def _stop_execution_gracefully(self):
231243
raise ExecutionFailed('Execution terminated by signal', exit=True)
232-
233-
from ._version import get_versions
234-
__version__ = get_versions()['version']
235-
del get_versions

PuppeteerLibrary/keywords/browsermanagement.py

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import os
22
import shutil
3+
from robot.api import logger
34
from PuppeteerLibrary.base.librarycomponent import LibraryComponent
45
from PuppeteerLibrary.base.robotlibcore import keyword
56
from PuppeteerLibrary.ikeywords.ibrowsermanagement_async import iBrowserManagementAsync
@@ -49,12 +50,13 @@ def open_browser(self, url, browser="chrome", alias=None, options={}):
4950
"""
5051
if options is None:
5152
options = {}
52-
53+
5354
self.info(url)
5455
library_context = self.ctx.get_library_context_by_name(alias)
5556
if library_context is None:
5657
library_context = self.ctx.create_library_context(alias, browser)
57-
self.loop.run_until_complete(self.ctx.set_current_library_context(alias))
58+
self.loop.run_until_complete(
59+
self.ctx.set_current_library_context(alias))
5860
self.loop.run_until_complete(library_context.start_server(options))
5961
self.loop.run_until_complete(library_context.create_new_page(options))
6062
self.loop.run_until_complete(self.get_async_keyword_group().go_to(url))
@@ -63,7 +65,8 @@ def open_browser(self, url, browser="chrome", alias=None, options={}):
6365
def close_window(self):
6466
""" Close current browser tab/page
6567
"""
66-
self.loop.run_until_complete(self.ctx.get_current_library_context().close_window())
68+
self.loop.run_until_complete(
69+
self.ctx.get_current_library_context().close_window())
6770

6871
@keyword
6972
def close_browser(self, alias=None):
@@ -78,15 +81,17 @@ def close_browser(self, alias=None):
7881
def close_all_browser(self):
7982
"""Close all browser
8083
"""
81-
library_contexts = self.ctx.get_all_library_context()
84+
library_contexts = self.ctx.get_all_library_context()
8285
for library_context in library_contexts:
83-
self.loop.run_until_complete(library_context.close_browser_context())
86+
self.loop.run_until_complete(
87+
library_context.close_browser_context())
8488

8589
@keyword
8690
def close_puppeteer(self):
8791
library_contexts_dict = self.ctx.get_all_library_context_dict()
8892
for key in list(library_contexts_dict.keys()):
89-
self.loop.run_until_complete(library_contexts_dict[key].stop_server())
93+
self.loop.run_until_complete(
94+
library_contexts_dict[key].stop_server())
9095
self.ctx.remove_library_context(key)
9196

9297
@keyword
@@ -113,13 +118,14 @@ def go_to(self, url):
113118
@keyword
114119
def reload_page(self):
115120
"""Reload the current page"""
116-
self.loop.run_until_complete(self.get_async_keyword_group().reload_page())
121+
self.loop.run_until_complete(
122+
self.get_async_keyword_group().reload_page())
117123

118124
@keyword
119125
def get_window_count(self):
120126
""" Get windows count
121127
"""
122-
return self.loop.run_until_complete(self.get_async_keyword_group().get_window_count())
128+
return self.loop.run_until_complete(self.get_async_keyword_group().get_window_count())
123129

124130
@keyword
125131
def wait_for_new_window_open(self, timeout=None):
@@ -131,7 +137,8 @@ def wait_for_new_window_open(self, timeout=None):
131137
| Run Async Keywords | Click Element | id:view_conditions | AND |
132138
| ... | `Wait For New Window Open` | | |
133139
"""
134-
self.loop.run_until_complete(self.get_async_keyword_group().wait_for_new_window_open(timeout))
140+
self.loop.run_until_complete(
141+
self.get_async_keyword_group().wait_for_new_window_open(timeout))
135142

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

147155
@keyword
148156
def switch_browser(self, alias):
@@ -265,11 +273,12 @@ def delete_browser_storage_state(self, ref):
265273
266274
*Limitation* only support Playwright browser
267275
"""
268-
file_path = self.STATES_FOLDER +'/state-'+ ref + '.json'
276+
file_path = self.STATES_FOLDER + '/state-' + ref + '.json'
269277
if os.path.exists(file_path):
270278
os.remove(file_path)
271279
else:
272-
self.warn('Can not delete the storate '+ref+' as it doesn\'t exists')
280+
self.warn('Can not delete the storate ' +
281+
ref+' as it doesn\'t exists')
273282

274283
@keyword
275284
def delete_all_browser_storage_states(self):
@@ -281,4 +290,3 @@ def delete_all_browser_storage_states(self):
281290
shutil.rmtree(self.STATES_FOLDER)
282291
except OSError as e:
283292
self.warn("Error: %s - %s." % (e.filename, e.strerror))
284-

PuppeteerLibrary/playwright/playwright_context.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import asyncio
2+
from robot.api import logger
23
from PuppeteerLibrary.custom_elements.base_page import BasePage
34
from PuppeteerLibrary.playwright.custom_elements.playwright_page import PlaywrightPage
45
from PuppeteerLibrary.playwright.async_keywords.playwright_checkbox import PlaywrightCheckbox
@@ -75,7 +76,6 @@ async def start_server(self, options: dict = {}):
7576
del merged_options['proxy']
7677
self.browser = await self.playwright.chromium.launch(
7778
headless=merged_options['headless'], proxy=proxy)
78-
merged_options
7979
elif self.browser_type == "webkit":
8080
self.browser = await self.playwright.webkit.launch(
8181
headless=merged_options['headless'])
@@ -85,7 +85,10 @@ async def start_server(self, options: dict = {}):
8585
self.browser.accept_downloads = True
8686

8787
async def stop_server(self):
88-
await self.playwright.stop()
88+
try:
89+
await asyncio.wait_for(self.playwright.stop(), timeout=5.0)
90+
except Exception:
91+
logger.warn('Can\'t stop server properly...')
8992
self._reset_server_context()
9093

9194
def is_server_started(self) -> bool:
@@ -149,7 +152,7 @@ def get_browser_context(self):
149152
async def close_browser_context(self):
150153
if self.browser is not None:
151154
try:
152-
await asyncio.wait_for(self.browser.close(), timeout=3)
155+
await asyncio.wait_for(self.browser.close(), timeout=5)
153156
except asyncio.TimeoutError:
154157
None
155158
self._reset_context()

0 commit comments

Comments
 (0)