Skip to content

Commit b180cc9

Browse files
authored
Add support run async keywords with first complete keywords (#51)
* init asnyc with first result * Add suport run async with first complete * Add demo exception cases * Update wait for page contain element async keywords * Fix missing async error
1 parent e94fa77 commit b180cc9

File tree

5 files changed

+81
-9
lines changed

5 files changed

+81
-9
lines changed

Examples/form-handler/iframe.robot

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,6 @@ ${HOME_PAGE_URL} http://127.0.0.1:7272/basic-html-elements.html
1313
Interact with iframe element
1414
Wait Until Page Contains Element id=ifrm
1515
Select Frame id=ifrm
16-
# Input Text not support iframe
17-
# Input Text id=exampleInputEmail1 demo@qahive.com
18-
# Input Text id=exampleInputPassword1 123456789
1916
Click Element id=exampleCheck1
2017

2118
*** Keywords ***

Examples/utilities/asyncio.robot

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
*** Settings ***
2+
Library PuppeteerLibrary
3+
Test Setup Open browser to test page
4+
Test Teardown Close All Browser
5+
Suite Teardown Close Puppeteer
6+
7+
*** Variables ***
8+
${HOME_PAGE_URL} http://127.0.0.1:7272/basic-html-elements.html
9+
10+
11+
*** Test Cases ***
12+
Run Async Keywords and wait for first completed keyword
13+
${result} = Run Async Keywords And Return First Completed
14+
... Click Element id=non_existing_id AND
15+
... Click Element id=get_ajax
16+
Should Be Equal As Integers 1 ${result}
17+
Run Keyword If ${result} == 0 Log first keyword completed
18+
Run Keyword If ${result} == 1 Log second keyword completed
19+
20+
Ignore error Run Async Keywords and Return First Complete if no keyword success
21+
Run Keyword And Expect Error All async keywords failed* Run Async Keywords And Return First Completed
22+
... Click Element id=non_existing_id AND
23+
... Click Element id=non_existing_id2
24+
25+
*** Keywords ***
26+
Open browser to test page
27+
${HEADLESS} Get variable value ${HEADLESS} ${False}
28+
&{options} = create dictionary headless=${HEADLESS}
29+
Open browser ${HOME_PAGE_URL} options=${options}

PuppeteerLibrary/keywords/utility.py

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,57 @@
66

77
class UtilityKeywords(LibraryComponent):
88

9+
@keyword
10+
def run_async_keywords_and_return_first_completed(self, *keywords):
11+
"""Executes all the given keywords in a asynchronous and wait until first keyword is completed
12+
13+
``Return`` Array of result for each keywords based on index
14+
15+
Example
16+
| `Run Async Keywords And Return First Completed` | Wait for response url | ${HOME_PAGE_URL}/login.html | AND |
17+
| ... | Wait for response url | ${HOME_PAGE_URL}/home.html | |
18+
"""
19+
self.ctx.load_async_keywords()
20+
run_keyword = _RunKeyword()
21+
return self.loop.run_until_complete( self._run_async_keywords_first_completed(run_keyword._split_run_keywords(list(keywords))) )
22+
23+
async def _wrapped_async_keyword_return_index(self, index, future):
24+
await future
25+
return index
26+
27+
async def _run_async_keywords_first_completed(self, iterable):
28+
org_statements = []
29+
index = 0
30+
for kw, args in iterable:
31+
kw_name = kw.lower().replace(' ', '_') + '_async'
32+
org_statements.append(self._wrapped_async_keyword_return_index(index, self.ctx.keywords[kw_name](*args)))
33+
index += 1
34+
statements = org_statements
35+
error_stack_trace = ''
36+
while True:
37+
done, pending = await asyncio.wait(statements, return_when=asyncio.FIRST_COMPLETED)
38+
statements = pending
39+
for future in done:
40+
try:
41+
# Raise an exception if coroutine failed
42+
result_index = future.result()
43+
# Force cancel all pending
44+
for p in pending:
45+
p.cancel()
46+
return result_index
47+
except Exception as e:
48+
error_stack_trace += str(e)+'\n'
49+
continue
50+
if len(pending) == 0:
51+
raise Exception("All async keywords failed \r\n"+ error_stack_trace)
52+
953
@keyword
1054
def run_async_keywords(self, *keywords):
11-
# Ensure that script load async keywords before run async keywords function
1255
"""Executes all the given keywords in a asynchronous and wait until all keyword is completed
1356
14-
``Return`` Array of return for reach keywords based on index
57+
``Return`` Array of result for each keywords based on index
1558
1659
Example:
17-
1860
| Open browser | ${HOME_PAGE_URL} | options=${options} | |
1961
| `Run Async Keywords` | Click Element | id:login_button | AND |
2062
| ... | Wait for response url | ${HOME_PAGE_URL}/home.html | |
@@ -23,7 +65,7 @@ def run_async_keywords(self, *keywords):
2365
self.ctx.load_async_keywords()
2466
run_keyword = _RunKeyword()
2567
return self.loop.run_until_complete( self._run_async_keywords(run_keyword._split_run_keywords(list(keywords))) )
26-
68+
2769
async def _run_async_keywords(self, iterable):
2870
statements = []
2971
for kw, args in iterable:

PuppeteerLibrary/keywords/waiting.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ def wait_until_page_contains_element(self, locator, timeout=None):
100100
| Open browser | ${HOME_PAGE_URL} | options=${options} |
101101
| `Wait Until Page Contains Element` | id:username | |
102102
"""
103-
return self.loop.run_until_complete(self.async_func.wait_for_selenium_selector(locator, timeout))
103+
return self.loop.run_until_complete(self.async_func.wait_until_page_contains_element_async(locator, timeout))
104104

105105
@keyword
106106
def wait_until_element_is_hidden(self, locator, timeout=None):

PuppeteerLibrary/keywords/waiting_async.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,11 @@ async def wait_for_navigation_async(self, timeout=None):
7070
@keyword
7171
async def wait_for_selenium_selector(self, selenium_locator, timeout=None, visible=False, hidden=False):
7272
timeout = self.timestr_to_secs_for_default_timeout(timeout)
73-
await self.ctx.get_current_page().waitForSelector_with_selenium_locator(selenium_locator, timeout, visible, hidden)
73+
return await self.ctx.get_current_page().waitForSelector_with_selenium_locator(selenium_locator, timeout, visible, hidden)
74+
75+
@keyword
76+
async def wait_until_page_contains_element_async(self, selenium_locator, timeout=None):
77+
return await self.wait_for_selenium_selector(selenium_locator, timeout, visible=False, hidden=False)
7478

7579
@keyword
7680
async def wait_until_element_is_hidden_async(self, locator, timeout=None):

0 commit comments

Comments
 (0)