From 96c1e51e8d792ba4fa28b5e81d0999716cab6411 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Fri, 2 Oct 2020 06:54:00 +0700 Subject: [PATCH 001/103] init playwright --- .../playwright-browser.robot | 8 ++++++++ PuppeteerLibrary/__init__.py | 1 + PuppeteerLibrary/ikeywords/__init__.py | 1 + .../ikeywords/ibrowsermanagement.py | 7 +++++++ PuppeteerLibrary/keywords/browsermanagement.py | 18 ++++++++++++++++++ PuppeteerLibrary/playwright/__init__.py | 1 + .../playwright/playwright_browsermanagement.py | 11 +++++++++++ 7 files changed, 47 insertions(+) create mode 100644 Examples/browser-management/playwright-browser.robot create mode 100644 PuppeteerLibrary/ikeywords/__init__.py create mode 100644 PuppeteerLibrary/ikeywords/ibrowsermanagement.py create mode 100644 PuppeteerLibrary/playwright/__init__.py create mode 100644 PuppeteerLibrary/playwright/playwright_browsermanagement.py diff --git a/Examples/browser-management/playwright-browser.robot b/Examples/browser-management/playwright-browser.robot new file mode 100644 index 0000000..8ed1be8 --- /dev/null +++ b/Examples/browser-management/playwright-browser.robot @@ -0,0 +1,8 @@ +*** Settings *** +Library PuppeteerLibrary + +*** Test Cases *** +New open browser + ${HEADLESS} Get variable value ${HEADLESS} ${False} + &{options} = create dictionary headless=${HEADLESS} + New Open Browser http://127.0.0.1:7272/basic-html-elements.html options=${options} diff --git a/PuppeteerLibrary/__init__.py b/PuppeteerLibrary/__init__.py index 4fb582d..395e711 100644 --- a/PuppeteerLibrary/__init__.py +++ b/PuppeteerLibrary/__init__.py @@ -1,6 +1,7 @@ import asyncio from robot.api.deco import not_keyword from robot.api import logger +from playwright import sync_playwright from pyppeteer.browser import Browser, BrowserContext from robot.libraries.BuiltIn import BuiltIn from PuppeteerLibrary.custom_elements.SPage import SPage diff --git a/PuppeteerLibrary/ikeywords/__init__.py b/PuppeteerLibrary/ikeywords/__init__.py new file mode 100644 index 0000000..93ec384 --- /dev/null +++ b/PuppeteerLibrary/ikeywords/__init__.py @@ -0,0 +1 @@ +from .ibrowsermanagement import iBrowserManagement \ No newline at end of file diff --git a/PuppeteerLibrary/ikeywords/ibrowsermanagement.py b/PuppeteerLibrary/ikeywords/ibrowsermanagement.py new file mode 100644 index 0000000..4d86eb0 --- /dev/null +++ b/PuppeteerLibrary/ikeywords/ibrowsermanagement.py @@ -0,0 +1,7 @@ +import abc + +class iBrowserManagement: + + @abc.abstractmethod + async def open_browser(self, url, browser="chrome", alias=None, options=None): + pass diff --git a/PuppeteerLibrary/keywords/browsermanagement.py b/PuppeteerLibrary/keywords/browsermanagement.py index 6667b47..8c1bb74 100644 --- a/PuppeteerLibrary/keywords/browsermanagement.py +++ b/PuppeteerLibrary/keywords/browsermanagement.py @@ -6,12 +6,30 @@ from PuppeteerLibrary.base.robotlibcore import keyword from PuppeteerLibrary.keywords.browsermanagement_async import BrowserManagementKeywordsAsync +# from playwright import sync_playwright +# from PuppeteerLibrary.playwright.playwright_browsermanagement import PlaywrightBrowserManagement class BrowserManagementKeywords(LibraryComponent): def __init__(self, ctx): super().__init__(ctx) self.async_func = BrowserManagementKeywordsAsync(self.ctx) + # self.playwright = PlaywrightBrowserManagement() + + @keyword + def new_open_browser(self, url, browser="chrome", alias=None, options=None): + if browser == "chrome": + print('') + # playwright = sync_playwright().start() + # web_browser = playwright.webkit.launch(headless=False) + # page = web_browser.newPage() + # page.goto("http://whatsmyuseragent.org/") + # self.loop.run_until_complete(self.playwright.open_browser(url, browser, alias, options)) + else: + print('') + + # def new_close_browser(self): + # self.async_func.close_browser() @keyword def open_browser(self, url, browser="chrome", alias=None, options=None): diff --git a/PuppeteerLibrary/playwright/__init__.py b/PuppeteerLibrary/playwright/__init__.py new file mode 100644 index 0000000..31c3eb1 --- /dev/null +++ b/PuppeteerLibrary/playwright/__init__.py @@ -0,0 +1 @@ +from .playwright_browsermanagement import PlaywrightBrowserManagement \ No newline at end of file diff --git a/PuppeteerLibrary/playwright/playwright_browsermanagement.py b/PuppeteerLibrary/playwright/playwright_browsermanagement.py new file mode 100644 index 0000000..be3beab --- /dev/null +++ b/PuppeteerLibrary/playwright/playwright_browsermanagement.py @@ -0,0 +1,11 @@ +from PuppeteerLibrary.ikeywords.ibrowsermanagement import iBrowserManagement +from playwright import sync_playwright + +class PlaywrightBrowserManagement(iBrowserManagement): + + async def open_browser(self, url, browser="chrome", alias=None, options=None): + playwright = sync_playwright().start() + web_browser = playwright.webkit.launch() + page = web_browser.newPage() + await page.goto("http://whatsmyuseragent.org/") + From 9e06b302d0683571a3420e0c2441266f11d35fe7 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Sun, 4 Oct 2020 12:06:07 +0700 Subject: [PATCH 002/103] Add playwright --- requirements.txt | 1 + setup.py | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 833876f..01ee5e0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,4 +2,5 @@ versioneer>=0.18 robotframework>=3.2.1 # pyppeteer>=0.2.2 git+https://github.com/qahive/pyppeteer.git@dev +playwright==0.142.1 robotframework-libdoc2json>=0.4 \ No newline at end of file diff --git a/setup.py b/setup.py index 38ace87..083c0af 100644 --- a/setup.py +++ b/setup.py @@ -39,7 +39,8 @@ platforms='any', install_requires=[ 'robotframework>=3.2.1', - 'pyppeteer>=0.2.2' + 'pyppeteer>=0.2.2', + 'playwright>=0.142.1' ], # python_requires='>3.5', # test_suite='nose.collector', From 61a4f564b2715eb3b7d4634e51d2db75d17b184c Mon Sep 17 00:00:00 2001 From: atthaboons Date: Mon, 5 Oct 2020 06:48:05 +0700 Subject: [PATCH 003/103] init puppeteer_browsermanagement --- .../playwright-browser.robot | 8 --- Examples/webkit/playwright-browser.robot | 12 ++++ PuppeteerLibrary/__init__.py | 10 +++- PuppeteerLibrary/iasync_keywords/__init__.py | 1 + .../ibrowsermanagement_async.py | 23 ++++++++ PuppeteerLibrary/ikeywords/__init__.py | 1 - .../ikeywords/ibrowsermanagement.py | 7 --- .../keywords/browsermanagement.py | 23 +++----- PuppeteerLibrary/playwright/__init__.py | 2 +- .../playwright/async_keywords/__init__.py | 1 + .../playwright_browsermanagement.py | 44 ++++++++++++++ .../playwright_browsermanagement.py | 11 ---- PuppeteerLibrary/puppeteer/__init__.py | 0 .../puppeteer/async_keywords/__init__.py | 1 + .../puppeteer_browsermanagement.py | 58 +++++++++++++++++++ 15 files changed, 158 insertions(+), 44 deletions(-) delete mode 100644 Examples/browser-management/playwright-browser.robot create mode 100644 Examples/webkit/playwright-browser.robot create mode 100644 PuppeteerLibrary/iasync_keywords/__init__.py create mode 100644 PuppeteerLibrary/iasync_keywords/ibrowsermanagement_async.py delete mode 100644 PuppeteerLibrary/ikeywords/__init__.py delete mode 100644 PuppeteerLibrary/ikeywords/ibrowsermanagement.py create mode 100644 PuppeteerLibrary/playwright/async_keywords/__init__.py create mode 100644 PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py delete mode 100644 PuppeteerLibrary/playwright/playwright_browsermanagement.py create mode 100644 PuppeteerLibrary/puppeteer/__init__.py create mode 100644 PuppeteerLibrary/puppeteer/async_keywords/__init__.py create mode 100644 PuppeteerLibrary/puppeteer/async_keywords/puppeteer_browsermanagement.py diff --git a/Examples/browser-management/playwright-browser.robot b/Examples/browser-management/playwright-browser.robot deleted file mode 100644 index 8ed1be8..0000000 --- a/Examples/browser-management/playwright-browser.robot +++ /dev/null @@ -1,8 +0,0 @@ -*** Settings *** -Library PuppeteerLibrary - -*** Test Cases *** -New open browser - ${HEADLESS} Get variable value ${HEADLESS} ${False} - &{options} = create dictionary headless=${HEADLESS} - New Open Browser http://127.0.0.1:7272/basic-html-elements.html options=${options} diff --git a/Examples/webkit/playwright-browser.robot b/Examples/webkit/playwright-browser.robot new file mode 100644 index 0000000..ce8c059 --- /dev/null +++ b/Examples/webkit/playwright-browser.robot @@ -0,0 +1,12 @@ +*** Settings *** +Library PuppeteerLibrary +Library Dialogs + +*** Test Cases *** +New open browser + ${HEADLESS} Get variable value ${HEADLESS} ${False} + &{options} = create dictionary headless=${HEADLESS} + New Open Browser https://www.google.com options=${options} + Dialogs.Pause Execution + # New Open Browser http://127.0.0.1:7272/basic-html-elements.html options=${options} + # Open Browser http://127.0.0.1:7272/basic-html-elements.html options=${options} diff --git a/PuppeteerLibrary/__init__.py b/PuppeteerLibrary/__init__.py index 395e711..d3bc114 100644 --- a/PuppeteerLibrary/__init__.py +++ b/PuppeteerLibrary/__init__.py @@ -1,7 +1,6 @@ import asyncio from robot.api.deco import not_keyword from robot.api import logger -from playwright import sync_playwright from pyppeteer.browser import Browser, BrowserContext from robot.libraries.BuiltIn import BuiltIn from PuppeteerLibrary.custom_elements.SPage import SPage @@ -153,6 +152,15 @@ def clear_browser(self): self.clear_current_iframe() @not_keyword + async def add_context_async(self, alias, browser_context): + if alias in self.contexts.keys(): + await self.contexts[alias].close() + del self.contexts[alias] + self.current_context_name = alias + self.contexts[self.current_context_name] = browser_context + + @not_keyword + # Will obsolted async def create_context_async(self, alias) -> BrowserContext: context = await self.browser.createIncognitoBrowserContext() if alias in self.contexts.keys(): diff --git a/PuppeteerLibrary/iasync_keywords/__init__.py b/PuppeteerLibrary/iasync_keywords/__init__.py new file mode 100644 index 0000000..a62403a --- /dev/null +++ b/PuppeteerLibrary/iasync_keywords/__init__.py @@ -0,0 +1 @@ +from .ibrowsermanagement_async import iBrowserManagementAsync \ No newline at end of file diff --git a/PuppeteerLibrary/iasync_keywords/ibrowsermanagement_async.py b/PuppeteerLibrary/iasync_keywords/ibrowsermanagement_async.py new file mode 100644 index 0000000..654e817 --- /dev/null +++ b/PuppeteerLibrary/iasync_keywords/ibrowsermanagement_async.py @@ -0,0 +1,23 @@ +import abc + +class iBrowserManagementAsync: + + @abc.abstractmethod + async def start_server_async(self, browser="chrome", options: dict = None, **kwargs: any): + pass + + @abc.abstractmethod + async def open_browser_async(self, url, browser="chrome", alias = None, options = None): + pass + + @abc.abstractmethod + async def close_browser_async(self, alias=None): + pass + + @abc.abstractmethod + async def close_all_browser_async(self): + pass + + @abc.abstractmethod + async def close_puppeteer_async(self): + pass diff --git a/PuppeteerLibrary/ikeywords/__init__.py b/PuppeteerLibrary/ikeywords/__init__.py deleted file mode 100644 index 93ec384..0000000 --- a/PuppeteerLibrary/ikeywords/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .ibrowsermanagement import iBrowserManagement \ No newline at end of file diff --git a/PuppeteerLibrary/ikeywords/ibrowsermanagement.py b/PuppeteerLibrary/ikeywords/ibrowsermanagement.py deleted file mode 100644 index 4d86eb0..0000000 --- a/PuppeteerLibrary/ikeywords/ibrowsermanagement.py +++ /dev/null @@ -1,7 +0,0 @@ -import abc - -class iBrowserManagement: - - @abc.abstractmethod - async def open_browser(self, url, browser="chrome", alias=None, options=None): - pass diff --git a/PuppeteerLibrary/keywords/browsermanagement.py b/PuppeteerLibrary/keywords/browsermanagement.py index 8c1bb74..b722306 100644 --- a/PuppeteerLibrary/keywords/browsermanagement.py +++ b/PuppeteerLibrary/keywords/browsermanagement.py @@ -6,30 +6,23 @@ from PuppeteerLibrary.base.robotlibcore import keyword from PuppeteerLibrary.keywords.browsermanagement_async import BrowserManagementKeywordsAsync -# from playwright import sync_playwright -# from PuppeteerLibrary.playwright.playwright_browsermanagement import PlaywrightBrowserManagement +from PuppeteerLibrary.puppeteer.async_keywords.puppeteer_browsermanagement import PuppeteerBrowserManagement +from PuppeteerLibrary.playwright.async_keywords.playwright_browsermanagement import PlaywrightBrowserManagement + class BrowserManagementKeywords(LibraryComponent): def __init__(self, ctx): super().__init__(ctx) self.async_func = BrowserManagementKeywordsAsync(self.ctx) - # self.playwright = PlaywrightBrowserManagement() + + self.playwright = PlaywrightBrowserManagement() + self.puppeteer = PuppeteerBrowserManagement(self.ctx) + self.browserManagement = self.puppeteer @keyword def new_open_browser(self, url, browser="chrome", alias=None, options=None): - if browser == "chrome": - print('') - # playwright = sync_playwright().start() - # web_browser = playwright.webkit.launch(headless=False) - # page = web_browser.newPage() - # page.goto("http://whatsmyuseragent.org/") - # self.loop.run_until_complete(self.playwright.open_browser(url, browser, alias, options)) - else: - print('') - - # def new_close_browser(self): - # self.async_func.close_browser() + return self.loop.run_until_complete(self.browserManagement.open_browser_async(url, browser, alias, options)) @keyword def open_browser(self, url, browser="chrome", alias=None, options=None): diff --git a/PuppeteerLibrary/playwright/__init__.py b/PuppeteerLibrary/playwright/__init__.py index 31c3eb1..3294d71 100644 --- a/PuppeteerLibrary/playwright/__init__.py +++ b/PuppeteerLibrary/playwright/__init__.py @@ -1 +1 @@ -from .playwright_browsermanagement import PlaywrightBrowserManagement \ No newline at end of file +# Just for notify python that this is library folder for searching for diff --git a/PuppeteerLibrary/playwright/async_keywords/__init__.py b/PuppeteerLibrary/playwright/async_keywords/__init__.py new file mode 100644 index 0000000..31c3eb1 --- /dev/null +++ b/PuppeteerLibrary/playwright/async_keywords/__init__.py @@ -0,0 +1 @@ +from .playwright_browsermanagement import PlaywrightBrowserManagement \ No newline at end of file diff --git a/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py b/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py new file mode 100644 index 0000000..dd47109 --- /dev/null +++ b/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py @@ -0,0 +1,44 @@ +from PuppeteerLibrary.iasync_keywords import iBrowserManagementAsync +try: + from playwright import async_playwright +except ImportError: + print('import playwright error') + +class PlaywrightBrowserManagement(iBrowserManagementAsync): + + async def start_server_async(self, browser, options: dict=None, **kwargs: any): + playwright = await async_playwright().start() + self.browser = await playwright.webkit.launch(headless=False) + return self.browser + + async def open_browser_async(self, url, browser, alias=None, options=None): + page = await self.browser.newPage() + await page.goto(url) + + """ + iphone_11 = p.devices['iPhone 11 Pro'] + browser = p.webkit.launch(headless=False) + context = browser.newContext( + **iphone_11, + locale='en-US', + geolocation={ 'longitude': 12.492507, 'latitude': 41.889938 }, + permissions=['geolocation'] + ) + page = context.newPage() + page.goto('https://maps.google.com') + page.click('text="Your location"') + page.screenshot(path='colosseum-iphone.png') + browser.close() + --------------------------------------------------------------------- + playwright = await async_playwright().start() + web_browser = await playwright.webkit.launch(headless=False) + page = await web_browser.newPage() + await page.goto("http://whatsmyuseragent.org/") + """ + + + async def close_browser_async(self, alias=None): + pass + + async def close_all_browser_async(self): + pass diff --git a/PuppeteerLibrary/playwright/playwright_browsermanagement.py b/PuppeteerLibrary/playwright/playwright_browsermanagement.py deleted file mode 100644 index be3beab..0000000 --- a/PuppeteerLibrary/playwright/playwright_browsermanagement.py +++ /dev/null @@ -1,11 +0,0 @@ -from PuppeteerLibrary.ikeywords.ibrowsermanagement import iBrowserManagement -from playwright import sync_playwright - -class PlaywrightBrowserManagement(iBrowserManagement): - - async def open_browser(self, url, browser="chrome", alias=None, options=None): - playwright = sync_playwright().start() - web_browser = playwright.webkit.launch() - page = web_browser.newPage() - await page.goto("http://whatsmyuseragent.org/") - diff --git a/PuppeteerLibrary/puppeteer/__init__.py b/PuppeteerLibrary/puppeteer/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/PuppeteerLibrary/puppeteer/async_keywords/__init__.py b/PuppeteerLibrary/puppeteer/async_keywords/__init__.py new file mode 100644 index 0000000..0a8411f --- /dev/null +++ b/PuppeteerLibrary/puppeteer/async_keywords/__init__.py @@ -0,0 +1 @@ +from .puppeteer_browsermanagement import PuppeteerBrowserManagement \ No newline at end of file diff --git a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_browsermanagement.py b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_browsermanagement.py new file mode 100644 index 0000000..88734c2 --- /dev/null +++ b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_browsermanagement.py @@ -0,0 +1,58 @@ +import sys +from pyppeteer import launch +from PuppeteerLibrary.base.librarycomponent import LibraryComponent +from PuppeteerLibrary.iasync_keywords import iBrowserManagementAsync +from PuppeteerLibrary.custom_elements.SPage import SPage + + +class PuppeteerBrowserManagement(LibraryComponent): + + async def create_page_async(self) -> SPage: + new_page = await self.ctx.get_current_context().newPage() + self.ctx.set_current_page(new_page) + return self.ctx.get_current_page() + + async def open_browser_async(self, url, browser, alias=None, options=None): + if self.ctx.browser is None: + default_args = [] + default_options = { + 'slowMo': 0, + 'headless': True, + 'devtools': False, + 'width': 1366, + 'height': 768 + } + merged_options = default_options + + if options is not None: + merged_options = {**merged_options, **options} + + if self.ctx.debug_mode is True: + merged_options = {**merged_options, + **self.ctx.debug_mode_options} + + if 'win' not in sys.platform.lower(): + default_args = ['--no-sandbox', '--disable-setuid-sandbox'] + + self.info(('Open browser to ' + url + '\n' + str(merged_options))) + self.browser = await launch( + headless=merged_options['headless'], + slowMo=merged_options['slowMo'], + devtools=merged_options['devtools'], + defaultViewport={ + 'width': merged_options['width'], + 'height': merged_options['height'] + }, + args=default_args) + + browser_context = await self.browser.createIncognitoBrowserContext() + await self.ctx.add_context_async(alias, browser_context) + current_page = await self.create_page_async() + await current_page.goto(url) + await current_page.screenshot({'path': 'example.png'}) + + async def close_browser_async(self, alias=None): + pass + + async def close_all_browser_async(self): + pass From 2b41b67f68a1046d9c4895e2a1372cbb8cd08bbb Mon Sep 17 00:00:00 2001 From: atthaboons Date: Mon, 5 Oct 2020 06:59:31 +0700 Subject: [PATCH 004/103] Update browser management --- .../ibrowsermanagement_async.py | 35 +++++++------ .../keywords/browsermanagement.py | 2 +- .../playwright_browsermanagement.py | 49 ++++++------------- 3 files changed, 35 insertions(+), 51 deletions(-) diff --git a/PuppeteerLibrary/iasync_keywords/ibrowsermanagement_async.py b/PuppeteerLibrary/iasync_keywords/ibrowsermanagement_async.py index 654e817..6b1e9dd 100644 --- a/PuppeteerLibrary/iasync_keywords/ibrowsermanagement_async.py +++ b/PuppeteerLibrary/iasync_keywords/ibrowsermanagement_async.py @@ -1,23 +1,26 @@ import abc +from PuppeteerLibrary.base.librarycomponent import LibraryComponent +from PuppeteerLibrary.base.robotlibcore import keyword -class iBrowserManagementAsync: - @abc.abstractmethod - async def start_server_async(self, browser="chrome", options: dict = None, **kwargs: any): - pass +class iBrowserManagementAsync(LibraryComponent): - @abc.abstractmethod - async def open_browser_async(self, url, browser="chrome", alias = None, options = None): - pass + @keyword + @abc.abstractmethod + async def open_browser_async(self, url, browser="chrome", alias=None, options=None): + pass - @abc.abstractmethod - async def close_browser_async(self, alias=None): - pass + @keyword + @abc.abstractmethod + async def close_browser_async(self, alias=None): + pass - @abc.abstractmethod - async def close_all_browser_async(self): - pass + @keyword + @abc.abstractmethod + async def close_all_browser_async(self): + pass - @abc.abstractmethod - async def close_puppeteer_async(self): - pass + @keyword + @abc.abstractmethod + async def close_puppeteer_async(self): + pass diff --git a/PuppeteerLibrary/keywords/browsermanagement.py b/PuppeteerLibrary/keywords/browsermanagement.py index b722306..e7d94e9 100644 --- a/PuppeteerLibrary/keywords/browsermanagement.py +++ b/PuppeteerLibrary/keywords/browsermanagement.py @@ -16,7 +16,7 @@ def __init__(self, ctx): super().__init__(ctx) self.async_func = BrowserManagementKeywordsAsync(self.ctx) - self.playwright = PlaywrightBrowserManagement() + self.playwright = PlaywrightBrowserManagement(self.ctx) self.puppeteer = PuppeteerBrowserManagement(self.ctx) self.browserManagement = self.puppeteer diff --git a/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py b/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py index dd47109..fb669fd 100644 --- a/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py +++ b/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py @@ -1,44 +1,25 @@ -from PuppeteerLibrary.iasync_keywords import iBrowserManagementAsync +from PuppeteerLibrary.base.librarycomponent import LibraryComponent try: from playwright import async_playwright except ImportError: print('import playwright error') -class PlaywrightBrowserManagement(iBrowserManagementAsync): - async def start_server_async(self, browser, options: dict=None, **kwargs: any): - playwright = await async_playwright().start() - self.browser = await playwright.webkit.launch(headless=False) - return self.browser +class PlaywrightBrowserManagement(LibraryComponent): - async def open_browser_async(self, url, browser, alias=None, options=None): - page = await self.browser.newPage() - await page.goto(url) + async def start_server_async(self, browser, options: dict = None): + playwright = await async_playwright().start() + self.browser = await playwright.webkit.launch(headless=False) + return self.browser - """ - iphone_11 = p.devices['iPhone 11 Pro'] - browser = p.webkit.launch(headless=False) - context = browser.newContext( - **iphone_11, - locale='en-US', - geolocation={ 'longitude': 12.492507, 'latitude': 41.889938 }, - permissions=['geolocation'] - ) - page = context.newPage() - page.goto('https://maps.google.com') - page.click('text="Your location"') - page.screenshot(path='colosseum-iphone.png') - browser.close() - --------------------------------------------------------------------- - playwright = await async_playwright().start() - web_browser = await playwright.webkit.launch(headless=False) - page = await web_browser.newPage() - await page.goto("http://whatsmyuseragent.org/") - """ - + async def open_browser_async(self, url, browser, alias=None, options=None): + if self.ctx.browser is None: + self.start_server_async(browser, options) + page = await self.browser.newPage() + await page.goto(url) - async def close_browser_async(self, alias=None): - pass + async def close_browser_async(self, alias=None): + pass - async def close_all_browser_async(self): - pass + async def close_all_browser_async(self): + pass From 7a8153d56d539d939eb47d68a35670743d98bc78 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Sat, 10 Oct 2020 15:10:37 +0700 Subject: [PATCH 005/103] init get webkit context --- Examples/webkit/playwright-browser.robot | 4 +- PuppeteerLibrary/__init__.py | 30 +++++++- PuppeteerLibrary/base/context.py | 3 + PuppeteerLibrary/base/ipuppeteer_library.py | 10 +++ PuppeteerLibrary/iasync_keywords/__init__.py | 1 - PuppeteerLibrary/keywords/__init__.py | 1 + .../keywords/browsermanagement.py | 7 +- .../ibrowsermanagement_async.py | 17 ++--- PuppeteerLibrary/library_context/__init__.py | 1 + .../library_context/ilibrary_context.py | 22 ++++++ .../library_context_factory.py | 19 +++++ .../playwright_browsermanagement.py | 26 ++++--- .../playwright/playwright_context.py | 42 +++++++++++ .../puppeteer_browsermanagement.py | 31 +++++--- .../puppeteer/puppeteer_context.py | 70 +++++++++++++++++++ 15 files changed, 245 insertions(+), 39 deletions(-) create mode 100644 PuppeteerLibrary/base/ipuppeteer_library.py delete mode 100644 PuppeteerLibrary/iasync_keywords/__init__.py rename PuppeteerLibrary/{iasync_keywords => keywords}/ibrowsermanagement_async.py (57%) create mode 100644 PuppeteerLibrary/library_context/__init__.py create mode 100644 PuppeteerLibrary/library_context/ilibrary_context.py create mode 100644 PuppeteerLibrary/library_context/library_context_factory.py create mode 100644 PuppeteerLibrary/playwright/playwright_context.py create mode 100644 PuppeteerLibrary/puppeteer/puppeteer_context.py diff --git a/Examples/webkit/playwright-browser.robot b/Examples/webkit/playwright-browser.robot index ce8c059..4b429ce 100644 --- a/Examples/webkit/playwright-browser.robot +++ b/Examples/webkit/playwright-browser.robot @@ -6,7 +6,7 @@ Library Dialogs New open browser ${HEADLESS} Get variable value ${HEADLESS} ${False} &{options} = create dictionary headless=${HEADLESS} - New Open Browser https://www.google.com options=${options} - Dialogs.Pause Execution + New Open Browser https://www.google.com browser=webkit options=${options} + Dialogs.Pause Execution # New Open Browser http://127.0.0.1:7272/basic-html-elements.html options=${options} # Open Browser http://127.0.0.1:7272/basic-html-elements.html options=${options} diff --git a/PuppeteerLibrary/__init__.py b/PuppeteerLibrary/__init__.py index d3bc114..32f0045 100644 --- a/PuppeteerLibrary/__init__.py +++ b/PuppeteerLibrary/__init__.py @@ -1,8 +1,11 @@ +from PuppeteerLibrary.base.ipuppeteer_library import iPuppeteerLibrary import asyncio from robot.api.deco import not_keyword from robot.api import logger -from pyppeteer.browser import Browser, BrowserContext from robot.libraries.BuiltIn import BuiltIn +from pyppeteer.browser import Browser, BrowserContext +from PuppeteerLibrary.library_context.ilibrary_context import iLibraryContext +from PuppeteerLibrary.library_context.library_context_factory import LibraryContextFactory from PuppeteerLibrary.custom_elements.SPage import SPage from PuppeteerLibrary.base.robotlibcore import DynamicCore from PuppeteerLibrary.keywords import ( @@ -38,7 +41,7 @@ del get_versions -class PuppeteerLibrary(DynamicCore): +class PuppeteerLibrary(DynamicCore, iPuppeteerLibrary): """PuppeteerLibrary is a web testing library for Robot Framework. PuppeteerLibrary uses the pyppeteer library internally to control a web browser. @@ -83,7 +86,10 @@ class PuppeteerLibrary(DynamicCore): async_libraries = [] browser = None - contexts = {} + puppeteer_browser: iLibraryContext = None + playwright_browser: iLibraryContext = None + + # contexts = {} current_context_name = None current_page = None current_iframe = None @@ -94,6 +100,14 @@ class PuppeteerLibrary(DynamicCore): 'devtools': False } + # new context + library_factory: LibraryContextFactory = None + library_contexts: dict = { + 'chrome': None, + 'webkit': None, + 'firefox': None + } + def __init__(self): try: self.loop = asyncio.get_event_loop() @@ -132,6 +146,8 @@ def __init__(self): WaitingKeywordsAsync(self) ] + self.library_factory = LibraryContextFactory() + @not_keyword def load_async_keywords(self): if self.is_load_async_keywords is True: @@ -139,6 +155,14 @@ def load_async_keywords(self): self.add_library_components(self.async_libraries) self.is_load_async_keywords = True + @not_keyword + def get_library_context(self, browser_type: str) -> iLibraryContext: + library_context = self.library_contexts[browser_type] + if library_context is None: + library_context = self.library_factory.create(browser_type) + self.library_contexts[browser_type] = library_context + return library_context + @not_keyword def get_browser(self) -> Browser: return self.browser diff --git a/PuppeteerLibrary/base/context.py b/PuppeteerLibrary/base/context.py index 87675a1..201ba78 100644 --- a/PuppeteerLibrary/base/context.py +++ b/PuppeteerLibrary/base/context.py @@ -1,8 +1,11 @@ + +from PuppeteerLibrary.base.ipuppeteer_library import iPuppeteerLibrary import asyncio class ContextAware(object): loop = None + ctx: iPuppeteerLibrary = None def __init__(self, ctx): """Base class exposing attributes from the common context. diff --git a/PuppeteerLibrary/base/ipuppeteer_library.py b/PuppeteerLibrary/base/ipuppeteer_library.py new file mode 100644 index 0000000..638e96b --- /dev/null +++ b/PuppeteerLibrary/base/ipuppeteer_library.py @@ -0,0 +1,10 @@ +from PuppeteerLibrary.library_context.ilibrary_context import iLibraryContext +from abc import ABC, abstractmethod + +class iPuppeteerLibrary(ABC): + + @abstractmethod + def get_library_context(self, browser_type: str) -> iLibraryContext: + pass + + diff --git a/PuppeteerLibrary/iasync_keywords/__init__.py b/PuppeteerLibrary/iasync_keywords/__init__.py deleted file mode 100644 index a62403a..0000000 --- a/PuppeteerLibrary/iasync_keywords/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .ibrowsermanagement_async import iBrowserManagementAsync \ No newline at end of file diff --git a/PuppeteerLibrary/keywords/__init__.py b/PuppeteerLibrary/keywords/__init__.py index 61037cf..cafb81c 100644 --- a/PuppeteerLibrary/keywords/__init__.py +++ b/PuppeteerLibrary/keywords/__init__.py @@ -8,6 +8,7 @@ from .element_async import ElementKeywordsAsync from .formelement import FormElementKeywords from .formelement_async import FormElementKeywordsAsync +from .ibrowsermanagement_async import iBrowserManagementAsync from .javascript import JavascriptKeywords from .javascript_async import JavascriptKeywordsAsync from .mockresponse import MockResponseKeywords diff --git a/PuppeteerLibrary/keywords/browsermanagement.py b/PuppeteerLibrary/keywords/browsermanagement.py index e7d94e9..5ca8ea1 100644 --- a/PuppeteerLibrary/keywords/browsermanagement.py +++ b/PuppeteerLibrary/keywords/browsermanagement.py @@ -5,7 +5,6 @@ from PuppeteerLibrary.base.librarycomponent import LibraryComponent from PuppeteerLibrary.base.robotlibcore import keyword from PuppeteerLibrary.keywords.browsermanagement_async import BrowserManagementKeywordsAsync - from PuppeteerLibrary.puppeteer.async_keywords.puppeteer_browsermanagement import PuppeteerBrowserManagement from PuppeteerLibrary.playwright.async_keywords.playwright_browsermanagement import PlaywrightBrowserManagement @@ -18,10 +17,14 @@ def __init__(self, ctx): self.playwright = PlaywrightBrowserManagement(self.ctx) self.puppeteer = PuppeteerBrowserManagement(self.ctx) - self.browserManagement = self.puppeteer + self.browserManagement = self.playwright @keyword def new_open_browser(self, url, browser="chrome", alias=None, options=None): + library_context = self.ctx.get_library_context(browser) + if library_context.is_server_started is False: + self.loop.run_until_complete(library_context.start_server()) + return self.loop.run_until_complete(self.browserManagement.open_browser_async(url, browser, alias, options)) @keyword diff --git a/PuppeteerLibrary/iasync_keywords/ibrowsermanagement_async.py b/PuppeteerLibrary/keywords/ibrowsermanagement_async.py similarity index 57% rename from PuppeteerLibrary/iasync_keywords/ibrowsermanagement_async.py rename to PuppeteerLibrary/keywords/ibrowsermanagement_async.py index 6b1e9dd..2a0acd5 100644 --- a/PuppeteerLibrary/iasync_keywords/ibrowsermanagement_async.py +++ b/PuppeteerLibrary/keywords/ibrowsermanagement_async.py @@ -1,26 +1,21 @@ -import abc +from abc import ABC, abstractmethod from PuppeteerLibrary.base.librarycomponent import LibraryComponent -from PuppeteerLibrary.base.robotlibcore import keyword -class iBrowserManagementAsync(LibraryComponent): +class iBrowserManagementAsync(LibraryComponent, ABC): - @keyword - @abc.abstractmethod + @abstractmethod async def open_browser_async(self, url, browser="chrome", alias=None, options=None): pass - @keyword - @abc.abstractmethod + @abstractmethod async def close_browser_async(self, alias=None): pass - @keyword - @abc.abstractmethod + @abstractmethod async def close_all_browser_async(self): pass - @keyword - @abc.abstractmethod + @abstractmethod async def close_puppeteer_async(self): pass diff --git a/PuppeteerLibrary/library_context/__init__.py b/PuppeteerLibrary/library_context/__init__.py new file mode 100644 index 0000000..d9f802f --- /dev/null +++ b/PuppeteerLibrary/library_context/__init__.py @@ -0,0 +1 @@ +from .ilibrary_context import iLibraryContext \ No newline at end of file diff --git a/PuppeteerLibrary/library_context/ilibrary_context.py b/PuppeteerLibrary/library_context/ilibrary_context.py new file mode 100644 index 0000000..99d4405 --- /dev/null +++ b/PuppeteerLibrary/library_context/ilibrary_context.py @@ -0,0 +1,22 @@ +from abc import ABC, abstractmethod + + +class iLibraryContext(ABC): + + browser_type: str = None + + def __init__(self, browser_type: str): + self.browser_type = browser_type + + @abstractmethod + async def start_server(self, options: dict=None): + pass + + @abstractmethod + async def stop_server(self): + pass + + @abstractmethod + def is_server_started(self) -> bool: + pass + diff --git a/PuppeteerLibrary/library_context/library_context_factory.py b/PuppeteerLibrary/library_context/library_context_factory.py new file mode 100644 index 0000000..a396eb9 --- /dev/null +++ b/PuppeteerLibrary/library_context/library_context_factory.py @@ -0,0 +1,19 @@ +from .ilibrary_context import iLibraryContext +from PuppeteerLibrary.puppeteer.puppeteer_context import PuppeteerContext +from PuppeteerLibrary.playwright.playwright_context import PlaywrightContext + +class LibraryContextFactory: + + def create(self, browser_type: str) -> iLibraryContext: + """Return iLibraryContext based on specific browser_type + + Create context based on browser type (chrome, safari, webkit) + """ + if browser_type.lower() == 'chrome': + return PuppeteerContext(browser_type) + elif browser_type.lower() == 'safari': + return PlaywrightContext(browser_type) + elif browser_type.lower() == 'webkit': + return PlaywrightContext(browser_type) + else: + raise Exception('Sorry, not supported for library type '+str(browser_type)+'.') diff --git a/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py b/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py index fb669fd..7819b89 100644 --- a/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py +++ b/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py @@ -1,21 +1,22 @@ -from PuppeteerLibrary.base.librarycomponent import LibraryComponent +from PuppeteerLibrary.keywords.ibrowsermanagement_async import iBrowserManagementAsync +from PuppeteerLibrary.custom_elements.SPage import SPage try: from playwright import async_playwright except ImportError: print('import playwright error') -class PlaywrightBrowserManagement(LibraryComponent): +class PlaywrightBrowserManagement(iBrowserManagementAsync): - async def start_server_async(self, browser, options: dict = None): - playwright = await async_playwright().start() - self.browser = await playwright.webkit.launch(headless=False) - return self.browser + def __init__(self, ctx): + super().__init__(ctx) async def open_browser_async(self, url, browser, alias=None, options=None): - if self.ctx.browser is None: - self.start_server_async(browser, options) - page = await self.browser.newPage() + if self.ctx.playwright_browser is None: + playwright = await async_playwright().start() + self.ctx.playwright_browser = await playwright.webkit.launch(headless=False) + # page = await self.browser.newPage() + page = await self._create_page_async() await page.goto(url) async def close_browser_async(self, alias=None): @@ -23,3 +24,10 @@ async def close_browser_async(self, alias=None): async def close_all_browser_async(self): pass + + async def close_puppeteer_async(self): + pass + + async def _create_page_async(self): + new_page = await self.ctx.playwright_browser.newPage() + return new_page diff --git a/PuppeteerLibrary/playwright/playwright_context.py b/PuppeteerLibrary/playwright/playwright_context.py new file mode 100644 index 0000000..189fb41 --- /dev/null +++ b/PuppeteerLibrary/playwright/playwright_context.py @@ -0,0 +1,42 @@ +from PuppeteerLibrary.library_context.ilibrary_context import iLibraryContext +try: + from playwright import async_playwright + from playwright.playwright import Playwright as AsyncPlaywright + from playwright.browser import Browser +except ImportError: + print('import playwright error') + + +class PlaywrightContext(iLibraryContext): + + playwright: any = None + browser: any = None + contexts = {} + current_page = None + current_iframe = None + + def __init__(self, browser_type: str): + super().__init__(browser_type) + + async def start_server(self, options: dict=None): + self.playwright = await async_playwright().start() + if self.browser_type == "webkit": + self.browser = await self.playwright.webkit.launch(headless=False) + elif self.browser_type == "firefox": + self.browser = await self.playwright.firefox.launch(headless=False) + + async def stop_server(self): + await self.playwright.stop() + self._reset_context() + + def is_server_started(self) -> bool: + if self.browser is not None: + return True + return False + + def _reset_context(self): + playwright = None + browser = None + contexts = {} + current_page = None + current_iframe = None diff --git a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_browsermanagement.py b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_browsermanagement.py index 88734c2..4ab0560 100644 --- a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_browsermanagement.py +++ b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_browsermanagement.py @@ -1,19 +1,21 @@ import sys from pyppeteer import launch -from PuppeteerLibrary.base.librarycomponent import LibraryComponent -from PuppeteerLibrary.iasync_keywords import iBrowserManagementAsync +from PuppeteerLibrary.library_context.library_context_factory import LibraryContextFactory +from PuppeteerLibrary.keywords.ibrowsermanagement_async import iBrowserManagementAsync from PuppeteerLibrary.custom_elements.SPage import SPage -class PuppeteerBrowserManagement(LibraryComponent): +class PuppeteerBrowserManagement(iBrowserManagementAsync): - async def create_page_async(self) -> SPage: - new_page = await self.ctx.get_current_context().newPage() - self.ctx.set_current_page(new_page) - return self.ctx.get_current_page() + def __init__(self, ctx): + super().__init__(ctx) + self.libraryContextFactory = LibraryContextFactory() async def open_browser_async(self, url, browser, alias=None, options=None): - if self.ctx.browser is None: + self.ctx.get_library_context(browser) + libraryContext = self.libraryContextFactory.create(browser) + + if self.ctx.puppeteer_browser is None: default_args = [] default_options = { 'slowMo': 0, @@ -35,7 +37,7 @@ async def open_browser_async(self, url, browser, alias=None, options=None): default_args = ['--no-sandbox', '--disable-setuid-sandbox'] self.info(('Open browser to ' + url + '\n' + str(merged_options))) - self.browser = await launch( + self.puppeteer_browser = await launch( headless=merged_options['headless'], slowMo=merged_options['slowMo'], devtools=merged_options['devtools'], @@ -47,12 +49,19 @@ async def open_browser_async(self, url, browser, alias=None, options=None): browser_context = await self.browser.createIncognitoBrowserContext() await self.ctx.add_context_async(alias, browser_context) - current_page = await self.create_page_async() + current_page = await self._create_page_async() await current_page.goto(url) - await current_page.screenshot({'path': 'example.png'}) async def close_browser_async(self, alias=None): pass async def close_all_browser_async(self): pass + + async def close_puppeteer_async(self): + pass + + async def _create_page_async(self) -> SPage: + new_page = await self.ctx.get_current_context().newPage() + self.ctx.set_current_page(new_page) + return self.ctx.get_current_page() diff --git a/PuppeteerLibrary/puppeteer/puppeteer_context.py b/PuppeteerLibrary/puppeteer/puppeteer_context.py new file mode 100644 index 0000000..3fb39de --- /dev/null +++ b/PuppeteerLibrary/puppeteer/puppeteer_context.py @@ -0,0 +1,70 @@ +import sys +from pyppeteer import launch +from pyppeteer.browser import Browser +from PuppeteerLibrary.library_context.ilibrary_context import iLibraryContext + +class PuppeteerContext(iLibraryContext): + + browser: Browser = None + contexts = {} + current_page = None + current_iframe = None + + debug_mode: bool = False + debug_mode_options: dict = { + 'slowMo': 200, + 'devtools': False + } + + def __init__(self, browser_type: str): + super().__init__(browser_type) + + async def start_server(self, options: dict=None): + default_args = [] + default_options = { + 'slowMo': 0, + 'headless': True, + 'devtools': False, + 'width': 1366, + 'height': 768 + } + merged_options = default_options + + if options is not None: + merged_options = {**merged_options, **options} + + if self.debug_mode is True: + merged_options = {**merged_options, **self.debug_mode_options} + + if 'win' not in sys.platform.lower(): + default_args = ['--no-sandbox', '--disable-setuid-sandbox'] + + self.browser = await launch( + headless=merged_options['headless'], + slowMo=merged_options['slowMo'], + devtools=merged_options['devtools'], + defaultViewport={ + 'width': merged_options['width'], + 'height': merged_options['height'] + }, + args=default_args) + + async def stop_server(self): + await self.browser.close() + self._reset_context() + + def is_server_started(self) -> bool: + if self.browser is not None: + return True + return False + + def _reset_context(self): + browser = None + contexts = {} + current_page = None + current_iframe = None + debug_mode = False + debug_mode_options = { + 'slowMo': 200, + 'devtools': False + } From 1c4c53896f2087e074767fc38eac79fcc131e604 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Sat, 10 Oct 2020 16:14:03 +0700 Subject: [PATCH 006/103] init playwright new page --- PuppeteerLibrary/__init__.py | 14 +++++++------- PuppeteerLibrary/keywords/browsermanagement.py | 5 ++--- .../library_context/ilibrary_context.py | 3 +++ .../async_keywords/playwright_browsermanagement.py | 3 +++ PuppeteerLibrary/playwright/playwright_context.py | 6 ++++++ 5 files changed, 21 insertions(+), 10 deletions(-) diff --git a/PuppeteerLibrary/__init__.py b/PuppeteerLibrary/__init__.py index 32f0045..10260a7 100644 --- a/PuppeteerLibrary/__init__.py +++ b/PuppeteerLibrary/__init__.py @@ -148,13 +148,6 @@ def __init__(self): self.library_factory = LibraryContextFactory() - @not_keyword - def load_async_keywords(self): - if self.is_load_async_keywords is True: - return - self.add_library_components(self.async_libraries) - self.is_load_async_keywords = True - @not_keyword def get_library_context(self, browser_type: str) -> iLibraryContext: library_context = self.library_contexts[browser_type] @@ -163,6 +156,13 @@ def get_library_context(self, browser_type: str) -> iLibraryContext: self.library_contexts[browser_type] = library_context return library_context + @not_keyword + def load_async_keywords(self): + if self.is_load_async_keywords is True: + return + self.add_library_components(self.async_libraries) + self.is_load_async_keywords = True + @not_keyword def get_browser(self) -> Browser: return self.browser diff --git a/PuppeteerLibrary/keywords/browsermanagement.py b/PuppeteerLibrary/keywords/browsermanagement.py index 5ca8ea1..2de4c59 100644 --- a/PuppeteerLibrary/keywords/browsermanagement.py +++ b/PuppeteerLibrary/keywords/browsermanagement.py @@ -22,9 +22,8 @@ def __init__(self, ctx): @keyword def new_open_browser(self, url, browser="chrome", alias=None, options=None): library_context = self.ctx.get_library_context(browser) - if library_context.is_server_started is False: - self.loop.run_until_complete(library_context.start_server()) - + if library_context.is_server_started() is False: + self.loop.run_until_complete(library_context.start_server(options)) return self.loop.run_until_complete(self.browserManagement.open_browser_async(url, browser, alias, options)) @keyword diff --git a/PuppeteerLibrary/library_context/ilibrary_context.py b/PuppeteerLibrary/library_context/ilibrary_context.py index 99d4405..cc9c217 100644 --- a/PuppeteerLibrary/library_context/ilibrary_context.py +++ b/PuppeteerLibrary/library_context/ilibrary_context.py @@ -20,3 +20,6 @@ async def stop_server(self): def is_server_started(self) -> bool: pass + @abstractmethod + async def create_new_page(self, options: dict=None): + pass diff --git a/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py b/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py index 7819b89..71c9d15 100644 --- a/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py +++ b/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py @@ -12,11 +12,14 @@ def __init__(self, ctx): super().__init__(ctx) async def open_browser_async(self, url, browser, alias=None, options=None): + ''' if self.ctx.playwright_browser is None: playwright = await async_playwright().start() self.ctx.playwright_browser = await playwright.webkit.launch(headless=False) # page = await self.browser.newPage() page = await self._create_page_async() + ''' + page = await self.ctx.get_library_context(browser).create_new_page() await page.goto(url) async def close_browser_async(self, alias=None): diff --git a/PuppeteerLibrary/playwright/playwright_context.py b/PuppeteerLibrary/playwright/playwright_context.py index 189fb41..d12a1d5 100644 --- a/PuppeteerLibrary/playwright/playwright_context.py +++ b/PuppeteerLibrary/playwright/playwright_context.py @@ -34,9 +34,15 @@ def is_server_started(self) -> bool: return True return False + async def create_new_page(self, options: dict=None): + self.current_page = await self.browser.newPage() + return self.current_page + def _reset_context(self): playwright = None browser = None contexts = {} current_page = None current_iframe = None + + \ No newline at end of file From 676d97415fe121e855318657de1d85004d0dcdfb Mon Sep 17 00:00:00 2001 From: atthaboons Date: Sun, 11 Oct 2020 10:50:37 +0700 Subject: [PATCH 007/103] Update craete browser with alias --- Examples/webkit/playwright-browser.robot | 6 ++++- PuppeteerLibrary/__init__.py | 20 ++++++++-------- PuppeteerLibrary/base/ipuppeteer_library.py | 6 +++-- .../keywords/browsermanagement.py | 24 ++++++++++--------- .../library_context/ilibrary_context.py | 4 ++++ .../playwright_browsermanagement.py | 11 --------- .../playwright/playwright_context.py | 7 ++++++ .../puppeteer_browsermanagement.py | 4 ---- .../puppeteer/puppeteer_context.py | 10 +++++++- 9 files changed, 52 insertions(+), 40 deletions(-) diff --git a/Examples/webkit/playwright-browser.robot b/Examples/webkit/playwright-browser.robot index 4b429ce..bf6ff69 100644 --- a/Examples/webkit/playwright-browser.robot +++ b/Examples/webkit/playwright-browser.robot @@ -6,7 +6,11 @@ Library Dialogs New open browser ${HEADLESS} Get variable value ${HEADLESS} ${False} &{options} = create dictionary headless=${HEADLESS} - New Open Browser https://www.google.com browser=webkit options=${options} + New Open Browser https://www.google.com browser=webkit alias=B1 options=${options} + + New Open Browser https://www.google.com browser=webkit alias=B2 options=${options} Dialogs.Pause Execution + # New Close All Browser + # New Open Browser http://127.0.0.1:7272/basic-html-elements.html options=${options} # Open Browser http://127.0.0.1:7272/basic-html-elements.html options=${options} diff --git a/PuppeteerLibrary/__init__.py b/PuppeteerLibrary/__init__.py index 10260a7..ca687db 100644 --- a/PuppeteerLibrary/__init__.py +++ b/PuppeteerLibrary/__init__.py @@ -101,12 +101,9 @@ class PuppeteerLibrary(DynamicCore, iPuppeteerLibrary): } # new context + current_libary_context: iLibraryContext = None library_factory: LibraryContextFactory = None - library_contexts: dict = { - 'chrome': None, - 'webkit': None, - 'firefox': None - } + library_contexts: dict = {} def __init__(self): try: @@ -149,11 +146,14 @@ def __init__(self): self.library_factory = LibraryContextFactory() @not_keyword - def get_library_context(self, browser_type: str) -> iLibraryContext: - library_context = self.library_contexts[browser_type] - if library_context is None: - library_context = self.library_factory.create(browser_type) - self.library_contexts[browser_type] = library_context + def get_current_library_context(self) -> iLibraryContext: + return self.current_libary_context + + @not_keyword + def create_library_context(self, alias: str, browser_type: str) -> iLibraryContext: + library_context = self.library_factory.create(browser_type) + self.library_contexts[alias] = library_context + self.current_libary_context = library_context return library_context @not_keyword diff --git a/PuppeteerLibrary/base/ipuppeteer_library.py b/PuppeteerLibrary/base/ipuppeteer_library.py index 638e96b..7cbf240 100644 --- a/PuppeteerLibrary/base/ipuppeteer_library.py +++ b/PuppeteerLibrary/base/ipuppeteer_library.py @@ -4,7 +4,9 @@ class iPuppeteerLibrary(ABC): @abstractmethod - def get_library_context(self, browser_type: str) -> iLibraryContext: + def get_current_library_context(self) -> iLibraryContext: pass - + @abstractmethod + def create_library_context(self,alias: str, browser_type: str) -> iLibraryContext: + pass diff --git a/PuppeteerLibrary/keywords/browsermanagement.py b/PuppeteerLibrary/keywords/browsermanagement.py index 2de4c59..eb06695 100644 --- a/PuppeteerLibrary/keywords/browsermanagement.py +++ b/PuppeteerLibrary/keywords/browsermanagement.py @@ -1,3 +1,4 @@ +from PuppeteerLibrary.keywords.ibrowsermanagement_async import iBrowserManagementAsync import re import sys from robot.utils import timestr_to_secs @@ -5,26 +6,27 @@ from PuppeteerLibrary.base.librarycomponent import LibraryComponent from PuppeteerLibrary.base.robotlibcore import keyword from PuppeteerLibrary.keywords.browsermanagement_async import BrowserManagementKeywordsAsync -from PuppeteerLibrary.puppeteer.async_keywords.puppeteer_browsermanagement import PuppeteerBrowserManagement -from PuppeteerLibrary.playwright.async_keywords.playwright_browsermanagement import PlaywrightBrowserManagement - class BrowserManagementKeywords(LibraryComponent): def __init__(self, ctx): super().__init__(ctx) self.async_func = BrowserManagementKeywordsAsync(self.ctx) - - self.playwright = PlaywrightBrowserManagement(self.ctx) - self.puppeteer = PuppeteerBrowserManagement(self.ctx) - self.browserManagement = self.playwright + + def get_async_keyword_group(self) -> iBrowserManagementAsync: + return self.ctx.get_current_library_context().get_async_keyword_group(type(self).__name__) @keyword def new_open_browser(self, url, browser="chrome", alias=None, options=None): - library_context = self.ctx.get_library_context(browser) - if library_context.is_server_started() is False: - self.loop.run_until_complete(library_context.start_server(options)) - return self.loop.run_until_complete(self.browserManagement.open_browser_async(url, browser, alias, options)) + library_context = self.ctx.create_library_context(alias, browser) + self.loop.run_until_complete(library_context.start_server(options)) + return self.loop.run_until_complete(library_context.create_new_page(options)) + + @keyword + def new_close_all_browser(self): + """Close all browser + """ + self.loop.run_until_complete(self.get_async_keyword_group().close_all_browser_async()) @keyword def open_browser(self, url, browser="chrome", alias=None, options=None): diff --git a/PuppeteerLibrary/library_context/ilibrary_context.py b/PuppeteerLibrary/library_context/ilibrary_context.py index cc9c217..062bfe2 100644 --- a/PuppeteerLibrary/library_context/ilibrary_context.py +++ b/PuppeteerLibrary/library_context/ilibrary_context.py @@ -23,3 +23,7 @@ def is_server_started(self) -> bool: @abstractmethod async def create_new_page(self, options: dict=None): pass + + @abstractmethod + async def get_async_keyword_group(self, keyword_group_name: str): + pass diff --git a/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py b/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py index 71c9d15..1264bb7 100644 --- a/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py +++ b/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py @@ -12,13 +12,6 @@ def __init__(self, ctx): super().__init__(ctx) async def open_browser_async(self, url, browser, alias=None, options=None): - ''' - if self.ctx.playwright_browser is None: - playwright = await async_playwright().start() - self.ctx.playwright_browser = await playwright.webkit.launch(headless=False) - # page = await self.browser.newPage() - page = await self._create_page_async() - ''' page = await self.ctx.get_library_context(browser).create_new_page() await page.goto(url) @@ -30,7 +23,3 @@ async def close_all_browser_async(self): async def close_puppeteer_async(self): pass - - async def _create_page_async(self): - new_page = await self.ctx.playwright_browser.newPage() - return new_page diff --git a/PuppeteerLibrary/playwright/playwright_context.py b/PuppeteerLibrary/playwright/playwright_context.py index d12a1d5..2565ee0 100644 --- a/PuppeteerLibrary/playwright/playwright_context.py +++ b/PuppeteerLibrary/playwright/playwright_context.py @@ -1,3 +1,4 @@ +from PuppeteerLibrary.playwright.async_keywords.playwright_browsermanagement import PlaywrightBrowserManagement from PuppeteerLibrary.library_context.ilibrary_context import iLibraryContext try: from playwright import async_playwright @@ -38,6 +39,12 @@ async def create_new_page(self, options: dict=None): self.current_page = await self.browser.newPage() return self.current_page + async def get_async_keyword_group(self, keyword_group_name: str): + switcher = { + "BrowserManagementKeywords": PlaywrightBrowserManagement(self) + } + return switcher.get(keyword_group_name) + def _reset_context(self): playwright = None browser = None diff --git a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_browsermanagement.py b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_browsermanagement.py index 4ab0560..05448f4 100644 --- a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_browsermanagement.py +++ b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_browsermanagement.py @@ -1,6 +1,5 @@ import sys from pyppeteer import launch -from PuppeteerLibrary.library_context.library_context_factory import LibraryContextFactory from PuppeteerLibrary.keywords.ibrowsermanagement_async import iBrowserManagementAsync from PuppeteerLibrary.custom_elements.SPage import SPage @@ -9,12 +8,9 @@ class PuppeteerBrowserManagement(iBrowserManagementAsync): def __init__(self, ctx): super().__init__(ctx) - self.libraryContextFactory = LibraryContextFactory() async def open_browser_async(self, url, browser, alias=None, options=None): self.ctx.get_library_context(browser) - libraryContext = self.libraryContextFactory.create(browser) - if self.ctx.puppeteer_browser is None: default_args = [] default_options = { diff --git a/PuppeteerLibrary/puppeteer/puppeteer_context.py b/PuppeteerLibrary/puppeteer/puppeteer_context.py index 3fb39de..62e4617 100644 --- a/PuppeteerLibrary/puppeteer/puppeteer_context.py +++ b/PuppeteerLibrary/puppeteer/puppeteer_context.py @@ -2,8 +2,10 @@ from pyppeteer import launch from pyppeteer.browser import Browser from PuppeteerLibrary.library_context.ilibrary_context import iLibraryContext +from PuppeteerLibrary.puppeteer.async_keywords.puppeteer_browsermanagement import PuppeteerBrowserManagement -class PuppeteerContext(iLibraryContext): +# class PuppeteerContext(iLibraryContext): +class PuppeteerContext: browser: Browser = None contexts = {} @@ -58,6 +60,12 @@ def is_server_started(self) -> bool: return True return False + async def get_async_keyword_group(self, keyword_group_name: str): + switcher = { + "BrowserManagementKeywords": PuppeteerBrowserManagement(self) + } + return switcher.get(keyword_group_name) + def _reset_context(self): browser = None contexts = {} From 3b1cde6b95cd52a9e23903630240e679340b8f7d Mon Sep 17 00:00:00 2001 From: atthaboons Date: Sun, 11 Oct 2020 12:13:11 +0700 Subject: [PATCH 008/103] Add close browser and puppeteer --- Examples/webkit/playwright-browser.robot | 4 ++-- PuppeteerLibrary/__init__.py | 9 +++++++++ PuppeteerLibrary/base/ipuppeteer_library.py | 9 +++++++++ .../keywords/browsermanagement.py | 19 ++++++++++++++++++- .../library_context/ilibrary_context.py | 4 ++++ .../playwright/playwright_context.py | 19 ++++++++++++------- 6 files changed, 54 insertions(+), 10 deletions(-) diff --git a/Examples/webkit/playwright-browser.robot b/Examples/webkit/playwright-browser.robot index bf6ff69..fd6d32f 100644 --- a/Examples/webkit/playwright-browser.robot +++ b/Examples/webkit/playwright-browser.robot @@ -7,10 +7,10 @@ New open browser ${HEADLESS} Get variable value ${HEADLESS} ${False} &{options} = create dictionary headless=${HEADLESS} New Open Browser https://www.google.com browser=webkit alias=B1 options=${options} - - New Open Browser https://www.google.com browser=webkit alias=B2 options=${options} Dialogs.Pause Execution + New Close Browser # New Close All Browser + New Close Puppeteer # New Open Browser http://127.0.0.1:7272/basic-html-elements.html options=${options} # Open Browser http://127.0.0.1:7272/basic-html-elements.html options=${options} diff --git a/PuppeteerLibrary/__init__.py b/PuppeteerLibrary/__init__.py index ca687db..9aca91d 100644 --- a/PuppeteerLibrary/__init__.py +++ b/PuppeteerLibrary/__init__.py @@ -1,3 +1,4 @@ +from typing import List from PuppeteerLibrary.base.ipuppeteer_library import iPuppeteerLibrary import asyncio from robot.api.deco import not_keyword @@ -149,6 +150,14 @@ def __init__(self): def get_current_library_context(self) -> iLibraryContext: return self.current_libary_context + @not_keyword + def get_library_context_by_name(self, alias: str) -> iLibraryContext: + return self.library_contexts[alias] + + @not_keyword + def get_all_library_context(self) -> List[iLibraryContext]: + return list(self.library_contexts.values()) + @not_keyword def create_library_context(self, alias: str, browser_type: str) -> iLibraryContext: library_context = self.library_factory.create(browser_type) diff --git a/PuppeteerLibrary/base/ipuppeteer_library.py b/PuppeteerLibrary/base/ipuppeteer_library.py index 7cbf240..4a020c8 100644 --- a/PuppeteerLibrary/base/ipuppeteer_library.py +++ b/PuppeteerLibrary/base/ipuppeteer_library.py @@ -1,3 +1,4 @@ +from typing import List from PuppeteerLibrary.library_context.ilibrary_context import iLibraryContext from abc import ABC, abstractmethod @@ -7,6 +8,14 @@ class iPuppeteerLibrary(ABC): def get_current_library_context(self) -> iLibraryContext: pass + @abstractmethod + def get_library_context_by_name(self, alias: str) -> iLibraryContext: + pass + + @abstractmethod + def get_all_library_context(self) -> List[iLibraryContext]: + pass + @abstractmethod def create_library_context(self,alias: str, browser_type: str) -> iLibraryContext: pass diff --git a/PuppeteerLibrary/keywords/browsermanagement.py b/PuppeteerLibrary/keywords/browsermanagement.py index eb06695..44071ec 100644 --- a/PuppeteerLibrary/keywords/browsermanagement.py +++ b/PuppeteerLibrary/keywords/browsermanagement.py @@ -22,11 +22,28 @@ def new_open_browser(self, url, browser="chrome", alias=None, options=None): self.loop.run_until_complete(library_context.start_server(options)) return self.loop.run_until_complete(library_context.create_new_page(options)) + @keyword + def new_close_browser(self, alias=None): + """Closes the current browser + """ + library_context = self.ctx.get_current_library_context() + if alias is not None: + library_context = self.ctx.get_library_context_by_name(alias) + self.loop.run_until_complete(library_context.close_browser_context()) + @keyword def new_close_all_browser(self): """Close all browser """ - self.loop.run_until_complete(self.get_async_keyword_group().close_all_browser_async()) + library_contexts = self.ctx.get_all_library_context() + for library_context in library_contexts: + self.loop.run_until_complete(library_context.close_browser_context()) + + @keyword + def new_close_puppeteer(self): + library_contexts = self.ctx.get_all_library_context() + for library_context in library_contexts: + self.loop.run_until_complete(library_context.stop_server()) @keyword def open_browser(self, url, browser="chrome", alias=None, options=None): diff --git a/PuppeteerLibrary/library_context/ilibrary_context.py b/PuppeteerLibrary/library_context/ilibrary_context.py index 062bfe2..fa962e0 100644 --- a/PuppeteerLibrary/library_context/ilibrary_context.py +++ b/PuppeteerLibrary/library_context/ilibrary_context.py @@ -24,6 +24,10 @@ def is_server_started(self) -> bool: async def create_new_page(self, options: dict=None): pass + @abstractmethod + async def close_browser_context(self): + pass + @abstractmethod async def get_async_keyword_group(self, keyword_group_name: str): pass diff --git a/PuppeteerLibrary/playwright/playwright_context.py b/PuppeteerLibrary/playwright/playwright_context.py index 2565ee0..34794c0 100644 --- a/PuppeteerLibrary/playwright/playwright_context.py +++ b/PuppeteerLibrary/playwright/playwright_context.py @@ -12,7 +12,6 @@ class PlaywrightContext(iLibraryContext): playwright: any = None browser: any = None - contexts = {} current_page = None current_iframe = None @@ -28,7 +27,7 @@ async def start_server(self, options: dict=None): async def stop_server(self): await self.playwright.stop() - self._reset_context() + self._reset_server_context() def is_server_started(self) -> bool: if self.browser is not None: @@ -39,6 +38,10 @@ async def create_new_page(self, options: dict=None): self.current_page = await self.browser.newPage() return self.current_page + async def close_browser_context(self): + await self.browser.close() + self._reset_context() + async def get_async_keyword_group(self, keyword_group_name: str): switcher = { "BrowserManagementKeywords": PlaywrightBrowserManagement(self) @@ -46,10 +49,12 @@ async def get_async_keyword_group(self, keyword_group_name: str): return switcher.get(keyword_group_name) def _reset_context(self): - playwright = None - browser = None - contexts = {} - current_page = None - current_iframe = None + self.browser = None + self.current_page = None + self.current_iframe = None + + def _reset_server_context(self): + self._reset_context() + self.playwright = None \ No newline at end of file From 7c43fca129a64a6ef3e3b3613a65363f5836deeb Mon Sep 17 00:00:00 2001 From: atthaboons Date: Sun, 11 Oct 2020 13:42:18 +0700 Subject: [PATCH 009/103] Add support goto keyword --- Examples/webkit/playwright-browser.robot | 10 +++------- .../keywords/browsermanagement.py | 7 +++---- .../keywords/ibrowsermanagement_async.py | 14 +------------ .../library_context/ilibrary_context.py | 6 +++++- .../playwright_browsermanagement.py | 20 ++++++++----------- .../playwright/playwright_context.py | 5 ++++- 6 files changed, 24 insertions(+), 38 deletions(-) diff --git a/Examples/webkit/playwright-browser.robot b/Examples/webkit/playwright-browser.robot index fd6d32f..a16e11c 100644 --- a/Examples/webkit/playwright-browser.robot +++ b/Examples/webkit/playwright-browser.robot @@ -4,13 +4,9 @@ Library Dialogs *** Test Cases *** New open browser + [Teardown] New Close Puppeteer ${HEADLESS} Get variable value ${HEADLESS} ${False} &{options} = create dictionary headless=${HEADLESS} New Open Browser https://www.google.com browser=webkit alias=B1 options=${options} - Dialogs.Pause Execution - New Close Browser - # New Close All Browser - New Close Puppeteer - - # New Open Browser http://127.0.0.1:7272/basic-html-elements.html options=${options} - # Open Browser http://127.0.0.1:7272/basic-html-elements.html options=${options} + Go To https://www.youtube.com + New Close Browser diff --git a/PuppeteerLibrary/keywords/browsermanagement.py b/PuppeteerLibrary/keywords/browsermanagement.py index 44071ec..4275dac 100644 --- a/PuppeteerLibrary/keywords/browsermanagement.py +++ b/PuppeteerLibrary/keywords/browsermanagement.py @@ -20,7 +20,8 @@ def get_async_keyword_group(self) -> iBrowserManagementAsync: def new_open_browser(self, url, browser="chrome", alias=None, options=None): library_context = self.ctx.create_library_context(alias, browser) self.loop.run_until_complete(library_context.start_server(options)) - return self.loop.run_until_complete(library_context.create_new_page(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)) @keyword def new_close_browser(self, alias=None): @@ -159,9 +160,7 @@ async def go_back_async(): @keyword def go_to(self, url): """Navigates the current page to the ``url``""" - async def go_to_async(): - await self.ctx.get_current_page().goto(url) - self.loop.run_until_complete(go_to_async()) + self.loop.run_until_complete(self.get_async_keyword_group().go_to(url)) @keyword def reload_page(self): diff --git a/PuppeteerLibrary/keywords/ibrowsermanagement_async.py b/PuppeteerLibrary/keywords/ibrowsermanagement_async.py index 2a0acd5..0abee41 100644 --- a/PuppeteerLibrary/keywords/ibrowsermanagement_async.py +++ b/PuppeteerLibrary/keywords/ibrowsermanagement_async.py @@ -5,17 +5,5 @@ class iBrowserManagementAsync(LibraryComponent, ABC): @abstractmethod - async def open_browser_async(self, url, browser="chrome", alias=None, options=None): - pass - - @abstractmethod - async def close_browser_async(self, alias=None): - pass - - @abstractmethod - async def close_all_browser_async(self): - pass - - @abstractmethod - async def close_puppeteer_async(self): + async def go_to(self, url): pass diff --git a/PuppeteerLibrary/library_context/ilibrary_context.py b/PuppeteerLibrary/library_context/ilibrary_context.py index fa962e0..e7d7599 100644 --- a/PuppeteerLibrary/library_context/ilibrary_context.py +++ b/PuppeteerLibrary/library_context/ilibrary_context.py @@ -24,10 +24,14 @@ def is_server_started(self) -> bool: async def create_new_page(self, options: dict=None): pass + @abstractmethod + def get_current_page(self): + pass + @abstractmethod async def close_browser_context(self): pass @abstractmethod - async def get_async_keyword_group(self, keyword_group_name: str): + def get_async_keyword_group(self, keyword_group_name: str): pass diff --git a/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py b/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py index 1264bb7..927f9d8 100644 --- a/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py +++ b/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py @@ -11,15 +11,11 @@ class PlaywrightBrowserManagement(iBrowserManagementAsync): def __init__(self, ctx): super().__init__(ctx) - async def open_browser_async(self, url, browser, alias=None, options=None): - page = await self.ctx.get_library_context(browser).create_new_page() - await page.goto(url) - - async def close_browser_async(self, alias=None): - pass - - async def close_all_browser_async(self): - pass - - async def close_puppeteer_async(self): - pass + async def go_to(self, url): + return await self.ctx.get_current_page().goto(url) + + ''' + async def go_to_async(): + await self.ctx.get_current_page().goto(url) + self.loop.run_until_complete(go_to_async()) + ''' diff --git a/PuppeteerLibrary/playwright/playwright_context.py b/PuppeteerLibrary/playwright/playwright_context.py index 34794c0..8764c51 100644 --- a/PuppeteerLibrary/playwright/playwright_context.py +++ b/PuppeteerLibrary/playwright/playwright_context.py @@ -38,11 +38,14 @@ async def create_new_page(self, options: dict=None): self.current_page = await self.browser.newPage() return self.current_page + def get_current_page(self): + return self.current_page + async def close_browser_context(self): await self.browser.close() self._reset_context() - async def get_async_keyword_group(self, keyword_group_name: str): + def get_async_keyword_group(self, keyword_group_name: str): switcher = { "BrowserManagementKeywords": PlaywrightBrowserManagement(self) } From 2c96cdc2badd9595483f40340852803c69257c79 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Sun, 11 Oct 2020 13:55:11 +0700 Subject: [PATCH 010/103] clean up --- .../async_keywords/playwright_browsermanagement.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py b/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py index 927f9d8..70f46b1 100644 --- a/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py +++ b/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py @@ -13,9 +13,3 @@ def __init__(self, ctx): async def go_to(self, url): return await self.ctx.get_current_page().goto(url) - - ''' - async def go_to_async(): - await self.ctx.get_current_page().goto(url) - self.loop.run_until_complete(go_to_async()) - ''' From c98f8c3e222ae44af99b480251789c8d97055b97 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Mon, 12 Oct 2020 17:21:47 +0700 Subject: [PATCH 011/103] Fix support call async keyword --- Examples/webkit/playwright-browser.robot | 5 ++++- PuppeteerLibrary/keywords/utility.py | 18 ++++++++++++++++-- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/Examples/webkit/playwright-browser.robot b/Examples/webkit/playwright-browser.robot index a16e11c..2c06f18 100644 --- a/Examples/webkit/playwright-browser.robot +++ b/Examples/webkit/playwright-browser.robot @@ -8,5 +8,8 @@ New open browser ${HEADLESS} Get variable value ${HEADLESS} ${False} &{options} = create dictionary headless=${HEADLESS} New Open Browser https://www.google.com browser=webkit alias=B1 options=${options} - Go To https://www.youtube.com + # Go To https://www.youtube.com + Run Async Keywords + ... Go To https://www.youtube.com AND + ... Go To https://www.youtube.com New Close Browser diff --git a/PuppeteerLibrary/keywords/utility.py b/PuppeteerLibrary/keywords/utility.py index 980f2a9..a484e1b 100644 --- a/PuppeteerLibrary/keywords/utility.py +++ b/PuppeteerLibrary/keywords/utility.py @@ -1,4 +1,7 @@ import asyncio +import inspect +from PuppeteerLibrary.keywords.browsermanagement import BrowserManagementKeywords +from PuppeteerLibrary.playwright.async_keywords.playwright_browsermanagement import PlaywrightBrowserManagement from robot.libraries.BuiltIn import _RunKeyword from PuppeteerLibrary.base.librarycomponent import LibraryComponent from PuppeteerLibrary.base.robotlibcore import keyword @@ -64,8 +67,19 @@ def run_async_keywords(self, *keywords): """ self.ctx.load_async_keywords() run_keyword = _RunKeyword() - return self.loop.run_until_complete( self._run_async_keywords(run_keyword._split_run_keywords(list(keywords))) ) - + return self.loop.run_until_complete( self._new_run_async_keywords(run_keyword._split_run_keywords(list(keywords))) ) + + async def _new_run_async_keywords(self, iterable): + statements = [] + for kw, args in iterable: + kw_name = kw.lower().replace(' ', '_') + async_keywords = self.ctx.keywords[kw_name].__self__.get_async_keyword_group() + statements.append(getattr(async_keywords, kw_name)(*args)) + try: + return await asyncio.gather(*statements) + except Exception as err: + raise Exception(err) + async def _run_async_keywords(self, iterable): statements = [] for kw, args in iterable: From 6cf8d109b16163bce95937ca29ff3511f98d30f6 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Tue, 13 Oct 2020 14:59:42 +0700 Subject: [PATCH 012/103] Create based keywords async class --- Examples/webkit/playwright-browser.robot | 8 ++--- .../keywords/base_async_keywords.py | 23 +++++++++++++ .../keywords/browsermanagement.py | 17 ++++++---- .../keywords/ibrowsermanagement_async.py | 22 +++++++++++-- .../library_context/ilibrary_context.py | 1 + .../playwright_browsermanagement.py | 32 +++++++++++++++++-- .../playwright/playwright_context.py | 1 + .../puppeteer_browsermanagement.py | 20 ++++++------ 8 files changed, 98 insertions(+), 26 deletions(-) create mode 100644 PuppeteerLibrary/keywords/base_async_keywords.py diff --git a/Examples/webkit/playwright-browser.robot b/Examples/webkit/playwright-browser.robot index 2c06f18..289c1a5 100644 --- a/Examples/webkit/playwright-browser.robot +++ b/Examples/webkit/playwright-browser.robot @@ -8,8 +8,8 @@ New open browser ${HEADLESS} Get variable value ${HEADLESS} ${False} &{options} = create dictionary headless=${HEADLESS} New Open Browser https://www.google.com browser=webkit alias=B1 options=${options} - # Go To https://www.youtube.com - Run Async Keywords - ... Go To https://www.youtube.com AND - ... Go To https://www.youtube.com + Go To https://www.youtube.com + # Run Async Keywords + # ... Go To https://www.youtube.com AND + # ... Go To https://www.youtube.com New Close Browser diff --git a/PuppeteerLibrary/keywords/base_async_keywords.py b/PuppeteerLibrary/keywords/base_async_keywords.py new file mode 100644 index 0000000..3615200 --- /dev/null +++ b/PuppeteerLibrary/keywords/base_async_keywords.py @@ -0,0 +1,23 @@ +from robot.api import logger +from robot.utils import timestr_to_secs +from PuppeteerLibrary.library_context.ilibrary_context import iLibraryContext + + +class BaseAsyncKeywords: + + def __init__(self, library_ctx: iLibraryContext): + self.library_ctx = library_ctx + + def info(self, msg, html=False): + logger.info(msg, html) + + def debug(self, msg, html=False): + logger.debug(msg, html) + + def warn(self, msg, html=False): + logger.warn(msg, html) + + def timestr_to_secs_for_default_timeout(self, timeout): + if timeout is None or timeout == '': + timeout = self.ctx.timeout + return timestr_to_secs(timeout) diff --git a/PuppeteerLibrary/keywords/browsermanagement.py b/PuppeteerLibrary/keywords/browsermanagement.py index 4275dac..4a3a601 100644 --- a/PuppeteerLibrary/keywords/browsermanagement.py +++ b/PuppeteerLibrary/keywords/browsermanagement.py @@ -131,12 +131,15 @@ def maximize_browser_window(self, width=1366, height=768): """ self.info(('width: ' + str(width) + '\n' + 'height: ' + str(height))) + self.loop.run_until_complete(self.get_async_keyword_group().maximize_browser_window(width, height)) + ''' async def maximize_browser_window_async(): await self.ctx.get_current_page().setViewport({ 'width': width, 'height': height }) self.loop.run_until_complete(maximize_browser_window_async()) + ''' @keyword def get_title(self): @@ -153,9 +156,7 @@ def get_location(self): @keyword def go_back(self): """Simulate browser go back""" - async def go_back_async(): - await self.ctx.get_current_page().goBack() - self.loop.run_until_complete(go_back_async()) + self.loop.run_until_complete(self.get_async_keyword_group().go_back()) @keyword def go_to(self, url): @@ -165,9 +166,10 @@ def go_to(self, url): @keyword def reload_page(self): """Reload the current page""" - async def reload_page_async(): - await self.ctx.get_current_page().reload() - self.loop.run_until_complete(reload_page_async()) + self.loop.run_until_complete(self.get_async_keyword_group().reload_page()) + # async def reload_page_async(): + # await self.ctx.get_current_page().reload() + # self.loop.run_until_complete(reload_page_async()) @keyword def set_timeout(self, timeout): @@ -192,7 +194,8 @@ def set_timeout(self, timeout): def get_window_count(self): """ Get windows count """ - return self.loop.run_until_complete(self.async_func.get_window_count_async()) + + # return self.loop.run_until_complete(self.async_func.get_window_count_async()) @keyword def wait_for_new_window_open(self, timeout=None): diff --git a/PuppeteerLibrary/keywords/ibrowsermanagement_async.py b/PuppeteerLibrary/keywords/ibrowsermanagement_async.py index 0abee41..fed7125 100644 --- a/PuppeteerLibrary/keywords/ibrowsermanagement_async.py +++ b/PuppeteerLibrary/keywords/ibrowsermanagement_async.py @@ -1,9 +1,27 @@ +from PuppeteerLibrary.keywords.base_async_keywords import BaseAsyncKeywords +from PuppeteerLibrary.library_context.ilibrary_context import iLibraryContext from abc import ABC, abstractmethod -from PuppeteerLibrary.base.librarycomponent import LibraryComponent -class iBrowserManagementAsync(LibraryComponent, ABC): +class iBrowserManagementAsync(BaseAsyncKeywords, ABC): + + @abstractmethod + async def maximize_browser_window(self, width=1366, height=768): + pass @abstractmethod async def go_to(self, url): pass + + @abstractmethod + async def go_back(self, url): + pass + + @abstractmethod + async def reload_page(self): + pass + + @abstractmethod + async def get_window_count(self): + pass + \ No newline at end of file diff --git a/PuppeteerLibrary/library_context/ilibrary_context.py b/PuppeteerLibrary/library_context/ilibrary_context.py index e7d7599..833fc3e 100644 --- a/PuppeteerLibrary/library_context/ilibrary_context.py +++ b/PuppeteerLibrary/library_context/ilibrary_context.py @@ -4,6 +4,7 @@ class iLibraryContext(ABC): browser_type: str = None + timeout: int = 30 def __init__(self, browser_type: str): self.browser_type = browser_type diff --git a/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py b/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py index 70f46b1..6d3b384 100644 --- a/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py +++ b/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py @@ -8,8 +8,34 @@ class PlaywrightBrowserManagement(iBrowserManagementAsync): - def __init__(self, ctx): - super().__init__(ctx) + def __init__(self, library_ctx): + super().__init__(library_ctx) + + async def maximize_browser_window(self, width=1366, height=768): + return await self.library_ctx.get_current_page().setViewportSize({ + width: width, + height: height, + }) async def go_to(self, url): - return await self.ctx.get_current_page().goto(url) + return await self.library_ctx.get_current_page().goto(url) + + async def go_back(self): + return await self.library_ctx.get_current_page().goBack() + + async def reload_page(self): + return await self.library_ctx.get_current_page().reload() + + async def get_window_count(self): + pass + ''' + pages = await self.library_ctx.get_browser().pages() + for page in pages: + # Workaround: for force pages re-cache + try: + await page.title() + except: + return -1 + return len(await self.library_ctx.get_browser().pages()) + ''' + \ No newline at end of file diff --git a/PuppeteerLibrary/playwright/playwright_context.py b/PuppeteerLibrary/playwright/playwright_context.py index 8764c51..df1bed8 100644 --- a/PuppeteerLibrary/playwright/playwright_context.py +++ b/PuppeteerLibrary/playwright/playwright_context.py @@ -14,6 +14,7 @@ class PlaywrightContext(iLibraryContext): browser: any = None current_page = None current_iframe = None + def __init__(self, browser_type: str): super().__init__(browser_type) diff --git a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_browsermanagement.py b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_browsermanagement.py index 05448f4..0c44459 100644 --- a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_browsermanagement.py +++ b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_browsermanagement.py @@ -6,12 +6,12 @@ class PuppeteerBrowserManagement(iBrowserManagementAsync): - def __init__(self, ctx): - super().__init__(ctx) + def __init__(self, library_ctx): + super().__init__(library_ctx) async def open_browser_async(self, url, browser, alias=None, options=None): - self.ctx.get_library_context(browser) - if self.ctx.puppeteer_browser is None: + self.library_ctx.get_library_context(browser) + if self.library_ctx.puppeteer_browser is None: default_args = [] default_options = { 'slowMo': 0, @@ -25,9 +25,9 @@ async def open_browser_async(self, url, browser, alias=None, options=None): if options is not None: merged_options = {**merged_options, **options} - if self.ctx.debug_mode is True: + if self.library_ctx.debug_mode is True: merged_options = {**merged_options, - **self.ctx.debug_mode_options} + **self.library_ctx.debug_mode_options} if 'win' not in sys.platform.lower(): default_args = ['--no-sandbox', '--disable-setuid-sandbox'] @@ -44,7 +44,7 @@ async def open_browser_async(self, url, browser, alias=None, options=None): args=default_args) browser_context = await self.browser.createIncognitoBrowserContext() - await self.ctx.add_context_async(alias, browser_context) + await self.library_ctx.add_context_async(alias, browser_context) current_page = await self._create_page_async() await current_page.goto(url) @@ -58,6 +58,6 @@ async def close_puppeteer_async(self): pass async def _create_page_async(self) -> SPage: - new_page = await self.ctx.get_current_context().newPage() - self.ctx.set_current_page(new_page) - return self.ctx.get_current_page() + new_page = await self.library_ctx.get_current_context().newPage() + self.library_ctx.set_current_page(new_page) + return self.library_ctx.get_current_page() From a538db61d388022587b8eb2879ecf43907cc4755 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Tue, 13 Oct 2020 15:50:15 +0700 Subject: [PATCH 013/103] Update open-close-browser demo --- .../open-close-browser.robot | 14 +-- .../keywords/browsermanagement.py | 92 ++++--------------- .../library_context/ilibrary_context.py | 4 + .../playwright_browsermanagement.py | 9 +- .../playwright/playwright_context.py | 3 + 5 files changed, 41 insertions(+), 81 deletions(-) diff --git a/Examples/browser-management/open-close-browser.robot b/Examples/browser-management/open-close-browser.robot index 941b441..0eada4d 100644 --- a/Examples/browser-management/open-close-browser.robot +++ b/Examples/browser-management/open-close-browser.robot @@ -5,16 +5,18 @@ Test Teardown Close All Browser *** Test Cases *** Switch to new browser - ${HEADLESS} Get variable value ${HEADLESS} ${False} + # ${BROWSER} = Get variable value ${BROWSER} chrome + ${BROWSER} = Get variable value ${BROWSER} webkit + ${HEADLESS} = Get variable value ${HEADLESS} ${False} &{options} = create dictionary headless=${HEADLESS} - Open browser http://127.0.0.1:7272/basic-html-elements.html options=${options} + Open browser http://127.0.0.1:7272/basic-html-elements.html browser=${BROWSER} options=${options} Run Async Keywords ... Wait For New Window Open AND ... Click Element id=open-new-tab - Switch Window NEW - Wait Until Page Contains Element id=exampleInputEmail1 - Switch Window title=Basic HTML Elements - Wait Until Page Contains Element id=open-new-tab + # Switch Window NEW + # Wait Until Page Contains Element id=exampleInputEmail1 + # Switch Window title=Basic HTML Elements + # Wait Until Page Contains Element id=open-new-tab Handle multiple browser ${HEADLESS} Get variable value ${HEADLESS} ${False} diff --git a/PuppeteerLibrary/keywords/browsermanagement.py b/PuppeteerLibrary/keywords/browsermanagement.py index 4a3a601..dec4118 100644 --- a/PuppeteerLibrary/keywords/browsermanagement.py +++ b/PuppeteerLibrary/keywords/browsermanagement.py @@ -16,44 +16,15 @@ def __init__(self, ctx): def get_async_keyword_group(self) -> iBrowserManagementAsync: return self.ctx.get_current_library_context().get_async_keyword_group(type(self).__name__) - @keyword - def new_open_browser(self, url, browser="chrome", alias=None, options=None): - library_context = self.ctx.create_library_context(alias, browser) - 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)) - - @keyword - def new_close_browser(self, alias=None): - """Closes the current browser - """ - library_context = self.ctx.get_current_library_context() - if alias is not None: - library_context = self.ctx.get_library_context_by_name(alias) - self.loop.run_until_complete(library_context.close_browser_context()) - - @keyword - def new_close_all_browser(self): - """Close all browser - """ - library_contexts = self.ctx.get_all_library_context() - for library_context in library_contexts: - self.loop.run_until_complete(library_context.close_browser_context()) - - @keyword - def new_close_puppeteer(self): - library_contexts = self.ctx.get_all_library_context() - for library_context in library_contexts: - self.loop.run_until_complete(library_context.stop_server()) - @keyword def open_browser(self, url, browser="chrome", alias=None, options=None): """Opens a new browser instance to the specific ``url``. The ``browser`` argument specifies which browser to use. - | = Browser = | = Name(s) = | - | Google Chrome | chrome | + | = Browser = | = Name(s) = | + | Google Chrome | chrome | + | Webkit (Safari engine) | webkit | The ``options`` argument as a dictionary @@ -70,60 +41,33 @@ def open_browser(self, url, browser="chrome", alias=None, options=None): | `Open browser` | https://www.w3schools.com/html/html_forms.asp | options=${options} | """ - async def open_browser_async(): - if self.ctx.browser is None: - default_args = [] - default_options = { - 'slowMo': 0, - 'headless': True, - 'devtools': False, - 'width': 1366, - 'height': 768 - } - - merged_options = default_options - - if options is not None: - merged_options = {**merged_options, **options} - - if self.ctx.debug_mode is True: - merged_options = {**merged_options, **self.ctx.debug_mode_options} - - if 'win' not in sys.platform.lower(): - default_args = ['--no-sandbox', '--disable-setuid-sandbox'] - - self.info(('Open browser to ' + url + '\n' + - str(merged_options))) - self.ctx.browser = await launch( - slowMo=merged_options['slowMo'], - devtools=merged_options['devtools'], - headless=merged_options['headless'], - defaultViewport={ - 'width': merged_options['width'], - 'height': merged_options['height'] - }, - args=default_args) - await self.ctx.create_context_async(alias) - current_page = await self.ctx.create_page_async() - await current_page.goto(url) - await current_page.screenshot({'path': 'example.png'}) - self.loop.run_until_complete(open_browser_async()) + library_context = self.ctx.create_library_context(alias, browser) + 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)) @keyword def close_browser(self, alias=None): """Closes the current browser """ - self.loop.run_until_complete(self.async_func.close_browser_async(alias)) + library_context = self.ctx.get_current_library_context() + if alias is not None: + library_context = self.ctx.get_library_context_by_name(alias) + self.loop.run_until_complete(library_context.close_browser_context()) @keyword def close_all_browser(self): """Close all browser """ - self.loop.run_until_complete(self.async_func.close_all_browser_async()) + library_contexts = self.ctx.get_all_library_context() + for library_context in library_contexts: + self.loop.run_until_complete(library_context.close_browser_context()) @keyword def close_puppeteer(self): - self.loop.run_until_complete(self.async_func.close_puppeteer_async()) + library_contexts = self.ctx.get_all_library_context() + for library_context in library_contexts: + self.loop.run_until_complete(library_context.stop_server()) @keyword def maximize_browser_window(self, width=1366, height=768): @@ -194,7 +138,7 @@ def set_timeout(self, timeout): def get_window_count(self): """ Get windows count """ - + pass # return self.loop.run_until_complete(self.async_func.get_window_count_async()) @keyword diff --git a/PuppeteerLibrary/library_context/ilibrary_context.py b/PuppeteerLibrary/library_context/ilibrary_context.py index 833fc3e..e8c8be3 100644 --- a/PuppeteerLibrary/library_context/ilibrary_context.py +++ b/PuppeteerLibrary/library_context/ilibrary_context.py @@ -29,6 +29,10 @@ async def create_new_page(self, options: dict=None): def get_current_page(self): pass + @abstractmethod + async def get_all_pages(self): + pass + @abstractmethod async def close_browser_context(self): pass diff --git a/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py b/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py index 6d3b384..e57338c 100644 --- a/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py +++ b/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py @@ -27,7 +27,14 @@ async def reload_page(self): return await self.library_ctx.get_current_page().reload() async def get_window_count(self): - pass + pages = await self.library_ctx.get_all_pages() + for page in pages: + # Workaround: for force pages re-cache + try: + await page.title() + except: + return -1 + return len(await self.library_ctx.get_all_pages()) ''' pages = await self.library_ctx.get_browser().pages() for page in pages: diff --git a/PuppeteerLibrary/playwright/playwright_context.py b/PuppeteerLibrary/playwright/playwright_context.py index df1bed8..f3454ed 100644 --- a/PuppeteerLibrary/playwright/playwright_context.py +++ b/PuppeteerLibrary/playwright/playwright_context.py @@ -42,6 +42,9 @@ async def create_new_page(self, options: dict=None): def get_current_page(self): return self.current_page + async def get_all_pages(self): + return await self.browser.pages() + async def close_browser_context(self): await self.browser.close() self._reset_context() From 708b5013c428ae6ec905ac796d32a89797c078d8 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Wed, 14 Oct 2020 19:56:55 +0700 Subject: [PATCH 014/103] Update base playwright page --- .../open-close-browser.robot | 7 ++-- PuppeteerLibrary/custom_elements/base_page.py | 20 +++++++++++ PuppeteerLibrary/keywords/element.py | 7 +++- .../keywords/ibrowsermanagement_async.py | 1 - PuppeteerLibrary/keywords/ielement_async.py | 9 +++++ .../library_context/ilibrary_context.py | 5 +-- .../playwright_browsermanagement.py | 10 +++--- .../async_keywords/playwright_element.py | 10 ++++++ .../playwright/custom_elements/__init__.py | 0 .../custom_elements/playwright_page.py | 34 +++++++++++++++++++ .../playwright/playwright_context.py | 20 ++++++----- setup.py | 2 +- 12 files changed, 103 insertions(+), 22 deletions(-) create mode 100644 PuppeteerLibrary/custom_elements/base_page.py create mode 100644 PuppeteerLibrary/keywords/ielement_async.py create mode 100644 PuppeteerLibrary/playwright/async_keywords/playwright_element.py create mode 100644 PuppeteerLibrary/playwright/custom_elements/__init__.py create mode 100644 PuppeteerLibrary/playwright/custom_elements/playwright_page.py diff --git a/Examples/browser-management/open-close-browser.robot b/Examples/browser-management/open-close-browser.robot index 0eada4d..0ab9c70 100644 --- a/Examples/browser-management/open-close-browser.robot +++ b/Examples/browser-management/open-close-browser.robot @@ -10,9 +10,10 @@ Switch to new browser ${HEADLESS} = Get variable value ${HEADLESS} ${False} &{options} = create dictionary headless=${HEADLESS} Open browser http://127.0.0.1:7272/basic-html-elements.html browser=${BROWSER} options=${options} - Run Async Keywords - ... Wait For New Window Open AND - ... Click Element id=open-new-tab + Click Element id=open-new-tab + # Run Async Keywords + # ... Wait For New Window Open AND + # ... Click Element id=open-new-tab # Switch Window NEW # Wait Until Page Contains Element id=exampleInputEmail1 # Switch Window title=Basic HTML Elements diff --git a/PuppeteerLibrary/custom_elements/base_page.py b/PuppeteerLibrary/custom_elements/base_page.py new file mode 100644 index 0000000..b61a0e4 --- /dev/null +++ b/PuppeteerLibrary/custom_elements/base_page.py @@ -0,0 +1,20 @@ +from abc import ABC, abstractmethod +from typing import Any + +class BasePage(ABC): + + @abstractmethod + def get_page(self) -> any: + pass + + @abstractmethod + async def click_with_selenium_locator(self, selenium_locator: str, options: dict = None, **kwargs: Any): + pass + + @abstractmethod + async def click_xpath(self, selector: str, options: dict = None, **kwargs: Any): + pass + + @abstractmethod + async def click(self, selector: str, options: dict = None, **kwargs: Any): + pass diff --git a/PuppeteerLibrary/keywords/element.py b/PuppeteerLibrary/keywords/element.py index b433eff..a410f21 100644 --- a/PuppeteerLibrary/keywords/element.py +++ b/PuppeteerLibrary/keywords/element.py @@ -1,3 +1,4 @@ +from PuppeteerLibrary.keywords.ielement_async import iElementAsync from PuppeteerLibrary.base.librarycomponent import LibraryComponent from PuppeteerLibrary.base.robotlibcore import keyword from PuppeteerLibrary.keywords.element_async import ElementKeywordsAsync @@ -9,6 +10,9 @@ def __init__(self, ctx): super().__init__(ctx) self.async_func = ElementKeywordsAsync(self.ctx) + def get_async_keyword_group(self) -> iElementAsync: + return self.ctx.get_current_library_context().get_async_keyword_group(type(self).__name__) + @keyword def click_element(self, locator): """Clicks element identified by ``locator``. @@ -17,7 +21,8 @@ def click_element(self, locator): | `Click Element` | id:register | """ - return self.loop.run_until_complete(self.async_func.click_element_async(locator)) + self.loop.run_until_complete(self.get_async_keyword_group().click_element(locator)) + # return self.loop.run_until_complete(self.async_func.click_element_async(locator)) @keyword def click_link(self, locator): diff --git a/PuppeteerLibrary/keywords/ibrowsermanagement_async.py b/PuppeteerLibrary/keywords/ibrowsermanagement_async.py index fed7125..e4a8999 100644 --- a/PuppeteerLibrary/keywords/ibrowsermanagement_async.py +++ b/PuppeteerLibrary/keywords/ibrowsermanagement_async.py @@ -1,5 +1,4 @@ from PuppeteerLibrary.keywords.base_async_keywords import BaseAsyncKeywords -from PuppeteerLibrary.library_context.ilibrary_context import iLibraryContext from abc import ABC, abstractmethod diff --git a/PuppeteerLibrary/keywords/ielement_async.py b/PuppeteerLibrary/keywords/ielement_async.py new file mode 100644 index 0000000..e443178 --- /dev/null +++ b/PuppeteerLibrary/keywords/ielement_async.py @@ -0,0 +1,9 @@ +from PuppeteerLibrary.keywords.base_async_keywords import BaseAsyncKeywords +from abc import ABC, abstractmethod + + +class iElementAsync(BaseAsyncKeywords, ABC): + + @abstractmethod + async def click_element(self, locator: str): + pass diff --git a/PuppeteerLibrary/library_context/ilibrary_context.py b/PuppeteerLibrary/library_context/ilibrary_context.py index e8c8be3..f51fb6b 100644 --- a/PuppeteerLibrary/library_context/ilibrary_context.py +++ b/PuppeteerLibrary/library_context/ilibrary_context.py @@ -1,3 +1,4 @@ +from PuppeteerLibrary.custom_elements.base_page import BasePage from abc import ABC, abstractmethod @@ -22,11 +23,11 @@ def is_server_started(self) -> bool: pass @abstractmethod - async def create_new_page(self, options: dict=None): + async def create_new_page(self, options: dict=None) -> BasePage: pass @abstractmethod - def get_current_page(self): + def get_current_page(self) -> BasePage: pass @abstractmethod diff --git a/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py b/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py index e57338c..1d14b9b 100644 --- a/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py +++ b/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py @@ -12,26 +12,26 @@ def __init__(self, library_ctx): super().__init__(library_ctx) async def maximize_browser_window(self, width=1366, height=768): - return await self.library_ctx.get_current_page().setViewportSize({ + return await self.library_ctx.get_current_page().get_page().setViewportSize({ width: width, height: height, }) async def go_to(self, url): - return await self.library_ctx.get_current_page().goto(url) + return await self.library_ctx.get_current_page().get_page().goto(url) async def go_back(self): - return await self.library_ctx.get_current_page().goBack() + return await self.library_ctx.get_current_page().get_page().goBack() async def reload_page(self): - return await self.library_ctx.get_current_page().reload() + return await self.library_ctx.get_current_page().get_page().reload() async def get_window_count(self): pages = await self.library_ctx.get_all_pages() for page in pages: # Workaround: for force pages re-cache try: - await page.title() + await page.get_page().title() except: return -1 return len(await self.library_ctx.get_all_pages()) diff --git a/PuppeteerLibrary/playwright/async_keywords/playwright_element.py b/PuppeteerLibrary/playwright/async_keywords/playwright_element.py new file mode 100644 index 0000000..515461b --- /dev/null +++ b/PuppeteerLibrary/playwright/async_keywords/playwright_element.py @@ -0,0 +1,10 @@ +from PuppeteerLibrary.keywords.ielement_async import iElementAsync + + +class PlaywrightElement(iElementAsync): + + def __init__(self, library_ctx): + super().__init__(library_ctx) + + async def click_element(self, locator: str): + return await self.library_ctx.get_current_page().click_with_selenium_locator(locator) diff --git a/PuppeteerLibrary/playwright/custom_elements/__init__.py b/PuppeteerLibrary/playwright/custom_elements/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/PuppeteerLibrary/playwright/custom_elements/playwright_page.py b/PuppeteerLibrary/playwright/custom_elements/playwright_page.py new file mode 100644 index 0000000..a4bdb67 --- /dev/null +++ b/PuppeteerLibrary/playwright/custom_elements/playwright_page.py @@ -0,0 +1,34 @@ +from typing import Any, Dict +from PuppeteerLibrary.custom_elements.base_page import BasePage +from PuppeteerLibrary.locators.SelectorAbstraction import SelectorAbstraction + +try: + from playwright.page import Page +except Exception: + from pyppeteer.page import Page + print('import playwright error') + +class PlaywrightPage(BasePage): + + def __init__(self, page: Page): + self.page = page + self.selected_iframe = None + + def get_page(self) -> Page: + return self.page + + async def click_with_selenium_locator(self, selenium_locator: str, options: dict = None, **kwargs: Any): + selector_value = SelectorAbstraction.get_selector(selenium_locator) + if SelectorAbstraction.is_xpath(selenium_locator): + await self.page.click_xpath(selector_value, options, **kwargs) + else: + await self.page.click(selector_value, options, **kwargs) + + async def click_xpath(self, selector: str, options: dict = None, **kwargs: Any): + pass + + async def click(self, selector: str, options: dict = None, **kwargs: Any): + if self.selected_iframe is None: + return await self.page.click(selector=selector, options=options, kwargs=kwargs) + else: + return await self.selected_iframe.click(selector=selector, options=options, kwargs=kwargs) diff --git a/PuppeteerLibrary/playwright/playwright_context.py b/PuppeteerLibrary/playwright/playwright_context.py index f3454ed..433cf78 100644 --- a/PuppeteerLibrary/playwright/playwright_context.py +++ b/PuppeteerLibrary/playwright/playwright_context.py @@ -1,3 +1,6 @@ +from PuppeteerLibrary.custom_elements.base_page import BasePage +from PuppeteerLibrary.playwright.async_keywords.playwright_element import PlaywrightElement +from PuppeteerLibrary.playwright.custom_elements.playwright_page import PlaywrightPage from PuppeteerLibrary.playwright.async_keywords.playwright_browsermanagement import PlaywrightBrowserManagement from PuppeteerLibrary.library_context.ilibrary_context import iLibraryContext try: @@ -12,10 +15,9 @@ class PlaywrightContext(iLibraryContext): playwright: any = None browser: any = None - current_page = None + current_page: any = None current_iframe = None - def __init__(self, browser_type: str): super().__init__(browser_type) @@ -35,11 +37,12 @@ def is_server_started(self) -> bool: return True return False - async def create_new_page(self, options: dict=None): - self.current_page = await self.browser.newPage() + async def create_new_page(self, options: dict=None) -> BasePage: + new_page = await self.browser.newPage() + self.current_page = PlaywrightPage(new_page) return self.current_page - - def get_current_page(self): + + def get_current_page(self) -> BasePage: return self.current_page async def get_all_pages(self): @@ -51,7 +54,8 @@ async def close_browser_context(self): def get_async_keyword_group(self, keyword_group_name: str): switcher = { - "BrowserManagementKeywords": PlaywrightBrowserManagement(self) + "BrowserManagementKeywords": PlaywrightBrowserManagement(self), + "ElementKeywords": PlaywrightElement(self) } return switcher.get(keyword_group_name) @@ -63,5 +67,3 @@ def _reset_context(self): def _reset_server_context(self): self._reset_context() self.playwright = None - - \ No newline at end of file diff --git a/setup.py b/setup.py index 083c0af..c75fc71 100644 --- a/setup.py +++ b/setup.py @@ -39,8 +39,8 @@ platforms='any', install_requires=[ 'robotframework>=3.2.1', + 'playwright>=0.142.1', 'pyppeteer>=0.2.2', - 'playwright>=0.142.1' ], # python_requires='>3.5', # test_suite='nose.collector', From 452655e2991b3189628768f1d2a309e75ba943b2 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Thu, 15 Oct 2020 07:24:46 +0700 Subject: [PATCH 015/103] Add custom playwright page context --- .../open-close-browser.robot | 8 ++--- PuppeteerLibrary/custom_elements/base_page.py | 20 ++++++++++++ .../keywords/base_async_keywords.py | 2 +- .../keywords/browsermanagement.py | 3 +- .../keywords/ibrowsermanagement_async.py | 5 ++- .../library_context/ilibrary_context.py | 4 +++ .../playwright_browsermanagement.py | 32 +++++++++++++------ .../custom_elements/playwright_page.py | 15 +++++++++ .../playwright/playwright_context.py | 5 ++- 9 files changed, 76 insertions(+), 18 deletions(-) diff --git a/Examples/browser-management/open-close-browser.robot b/Examples/browser-management/open-close-browser.robot index 0ab9c70..b9c741b 100644 --- a/Examples/browser-management/open-close-browser.robot +++ b/Examples/browser-management/open-close-browser.robot @@ -10,10 +10,10 @@ Switch to new browser ${HEADLESS} = Get variable value ${HEADLESS} ${False} &{options} = create dictionary headless=${HEADLESS} Open browser http://127.0.0.1:7272/basic-html-elements.html browser=${BROWSER} options=${options} - Click Element id=open-new-tab - # Run Async Keywords - # ... Wait For New Window Open AND - # ... Click Element id=open-new-tab + Run Async Keywords + ... Click Element id=open-new-tab AND + ... Wait For New Window Open + # Switch Window NEW # Wait Until Page Contains Element id=exampleInputEmail1 # Switch Window title=Basic HTML Elements diff --git a/PuppeteerLibrary/custom_elements/base_page.py b/PuppeteerLibrary/custom_elements/base_page.py index b61a0e4..7feb215 100644 --- a/PuppeteerLibrary/custom_elements/base_page.py +++ b/PuppeteerLibrary/custom_elements/base_page.py @@ -7,6 +7,26 @@ class BasePage(ABC): def get_page(self) -> any: pass + @abstractmethod + async def goto(self, url: str): + pass + + @abstractmethod + async def go_back(self): + pass + + @abstractmethod + async def reload_page(self): + pass + + @abstractmethod + async def title(self): + pass + + @abstractmethod + async def set_viewport_size(self, width, height): + pass + @abstractmethod async def click_with_selenium_locator(self, selenium_locator: str, options: dict = None, **kwargs: Any): pass diff --git a/PuppeteerLibrary/keywords/base_async_keywords.py b/PuppeteerLibrary/keywords/base_async_keywords.py index 3615200..a6f6634 100644 --- a/PuppeteerLibrary/keywords/base_async_keywords.py +++ b/PuppeteerLibrary/keywords/base_async_keywords.py @@ -19,5 +19,5 @@ def warn(self, msg, html=False): def timestr_to_secs_for_default_timeout(self, timeout): if timeout is None or timeout == '': - timeout = self.ctx.timeout + timeout = self.library_ctx.timeout return timestr_to_secs(timeout) diff --git a/PuppeteerLibrary/keywords/browsermanagement.py b/PuppeteerLibrary/keywords/browsermanagement.py index dec4118..be594e0 100644 --- a/PuppeteerLibrary/keywords/browsermanagement.py +++ b/PuppeteerLibrary/keywords/browsermanagement.py @@ -151,7 +151,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.async_func.wait_for_new_window_open_async(timeout)) + self.loop.run_until_complete(self.get_async_keyword_group().wait_for_new_window_open(timeout)) + # self.loop.run_until_complete(self.async_func.wait_for_new_window_open_async(timeout)) @keyword def switch_window(self, locator='MAIN'): diff --git a/PuppeteerLibrary/keywords/ibrowsermanagement_async.py b/PuppeteerLibrary/keywords/ibrowsermanagement_async.py index e4a8999..129fb8f 100644 --- a/PuppeteerLibrary/keywords/ibrowsermanagement_async.py +++ b/PuppeteerLibrary/keywords/ibrowsermanagement_async.py @@ -23,4 +23,7 @@ async def reload_page(self): @abstractmethod async def get_window_count(self): pass - \ No newline at end of file + + @abstractmethod + async def wait_for_new_window_open(self, timeout=None): + pass diff --git a/PuppeteerLibrary/library_context/ilibrary_context.py b/PuppeteerLibrary/library_context/ilibrary_context.py index f51fb6b..7e8b0f0 100644 --- a/PuppeteerLibrary/library_context/ilibrary_context.py +++ b/PuppeteerLibrary/library_context/ilibrary_context.py @@ -34,6 +34,10 @@ def get_current_page(self) -> BasePage: async def get_all_pages(self): pass + @abstractmethod + def get_browser_context(self): + pass + @abstractmethod async def close_browser_context(self): pass diff --git a/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py b/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py index 1d14b9b..728300d 100644 --- a/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py +++ b/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py @@ -1,5 +1,6 @@ +import asyncio +import time from PuppeteerLibrary.keywords.ibrowsermanagement_async import iBrowserManagementAsync -from PuppeteerLibrary.custom_elements.SPage import SPage try: from playwright import async_playwright except ImportError: @@ -12,26 +13,23 @@ def __init__(self, library_ctx): super().__init__(library_ctx) async def maximize_browser_window(self, width=1366, height=768): - return await self.library_ctx.get_current_page().get_page().setViewportSize({ - width: width, - height: height, - }) + return await self.library_ctx.get_current_page().set_viewport_size(width, height) async def go_to(self, url): - return await self.library_ctx.get_current_page().get_page().goto(url) + return await self.library_ctx.get_current_page().goto(url) async def go_back(self): - return await self.library_ctx.get_current_page().get_page().goBack() + return await self.library_ctx.get_current_page().go_back() async def reload_page(self): - return await self.library_ctx.get_current_page().get_page().reload() + return await self.library_ctx.get_current_page().reload_page() async def get_window_count(self): pages = await self.library_ctx.get_all_pages() for page in pages: # Workaround: for force pages re-cache try: - await page.get_page().title() + await page.title() except: return -1 return len(await self.library_ctx.get_all_pages()) @@ -45,4 +43,18 @@ async def get_window_count(self): return -1 return len(await self.library_ctx.get_browser().pages()) ''' - \ No newline at end of file + + async def wait_for_new_window_open(self, timeout=None): + page_len = 0 + # Workaround: + # We get length without force reset. For ensure that when we count page length. + # Page length still not update / same as before open new window + pre_page_len = len(await self.library_ctx.get_all_pages()) + timeout = self.timestr_to_secs_for_default_timeout(timeout) + max_time = time.time() + timeout + while time.time() < max_time: + page_len = len(await self.library_ctx.get_all_pages()) + if page_len > pre_page_len: + return + await asyncio.sleep(0.5) + raise Exception('No new page has been open. pre: ' + str(pre_page_len) + ' current: ' + str(page_len)) diff --git a/PuppeteerLibrary/playwright/custom_elements/playwright_page.py b/PuppeteerLibrary/playwright/custom_elements/playwright_page.py index a4bdb67..d9fe341 100644 --- a/PuppeteerLibrary/playwright/custom_elements/playwright_page.py +++ b/PuppeteerLibrary/playwright/custom_elements/playwright_page.py @@ -17,6 +17,21 @@ def __init__(self, page: Page): def get_page(self) -> Page: return self.page + async def goto(self, url: str): + return await self.page.goto(url) + + async def go_back(self): + return await self.page.goBack() + + async def reload_page(self): + return await self.page.reload() + + async def title(self): + return await self.page.title() + + async def set_viewport_size(self, width: int, height: int): + return await self.page.setViewportSize(width, height) + async def click_with_selenium_locator(self, selenium_locator: str, options: dict = None, **kwargs: Any): selector_value = SelectorAbstraction.get_selector(selenium_locator) if SelectorAbstraction.is_xpath(selenium_locator): diff --git a/PuppeteerLibrary/playwright/playwright_context.py b/PuppeteerLibrary/playwright/playwright_context.py index 433cf78..ba81a26 100644 --- a/PuppeteerLibrary/playwright/playwright_context.py +++ b/PuppeteerLibrary/playwright/playwright_context.py @@ -46,7 +46,10 @@ def get_current_page(self) -> BasePage: return self.current_page async def get_all_pages(self): - return await self.browser.pages() + return self.browser.contexts[0].pages + + def get_browser_context(self): + return self.browser async def close_browser_context(self): await self.browser.close() From 41820e48d05af5fe910e08a2831831681dfca5cd Mon Sep 17 00:00:00 2001 From: atthaboons Date: Thu, 15 Oct 2020 07:38:41 +0700 Subject: [PATCH 016/103] Add support switch window keyword --- .../open-close-browser.robot | 3 +- .../keywords/browsermanagement.py | 5 ++- .../keywords/ibrowsermanagement_async.py | 4 +++ .../library_context/ilibrary_context.py | 4 +++ .../playwright_browsermanagement.py | 33 +++++++++++++++++++ .../playwright/playwright_context.py | 4 +++ 6 files changed, 50 insertions(+), 3 deletions(-) diff --git a/Examples/browser-management/open-close-browser.robot b/Examples/browser-management/open-close-browser.robot index b9c741b..dffd76e 100644 --- a/Examples/browser-management/open-close-browser.robot +++ b/Examples/browser-management/open-close-browser.robot @@ -13,8 +13,7 @@ Switch to new browser Run Async Keywords ... Click Element id=open-new-tab AND ... Wait For New Window Open - - # Switch Window NEW + Switch Window NEW # Wait Until Page Contains Element id=exampleInputEmail1 # Switch Window title=Basic HTML Elements # Wait Until Page Contains Element id=open-new-tab diff --git a/PuppeteerLibrary/keywords/browsermanagement.py b/PuppeteerLibrary/keywords/browsermanagement.py index be594e0..c6795f0 100644 --- a/PuppeteerLibrary/keywords/browsermanagement.py +++ b/PuppeteerLibrary/keywords/browsermanagement.py @@ -152,7 +152,6 @@ def wait_for_new_window_open(self, timeout=None): | ... | `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.async_func.wait_for_new_window_open_async(timeout)) @keyword def switch_window(self, locator='MAIN'): @@ -163,6 +162,9 @@ 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)) + + ''' async def switch_window_async(): pages = await self.ctx.get_browser().pages() if locator == 'MAIN': @@ -196,6 +198,7 @@ async def switch_window_async(): raise Exception('Can\'t find specify page locator.') return self.loop.run_until_complete(switch_window_async()) + ''' @keyword def switch_browser(self, alias): diff --git a/PuppeteerLibrary/keywords/ibrowsermanagement_async.py b/PuppeteerLibrary/keywords/ibrowsermanagement_async.py index 129fb8f..044c5a2 100644 --- a/PuppeteerLibrary/keywords/ibrowsermanagement_async.py +++ b/PuppeteerLibrary/keywords/ibrowsermanagement_async.py @@ -27,3 +27,7 @@ async def get_window_count(self): @abstractmethod async def wait_for_new_window_open(self, timeout=None): pass + + @abstractmethod + async def switch_window(self, locator='MAIN'): + pass diff --git a/PuppeteerLibrary/library_context/ilibrary_context.py b/PuppeteerLibrary/library_context/ilibrary_context.py index 7e8b0f0..bdab19c 100644 --- a/PuppeteerLibrary/library_context/ilibrary_context.py +++ b/PuppeteerLibrary/library_context/ilibrary_context.py @@ -30,6 +30,10 @@ async def create_new_page(self, options: dict=None) -> BasePage: def get_current_page(self) -> BasePage: pass + @abstractmethod + def set_current_page(self, page: any) -> BasePage: + pass + @abstractmethod async def get_all_pages(self): pass diff --git a/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py b/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py index 728300d..8e27300 100644 --- a/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py +++ b/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py @@ -1,4 +1,5 @@ import asyncio +import re import time from PuppeteerLibrary.keywords.ibrowsermanagement_async import iBrowserManagementAsync try: @@ -58,3 +59,35 @@ async def wait_for_new_window_open(self, timeout=None): return await asyncio.sleep(0.5) raise Exception('No new page has been open. pre: ' + str(pre_page_len) + ' current: ' + str(page_len)) + + async def switch_window(self, locator='MAIN'): + pages = await self.library_ctx.get_all_pages() + if locator == 'MAIN': + page = pages[0] + await page.bringToFront() + return self.library_ctx.set_current_page(page) + + elif locator == 'NEW': + page = pages[-1] + await page.bringToFront() + return self.library_ctx.set_current_page(page) + + elif 'title=' in locator: + title = locator.replace('title=', '') + for page in pages: + page_title = await page.title() + if page_title == title: + await page.bringToFront() + return self.library_ctx.set_current_page(page) + self.info('Title mismatch: ' + page_title) + + elif 'url=' in locator: + url = locator.replace('url=', '') + for page in pages: + if re.match(url, page.url): + await page.bringToFront() + return self.library_ctx.set_current_page(page) + self.info('Url mismatch: ' + page.url) + else: + raise Exception('Sorry Switch window support only NEW, MAIN, title and url') + raise Exception('Can\'t find specify page locator.') diff --git a/PuppeteerLibrary/playwright/playwright_context.py b/PuppeteerLibrary/playwright/playwright_context.py index ba81a26..c66e255 100644 --- a/PuppeteerLibrary/playwright/playwright_context.py +++ b/PuppeteerLibrary/playwright/playwright_context.py @@ -45,6 +45,10 @@ async def create_new_page(self, options: dict=None) -> BasePage: def get_current_page(self) -> BasePage: return self.current_page + def set_current_page(self, page: any) -> BasePage: + self.current_page = PlaywrightPage(page) + return self.current_page + async def get_all_pages(self): return self.browser.contexts[0].pages From bd30936f11974fa2ee67557d5ee02f32ff2956eb Mon Sep 17 00:00:00 2001 From: atthaboons Date: Thu, 15 Oct 2020 07:52:44 +0700 Subject: [PATCH 017/103] init waiting keywords --- .../open-close-browser.robot | 2 +- .../keywords/browsermanagement.py | 3 - PuppeteerLibrary/keywords/iwaiting_async.py | 61 +++++++++++++++++++ .../async_keywords/playwright_waiting.py | 50 +++++++++++++++ 4 files changed, 112 insertions(+), 4 deletions(-) create mode 100644 PuppeteerLibrary/keywords/iwaiting_async.py create mode 100644 PuppeteerLibrary/playwright/async_keywords/playwright_waiting.py diff --git a/Examples/browser-management/open-close-browser.robot b/Examples/browser-management/open-close-browser.robot index dffd76e..469221d 100644 --- a/Examples/browser-management/open-close-browser.robot +++ b/Examples/browser-management/open-close-browser.robot @@ -14,7 +14,7 @@ Switch to new browser ... Click Element id=open-new-tab AND ... Wait For New Window Open Switch Window NEW - # Wait Until Page Contains Element id=exampleInputEmail1 + Wait Until Page Contains Element id=exampleInputEmail1 # Switch Window title=Basic HTML Elements # Wait Until Page Contains Element id=open-new-tab diff --git a/PuppeteerLibrary/keywords/browsermanagement.py b/PuppeteerLibrary/keywords/browsermanagement.py index c6795f0..74308f6 100644 --- a/PuppeteerLibrary/keywords/browsermanagement.py +++ b/PuppeteerLibrary/keywords/browsermanagement.py @@ -1,8 +1,5 @@ from PuppeteerLibrary.keywords.ibrowsermanagement_async import iBrowserManagementAsync -import re -import sys from robot.utils import timestr_to_secs -from pyppeteer import launch from PuppeteerLibrary.base.librarycomponent import LibraryComponent from PuppeteerLibrary.base.robotlibcore import keyword from PuppeteerLibrary.keywords.browsermanagement_async import BrowserManagementKeywordsAsync diff --git a/PuppeteerLibrary/keywords/iwaiting_async.py b/PuppeteerLibrary/keywords/iwaiting_async.py new file mode 100644 index 0000000..f8370e6 --- /dev/null +++ b/PuppeteerLibrary/keywords/iwaiting_async.py @@ -0,0 +1,61 @@ +from PuppeteerLibrary.keywords.base_async_keywords import BaseAsyncKeywords +from abc import ABC, abstractmethod + + +class iWaitingAsync(BaseAsyncKeywords, ABC): + + @abstractmethod + async def wait_for_request_url(self, url, method='GET', body=None, timeout=None): + pass + + @abstractmethod + async def wait_for_response_url(self, url, status=200, body=None, timeout=None): + pass + + @abstractmethod + async def wait_for_navigation(self): + pass + + @abstractmethod + async def wait_until_page_contains_element(self, locator, timeout=None): + pass + + @abstractmethod + async def wait_until_element_is_hidden(self, locator, timeout=None): + pass + + @abstractmethod + async def wait_until_element_is_visible(self, locator, timeout=None): + pass + + @abstractmethod + async def wait_until_page_contains(self, text, timeout=None): + pass + + @abstractmethod + async def wait_until_page_does_not_contains(self, text, timeout=None): + pass + + @abstractmethod + async def wait_until_element_contains(self, locator, text, timeout=None): + pass + + @abstractmethod + async def wait_until_element_does_not_contains(self, locator, text, timeout=None): + pass + + @abstractmethod + async def wait_until_location_contains(self, expected, timeout=None): + pass + + @abstractmethod + async def wait_until_location_does_not_contains(self, expected, timeout=None): + pass + + @abstractmethod + async def wait_until_element_is_enabled(self, selenium_locator, timeout=None): + pass + + @abstractmethod + async def wait_until_element_finished_animating(self, selenium_locator, timeout=None): + pass diff --git a/PuppeteerLibrary/playwright/async_keywords/playwright_waiting.py b/PuppeteerLibrary/playwright/async_keywords/playwright_waiting.py new file mode 100644 index 0000000..5b9fe99 --- /dev/null +++ b/PuppeteerLibrary/playwright/async_keywords/playwright_waiting.py @@ -0,0 +1,50 @@ +from PuppeteerLibrary.keywords.iwaiting_async import iWaitingAsync + + +class PlaywrightWaiting(iWaitingAsync): + + def __init__(self, library_ctx): + super().__init__(library_ctx) + + async def wait_for_request_url(self, url, method='GET', body=None, timeout=None): + pass + + async def wait_for_response_url(self, url, status=200, body=None, timeout=None): + pass + + async def wait_for_navigation(self): + pass + + async def wait_until_page_contains_element(self, locator, timeout=None): + pass + + async def wait_until_element_is_hidden(self, locator, timeout=None): + pass + + async def wait_until_element_is_visible(self, locator, timeout=None): + pass + + async def wait_until_page_contains(self, text, timeout=None): + pass + + async def wait_until_page_does_not_contains(self, text, timeout=None): + pass + + async def wait_until_element_contains(self, locator, text, timeout=None): + pass + + async def wait_until_element_does_not_contains(self, locator, text, timeout=None): + pass + + async def wait_until_location_contains(self, expected, timeout=None): + pass + + async def wait_until_location_does_not_contains(self, expected, timeout=None): + pass + + async def wait_until_element_is_enabled(self, selenium_locator, timeout=None): + pass + + async def wait_until_element_finished_animating(self, selenium_locator, timeout=None): + pass + From 4a285239c70b67b2e32d285e6a8de8e537632812 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Thu, 15 Oct 2020 20:08:16 +0700 Subject: [PATCH 018/103] init waiting keywords for playwright and playwright page --- .../library_context/ilibrary_context.py | 4 ++ .../async_keywords/playwright_waiting.py | 4 ++ .../custom_elements/playwright_page.py | 60 +++++++++++++++++-- .../playwright/playwright_context.py | 4 +- 4 files changed, 65 insertions(+), 7 deletions(-) diff --git a/PuppeteerLibrary/library_context/ilibrary_context.py b/PuppeteerLibrary/library_context/ilibrary_context.py index bdab19c..5af22cb 100644 --- a/PuppeteerLibrary/library_context/ilibrary_context.py +++ b/PuppeteerLibrary/library_context/ilibrary_context.py @@ -49,3 +49,7 @@ async def close_browser_context(self): @abstractmethod def get_async_keyword_group(self, keyword_group_name: str): pass + + @abstractmethod + def waitForSelector_with_selenium_locator(self): + pass diff --git a/PuppeteerLibrary/playwright/async_keywords/playwright_waiting.py b/PuppeteerLibrary/playwright/async_keywords/playwright_waiting.py index 5b9fe99..b5ac140 100644 --- a/PuppeteerLibrary/playwright/async_keywords/playwright_waiting.py +++ b/PuppeteerLibrary/playwright/async_keywords/playwright_waiting.py @@ -6,6 +6,10 @@ class PlaywrightWaiting(iWaitingAsync): def __init__(self, library_ctx): super().__init__(library_ctx) + async def _wait_for_selenium_selector(self, selenium_locator, timeout=None, visible=False, hidden=False): + timeout = self.timestr_to_secs_for_default_timeout(timeout) + return await self.library_ctx.get_current_page().waitForSelector_with_selenium_locator(selenium_locator, timeout, visible, hidden) + async def wait_for_request_url(self, url, method='GET', body=None, timeout=None): pass diff --git a/PuppeteerLibrary/playwright/custom_elements/playwright_page.py b/PuppeteerLibrary/playwright/custom_elements/playwright_page.py index d9fe341..6f6871a 100644 --- a/PuppeteerLibrary/playwright/custom_elements/playwright_page.py +++ b/PuppeteerLibrary/playwright/custom_elements/playwright_page.py @@ -1,7 +1,6 @@ -from typing import Any, Dict +from typing import Any, Dict, Optional from PuppeteerLibrary.custom_elements.base_page import BasePage from PuppeteerLibrary.locators.SelectorAbstraction import SelectorAbstraction - try: from playwright.page import Page except Exception: @@ -32,6 +31,15 @@ async def title(self): async def set_viewport_size(self, width: int, height: int): return await self.page.setViewportSize(width, height) + ############ + # Click + ############ + async def click(self, selector: str, options: dict = None, **kwargs: Any): + if self.selected_iframe is None: + return await self.page.click(selector=selector, options=options, kwargs=kwargs) + else: + return await self.selected_iframe.click(selector=selector, options=options, kwargs=kwargs) + async def click_with_selenium_locator(self, selenium_locator: str, options: dict = None, **kwargs: Any): selector_value = SelectorAbstraction.get_selector(selenium_locator) if SelectorAbstraction.is_xpath(selenium_locator): @@ -42,8 +50,48 @@ async def click_with_selenium_locator(self, selenium_locator: str, options: dict async def click_xpath(self, selector: str, options: dict = None, **kwargs: Any): pass - async def click(self, selector: str, options: dict = None, **kwargs: Any): - if self.selected_iframe is None: - return await self.page.click(selector=selector, options=options, kwargs=kwargs) + ############ + # Type + ############ + async def type_with_selenium_locator(self, selenium_locator: str, text: str, options: dict = None, **kwargs: Any): + pass + + async def type_xpath(self, selector, text: str, options: dict = None, **kwargs: Any): + pass + + ############ + # Wait + ############ + async def waitForSelector_with_selenium_locator(self, selenium_locator: str, timeout: float, visible=False, hidden=False): + pass + ''' + options = { + 'timeout': timeout * 1000, + 'visible': visible, + 'hidden': hidden + } + selector_value = SelectorAbstraction.get_selector(selenium_locator) + if SelectorAbstraction.is_xpath(selenium_locator): + return await self.waitForXPath(xpath=selector_value, options=options) else: - return await self.selected_iframe.click(selector=selector, options=options, kwargs=kwargs) + return await self.waitForSelector(selector=selector_value, options=options) + ''' + + async def waitForXPath(self, xpath: str, options: dict = None, **kwargs: Any): + pass + + async def waitForSelector(self, selector: str, options: dict = None, **kwargs: Any): + pass + + ############ + # Query + ############ + async def querySelector(self, selector: str): + pass + + async def querySelectorAll_with_selenium_locator(self, selenium_locator: str): + pass + + async def querySelector_with_selenium_locator(self, selenium_locator: str): + pass + diff --git a/PuppeteerLibrary/playwright/playwright_context.py b/PuppeteerLibrary/playwright/playwright_context.py index c66e255..4c28ef8 100644 --- a/PuppeteerLibrary/playwright/playwright_context.py +++ b/PuppeteerLibrary/playwright/playwright_context.py @@ -1,3 +1,4 @@ +from PuppeteerLibrary.playwright.async_keywords.playwright_waiting import PlaywrightWaiting from PuppeteerLibrary.custom_elements.base_page import BasePage from PuppeteerLibrary.playwright.async_keywords.playwright_element import PlaywrightElement from PuppeteerLibrary.playwright.custom_elements.playwright_page import PlaywrightPage @@ -62,7 +63,8 @@ async def close_browser_context(self): def get_async_keyword_group(self, keyword_group_name: str): switcher = { "BrowserManagementKeywords": PlaywrightBrowserManagement(self), - "ElementKeywords": PlaywrightElement(self) + "ElementKeywords": PlaywrightElement(self), + "WaitingKeywords": PlaywrightWaiting(self) } return switcher.get(keyword_group_name) From 1f47d7633db584b1bd99832e627d74a784830f6e Mon Sep 17 00:00:00 2001 From: atthaboons Date: Fri, 16 Oct 2020 07:06:06 +0700 Subject: [PATCH 019/103] Update support open-close browser keyword --- .../open-close-browser.robot | 4 +- PuppeteerLibrary/custom_elements/base_page.py | 38 ++++++++++++++++++- PuppeteerLibrary/keywords/waiting.py | 7 +++- .../library_context/ilibrary_context.py | 4 -- .../async_keywords/playwright_waiting.py | 2 +- .../custom_elements/playwright_page.py | 25 +++++------- 6 files changed, 56 insertions(+), 24 deletions(-) diff --git a/Examples/browser-management/open-close-browser.robot b/Examples/browser-management/open-close-browser.robot index 469221d..db3a80d 100644 --- a/Examples/browser-management/open-close-browser.robot +++ b/Examples/browser-management/open-close-browser.robot @@ -15,8 +15,8 @@ Switch to new browser ... Wait For New Window Open Switch Window NEW Wait Until Page Contains Element id=exampleInputEmail1 - # Switch Window title=Basic HTML Elements - # Wait Until Page Contains Element id=open-new-tab + Switch Window title=Basic HTML Elements + Wait Until Page Contains Element id=open-new-tab Handle multiple browser ${HEADLESS} Get variable value ${HEADLESS} ${False} diff --git a/PuppeteerLibrary/custom_elements/base_page.py b/PuppeteerLibrary/custom_elements/base_page.py index 7feb215..2919bd9 100644 --- a/PuppeteerLibrary/custom_elements/base_page.py +++ b/PuppeteerLibrary/custom_elements/base_page.py @@ -27,6 +27,13 @@ async def title(self): async def set_viewport_size(self, width, height): pass + ############ + # Click + ############ + @abstractmethod + async def click(self, selector: str, options: dict = None, **kwargs: Any): + pass + @abstractmethod async def click_with_selenium_locator(self, selenium_locator: str, options: dict = None, **kwargs: Any): pass @@ -35,6 +42,35 @@ async def click_with_selenium_locator(self, selenium_locator: str, options: dict async def click_xpath(self, selector: str, options: dict = None, **kwargs: Any): pass + ############ + # Type + ############ @abstractmethod - async def click(self, selector: str, options: dict = None, **kwargs: Any): + async def type_with_selenium_locator(self, selenium_locator: str, text: str, options: dict = None, **kwargs: Any): + pass + + @abstractmethod + async def type_xpath(self, selector, text: str, options: dict = None, **kwargs: Any): + pass + + ############ + # Wait + ############ + @abstractmethod + async def waitForSelector_with_selenium_locator(self, selenium_locator: str, timeout: float, visible=False, hidden=False): + pass + + ############ + # Query + ############ + @abstractmethod + async def querySelector(self, selector: str): + pass + + @abstractmethod + async def querySelectorAll_with_selenium_locator(self, selenium_locator: str): + pass + + @abstractmethod + async def querySelector_with_selenium_locator(self, selenium_locator: str): pass diff --git a/PuppeteerLibrary/keywords/waiting.py b/PuppeteerLibrary/keywords/waiting.py index a79362a..cb3b267 100644 --- a/PuppeteerLibrary/keywords/waiting.py +++ b/PuppeteerLibrary/keywords/waiting.py @@ -1,3 +1,4 @@ +from PuppeteerLibrary.keywords.iwaiting_async import iWaitingAsync from PuppeteerLibrary.keywords.waiting_async import WaitingKeywordsAsync from PuppeteerLibrary.base.librarycomponent import LibraryComponent from PuppeteerLibrary.base.robotlibcore import keyword @@ -9,6 +10,9 @@ def __init__(self, ctx): super().__init__(ctx) self.async_func = WaitingKeywordsAsync(self.ctx) + def get_async_keyword_group(self) -> iWaitingAsync: + return self.ctx.get_current_library_context().get_async_keyword_group(type(self).__name__) + @keyword def wait_for_request_url(self, url, method='GET', body=None, timeout=None): """ @@ -100,7 +104,8 @@ def wait_until_page_contains_element(self, locator, timeout=None): | Open browser | ${HOME_PAGE_URL} | options=${options} | | `Wait Until Page Contains Element` | id:username | | """ - return self.loop.run_until_complete(self.async_func.wait_until_page_contains_element_async(locator, timeout)) + self.loop.run_until_complete(self.get_async_keyword_group().wait_until_page_contains_element(locator, timeout)) + # return self.loop.run_until_complete(self.async_func.wait_until_page_contains_element_async(locator, timeout)) @keyword def wait_until_element_is_hidden(self, locator, timeout=None): diff --git a/PuppeteerLibrary/library_context/ilibrary_context.py b/PuppeteerLibrary/library_context/ilibrary_context.py index 5af22cb..bdab19c 100644 --- a/PuppeteerLibrary/library_context/ilibrary_context.py +++ b/PuppeteerLibrary/library_context/ilibrary_context.py @@ -49,7 +49,3 @@ async def close_browser_context(self): @abstractmethod def get_async_keyword_group(self, keyword_group_name: str): pass - - @abstractmethod - def waitForSelector_with_selenium_locator(self): - pass diff --git a/PuppeteerLibrary/playwright/async_keywords/playwright_waiting.py b/PuppeteerLibrary/playwright/async_keywords/playwright_waiting.py index b5ac140..98cb660 100644 --- a/PuppeteerLibrary/playwright/async_keywords/playwright_waiting.py +++ b/PuppeteerLibrary/playwright/async_keywords/playwright_waiting.py @@ -20,7 +20,7 @@ async def wait_for_navigation(self): pass async def wait_until_page_contains_element(self, locator, timeout=None): - pass + return await self._wait_for_selenium_selector(locator, timeout, visible=False, hidden=False) async def wait_until_element_is_hidden(self, locator, timeout=None): pass diff --git a/PuppeteerLibrary/playwright/custom_elements/playwright_page.py b/PuppeteerLibrary/playwright/custom_elements/playwright_page.py index 6f6871a..1166762 100644 --- a/PuppeteerLibrary/playwright/custom_elements/playwright_page.py +++ b/PuppeteerLibrary/playwright/custom_elements/playwright_page.py @@ -63,25 +63,20 @@ async def type_xpath(self, selector, text: str, options: dict = None, **kwargs: # Wait ############ async def waitForSelector_with_selenium_locator(self, selenium_locator: str, timeout: float, visible=False, hidden=False): - pass - ''' options = { 'timeout': timeout * 1000, - 'visible': visible, - 'hidden': hidden + 'state': 'visible' } - selector_value = SelectorAbstraction.get_selector(selenium_locator) - if SelectorAbstraction.is_xpath(selenium_locator): - return await self.waitForXPath(xpath=selector_value, options=options) - else: - return await self.waitForSelector(selector=selector_value, options=options) - ''' + if visible is True: + options['state'] = 'visible' + if hidden is True: + options['state'] = 'hidden' - async def waitForXPath(self, xpath: str, options: dict = None, **kwargs: Any): - pass - - async def waitForSelector(self, selector: str, options: dict = None, **kwargs: Any): - pass + selector_value = SelectorAbstraction.get_selector(selenium_locator) + return await self.get_page().waitForSelector( + selector=selector_value, + timeout=options['timeout'], + state=options['state']) ############ # Query From e394a1bccf204cbe09da51b83f91a0203891d6ef Mon Sep 17 00:00:00 2001 From: atthaboons Date: Fri, 16 Oct 2020 07:34:55 +0700 Subject: [PATCH 020/103] Support switch library context --- .../open-close-browser.robot | 19 ++++++++++++------- PuppeteerLibrary/__init__.py | 8 +++++++- .../keywords/browsermanagement.py | 2 +- .../playwright_browsermanagement.py | 2 +- 4 files changed, 21 insertions(+), 10 deletions(-) diff --git a/Examples/browser-management/open-close-browser.robot b/Examples/browser-management/open-close-browser.robot index db3a80d..bc46ec7 100644 --- a/Examples/browser-management/open-close-browser.robot +++ b/Examples/browser-management/open-close-browser.robot @@ -3,10 +3,14 @@ Library PuppeteerLibrary Suite Teardown Close Puppeteer Test Teardown Close All Browser +*** Variables *** +# ${DEFAULT_BROWSER} chrome +${DEFAULT_BROWSER} webkit + + *** Test Cases *** Switch to new browser - # ${BROWSER} = Get variable value ${BROWSER} chrome - ${BROWSER} = Get variable value ${BROWSER} webkit + ${BROWSER} = Get variable value ${BROWSER} ${DEFAULT_BROWSER} ${HEADLESS} = Get variable value ${HEADLESS} ${False} &{options} = create dictionary headless=${HEADLESS} Open browser http://127.0.0.1:7272/basic-html-elements.html browser=${BROWSER} options=${options} @@ -19,16 +23,17 @@ Switch to new browser Wait Until Page Contains Element id=open-new-tab Handle multiple browser + ${BROWSER} = Get variable value ${BROWSER} ${DEFAULT_BROWSER} ${HEADLESS} Get variable value ${HEADLESS} ${False} &{options} = create dictionary headless=${HEADLESS} - Open browser http://127.0.0.1:7272/basic-html-elements.html options=${options} alias=Browser 1 + Open browser http://127.0.0.1:7272/basic-html-elements.html browser=${BROWSER} options=${options} alias=Browser 1 Run Async Keywords ... Wait For New Window Open AND ... Click Element id=open-new-tab Switch Window NEW - Open browser http://127.0.0.1:7272/basic-html-elements.html options=${options} alias=Browser 2 + Open browser http://127.0.0.1:7272/basic-html-elements.html browser=${BROWSER} options=${options} alias=Browser 2 Switch Browser Browser 1 - Wait Until Page Contains Login form - Switch Browser Browser 2 - Wait Until Page Contains Browser Management + # Wait Until Page Contains Login form + # Switch Browser Browser 2 + # Wait Until Page Contains Browser Management \ No newline at end of file diff --git a/PuppeteerLibrary/__init__.py b/PuppeteerLibrary/__init__.py index 9aca91d..23d1104 100644 --- a/PuppeteerLibrary/__init__.py +++ b/PuppeteerLibrary/__init__.py @@ -149,6 +149,12 @@ def __init__(self): @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) -> BrowserContext: + self.current_library_context_name = context_name + context = self.get_current_library_context() + return context @not_keyword def get_library_context_by_name(self, alias: str) -> iLibraryContext: @@ -163,7 +169,7 @@ 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 load_async_keywords(self): diff --git a/PuppeteerLibrary/keywords/browsermanagement.py b/PuppeteerLibrary/keywords/browsermanagement.py index 74308f6..b57f7bf 100644 --- a/PuppeteerLibrary/keywords/browsermanagement.py +++ b/PuppeteerLibrary/keywords/browsermanagement.py @@ -201,7 +201,7 @@ async def switch_window_async(): def switch_browser(self, alias): """Switch browser context based on alias name """ - return self.loop.run_until_complete(self.ctx.set_current_context(alias)) + return self.loop.run_until_complete(self.ctx.set_current_library_context(alias)) @keyword def enable_emulate_mode(self, emulate_name): diff --git a/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py b/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py index 8e27300..532a236 100644 --- a/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py +++ b/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py @@ -44,7 +44,7 @@ async def get_window_count(self): return -1 return len(await self.library_ctx.get_browser().pages()) ''' - + async def wait_for_new_window_open(self, timeout=None): page_len = 0 # Workaround: From 6d7d75e19ab03a191e492c90a2dd5293a4773439 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Fri, 16 Oct 2020 23:15:21 +0700 Subject: [PATCH 021/103] Add capture screenshot --- .../open-close-browser.robot | 1 + .../keywords/iscreenshot_async.py | 11 +++++ PuppeteerLibrary/keywords/screenshot.py | 40 ++++++++++++++++++- PuppeteerLibrary/keywords/waiting.py | 3 +- .../async_keywords/playwright_screenshot.py | 13 ++++++ .../async_keywords/playwright_waiting.py | 13 +++++- .../playwright/playwright_context.py | 2 + 7 files changed, 79 insertions(+), 4 deletions(-) create mode 100644 PuppeteerLibrary/keywords/iscreenshot_async.py create mode 100644 PuppeteerLibrary/playwright/async_keywords/playwright_screenshot.py diff --git a/Examples/browser-management/open-close-browser.robot b/Examples/browser-management/open-close-browser.robot index bc46ec7..ef9120f 100644 --- a/Examples/browser-management/open-close-browser.robot +++ b/Examples/browser-management/open-close-browser.robot @@ -23,6 +23,7 @@ Switch to new browser Wait Until Page Contains Element id=open-new-tab Handle multiple browser + [Teardown] Capture Page Screenshot ${BROWSER} = Get variable value ${BROWSER} ${DEFAULT_BROWSER} ${HEADLESS} Get variable value ${HEADLESS} ${False} &{options} = create dictionary headless=${HEADLESS} diff --git a/PuppeteerLibrary/keywords/iscreenshot_async.py b/PuppeteerLibrary/keywords/iscreenshot_async.py new file mode 100644 index 0000000..6e78ba6 --- /dev/null +++ b/PuppeteerLibrary/keywords/iscreenshot_async.py @@ -0,0 +1,11 @@ +from PuppeteerLibrary.keywords.base_async_keywords import BaseAsyncKeywords +from abc import ABC, abstractmethod + + +class iScreenshotAsync(BaseAsyncKeywords, ABC): + + @abstractmethod + async def capture_page_screenshot(self, path: str): + pass + + \ No newline at end of file diff --git a/PuppeteerLibrary/keywords/screenshot.py b/PuppeteerLibrary/keywords/screenshot.py index b92e3ad..2147787 100644 --- a/PuppeteerLibrary/keywords/screenshot.py +++ b/PuppeteerLibrary/keywords/screenshot.py @@ -1,3 +1,6 @@ +from PuppeteerLibrary.keywords.iscreenshot_async import iScreenshotAsync +import os +from robot.utils import get_link_path from PuppeteerLibrary.base.librarycomponent import LibraryComponent from PuppeteerLibrary.base.robotlibcore import keyword from PuppeteerLibrary.keywords.screenshot_async import ScreenshotKeywordsAsync, DEFAULT_FILENAME_PAGE @@ -7,8 +10,12 @@ class ScreenshotKeywords(LibraryComponent): def __init__(self, ctx): super().__init__(ctx) + self.log_dir = os.curdir self.async_func = ScreenshotKeywordsAsync(self.ctx) + def get_async_keyword_group(self) -> iScreenshotAsync: + return self.ctx.get_current_library_context().get_async_keyword_group(type(self).__name__) + @keyword def capture_page_screenshot(self, filename=DEFAULT_FILENAME_PAGE): """ @@ -23,4 +30,35 @@ def capture_page_screenshot(self, filename=DEFAULT_FILENAME_PAGE): | Capture page screenshot | custom-{index}.png | """ - return self.loop.run_until_complete(self.async_func.capture_page_screenshot_async(filename)) + path = self._get_screenshot_path(filename) + self.loop.run_until_complete(self.get_async_keyword_group().capture_page_screenshot(path)) + self._embed_to_log_as_file(path, 800) + + def _get_screenshot_path(self, filename): + directory = self.log_dir + filename = filename.replace('/', os.sep) + index = 0 + while True: + index += 1 + formatted = self._format_path(filename, index) + path = os.path.join(directory, formatted) + if formatted == filename or not os.path.exists(path): + return path + + def _format_path(self, file_path, index): + return file_path.format_map(_SafeFormatter(index=index)) + + def _embed_to_log_as_file(self, path, width): + """ + Image is shown on its own row and thus previous row is closed on purpose. + Depending on Robot's log structure is a bit risky. + + """ + self.info('' + '' + .format(src=get_link_path(path, self.log_dir), width=width), html=True) + +class _SafeFormatter(dict): + + def __missing__(self, key): + return '{%s}' % key diff --git a/PuppeteerLibrary/keywords/waiting.py b/PuppeteerLibrary/keywords/waiting.py index cb3b267..8bd95de 100644 --- a/PuppeteerLibrary/keywords/waiting.py +++ b/PuppeteerLibrary/keywords/waiting.py @@ -144,7 +144,8 @@ def wait_until_page_contains(self, text, timeout=None): | ... | Wait For Navigation | | | | `Wait Until Page Contains` | Invalid user name or password | | | """ - return self.loop.run_until_complete(self.async_func.wait_until_page_contains_async(text, timeout)) + self.loop.run_until_complete(self.get_async_keyword_group().wait_until_page_contains(text, timeout)) + # return self.loop.run_until_complete(self.async_func.wait_until_page_contains_async(text, timeout)) @keyword def wait_until_page_does_not_contains(self, text, timeout=None): diff --git a/PuppeteerLibrary/playwright/async_keywords/playwright_screenshot.py b/PuppeteerLibrary/playwright/async_keywords/playwright_screenshot.py new file mode 100644 index 0000000..72e83d3 --- /dev/null +++ b/PuppeteerLibrary/playwright/async_keywords/playwright_screenshot.py @@ -0,0 +1,13 @@ +from PuppeteerLibrary.playwright.async_keywords.playwright_waiting import PlaywrightWaiting +from PuppeteerLibrary.keywords.iscreenshot_async import iScreenshotAsync + + +class PlaywrightScreenshot(iScreenshotAsync): + + def __init__(self, library_ctx): + super().__init__(library_ctx) + + async def capture_page_screenshot(self, path: str): + return await self.library_ctx.get_current_page().get_page().screenshot( + path=f''+path + ) diff --git a/PuppeteerLibrary/playwright/async_keywords/playwright_waiting.py b/PuppeteerLibrary/playwright/async_keywords/playwright_waiting.py index 98cb660..ec48055 100644 --- a/PuppeteerLibrary/playwright/async_keywords/playwright_waiting.py +++ b/PuppeteerLibrary/playwright/async_keywords/playwright_waiting.py @@ -9,6 +9,14 @@ def __init__(self, library_ctx): async def _wait_for_selenium_selector(self, selenium_locator, timeout=None, visible=False, hidden=False): timeout = self.timestr_to_secs_for_default_timeout(timeout) return await self.library_ctx.get_current_page().waitForSelector_with_selenium_locator(selenium_locator, timeout, visible, hidden) + + def escape_xpath_value(self, value): + if '"' in value and '\'' in value: + parts_wo_apos = value.split('\'') + return "concat('%s')" % "', \"'\", '".join(parts_wo_apos) + if '\'' in value: + return "\"%s\"" % value + return "'%s'" % value async def wait_for_request_url(self, url, method='GET', body=None, timeout=None): pass @@ -20,7 +28,7 @@ async def wait_for_navigation(self): pass async def wait_until_page_contains_element(self, locator, timeout=None): - return await self._wait_for_selenium_selector(locator, timeout, visible=False, hidden=False) + return await self._wait_for_selenium_selector(locator, timeout, visible=True, hidden=False) async def wait_until_element_is_hidden(self, locator, timeout=None): pass @@ -29,7 +37,8 @@ async def wait_until_element_is_visible(self, locator, timeout=None): pass async def wait_until_page_contains(self, text, timeout=None): - pass + locator = "xpath://*[contains(., %s)]" % self.escape_xpath_value(text) + return await self._wait_for_selenium_selector(locator, timeout, visible=True, hidden=False) async def wait_until_page_does_not_contains(self, text, timeout=None): pass diff --git a/PuppeteerLibrary/playwright/playwright_context.py b/PuppeteerLibrary/playwright/playwright_context.py index 4c28ef8..4fd3738 100644 --- a/PuppeteerLibrary/playwright/playwright_context.py +++ b/PuppeteerLibrary/playwright/playwright_context.py @@ -1,3 +1,4 @@ +from PuppeteerLibrary.playwright.async_keywords.playwright_screenshot import PlaywrightScreenshot from PuppeteerLibrary.playwright.async_keywords.playwright_waiting import PlaywrightWaiting from PuppeteerLibrary.custom_elements.base_page import BasePage from PuppeteerLibrary.playwright.async_keywords.playwright_element import PlaywrightElement @@ -64,6 +65,7 @@ def get_async_keyword_group(self, keyword_group_name: str): switcher = { "BrowserManagementKeywords": PlaywrightBrowserManagement(self), "ElementKeywords": PlaywrightElement(self), + "ScreenshotKeywords": PlaywrightScreenshot(self), "WaitingKeywords": PlaywrightWaiting(self) } return switcher.get(keyword_group_name) From 0e5c4e4a156eb538fed3325f28d0a43bb686f159 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Fri, 16 Oct 2020 23:30:03 +0700 Subject: [PATCH 022/103] Fix switch browser context --- Examples/browser-management/open-close-browser.robot | 6 +++--- PuppeteerLibrary/__init__.py | 7 +++---- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/Examples/browser-management/open-close-browser.robot b/Examples/browser-management/open-close-browser.robot index ef9120f..da7c4c0 100644 --- a/Examples/browser-management/open-close-browser.robot +++ b/Examples/browser-management/open-close-browser.robot @@ -34,7 +34,7 @@ Handle multiple browser Switch Window NEW Open browser http://127.0.0.1:7272/basic-html-elements.html browser=${BROWSER} options=${options} alias=Browser 2 Switch Browser Browser 1 - # Wait Until Page Contains Login form - # Switch Browser Browser 2 - # Wait Until Page Contains Browser Management + Wait Until Page Contains Login form + Switch Browser Browser 2 + Wait Until Page Contains Browser Management \ No newline at end of file diff --git a/PuppeteerLibrary/__init__.py b/PuppeteerLibrary/__init__.py index 23d1104..816a776 100644 --- a/PuppeteerLibrary/__init__.py +++ b/PuppeteerLibrary/__init__.py @@ -151,10 +151,9 @@ def get_current_library_context(self) -> iLibraryContext: return self.current_libary_context @not_keyword - async def set_current_library_context(self, context_name) -> BrowserContext: - self.current_library_context_name = context_name - context = self.get_current_library_context() - return context + async def set_current_library_context(self, context_name) -> iLibraryContext: + self.current_libary_context = self.library_contexts[context_name] + return self.current_libary_context @not_keyword def get_library_context_by_name(self, alias: str) -> iLibraryContext: From 9f926785fad8bd21783259c5f0b093d632506161 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Sat, 17 Oct 2020 09:52:29 +0700 Subject: [PATCH 023/103] Add ignore test --- Examples/alert-handler/alert-handler.robot | 1 + Examples/api/mock-api.robot | 1 + .../browser-management/emulator-mode.robot | 1 + Examples/debug-mode/enable-debug-mode.robot | 1 + Examples/form-handler/dropdown-list.robot | 1 + .../form-handler/element-properties.robot | 1 + Examples/form-handler/file-upload.robot | 1 + Examples/form-handler/form-submit.robot | 1 + Examples/form-handler/iframe.robot | 1 + Examples/input/mouse.robot | 1 + Examples/utilities/asyncio.robot | 1 + Examples/utilities/execute-javascript.robot | 1 + Examples/utilities/generate-pdf.robot | 1 + Examples/utilities/log-messages.robot | 1 + Examples/utilities/screenshot.robot | 1 + Examples/utilities/timeout.robot | 1 + Examples/utilities/wait.robot | 1 + Examples/webkit/playwright-browser.robot | 15 --- .../custom_elements/playwright_page.py | 2 +- .../puppeteer/custom_elements/__init__.py | 0 .../custom_elements/puppeteer_page.py | 103 ++++++++++++++++++ .../puppeteer/puppeteer_context.py | 22 +++- 22 files changed, 141 insertions(+), 18 deletions(-) delete mode 100644 Examples/webkit/playwright-browser.robot create mode 100644 PuppeteerLibrary/puppeteer/custom_elements/__init__.py create mode 100644 PuppeteerLibrary/puppeteer/custom_elements/puppeteer_page.py diff --git a/Examples/alert-handler/alert-handler.robot b/Examples/alert-handler/alert-handler.robot index f8eabe0..2837385 100644 --- a/Examples/alert-handler/alert-handler.robot +++ b/Examples/alert-handler/alert-handler.robot @@ -1,4 +1,5 @@ *** Settings *** +Force Tags Ignore Library PuppeteerLibrary Test Setup Open browser to test page Test Teardown Close All Browser diff --git a/Examples/api/mock-api.robot b/Examples/api/mock-api.robot index ca01128..3fbb1de 100644 --- a/Examples/api/mock-api.robot +++ b/Examples/api/mock-api.robot @@ -1,4 +1,5 @@ *** Settings *** +Force Tags Ignore Library PuppeteerLibrary Test Setup Open browser to test page Test Teardown Close All Browser diff --git a/Examples/browser-management/emulator-mode.robot b/Examples/browser-management/emulator-mode.robot index bf35332..d477432 100644 --- a/Examples/browser-management/emulator-mode.robot +++ b/Examples/browser-management/emulator-mode.robot @@ -1,4 +1,5 @@ *** Settings *** +Force Tags Ignore Library PuppeteerLibrary Suite Teardown Close Puppeteer diff --git a/Examples/debug-mode/enable-debug-mode.robot b/Examples/debug-mode/enable-debug-mode.robot index df31d0c..4297a88 100644 --- a/Examples/debug-mode/enable-debug-mode.robot +++ b/Examples/debug-mode/enable-debug-mode.robot @@ -1,4 +1,5 @@ *** Settings *** +Force Tags Ignore Library PuppeteerLibrary Test Teardown Close All Browser Suite Teardown Close Puppeteer diff --git a/Examples/form-handler/dropdown-list.robot b/Examples/form-handler/dropdown-list.robot index 872d46c..bf03b95 100644 --- a/Examples/form-handler/dropdown-list.robot +++ b/Examples/form-handler/dropdown-list.robot @@ -1,4 +1,5 @@ *** Settings *** +Force Tags Ignore Library PuppeteerLibrary Test Setup Open browser to test page Test Teardown Close All Browser diff --git a/Examples/form-handler/element-properties.robot b/Examples/form-handler/element-properties.robot index cf5dfc4..0fc88f9 100644 --- a/Examples/form-handler/element-properties.robot +++ b/Examples/form-handler/element-properties.robot @@ -1,4 +1,5 @@ *** Settings *** +Force Tags Ignore Library PuppeteerLibrary Test Setup Open browser to test page Test Teardown Close All Browser diff --git a/Examples/form-handler/file-upload.robot b/Examples/form-handler/file-upload.robot index 7fb6877..136554b 100644 --- a/Examples/form-handler/file-upload.robot +++ b/Examples/form-handler/file-upload.robot @@ -1,4 +1,5 @@ *** Settings *** +Force Tags Ignore Library PuppeteerLibrary Test Setup Open browser to test page Test Teardown Close All Browser diff --git a/Examples/form-handler/form-submit.robot b/Examples/form-handler/form-submit.robot index b6654a3..711e4c4 100644 --- a/Examples/form-handler/form-submit.robot +++ b/Examples/form-handler/form-submit.robot @@ -1,4 +1,5 @@ *** Settings *** +Force Tags Ignore Library PuppeteerLibrary Test Teardown Close All Browser Suite Teardown Close Puppeteer diff --git a/Examples/form-handler/iframe.robot b/Examples/form-handler/iframe.robot index ae260dd..0fa0669 100644 --- a/Examples/form-handler/iframe.robot +++ b/Examples/form-handler/iframe.robot @@ -1,4 +1,5 @@ *** Settings *** +Force Tags Ignore Library PuppeteerLibrary Test Setup Open browser to test page Test Teardown Close All Browser diff --git a/Examples/input/mouse.robot b/Examples/input/mouse.robot index 21c9ea7..daec50b 100644 --- a/Examples/input/mouse.robot +++ b/Examples/input/mouse.robot @@ -1,4 +1,5 @@ *** Settings *** +Force Tags Ignore Library PuppeteerLibrary Test Setup Open browser to test page Test Teardown Close All Browser diff --git a/Examples/utilities/asyncio.robot b/Examples/utilities/asyncio.robot index efb330f..fa65f4d 100644 --- a/Examples/utilities/asyncio.robot +++ b/Examples/utilities/asyncio.robot @@ -1,4 +1,5 @@ *** Settings *** +Force Tags Ignore Library PuppeteerLibrary Test Setup Open browser to test page Test Teardown Close All Browser diff --git a/Examples/utilities/execute-javascript.robot b/Examples/utilities/execute-javascript.robot index 9995ce3..54b96e4 100644 --- a/Examples/utilities/execute-javascript.robot +++ b/Examples/utilities/execute-javascript.robot @@ -1,4 +1,5 @@ *** Settings *** +Force Tags Ignore Library PuppeteerLibrary Test Setup Open browser to test page Test Teardown Close Browser diff --git a/Examples/utilities/generate-pdf.robot b/Examples/utilities/generate-pdf.robot index 81b3bac..241e512 100644 --- a/Examples/utilities/generate-pdf.robot +++ b/Examples/utilities/generate-pdf.robot @@ -1,4 +1,5 @@ *** Settings *** +Force Tags Ignore Library PuppeteerLibrary Test Setup Open browser to test page Test Teardown Close All Browser diff --git a/Examples/utilities/log-messages.robot b/Examples/utilities/log-messages.robot index a05ae38..8fd4153 100644 --- a/Examples/utilities/log-messages.robot +++ b/Examples/utilities/log-messages.robot @@ -1,4 +1,5 @@ *** Settings *** +Force Tags Ignore Library PuppeteerLibrary Test Setup Open browser to test page Test Teardown Close Browser diff --git a/Examples/utilities/screenshot.robot b/Examples/utilities/screenshot.robot index 1c917ae..eba7d8e 100644 --- a/Examples/utilities/screenshot.robot +++ b/Examples/utilities/screenshot.robot @@ -1,4 +1,5 @@ *** Settings *** +Force Tags Ignore Library PuppeteerLibrary Test Setup Open browser to test page Test Teardown Close Browser diff --git a/Examples/utilities/timeout.robot b/Examples/utilities/timeout.robot index a03353f..32736ec 100644 --- a/Examples/utilities/timeout.robot +++ b/Examples/utilities/timeout.robot @@ -1,4 +1,5 @@ *** Settings *** +Force Tags Ignore Library PuppeteerLibrary Test Setup Open test browser Test Teardown Close Browser diff --git a/Examples/utilities/wait.robot b/Examples/utilities/wait.robot index 9b677eb..a8ac211 100644 --- a/Examples/utilities/wait.robot +++ b/Examples/utilities/wait.robot @@ -1,4 +1,5 @@ *** Settings *** +Force Tags Ignore Library PuppeteerLibrary Test Teardown Close Browser diff --git a/Examples/webkit/playwright-browser.robot b/Examples/webkit/playwright-browser.robot deleted file mode 100644 index 289c1a5..0000000 --- a/Examples/webkit/playwright-browser.robot +++ /dev/null @@ -1,15 +0,0 @@ -*** Settings *** -Library PuppeteerLibrary -Library Dialogs - -*** Test Cases *** -New open browser - [Teardown] New Close Puppeteer - ${HEADLESS} Get variable value ${HEADLESS} ${False} - &{options} = create dictionary headless=${HEADLESS} - New Open Browser https://www.google.com browser=webkit alias=B1 options=${options} - Go To https://www.youtube.com - # Run Async Keywords - # ... Go To https://www.youtube.com AND - # ... Go To https://www.youtube.com - New Close Browser diff --git a/PuppeteerLibrary/playwright/custom_elements/playwright_page.py b/PuppeteerLibrary/playwright/custom_elements/playwright_page.py index 1166762..02f6f90 100644 --- a/PuppeteerLibrary/playwright/custom_elements/playwright_page.py +++ b/PuppeteerLibrary/playwright/custom_elements/playwright_page.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, Optional +from typing import Any from PuppeteerLibrary.custom_elements.base_page import BasePage from PuppeteerLibrary.locators.SelectorAbstraction import SelectorAbstraction try: diff --git a/PuppeteerLibrary/puppeteer/custom_elements/__init__.py b/PuppeteerLibrary/puppeteer/custom_elements/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/PuppeteerLibrary/puppeteer/custom_elements/puppeteer_page.py b/PuppeteerLibrary/puppeteer/custom_elements/puppeteer_page.py new file mode 100644 index 0000000..49a12ed --- /dev/null +++ b/PuppeteerLibrary/puppeteer/custom_elements/puppeteer_page.py @@ -0,0 +1,103 @@ +from typing import Any +from pyppeteer.page import Page +from PuppeteerLibrary.custom_elements.base_page import BasePage +from PuppeteerLibrary.locators.SelectorAbstraction import SelectorAbstraction + + +class PuppeteerPage(BasePage): + + def __init__(self, page: Page): + self.page = page + self.selected_iframe = None + + def get_page(self) -> Page: + return self.page + + async def goto(self, url: str): + pass + # return await self.page.goto(url) + + async def go_back(self): + pass + # return await self.page.goBack() + + async def reload_page(self): + pass + # return await self.page.reload() + + async def title(self): + pass + # return await self.page.title() + + async def set_viewport_size(self, width: int, height: int): + pass + # return await self.page.setViewportSize(width, height) + + ############ + # Click + ############ + async def click(self, selector: str, options: dict = None, **kwargs: Any): + pass + ''' + if self.selected_iframe is None: + return await self.page.click(selector=selector, options=options, kwargs=kwargs) + else: + return await self.selected_iframe.click(selector=selector, options=options, kwargs=kwargs) + ''' + + async def click_with_selenium_locator(self, selenium_locator: str, options: dict = None, **kwargs: Any): + pass + ''' + selector_value = SelectorAbstraction.get_selector(selenium_locator) + if SelectorAbstraction.is_xpath(selenium_locator): + await self.page.click_xpath(selector_value, options, **kwargs) + else: + await self.page.click(selector_value, options, **kwargs) + ''' + + async def click_xpath(self, selector: str, options: dict = None, **kwargs: Any): + pass + + ############ + # Type + ############ + async def type_with_selenium_locator(self, selenium_locator: str, text: str, options: dict = None, **kwargs: Any): + pass + + async def type_xpath(self, selector, text: str, options: dict = None, **kwargs: Any): + pass + + ############ + # Wait + ############ + async def waitForSelector_with_selenium_locator(self, selenium_locator: str, timeout: float, visible=False, hidden=False): + pass + ''' + options = { + 'timeout': timeout * 1000, + 'state': 'visible' + } + if visible is True: + options['state'] = 'visible' + if hidden is True: + options['state'] = 'hidden' + + selector_value = SelectorAbstraction.get_selector(selenium_locator) + return await self.get_page().waitForSelector( + selector=selector_value, + timeout=options['timeout'], + state=options['state']) + ''' + + ############ + # Query + ############ + async def querySelector(self, selector: str): + pass + + async def querySelectorAll_with_selenium_locator(self, selenium_locator: str): + pass + + async def querySelector_with_selenium_locator(self, selenium_locator: str): + pass + diff --git a/PuppeteerLibrary/puppeteer/puppeteer_context.py b/PuppeteerLibrary/puppeteer/puppeteer_context.py index 62e4617..d133bd0 100644 --- a/PuppeteerLibrary/puppeteer/puppeteer_context.py +++ b/PuppeteerLibrary/puppeteer/puppeteer_context.py @@ -1,11 +1,11 @@ import sys from pyppeteer import launch from pyppeteer.browser import Browser +from PuppeteerLibrary.custom_elements.base_page import BasePage from PuppeteerLibrary.library_context.ilibrary_context import iLibraryContext from PuppeteerLibrary.puppeteer.async_keywords.puppeteer_browsermanagement import PuppeteerBrowserManagement -# class PuppeteerContext(iLibraryContext): -class PuppeteerContext: +class PuppeteerContext(iLibraryContext): browser: Browser = None contexts = {} @@ -60,6 +60,24 @@ def is_server_started(self) -> bool: return True return False + async def create_new_page(self, options: dict=None) -> BasePage: + pass + + def get_current_page(self) -> BasePage: + pass + + def set_current_page(self, page: any) -> BasePage: + pass + + async def get_all_pages(self): + pass + + def get_browser_context(self): + pass + + async def close_browser_context(self): + pass + async def get_async_keyword_group(self, keyword_group_name: str): switcher = { "BrowserManagementKeywords": PuppeteerBrowserManagement(self) From e8ac2df6ca889a77eafed02fca902f5f18996050 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Sat, 17 Oct 2020 10:02:50 +0700 Subject: [PATCH 024/103] update git workflow support specific test browser --- .github/workflows/pythonpackage.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index 915efb8..df96440 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -9,7 +9,12 @@ jobs: strategy: max-parallel: 4 matrix: - python-version: [3.6, 3.7, 3.8] + # python-version: [3.6, 3.7, 3.8] + include: + - python-version: 3.7 + browser: webkit + - python-version: 3.8 + browser: webkit steps: - uses: actions/checkout@v1 @@ -34,4 +39,4 @@ jobs: pyppeteer-install pip install -r demoapp/requirements.txt python demoapp/server.py & - robot -v HEADLESS:True -e Ignore Examples + robot -v HEADLESS:True -v BROWSER:${{ matrix.browser }} -e Ignore Examples From 6193c92a3b4736f02f83283bb16bdd91550c76b2 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Sat, 17 Oct 2020 10:05:15 +0700 Subject: [PATCH 025/103] Install playwright --- .github/workflows/pythonpackage.yml | 1 + README.md | 1 + 2 files changed, 2 insertions(+) diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index df96440..b88b873 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -37,6 +37,7 @@ jobs: run: | python setup.py install pyppeteer-install + python -m playwright install pip install -r demoapp/requirements.txt python demoapp/server.py & robot -v HEADLESS:True -v BROWSER:${{ matrix.browser }} -e Ignore Examples diff --git a/README.md b/README.md index 2a4bfcc..9b07698 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ Installation The recommended installation method is using pip_:: pip install --upgrade robotframework-puppeteerlibrary + python -m playwright install Or manually install by running following command From 2f3de95534d3b1edfad6da12d2959c78fdca535b Mon Sep 17 00:00:00 2001 From: atthaboons Date: Sat, 17 Oct 2020 10:10:58 +0700 Subject: [PATCH 026/103] install playwright lib --- .github/workflows/pythonpackage.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index b88b873..9c1dc9d 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -38,6 +38,7 @@ jobs: python setup.py install pyppeteer-install python -m playwright install + sudo apt-get install libgles2 gstreamer1.0-libav pip install -r demoapp/requirements.txt python demoapp/server.py & robot -v HEADLESS:True -v BROWSER:${{ matrix.browser }} -e Ignore Examples From 24aa10abf37469366dfd2b07e20de15b93a19d13 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Sat, 17 Oct 2020 10:18:31 +0700 Subject: [PATCH 027/103] update library --- .github/workflows/pythonpackage.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index 9c1dc9d..d8383c7 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -26,6 +26,8 @@ jobs: run: | python -m pip install --upgrade pip pip install -r requirements.txt + sudo apt-get install libgles2 gstreamer1.0-libav + python -m playwright install - name: Lint with flake8 run: | pip install flake8 @@ -37,8 +39,6 @@ jobs: run: | python setup.py install pyppeteer-install - python -m playwright install - sudo apt-get install libgles2 gstreamer1.0-libav pip install -r demoapp/requirements.txt python demoapp/server.py & robot -v HEADLESS:True -v BROWSER:${{ matrix.browser }} -e Ignore Examples From 3761e0649909d6b03315a4de8556863039972957 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Sat, 17 Oct 2020 10:21:24 +0700 Subject: [PATCH 028/103] install webkit --- .github/workflows/pythonpackage.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index d8383c7..78a209a 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -39,6 +39,7 @@ jobs: run: | python setup.py install pyppeteer-install + python -m playwright install pip install -r demoapp/requirements.txt python demoapp/server.py & robot -v HEADLESS:True -v BROWSER:${{ matrix.browser }} -e Ignore Examples From 113388ce33f35fe20b9557d7a4e7ba1075379c11 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Sat, 17 Oct 2020 14:13:33 +0700 Subject: [PATCH 029/103] Install webkit --- .github/workflows/pythonpackage.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index 78a209a..db40056 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -13,8 +13,8 @@ jobs: include: - python-version: 3.7 browser: webkit - - python-version: 3.8 - browser: webkit + # - python-version: 3.8 + # browser: chrome steps: - uses: actions/checkout@v1 @@ -26,7 +26,12 @@ jobs: run: | python -m pip install --upgrade pip pip install -r requirements.txt + - name: Install webkit + run: | + sudo add-apt-repository ppa:webkit-team + sudo apt-get update sudo apt-get install libgles2 gstreamer1.0-libav + npm i playwright-webkit python -m playwright install - name: Lint with flake8 run: | From 872f221fe2942479f2aa47adf03e81f3a9d3777b Mon Sep 17 00:00:00 2001 From: atthaboons Date: Sat, 17 Oct 2020 14:26:41 +0700 Subject: [PATCH 030/103] install playwright webkit --- .github/workflows/pythonpackage.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index db40056..c772139 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -28,9 +28,6 @@ jobs: pip install -r requirements.txt - name: Install webkit run: | - sudo add-apt-repository ppa:webkit-team - sudo apt-get update - sudo apt-get install libgles2 gstreamer1.0-libav npm i playwright-webkit python -m playwright install - name: Lint with flake8 From a181852db247ce8e1f185798bd83a6a4eb1af0f2 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Sat, 17 Oct 2020 14:28:34 +0700 Subject: [PATCH 031/103] Add missing ubuntu lib --- .github/workflows/pythonpackage.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index c772139..0393cb1 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -28,6 +28,7 @@ jobs: pip install -r requirements.txt - name: Install webkit run: | + sudo apt-get install libgles2 gstreamer1.0-libav npm i playwright-webkit python -m playwright install - name: Lint with flake8 From 87f426916e659c27fdf021f094eb529f5d42fdf0 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Sat, 17 Oct 2020 14:49:59 +0700 Subject: [PATCH 032/103] update python --- .github/workflows/pythonpackage.yml | 5 ++--- Examples/browser-management/open-close-browser.robot | 2 ++ 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index 0393cb1..1ec1288 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -29,8 +29,8 @@ jobs: - name: Install webkit run: | sudo apt-get install libgles2 gstreamer1.0-libav - npm i playwright-webkit - python -m playwright install + pip3 install playwright + python3 -m playwright install - name: Lint with flake8 run: | pip install flake8 @@ -42,7 +42,6 @@ jobs: run: | python setup.py install pyppeteer-install - python -m playwright install pip install -r demoapp/requirements.txt python demoapp/server.py & robot -v HEADLESS:True -v BROWSER:${{ matrix.browser }} -e Ignore Examples diff --git a/Examples/browser-management/open-close-browser.robot b/Examples/browser-management/open-close-browser.robot index da7c4c0..ff02a27 100644 --- a/Examples/browser-management/open-close-browser.robot +++ b/Examples/browser-management/open-close-browser.robot @@ -1,5 +1,6 @@ *** Settings *** Library PuppeteerLibrary +Library Dialogs Suite Teardown Close Puppeteer Test Teardown Close All Browser @@ -21,6 +22,7 @@ Switch to new browser Wait Until Page Contains Element id=exampleInputEmail1 Switch Window title=Basic HTML Elements Wait Until Page Contains Element id=open-new-tab + Dialogs.Pause Execution Handle multiple browser [Teardown] Capture Page Screenshot From 1649c3d0a007af678f2d316ccdc7c34bc4be6b63 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Sat, 17 Oct 2020 14:52:41 +0700 Subject: [PATCH 033/103] Update to version 3 --- .github/workflows/pythonpackage.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index 1ec1288..bb40627 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -24,8 +24,8 @@ jobs: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | - python -m pip install --upgrade pip - pip install -r requirements.txt + python3 -m pip install --upgrade pip + pip3 install -r requirements.txt - name: Install webkit run: | sudo apt-get install libgles2 gstreamer1.0-libav @@ -40,8 +40,8 @@ jobs: flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics - name: System test run: | - python setup.py install + python3 setup.py install pyppeteer-install - pip install -r demoapp/requirements.txt - python demoapp/server.py & + pip3 install -r demoapp/requirements.txt + python3 demoapp/server.py & robot -v HEADLESS:True -v BROWSER:${{ matrix.browser }} -e Ignore Examples From 2c9e65c6beb5a4fbef616be3ace452d7dde14494 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Sat, 17 Oct 2020 14:58:42 +0700 Subject: [PATCH 034/103] no message --- .github/workflows/pythonpackage.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index bb40627..253a65f 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -44,4 +44,6 @@ jobs: pyppeteer-install pip3 install -r demoapp/requirements.txt python3 demoapp/server.py & + python3 -m playwright install + python -m playwright install robot -v HEADLESS:True -v BROWSER:${{ matrix.browser }} -e Ignore Examples From aeed8b62d1b5f74c74c442ead6838da08bd35fe1 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Sat, 17 Oct 2020 15:03:33 +0700 Subject: [PATCH 035/103] add recheck python version --- .github/workflows/pythonpackage.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index 253a65f..593b511 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -24,6 +24,8 @@ jobs: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | + python --version + python3 --versions python3 -m pip install --upgrade pip pip3 install -r requirements.txt - name: Install webkit @@ -46,4 +48,5 @@ jobs: python3 demoapp/server.py & python3 -m playwright install python -m playwright install + cat /home/runner/.cache/ms-playwright/webkit-1343 robot -v HEADLESS:True -v BROWSER:${{ matrix.browser }} -e Ignore Examples From 07b88bfb0a159cab4d111d3e55575c790de0c6be Mon Sep 17 00:00:00 2001 From: atthaboons Date: Sat, 17 Oct 2020 15:05:28 +0700 Subject: [PATCH 036/103] fix typo --- .github/workflows/pythonpackage.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index 593b511..8d8155f 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -25,7 +25,7 @@ jobs: - name: Install dependencies run: | python --version - python3 --versions + python3 --version python3 -m pip install --upgrade pip pip3 install -r requirements.txt - name: Install webkit From 8d39ad5af4df496063cfe58289934ef6afc1d051 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Sat, 17 Oct 2020 15:09:04 +0700 Subject: [PATCH 037/103] check webkit folder --- .github/workflows/pythonpackage.yml | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index 8d8155f..bd42a19 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -24,15 +24,13 @@ jobs: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | - python --version - python3 --version - python3 -m pip install --upgrade pip - pip3 install -r requirements.txt + python -m pip install --upgrade pip + pip install -r requirements.txt - name: Install webkit run: | sudo apt-get install libgles2 gstreamer1.0-libav - pip3 install playwright - python3 -m playwright install + pip install playwright + python -m playwright install - name: Lint with flake8 run: | pip install flake8 @@ -42,11 +40,10 @@ jobs: flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics - name: System test run: | - python3 setup.py install + python setup.py install pyppeteer-install - pip3 install -r demoapp/requirements.txt - python3 demoapp/server.py & - python3 -m playwright install + pip install -r demoapp/requirements.txt + python demoapp/server.py & python -m playwright install - cat /home/runner/.cache/ms-playwright/webkit-1343 + ls /home/runner/.cache/ms-playwright/webkit-1343 robot -v HEADLESS:True -v BROWSER:${{ matrix.browser }} -e Ignore Examples From b8632a50ca2d86cd552dac5542c340cd7ee514ee Mon Sep 17 00:00:00 2001 From: atthaboons Date: Sat, 17 Oct 2020 15:18:54 +0700 Subject: [PATCH 038/103] support ubuntu webkit --- .github/workflows/pythonpackage.yml | 44 +++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index bd42a19..765158f 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -28,7 +28,31 @@ jobs: pip install -r requirements.txt - name: Install webkit run: | - sudo apt-get install libgles2 gstreamer1.0-libav + apt-get update && apt-get install -y --no-install-recommends \ + gstreamer1.0-libav \ + libwoff1 \ + libopus0 \ + libwebp6 \ + libwebpdemux2 \ + libenchant1c2a \ + libgudev-1.0-0 \ + libsecret-1-0 \ + libhyphen0 \ + libgdk-pixbuf2.0-0 \ + libegl1 \ + libnotify4 \ + libxslt1.1 \ + libevent-2.1-6 \ + libgles2 \ + libvpx5 \ + libxcomposite1 \ + libatk1.0-0 \ + libatk-bridge2.0-0 \ + libepoxy0 \ + libgtk-3-0 \ + libharfbuzz-icu0 + apt-get install -y --no-install-recommends \ + xvfb pip install playwright python -m playwright install - name: Lint with flake8 @@ -39,11 +63,13 @@ jobs: # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics - name: System test - run: | - python setup.py install - pyppeteer-install - pip install -r demoapp/requirements.txt - python demoapp/server.py & - python -m playwright install - ls /home/runner/.cache/ms-playwright/webkit-1343 - robot -v HEADLESS:True -v BROWSER:${{ matrix.browser }} -e Ignore Examples + uses: GabrielBB/xvfb-action@v1 + with: + working-directory: ./ #optional + run: | + python setup.py install + pyppeteer-install + pip install -r demoapp/requirements.txt + python demoapp/server.py & + python -m playwright install + robot -v BROWSER:${{ matrix.browser }} -e Ignore Examples From 0d45cd6137af3724277dfeecada40698681cb7b2 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Sat, 17 Oct 2020 15:21:44 +0700 Subject: [PATCH 039/103] update path --- .github/workflows/pythonpackage.yml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index 765158f..726ce7a 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -63,13 +63,13 @@ jobs: # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics - name: System test - uses: GabrielBB/xvfb-action@v1 - with: - working-directory: ./ #optional - run: | - python setup.py install - pyppeteer-install - pip install -r demoapp/requirements.txt - python demoapp/server.py & - python -m playwright install - robot -v BROWSER:${{ matrix.browser }} -e Ignore Examples + uses: GabrielBB/xvfb-action@v1 + with: + working-directory: ./ #optional + run: | + python setup.py install + pyppeteer-install + pip install -r demoapp/requirements.txt + python demoapp/server.py & + python -m playwright install + robot -v BROWSER:${{ matrix.browser }} -e Ignore Examples From 15868e46908a7ee407406b80df4c20ace50833b4 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Sat, 17 Oct 2020 15:23:42 +0700 Subject: [PATCH 040/103] update install --- .github/workflows/pythonpackage.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index 726ce7a..2a0c2a0 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -28,7 +28,8 @@ jobs: pip install -r requirements.txt - name: Install webkit run: | - apt-get update && apt-get install -y --no-install-recommends \ + sudo apt-get update + sudo apt-get install -y --no-install-recommends \ gstreamer1.0-libav \ libwoff1 \ libopus0 \ @@ -50,8 +51,7 @@ jobs: libatk-bridge2.0-0 \ libepoxy0 \ libgtk-3-0 \ - libharfbuzz-icu0 - apt-get install -y --no-install-recommends \ + libharfbuzz-icu0 \ xvfb pip install playwright python -m playwright install From 6af8fd1bcebe8ee1f09fc145975b0ff0aa0ed980 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Sat, 17 Oct 2020 15:29:35 +0700 Subject: [PATCH 041/103] Refactor build flow --- .github/workflows/pythonpackage.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index 2a0c2a0..cb626d9 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -62,14 +62,14 @@ jobs: flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics + - name: Run test project + run: | + python setup.py install + pyppeteer-install + pip install -r demoapp/requirements.txt + python demoapp/server.py & - name: System test uses: GabrielBB/xvfb-action@v1 with: working-directory: ./ #optional - run: | - python setup.py install - pyppeteer-install - pip install -r demoapp/requirements.txt - python demoapp/server.py & - python -m playwright install - robot -v BROWSER:${{ matrix.browser }} -e Ignore Examples + run: robot -v BROWSER:${{ matrix.browser }} -e Ignore Examples From 37f764c14205dc551ead9870a2533942ba3283ba Mon Sep 17 00:00:00 2001 From: atthaboons Date: Sat, 17 Oct 2020 18:05:00 +0700 Subject: [PATCH 042/103] update python version --- .github/workflows/pythonpackage.yml | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index cb626d9..0ed9831 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -9,7 +9,7 @@ jobs: strategy: max-parallel: 4 matrix: - # python-version: [3.6, 3.7, 3.8] + # python-version: [3.7, 3.8, 3.9] include: - python-version: 3.7 browser: webkit @@ -24,8 +24,8 @@ jobs: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | - python -m pip install --upgrade pip - pip install -r requirements.txt + python${{ matrix.python-version }} -m pip${{ matrix.python-version }} install --upgrade pip${{ matrix.python-version }} + pip${{ matrix.python-version }} install -r requirements.txt - name: Install webkit run: | sudo apt-get update @@ -53,21 +53,20 @@ jobs: libgtk-3-0 \ libharfbuzz-icu0 \ xvfb - pip install playwright - python -m playwright install - name: Lint with flake8 run: | - pip install flake8 + pip${{ matrix.python-version }} install flake8 # stop the build if there are Python syntax errors or undefined names flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics - name: Run test project run: | - python setup.py install + python${{ matrix.python-version }} setup.py install + pip${{ matrix.python-version }} install -r demoapp/requirements.txt pyppeteer-install - pip install -r demoapp/requirements.txt - python demoapp/server.py & + python${{ matrix.python-version }} -m playwright install + python${{ matrix.python-version }} demoapp/server.py & - name: System test uses: GabrielBB/xvfb-action@v1 with: From b18a6f4160e63a725a68d98932b943ffe967669f Mon Sep 17 00:00:00 2001 From: atthaboons Date: Sat, 17 Oct 2020 18:07:23 +0700 Subject: [PATCH 043/103] update upgrade pip command --- .github/workflows/pythonpackage.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index 0ed9831..6dcf82e 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -24,7 +24,7 @@ jobs: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | - python${{ matrix.python-version }} -m pip${{ matrix.python-version }} install --upgrade pip${{ matrix.python-version }} + python${{ matrix.python-version }} -m pip install --upgrade pip pip${{ matrix.python-version }} install -r requirements.txt - name: Install webkit run: | From 5fc4b247490ec6e7d614122ae358fe1387ae29ba Mon Sep 17 00:00:00 2001 From: atthaboons Date: Sat, 17 Oct 2020 18:16:23 +0700 Subject: [PATCH 044/103] Update playwright version --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 01ee5e0..3127cba 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,5 +2,5 @@ versioneer>=0.18 robotframework>=3.2.1 # pyppeteer>=0.2.2 git+https://github.com/qahive/pyppeteer.git@dev -playwright==0.142.1 +playwright==0.151.0 robotframework-libdoc2json>=0.4 \ No newline at end of file From 7dfe49cfddf0a7b2e8310b950ff77f49908285af Mon Sep 17 00:00:00 2001 From: atthaboons Date: Sat, 17 Oct 2020 18:19:47 +0700 Subject: [PATCH 045/103] revert playwright version --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 3127cba..01ee5e0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,5 +2,5 @@ versioneer>=0.18 robotframework>=3.2.1 # pyppeteer>=0.2.2 git+https://github.com/qahive/pyppeteer.git@dev -playwright==0.151.0 +playwright==0.142.1 robotframework-libdoc2json>=0.4 \ No newline at end of file From 2b3f912318ed94a47547f035e2bd7c4edb18a2d5 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Sat, 17 Oct 2020 18:24:41 +0700 Subject: [PATCH 046/103] test run browser --- .github/workflows/pythonpackage.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index 6dcf82e..479bcb6 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -66,6 +66,7 @@ jobs: pip${{ matrix.python-version }} install -r demoapp/requirements.txt pyppeteer-install python${{ matrix.python-version }} -m playwright install + /home/runner/.cache/ms-playwright/webkit-1343/pw_run.sh python${{ matrix.python-version }} demoapp/server.py & - name: System test uses: GabrielBB/xvfb-action@v1 From a3cf8bef9ea0cf1e78ba3f272114536c59673f21 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Sat, 17 Oct 2020 18:30:46 +0700 Subject: [PATCH 047/103] add missing webkit lib --- .github/workflows/pythonpackage.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index 479bcb6..5fac29c 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -31,6 +31,8 @@ jobs: sudo apt-get update sudo apt-get install -y --no-install-recommends \ gstreamer1.0-libav \ + gstreamer1.0-plugins-bad \ + libgstreamer-plugins-bad1.0-0 \ libwoff1 \ libopus0 \ libwebp6 \ From b7adb7c37509cd28b378a26f178cdcf8e5111144 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Sat, 17 Oct 2020 18:33:32 +0700 Subject: [PATCH 048/103] remove running webkit browser --- .github/workflows/pythonpackage.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index 5fac29c..6c30143 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -68,7 +68,6 @@ jobs: pip${{ matrix.python-version }} install -r demoapp/requirements.txt pyppeteer-install python${{ matrix.python-version }} -m playwright install - /home/runner/.cache/ms-playwright/webkit-1343/pw_run.sh python${{ matrix.python-version }} demoapp/server.py & - name: System test uses: GabrielBB/xvfb-action@v1 From 688a230ead808f4d10e337d29af45bfbad39ccf8 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Sat, 17 Oct 2020 18:39:30 +0700 Subject: [PATCH 049/103] Remove dialogs pause --- Examples/browser-management/open-close-browser.robot | 2 -- 1 file changed, 2 deletions(-) diff --git a/Examples/browser-management/open-close-browser.robot b/Examples/browser-management/open-close-browser.robot index ff02a27..da7c4c0 100644 --- a/Examples/browser-management/open-close-browser.robot +++ b/Examples/browser-management/open-close-browser.robot @@ -1,6 +1,5 @@ *** Settings *** Library PuppeteerLibrary -Library Dialogs Suite Teardown Close Puppeteer Test Teardown Close All Browser @@ -22,7 +21,6 @@ Switch to new browser Wait Until Page Contains Element id=exampleInputEmail1 Switch Window title=Basic HTML Elements Wait Until Page Contains Element id=open-new-tab - Dialogs.Pause Execution Handle multiple browser [Teardown] Capture Page Screenshot From afb70192886051faca1333c419a8787c67b785be Mon Sep 17 00:00:00 2001 From: atthaboons Date: Sat, 17 Oct 2020 21:22:05 +0700 Subject: [PATCH 050/103] Remove fix python version --- .github/workflows/pythonpackage.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index 6c30143..7e97b4a 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -24,8 +24,8 @@ jobs: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | - python${{ matrix.python-version }} -m pip install --upgrade pip - pip${{ matrix.python-version }} install -r requirements.txt + python -m pip install --upgrade pip + pip install -r requirements.txt - name: Install webkit run: | sudo apt-get update @@ -57,18 +57,18 @@ jobs: xvfb - name: Lint with flake8 run: | - pip${{ matrix.python-version }} install flake8 + pip install flake8 # stop the build if there are Python syntax errors or undefined names flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics - name: Run test project run: | - python${{ matrix.python-version }} setup.py install - pip${{ matrix.python-version }} install -r demoapp/requirements.txt + python setup.py install + pip install -r demoapp/requirements.txt pyppeteer-install - python${{ matrix.python-version }} -m playwright install - python${{ matrix.python-version }} demoapp/server.py & + python -m playwright install + python demoapp/server.py & - name: System test uses: GabrielBB/xvfb-action@v1 with: From 46f7c1bbee2dcfbd01b1360f09274f69e5956b76 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Sat, 17 Oct 2020 22:51:50 +0700 Subject: [PATCH 051/103] Init support chrome playwright --- .../open-close-browser.robot | 18 ++--- .../keywords/browsermanagement.py | 8 --- .../puppeteer_browsermanagement.py | 65 +++++-------------- .../custom_elements/puppeteer_page.py | 3 +- .../puppeteer/puppeteer_context.py | 11 ++-- 5 files changed, 35 insertions(+), 70 deletions(-) diff --git a/Examples/browser-management/open-close-browser.robot b/Examples/browser-management/open-close-browser.robot index da7c4c0..5bda2bd 100644 --- a/Examples/browser-management/open-close-browser.robot +++ b/Examples/browser-management/open-close-browser.robot @@ -4,8 +4,8 @@ Suite Teardown Close Puppeteer Test Teardown Close All Browser *** Variables *** -# ${DEFAULT_BROWSER} chrome -${DEFAULT_BROWSER} webkit +${DEFAULT_BROWSER} chrome +# ${DEFAULT_BROWSER} webkit *** Test Cases *** @@ -14,13 +14,13 @@ Switch to new browser ${HEADLESS} = Get variable value ${HEADLESS} ${False} &{options} = create dictionary headless=${HEADLESS} Open browser http://127.0.0.1:7272/basic-html-elements.html browser=${BROWSER} options=${options} - Run Async Keywords - ... Click Element id=open-new-tab AND - ... Wait For New Window Open - Switch Window NEW - Wait Until Page Contains Element id=exampleInputEmail1 - Switch Window title=Basic HTML Elements - Wait Until Page Contains Element id=open-new-tab + # Run Async Keywords + # ... Click Element id=open-new-tab AND + # ... Wait For New Window Open + # Switch Window NEW + # Wait Until Page Contains Element id=exampleInputEmail1 + # Switch Window title=Basic HTML Elements + # Wait Until Page Contains Element id=open-new-tab Handle multiple browser [Teardown] Capture Page Screenshot diff --git a/PuppeteerLibrary/keywords/browsermanagement.py b/PuppeteerLibrary/keywords/browsermanagement.py index b57f7bf..85de45f 100644 --- a/PuppeteerLibrary/keywords/browsermanagement.py +++ b/PuppeteerLibrary/keywords/browsermanagement.py @@ -73,14 +73,6 @@ def maximize_browser_window(self, width=1366, height=768): self.info(('width: ' + str(width) + '\n' + 'height: ' + str(height))) self.loop.run_until_complete(self.get_async_keyword_group().maximize_browser_window(width, height)) - ''' - async def maximize_browser_window_async(): - await self.ctx.get_current_page().setViewport({ - 'width': width, - 'height': height - }) - self.loop.run_until_complete(maximize_browser_window_async()) - ''' @keyword def get_title(self): diff --git a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_browsermanagement.py b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_browsermanagement.py index 0c44459..23db236 100644 --- a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_browsermanagement.py +++ b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_browsermanagement.py @@ -9,55 +9,26 @@ class PuppeteerBrowserManagement(iBrowserManagementAsync): def __init__(self, library_ctx): super().__init__(library_ctx) - async def open_browser_async(self, url, browser, alias=None, options=None): - self.library_ctx.get_library_context(browser) - if self.library_ctx.puppeteer_browser is None: - default_args = [] - default_options = { - 'slowMo': 0, - 'headless': True, - 'devtools': False, - 'width': 1366, - 'height': 768 - } - merged_options = default_options - - if options is not None: - merged_options = {**merged_options, **options} - - if self.library_ctx.debug_mode is True: - merged_options = {**merged_options, - **self.library_ctx.debug_mode_options} - - if 'win' not in sys.platform.lower(): - default_args = ['--no-sandbox', '--disable-setuid-sandbox'] - - self.info(('Open browser to ' + url + '\n' + str(merged_options))) - self.puppeteer_browser = await launch( - headless=merged_options['headless'], - slowMo=merged_options['slowMo'], - devtools=merged_options['devtools'], - defaultViewport={ - 'width': merged_options['width'], - 'height': merged_options['height'] - }, - args=default_args) - - browser_context = await self.browser.createIncognitoBrowserContext() - await self.library_ctx.add_context_async(alias, browser_context) - current_page = await self._create_page_async() - await current_page.goto(url) - - async def close_browser_async(self, alias=None): + async def maximize_browser_window(self, width=1366, height=768): + return await self.ctx.get_current_page().setViewport({ + 'width': width, + 'height': height + }) + + async def go_to(self, url): + return await self.library_ctx.get_current_page().goto(url) + + async def go_back(self): + return await self.library_ctx.get_current_page().go_back() + + async def reload_page(self): + return await self.library_ctx.get_current_page().reload_page() + + async def get_window_count(self): pass - async def close_all_browser_async(self): + async def wait_for_new_window_open(self, timeout=None): pass - async def close_puppeteer_async(self): + async def switch_window(self, locator='MAIN'): pass - - async def _create_page_async(self) -> SPage: - new_page = await self.library_ctx.get_current_context().newPage() - self.library_ctx.set_current_page(new_page) - return self.library_ctx.get_current_page() diff --git a/PuppeteerLibrary/puppeteer/custom_elements/puppeteer_page.py b/PuppeteerLibrary/puppeteer/custom_elements/puppeteer_page.py index 49a12ed..069b506 100644 --- a/PuppeteerLibrary/puppeteer/custom_elements/puppeteer_page.py +++ b/PuppeteerLibrary/puppeteer/custom_elements/puppeteer_page.py @@ -14,8 +14,7 @@ def get_page(self) -> Page: return self.page async def goto(self, url: str): - pass - # return await self.page.goto(url) + return await self.page.goto(url) async def go_back(self): pass diff --git a/PuppeteerLibrary/puppeteer/puppeteer_context.py b/PuppeteerLibrary/puppeteer/puppeteer_context.py index d133bd0..c669686 100644 --- a/PuppeteerLibrary/puppeteer/puppeteer_context.py +++ b/PuppeteerLibrary/puppeteer/puppeteer_context.py @@ -1,3 +1,4 @@ +from PuppeteerLibrary.puppeteer.custom_elements.puppeteer_page import PuppeteerPage import sys from pyppeteer import launch from pyppeteer.browser import Browser @@ -39,7 +40,7 @@ async def start_server(self, options: dict=None): merged_options = {**merged_options, **self.debug_mode_options} if 'win' not in sys.platform.lower(): - default_args = ['--no-sandbox', '--disable-setuid-sandbox'] + default_args = ['--no-sandbox', '--disable-setuid-sandbox'] self.browser = await launch( headless=merged_options['headless'], @@ -61,10 +62,12 @@ def is_server_started(self) -> bool: return False async def create_new_page(self, options: dict=None) -> BasePage: - pass + new_page = await self.browser.newPage() + self.current_page = PuppeteerPage(new_page) + return self.current_page def get_current_page(self) -> BasePage: - pass + return self.current_page def set_current_page(self, page: any) -> BasePage: pass @@ -78,7 +81,7 @@ def get_browser_context(self): async def close_browser_context(self): pass - async def get_async_keyword_group(self, keyword_group_name: str): + def get_async_keyword_group(self, keyword_group_name: str): switcher = { "BrowserManagementKeywords": PuppeteerBrowserManagement(self) } From 9525e4c6a7d518cc1761afbd8db97361de875aec Mon Sep 17 00:00:00 2001 From: atthaboons Date: Sun, 18 Oct 2020 08:10:28 +0700 Subject: [PATCH 052/103] Add puppeteer page count --- .../open-close-browser.robot | 6 ++-- .../puppeteer_browsermanagement.py | 29 +++++++++++++++++-- .../async_keywords/puppeteer_element.py | 11 +++++++ .../custom_elements/puppeteer_page.py | 3 -- .../puppeteer/puppeteer_context.py | 10 ++++--- 5 files changed, 46 insertions(+), 13 deletions(-) create mode 100644 PuppeteerLibrary/puppeteer/async_keywords/puppeteer_element.py diff --git a/Examples/browser-management/open-close-browser.robot b/Examples/browser-management/open-close-browser.robot index 5bda2bd..acc832a 100644 --- a/Examples/browser-management/open-close-browser.robot +++ b/Examples/browser-management/open-close-browser.robot @@ -14,9 +14,9 @@ Switch to new browser ${HEADLESS} = Get variable value ${HEADLESS} ${False} &{options} = create dictionary headless=${HEADLESS} Open browser http://127.0.0.1:7272/basic-html-elements.html browser=${BROWSER} options=${options} - # Run Async Keywords - # ... Click Element id=open-new-tab AND - # ... Wait For New Window Open + Run Async Keywords + ... Click Element id=open-new-tab AND + ... Wait For New Window Open # Switch Window NEW # Wait Until Page Contains Element id=exampleInputEmail1 # Switch Window title=Basic HTML Elements diff --git a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_browsermanagement.py b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_browsermanagement.py index 23db236..9c43e10 100644 --- a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_browsermanagement.py +++ b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_browsermanagement.py @@ -1,5 +1,6 @@ -import sys -from pyppeteer import launch +import asyncio +import re +import time from PuppeteerLibrary.keywords.ibrowsermanagement_async import iBrowserManagementAsync from PuppeteerLibrary.custom_elements.SPage import SPage @@ -28,7 +29,29 @@ async def get_window_count(self): pass async def wait_for_new_window_open(self, timeout=None): - pass + page_len = 0 + # Workaround: + # We get length without force reset. For ensure that when we count page length. + # Page length still not update / same as before open new window + pre_page_len = len(await self.library_ctx.get_all_pages()) + timeout = self.timestr_to_secs_for_default_timeout(timeout) + max_time = time.time() + timeout + while time.time() < max_time: + page_len = await self._get_window_count_async() + if page_len > pre_page_len: + return + await asyncio.sleep(0.5) + raise Exception('No new page has been open. pre: ' + str(pre_page_len) + ' current: ' + str(page_len)) + + async def _get_window_count_async(self): + pages = await self.library_ctx.get_all_pages() + for page in pages: + # Workaround: for force pages re-cache + try: + await page.title() + except: + return [] + return len(await self.library_ctx.get_all_pages()) async def switch_window(self, locator='MAIN'): pass diff --git a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_element.py b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_element.py new file mode 100644 index 0000000..77fad88 --- /dev/null +++ b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_element.py @@ -0,0 +1,11 @@ +from PuppeteerLibrary.keywords.ielement_async import iElementAsync + + +class PuppeteerElement(iElementAsync): + + def __init__(self, library_ctx): + super().__init__(library_ctx) + + async def click_element(self, locator: str): + return await self.library_ctx.get_current_page().click_with_selenium_locator(locator) + diff --git a/PuppeteerLibrary/puppeteer/custom_elements/puppeteer_page.py b/PuppeteerLibrary/puppeteer/custom_elements/puppeteer_page.py index 069b506..43abd92 100644 --- a/PuppeteerLibrary/puppeteer/custom_elements/puppeteer_page.py +++ b/PuppeteerLibrary/puppeteer/custom_elements/puppeteer_page.py @@ -45,14 +45,11 @@ async def click(self, selector: str, options: dict = None, **kwargs: Any): ''' async def click_with_selenium_locator(self, selenium_locator: str, options: dict = None, **kwargs: Any): - pass - ''' selector_value = SelectorAbstraction.get_selector(selenium_locator) if SelectorAbstraction.is_xpath(selenium_locator): await self.page.click_xpath(selector_value, options, **kwargs) else: await self.page.click(selector_value, options, **kwargs) - ''' async def click_xpath(self, selector: str, options: dict = None, **kwargs: Any): pass diff --git a/PuppeteerLibrary/puppeteer/puppeteer_context.py b/PuppeteerLibrary/puppeteer/puppeteer_context.py index c669686..bd58b06 100644 --- a/PuppeteerLibrary/puppeteer/puppeteer_context.py +++ b/PuppeteerLibrary/puppeteer/puppeteer_context.py @@ -1,10 +1,11 @@ -from PuppeteerLibrary.puppeteer.custom_elements.puppeteer_page import PuppeteerPage import sys from pyppeteer import launch from pyppeteer.browser import Browser from PuppeteerLibrary.custom_elements.base_page import BasePage from PuppeteerLibrary.library_context.ilibrary_context import iLibraryContext from PuppeteerLibrary.puppeteer.async_keywords.puppeteer_browsermanagement import PuppeteerBrowserManagement +from PuppeteerLibrary.puppeteer.async_keywords.puppeteer_element import PuppeteerElement +from PuppeteerLibrary.puppeteer.custom_elements.puppeteer_page import PuppeteerPage class PuppeteerContext(iLibraryContext): @@ -73,17 +74,18 @@ def set_current_page(self, page: any) -> BasePage: pass async def get_all_pages(self): - pass + return await self.browser.pages() def get_browser_context(self): - pass + return self.browser async def close_browser_context(self): pass def get_async_keyword_group(self, keyword_group_name: str): switcher = { - "BrowserManagementKeywords": PuppeteerBrowserManagement(self) + "BrowserManagementKeywords": PuppeteerBrowserManagement(self), + "ElementKeywords": PuppeteerElement(self) } return switcher.get(keyword_group_name) From 650fa260a7f3f319bc0c222c6d1fcadb6d1cfc82 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Wed, 21 Oct 2020 07:03:30 +0700 Subject: [PATCH 053/103] init puppeteer screenshot --- .../open-close-browser.robot | 8 +-- .../keywords/browsermanagement.py | 36 ---------- PuppeteerLibrary/keywords/waiting.py | 1 - .../puppeteer_browsermanagement.py | 31 ++++++++- .../async_keywords/puppeteer_screenshot.py | 12 ++++ .../async_keywords/puppeteer_waiting.py | 65 +++++++++++++++++++ .../custom_elements/puppeteer_page.py | 15 ++--- .../puppeteer/puppeteer_context.py | 6 +- 8 files changed, 123 insertions(+), 51 deletions(-) create mode 100644 PuppeteerLibrary/puppeteer/async_keywords/puppeteer_screenshot.py create mode 100644 PuppeteerLibrary/puppeteer/async_keywords/puppeteer_waiting.py diff --git a/Examples/browser-management/open-close-browser.robot b/Examples/browser-management/open-close-browser.robot index acc832a..aa7babc 100644 --- a/Examples/browser-management/open-close-browser.robot +++ b/Examples/browser-management/open-close-browser.robot @@ -17,10 +17,10 @@ Switch to new browser Run Async Keywords ... Click Element id=open-new-tab AND ... Wait For New Window Open - # Switch Window NEW - # Wait Until Page Contains Element id=exampleInputEmail1 - # Switch Window title=Basic HTML Elements - # Wait Until Page Contains Element id=open-new-tab + Switch Window NEW + Wait Until Page Contains Element id=exampleInputEmail1 + Switch Window title=Basic HTML Elements + Wait Until Page Contains Element id=open-new-tab Handle multiple browser [Teardown] Capture Page Screenshot diff --git a/PuppeteerLibrary/keywords/browsermanagement.py b/PuppeteerLibrary/keywords/browsermanagement.py index 85de45f..ab750eb 100644 --- a/PuppeteerLibrary/keywords/browsermanagement.py +++ b/PuppeteerLibrary/keywords/browsermanagement.py @@ -152,42 +152,6 @@ def switch_window(self, locator='MAIN'): - url="https://qahive.com": url support regex Example: url=.*qahive.com """ self.loop.run_until_complete(self.get_async_keyword_group().switch_window(locator)) - - ''' - async def switch_window_async(): - pages = await self.ctx.get_browser().pages() - if locator == 'MAIN': - page = pages[0] - await page.bringToFront() - return self.ctx.set_current_page(page) - - elif locator == 'NEW': - page = pages[-1] - await page.bringToFront() - return self.ctx.set_current_page(page) - - elif 'title=' in locator: - title = locator.replace('title=', '') - for page in pages: - page_title = await page.title() - if page_title == title: - await page.bringToFront() - return self.ctx.set_current_page(page) - self.info('Title mismatch: ' + page_title) - - elif 'url=' in locator: - url = locator.replace('url=', '') - for page in pages: - if re.match(url, page.url): - await page.bringToFront() - return self.ctx.set_current_page(page) - self.info('Url mismatch: ' + page.url) - else: - raise Exception('Sorry Switch window support only NEW, MAIN, title and url') - raise Exception('Can\'t find specify page locator.') - - return self.loop.run_until_complete(switch_window_async()) - ''' @keyword def switch_browser(self, alias): diff --git a/PuppeteerLibrary/keywords/waiting.py b/PuppeteerLibrary/keywords/waiting.py index 8bd95de..157eb3b 100644 --- a/PuppeteerLibrary/keywords/waiting.py +++ b/PuppeteerLibrary/keywords/waiting.py @@ -105,7 +105,6 @@ def wait_until_page_contains_element(self, locator, timeout=None): | `Wait Until Page Contains Element` | id:username | | """ self.loop.run_until_complete(self.get_async_keyword_group().wait_until_page_contains_element(locator, timeout)) - # return self.loop.run_until_complete(self.async_func.wait_until_page_contains_element_async(locator, timeout)) @keyword def wait_until_element_is_hidden(self, locator, timeout=None): diff --git a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_browsermanagement.py b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_browsermanagement.py index 9c43e10..7b938ea 100644 --- a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_browsermanagement.py +++ b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_browsermanagement.py @@ -54,4 +54,33 @@ async def _get_window_count_async(self): return len(await self.library_ctx.get_all_pages()) async def switch_window(self, locator='MAIN'): - pass + pages = await self.library_ctx.get_all_pages() + if locator == 'MAIN': + page = pages[0] + await page.bringToFront() + return self.library_ctx.set_current_page(page) + + elif locator == 'NEW': + page = pages[-1] + await page.bringToFront() + return self.library_ctx.set_current_page(page) + + elif 'title=' in locator: + title = locator.replace('title=', '') + for page in pages: + page_title = await page.title() + if page_title == title: + await page.bringToFront() + return self.library_ctx.set_current_page(page) + self.info('Title mismatch: ' + page_title) + + elif 'url=' in locator: + url = locator.replace('url=', '') + for page in pages: + if re.match(url, page.url): + await page.bringToFront() + return self.library_ctx.set_current_page(page) + self.info('Url mismatch: ' + page.url) + else: + raise Exception('Sorry Switch window support only NEW, MAIN, title and url') + raise Exception('Can\'t find specify page locator.') diff --git a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_screenshot.py b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_screenshot.py new file mode 100644 index 0000000..4d303e8 --- /dev/null +++ b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_screenshot.py @@ -0,0 +1,12 @@ +from PuppeteerLibrary.keywords.iscreenshot_async import iScreenshotAsync + + +class PuppeteerScreenshot(iScreenshotAsync): + + def __init__(self, library_ctx): + super().__init__(library_ctx) + + async def capture_page_screenshot(self, path: str): + return await self.library_ctx.get_current_page().get_page().screenshot( + {'path': path} + ) diff --git a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_waiting.py b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_waiting.py new file mode 100644 index 0000000..b3e1d85 --- /dev/null +++ b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_waiting.py @@ -0,0 +1,65 @@ +from PuppeteerLibrary.keywords.iwaiting_async import iWaitingAsync + + +class PuppeteerWaiting(iWaitingAsync): + + def __init__(self, library_ctx): + super().__init__(library_ctx) + + async def _wait_for_selenium_selector(self, selenium_locator, timeout=None, visible=False, hidden=False): + timeout = self.timestr_to_secs_for_default_timeout(timeout) + return await self.library_ctx.get_current_page().waitForSelector_with_selenium_locator(selenium_locator, timeout, visible, hidden) + + def escape_xpath_value(self, value): + if '"' in value and '\'' in value: + parts_wo_apos = value.split('\'') + return "concat('%s')" % "', \"'\", '".join(parts_wo_apos) + if '\'' in value: + return "\"%s\"" % value + return "'%s'" % value + + async def wait_for_request_url(self, url, method='GET', body=None, timeout=None): + pass + + async def wait_for_response_url(self, url, status=200, body=None, timeout=None): + pass + + async def wait_for_navigation(self): + pass + + async def wait_until_page_contains_element(self, locator, timeout=None): + return await self._wait_for_selenium_selector(locator, timeout, visible=True, hidden=False) + + async def wait_until_element_is_hidden(self, locator, timeout=None): + pass + + async def wait_until_element_is_visible(self, locator, timeout=None): + pass + + async def wait_until_page_contains(self, text, timeout=None): + locator = "xpath://*[contains(., %s)]" % self.escape_xpath_value(text) + return await self._wait_for_selenium_selector(locator, timeout, visible=True, hidden=False) + + async def wait_until_page_does_not_contains(self, text, timeout=None): + pass + + async def wait_until_element_contains(self, locator, text, timeout=None): + pass + + async def wait_until_element_does_not_contains(self, locator, text, timeout=None): + pass + + async def wait_until_location_contains(self, expected, timeout=None): + pass + + async def wait_until_location_does_not_contains(self, expected, timeout=None): + pass + + async def wait_until_element_is_enabled(self, selenium_locator, timeout=None): + pass + + async def wait_until_element_finished_animating(self, selenium_locator, timeout=None): + pass + + + diff --git a/PuppeteerLibrary/puppeteer/custom_elements/puppeteer_page.py b/PuppeteerLibrary/puppeteer/custom_elements/puppeteer_page.py index 43abd92..6c977d8 100644 --- a/PuppeteerLibrary/puppeteer/custom_elements/puppeteer_page.py +++ b/PuppeteerLibrary/puppeteer/custom_elements/puppeteer_page.py @@ -17,20 +17,19 @@ async def goto(self, url: str): return await self.page.goto(url) async def go_back(self): - pass - # return await self.page.goBack() + return await self.page.goBack() async def reload_page(self): - pass - # return await self.page.reload() + return await self.page.reload() async def title(self): - pass - # return await self.page.title() + return await self.page.title() async def set_viewport_size(self, width: int, height: int): - pass - # return await self.page.setViewportSize(width, height) + self.page.setViewport({ + width: width, + height: height + }) ############ # Click diff --git a/PuppeteerLibrary/puppeteer/puppeteer_context.py b/PuppeteerLibrary/puppeteer/puppeteer_context.py index bd58b06..2afb00e 100644 --- a/PuppeteerLibrary/puppeteer/puppeteer_context.py +++ b/PuppeteerLibrary/puppeteer/puppeteer_context.py @@ -1,3 +1,5 @@ +from PuppeteerLibrary.puppeteer.async_keywords.puppeteer_screenshot import PuppeteerScreenshot +from PuppeteerLibrary.puppeteer.async_keywords.puppeteer_waiting import PuppeteerWaiting import sys from pyppeteer import launch from pyppeteer.browser import Browser @@ -85,7 +87,9 @@ async def close_browser_context(self): def get_async_keyword_group(self, keyword_group_name: str): switcher = { "BrowserManagementKeywords": PuppeteerBrowserManagement(self), - "ElementKeywords": PuppeteerElement(self) + "ElementKeywords": PuppeteerElement(self), + "ScreenshotKeywords": PuppeteerScreenshot(self), + "WaitingKeywords": PuppeteerWaiting(self) } return switcher.get(keyword_group_name) From 8604e2ddfd2af67549cf513c3198f8450ba1a720 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Wed, 21 Oct 2020 07:34:36 +0700 Subject: [PATCH 054/103] Add support emulator mode --- Examples/browser-management/emulator-mode.robot | 10 +++++++--- PuppeteerLibrary/keywords/browsermanagement.py | 3 ++- PuppeteerLibrary/keywords/ibrowsermanagement_async.py | 4 ++++ .../async_keywords/playwright_browsermanagement.py | 8 ++++---- .../async_keywords/puppeteer_browsermanagement.py | 6 +++++- 5 files changed, 22 insertions(+), 9 deletions(-) diff --git a/Examples/browser-management/emulator-mode.robot b/Examples/browser-management/emulator-mode.robot index d477432..4dae002 100644 --- a/Examples/browser-management/emulator-mode.robot +++ b/Examples/browser-management/emulator-mode.robot @@ -1,13 +1,17 @@ *** Settings *** -Force Tags Ignore Library PuppeteerLibrary Suite Teardown Close Puppeteer +*** Variables *** +${DEFAULT_BROWSER} chrome +# ${DEFAULT_BROWSER} webkit + *** Test Cases *** Example enable emulator mode [Teardown] Close All Browser - ${HEADLESS} Get variable value ${HEADLESS} ${False} + ${BROWSER} = Get variable value ${BROWSER} ${DEFAULT_BROWSER} + ${HEADLESS} = Get variable value ${HEADLESS} ${False} &{options} = create dictionary headless=${HEADLESS} - Open browser http://127.0.0.1:7272/basic-html-elements.html options=${options} alias=Browser 1 + Open browser http://127.0.0.1:7272/basic-html-elements.html browser=${BROWSER} options=${options} alias=Browser 1 Enable emulate mode iPhone SE Capture page screenshot diff --git a/PuppeteerLibrary/keywords/browsermanagement.py b/PuppeteerLibrary/keywords/browsermanagement.py index ab750eb..3af9fc1 100644 --- a/PuppeteerLibrary/keywords/browsermanagement.py +++ b/PuppeteerLibrary/keywords/browsermanagement.py @@ -164,6 +164,7 @@ def enable_emulate_mode(self, emulate_name): """Emulate specific mobile or tablet The ``emulate_name`` argument specifies which emulator to use. + Only support for chrome (Puppeteer) | = Example Options = | | iPhone X | @@ -172,7 +173,7 @@ def enable_emulate_mode(self, emulate_name): More emulate_name please visit [device_descriptors.py](https://github.com/qahive/robotframework-puppeteer/tree/master/PuppeteerLibrary/utils/device_descriptors.py) """ - return self.loop.run_until_complete(self.async_func.enable_emulate_mode_async(emulate_name)) + return self.loop.run_until_complete(self.get_async_keyword_group().enable_emulate_mode_async(emulate_name)) @keyword def select_frame(self, selenium_locator): diff --git a/PuppeteerLibrary/keywords/ibrowsermanagement_async.py b/PuppeteerLibrary/keywords/ibrowsermanagement_async.py index 044c5a2..b417947 100644 --- a/PuppeteerLibrary/keywords/ibrowsermanagement_async.py +++ b/PuppeteerLibrary/keywords/ibrowsermanagement_async.py @@ -31,3 +31,7 @@ async def wait_for_new_window_open(self, timeout=None): @abstractmethod async def switch_window(self, locator='MAIN'): pass + + @abstractmethod + async def enable_emulate_mode_async(self, emulate_name): + pass diff --git a/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py b/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py index 532a236..37fb838 100644 --- a/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py +++ b/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py @@ -1,11 +1,8 @@ import asyncio import re import time +from PuppeteerLibrary.utils.device_descriptors import DEVICE_DESCRIPTORS from PuppeteerLibrary.keywords.ibrowsermanagement_async import iBrowserManagementAsync -try: - from playwright import async_playwright -except ImportError: - print('import playwright error') class PlaywrightBrowserManagement(iBrowserManagementAsync): @@ -91,3 +88,6 @@ async def switch_window(self, locator='MAIN'): else: raise Exception('Sorry Switch window support only NEW, MAIN, title and url') raise Exception('Can\'t find specify page locator.') + + async def enable_emulate_mode_async(self, emulate_name): + Warning('Playwright not support emulate mode.') diff --git a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_browsermanagement.py b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_browsermanagement.py index 7b938ea..3f23b8d 100644 --- a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_browsermanagement.py +++ b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_browsermanagement.py @@ -1,8 +1,8 @@ import asyncio import re import time +from PuppeteerLibrary.utils.device_descriptors import DEVICE_DESCRIPTORS from PuppeteerLibrary.keywords.ibrowsermanagement_async import iBrowserManagementAsync -from PuppeteerLibrary.custom_elements.SPage import SPage class PuppeteerBrowserManagement(iBrowserManagementAsync): @@ -84,3 +84,7 @@ async def switch_window(self, locator='MAIN'): else: raise Exception('Sorry Switch window support only NEW, MAIN, title and url') raise Exception('Can\'t find specify page locator.') + + async def enable_emulate_mode_async(self, emulate_name): + await self.library_ctx.get_current_page().get_page().emulate(DEVICE_DESCRIPTORS[emulate_name]) + From f323bdddd365205aa848ac51f82b36d1f8cd5f88 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Thu, 22 Oct 2020 07:06:28 +0700 Subject: [PATCH 055/103] Enhance support emulator mode on playwright --- Examples/alert-handler/alert-handler.robot | 9 +++++++-- Examples/browser-management/emulator-mode.robot | 3 +-- PuppeteerLibrary/keywords/ibrowsermanagement_async.py | 4 ---- .../async_keywords/playwright_browsermanagement.py | 3 --- PuppeteerLibrary/playwright/playwright_context.py | 7 +++++-- .../puppeteer/async_keywords/puppeteer_alert.py | 4 ++++ .../async_keywords/puppeteer_browsermanagement.py | 4 ---- PuppeteerLibrary/puppeteer/puppeteer_context.py | 8 ++++++-- PuppeteerLibrary/utils/device_descriptors.py | 11 +++++++++++ 9 files changed, 34 insertions(+), 19 deletions(-) create mode 100644 PuppeteerLibrary/puppeteer/async_keywords/puppeteer_alert.py diff --git a/Examples/alert-handler/alert-handler.robot b/Examples/alert-handler/alert-handler.robot index 2837385..abf2146 100644 --- a/Examples/alert-handler/alert-handler.robot +++ b/Examples/alert-handler/alert-handler.robot @@ -5,9 +5,13 @@ Test Setup Open browser to test page Test Teardown Close All Browser Suite Teardown Close Puppeteer + *** Variables *** +${DEFAULT_BROWSER} chrome +# ${DEFAULT_BROWSER} webkit ${HOME_PAGE_URL} http://127.0.0.1:7272/basic-html-elements.html + *** Test Cases *** Accept alert Run Async Keywords @@ -20,10 +24,11 @@ Dismiss alert ... Handle Alert DISMISS AND ... Click Button id=alert_confirm Click Element id:get_ajax + *** Keywords *** Open browser to test page + ${BROWSER} = Get variable value ${BROWSER} ${DEFAULT_BROWSER} ${HEADLESS} Get variable value ${HEADLESS} ${False} &{options} = create dictionary headless=${HEADLESS} - Open browser ${HOME_PAGE_URL} options=${options} - + Open browser ${HOME_PAGE_URL} browser=${BROWSER} options=${options} diff --git a/Examples/browser-management/emulator-mode.robot b/Examples/browser-management/emulator-mode.robot index 4dae002..729f5ba 100644 --- a/Examples/browser-management/emulator-mode.robot +++ b/Examples/browser-management/emulator-mode.robot @@ -11,7 +11,6 @@ Example enable emulator mode [Teardown] Close All Browser ${BROWSER} = Get variable value ${BROWSER} ${DEFAULT_BROWSER} ${HEADLESS} = Get variable value ${HEADLESS} ${False} - &{options} = create dictionary headless=${HEADLESS} + &{options} = create dictionary headless=${HEADLESS} emulate=iPhone 11 Open browser http://127.0.0.1:7272/basic-html-elements.html browser=${BROWSER} options=${options} alias=Browser 1 - Enable emulate mode iPhone SE Capture page screenshot diff --git a/PuppeteerLibrary/keywords/ibrowsermanagement_async.py b/PuppeteerLibrary/keywords/ibrowsermanagement_async.py index b417947..044c5a2 100644 --- a/PuppeteerLibrary/keywords/ibrowsermanagement_async.py +++ b/PuppeteerLibrary/keywords/ibrowsermanagement_async.py @@ -31,7 +31,3 @@ async def wait_for_new_window_open(self, timeout=None): @abstractmethod async def switch_window(self, locator='MAIN'): pass - - @abstractmethod - async def enable_emulate_mode_async(self, emulate_name): - pass diff --git a/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py b/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py index 37fb838..3683ee1 100644 --- a/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py +++ b/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py @@ -88,6 +88,3 @@ async def switch_window(self, locator='MAIN'): else: raise Exception('Sorry Switch window support only NEW, MAIN, title and url') raise Exception('Can\'t find specify page locator.') - - async def enable_emulate_mode_async(self, emulate_name): - Warning('Playwright not support emulate mode.') diff --git a/PuppeteerLibrary/playwright/playwright_context.py b/PuppeteerLibrary/playwright/playwright_context.py index 4fd3738..26eedbb 100644 --- a/PuppeteerLibrary/playwright/playwright_context.py +++ b/PuppeteerLibrary/playwright/playwright_context.py @@ -1,6 +1,6 @@ +from PuppeteerLibrary.custom_elements.base_page import BasePage from PuppeteerLibrary.playwright.async_keywords.playwright_screenshot import PlaywrightScreenshot from PuppeteerLibrary.playwright.async_keywords.playwright_waiting import PlaywrightWaiting -from PuppeteerLibrary.custom_elements.base_page import BasePage from PuppeteerLibrary.playwright.async_keywords.playwright_element import PlaywrightElement from PuppeteerLibrary.playwright.custom_elements.playwright_page import PlaywrightPage from PuppeteerLibrary.playwright.async_keywords.playwright_browsermanagement import PlaywrightBrowserManagement @@ -40,7 +40,10 @@ def is_server_started(self) -> bool: return False async def create_new_page(self, options: dict=None) -> BasePage: - new_page = await self.browser.newPage() + device_options = {} + if 'emulate' in options: + device_options = self.playwright.devices[options['emulate']] + new_page = await self.browser.newPage(**device_options) self.current_page = PlaywrightPage(new_page) return self.current_page diff --git a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_alert.py b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_alert.py new file mode 100644 index 0000000..77d86df --- /dev/null +++ b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_alert.py @@ -0,0 +1,4 @@ +class PuppeteerAlert(iAlertAsync): + + def __init__(self, library_ctx): + super().__init__(library_ctx) diff --git a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_browsermanagement.py b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_browsermanagement.py index 3f23b8d..1c3f1df 100644 --- a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_browsermanagement.py +++ b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_browsermanagement.py @@ -1,7 +1,6 @@ import asyncio import re import time -from PuppeteerLibrary.utils.device_descriptors import DEVICE_DESCRIPTORS from PuppeteerLibrary.keywords.ibrowsermanagement_async import iBrowserManagementAsync @@ -85,6 +84,3 @@ async def switch_window(self, locator='MAIN'): raise Exception('Sorry Switch window support only NEW, MAIN, title and url') raise Exception('Can\'t find specify page locator.') - async def enable_emulate_mode_async(self, emulate_name): - await self.library_ctx.get_current_page().get_page().emulate(DEVICE_DESCRIPTORS[emulate_name]) - diff --git a/PuppeteerLibrary/puppeteer/puppeteer_context.py b/PuppeteerLibrary/puppeteer/puppeteer_context.py index 2afb00e..1696037 100644 --- a/PuppeteerLibrary/puppeteer/puppeteer_context.py +++ b/PuppeteerLibrary/puppeteer/puppeteer_context.py @@ -1,13 +1,15 @@ -from PuppeteerLibrary.puppeteer.async_keywords.puppeteer_screenshot import PuppeteerScreenshot -from PuppeteerLibrary.puppeteer.async_keywords.puppeteer_waiting import PuppeteerWaiting import sys from pyppeteer import launch from pyppeteer.browser import Browser +from PuppeteerLibrary.puppeteer.async_keywords.puppeteer_screenshot import PuppeteerScreenshot +from PuppeteerLibrary.puppeteer.async_keywords.puppeteer_waiting import PuppeteerWaiting from PuppeteerLibrary.custom_elements.base_page import BasePage from PuppeteerLibrary.library_context.ilibrary_context import iLibraryContext from PuppeteerLibrary.puppeteer.async_keywords.puppeteer_browsermanagement import PuppeteerBrowserManagement from PuppeteerLibrary.puppeteer.async_keywords.puppeteer_element import PuppeteerElement from PuppeteerLibrary.puppeteer.custom_elements.puppeteer_page import PuppeteerPage +from PuppeteerLibrary.utils.device_descriptors import DEVICE_DESCRIPTORS + class PuppeteerContext(iLibraryContext): @@ -67,6 +69,8 @@ def is_server_started(self) -> bool: async def create_new_page(self, options: dict=None) -> BasePage: new_page = await self.browser.newPage() self.current_page = PuppeteerPage(new_page) + if 'emulate' in options: + await self.current_page.get_page().emulate(DEVICE_DESCRIPTORS[options['emulate']]) return self.current_page def get_current_page(self) -> BasePage: diff --git a/PuppeteerLibrary/utils/device_descriptors.py b/PuppeteerLibrary/utils/device_descriptors.py index 5f04581..b5d4a1f 100644 --- a/PuppeteerLibrary/utils/device_descriptors.py +++ b/PuppeteerLibrary/utils/device_descriptors.py @@ -430,6 +430,17 @@ 'isLandscape': True } }, + 'iPhone 11': { + 'userAgent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0 Mobile/15E148 Safari/604.1', + 'viewport': { + 'width': 414, + 'height': 896, + 'deviceScaleFactor': 2, + 'isMobile': True, + 'hasTouch': True, + 'isLandscape': False + } + }, 'JioPhone 2': { 'userAgent': 'Mozilla/5.0 (Mobile; LYF/F300B/LYF-F300B-001-01-15-130718-i;Android; rv:48.0) Gecko/48.0 Firefox/48.0 KAIOS/2.5', 'viewport': { From 2fd5e6d97f5963c565de9990425ff395774f90d6 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Thu, 22 Oct 2020 07:29:05 +0700 Subject: [PATCH 056/103] Add alert for puppeteer --- Examples/alert-handler/alert-handler.robot | 4 ++-- PuppeteerLibrary/keywords/alert.py | 6 +++++- PuppeteerLibrary/keywords/ialert_async.py | 9 +++++++++ .../puppeteer/async_keywords/puppeteer_alert.py | 13 +++++++++++++ PuppeteerLibrary/puppeteer/puppeteer_context.py | 2 ++ 5 files changed, 31 insertions(+), 3 deletions(-) create mode 100644 PuppeteerLibrary/keywords/ialert_async.py diff --git a/Examples/alert-handler/alert-handler.robot b/Examples/alert-handler/alert-handler.robot index abf2146..71d2599 100644 --- a/Examples/alert-handler/alert-handler.robot +++ b/Examples/alert-handler/alert-handler.robot @@ -1,5 +1,4 @@ *** Settings *** -Force Tags Ignore Library PuppeteerLibrary Test Setup Open browser to test page Test Teardown Close All Browser @@ -16,7 +15,8 @@ ${HOME_PAGE_URL} http://127.0.0.1:7272/basic-html-elements.html Accept alert Run Async Keywords ... Handle Alert ACCEPT AND - ... Click Button id=alert_confirm + ... Click Element id=alert_confirm + # ... Click Button id=alert_confirm Click Element id:get_ajax Dismiss alert diff --git a/PuppeteerLibrary/keywords/alert.py b/PuppeteerLibrary/keywords/alert.py index ebd36ac..80c7616 100644 --- a/PuppeteerLibrary/keywords/alert.py +++ b/PuppeteerLibrary/keywords/alert.py @@ -1,6 +1,7 @@ from PuppeteerLibrary.base.librarycomponent import LibraryComponent from PuppeteerLibrary.base.robotlibcore import keyword from PuppeteerLibrary.keywords.alert_async import AlertKeywordsAsync +from PuppeteerLibrary.keywords.ialert_async import iAlertAsync class AlertKeywords(LibraryComponent): @@ -9,6 +10,9 @@ def __init__(self, ctx): super().__init__(ctx) self.async_func = AlertKeywordsAsync(self.ctx) + def get_async_keyword_group(self) -> iAlertAsync: + return self.ctx.get_current_library_context().get_async_keyword_group(type(self).__name__) + @keyword def handle_alert(self, action, prompt_text=''): """Handles the current alert and returns its message. @@ -24,4 +28,4 @@ def handle_alert(self, action, prompt_text=''): | ... Click Button | id=alert_confirm | | """ - return self.loop.run_until_complete(self.async_func.handle_alert_async(action, prompt_text)) + return self.loop.run_until_complete(self.get_async_keyword_group().handle_alert(action, prompt_text)) diff --git a/PuppeteerLibrary/keywords/ialert_async.py b/PuppeteerLibrary/keywords/ialert_async.py new file mode 100644 index 0000000..5b26ca2 --- /dev/null +++ b/PuppeteerLibrary/keywords/ialert_async.py @@ -0,0 +1,9 @@ +from PuppeteerLibrary.keywords.base_async_keywords import BaseAsyncKeywords +from abc import ABC, abstractmethod + + +class iAlertAsync(BaseAsyncKeywords, ABC): + + @abstractmethod + async def handle_alert(self, action, prompt_text=''): + pass diff --git a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_alert.py b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_alert.py index 77d86df..b5a2593 100644 --- a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_alert.py +++ b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_alert.py @@ -1,4 +1,17 @@ +import asyncio +from PuppeteerLibrary.keywords.ialert_async import iAlertAsync + + class PuppeteerAlert(iAlertAsync): def __init__(self, library_ctx): super().__init__(library_ctx) + + async def handle_alert(self, action, prompt_text=''): + return self.library_ctx.get_current_page().get_page().on('dialog', lambda dialog: asyncio.ensure_future(self.handle_dialog(dialog, action, prompt_text))) + + async def handle_dialog(self, dialog, action, prompt_text=''): + if action == 'ACCEPT': + await dialog.accept(prompt_text) + elif action == 'DISMISS': + await dialog.dismiss() diff --git a/PuppeteerLibrary/puppeteer/puppeteer_context.py b/PuppeteerLibrary/puppeteer/puppeteer_context.py index 1696037..cdd8292 100644 --- a/PuppeteerLibrary/puppeteer/puppeteer_context.py +++ b/PuppeteerLibrary/puppeteer/puppeteer_context.py @@ -1,6 +1,7 @@ import sys from pyppeteer import launch from pyppeteer.browser import Browser +from PuppeteerLibrary.puppeteer.async_keywords.puppeteer_alert import PuppeteerAlert from PuppeteerLibrary.puppeteer.async_keywords.puppeteer_screenshot import PuppeteerScreenshot from PuppeteerLibrary.puppeteer.async_keywords.puppeteer_waiting import PuppeteerWaiting from PuppeteerLibrary.custom_elements.base_page import BasePage @@ -90,6 +91,7 @@ async def close_browser_context(self): def get_async_keyword_group(self, keyword_group_name: str): switcher = { + "AlertKeywords": PuppeteerAlert(self), "BrowserManagementKeywords": PuppeteerBrowserManagement(self), "ElementKeywords": PuppeteerElement(self), "ScreenshotKeywords": PuppeteerScreenshot(self), From fb28a23f81225485aa5797506b2d72b9d83ef441 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Thu, 22 Oct 2020 07:41:18 +0700 Subject: [PATCH 057/103] Add doc --- Examples/alert-handler/alert-handler.robot | 3 ++- PuppeteerLibrary/keywords/alert.py | 3 +++ PuppeteerLibrary/keywords/browsermanagement.py | 1 + .../playwright/async_keywords/playwright_alert.py | 11 +++++++++++ PuppeteerLibrary/playwright/playwright_context.py | 2 ++ 5 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 PuppeteerLibrary/playwright/async_keywords/playwright_alert.py diff --git a/Examples/alert-handler/alert-handler.robot b/Examples/alert-handler/alert-handler.robot index 71d2599..b9eefcc 100644 --- a/Examples/alert-handler/alert-handler.robot +++ b/Examples/alert-handler/alert-handler.robot @@ -1,4 +1,5 @@ *** Settings *** +Library Dialogs Library PuppeteerLibrary Test Setup Open browser to test page Test Teardown Close All Browser @@ -7,12 +8,12 @@ Suite Teardown Close Puppeteer *** Variables *** ${DEFAULT_BROWSER} chrome -# ${DEFAULT_BROWSER} webkit ${HOME_PAGE_URL} http://127.0.0.1:7272/basic-html-elements.html *** Test Cases *** Accept alert + [Tags] IGNORE_webkit Run Async Keywords ... Handle Alert ACCEPT AND ... Click Element id=alert_confirm diff --git a/PuppeteerLibrary/keywords/alert.py b/PuppeteerLibrary/keywords/alert.py index 80c7616..2f4c643 100644 --- a/PuppeteerLibrary/keywords/alert.py +++ b/PuppeteerLibrary/keywords/alert.py @@ -27,5 +27,8 @@ def handle_alert(self, action, prompt_text=''): | ... Handle Alert | ACCEPT | AND | | ... Click Button | id=alert_confirm | | + Limitation: + Not support for webkit + """ return self.loop.run_until_complete(self.get_async_keyword_group().handle_alert(action, prompt_text)) diff --git a/PuppeteerLibrary/keywords/browsermanagement.py b/PuppeteerLibrary/keywords/browsermanagement.py index 3af9fc1..9c6c8ee 100644 --- a/PuppeteerLibrary/keywords/browsermanagement.py +++ b/PuppeteerLibrary/keywords/browsermanagement.py @@ -30,6 +30,7 @@ def open_browser(self, url, browser="chrome", alias=None, options=None): | headless | default True | | width | default 1366 | | height | default 768 | + | emulate | iPhone 11 | Example: diff --git a/PuppeteerLibrary/playwright/async_keywords/playwright_alert.py b/PuppeteerLibrary/playwright/async_keywords/playwright_alert.py new file mode 100644 index 0000000..239280e --- /dev/null +++ b/PuppeteerLibrary/playwright/async_keywords/playwright_alert.py @@ -0,0 +1,11 @@ +import asyncio +from PuppeteerLibrary.keywords.ialert_async import iAlertAsync + + +class PlaywrightAlert(iAlertAsync): + + def __init__(self, library_ctx): + super().__init__(library_ctx) + + async def handle_alert(self, action, prompt_text=''): + pass diff --git a/PuppeteerLibrary/playwright/playwright_context.py b/PuppeteerLibrary/playwright/playwright_context.py index 26eedbb..a7c00ca 100644 --- a/PuppeteerLibrary/playwright/playwright_context.py +++ b/PuppeteerLibrary/playwright/playwright_context.py @@ -1,4 +1,5 @@ from PuppeteerLibrary.custom_elements.base_page import BasePage +from PuppeteerLibrary.playwright.async_keywords.playwright_alert import PlaywrightAlert from PuppeteerLibrary.playwright.async_keywords.playwright_screenshot import PlaywrightScreenshot from PuppeteerLibrary.playwright.async_keywords.playwright_waiting import PlaywrightWaiting from PuppeteerLibrary.playwright.async_keywords.playwright_element import PlaywrightElement @@ -66,6 +67,7 @@ async def close_browser_context(self): def get_async_keyword_group(self, keyword_group_name: str): switcher = { + "AlertKeywords": PlaywrightAlert(self), "BrowserManagementKeywords": PlaywrightBrowserManagement(self), "ElementKeywords": PlaywrightElement(self), "ScreenshotKeywords": PlaywrightScreenshot(self), From c7035ddd6a7af65d16597a2ad5c21cff1ab6bd79 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Thu, 22 Oct 2020 07:43:19 +0700 Subject: [PATCH 058/103] clean up doc --- Examples/alert-handler/alert-handler.robot | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Examples/alert-handler/alert-handler.robot b/Examples/alert-handler/alert-handler.robot index b9eefcc..789141b 100644 --- a/Examples/alert-handler/alert-handler.robot +++ b/Examples/alert-handler/alert-handler.robot @@ -1,5 +1,4 @@ *** Settings *** -Library Dialogs Library PuppeteerLibrary Test Setup Open browser to test page Test Teardown Close All Browser @@ -17,13 +16,13 @@ Accept alert Run Async Keywords ... Handle Alert ACCEPT AND ... Click Element id=alert_confirm - # ... Click Button id=alert_confirm Click Element id:get_ajax Dismiss alert + [Tags] IGNORE_webkit Run Async Keywords ... Handle Alert DISMISS AND - ... Click Button id=alert_confirm + ... Click Element id=alert_confirm Click Element id:get_ajax From 82fb8d225c8111fc7c534c639d2a781681516f7b Mon Sep 17 00:00:00 2001 From: atthaboons Date: Thu, 22 Oct 2020 16:24:03 +0700 Subject: [PATCH 059/103] refactor build pipeline ignore specific test --- .github/workflows/pythonpackage.yml | 8 +++++--- Examples/alert-handler/alert-handler.robot | 4 ++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index 7e97b4a..365b1ea 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -13,8 +13,10 @@ jobs: include: - python-version: 3.7 browser: webkit - # - python-version: 3.8 - # browser: chrome + - python-version: 3.8 + browser: chrome + - python-version: 3.9 + browser: chrome steps: - uses: actions/checkout@v1 @@ -73,4 +75,4 @@ jobs: uses: GabrielBB/xvfb-action@v1 with: working-directory: ./ #optional - run: robot -v BROWSER:${{ matrix.browser }} -e Ignore Examples + run: robot -v BROWSER:${{ matrix.browser }} -e IgnoreANDIgnore_${{ matrix.browser }} Examples diff --git a/Examples/alert-handler/alert-handler.robot b/Examples/alert-handler/alert-handler.robot index 789141b..666ea59 100644 --- a/Examples/alert-handler/alert-handler.robot +++ b/Examples/alert-handler/alert-handler.robot @@ -12,14 +12,14 @@ ${HOME_PAGE_URL} http://127.0.0.1:7272/basic-html-elements.html *** Test Cases *** Accept alert - [Tags] IGNORE_webkit + [Tags] Ignore_webkit Run Async Keywords ... Handle Alert ACCEPT AND ... Click Element id=alert_confirm Click Element id:get_ajax Dismiss alert - [Tags] IGNORE_webkit + [Tags] Ignore_webkit Run Async Keywords ... Handle Alert DISMISS AND ... Click Element id=alert_confirm From 9c2d84d1779b49b203e10ac562e2d022cb4d22c7 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Thu, 22 Oct 2020 16:27:38 +0700 Subject: [PATCH 060/103] Update condition --- .github/workflows/pythonpackage.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index 365b1ea..1886ef6 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -75,4 +75,4 @@ jobs: uses: GabrielBB/xvfb-action@v1 with: working-directory: ./ #optional - run: robot -v BROWSER:${{ matrix.browser }} -e IgnoreANDIgnore_${{ matrix.browser }} Examples + run: robot -v BROWSER:${{ matrix.browser }} -e IgnoreORIgnore_${{ matrix.browser }} Examples From f0a54a3367d90dc317a16c9eaf0200af72f7de9d Mon Sep 17 00:00:00 2001 From: atthaboons Date: Thu, 22 Oct 2020 16:37:07 +0700 Subject: [PATCH 061/103] Update browser context --- PuppeteerLibrary/playwright/playwright_context.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/PuppeteerLibrary/playwright/playwright_context.py b/PuppeteerLibrary/playwright/playwright_context.py index a7c00ca..2f15640 100644 --- a/PuppeteerLibrary/playwright/playwright_context.py +++ b/PuppeteerLibrary/playwright/playwright_context.py @@ -62,7 +62,8 @@ def get_browser_context(self): return self.browser async def close_browser_context(self): - await self.browser.close() + if self.browser is not None: + await self.browser.close() self._reset_context() def get_async_keyword_group(self, keyword_group_name: str): From 98fbdf08f280d904bc996c1af6b8b084fa5196a4 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Thu, 22 Oct 2020 17:07:24 +0700 Subject: [PATCH 062/103] upgrade playwright to latest version --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 01ee5e0..3127cba 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,5 +2,5 @@ versioneer>=0.18 robotframework>=3.2.1 # pyppeteer>=0.2.2 git+https://github.com/qahive/pyppeteer.git@dev -playwright==0.142.1 +playwright==0.151.0 robotframework-libdoc2json>=0.4 \ No newline at end of file From e2b017596a4f7305b44c508a45bda77a8eedbb95 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Thu, 22 Oct 2020 17:28:01 +0700 Subject: [PATCH 063/103] update pyppeteer lib version --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 3127cba..64a55af 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,6 @@ versioneer>=0.18 robotframework>=3.2.1 # pyppeteer>=0.2.2 -git+https://github.com/qahive/pyppeteer.git@dev playwright==0.151.0 +git+https://github.com/qahive/pyppeteer.git@dev2 robotframework-libdoc2json>=0.4 \ No newline at end of file From cca919137d77baa7f3c2f281eacc17592c156c82 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Thu, 22 Oct 2020 18:27:55 +0700 Subject: [PATCH 064/103] Add puppeteer dropdown --- Examples/form-handler/dropdown-list.robot | 6 ++-- PuppeteerLibrary/keywords/dropdown.py | 10 ++++-- PuppeteerLibrary/keywords/idropdown_async.py | 13 ++++++++ .../async_keywords/puppeteer_dropdown.py | 33 +++++++++++++++++++ .../puppeteer/puppeteer_context.py | 5 ++- requirements.txt | 2 +- setup.py | 2 +- 7 files changed, 64 insertions(+), 7 deletions(-) create mode 100644 PuppeteerLibrary/keywords/idropdown_async.py create mode 100644 PuppeteerLibrary/puppeteer/async_keywords/puppeteer_dropdown.py diff --git a/Examples/form-handler/dropdown-list.robot b/Examples/form-handler/dropdown-list.robot index bf03b95..7f1b29f 100644 --- a/Examples/form-handler/dropdown-list.robot +++ b/Examples/form-handler/dropdown-list.robot @@ -1,11 +1,12 @@ *** Settings *** -Force Tags Ignore Library PuppeteerLibrary Test Setup Open browser to test page Test Teardown Close All Browser Suite Teardown Close Puppeteer *** Variables *** +${DEFAULT_BROWSER} chrome +# ${DEFAULT_BROWSER} webkit ${HOME_PAGE_URL} http://127.0.0.1:7272/basic-html-elements.html @@ -24,6 +25,7 @@ Select dropdown list by labels with xpath *** Keywords *** Open browser to test page + ${BROWSER} = Get variable value ${BROWSER} ${DEFAULT_BROWSER} ${HEADLESS} Get variable value ${HEADLESS} ${False} &{options} = create dictionary headless=${HEADLESS} - Open browser ${HOME_PAGE_URL} options=${options} + Open browser ${HOME_PAGE_URL} browser=${BROWSER} options=${options} diff --git a/PuppeteerLibrary/keywords/dropdown.py b/PuppeteerLibrary/keywords/dropdown.py index e4acf11..48c143b 100644 --- a/PuppeteerLibrary/keywords/dropdown.py +++ b/PuppeteerLibrary/keywords/dropdown.py @@ -1,6 +1,7 @@ from PuppeteerLibrary.base.librarycomponent import LibraryComponent from PuppeteerLibrary.base.robotlibcore import keyword from PuppeteerLibrary.keywords.dropdown_async import DropdownKeywordsAsync +from PuppeteerLibrary.keywords.idropdown_async import iDropdownAsync class DropdownKeywords(LibraryComponent): @@ -9,10 +10,15 @@ def __init__(self, ctx): super().__init__(ctx) self.async_func = DropdownKeywordsAsync(self.ctx) + def get_async_keyword_group(self) -> iDropdownAsync: + return self.ctx.get_current_library_context().get_async_keyword_group(type(self).__name__) + @keyword def select_from_list_by_value(self, locator, values): - return self.loop.run_until_complete(self.async_func.select_from_list_by_value_async(locator, values)) + return self.loop.run_until_complete(self.get_async_keyword_group().select_from_list_by_value(locator, values)) + # return self.loop.run_until_complete(self.async_func.select_from_list_by_value_async(locator, values)) @keyword def select_from_list_by_label(self, locator, labels): - return self.loop.run_until_complete(self.async_func.select_from_list_by_label_async(locator, labels)) + return self.loop.run_until_complete(self.get_async_keyword_group().select_from_list_by_label(locator, labels)) + # return self.loop.run_until_complete(self.async_func.select_from_list_by_label_async(locator, labels)) diff --git a/PuppeteerLibrary/keywords/idropdown_async.py b/PuppeteerLibrary/keywords/idropdown_async.py new file mode 100644 index 0000000..a3d3608 --- /dev/null +++ b/PuppeteerLibrary/keywords/idropdown_async.py @@ -0,0 +1,13 @@ +from PuppeteerLibrary.keywords.base_async_keywords import BaseAsyncKeywords +from abc import ABC, abstractmethod + + +class iDropdownAsync(BaseAsyncKeywords, ABC): + + @abstractmethod + async def select_from_list_by_value(self, locator, values): + pass + + @abstractmethod + async def select_from_list_by_label(self, locator, labels): + pass diff --git a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_dropdown.py b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_dropdown.py new file mode 100644 index 0000000..f4085bb --- /dev/null +++ b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_dropdown.py @@ -0,0 +1,33 @@ +from PuppeteerLibrary.keywords.idropdown_async import iDropdownAsync +from PuppeteerLibrary.locators.SelectorAbstraction import SelectorAbstraction + + +class PuppeteerDropdown(iDropdownAsync): + + def __init__(self, library_ctx): + super().__init__(library_ctx) + + async def select_from_list_by_value(self, locator, values): + selector_value = SelectorAbstraction.get_selector(locator) + if SelectorAbstraction.is_xpath(locator): + await self.library_ctx.get_current_page().get_page().evaluate(''' + element = document.evaluate('{selector_value}//option[contains(@value, "{values}")]', document, null, XPathResult.ANY_TYPE, null).iterateNext(); + element.selected = true; + '''.format(selector_value=selector_value, values=values)) + else: + await self.library_ctx.get_current_page().get_page().select(selector_value, values) + + async def select_from_list_by_label(self, locator, labels): + selector_value = SelectorAbstraction.get_selector(locator) + if SelectorAbstraction.is_xpath(locator): + await self.library_ctx.get_current_page().get_page().evaluate(''' + element = document.evaluate('{selector_value}//option[text()=\"{label}\"]', document, null, XPathResult.ANY_TYPE, null).iterateNext(); + element.selected = true; + '''.format(selector_value=selector_value, label=labels)) + else: + await self.library_ctx.get_current_page().get_page().evaluate(''' + selector_element = document.querySelector('{selector_value}'); + element = document.evaluate('//option[text()=\"{label}\"]', selector_element, null, XPathResult.ANY_TYPE, null).iterateNext(); + element.selected = true; + '''.format(selector_value=selector_value, label=labels)) + diff --git a/PuppeteerLibrary/puppeteer/puppeteer_context.py b/PuppeteerLibrary/puppeteer/puppeteer_context.py index cdd8292..7c05ccf 100644 --- a/PuppeteerLibrary/puppeteer/puppeteer_context.py +++ b/PuppeteerLibrary/puppeteer/puppeteer_context.py @@ -1,3 +1,4 @@ +from PuppeteerLibrary.puppeteer.async_keywords.puppeteer_dropdown import PuppeteerDropdown import sys from pyppeteer import launch from pyppeteer.browser import Browser @@ -7,6 +8,7 @@ from PuppeteerLibrary.custom_elements.base_page import BasePage from PuppeteerLibrary.library_context.ilibrary_context import iLibraryContext from PuppeteerLibrary.puppeteer.async_keywords.puppeteer_browsermanagement import PuppeteerBrowserManagement +from PuppeteerLibrary.puppeteer.async_keywords.puppeteer_dropdown import PuppeteerDropdown from PuppeteerLibrary.puppeteer.async_keywords.puppeteer_element import PuppeteerElement from PuppeteerLibrary.puppeteer.custom_elements.puppeteer_page import PuppeteerPage from PuppeteerLibrary.utils.device_descriptors import DEVICE_DESCRIPTORS @@ -87,12 +89,13 @@ def get_browser_context(self): return self.browser async def close_browser_context(self): - pass + await self.browser.close() def get_async_keyword_group(self, keyword_group_name: str): switcher = { "AlertKeywords": PuppeteerAlert(self), "BrowserManagementKeywords": PuppeteerBrowserManagement(self), + "DropdownKeywords": PuppeteerDropdown(self), "ElementKeywords": PuppeteerElement(self), "ScreenshotKeywords": PuppeteerScreenshot(self), "WaitingKeywords": PuppeteerWaiting(self) diff --git a/requirements.txt b/requirements.txt index 64a55af..a78446c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,6 @@ versioneer>=0.18 robotframework>=3.2.1 -# pyppeteer>=0.2.2 playwright==0.151.0 +# pyppeteer>=0.2.2 git+https://github.com/qahive/pyppeteer.git@dev2 robotframework-libdoc2json>=0.4 \ No newline at end of file diff --git a/setup.py b/setup.py index c75fc71..e1fa57c 100644 --- a/setup.py +++ b/setup.py @@ -39,7 +39,7 @@ platforms='any', install_requires=[ 'robotframework>=3.2.1', - 'playwright>=0.142.1', + 'playwright>=0.151.0', 'pyppeteer>=0.2.2', ], # python_requires='>3.5', From 3484095f65a11a8dfabc32f6c31261af90dcf023 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Thu, 22 Oct 2020 18:38:03 +0700 Subject: [PATCH 065/103] Add playwright dropdown --- .../async_keywords/playwright_dropdown.py | 32 +++++++++++++++++++ .../playwright/playwright_context.py | 3 ++ 2 files changed, 35 insertions(+) create mode 100644 PuppeteerLibrary/playwright/async_keywords/playwright_dropdown.py diff --git a/PuppeteerLibrary/playwright/async_keywords/playwright_dropdown.py b/PuppeteerLibrary/playwright/async_keywords/playwright_dropdown.py new file mode 100644 index 0000000..5866809 --- /dev/null +++ b/PuppeteerLibrary/playwright/async_keywords/playwright_dropdown.py @@ -0,0 +1,32 @@ +from PuppeteerLibrary.keywords.idropdown_async import iDropdownAsync +from PuppeteerLibrary.locators.SelectorAbstraction import SelectorAbstraction + + +class PlaywrightDropdown(iDropdownAsync): + + def __init__(self, library_ctx): + super().__init__(library_ctx) + + async def select_from_list_by_value(self, locator, values): + selector_value = SelectorAbstraction.get_selector(locator) + if SelectorAbstraction.is_xpath(locator): + await self.library_ctx.get_current_page().get_page().evaluate(''' + element = document.evaluate('{selector_value}//option[contains(@value, "{values}")]', document, null, XPathResult.ANY_TYPE, null).iterateNext(); + element.selected = true; + '''.format(selector_value=selector_value, values=values)) + else: + await self.library_ctx.get_current_page().get_page().selectOption(selector_value, { + 'value': values + }) + + async def select_from_list_by_label(self, locator, labels): + selector_value = SelectorAbstraction.get_selector(locator) + if SelectorAbstraction.is_xpath(locator): + await self.library_ctx.get_current_page().get_page().evaluate(''' + element = document.evaluate('{selector_value}//option[text()=\"{label}\"]', document, null, XPathResult.ANY_TYPE, null).iterateNext(); + element.selected = true; + '''.format(selector_value=selector_value, label=labels)) + else: + await self.library_ctx.get_current_page().get_page().selectOption(selector_value, { + 'label': labels + }) \ No newline at end of file diff --git a/PuppeteerLibrary/playwright/playwright_context.py b/PuppeteerLibrary/playwright/playwright_context.py index 2f15640..8e04f91 100644 --- a/PuppeteerLibrary/playwright/playwright_context.py +++ b/PuppeteerLibrary/playwright/playwright_context.py @@ -1,8 +1,10 @@ +from PuppeteerLibrary.playwright.async_keywords.playwright_dropdown import PlaywrightDropdown from PuppeteerLibrary.custom_elements.base_page import BasePage from PuppeteerLibrary.playwright.async_keywords.playwright_alert import PlaywrightAlert from PuppeteerLibrary.playwright.async_keywords.playwright_screenshot import PlaywrightScreenshot from PuppeteerLibrary.playwright.async_keywords.playwright_waiting import PlaywrightWaiting from PuppeteerLibrary.playwright.async_keywords.playwright_element import PlaywrightElement +from PuppeteerLibrary.playwright.async_keywords.playwright_dropdown import PlaywrightDropdown from PuppeteerLibrary.playwright.custom_elements.playwright_page import PlaywrightPage from PuppeteerLibrary.playwright.async_keywords.playwright_browsermanagement import PlaywrightBrowserManagement from PuppeteerLibrary.library_context.ilibrary_context import iLibraryContext @@ -70,6 +72,7 @@ def get_async_keyword_group(self, keyword_group_name: str): switcher = { "AlertKeywords": PlaywrightAlert(self), "BrowserManagementKeywords": PlaywrightBrowserManagement(self), + "DropdownKeywords": PlaywrightDropdown(self), "ElementKeywords": PlaywrightElement(self), "ScreenshotKeywords": PlaywrightScreenshot(self), "WaitingKeywords": PlaywrightWaiting(self) From cf2e3ce4192b02c58a60a915e53b7fc6b00f1e0c Mon Sep 17 00:00:00 2001 From: atthaboons Date: Thu, 22 Oct 2020 19:27:33 +0700 Subject: [PATCH 066/103] Add element enable & disable keywords --- PuppeteerLibrary/keywords/element.py | 5 ++--- PuppeteerLibrary/keywords/ielement_async.py | 14 ++++++++++++++ .../async_keywords/puppeteer_element.py | 19 +++++++++++++++++++ .../custom_elements/puppeteer_page.py | 17 ++++++++++++++--- .../puppeteer/puppeteer_context.py | 1 - 5 files changed, 49 insertions(+), 7 deletions(-) diff --git a/PuppeteerLibrary/keywords/element.py b/PuppeteerLibrary/keywords/element.py index a410f21..3f6430d 100644 --- a/PuppeteerLibrary/keywords/element.py +++ b/PuppeteerLibrary/keywords/element.py @@ -22,7 +22,6 @@ def click_element(self, locator): | `Click Element` | id:register | """ self.loop.run_until_complete(self.get_async_keyword_group().click_element(locator)) - # return self.loop.run_until_complete(self.async_func.click_element_async(locator)) @keyword def click_link(self, locator): @@ -79,14 +78,14 @@ def element_should_be_disabled(self, locator): """ Verifies that element identified by locator is disabled. """ - return self.loop.run_until_complete(self.async_func.element_should_be_disabled_async(locator)) + return self.loop.run_until_complete(self.get_async_keyword_group().element_should_be_disabled(locator)) @keyword def element_should_be_enabled(self, locator): """ Verifies that element identified by locator is enabled. """ - return self.loop.run_until_complete(self.async_func.element_should_be_enabled_async(locator)) + return self.loop.run_until_complete(self.get_async_keyword_group().element_should_be_enabled(locator)) @keyword def element_should_be_visible(self, locator): diff --git a/PuppeteerLibrary/keywords/ielement_async.py b/PuppeteerLibrary/keywords/ielement_async.py index e443178..1cd220b 100644 --- a/PuppeteerLibrary/keywords/ielement_async.py +++ b/PuppeteerLibrary/keywords/ielement_async.py @@ -4,6 +4,20 @@ class iElementAsync(BaseAsyncKeywords, ABC): + ############################## + # Click + ############################## @abstractmethod async def click_element(self, locator: str): pass + + ############################## + # Status + ############################## + @abstractmethod + async def element_should_be_enabled(self, locator: str): + pass + + @abstractmethod + async def element_should_be_disabled(self, locator: str): + pass diff --git a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_element.py b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_element.py index 77fad88..c9220c7 100644 --- a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_element.py +++ b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_element.py @@ -6,6 +6,25 @@ class PuppeteerElement(iElementAsync): def __init__(self, library_ctx): super().__init__(library_ctx) + ############################## + # Click + ############################## async def click_element(self, locator: str): return await self.library_ctx.get_current_page().click_with_selenium_locator(locator) + ############################## + # Status + ############################## + async def element_should_be_enabled(self, locator: str): + element = await self.library_ctx.get_current_page().querySelector_with_selenium_locator(locator) + is_disabled = await (await element.getProperty('disabled')).jsonValue() + if is_disabled: + raise AssertionError("Element '%s' is disabled. " % locator) + return element + + async def element_should_be_disabled(self, locator: str): + element = await self.library_ctx.get_current_page().querySelector_with_selenium_locator(locator) + is_disabled = await (await element.getProperty('disabled')).jsonValue() + if not is_disabled: + raise AssertionError("Element '%s' is enabled. " % locator) + return element diff --git a/PuppeteerLibrary/puppeteer/custom_elements/puppeteer_page.py b/PuppeteerLibrary/puppeteer/custom_elements/puppeteer_page.py index 6c977d8..55912aa 100644 --- a/PuppeteerLibrary/puppeteer/custom_elements/puppeteer_page.py +++ b/PuppeteerLibrary/puppeteer/custom_elements/puppeteer_page.py @@ -88,11 +88,22 @@ async def waitForSelector_with_selenium_locator(self, selenium_locator: str, tim # Query ############ async def querySelector(self, selector: str): - pass + if self.selected_iframe is not None: + return await self.selected_iframe.querySelector(selector=selector) + else: + return await self.get_page().querySelector(selector=selector) async def querySelectorAll_with_selenium_locator(self, selenium_locator: str): - pass + selector_value = SelectorAbstraction.get_selector(selenium_locator) + if SelectorAbstraction.is_xpath(selenium_locator): + return await self.get_page().xpath(selector_value) + else: + return await self.get_page().querySelectorAll(selector_value) async def querySelector_with_selenium_locator(self, selenium_locator: str): - pass + selector_value = SelectorAbstraction.get_selector(selenium_locator) + if SelectorAbstraction.is_xpath(selenium_locator): + return (await self.get_page().xpath(selector_value))[0] + else: + return await self.get_page().querySelector(selector_value) diff --git a/PuppeteerLibrary/puppeteer/puppeteer_context.py b/PuppeteerLibrary/puppeteer/puppeteer_context.py index 7c05ccf..f7dba24 100644 --- a/PuppeteerLibrary/puppeteer/puppeteer_context.py +++ b/PuppeteerLibrary/puppeteer/puppeteer_context.py @@ -1,4 +1,3 @@ -from PuppeteerLibrary.puppeteer.async_keywords.puppeteer_dropdown import PuppeteerDropdown import sys from pyppeteer import launch from pyppeteer.browser import Browser From b4bbfa59177188cfa0ea5808b50392170785138a Mon Sep 17 00:00:00 2001 From: atthaboons Date: Fri, 23 Oct 2020 07:43:46 +0700 Subject: [PATCH 067/103] Fix close playwright --- Examples/form-handler/dropdown-list.robot | 8 ++-- PuppeteerLibrary/__init__.py | 45 +++++++++++++------ .../keywords/browsermanagement.py | 7 +-- PuppeteerLibrary/keywords/dropdown.py | 2 - .../async_keywords/playwright_element.py | 12 +++++ 5 files changed, 51 insertions(+), 23 deletions(-) diff --git a/Examples/form-handler/dropdown-list.robot b/Examples/form-handler/dropdown-list.robot index 7f1b29f..8ab5933 100644 --- a/Examples/form-handler/dropdown-list.robot +++ b/Examples/form-handler/dropdown-list.robot @@ -17,11 +17,11 @@ Select dropdown list by values with id Select dropdown list by values with xpath Select From List By Value xpath=//select[@id="cars"] audi -Select dropdown list by labels with id - Select From List By Label id=cars Audi +# Select dropdown list by labels with id +# Select From List By Label id=cars Audi -Select dropdown list by labels with xpath - Select From List By Label xpath=//select[@id="cars"] Audi +# Select dropdown list by labels with xpath +# Select From List By Label xpath=//select[@id="cars"] Audi *** Keywords *** Open browser to test page diff --git a/PuppeteerLibrary/__init__.py b/PuppeteerLibrary/__init__.py index 816a776..6584dd5 100644 --- a/PuppeteerLibrary/__init__.py +++ b/PuppeteerLibrary/__init__.py @@ -163,13 +163,36 @@ def get_library_context_by_name(self, alias: str) -> iLibraryContext: def get_all_library_context(self) -> List[iLibraryContext]: return list(self.library_contexts.values()) + @not_keyword + def get_all_library_context_dict(self) -> dict: + return self.library_contexts + + @not_keyword + def get_browser(self) -> Browser: + return self.browser + @not_keyword def create_library_context(self, alias: str, browser_type: str) -> iLibraryContext: library_context = self.library_factory.create(browser_type) self.library_contexts[alias] = library_context self.current_libary_context = library_context return library_context - + + @not_keyword + def remove_library_context(self, alias): + if alias not in self.library_contexts.keys(): + return + deleted_library_context = self.library_contexts[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] + else: + self.current_libary_context = None + + ############################## + # Will obsolted + ############################## @not_keyword def load_async_keywords(self): if self.is_load_async_keywords is True: @@ -177,10 +200,6 @@ def load_async_keywords(self): self.add_library_components(self.async_libraries) self.is_load_async_keywords = True - @not_keyword - def get_browser(self) -> Browser: - return self.browser - @not_keyword def clear_browser(self): self.browser = None @@ -190,15 +209,6 @@ def clear_browser(self): self.clear_current_iframe() @not_keyword - async def add_context_async(self, alias, browser_context): - if alias in self.contexts.keys(): - await self.contexts[alias].close() - del self.contexts[alias] - self.current_context_name = alias - self.contexts[self.current_context_name] = browser_context - - @not_keyword - # Will obsolted async def create_context_async(self, alias) -> BrowserContext: context = await self.browser.createIncognitoBrowserContext() if alias in self.contexts.keys(): @@ -207,6 +217,13 @@ async def create_context_async(self, alias) -> BrowserContext: self.current_context_name = alias self.contexts[self.current_context_name] = context return context + + @not_keyword + async def add_context_async(self, alias, browser_context): + if alias in self.library_contexts.keys(): + del self.library_contexts[alias] + self.current_context_name = alias + self.library_contexts[self.current_context_name] = browser_context @not_keyword def get_current_context(self) -> BrowserContext: diff --git a/PuppeteerLibrary/keywords/browsermanagement.py b/PuppeteerLibrary/keywords/browsermanagement.py index 9c6c8ee..f80f64c 100644 --- a/PuppeteerLibrary/keywords/browsermanagement.py +++ b/PuppeteerLibrary/keywords/browsermanagement.py @@ -63,9 +63,10 @@ def close_all_browser(self): @keyword def close_puppeteer(self): - library_contexts = self.ctx.get_all_library_context() - for library_context in library_contexts: - self.loop.run_until_complete(library_context.stop_server()) + 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.ctx.remove_library_context(key) @keyword def maximize_browser_window(self, width=1366, height=768): diff --git a/PuppeteerLibrary/keywords/dropdown.py b/PuppeteerLibrary/keywords/dropdown.py index 48c143b..b221643 100644 --- a/PuppeteerLibrary/keywords/dropdown.py +++ b/PuppeteerLibrary/keywords/dropdown.py @@ -16,9 +16,7 @@ def get_async_keyword_group(self) -> iDropdownAsync: @keyword def select_from_list_by_value(self, locator, values): return self.loop.run_until_complete(self.get_async_keyword_group().select_from_list_by_value(locator, values)) - # return self.loop.run_until_complete(self.async_func.select_from_list_by_value_async(locator, values)) @keyword def select_from_list_by_label(self, locator, labels): return self.loop.run_until_complete(self.get_async_keyword_group().select_from_list_by_label(locator, labels)) - # return self.loop.run_until_complete(self.async_func.select_from_list_by_label_async(locator, labels)) diff --git a/PuppeteerLibrary/playwright/async_keywords/playwright_element.py b/PuppeteerLibrary/playwright/async_keywords/playwright_element.py index 515461b..dce84bc 100644 --- a/PuppeteerLibrary/playwright/async_keywords/playwright_element.py +++ b/PuppeteerLibrary/playwright/async_keywords/playwright_element.py @@ -6,5 +6,17 @@ class PlaywrightElement(iElementAsync): def __init__(self, library_ctx): super().__init__(library_ctx) + ############################## + # Click + ############################## async def click_element(self, locator: str): return await self.library_ctx.get_current_page().click_with_selenium_locator(locator) + + ############################## + # Status + ############################## + async def element_should_be_enabled(self, locator: str): + pass + + async def element_should_be_disabled(self, locator: str): + pass From dd3a766fa10f067eaa5d34a13a5ea5c75f4b8cd2 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Fri, 23 Oct 2020 10:13:39 +0700 Subject: [PATCH 068/103] Puppeteer Element visibility checking --- PuppeteerLibrary/keywords/element.py | 4 +-- PuppeteerLibrary/keywords/ielement_async.py | 8 +++++ .../async_keywords/puppeteer_element.py | 13 +++++++++ .../custom_elements/puppeteer_page.py | 29 ++++++++++++++++--- 4 files changed, 48 insertions(+), 6 deletions(-) diff --git a/PuppeteerLibrary/keywords/element.py b/PuppeteerLibrary/keywords/element.py index 3f6430d..5f95a83 100644 --- a/PuppeteerLibrary/keywords/element.py +++ b/PuppeteerLibrary/keywords/element.py @@ -92,14 +92,14 @@ def element_should_be_visible(self, locator): """ Verifies that element identified by locator is visible. """ - return self.loop.run_until_complete(self.async_func.element_should_be_visible_async(locator)) + return self.loop.run_until_complete(self.get_async_keyword_group().element_should_be_visible(locator)) @keyword def element_should_not_be_visible(self, locator): """ Verifies that element identified by locator is not be visible. """ - return self.loop.run_until_complete(self.async_func.element_should_not_be_visible_async(locator)) + return self.loop.run_until_complete(self.get_async_keyword_group().element_should_not_be_visible(locator)) @keyword def element_should_contain(self, locator, expected, ignore_case=False): diff --git a/PuppeteerLibrary/keywords/ielement_async.py b/PuppeteerLibrary/keywords/ielement_async.py index 1cd220b..0ca752e 100644 --- a/PuppeteerLibrary/keywords/ielement_async.py +++ b/PuppeteerLibrary/keywords/ielement_async.py @@ -21,3 +21,11 @@ async def element_should_be_enabled(self, locator: str): @abstractmethod async def element_should_be_disabled(self, locator: str): pass + + @abstractmethod + async def element_should_be_visible(self, locator:str): + pass + + @abstractmethod + async def element_should_not_be_visible(self, locator:str): + pass diff --git a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_element.py b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_element.py index c9220c7..eac8cc4 100644 --- a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_element.py +++ b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_element.py @@ -28,3 +28,16 @@ async def element_should_be_disabled(self, locator: str): if not is_disabled: raise AssertionError("Element '%s' is enabled. " % locator) return element + + async def element_should_be_visible(self, locator:str): + try: + return await self.library_ctx.get_current_page().waitForSelector_with_selenium_locator(locator, 0.1, visible=True, hidden=False) + except: + raise AssertionError("Element '%s' is not be visible. " % locator) + + async def element_should_not_be_visible(self, locator:str): + try: + return await self.library_ctx.get_current_page().waitForSelector_with_selenium_locator(locator, 0.1, visible=False, hidden=True) + except: + raise AssertionError("Element '%s' is visible. " % locator) + diff --git a/PuppeteerLibrary/puppeteer/custom_elements/puppeteer_page.py b/PuppeteerLibrary/puppeteer/custom_elements/puppeteer_page.py index 55912aa..0120117 100644 --- a/PuppeteerLibrary/puppeteer/custom_elements/puppeteer_page.py +++ b/PuppeteerLibrary/puppeteer/custom_elements/puppeteer_page.py @@ -66,7 +66,17 @@ async def type_xpath(self, selector, text: str, options: dict = None, **kwargs: # Wait ############ async def waitForSelector_with_selenium_locator(self, selenium_locator: str, timeout: float, visible=False, hidden=False): - pass + options = { + 'timeout': timeout * 1000, + 'visible': visible, + 'hidden': hidden + } + selector_value = SelectorAbstraction.get_selector(selenium_locator) + if SelectorAbstraction.is_xpath(selenium_locator): + return await self._waitForXPath(xpath=selector_value, options=options) + else: + return await self._waitForSelector(selector=selector_value, options=options) + ''' options = { 'timeout': timeout * 1000, @@ -76,14 +86,25 @@ async def waitForSelector_with_selenium_locator(self, selenium_locator: str, tim options['state'] = 'visible' if hidden is True: options['state'] = 'hidden' - selector_value = SelectorAbstraction.get_selector(selenium_locator) return await self.get_page().waitForSelector( - selector=selector_value, - timeout=options['timeout'], + selector=selector_value, + timeout=options['timeout'], state=options['state']) ''' + async def _waitForSelector(self, selector: str, options: dict = None): + if self.selected_iframe is None: + return await self.get_page().waitForSelector(selector=selector, options=options) + else: + return await self.selected_iframe.waitForSelector(selector=selector, options=options) + + async def _waitForXPath(self, xpath: str, options: dict = None): + if self.selected_iframe is None: + return await self.get_page().waitForXPath(xpath=xpath, options=options) + else: + return await self.selected_iframe.waitForXPath(xpath=xpath, options=options) + ############ # Query ############ From 6a39093c1ff94f426cfdf673b55ba72bffe9f967 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Fri, 23 Oct 2020 11:03:16 +0700 Subject: [PATCH 069/103] Add element property validation --- .../form-handler/element-properties.robot | 7 ++++-- PuppeteerLibrary/keywords/element.py | 10 ++++---- PuppeteerLibrary/keywords/ielement_async.py | 23 ++++++++++++++++++ .../async_keywords/puppeteer_element.py | 24 +++++++++++++++++++ 4 files changed, 57 insertions(+), 7 deletions(-) diff --git a/Examples/form-handler/element-properties.robot b/Examples/form-handler/element-properties.robot index 0fc88f9..e5bf226 100644 --- a/Examples/form-handler/element-properties.robot +++ b/Examples/form-handler/element-properties.robot @@ -1,5 +1,4 @@ *** Settings *** -Force Tags Ignore Library PuppeteerLibrary Test Setup Open browser to test page Test Teardown Close All Browser @@ -21,7 +20,11 @@ Element is visible and not visible Element Should Be Visible id:prop-visible Element Should Not Be Visible id:prop-hide Run Keyword And Expect Error REGEXP:Element 'id:prop-hide' is not be visible Element Should Be Visible id:prop-hide - + +Get Element Text + ${text} = Get Text id=prop-text + Should Contain ${text} Please + Element should containt text Element Should Contain id=prop-text Please ${True} diff --git a/PuppeteerLibrary/keywords/element.py b/PuppeteerLibrary/keywords/element.py index 5f95a83..e01a084 100644 --- a/PuppeteerLibrary/keywords/element.py +++ b/PuppeteerLibrary/keywords/element.py @@ -61,7 +61,7 @@ def get_text(self, locator): | ${text} | `Get Text` | id:username | """ - return self.loop.run_until_complete(self.async_func.get_text_async(locator)) + return self.loop.run_until_complete(self.get_async_keyword_group().get_text(locator)) @keyword def get_value(self, locator): @@ -106,28 +106,28 @@ def element_should_contain(self, locator, expected, ignore_case=False): """ Verifies that element locator contains text `expected`. """ - return self.loop.run_until_complete(self.async_func.element_should_contain_async(locator, expected, ignore_case)) + return self.loop.run_until_complete(self.get_async_keyword_group().element_should_contain(locator, expected, ignore_case)) @keyword def element_should_not_contain(self, locator, expected, ignore_case=False): """ Verifies that element locator should not contains text `expected`. """ - return self.loop.run_until_complete(self.async_func.element_should_not_contain_async(locator, expected, ignore_case)) + return self.loop.run_until_complete(self.get_async_keyword_group().element_should_not_contain(locator, expected, ignore_case)) @keyword def element_text_should_be(self, locator, expected, ignore_case=False): """ Verifies that element locator contains exact the text `expected`. """ - return self.loop.run_until_complete(self.async_func.element_text_should_be_async(locator, expected, ignore_case)) + return self.loop.run_until_complete(self.get_async_keyword_group().element_text_should_be(locator, expected, ignore_case)) @keyword def element_text_should_not_be(self, locator, expected, ignore_case=False): """ Verifies that element locator not contains exact the text `expected`. """ - return self.loop.run_until_complete(self.async_func.element_text_should_not_be_async(locator, expected, ignore_case)) + return self.loop.run_until_complete(self.get_async_keyword_group().element_text_should_not_be(locator, expected, ignore_case)) @keyword def upload_file(self, locator, file_path): diff --git a/PuppeteerLibrary/keywords/ielement_async.py b/PuppeteerLibrary/keywords/ielement_async.py index 0ca752e..ec9e6ae 100644 --- a/PuppeteerLibrary/keywords/ielement_async.py +++ b/PuppeteerLibrary/keywords/ielement_async.py @@ -29,3 +29,26 @@ async def element_should_be_visible(self, locator:str): @abstractmethod async def element_should_not_be_visible(self, locator:str): pass + + ############################## + # Property + ############################## + @abstractmethod + async def element_should_contain(self, locator: str, expected: str, ignore_case=False): + pass + + @abstractmethod + async def element_should_not_contain(self, locator: str, expected: str, ignore_case=False): + pass + + @abstractmethod + async def get_text(self, locator: str): + pass + + @abstractmethod + async def element_text_should_be(self, locator: str, expected: str, ignore_case=False): + pass + + @abstractmethod + async def element_text_should_not_be(self, locator: str, expected: str, ignore_case=False): + pass diff --git a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_element.py b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_element.py index eac8cc4..9d10044 100644 --- a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_element.py +++ b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_element.py @@ -1,3 +1,4 @@ +from robot.libraries.BuiltIn import BuiltIn from PuppeteerLibrary.keywords.ielement_async import iElementAsync @@ -41,3 +42,26 @@ async def element_should_not_be_visible(self, locator:str): except: raise AssertionError("Element '%s' is visible. " % locator) + ############################## + # Property + ############################## + async def element_should_contain(self, locator: str, expected: str, ignore_case=False): + text = await self.get_text(locator) + return BuiltIn().should_contain(text, expected, ignore_case=ignore_case) + + async def element_should_not_contain(self, locator: str, expected: str, ignore_case=False): + text = await self.get_text(locator) + return BuiltIn().should_not_contain(text, expected, ignore_case=ignore_case) + + async def get_text(self, locator: str): + element = await self.library_ctx.get_current_page().querySelector_with_selenium_locator(locator) + return (await (await element.getProperty('textContent')).jsonValue()) + + async def element_text_should_be(self, locator: str, expected: str, ignore_case=False): + text = await self.get_text(locator) + return BuiltIn().should_be_equal_as_strings(text, expected, ignore_case=ignore_case) + + async def element_text_should_not_be(self, locator: str, expected: str, ignore_case=False): + text = await self.get_text(locator) + return BuiltIn().should_not_be_equal_as_strings(text, expected, ignore_case=ignore_case) + From 731d49020628e171c094292f61f8017853321aeb Mon Sep 17 00:00:00 2001 From: atthaboons Date: Fri, 23 Oct 2020 11:11:09 +0700 Subject: [PATCH 070/103] puppeteer element properties validation --- Examples/form-handler/dropdown-list.robot | 8 +++--- .../form-handler/element-properties.robot | 5 +++- .../async_keywords/playwright_element.py | 25 +++++++++++++++++++ 3 files changed, 33 insertions(+), 5 deletions(-) diff --git a/Examples/form-handler/dropdown-list.robot b/Examples/form-handler/dropdown-list.robot index 8ab5933..7f1b29f 100644 --- a/Examples/form-handler/dropdown-list.robot +++ b/Examples/form-handler/dropdown-list.robot @@ -17,11 +17,11 @@ Select dropdown list by values with id Select dropdown list by values with xpath Select From List By Value xpath=//select[@id="cars"] audi -# Select dropdown list by labels with id -# Select From List By Label id=cars Audi +Select dropdown list by labels with id + Select From List By Label id=cars Audi -# Select dropdown list by labels with xpath -# Select From List By Label xpath=//select[@id="cars"] Audi +Select dropdown list by labels with xpath + Select From List By Label xpath=//select[@id="cars"] Audi *** Keywords *** Open browser to test page diff --git a/Examples/form-handler/element-properties.robot b/Examples/form-handler/element-properties.robot index e5bf226..06e2ef9 100644 --- a/Examples/form-handler/element-properties.robot +++ b/Examples/form-handler/element-properties.robot @@ -5,6 +5,8 @@ Test Teardown Close All Browser Suite Teardown Close Puppeteer *** Variables *** +${DEFAULT_BROWSER} chrome +# ${DEFAULT_BROWSER} webkit ${HOME_PAGE_URL} http://127.0.0.1:7272/basic-html-elements.html @@ -39,6 +41,7 @@ Element text should not be *** Keywords *** Open browser to test page + ${BROWSER} = Get variable value ${BROWSER} ${DEFAULT_BROWSER} ${HEADLESS} Get variable value ${HEADLESS} ${False} &{options} = create dictionary headless=${HEADLESS} - Open browser ${HOME_PAGE_URL} options=${options} + Open browser ${HOME_PAGE_URL} browser=${BROWSER} options=${options} diff --git a/PuppeteerLibrary/playwright/async_keywords/playwright_element.py b/PuppeteerLibrary/playwright/async_keywords/playwright_element.py index dce84bc..ff1e895 100644 --- a/PuppeteerLibrary/playwright/async_keywords/playwright_element.py +++ b/PuppeteerLibrary/playwright/async_keywords/playwright_element.py @@ -1,3 +1,4 @@ +from robot.libraries.BuiltIn import BuiltIn from PuppeteerLibrary.keywords.ielement_async import iElementAsync @@ -20,3 +21,27 @@ async def element_should_be_enabled(self, locator: str): async def element_should_be_disabled(self, locator: str): pass + + async def element_should_be_visible(self, locator:str): + pass + + async def element_should_not_be_visible(self, locator:str): + pass + + ############################## + # Property + ############################## + async def element_should_contain(self, locator: str, expected: str, ignore_case=False): + pass + + async def element_should_not_contain(self, locator: str, expected: str, ignore_case=False): + pass + + async def get_text(self, locator: str): + pass + + async def element_text_should_be(self, locator: str, expected: str, ignore_case=False): + pass + + async def element_text_should_not_be(self, locator: str, expected: str, ignore_case=False): + pass From 7fec2ffbbdacba7dea47259def7a42df42b94619 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Fri, 23 Oct 2020 11:30:06 +0700 Subject: [PATCH 071/103] Playwright element properties validation --- .../form-handler/element-properties.robot | 1 - .../async_keywords/playwright_element.py | 37 ++++++++++++++----- .../custom_elements/playwright_page.py | 18 +++++++-- .../custom_elements/puppeteer_page.py | 16 -------- 4 files changed, 42 insertions(+), 30 deletions(-) diff --git a/Examples/form-handler/element-properties.robot b/Examples/form-handler/element-properties.robot index 06e2ef9..2353359 100644 --- a/Examples/form-handler/element-properties.robot +++ b/Examples/form-handler/element-properties.robot @@ -6,7 +6,6 @@ Suite Teardown Close Puppeteer *** Variables *** ${DEFAULT_BROWSER} chrome -# ${DEFAULT_BROWSER} webkit ${HOME_PAGE_URL} http://127.0.0.1:7272/basic-html-elements.html diff --git a/PuppeteerLibrary/playwright/async_keywords/playwright_element.py b/PuppeteerLibrary/playwright/async_keywords/playwright_element.py index ff1e895..a3da1a7 100644 --- a/PuppeteerLibrary/playwright/async_keywords/playwright_element.py +++ b/PuppeteerLibrary/playwright/async_keywords/playwright_element.py @@ -17,31 +17,50 @@ async def click_element(self, locator: str): # Status ############################## async def element_should_be_enabled(self, locator: str): - pass + element = await self.library_ctx.get_current_page().querySelector_with_selenium_locator(locator) + is_disabled = await (await element.getProperty('disabled')).jsonValue() + if is_disabled: + raise AssertionError("Element '%s' is disabled. " % locator) + return element async def element_should_be_disabled(self, locator: str): - pass + element = await self.library_ctx.get_current_page().querySelector_with_selenium_locator(locator) + is_disabled = await (await element.getProperty('disabled')).jsonValue() + if not is_disabled: + raise AssertionError("Element '%s' is enabled. " % locator) + return element async def element_should_be_visible(self, locator:str): - pass + try: + return await self.library_ctx.get_current_page().waitForSelector_with_selenium_locator(locator, 0.1, visible=True, hidden=False) + except: + raise AssertionError("Element '%s' is not be visible. " % locator) async def element_should_not_be_visible(self, locator:str): - pass + try: + return await self.library_ctx.get_current_page().waitForSelector_with_selenium_locator(locator, 0.1, visible=False, hidden=True) + except: + raise AssertionError("Element '%s' is visible. " % locator) ############################## # Property ############################## async def element_should_contain(self, locator: str, expected: str, ignore_case=False): - pass + text = await self.get_text(locator) + return BuiltIn().should_contain(text, expected, ignore_case=ignore_case) async def element_should_not_contain(self, locator: str, expected: str, ignore_case=False): - pass + text = await self.get_text(locator) + return BuiltIn().should_not_contain(text, expected, ignore_case=ignore_case) async def get_text(self, locator: str): - pass + element = await self.library_ctx.get_current_page().querySelector_with_selenium_locator(locator) + return (await (await element.getProperty('textContent')).jsonValue()) async def element_text_should_be(self, locator: str, expected: str, ignore_case=False): - pass + text = await self.get_text(locator) + return BuiltIn().should_be_equal_as_strings(text, expected, ignore_case=ignore_case) async def element_text_should_not_be(self, locator: str, expected: str, ignore_case=False): - pass + text = await self.get_text(locator) + return BuiltIn().should_not_be_equal_as_strings(text, expected, ignore_case=ignore_case) diff --git a/PuppeteerLibrary/playwright/custom_elements/playwright_page.py b/PuppeteerLibrary/playwright/custom_elements/playwright_page.py index 02f6f90..b5ae2e8 100644 --- a/PuppeteerLibrary/playwright/custom_elements/playwright_page.py +++ b/PuppeteerLibrary/playwright/custom_elements/playwright_page.py @@ -82,11 +82,21 @@ async def waitForSelector_with_selenium_locator(self, selenium_locator: str, tim # Query ############ async def querySelector(self, selector: str): - pass + if self.selected_iframe is not None: + return await self.selected_iframe.querySelector(selector=selector) + else: + return await self.get_page().querySelector(selector=selector) async def querySelectorAll_with_selenium_locator(self, selenium_locator: str): - pass + selector_value = SelectorAbstraction.get_selector(selenium_locator) + if SelectorAbstraction.is_xpath(selenium_locator): + return await self.get_page().xpath(selector_value) + else: + return await self.get_page().querySelectorAll(selector_value) async def querySelector_with_selenium_locator(self, selenium_locator: str): - pass - + selector_value = SelectorAbstraction.get_selector(selenium_locator) + if SelectorAbstraction.is_xpath(selenium_locator): + return (await self.get_page().xpath(selector_value))[0] + else: + return await self.get_page().querySelector(selector_value) diff --git a/PuppeteerLibrary/puppeteer/custom_elements/puppeteer_page.py b/PuppeteerLibrary/puppeteer/custom_elements/puppeteer_page.py index 0120117..bcd36ed 100644 --- a/PuppeteerLibrary/puppeteer/custom_elements/puppeteer_page.py +++ b/PuppeteerLibrary/puppeteer/custom_elements/puppeteer_page.py @@ -76,22 +76,6 @@ async def waitForSelector_with_selenium_locator(self, selenium_locator: str, tim return await self._waitForXPath(xpath=selector_value, options=options) else: return await self._waitForSelector(selector=selector_value, options=options) - - ''' - options = { - 'timeout': timeout * 1000, - 'state': 'visible' - } - if visible is True: - options['state'] = 'visible' - if hidden is True: - options['state'] = 'hidden' - selector_value = SelectorAbstraction.get_selector(selenium_locator) - return await self.get_page().waitForSelector( - selector=selector_value, - timeout=options['timeout'], - state=options['state']) - ''' async def _waitForSelector(self, selector: str, options: dict = None): if self.selected_iframe is None: From 9bb177c1997f6eb534fa95cfb8c08edd32905bbb Mon Sep 17 00:00:00 2001 From: atthaboons Date: Fri, 23 Oct 2020 11:50:51 +0700 Subject: [PATCH 072/103] Fix browser management for puppeteer --- Examples/browser-management/open-close-browser.robot | 3 ++- PuppeteerLibrary/puppeteer/puppeteer_context.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Examples/browser-management/open-close-browser.robot b/Examples/browser-management/open-close-browser.robot index aa7babc..a0b427e 100644 --- a/Examples/browser-management/open-close-browser.robot +++ b/Examples/browser-management/open-close-browser.robot @@ -1,11 +1,11 @@ *** Settings *** +Library Dialogs Library PuppeteerLibrary Suite Teardown Close Puppeteer Test Teardown Close All Browser *** Variables *** ${DEFAULT_BROWSER} chrome -# ${DEFAULT_BROWSER} webkit *** Test Cases *** @@ -18,6 +18,7 @@ Switch to new browser ... Click Element id=open-new-tab AND ... Wait For New Window Open Switch Window NEW + Dialogs.Pause Execution Wait Until Page Contains Element id=exampleInputEmail1 Switch Window title=Basic HTML Elements Wait Until Page Contains Element id=open-new-tab diff --git a/PuppeteerLibrary/puppeteer/puppeteer_context.py b/PuppeteerLibrary/puppeteer/puppeteer_context.py index f7dba24..1adf9fc 100644 --- a/PuppeteerLibrary/puppeteer/puppeteer_context.py +++ b/PuppeteerLibrary/puppeteer/puppeteer_context.py @@ -79,7 +79,8 @@ def get_current_page(self) -> BasePage: return self.current_page def set_current_page(self, page: any) -> BasePage: - pass + self.current_page = PuppeteerPage(page) + return self.current_page async def get_all_pages(self): return await self.browser.pages() From 3ac9b83bcb1c84d57d97ed6142e08cda7b7f4259 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Fri, 23 Oct 2020 11:57:26 +0700 Subject: [PATCH 073/103] Remove dialog pause --- Examples/browser-management/open-close-browser.robot | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Examples/browser-management/open-close-browser.robot b/Examples/browser-management/open-close-browser.robot index a0b427e..1a40278 100644 --- a/Examples/browser-management/open-close-browser.robot +++ b/Examples/browser-management/open-close-browser.robot @@ -1,5 +1,4 @@ *** Settings *** -Library Dialogs Library PuppeteerLibrary Suite Teardown Close Puppeteer Test Teardown Close All Browser @@ -17,8 +16,7 @@ Switch to new browser Run Async Keywords ... Click Element id=open-new-tab AND ... Wait For New Window Open - Switch Window NEW - Dialogs.Pause Execution + Switch Window NEW Wait Until Page Contains Element id=exampleInputEmail1 Switch Window title=Basic HTML Elements Wait Until Page Contains Element id=open-new-tab From 96e5bc8f71472bef1913eddf4b0fef528f2937d0 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Fri, 23 Oct 2020 14:05:37 +0700 Subject: [PATCH 074/103] Puppeteer support file upload --- Examples/form-handler/file-upload.robot | 6 ++++-- PuppeteerLibrary/keywords/element.py | 2 +- PuppeteerLibrary/keywords/ielement_async.py | 6 +++++- .../puppeteer/async_keywords/puppeteer_element.py | 4 ++++ 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/Examples/form-handler/file-upload.robot b/Examples/form-handler/file-upload.robot index 136554b..2b0730e 100644 --- a/Examples/form-handler/file-upload.robot +++ b/Examples/form-handler/file-upload.robot @@ -1,5 +1,4 @@ *** Settings *** -Force Tags Ignore Library PuppeteerLibrary Test Setup Open browser to test page Test Teardown Close All Browser @@ -7,6 +6,8 @@ Suite Teardown Close Puppeteer *** Variables *** +# ${DEFAULT_BROWSER} chrome +${DEFAULT_BROWSER} webkit ${HOME_PAGE_URL} http://127.0.0.1:7272/basic-html-elements.html @@ -16,6 +17,7 @@ Upload file *** Keywords *** Open browser to test page + ${BROWSER} = Get variable value ${BROWSER} ${DEFAULT_BROWSER} ${HEADLESS} Get variable value ${HEADLESS} ${False} &{options} = create dictionary headless=${HEADLESS} - Open browser ${HOME_PAGE_URL} options=${options} + Open browser ${HOME_PAGE_URL} browser=${BROWSER} options=${options} diff --git a/PuppeteerLibrary/keywords/element.py b/PuppeteerLibrary/keywords/element.py index e01a084..30854e5 100644 --- a/PuppeteerLibrary/keywords/element.py +++ b/PuppeteerLibrary/keywords/element.py @@ -133,4 +133,4 @@ def element_text_should_not_be(self, locator, expected, ignore_case=False): def upload_file(self, locator, file_path): """ Upload file """ - return self.loop.run_until_complete(self.async_func.upload_file_async(locator, file_path)) + return self.loop.run_until_complete(self.get_async_keyword_group().upload_file(locator, file_path)) diff --git a/PuppeteerLibrary/keywords/ielement_async.py b/PuppeteerLibrary/keywords/ielement_async.py index ec9e6ae..7a4e17a 100644 --- a/PuppeteerLibrary/keywords/ielement_async.py +++ b/PuppeteerLibrary/keywords/ielement_async.py @@ -5,11 +5,15 @@ class iElementAsync(BaseAsyncKeywords, ABC): ############################## - # Click + # Action ############################## @abstractmethod async def click_element(self, locator: str): pass + + @abstractmethod + async def upload_file(self, locator: str, file_path: str): + pass ############################## # Status diff --git a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_element.py b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_element.py index 9d10044..32793fc 100644 --- a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_element.py +++ b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_element.py @@ -13,6 +13,10 @@ def __init__(self, library_ctx): async def click_element(self, locator: str): return await self.library_ctx.get_current_page().click_with_selenium_locator(locator) + async def upload_file(self, locator: str, file_path: str): + element = await self.library_ctx.get_current_page().querySelector_with_selenium_locator(locator) + await element.uploadFile(file_path) + ############################## # Status ############################## From 85ed9e33403b0e1a7f024edd4bfa3f2785e78c85 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Fri, 23 Oct 2020 14:18:18 +0700 Subject: [PATCH 075/103] Playwright file upload --- Examples/form-handler/file-upload.robot | 3 +-- .../playwright/async_keywords/playwright_element.py | 4 ++++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Examples/form-handler/file-upload.robot b/Examples/form-handler/file-upload.robot index 2b0730e..f611249 100644 --- a/Examples/form-handler/file-upload.robot +++ b/Examples/form-handler/file-upload.robot @@ -6,8 +6,7 @@ Suite Teardown Close Puppeteer *** Variables *** -# ${DEFAULT_BROWSER} chrome -${DEFAULT_BROWSER} webkit +${DEFAULT_BROWSER} chrome ${HOME_PAGE_URL} http://127.0.0.1:7272/basic-html-elements.html diff --git a/PuppeteerLibrary/playwright/async_keywords/playwright_element.py b/PuppeteerLibrary/playwright/async_keywords/playwright_element.py index a3da1a7..b3a436a 100644 --- a/PuppeteerLibrary/playwright/async_keywords/playwright_element.py +++ b/PuppeteerLibrary/playwright/async_keywords/playwright_element.py @@ -13,6 +13,10 @@ def __init__(self, library_ctx): async def click_element(self, locator: str): return await self.library_ctx.get_current_page().click_with_selenium_locator(locator) + async def upload_file(self, locator: str, file_path: str): + element = await self.library_ctx.get_current_page().querySelector_with_selenium_locator(locator) + await element.setInputFiles(file_path) + ############################## # Status ############################## From 3b6b4b0cac8790e8f9a6dbc7050f8865e3cc40c3 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Fri, 23 Oct 2020 16:32:31 +0700 Subject: [PATCH 076/103] Puppeteer form element --- Examples/form-handler/form-submit.robot | 10 +++++++--- PuppeteerLibrary/keywords/formelement.py | 8 ++++++-- .../keywords/iformelement_async.py | 14 +++++++++++++ .../async_keywords/puppeteer_formelement.py | 20 +++++++++++++++++++ .../custom_elements/puppeteer_page.py | 9 +++++++-- .../puppeteer/puppeteer_context.py | 2 ++ 6 files changed, 56 insertions(+), 7 deletions(-) create mode 100644 PuppeteerLibrary/keywords/iformelement_async.py create mode 100644 PuppeteerLibrary/puppeteer/async_keywords/puppeteer_formelement.py diff --git a/Examples/form-handler/form-submit.robot b/Examples/form-handler/form-submit.robot index 711e4c4..09808a7 100644 --- a/Examples/form-handler/form-submit.robot +++ b/Examples/form-handler/form-submit.robot @@ -1,9 +1,12 @@ *** Settings *** -Force Tags Ignore Library PuppeteerLibrary Test Teardown Close All Browser Suite Teardown Close Puppeteer +*** Variables *** +# ${DEFAULT_BROWSER} chrome +${DEFAULT_BROWSER} webkit + *** Test Cases *** Submit login form @@ -15,7 +18,7 @@ Submit login form ... Wait For New Window Open AND ... Click Element css=button[type="submit"] Switch Window NEW - Wait Until Page Contains Login succeeded + Wait Until Page Contains Login succeeded Submit register form Open browser to test page http://127.0.0.1:7272/register-form-example.html @@ -30,6 +33,7 @@ Submit register form *** Keywords *** Open browser to test page [Arguments] ${url} + ${BROWSER} = Get variable value ${BROWSER} ${DEFAULT_BROWSER} ${HEADLESS} Get variable value ${HEADLESS} ${False} &{options} = create dictionary headless=${HEADLESS} - Open browser ${url} options=${options} + Open browser ${url} browser=${BROWSER} options=${options} diff --git a/PuppeteerLibrary/keywords/formelement.py b/PuppeteerLibrary/keywords/formelement.py index 37b96b9..3608a02 100644 --- a/PuppeteerLibrary/keywords/formelement.py +++ b/PuppeteerLibrary/keywords/formelement.py @@ -1,3 +1,4 @@ +from PuppeteerLibrary.keywords.iformelement_async import iFormElementAsync from PuppeteerLibrary.base.librarycomponent import LibraryComponent from PuppeteerLibrary.base.robotlibcore import keyword from PuppeteerLibrary.keywords.formelement_async import FormElementKeywordsAsync @@ -9,6 +10,9 @@ def __init__(self, ctx): super().__init__(ctx) self.async_func = FormElementKeywordsAsync(self.ctx) + def get_async_keyword_group(self) -> iFormElementAsync: + return self.ctx.get_current_library_context().get_async_keyword_group(type(self).__name__) + @keyword def input_text(self, locator, text, clear=True): """Types the given text into text field identified by ``locator``. @@ -21,7 +25,7 @@ def input_text(self, locator, text, clear=True): | `Input Text` | id:username | john | True | """ - self.loop.run_until_complete(self.async_func.input_text_async(locator, text, clear)) + self.loop.run_until_complete(self.get_async_keyword_group().input_text(locator, text, clear)) @keyword def clear_element_text(self, locator): @@ -31,5 +35,5 @@ def clear_element_text(self, locator): | `Clear Element Text` | id:name | """ - self.loop.run_until_complete(self.async_func.clear_element_text_async(locator)) + self.loop.run_until_complete(self.get_async_keyword_group().clear_element_text(locator)) diff --git a/PuppeteerLibrary/keywords/iformelement_async.py b/PuppeteerLibrary/keywords/iformelement_async.py new file mode 100644 index 0000000..fb7fc90 --- /dev/null +++ b/PuppeteerLibrary/keywords/iformelement_async.py @@ -0,0 +1,14 @@ +from PuppeteerLibrary.keywords.base_async_keywords import BaseAsyncKeywords +from abc import ABC, abstractmethod + + +class iFormElementAsync(BaseAsyncKeywords, ABC): + + @abstractmethod + async def input_text(self, locator: str, text: str, clear=True): + pass + + @abstractmethod + async def clear_element_text(self, locator: str): + pass + \ No newline at end of file diff --git a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_formelement.py b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_formelement.py new file mode 100644 index 0000000..0cefd75 --- /dev/null +++ b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_formelement.py @@ -0,0 +1,20 @@ +from robot.libraries.BuiltIn import BuiltIn +from PuppeteerLibrary.keywords.iformelement_async import iFormElementAsync + + +class PuppeteerFormElement(iFormElementAsync): + + def __init__(self, library_ctx): + super().__init__(library_ctx) + + async def input_text(self, locator: str, text: str, clear=True): + if clear: + await self._clear_input_text(locator) + await self.library_ctx.get_current_page().type_with_selenium_locator(locator, text) + + async def clear_element_text(self, locator: str): + await self._clear_input_text(locator) + + async def _clear_input_text(self, selenium_locator): + await self.library_ctx.get_current_page().click_with_selenium_locator(selenium_locator, {'clickCount': 3}) + await self.library_ctx.get_current_page().get_page().keyboard.press('Backspace') diff --git a/PuppeteerLibrary/puppeteer/custom_elements/puppeteer_page.py b/PuppeteerLibrary/puppeteer/custom_elements/puppeteer_page.py index bcd36ed..87a6113 100644 --- a/PuppeteerLibrary/puppeteer/custom_elements/puppeteer_page.py +++ b/PuppeteerLibrary/puppeteer/custom_elements/puppeteer_page.py @@ -57,10 +57,15 @@ async def click_xpath(self, selector: str, options: dict = None, **kwargs: Any): # Type ############ async def type_with_selenium_locator(self, selenium_locator: str, text: str, options: dict = None, **kwargs: Any): - pass + selector_value = SelectorAbstraction.get_selector(selenium_locator) + if SelectorAbstraction.is_xpath(selenium_locator): + await self.type_xpath(selector=selector_value, text=text, options=options, kwargs=kwargs) + else: + await self.get_page().type(selector=selector_value, text=text, options=options, kwargs=kwargs) async def type_xpath(self, selector, text: str, options: dict = None, **kwargs: Any): - pass + element = await self.get_page().xpath(selector) + await element[0].type(text, options, **kwargs) ############ # Wait diff --git a/PuppeteerLibrary/puppeteer/puppeteer_context.py b/PuppeteerLibrary/puppeteer/puppeteer_context.py index 1adf9fc..c703f26 100644 --- a/PuppeteerLibrary/puppeteer/puppeteer_context.py +++ b/PuppeteerLibrary/puppeteer/puppeteer_context.py @@ -9,6 +9,7 @@ from PuppeteerLibrary.puppeteer.async_keywords.puppeteer_browsermanagement import PuppeteerBrowserManagement from PuppeteerLibrary.puppeteer.async_keywords.puppeteer_dropdown import PuppeteerDropdown from PuppeteerLibrary.puppeteer.async_keywords.puppeteer_element import PuppeteerElement +from PuppeteerLibrary.puppeteer.async_keywords.puppeteer_formelement import PuppeteerFormElement from PuppeteerLibrary.puppeteer.custom_elements.puppeteer_page import PuppeteerPage from PuppeteerLibrary.utils.device_descriptors import DEVICE_DESCRIPTORS @@ -97,6 +98,7 @@ def get_async_keyword_group(self, keyword_group_name: str): "BrowserManagementKeywords": PuppeteerBrowserManagement(self), "DropdownKeywords": PuppeteerDropdown(self), "ElementKeywords": PuppeteerElement(self), + "FormElementKeywords": PuppeteerFormElement(self), "ScreenshotKeywords": PuppeteerScreenshot(self), "WaitingKeywords": PuppeteerWaiting(self) } From eb247a7502244632858283e0930bf532fbf7e2e4 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Fri, 23 Oct 2020 20:59:57 +0700 Subject: [PATCH 077/103] Playwright formelement keywords --- Examples/form-handler/form-submit.robot | 3 +-- .../async_keywords/playwright_formelement.py | 22 +++++++++++++++++++ .../custom_elements/playwright_page.py | 21 +++++++++++++----- .../playwright/playwright_context.py | 4 +++- 4 files changed, 42 insertions(+), 8 deletions(-) create mode 100644 PuppeteerLibrary/playwright/async_keywords/playwright_formelement.py diff --git a/Examples/form-handler/form-submit.robot b/Examples/form-handler/form-submit.robot index 09808a7..ba55aa7 100644 --- a/Examples/form-handler/form-submit.robot +++ b/Examples/form-handler/form-submit.robot @@ -4,8 +4,7 @@ Test Teardown Close All Browser Suite Teardown Close Puppeteer *** Variables *** -# ${DEFAULT_BROWSER} chrome -${DEFAULT_BROWSER} webkit +${DEFAULT_BROWSER} chrome *** Test Cases *** diff --git a/PuppeteerLibrary/playwright/async_keywords/playwright_formelement.py b/PuppeteerLibrary/playwright/async_keywords/playwright_formelement.py new file mode 100644 index 0000000..6d28466 --- /dev/null +++ b/PuppeteerLibrary/playwright/async_keywords/playwright_formelement.py @@ -0,0 +1,22 @@ +from PuppeteerLibrary.keywords.iformelement_async import iFormElementAsync +from PuppeteerLibrary.locators.SelectorAbstraction import SelectorAbstraction + + +class PlaywrightFormElement(iFormElementAsync): + + def __init__(self, library_ctx): + super().__init__(library_ctx) + + async def input_text(self, locator: str, text: str, clear=True): + if clear: + await self._clear_input_text(locator) + await self.library_ctx.get_current_page().type_with_selenium_locator(locator, text) + + async def clear_element_text(self, locator: str): + await self._clear_input_text(locator) + + async def _clear_input_text(self, selenium_locator): + await self.library_ctx.get_current_page().click_with_selenium_locator(selenium_locator, {'clickCount': 3}) + await self.library_ctx.get_current_page().get_page().keyboard.press('Backspace') + + \ No newline at end of file diff --git a/PuppeteerLibrary/playwright/custom_elements/playwright_page.py b/PuppeteerLibrary/playwright/custom_elements/playwright_page.py index b5ae2e8..8b40fba 100644 --- a/PuppeteerLibrary/playwright/custom_elements/playwright_page.py +++ b/PuppeteerLibrary/playwright/custom_elements/playwright_page.py @@ -41,23 +41,34 @@ async def click(self, selector: str, options: dict = None, **kwargs: Any): return await self.selected_iframe.click(selector=selector, options=options, kwargs=kwargs) async def click_with_selenium_locator(self, selenium_locator: str, options: dict = None, **kwargs: Any): + if options is None: + options = {} selector_value = SelectorAbstraction.get_selector(selenium_locator) if SelectorAbstraction.is_xpath(selenium_locator): - await self.page.click_xpath(selector_value, options, **kwargs) + await self.page.click_xpath(selector_value, **options) else: - await self.page.click(selector_value, options, **kwargs) + await self.page.click(selector_value, **options) async def click_xpath(self, selector: str, options: dict = None, **kwargs: Any): - pass + raise Exception('Not implemented click_xpath.') ############ # Type ############ async def type_with_selenium_locator(self, selenium_locator: str, text: str, options: dict = None, **kwargs: Any): - pass + if options is None: + options = {} + selector_value = SelectorAbstraction.get_selector(selenium_locator) + if SelectorAbstraction.is_xpath(selenium_locator): + await self.type_xpath(selector=selector_value, text=text, **options) + else: + await self.get_page().type(selector=selector_value, text=text, **options) async def type_xpath(self, selector, text: str, options: dict = None, **kwargs: Any): - pass + if options is None: + options = {} + element = await self.get_page().xpath(selector) + await element[0].type(text, **options) ############ # Wait diff --git a/PuppeteerLibrary/playwright/playwright_context.py b/PuppeteerLibrary/playwright/playwright_context.py index 8e04f91..2a51507 100644 --- a/PuppeteerLibrary/playwright/playwright_context.py +++ b/PuppeteerLibrary/playwright/playwright_context.py @@ -1,5 +1,6 @@ -from PuppeteerLibrary.playwright.async_keywords.playwright_dropdown import PlaywrightDropdown from PuppeteerLibrary.custom_elements.base_page import BasePage +from PuppeteerLibrary.playwright.async_keywords.playwright_formelement import PlaywrightFormElement +from PuppeteerLibrary.playwright.async_keywords.playwright_dropdown import PlaywrightDropdown from PuppeteerLibrary.playwright.async_keywords.playwright_alert import PlaywrightAlert from PuppeteerLibrary.playwright.async_keywords.playwright_screenshot import PlaywrightScreenshot from PuppeteerLibrary.playwright.async_keywords.playwright_waiting import PlaywrightWaiting @@ -74,6 +75,7 @@ def get_async_keyword_group(self, keyword_group_name: str): "BrowserManagementKeywords": PlaywrightBrowserManagement(self), "DropdownKeywords": PlaywrightDropdown(self), "ElementKeywords": PlaywrightElement(self), + "FormElementKeywords": PlaywrightFormElement(self), "ScreenshotKeywords": PlaywrightScreenshot(self), "WaitingKeywords": PlaywrightWaiting(self) } From bba3da9e5ba3c69918ea0d9116300b103e3a6480 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Fri, 23 Oct 2020 22:08:51 +0700 Subject: [PATCH 078/103] puppeteer iframe keywords --- Examples/form-handler/iframe.robot | 9 ++++--- PuppeteerLibrary/custom_elements/base_page.py | 15 +++++++++-- .../keywords/browsermanagement.py | 6 ++--- .../keywords/ibrowsermanagement_async.py | 11 ++++++++ .../playwright_browsermanagement.py | 10 ++++++++ .../custom_elements/playwright_page.py | 9 +++++++ .../puppeteer_browsermanagement.py | 11 ++++++++ .../custom_elements/puppeteer_page.py | 25 +++++++++++-------- 8 files changed, 78 insertions(+), 18 deletions(-) diff --git a/Examples/form-handler/iframe.robot b/Examples/form-handler/iframe.robot index 0fa0669..74130a5 100644 --- a/Examples/form-handler/iframe.robot +++ b/Examples/form-handler/iframe.robot @@ -1,5 +1,4 @@ *** Settings *** -Force Tags Ignore Library PuppeteerLibrary Test Setup Open browser to test page Test Teardown Close All Browser @@ -7,6 +6,7 @@ Suite Teardown Close Puppeteer *** Variables *** +${DEFAULT_BROWSER} chrome ${HOME_PAGE_URL} http://127.0.0.1:7272/basic-html-elements.html @@ -15,9 +15,12 @@ Interact with iframe element Wait Until Page Contains Element id=ifrm Select Frame id=ifrm Click Element id=exampleCheck1 + Unselect Frame + Wait Until Page Contains Element id=ifrm *** Keywords *** Open browser to test page + ${BROWSER} = Get variable value ${BROWSER} ${DEFAULT_BROWSER} ${HEADLESS} Get variable value ${HEADLESS} ${False} - &{options} = create dictionary headless=${HEADLESS} - Open browser ${HOME_PAGE_URL} options=${options} + &{options} = create dictionary headless=${HEADLESS} + Open browser ${HOME_PAGE_URL} browser=${BROWSER} options=${options} diff --git a/PuppeteerLibrary/custom_elements/base_page.py b/PuppeteerLibrary/custom_elements/base_page.py index 2919bd9..28b6dc5 100644 --- a/PuppeteerLibrary/custom_elements/base_page.py +++ b/PuppeteerLibrary/custom_elements/base_page.py @@ -60,9 +60,9 @@ async def type_xpath(self, selector, text: str, options: dict = None, **kwargs: async def waitForSelector_with_selenium_locator(self, selenium_locator: str, timeout: float, visible=False, hidden=False): pass - ############ + ############################## # Query - ############ + ############################## @abstractmethod async def querySelector(self, selector: str): pass @@ -74,3 +74,14 @@ async def querySelectorAll_with_selenium_locator(self, selenium_locator: str): @abstractmethod async def querySelector_with_selenium_locator(self, selenium_locator: str): pass + + ############################## + # iframe + ############################## + @abstractmethod + def set_current_iframe(self, iframe): + pass + + @abstractmethod + def unselect_iframe(self): + pass diff --git a/PuppeteerLibrary/keywords/browsermanagement.py b/PuppeteerLibrary/keywords/browsermanagement.py index f80f64c..389e6f0 100644 --- a/PuppeteerLibrary/keywords/browsermanagement.py +++ b/PuppeteerLibrary/keywords/browsermanagement.py @@ -178,9 +178,9 @@ def enable_emulate_mode(self, emulate_name): return self.loop.run_until_complete(self.get_async_keyword_group().enable_emulate_mode_async(emulate_name)) @keyword - def select_frame(self, selenium_locator): - return self.loop.run_until_complete(self.async_func.select_frame_async(selenium_locator)) + def select_frame(self, locator): + return self.loop.run_until_complete(self.get_async_keyword_group().select_frame(locator)) @keyword def unselect_frame(self): - self.ctx.clear_current_iframe() + self.get_async_keyword_group().unselect_iframe() diff --git a/PuppeteerLibrary/keywords/ibrowsermanagement_async.py b/PuppeteerLibrary/keywords/ibrowsermanagement_async.py index 044c5a2..fc3dcff 100644 --- a/PuppeteerLibrary/keywords/ibrowsermanagement_async.py +++ b/PuppeteerLibrary/keywords/ibrowsermanagement_async.py @@ -31,3 +31,14 @@ async def wait_for_new_window_open(self, timeout=None): @abstractmethod async def switch_window(self, locator='MAIN'): pass + + ############################## + # iFrame + ############################## + @abstractmethod + async def select_frame(self, locator: str): + pass + + @abstractmethod + def unselect_iframe(self): + pass diff --git a/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py b/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py index 3683ee1..2fae6b4 100644 --- a/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py +++ b/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py @@ -88,3 +88,13 @@ async def switch_window(self, locator='MAIN'): else: raise Exception('Sorry Switch window support only NEW, MAIN, title and url') raise Exception('Can\'t find specify page locator.') + + ############################## + # iFrame + ############################## + async def select_frame(self, locator: str): + raise Exception('Not implemented.') + + async def unselect_frame(self): + raise Exception('Not implemented.') + diff --git a/PuppeteerLibrary/playwright/custom_elements/playwright_page.py b/PuppeteerLibrary/playwright/custom_elements/playwright_page.py index 8b40fba..c0099ea 100644 --- a/PuppeteerLibrary/playwright/custom_elements/playwright_page.py +++ b/PuppeteerLibrary/playwright/custom_elements/playwright_page.py @@ -111,3 +111,12 @@ async def querySelector_with_selenium_locator(self, selenium_locator: str): return (await self.get_page().xpath(selector_value))[0] else: return await self.get_page().querySelector(selector_value) + + ############################## + # iframe + ############################## + def set_current_iframe(self, iframe): + self.selected_iframe = iframe + + def unselect_iframe(self): + self.selected_iframe = None diff --git a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_browsermanagement.py b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_browsermanagement.py index 1c3f1df..beb58ca 100644 --- a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_browsermanagement.py +++ b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_browsermanagement.py @@ -84,3 +84,14 @@ async def switch_window(self, locator='MAIN'): raise Exception('Sorry Switch window support only NEW, MAIN, title and url') raise Exception('Can\'t find specify page locator.') + ############################## + # iFrame + ############################## + async def select_frame(self, locator: str): + element = await self.library_ctx.get_current_page().querySelector_with_selenium_locator(locator) + iframe = await element.contentFrame() + self.library_ctx.get_current_page().set_current_iframe(iframe) + + def unselect_iframe(self): + self.library_ctx.get_current_page().unselect_iframe() + diff --git a/PuppeteerLibrary/puppeteer/custom_elements/puppeteer_page.py b/PuppeteerLibrary/puppeteer/custom_elements/puppeteer_page.py index 87a6113..1da12ef 100644 --- a/PuppeteerLibrary/puppeteer/custom_elements/puppeteer_page.py +++ b/PuppeteerLibrary/puppeteer/custom_elements/puppeteer_page.py @@ -34,21 +34,18 @@ async def set_viewport_size(self, width: int, height: int): ############ # Click ############ - async def click(self, selector: str, options: dict = None, **kwargs: Any): - pass - ''' - if self.selected_iframe is None: - return await self.page.click(selector=selector, options=options, kwargs=kwargs) - else: - return await self.selected_iframe.click(selector=selector, options=options, kwargs=kwargs) - ''' - async def click_with_selenium_locator(self, selenium_locator: str, options: dict = None, **kwargs: Any): selector_value = SelectorAbstraction.get_selector(selenium_locator) if SelectorAbstraction.is_xpath(selenium_locator): await self.page.click_xpath(selector_value, options, **kwargs) else: - await self.page.click(selector_value, options, **kwargs) + await self.click(selector_value, options, **kwargs) + + async def click(self, selector: str, options: dict = None, **kwargs: Any): + if self.selected_iframe is not None: + return await self.selected_iframe.click(selector=selector, options=options, kwargs=kwargs) + else: + return await self.page.click(selector=selector, options=options, kwargs=kwargs) async def click_xpath(self, selector: str, options: dict = None, **kwargs: Any): pass @@ -117,3 +114,11 @@ async def querySelector_with_selenium_locator(self, selenium_locator: str): else: return await self.get_page().querySelector(selector_value) + ############################## + # iframe + ############################## + def set_current_iframe(self, iframe): + self.selected_iframe = iframe + + def unselect_iframe(self): + self.selected_iframe = None From 5d55e117136eb2af29076404a220194e89b7181a Mon Sep 17 00:00:00 2001 From: atthaboons Date: Sat, 24 Oct 2020 06:58:43 +0700 Subject: [PATCH 079/103] Puppeteer iframe support --- Examples/form-handler/form-submit.robot | 2 +- Examples/form-handler/iframe.robot | 3 +++ .../custom_elements/puppeteer_page.py | 27 ++++++++++++++----- 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/Examples/form-handler/form-submit.robot b/Examples/form-handler/form-submit.robot index ba55aa7..65f7fd1 100644 --- a/Examples/form-handler/form-submit.robot +++ b/Examples/form-handler/form-submit.robot @@ -11,7 +11,7 @@ ${DEFAULT_BROWSER} chrome Submit login form Open browser to test page http://127.0.0.1:7272/login-form-example.html Input Text id=exampleInputEmail1 demo@qahive.com - Input Text id=exampleInputPassword1 123456789 + Input Text xpath=//*[@id='exampleInputPassword1'] 123456789 Click Element id=exampleCheck1 Run Async Keywords ... Wait For New Window Open AND diff --git a/Examples/form-handler/iframe.robot b/Examples/form-handler/iframe.robot index 74130a5..d55030c 100644 --- a/Examples/form-handler/iframe.robot +++ b/Examples/form-handler/iframe.robot @@ -14,7 +14,10 @@ ${HOME_PAGE_URL} http://127.0.0.1:7272/basic-html-elements.html Interact with iframe element Wait Until Page Contains Element id=ifrm Select Frame id=ifrm + Input Text id=exampleInputEmail1 demo@qahive.com + Input Text xpath=//*[@id='exampleInputPassword1'] 123456789 Click Element id=exampleCheck1 + Click Element xpath=//*[@id='exampleCheck1'] Unselect Frame Wait Until Page Contains Element id=ifrm diff --git a/PuppeteerLibrary/puppeteer/custom_elements/puppeteer_page.py b/PuppeteerLibrary/puppeteer/custom_elements/puppeteer_page.py index 1da12ef..896e3bb 100644 --- a/PuppeteerLibrary/puppeteer/custom_elements/puppeteer_page.py +++ b/PuppeteerLibrary/puppeteer/custom_elements/puppeteer_page.py @@ -37,7 +37,7 @@ async def set_viewport_size(self, width: int, height: int): async def click_with_selenium_locator(self, selenium_locator: str, options: dict = None, **kwargs: Any): selector_value = SelectorAbstraction.get_selector(selenium_locator) if SelectorAbstraction.is_xpath(selenium_locator): - await self.page.click_xpath(selector_value, options, **kwargs) + await self.click_xpath(selector_value, options, **kwargs) else: await self.click(selector_value, options, **kwargs) @@ -45,10 +45,15 @@ async def click(self, selector: str, options: dict = None, **kwargs: Any): if self.selected_iframe is not None: return await self.selected_iframe.click(selector=selector, options=options, kwargs=kwargs) else: - return await self.page.click(selector=selector, options=options, kwargs=kwargs) + return await self.get_page().click(selector=selector, options=options, kwargs=kwargs) async def click_xpath(self, selector: str, options: dict = None, **kwargs: Any): - pass + if self.selected_iframe is not None: + elements = await self.selected_iframe.xpath(selector) + return await elements[0].click(options, **kwargs) + else: + elements = await self.get_page().xpath(selector) + return await elements[0].click(options, **kwargs) ############ # Type @@ -58,11 +63,21 @@ async def type_with_selenium_locator(self, selenium_locator: str, text: str, opt if SelectorAbstraction.is_xpath(selenium_locator): await self.type_xpath(selector=selector_value, text=text, options=options, kwargs=kwargs) else: - await self.get_page().type(selector=selector_value, text=text, options=options, kwargs=kwargs) + await self.type(selector=selector_value, text=text, options=options, kwargs=kwargs) + + async def type(self, selector, text: str, options: dict = None, **kwargs: Any): + if self.selected_iframe is not None: + return await self.selected_iframe.type(selector=selector, text=text, options=options, kwargs=kwargs) + else: + return await self.get_page().type(selector=selector, text=text, options=options, kwargs=kwargs) async def type_xpath(self, selector, text: str, options: dict = None, **kwargs: Any): - element = await self.get_page().xpath(selector) - await element[0].type(text, options, **kwargs) + if self.selected_iframe is not None: + elements = await self.selected_iframe.xpath(selector) + await elements[0].type(text, options, **kwargs) + else: + elements = await self.get_page().xpath(selector) + await elements[0].type(text, options, **kwargs) ############ # Wait From 3d6c5446917b8792ce55315e88d2e6d6e6428fe3 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Sat, 24 Oct 2020 07:04:03 +0700 Subject: [PATCH 080/103] update properties --- Examples/form-handler/iframe.robot | 3 ++- .../custom_elements/puppeteer_page.py | 22 +++++++++---------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/Examples/form-handler/iframe.robot b/Examples/form-handler/iframe.robot index d55030c..9ef718e 100644 --- a/Examples/form-handler/iframe.robot +++ b/Examples/form-handler/iframe.robot @@ -6,7 +6,8 @@ Suite Teardown Close Puppeteer *** Variables *** -${DEFAULT_BROWSER} chrome +# ${DEFAULT_BROWSER} chrome +${DEFAULT_BROWSER} webkit ${HOME_PAGE_URL} http://127.0.0.1:7272/basic-html-elements.html diff --git a/PuppeteerLibrary/puppeteer/custom_elements/puppeteer_page.py b/PuppeteerLibrary/puppeteer/custom_elements/puppeteer_page.py index 896e3bb..b1f92ca 100644 --- a/PuppeteerLibrary/puppeteer/custom_elements/puppeteer_page.py +++ b/PuppeteerLibrary/puppeteer/custom_elements/puppeteer_page.py @@ -45,14 +45,14 @@ async def click(self, selector: str, options: dict = None, **kwargs: Any): if self.selected_iframe is not None: return await self.selected_iframe.click(selector=selector, options=options, kwargs=kwargs) else: - return await self.get_page().click(selector=selector, options=options, kwargs=kwargs) + return await self.page.click(selector=selector, options=options, kwargs=kwargs) async def click_xpath(self, selector: str, options: dict = None, **kwargs: Any): if self.selected_iframe is not None: elements = await self.selected_iframe.xpath(selector) return await elements[0].click(options, **kwargs) else: - elements = await self.get_page().xpath(selector) + elements = await self.page.xpath(selector) return await elements[0].click(options, **kwargs) ############ @@ -69,14 +69,14 @@ async def type(self, selector, text: str, options: dict = None, **kwargs: Any): if self.selected_iframe is not None: return await self.selected_iframe.type(selector=selector, text=text, options=options, kwargs=kwargs) else: - return await self.get_page().type(selector=selector, text=text, options=options, kwargs=kwargs) + return await self.page.type(selector=selector, text=text, options=options, kwargs=kwargs) async def type_xpath(self, selector, text: str, options: dict = None, **kwargs: Any): if self.selected_iframe is not None: elements = await self.selected_iframe.xpath(selector) await elements[0].type(text, options, **kwargs) else: - elements = await self.get_page().xpath(selector) + elements = await self.page.xpath(selector) await elements[0].type(text, options, **kwargs) ############ @@ -96,13 +96,13 @@ async def waitForSelector_with_selenium_locator(self, selenium_locator: str, tim async def _waitForSelector(self, selector: str, options: dict = None): if self.selected_iframe is None: - return await self.get_page().waitForSelector(selector=selector, options=options) + return await self.page.waitForSelector(selector=selector, options=options) else: return await self.selected_iframe.waitForSelector(selector=selector, options=options) async def _waitForXPath(self, xpath: str, options: dict = None): if self.selected_iframe is None: - return await self.get_page().waitForXPath(xpath=xpath, options=options) + return await self.page.waitForXPath(xpath=xpath, options=options) else: return await self.selected_iframe.waitForXPath(xpath=xpath, options=options) @@ -113,21 +113,21 @@ async def querySelector(self, selector: str): if self.selected_iframe is not None: return await self.selected_iframe.querySelector(selector=selector) else: - return await self.get_page().querySelector(selector=selector) + return await self.page.querySelector(selector=selector) async def querySelectorAll_with_selenium_locator(self, selenium_locator: str): selector_value = SelectorAbstraction.get_selector(selenium_locator) if SelectorAbstraction.is_xpath(selenium_locator): - return await self.get_page().xpath(selector_value) + return await self.page.xpath(selector_value) else: - return await self.get_page().querySelectorAll(selector_value) + return await self.page.querySelectorAll(selector_value) async def querySelector_with_selenium_locator(self, selenium_locator: str): selector_value = SelectorAbstraction.get_selector(selenium_locator) if SelectorAbstraction.is_xpath(selenium_locator): - return (await self.get_page().xpath(selector_value))[0] + return (await self.page.xpath(selector_value))[0] else: - return await self.get_page().querySelector(selector_value) + return await self.page.querySelector(selector_value) ############################## # iframe From ee5c2b0569a02334b75c6d5826f357f7131e6259 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Sat, 24 Oct 2020 07:43:30 +0700 Subject: [PATCH 081/103] Playwright iframe --- Examples/form-handler/iframe.robot | 3 +- PuppeteerLibrary/custom_elements/base_page.py | 12 -------- .../playwright_browsermanagement.py | 8 +++-- .../custom_elements/playwright_page.py | 29 +++++-------------- 4 files changed, 13 insertions(+), 39 deletions(-) diff --git a/Examples/form-handler/iframe.robot b/Examples/form-handler/iframe.robot index 9ef718e..d55030c 100644 --- a/Examples/form-handler/iframe.robot +++ b/Examples/form-handler/iframe.robot @@ -6,8 +6,7 @@ Suite Teardown Close Puppeteer *** Variables *** -# ${DEFAULT_BROWSER} chrome -${DEFAULT_BROWSER} webkit +${DEFAULT_BROWSER} chrome ${HOME_PAGE_URL} http://127.0.0.1:7272/basic-html-elements.html diff --git a/PuppeteerLibrary/custom_elements/base_page.py b/PuppeteerLibrary/custom_elements/base_page.py index 28b6dc5..30fcb56 100644 --- a/PuppeteerLibrary/custom_elements/base_page.py +++ b/PuppeteerLibrary/custom_elements/base_page.py @@ -30,18 +30,10 @@ async def set_viewport_size(self, width, height): ############ # Click ############ - @abstractmethod - async def click(self, selector: str, options: dict = None, **kwargs: Any): - pass - @abstractmethod async def click_with_selenium_locator(self, selenium_locator: str, options: dict = None, **kwargs: Any): pass - @abstractmethod - async def click_xpath(self, selector: str, options: dict = None, **kwargs: Any): - pass - ############ # Type ############ @@ -49,10 +41,6 @@ async def click_xpath(self, selector: str, options: dict = None, **kwargs: Any): async def type_with_selenium_locator(self, selenium_locator: str, text: str, options: dict = None, **kwargs: Any): pass - @abstractmethod - async def type_xpath(self, selector, text: str, options: dict = None, **kwargs: Any): - pass - ############ # Wait ############ diff --git a/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py b/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py index 2fae6b4..3e4ccb7 100644 --- a/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py +++ b/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py @@ -93,8 +93,10 @@ async def switch_window(self, locator='MAIN'): # iFrame ############################## async def select_frame(self, locator: str): - raise Exception('Not implemented.') + element = await self.library_ctx.get_current_page().querySelector_with_selenium_locator(locator) + iframe = await element.contentFrame() + self.library_ctx.get_current_page().set_current_iframe(iframe) - async def unselect_frame(self): - raise Exception('Not implemented.') + def unselect_iframe(self): + self.library_ctx.get_current_page().unselect_iframe() diff --git a/PuppeteerLibrary/playwright/custom_elements/playwright_page.py b/PuppeteerLibrary/playwright/custom_elements/playwright_page.py index c0099ea..a46ece7 100644 --- a/PuppeteerLibrary/playwright/custom_elements/playwright_page.py +++ b/PuppeteerLibrary/playwright/custom_elements/playwright_page.py @@ -34,23 +34,15 @@ async def set_viewport_size(self, width: int, height: int): ############ # Click ############ - async def click(self, selector: str, options: dict = None, **kwargs: Any): - if self.selected_iframe is None: - return await self.page.click(selector=selector, options=options, kwargs=kwargs) - else: - return await self.selected_iframe.click(selector=selector, options=options, kwargs=kwargs) - async def click_with_selenium_locator(self, selenium_locator: str, options: dict = None, **kwargs: Any): if options is None: options = {} selector_value = SelectorAbstraction.get_selector(selenium_locator) - if SelectorAbstraction.is_xpath(selenium_locator): - await self.page.click_xpath(selector_value, **options) - else: - await self.page.click(selector_value, **options) - async def click_xpath(self, selector: str, options: dict = None, **kwargs: Any): - raise Exception('Not implemented click_xpath.') + if self.selected_iframe is not None: + return await self.selected_iframe.click(selector=selenium_locator, **options) + else: + return await self.page.click(selector=selenium_locator, **options) ############ # Type @@ -58,17 +50,10 @@ async def click_xpath(self, selector: str, options: dict = None, **kwargs: Any): async def type_with_selenium_locator(self, selenium_locator: str, text: str, options: dict = None, **kwargs: Any): if options is None: options = {} - selector_value = SelectorAbstraction.get_selector(selenium_locator) - if SelectorAbstraction.is_xpath(selenium_locator): - await self.type_xpath(selector=selector_value, text=text, **options) + if self.selected_iframe is not None: + return await self.selected_iframe.type(selector=selenium_locator, text=text, **options) else: - await self.get_page().type(selector=selector_value, text=text, **options) - - async def type_xpath(self, selector, text: str, options: dict = None, **kwargs: Any): - if options is None: - options = {} - element = await self.get_page().xpath(selector) - await element[0].type(text, **options) + return await self.page.type(selector=selenium_locator, text=text, **options) ############ # Wait From dd3aa581a8461afc965bd7d13588a4b6d6ba105d Mon Sep 17 00:00:00 2001 From: atthaboons Date: Thu, 29 Oct 2020 07:21:17 +0700 Subject: [PATCH 082/103] Add Puppeteer mouseevent keywords --- Examples/input/mouse.robot | 5 +++- .../keywords/imouseevent_async.py | 22 ++++++++++++++++ PuppeteerLibrary/keywords/mouseevent.py | 12 ++++++--- .../async_keywords/playwright_mouseevent.py | 20 ++++++++++++++ .../playwright/playwright_context.py | 2 ++ .../async_keywords/puppeteer_mouseevent.py | 26 +++++++++++++++++++ .../puppeteer/puppeteer_context.py | 6 +++-- 7 files changed, 86 insertions(+), 7 deletions(-) create mode 100644 PuppeteerLibrary/keywords/imouseevent_async.py create mode 100644 PuppeteerLibrary/playwright/async_keywords/playwright_mouseevent.py create mode 100644 PuppeteerLibrary/puppeteer/async_keywords/puppeteer_mouseevent.py diff --git a/Examples/input/mouse.robot b/Examples/input/mouse.robot index daec50b..44da1b7 100644 --- a/Examples/input/mouse.robot +++ b/Examples/input/mouse.robot @@ -5,6 +5,8 @@ Test Setup Open browser to test page Test Teardown Close All Browser *** Variables *** +${DEFAULT_BROWSER} chrome +# ${DEFAULT_BROWSER} webkit ${HOME_PAGE_URL} http://127.0.0.1:7272/basic-html-elements.html @@ -23,7 +25,8 @@ Mouse drag *** Keywords *** Open browser to test page + ${BROWSER} = Get variable value ${BROWSER} ${DEFAULT_BROWSER} ${HEADLESS} Get variable value ${HEADLESS} ${False} &{options} = create dictionary headless=${HEADLESS} - Open browser ${HOME_PAGE_URL} options=${options} + Open browser ${HOME_PAGE_URL} browser=${BROWSER} options=${options} diff --git a/PuppeteerLibrary/keywords/imouseevent_async.py b/PuppeteerLibrary/keywords/imouseevent_async.py new file mode 100644 index 0000000..8990038 --- /dev/null +++ b/PuppeteerLibrary/keywords/imouseevent_async.py @@ -0,0 +1,22 @@ +from PuppeteerLibrary.keywords.base_async_keywords import BaseAsyncKeywords +from abc import ABC, abstractmethod + + +class iMouseEventAsync(BaseAsyncKeywords, ABC): + + @abstractmethod + async def mouse_over(self, locator): + pass + + @abstractmethod + async def mouse_down(self, locator): + pass + + @abstractmethod + async def mouse_up(self): + pass + + @abstractmethod + def mouse_move(self, x, y): + pass + \ No newline at end of file diff --git a/PuppeteerLibrary/keywords/mouseevent.py b/PuppeteerLibrary/keywords/mouseevent.py index 6e16b8a..a1a9807 100644 --- a/PuppeteerLibrary/keywords/mouseevent.py +++ b/PuppeteerLibrary/keywords/mouseevent.py @@ -1,3 +1,4 @@ +from PuppeteerLibrary.keywords.imouseevent_async import iMouseEventAsync from PuppeteerLibrary.base.robotlibcore import keyword from PuppeteerLibrary.base.librarycomponent import LibraryComponent from PuppeteerLibrary.keywords.mouseevent_async import MouseEventKeywordsAsync @@ -9,26 +10,29 @@ def __init__(self, ctx): super().__init__(ctx) self.async_func = MouseEventKeywordsAsync(self.ctx) + def get_async_keyword_group(self) -> iMouseEventAsync: + return self.ctx.get_current_library_context().get_async_keyword_group(type(self).__name__) + @keyword def mouse_over(self, locator): """Mouse over the element. """ - return self.loop.run_until_complete(self.async_func.mouse_over_async(locator)) + return self.loop.run_until_complete(self.get_async_keyword_group().mouse_over(locator)) @keyword def mouse_down(self, locator): """Mouse down on the element. """ - return self.loop.run_until_complete(self.async_func.mouse_down_async(locator)) + return self.loop.run_until_complete(self.get_async_keyword_group().mouse_down(locator)) @keyword def mouse_up(self): """Mouse up. """ - return self.loop.run_until_complete(self.async_func.mouse_up_async()) + return self.loop.run_until_complete(self.get_async_keyword_group().mouse_up()) @keyword def mouse_move(self, x, y): """Move mouse to position x, y. """ - return self.loop.run_until_complete(self.async_func.mouse_move_async(x, y)) + return self.loop.run_until_complete(self.get_async_keyword_group().mouse_move(x, y)) diff --git a/PuppeteerLibrary/playwright/async_keywords/playwright_mouseevent.py b/PuppeteerLibrary/playwright/async_keywords/playwright_mouseevent.py new file mode 100644 index 0000000..1d7870b --- /dev/null +++ b/PuppeteerLibrary/playwright/async_keywords/playwright_mouseevent.py @@ -0,0 +1,20 @@ +from robot.libraries.BuiltIn import BuiltIn +from PuppeteerLibrary.keywords.imouseevent_async import iMouseEventAsync + + +class PlaywrightMouseEvent(iMouseEventAsync): + + def __init__(self, library_ctx): + super().__init__(library_ctx) + + async def mouse_over(self, locator): + raise Exception('Not implemented') + + async def mouse_down(self, locator): + raise Exception('Not implemented') + + async def mouse_up(self): + raise Exception('Not implemented') + + async def mouse_move(self, x, y): + raise Exception('Not implemented') diff --git a/PuppeteerLibrary/playwright/playwright_context.py b/PuppeteerLibrary/playwright/playwright_context.py index 2a51507..7690739 100644 --- a/PuppeteerLibrary/playwright/playwright_context.py +++ b/PuppeteerLibrary/playwright/playwright_context.py @@ -6,6 +6,7 @@ from PuppeteerLibrary.playwright.async_keywords.playwright_waiting import PlaywrightWaiting from PuppeteerLibrary.playwright.async_keywords.playwright_element import PlaywrightElement from PuppeteerLibrary.playwright.async_keywords.playwright_dropdown import PlaywrightDropdown +from PuppeteerLibrary.playwright.async_keywords.playwright_mouseevent import PlaywrightMouseEvent from PuppeteerLibrary.playwright.custom_elements.playwright_page import PlaywrightPage from PuppeteerLibrary.playwright.async_keywords.playwright_browsermanagement import PlaywrightBrowserManagement from PuppeteerLibrary.library_context.ilibrary_context import iLibraryContext @@ -76,6 +77,7 @@ def get_async_keyword_group(self, keyword_group_name: str): "DropdownKeywords": PlaywrightDropdown(self), "ElementKeywords": PlaywrightElement(self), "FormElementKeywords": PlaywrightFormElement(self), + "MouseEventKeywords": PlaywrightMouseEvent(self), "ScreenshotKeywords": PlaywrightScreenshot(self), "WaitingKeywords": PlaywrightWaiting(self) } diff --git a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_mouseevent.py b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_mouseevent.py new file mode 100644 index 0000000..765e1ba --- /dev/null +++ b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_mouseevent.py @@ -0,0 +1,26 @@ +from robot.libraries.BuiltIn import BuiltIn +from PuppeteerLibrary.keywords.imouseevent_async import iMouseEventAsync + + +class PuppeteerMouseEvent(iMouseEventAsync): + + def __init__(self, library_ctx): + super().__init__(library_ctx) + + async def mouse_over(self, locator): + element = await self.library_ctx.get_current_page().querySelector_with_selenium_locator(locator) + await element.hover() + + async def mouse_down(self, locator): + element = await self.library_ctx.get_current_page().querySelector_with_selenium_locator(locator) + bounding_box = await element.boundingBox() + await self.library_ctx.get_current_page().get_page().mouse.move( + bounding_box['x'] + bounding_box['width'] / 2, + bounding_box['y'] + bounding_box['height'] / 2) + await self.library_ctx.get_current_page().get_page().mouse.down() + + async def mouse_up(self): + await self.library_ctx.get_current_page().get_page().mouse.up() + + async def mouse_move(self, x, y): + await self.library_ctx.get_current_page().get_page().mouse.move(int(x), int(y)) diff --git a/PuppeteerLibrary/puppeteer/puppeteer_context.py b/PuppeteerLibrary/puppeteer/puppeteer_context.py index c703f26..a7a6af5 100644 --- a/PuppeteerLibrary/puppeteer/puppeteer_context.py +++ b/PuppeteerLibrary/puppeteer/puppeteer_context.py @@ -1,15 +1,16 @@ import sys from pyppeteer import launch from pyppeteer.browser import Browser +from PuppeteerLibrary.custom_elements.base_page import BasePage +from PuppeteerLibrary.library_context.ilibrary_context import iLibraryContext from PuppeteerLibrary.puppeteer.async_keywords.puppeteer_alert import PuppeteerAlert from PuppeteerLibrary.puppeteer.async_keywords.puppeteer_screenshot import PuppeteerScreenshot from PuppeteerLibrary.puppeteer.async_keywords.puppeteer_waiting import PuppeteerWaiting -from PuppeteerLibrary.custom_elements.base_page import BasePage -from PuppeteerLibrary.library_context.ilibrary_context import iLibraryContext from PuppeteerLibrary.puppeteer.async_keywords.puppeteer_browsermanagement import PuppeteerBrowserManagement from PuppeteerLibrary.puppeteer.async_keywords.puppeteer_dropdown import PuppeteerDropdown from PuppeteerLibrary.puppeteer.async_keywords.puppeteer_element import PuppeteerElement from PuppeteerLibrary.puppeteer.async_keywords.puppeteer_formelement import PuppeteerFormElement +from PuppeteerLibrary.puppeteer.async_keywords.puppeteer_mouseevent import PuppeteerMouseEvent from PuppeteerLibrary.puppeteer.custom_elements.puppeteer_page import PuppeteerPage from PuppeteerLibrary.utils.device_descriptors import DEVICE_DESCRIPTORS @@ -99,6 +100,7 @@ def get_async_keyword_group(self, keyword_group_name: str): "DropdownKeywords": PuppeteerDropdown(self), "ElementKeywords": PuppeteerElement(self), "FormElementKeywords": PuppeteerFormElement(self), + "MouseEventKeywords": PuppeteerMouseEvent(self), "ScreenshotKeywords": PuppeteerScreenshot(self), "WaitingKeywords": PuppeteerWaiting(self) } From f27743fa2b231029d63254dd4a0a1faaea5c7161 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Thu, 29 Oct 2020 07:24:32 +0700 Subject: [PATCH 083/103] Add Playwright mouse event keywords --- Examples/input/mouse.robot | 2 +- .../async_keywords/playwright_mouseevent.py | 14 ++++++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/Examples/input/mouse.robot b/Examples/input/mouse.robot index 44da1b7..25d3f33 100644 --- a/Examples/input/mouse.robot +++ b/Examples/input/mouse.robot @@ -3,6 +3,7 @@ Force Tags Ignore Library PuppeteerLibrary Test Setup Open browser to test page Test Teardown Close All Browser +Suite Teardown Close Puppeteer *** Variables *** ${DEFAULT_BROWSER} chrome @@ -29,4 +30,3 @@ Open browser to test page ${HEADLESS} Get variable value ${HEADLESS} ${False} &{options} = create dictionary headless=${HEADLESS} Open browser ${HOME_PAGE_URL} browser=${BROWSER} options=${options} - diff --git a/PuppeteerLibrary/playwright/async_keywords/playwright_mouseevent.py b/PuppeteerLibrary/playwright/async_keywords/playwright_mouseevent.py index 1d7870b..17040e7 100644 --- a/PuppeteerLibrary/playwright/async_keywords/playwright_mouseevent.py +++ b/PuppeteerLibrary/playwright/async_keywords/playwright_mouseevent.py @@ -8,13 +8,19 @@ def __init__(self, library_ctx): super().__init__(library_ctx) async def mouse_over(self, locator): - raise Exception('Not implemented') + element = await self.library_ctx.get_current_page().querySelector_with_selenium_locator(locator) + await element.hover() async def mouse_down(self, locator): - raise Exception('Not implemented') + element = await self.library_ctx.get_current_page().querySelector_with_selenium_locator(locator) + bounding_box = await element.boundingBox() + await self.library_ctx.get_current_page().get_page().mouse.move( + bounding_box['x'] + bounding_box['width'] / 2, + bounding_box['y'] + bounding_box['height'] / 2) + await self.library_ctx.get_current_page().get_page().mouse.down() async def mouse_up(self): - raise Exception('Not implemented') + await self.library_ctx.get_current_page().get_page().mouse.up() async def mouse_move(self, x, y): - raise Exception('Not implemented') + await self.library_ctx.get_current_page().get_page().mouse.move(int(x), int(y)) From f7a4a1a7b5e74097508283c96c4bb457130a6da7 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Thu, 29 Oct 2020 07:27:03 +0700 Subject: [PATCH 084/103] Remove ignore mouse event test case --- Examples/input/mouse.robot | 1 - Examples/utilities/asyncio.robot | 7 +++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Examples/input/mouse.robot b/Examples/input/mouse.robot index 25d3f33..d0e4178 100644 --- a/Examples/input/mouse.robot +++ b/Examples/input/mouse.robot @@ -1,5 +1,4 @@ *** Settings *** -Force Tags Ignore Library PuppeteerLibrary Test Setup Open browser to test page Test Teardown Close All Browser diff --git a/Examples/utilities/asyncio.robot b/Examples/utilities/asyncio.robot index fa65f4d..92610a5 100644 --- a/Examples/utilities/asyncio.robot +++ b/Examples/utilities/asyncio.robot @@ -6,6 +6,8 @@ Test Teardown Close All Browser Suite Teardown Close Puppeteer *** Variables *** +${DEFAULT_BROWSER} chrome +# ${DEFAULT_BROWSER} webkit ${HOME_PAGE_URL} http://127.0.0.1:7272/basic-html-elements.html @@ -25,6 +27,7 @@ Ignore error Run Async Keywords and Return First Complete if no keyword success *** Keywords *** Open browser to test page - ${HEADLESS} Get variable value ${HEADLESS} ${False} + ${BROWSER} = Get variable value ${BROWSER} ${DEFAULT_BROWSER} + ${HEADLESS} = Get variable value ${HEADLESS} ${False} &{options} = create dictionary headless=${HEADLESS} - Open browser ${HOME_PAGE_URL} options=${options} + Open browser ${HOME_PAGE_URL} browser=${BROWSER} options=${options} From c535e651b0430e897a931944b4c2a9047577c685 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Thu, 29 Oct 2020 09:41:44 +0700 Subject: [PATCH 085/103] Add Playwright asyncio keywords --- Examples/utilities/asyncio.robot | 7 +++--- PuppeteerLibrary/keywords/utility.py | 22 ++++++++++--------- .../playwright/playwright_context.py | 6 ++++- 3 files changed, 21 insertions(+), 14 deletions(-) diff --git a/Examples/utilities/asyncio.robot b/Examples/utilities/asyncio.robot index 92610a5..0fed6f1 100644 --- a/Examples/utilities/asyncio.robot +++ b/Examples/utilities/asyncio.robot @@ -1,13 +1,14 @@ *** Settings *** Force Tags Ignore +Library Dialogs Library PuppeteerLibrary Test Setup Open browser to test page Test Teardown Close All Browser Suite Teardown Close Puppeteer *** Variables *** -${DEFAULT_BROWSER} chrome -# ${DEFAULT_BROWSER} webkit +# ${DEFAULT_BROWSER} chrome +${DEFAULT_BROWSER} webkit ${HOME_PAGE_URL} http://127.0.0.1:7272/basic-html-elements.html @@ -16,7 +17,7 @@ Run Async Keywords and wait for first completed keyword ${result} = Run Async Keywords And Return First Completed ... Click Element id=non_existing_id AND ... Click Element id=get_ajax - Should Be Equal As Integers 1 ${result} + Should Be Equal As Integers 1 ${result} Run Keyword If ${result} == 0 Log first keyword completed Run Keyword If ${result} == 1 Log second keyword completed diff --git a/PuppeteerLibrary/keywords/utility.py b/PuppeteerLibrary/keywords/utility.py index a484e1b..5fa0a5c 100644 --- a/PuppeteerLibrary/keywords/utility.py +++ b/PuppeteerLibrary/keywords/utility.py @@ -1,5 +1,4 @@ import asyncio -import inspect from PuppeteerLibrary.keywords.browsermanagement import BrowserManagementKeywords from PuppeteerLibrary.playwright.async_keywords.playwright_browsermanagement import PlaywrightBrowserManagement from robot.libraries.BuiltIn import _RunKeyword @@ -9,6 +8,9 @@ class UtilityKeywords(LibraryComponent): + def __init__(self, ctx): + super().__init__(ctx) + @keyword def run_async_keywords_and_return_first_completed(self, *keywords): """Executes all the given keywords in a asynchronous and wait until first keyword is completed @@ -19,20 +21,16 @@ def run_async_keywords_and_return_first_completed(self, *keywords): | `Run Async Keywords And Return First Completed` | Wait for response url | ${HOME_PAGE_URL}/login.html | AND | | ... | Wait for response url | ${HOME_PAGE_URL}/home.html | | """ - self.ctx.load_async_keywords() run_keyword = _RunKeyword() return self.loop.run_until_complete( self._run_async_keywords_first_completed(run_keyword._split_run_keywords(list(keywords))) ) - async def _wrapped_async_keyword_return_index(self, index, future): - await future - return index - async def _run_async_keywords_first_completed(self, iterable): org_statements = [] index = 0 for kw, args in iterable: - kw_name = kw.lower().replace(' ', '_') + '_async' - org_statements.append(self._wrapped_async_keyword_return_index(index, self.ctx.keywords[kw_name](*args))) + kw_name = kw.lower().replace(' ', '_') + async_keywords = self.ctx.keywords[kw_name].__self__.get_async_keyword_group() + org_statements.append(self._wrapped_async_keyword_return_index(index, getattr(async_keywords, kw_name)(*args) )) index += 1 statements = org_statements error_stack_trace = '' @@ -52,7 +50,11 @@ async def _run_async_keywords_first_completed(self, iterable): continue if len(pending) == 0: raise Exception("All async keywords failed \r\n"+ error_stack_trace) - + + async def _wrapped_async_keyword_return_index(self, index, future): + await future + return index + @keyword def run_async_keywords(self, *keywords): """Executes all the given keywords in a asynchronous and wait until all keyword is completed @@ -83,7 +85,7 @@ async def _new_run_async_keywords(self, iterable): async def _run_async_keywords(self, iterable): statements = [] for kw, args in iterable: - kw_name = kw.lower().replace(' ', '_') + '_async' + kw_name = kw.lower() statements.append(self.ctx.keywords[kw_name](*args)) try: return await asyncio.gather(*statements) diff --git a/PuppeteerLibrary/playwright/playwright_context.py b/PuppeteerLibrary/playwright/playwright_context.py index 7690739..bc7ef93 100644 --- a/PuppeteerLibrary/playwright/playwright_context.py +++ b/PuppeteerLibrary/playwright/playwright_context.py @@ -1,3 +1,4 @@ +import asyncio from PuppeteerLibrary.custom_elements.base_page import BasePage from PuppeteerLibrary.playwright.async_keywords.playwright_formelement import PlaywrightFormElement from PuppeteerLibrary.playwright.async_keywords.playwright_dropdown import PlaywrightDropdown @@ -67,7 +68,10 @@ def get_browser_context(self): async def close_browser_context(self): if self.browser is not None: - await self.browser.close() + try: + await asyncio.wait_for(self.browser.close(), timeout=3) + except asyncio.TimeoutError: + None self._reset_context() def get_async_keyword_group(self, keyword_group_name: str): From e836fdb0a7921d3912988744400078b5837912ad Mon Sep 17 00:00:00 2001 From: atthaboons Date: Thu, 29 Oct 2020 09:42:17 +0700 Subject: [PATCH 086/103] Update default test browser --- Examples/utilities/asyncio.robot | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Examples/utilities/asyncio.robot b/Examples/utilities/asyncio.robot index 0fed6f1..f710103 100644 --- a/Examples/utilities/asyncio.robot +++ b/Examples/utilities/asyncio.robot @@ -7,8 +7,8 @@ Test Teardown Close All Browser Suite Teardown Close Puppeteer *** Variables *** -# ${DEFAULT_BROWSER} chrome -${DEFAULT_BROWSER} webkit +${DEFAULT_BROWSER} chrome +# ${DEFAULT_BROWSER} webkit ${HOME_PAGE_URL} http://127.0.0.1:7272/basic-html-elements.html From a1aca8371fe9964cad98544c42d74665a750c823 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Thu, 29 Oct 2020 19:17:29 +0700 Subject: [PATCH 087/103] Add support javascript keywords --- Examples/utilities/asyncio.robot | 4 +--- Examples/utilities/execute-javascript.robot | 18 +++++++++++------- PuppeteerLibrary/keywords/ijavascript_async.py | 9 +++++++++ PuppeteerLibrary/keywords/javascript.py | 9 ++++++--- .../async_keywords/playwright_javascript.py | 10 ++++++++++ .../playwright/playwright_context.py | 2 ++ .../async_keywords/puppeteer_javascript.py | 10 ++++++++++ .../puppeteer/puppeteer_context.py | 2 ++ 8 files changed, 51 insertions(+), 13 deletions(-) create mode 100644 PuppeteerLibrary/keywords/ijavascript_async.py create mode 100644 PuppeteerLibrary/playwright/async_keywords/playwright_javascript.py create mode 100644 PuppeteerLibrary/puppeteer/async_keywords/puppeteer_javascript.py diff --git a/Examples/utilities/asyncio.robot b/Examples/utilities/asyncio.robot index f710103..4407fae 100644 --- a/Examples/utilities/asyncio.robot +++ b/Examples/utilities/asyncio.robot @@ -1,6 +1,4 @@ -*** Settings *** -Force Tags Ignore -Library Dialogs +*** Settings *** Library PuppeteerLibrary Test Setup Open browser to test page Test Teardown Close All Browser diff --git a/Examples/utilities/execute-javascript.robot b/Examples/utilities/execute-javascript.robot index 54b96e4..9baf27d 100644 --- a/Examples/utilities/execute-javascript.robot +++ b/Examples/utilities/execute-javascript.robot @@ -1,24 +1,28 @@ *** Settings *** -Force Tags Ignore Library PuppeteerLibrary Test Setup Open browser to test page -Test Teardown Close Browser +Test Teardown Close All Browser +Suite Teardown Close Puppeteer *** Variables *** +${DEFAULT_BROWSER} chrome +# ${DEFAULT_BROWSER} webkit ${HOME_PAGE_URL} http://127.0.0.1:7272/basic-html-elements.html *** Test Cases *** Execute javascript command + [Tags] Ignore_webkit Handle Alert ACCEPT - Execute Javascript console.log('Hi five'); Execute Javascript alert('Hello world'); - +Execute javascript log + Execute Javascript console.log('Hi five'); + *** Keywords *** Open browser to test page - ${HEADLESS} Get variable value ${HEADLESS} ${False} + ${BROWSER} = Get variable value ${BROWSER} ${DEFAULT_BROWSER} + ${HEADLESS} = Get variable value ${HEADLESS} ${False} &{options} = create dictionary headless=${HEADLESS} - Open browser ${HOME_PAGE_URL} options=${options} - + Open browser ${HOME_PAGE_URL} browser=${BROWSER} options=${options} diff --git a/PuppeteerLibrary/keywords/ijavascript_async.py b/PuppeteerLibrary/keywords/ijavascript_async.py new file mode 100644 index 0000000..2438d40 --- /dev/null +++ b/PuppeteerLibrary/keywords/ijavascript_async.py @@ -0,0 +1,9 @@ +from PuppeteerLibrary.keywords.base_async_keywords import BaseAsyncKeywords +from abc import ABC, abstractmethod + + +class iJavascriptAsync(BaseAsyncKeywords, ABC): + + @abstractmethod + async def execute_javascript(self, code): + pass diff --git a/PuppeteerLibrary/keywords/javascript.py b/PuppeteerLibrary/keywords/javascript.py index 0b16aaa..71ae39d 100644 --- a/PuppeteerLibrary/keywords/javascript.py +++ b/PuppeteerLibrary/keywords/javascript.py @@ -1,13 +1,16 @@ +from PuppeteerLibrary.keywords.ijavascript_async import iJavascriptAsync from PuppeteerLibrary.base.robotlibcore import keyword from PuppeteerLibrary.base.librarycomponent import LibraryComponent -from PuppeteerLibrary.keywords.javascript_async import JavascriptKeywordsAsync + class JavascriptKeywords(LibraryComponent): def __init__(self, ctx): super().__init__(ctx) - self.async_func = JavascriptKeywordsAsync(self.ctx) + + def get_async_keyword_group(self) -> iJavascriptAsync: + return self.ctx.get_current_library_context().get_async_keyword_group(type(self).__name__) @keyword def execute_javascript(self, code): @@ -22,4 +25,4 @@ def execute_javascript(self, code): | `Execute Javascript` | console.log('Hi 5'); | """ - return self.loop.run_until_complete(self.async_func.execute_javascript_async(code)) + return self.loop.run_until_complete(self.get_async_keyword_group().execute_javascript(code)) diff --git a/PuppeteerLibrary/playwright/async_keywords/playwright_javascript.py b/PuppeteerLibrary/playwright/async_keywords/playwright_javascript.py new file mode 100644 index 0000000..58e976e --- /dev/null +++ b/PuppeteerLibrary/playwright/async_keywords/playwright_javascript.py @@ -0,0 +1,10 @@ +from PuppeteerLibrary.keywords.ijavascript_async import iJavascriptAsync + + +class PlaywrightJavascript(iJavascriptAsync): + + def __init__(self, library_ctx): + super().__init__(library_ctx) + + async def execute_javascript(self, code): + return await self.library_ctx.get_current_page().get_page().evaluate(code) diff --git a/PuppeteerLibrary/playwright/playwright_context.py b/PuppeteerLibrary/playwright/playwright_context.py index bc7ef93..7b11e76 100644 --- a/PuppeteerLibrary/playwright/playwright_context.py +++ b/PuppeteerLibrary/playwright/playwright_context.py @@ -1,3 +1,4 @@ +from PuppeteerLibrary.playwright.async_keywords.playwright_javascript import PlaywrightJavascript import asyncio from PuppeteerLibrary.custom_elements.base_page import BasePage from PuppeteerLibrary.playwright.async_keywords.playwright_formelement import PlaywrightFormElement @@ -81,6 +82,7 @@ def get_async_keyword_group(self, keyword_group_name: str): "DropdownKeywords": PlaywrightDropdown(self), "ElementKeywords": PlaywrightElement(self), "FormElementKeywords": PlaywrightFormElement(self), + "JavascriptKeywords": PlaywrightJavascript(self), "MouseEventKeywords": PlaywrightMouseEvent(self), "ScreenshotKeywords": PlaywrightScreenshot(self), "WaitingKeywords": PlaywrightWaiting(self) diff --git a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_javascript.py b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_javascript.py new file mode 100644 index 0000000..9efdb15 --- /dev/null +++ b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_javascript.py @@ -0,0 +1,10 @@ +from PuppeteerLibrary.keywords.ijavascript_async import iJavascriptAsync + + +class PuppeteerJavascript(iJavascriptAsync): + + def __init__(self, library_ctx): + super().__init__(library_ctx) + + async def execute_javascript(self, code): + return await self.library_ctx.get_current_page().get_page().evaluate(code) diff --git a/PuppeteerLibrary/puppeteer/puppeteer_context.py b/PuppeteerLibrary/puppeteer/puppeteer_context.py index a7a6af5..8f01d80 100644 --- a/PuppeteerLibrary/puppeteer/puppeteer_context.py +++ b/PuppeteerLibrary/puppeteer/puppeteer_context.py @@ -1,3 +1,4 @@ +from PuppeteerLibrary.puppeteer.async_keywords.puppeteer_javascript import PuppeteerJavascript import sys from pyppeteer import launch from pyppeteer.browser import Browser @@ -100,6 +101,7 @@ def get_async_keyword_group(self, keyword_group_name: str): "DropdownKeywords": PuppeteerDropdown(self), "ElementKeywords": PuppeteerElement(self), "FormElementKeywords": PuppeteerFormElement(self), + "JavascriptKeywords": PuppeteerJavascript(self), "MouseEventKeywords": PuppeteerMouseEvent(self), "ScreenshotKeywords": PuppeteerScreenshot(self), "WaitingKeywords": PuppeteerWaiting(self) From 714f6949447dce1e1968acf27c7a8eba5872a0c0 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Thu, 29 Oct 2020 19:40:52 +0700 Subject: [PATCH 088/103] Move all interface keywords to ikeywords folder --- Examples/utilities/generate-pdf.robot | 11 +++++++++-- PuppeteerLibrary/ikeywords/__init__.py | 10 ++++++++++ .../{keywords => ikeywords}/base_async_keywords.py | 0 .../{keywords => ikeywords}/ialert_async.py | 2 +- .../ibrowsermanagement_async.py | 2 +- .../{keywords => ikeywords}/idropdown_async.py | 2 +- .../{keywords => ikeywords}/ielement_async.py | 2 +- .../{keywords => ikeywords}/iformelement_async.py | 2 +- .../{keywords => ikeywords}/ijavascript_async.py | 2 +- .../{keywords => ikeywords}/imouseevent_async.py | 2 +- .../{keywords => ikeywords}/iscreenshot_async.py | 2 +- .../{keywords => ikeywords}/iwaiting_async.py | 2 +- PuppeteerLibrary/keywords/__init__.py | 1 - PuppeteerLibrary/keywords/alert.py | 4 +--- PuppeteerLibrary/keywords/browsermanagement.py | 3 ++- PuppeteerLibrary/keywords/dropdown.py | 2 +- PuppeteerLibrary/keywords/element.py | 2 +- PuppeteerLibrary/keywords/formelement.py | 2 +- PuppeteerLibrary/keywords/javascript.py | 2 +- PuppeteerLibrary/keywords/mouseevent.py | 2 +- PuppeteerLibrary/keywords/screenshot.py | 2 +- PuppeteerLibrary/keywords/waiting.py | 2 +- .../playwright/async_keywords/playwright_alert.py | 2 +- .../async_keywords/playwright_browsermanagement.py | 2 +- .../playwright/async_keywords/playwright_dropdown.py | 2 +- .../playwright/async_keywords/playwright_element.py | 2 +- .../async_keywords/playwright_formelement.py | 2 +- .../async_keywords/playwright_javascript.py | 2 +- .../async_keywords/playwright_mouseevent.py | 2 +- .../async_keywords/playwright_screenshot.py | 2 +- .../playwright/async_keywords/playwright_waiting.py | 2 +- .../puppeteer/async_keywords/puppeteer_alert.py | 2 +- .../async_keywords/puppeteer_browsermanagement.py | 2 +- .../puppeteer/async_keywords/puppeteer_dropdown.py | 2 +- .../puppeteer/async_keywords/puppeteer_element.py | 2 +- .../puppeteer/async_keywords/puppeteer_formelement.py | 2 +- .../puppeteer/async_keywords/puppeteer_javascript.py | 2 +- .../puppeteer/async_keywords/puppeteer_mouseevent.py | 2 +- .../puppeteer/async_keywords/puppeteer_screenshot.py | 2 +- .../puppeteer/async_keywords/puppeteer_waiting.py | 2 +- PuppeteerLibrary/puppeteer/puppeteer_context.py | 2 +- 41 files changed, 57 insertions(+), 42 deletions(-) create mode 100644 PuppeteerLibrary/ikeywords/__init__.py rename PuppeteerLibrary/{keywords => ikeywords}/base_async_keywords.py (100%) rename PuppeteerLibrary/{keywords => ikeywords}/ialert_async.py (69%) rename PuppeteerLibrary/{keywords => ikeywords}/ibrowsermanagement_async.py (92%) rename PuppeteerLibrary/{keywords => ikeywords}/idropdown_async.py (78%) rename PuppeteerLibrary/{keywords => ikeywords}/ielement_async.py (95%) rename PuppeteerLibrary/{keywords => ikeywords}/iformelement_async.py (79%) rename PuppeteerLibrary/{keywords => ikeywords}/ijavascript_async.py (68%) rename PuppeteerLibrary/{keywords => ikeywords}/imouseevent_async.py (83%) rename PuppeteerLibrary/{keywords => ikeywords}/iscreenshot_async.py (71%) rename PuppeteerLibrary/{keywords => ikeywords}/iwaiting_async.py (95%) diff --git a/Examples/utilities/generate-pdf.robot b/Examples/utilities/generate-pdf.robot index 241e512..e184f56 100644 --- a/Examples/utilities/generate-pdf.robot +++ b/Examples/utilities/generate-pdf.robot @@ -5,7 +5,10 @@ Test Setup Open browser to test page Test Teardown Close All Browser Suite Teardown Close Puppeteer + *** Variables *** +${DEFAULT_BROWSER} chrome +# ${DEFAULT_BROWSER} webkit ${HOME_PAGE_URL} http://127.0.0.1:7272/basic-html-elements.html @@ -14,7 +17,11 @@ Generate pdf file [Documentation] Only support on headless mode Print as pdf + *** Keywords *** Open browser to test page - &{options} = create dictionary headless=${True} - Open browser ${HOME_PAGE_URL} options=${options} + ${BROWSER} = Get variable value ${BROWSER} ${DEFAULT_BROWSER} + ${HEADLESS} = Get variable value ${HEADLESS} ${False} + &{options} = create dictionary headless=${HEADLESS} + Open browser ${HOME_PAGE_URL} browser=${BROWSER} options=${options} + diff --git a/PuppeteerLibrary/ikeywords/__init__.py b/PuppeteerLibrary/ikeywords/__init__.py new file mode 100644 index 0000000..49c52bb --- /dev/null +++ b/PuppeteerLibrary/ikeywords/__init__.py @@ -0,0 +1,10 @@ +from .base_async_keywords import BaseAsyncKeywords +from .ialert_async import iAlertAsync +from .ibrowsermanagement_async import iBrowserManagementAsync +from .idropdown_async import iDropdownAsync +from .ielement_async import iElementAsync +from .iformelement_async import iFormElementAsync +from .ijavascript_async import iJavascriptAsync +from .imouseevent_async import iMouseEventAsync +from .iscreenshot_async import iScreenshotAsync +from .iwaiting_async import iWaitingAsync diff --git a/PuppeteerLibrary/keywords/base_async_keywords.py b/PuppeteerLibrary/ikeywords/base_async_keywords.py similarity index 100% rename from PuppeteerLibrary/keywords/base_async_keywords.py rename to PuppeteerLibrary/ikeywords/base_async_keywords.py diff --git a/PuppeteerLibrary/keywords/ialert_async.py b/PuppeteerLibrary/ikeywords/ialert_async.py similarity index 69% rename from PuppeteerLibrary/keywords/ialert_async.py rename to PuppeteerLibrary/ikeywords/ialert_async.py index 5b26ca2..8577328 100644 --- a/PuppeteerLibrary/keywords/ialert_async.py +++ b/PuppeteerLibrary/ikeywords/ialert_async.py @@ -1,4 +1,4 @@ -from PuppeteerLibrary.keywords.base_async_keywords import BaseAsyncKeywords +from PuppeteerLibrary.ikeywords.base_async_keywords import BaseAsyncKeywords from abc import ABC, abstractmethod diff --git a/PuppeteerLibrary/keywords/ibrowsermanagement_async.py b/PuppeteerLibrary/ikeywords/ibrowsermanagement_async.py similarity index 92% rename from PuppeteerLibrary/keywords/ibrowsermanagement_async.py rename to PuppeteerLibrary/ikeywords/ibrowsermanagement_async.py index fc3dcff..2920321 100644 --- a/PuppeteerLibrary/keywords/ibrowsermanagement_async.py +++ b/PuppeteerLibrary/ikeywords/ibrowsermanagement_async.py @@ -1,5 +1,5 @@ -from PuppeteerLibrary.keywords.base_async_keywords import BaseAsyncKeywords from abc import ABC, abstractmethod +from PuppeteerLibrary.ikeywords.base_async_keywords import BaseAsyncKeywords class iBrowserManagementAsync(BaseAsyncKeywords, ABC): diff --git a/PuppeteerLibrary/keywords/idropdown_async.py b/PuppeteerLibrary/ikeywords/idropdown_async.py similarity index 78% rename from PuppeteerLibrary/keywords/idropdown_async.py rename to PuppeteerLibrary/ikeywords/idropdown_async.py index a3d3608..53ec553 100644 --- a/PuppeteerLibrary/keywords/idropdown_async.py +++ b/PuppeteerLibrary/ikeywords/idropdown_async.py @@ -1,5 +1,5 @@ -from PuppeteerLibrary.keywords.base_async_keywords import BaseAsyncKeywords from abc import ABC, abstractmethod +from PuppeteerLibrary.ikeywords.base_async_keywords import BaseAsyncKeywords class iDropdownAsync(BaseAsyncKeywords, ABC): diff --git a/PuppeteerLibrary/keywords/ielement_async.py b/PuppeteerLibrary/ikeywords/ielement_async.py similarity index 95% rename from PuppeteerLibrary/keywords/ielement_async.py rename to PuppeteerLibrary/ikeywords/ielement_async.py index 7a4e17a..7f25f96 100644 --- a/PuppeteerLibrary/keywords/ielement_async.py +++ b/PuppeteerLibrary/ikeywords/ielement_async.py @@ -1,4 +1,4 @@ -from PuppeteerLibrary.keywords.base_async_keywords import BaseAsyncKeywords +from PuppeteerLibrary.ikeywords.base_async_keywords import BaseAsyncKeywords from abc import ABC, abstractmethod diff --git a/PuppeteerLibrary/keywords/iformelement_async.py b/PuppeteerLibrary/ikeywords/iformelement_async.py similarity index 79% rename from PuppeteerLibrary/keywords/iformelement_async.py rename to PuppeteerLibrary/ikeywords/iformelement_async.py index fb7fc90..0c9c5f6 100644 --- a/PuppeteerLibrary/keywords/iformelement_async.py +++ b/PuppeteerLibrary/ikeywords/iformelement_async.py @@ -1,5 +1,5 @@ -from PuppeteerLibrary.keywords.base_async_keywords import BaseAsyncKeywords from abc import ABC, abstractmethod +from PuppeteerLibrary.ikeywords.base_async_keywords import BaseAsyncKeywords class iFormElementAsync(BaseAsyncKeywords, ABC): diff --git a/PuppeteerLibrary/keywords/ijavascript_async.py b/PuppeteerLibrary/ikeywords/ijavascript_async.py similarity index 68% rename from PuppeteerLibrary/keywords/ijavascript_async.py rename to PuppeteerLibrary/ikeywords/ijavascript_async.py index 2438d40..e9df977 100644 --- a/PuppeteerLibrary/keywords/ijavascript_async.py +++ b/PuppeteerLibrary/ikeywords/ijavascript_async.py @@ -1,5 +1,5 @@ -from PuppeteerLibrary.keywords.base_async_keywords import BaseAsyncKeywords from abc import ABC, abstractmethod +from PuppeteerLibrary.ikeywords.base_async_keywords import BaseAsyncKeywords class iJavascriptAsync(BaseAsyncKeywords, ABC): diff --git a/PuppeteerLibrary/keywords/imouseevent_async.py b/PuppeteerLibrary/ikeywords/imouseevent_async.py similarity index 83% rename from PuppeteerLibrary/keywords/imouseevent_async.py rename to PuppeteerLibrary/ikeywords/imouseevent_async.py index 8990038..54f2cc6 100644 --- a/PuppeteerLibrary/keywords/imouseevent_async.py +++ b/PuppeteerLibrary/ikeywords/imouseevent_async.py @@ -1,5 +1,5 @@ -from PuppeteerLibrary.keywords.base_async_keywords import BaseAsyncKeywords from abc import ABC, abstractmethod +from PuppeteerLibrary.ikeywords.base_async_keywords import BaseAsyncKeywords class iMouseEventAsync(BaseAsyncKeywords, ABC): diff --git a/PuppeteerLibrary/keywords/iscreenshot_async.py b/PuppeteerLibrary/ikeywords/iscreenshot_async.py similarity index 71% rename from PuppeteerLibrary/keywords/iscreenshot_async.py rename to PuppeteerLibrary/ikeywords/iscreenshot_async.py index 6e78ba6..65ad276 100644 --- a/PuppeteerLibrary/keywords/iscreenshot_async.py +++ b/PuppeteerLibrary/ikeywords/iscreenshot_async.py @@ -1,5 +1,5 @@ -from PuppeteerLibrary.keywords.base_async_keywords import BaseAsyncKeywords from abc import ABC, abstractmethod +from PuppeteerLibrary.ikeywords.base_async_keywords import BaseAsyncKeywords class iScreenshotAsync(BaseAsyncKeywords, ABC): diff --git a/PuppeteerLibrary/keywords/iwaiting_async.py b/PuppeteerLibrary/ikeywords/iwaiting_async.py similarity index 95% rename from PuppeteerLibrary/keywords/iwaiting_async.py rename to PuppeteerLibrary/ikeywords/iwaiting_async.py index f8370e6..63ffea8 100644 --- a/PuppeteerLibrary/keywords/iwaiting_async.py +++ b/PuppeteerLibrary/ikeywords/iwaiting_async.py @@ -1,5 +1,5 @@ -from PuppeteerLibrary.keywords.base_async_keywords import BaseAsyncKeywords from abc import ABC, abstractmethod +from PuppeteerLibrary.ikeywords.base_async_keywords import BaseAsyncKeywords class iWaitingAsync(BaseAsyncKeywords, ABC): diff --git a/PuppeteerLibrary/keywords/__init__.py b/PuppeteerLibrary/keywords/__init__.py index cafb81c..61037cf 100644 --- a/PuppeteerLibrary/keywords/__init__.py +++ b/PuppeteerLibrary/keywords/__init__.py @@ -8,7 +8,6 @@ from .element_async import ElementKeywordsAsync from .formelement import FormElementKeywords from .formelement_async import FormElementKeywordsAsync -from .ibrowsermanagement_async import iBrowserManagementAsync from .javascript import JavascriptKeywords from .javascript_async import JavascriptKeywordsAsync from .mockresponse import MockResponseKeywords diff --git a/PuppeteerLibrary/keywords/alert.py b/PuppeteerLibrary/keywords/alert.py index 2f4c643..a1263a0 100644 --- a/PuppeteerLibrary/keywords/alert.py +++ b/PuppeteerLibrary/keywords/alert.py @@ -1,14 +1,12 @@ +from PuppeteerLibrary.ikeywords.ialert_async import iAlertAsync from PuppeteerLibrary.base.librarycomponent import LibraryComponent from PuppeteerLibrary.base.robotlibcore import keyword -from PuppeteerLibrary.keywords.alert_async import AlertKeywordsAsync -from PuppeteerLibrary.keywords.ialert_async import iAlertAsync class AlertKeywords(LibraryComponent): def __init__(self, ctx): super().__init__(ctx) - self.async_func = AlertKeywordsAsync(self.ctx) def get_async_keyword_group(self) -> iAlertAsync: return self.ctx.get_current_library_context().get_async_keyword_group(type(self).__name__) diff --git a/PuppeteerLibrary/keywords/browsermanagement.py b/PuppeteerLibrary/keywords/browsermanagement.py index 389e6f0..56d0558 100644 --- a/PuppeteerLibrary/keywords/browsermanagement.py +++ b/PuppeteerLibrary/keywords/browsermanagement.py @@ -1,8 +1,9 @@ -from PuppeteerLibrary.keywords.ibrowsermanagement_async import iBrowserManagementAsync from robot.utils import timestr_to_secs from PuppeteerLibrary.base.librarycomponent import LibraryComponent from PuppeteerLibrary.base.robotlibcore import keyword from PuppeteerLibrary.keywords.browsermanagement_async import BrowserManagementKeywordsAsync +from PuppeteerLibrary.ikeywords.ibrowsermanagement_async import iBrowserManagementAsync + class BrowserManagementKeywords(LibraryComponent): diff --git a/PuppeteerLibrary/keywords/dropdown.py b/PuppeteerLibrary/keywords/dropdown.py index b221643..07bce0d 100644 --- a/PuppeteerLibrary/keywords/dropdown.py +++ b/PuppeteerLibrary/keywords/dropdown.py @@ -1,7 +1,7 @@ from PuppeteerLibrary.base.librarycomponent import LibraryComponent from PuppeteerLibrary.base.robotlibcore import keyword from PuppeteerLibrary.keywords.dropdown_async import DropdownKeywordsAsync -from PuppeteerLibrary.keywords.idropdown_async import iDropdownAsync +from PuppeteerLibrary.ikeywords.idropdown_async import iDropdownAsync class DropdownKeywords(LibraryComponent): diff --git a/PuppeteerLibrary/keywords/element.py b/PuppeteerLibrary/keywords/element.py index 30854e5..0b0eb50 100644 --- a/PuppeteerLibrary/keywords/element.py +++ b/PuppeteerLibrary/keywords/element.py @@ -1,7 +1,7 @@ -from PuppeteerLibrary.keywords.ielement_async import iElementAsync from PuppeteerLibrary.base.librarycomponent import LibraryComponent from PuppeteerLibrary.base.robotlibcore import keyword from PuppeteerLibrary.keywords.element_async import ElementKeywordsAsync +from PuppeteerLibrary.ikeywords.ielement_async import iElementAsync class ElementKeywords(LibraryComponent): diff --git a/PuppeteerLibrary/keywords/formelement.py b/PuppeteerLibrary/keywords/formelement.py index 3608a02..dd27165 100644 --- a/PuppeteerLibrary/keywords/formelement.py +++ b/PuppeteerLibrary/keywords/formelement.py @@ -1,4 +1,4 @@ -from PuppeteerLibrary.keywords.iformelement_async import iFormElementAsync +from PuppeteerLibrary.ikeywords.iformelement_async import iFormElementAsync from PuppeteerLibrary.base.librarycomponent import LibraryComponent from PuppeteerLibrary.base.robotlibcore import keyword from PuppeteerLibrary.keywords.formelement_async import FormElementKeywordsAsync diff --git a/PuppeteerLibrary/keywords/javascript.py b/PuppeteerLibrary/keywords/javascript.py index 71ae39d..2811750 100644 --- a/PuppeteerLibrary/keywords/javascript.py +++ b/PuppeteerLibrary/keywords/javascript.py @@ -1,4 +1,4 @@ -from PuppeteerLibrary.keywords.ijavascript_async import iJavascriptAsync +from PuppeteerLibrary.ikeywords.ijavascript_async import iJavascriptAsync from PuppeteerLibrary.base.robotlibcore import keyword from PuppeteerLibrary.base.librarycomponent import LibraryComponent diff --git a/PuppeteerLibrary/keywords/mouseevent.py b/PuppeteerLibrary/keywords/mouseevent.py index a1a9807..b79d2b3 100644 --- a/PuppeteerLibrary/keywords/mouseevent.py +++ b/PuppeteerLibrary/keywords/mouseevent.py @@ -1,4 +1,4 @@ -from PuppeteerLibrary.keywords.imouseevent_async import iMouseEventAsync +from PuppeteerLibrary.ikeywords.imouseevent_async import iMouseEventAsync from PuppeteerLibrary.base.robotlibcore import keyword from PuppeteerLibrary.base.librarycomponent import LibraryComponent from PuppeteerLibrary.keywords.mouseevent_async import MouseEventKeywordsAsync diff --git a/PuppeteerLibrary/keywords/screenshot.py b/PuppeteerLibrary/keywords/screenshot.py index 2147787..c65cde6 100644 --- a/PuppeteerLibrary/keywords/screenshot.py +++ b/PuppeteerLibrary/keywords/screenshot.py @@ -1,9 +1,9 @@ -from PuppeteerLibrary.keywords.iscreenshot_async import iScreenshotAsync import os from robot.utils import get_link_path from PuppeteerLibrary.base.librarycomponent import LibraryComponent from PuppeteerLibrary.base.robotlibcore import keyword from PuppeteerLibrary.keywords.screenshot_async import ScreenshotKeywordsAsync, DEFAULT_FILENAME_PAGE +from PuppeteerLibrary.ikeywords.iscreenshot_async import iScreenshotAsync class ScreenshotKeywords(LibraryComponent): diff --git a/PuppeteerLibrary/keywords/waiting.py b/PuppeteerLibrary/keywords/waiting.py index 157eb3b..3704000 100644 --- a/PuppeteerLibrary/keywords/waiting.py +++ b/PuppeteerLibrary/keywords/waiting.py @@ -1,4 +1,4 @@ -from PuppeteerLibrary.keywords.iwaiting_async import iWaitingAsync +from PuppeteerLibrary.ikeywords.iwaiting_async import iWaitingAsync from PuppeteerLibrary.keywords.waiting_async import WaitingKeywordsAsync from PuppeteerLibrary.base.librarycomponent import LibraryComponent from PuppeteerLibrary.base.robotlibcore import keyword diff --git a/PuppeteerLibrary/playwright/async_keywords/playwright_alert.py b/PuppeteerLibrary/playwright/async_keywords/playwright_alert.py index 239280e..b3be74f 100644 --- a/PuppeteerLibrary/playwright/async_keywords/playwright_alert.py +++ b/PuppeteerLibrary/playwright/async_keywords/playwright_alert.py @@ -1,5 +1,5 @@ import asyncio -from PuppeteerLibrary.keywords.ialert_async import iAlertAsync +from PuppeteerLibrary.ikeywords.ialert_async import iAlertAsync class PlaywrightAlert(iAlertAsync): diff --git a/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py b/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py index 3e4ccb7..9a7858d 100644 --- a/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py +++ b/PuppeteerLibrary/playwright/async_keywords/playwright_browsermanagement.py @@ -2,7 +2,7 @@ import re import time from PuppeteerLibrary.utils.device_descriptors import DEVICE_DESCRIPTORS -from PuppeteerLibrary.keywords.ibrowsermanagement_async import iBrowserManagementAsync +from PuppeteerLibrary.ikeywords.ibrowsermanagement_async import iBrowserManagementAsync class PlaywrightBrowserManagement(iBrowserManagementAsync): diff --git a/PuppeteerLibrary/playwright/async_keywords/playwright_dropdown.py b/PuppeteerLibrary/playwright/async_keywords/playwright_dropdown.py index 5866809..ddeaa14 100644 --- a/PuppeteerLibrary/playwright/async_keywords/playwright_dropdown.py +++ b/PuppeteerLibrary/playwright/async_keywords/playwright_dropdown.py @@ -1,4 +1,4 @@ -from PuppeteerLibrary.keywords.idropdown_async import iDropdownAsync +from PuppeteerLibrary.ikeywords.idropdown_async import iDropdownAsync from PuppeteerLibrary.locators.SelectorAbstraction import SelectorAbstraction diff --git a/PuppeteerLibrary/playwright/async_keywords/playwright_element.py b/PuppeteerLibrary/playwright/async_keywords/playwright_element.py index b3a436a..3514add 100644 --- a/PuppeteerLibrary/playwright/async_keywords/playwright_element.py +++ b/PuppeteerLibrary/playwright/async_keywords/playwright_element.py @@ -1,5 +1,5 @@ from robot.libraries.BuiltIn import BuiltIn -from PuppeteerLibrary.keywords.ielement_async import iElementAsync +from PuppeteerLibrary.ikeywords.ielement_async import iElementAsync class PlaywrightElement(iElementAsync): diff --git a/PuppeteerLibrary/playwright/async_keywords/playwright_formelement.py b/PuppeteerLibrary/playwright/async_keywords/playwright_formelement.py index 6d28466..ad04342 100644 --- a/PuppeteerLibrary/playwright/async_keywords/playwright_formelement.py +++ b/PuppeteerLibrary/playwright/async_keywords/playwright_formelement.py @@ -1,4 +1,4 @@ -from PuppeteerLibrary.keywords.iformelement_async import iFormElementAsync +from PuppeteerLibrary.ikeywords.iformelement_async import iFormElementAsync from PuppeteerLibrary.locators.SelectorAbstraction import SelectorAbstraction diff --git a/PuppeteerLibrary/playwright/async_keywords/playwright_javascript.py b/PuppeteerLibrary/playwright/async_keywords/playwright_javascript.py index 58e976e..94216b6 100644 --- a/PuppeteerLibrary/playwright/async_keywords/playwright_javascript.py +++ b/PuppeteerLibrary/playwright/async_keywords/playwright_javascript.py @@ -1,4 +1,4 @@ -from PuppeteerLibrary.keywords.ijavascript_async import iJavascriptAsync +from PuppeteerLibrary.ikeywords.ijavascript_async import iJavascriptAsync class PlaywrightJavascript(iJavascriptAsync): diff --git a/PuppeteerLibrary/playwright/async_keywords/playwright_mouseevent.py b/PuppeteerLibrary/playwright/async_keywords/playwright_mouseevent.py index 17040e7..5666140 100644 --- a/PuppeteerLibrary/playwright/async_keywords/playwright_mouseevent.py +++ b/PuppeteerLibrary/playwright/async_keywords/playwright_mouseevent.py @@ -1,5 +1,5 @@ from robot.libraries.BuiltIn import BuiltIn -from PuppeteerLibrary.keywords.imouseevent_async import iMouseEventAsync +from PuppeteerLibrary.ikeywords.imouseevent_async import iMouseEventAsync class PlaywrightMouseEvent(iMouseEventAsync): diff --git a/PuppeteerLibrary/playwright/async_keywords/playwright_screenshot.py b/PuppeteerLibrary/playwright/async_keywords/playwright_screenshot.py index 72e83d3..f814109 100644 --- a/PuppeteerLibrary/playwright/async_keywords/playwright_screenshot.py +++ b/PuppeteerLibrary/playwright/async_keywords/playwright_screenshot.py @@ -1,5 +1,5 @@ from PuppeteerLibrary.playwright.async_keywords.playwright_waiting import PlaywrightWaiting -from PuppeteerLibrary.keywords.iscreenshot_async import iScreenshotAsync +from PuppeteerLibrary.ikeywords.iscreenshot_async import iScreenshotAsync class PlaywrightScreenshot(iScreenshotAsync): diff --git a/PuppeteerLibrary/playwright/async_keywords/playwright_waiting.py b/PuppeteerLibrary/playwright/async_keywords/playwright_waiting.py index ec48055..5724fdb 100644 --- a/PuppeteerLibrary/playwright/async_keywords/playwright_waiting.py +++ b/PuppeteerLibrary/playwright/async_keywords/playwright_waiting.py @@ -1,4 +1,4 @@ -from PuppeteerLibrary.keywords.iwaiting_async import iWaitingAsync +from PuppeteerLibrary.ikeywords.iwaiting_async import iWaitingAsync class PlaywrightWaiting(iWaitingAsync): diff --git a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_alert.py b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_alert.py index b5a2593..8696af4 100644 --- a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_alert.py +++ b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_alert.py @@ -1,5 +1,5 @@ import asyncio -from PuppeteerLibrary.keywords.ialert_async import iAlertAsync +from PuppeteerLibrary.ikeywords.ialert_async import iAlertAsync class PuppeteerAlert(iAlertAsync): diff --git a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_browsermanagement.py b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_browsermanagement.py index beb58ca..734f0b1 100644 --- a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_browsermanagement.py +++ b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_browsermanagement.py @@ -1,7 +1,7 @@ import asyncio import re import time -from PuppeteerLibrary.keywords.ibrowsermanagement_async import iBrowserManagementAsync +from PuppeteerLibrary.ikeywords.ibrowsermanagement_async import iBrowserManagementAsync class PuppeteerBrowserManagement(iBrowserManagementAsync): diff --git a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_dropdown.py b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_dropdown.py index f4085bb..66b3202 100644 --- a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_dropdown.py +++ b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_dropdown.py @@ -1,4 +1,4 @@ -from PuppeteerLibrary.keywords.idropdown_async import iDropdownAsync +from PuppeteerLibrary.ikeywords.idropdown_async import iDropdownAsync from PuppeteerLibrary.locators.SelectorAbstraction import SelectorAbstraction diff --git a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_element.py b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_element.py index 32793fc..c6253f8 100644 --- a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_element.py +++ b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_element.py @@ -1,5 +1,5 @@ from robot.libraries.BuiltIn import BuiltIn -from PuppeteerLibrary.keywords.ielement_async import iElementAsync +from PuppeteerLibrary.ikeywords.ielement_async import iElementAsync class PuppeteerElement(iElementAsync): diff --git a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_formelement.py b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_formelement.py index 0cefd75..b8dae0b 100644 --- a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_formelement.py +++ b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_formelement.py @@ -1,5 +1,5 @@ from robot.libraries.BuiltIn import BuiltIn -from PuppeteerLibrary.keywords.iformelement_async import iFormElementAsync +from PuppeteerLibrary.ikeywords.iformelement_async import iFormElementAsync class PuppeteerFormElement(iFormElementAsync): diff --git a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_javascript.py b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_javascript.py index 9efdb15..c54b53a 100644 --- a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_javascript.py +++ b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_javascript.py @@ -1,4 +1,4 @@ -from PuppeteerLibrary.keywords.ijavascript_async import iJavascriptAsync +from PuppeteerLibrary.ikeywords.ijavascript_async import iJavascriptAsync class PuppeteerJavascript(iJavascriptAsync): diff --git a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_mouseevent.py b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_mouseevent.py index 765e1ba..aeca5c2 100644 --- a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_mouseevent.py +++ b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_mouseevent.py @@ -1,5 +1,5 @@ from robot.libraries.BuiltIn import BuiltIn -from PuppeteerLibrary.keywords.imouseevent_async import iMouseEventAsync +from PuppeteerLibrary.ikeywords.imouseevent_async import iMouseEventAsync class PuppeteerMouseEvent(iMouseEventAsync): diff --git a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_screenshot.py b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_screenshot.py index 4d303e8..53f9290 100644 --- a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_screenshot.py +++ b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_screenshot.py @@ -1,4 +1,4 @@ -from PuppeteerLibrary.keywords.iscreenshot_async import iScreenshotAsync +from PuppeteerLibrary.ikeywords.iscreenshot_async import iScreenshotAsync class PuppeteerScreenshot(iScreenshotAsync): diff --git a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_waiting.py b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_waiting.py index b3e1d85..ffd7889 100644 --- a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_waiting.py +++ b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_waiting.py @@ -1,4 +1,4 @@ -from PuppeteerLibrary.keywords.iwaiting_async import iWaitingAsync +from PuppeteerLibrary.ikeywords.iwaiting_async import iWaitingAsync class PuppeteerWaiting(iWaitingAsync): diff --git a/PuppeteerLibrary/puppeteer/puppeteer_context.py b/PuppeteerLibrary/puppeteer/puppeteer_context.py index 8f01d80..2d02389 100644 --- a/PuppeteerLibrary/puppeteer/puppeteer_context.py +++ b/PuppeteerLibrary/puppeteer/puppeteer_context.py @@ -1,4 +1,3 @@ -from PuppeteerLibrary.puppeteer.async_keywords.puppeteer_javascript import PuppeteerJavascript import sys from pyppeteer import launch from pyppeteer.browser import Browser @@ -14,6 +13,7 @@ from PuppeteerLibrary.puppeteer.async_keywords.puppeteer_mouseevent import PuppeteerMouseEvent from PuppeteerLibrary.puppeteer.custom_elements.puppeteer_page import PuppeteerPage from PuppeteerLibrary.utils.device_descriptors import DEVICE_DESCRIPTORS +from PuppeteerLibrary.puppeteer.async_keywords.puppeteer_javascript import PuppeteerJavascript class PuppeteerContext(iLibraryContext): From e20b1d94059701e67127aee6303739d8baf14c2d Mon Sep 17 00:00:00 2001 From: atthaboons Date: Fri, 30 Oct 2020 06:52:02 +0700 Subject: [PATCH 089/103] Create print as pdf --- Examples/utilities/generate-pdf.robot | 7 ++-- PuppeteerLibrary/ikeywords/__init__.py | 1 + PuppeteerLibrary/ikeywords/ipdf_async.py | 34 +++++++++++++++++++ PuppeteerLibrary/keywords/pdf.py | 10 +++--- .../async_keywords/playwright_pdf.py | 16 +++++++++ .../playwright/playwright_context.py | 6 ++-- .../async_keywords/puppeteer_mouseevent.py | 1 - .../puppeteer/async_keywords/puppeteer_pdf.py | 13 +++++++ .../puppeteer/puppeteer_context.py | 4 ++- 9 files changed, 80 insertions(+), 12 deletions(-) create mode 100644 PuppeteerLibrary/ikeywords/ipdf_async.py create mode 100644 PuppeteerLibrary/playwright/async_keywords/playwright_pdf.py create mode 100644 PuppeteerLibrary/puppeteer/async_keywords/puppeteer_pdf.py diff --git a/Examples/utilities/generate-pdf.robot b/Examples/utilities/generate-pdf.robot index e184f56..d988c09 100644 --- a/Examples/utilities/generate-pdf.robot +++ b/Examples/utilities/generate-pdf.robot @@ -1,5 +1,4 @@ *** Settings *** -Force Tags Ignore Library PuppeteerLibrary Test Setup Open browser to test page Test Teardown Close All Browser @@ -8,20 +7,20 @@ Suite Teardown Close Puppeteer *** Variables *** ${DEFAULT_BROWSER} chrome -# ${DEFAULT_BROWSER} webkit ${HOME_PAGE_URL} http://127.0.0.1:7272/basic-html-elements.html *** Test Cases *** Generate pdf file - [Documentation] Only support on headless mode + [Tags] Ignore_webkit + [Documentation] Only support on chrome headless mode Print as pdf *** Keywords *** Open browser to test page ${BROWSER} = Get variable value ${BROWSER} ${DEFAULT_BROWSER} - ${HEADLESS} = Get variable value ${HEADLESS} ${False} + ${HEADLESS} = Get variable value ${HEADLESS} ${True} &{options} = create dictionary headless=${HEADLESS} Open browser ${HOME_PAGE_URL} browser=${BROWSER} options=${options} diff --git a/PuppeteerLibrary/ikeywords/__init__.py b/PuppeteerLibrary/ikeywords/__init__.py index 49c52bb..79c8a32 100644 --- a/PuppeteerLibrary/ikeywords/__init__.py +++ b/PuppeteerLibrary/ikeywords/__init__.py @@ -8,3 +8,4 @@ from .imouseevent_async import iMouseEventAsync from .iscreenshot_async import iScreenshotAsync from .iwaiting_async import iWaitingAsync +from .ipdf_async import iPDFAsync diff --git a/PuppeteerLibrary/ikeywords/ipdf_async.py b/PuppeteerLibrary/ikeywords/ipdf_async.py new file mode 100644 index 0000000..82cc9b7 --- /dev/null +++ b/PuppeteerLibrary/ikeywords/ipdf_async.py @@ -0,0 +1,34 @@ +import os +from abc import ABC, abstractmethod +from PuppeteerLibrary.ikeywords.base_async_keywords import BaseAsyncKeywords + +DEFAULT_FILENAME_PAGE = 'pdf-{index}.pdf' + +class iPDFAsync(BaseAsyncKeywords, ABC): + + def __init__(self, library_ctx): + super().__init__(library_ctx) + self.log_dir = os.curdir + + @abstractmethod + async def print_as_pdf(self, filename=DEFAULT_FILENAME_PAGE): + pass + + def _get_pdf_path(self, filename): + directory = self.log_dir + filename = filename.replace('/', os.sep) + index = 0 + while True: + index += 1 + formatted = self._format_path(filename, index) + path = os.path.join(directory, formatted) + if formatted == filename or not os.path.exists(path): + return path + + def _format_path(self, file_path, index): + return file_path.format_map(_SafeFormatter(index=index)) + +class _SafeFormatter(dict): + + def __missing__(self, key): + return '{%s}' % key diff --git a/PuppeteerLibrary/keywords/pdf.py b/PuppeteerLibrary/keywords/pdf.py index 34ebb9a..e6a9b64 100644 --- a/PuppeteerLibrary/keywords/pdf.py +++ b/PuppeteerLibrary/keywords/pdf.py @@ -1,14 +1,15 @@ +from PuppeteerLibrary.ikeywords.ipdf_async import iPDFAsync, DEFAULT_FILENAME_PAGE from PuppeteerLibrary.base.librarycomponent import LibraryComponent from PuppeteerLibrary.base.robotlibcore import keyword -from PuppeteerLibrary.keywords.pdf_async import PDFKeywordsAsync, DEFAULT_FILENAME_PAGE - class PDFKeywords(LibraryComponent): def __init__(self, ctx): super().__init__(ctx) - self.async_func = PDFKeywordsAsync(self.ctx) + def get_async_keyword_group(self) -> iPDFAsync: + return self.ctx.get_current_library_context().get_async_keyword_group(type(self).__name__) + @keyword def print_as_pdf(self, filename=DEFAULT_FILENAME_PAGE): """ @@ -25,4 +26,5 @@ def print_as_pdf(self, filename=DEFAULT_FILENAME_PAGE): | Print as PDF | custom-pdf-{index}.pdf | | """ - return self.loop.run_until_complete(self.async_func.print_as_pdf_async(filename)) + return self.loop.run_until_complete(self.get_async_keyword_group().print_as_pdf(filename)) + # return self.loop.run_until_complete(self.async_func.print_as_pdf_async(filename)) diff --git a/PuppeteerLibrary/playwright/async_keywords/playwright_pdf.py b/PuppeteerLibrary/playwright/async_keywords/playwright_pdf.py new file mode 100644 index 0000000..d6b4beb --- /dev/null +++ b/PuppeteerLibrary/playwright/async_keywords/playwright_pdf.py @@ -0,0 +1,16 @@ +from PuppeteerLibrary.ikeywords.ipdf_async import iPDFAsync, DEFAULT_FILENAME_PAGE + + +class PlaywrightPDF(iPDFAsync): + + def __init__(self, library_ctx): + super().__init__(library_ctx) + + async def print_as_pdf(self, filename=DEFAULT_FILENAME_PAGE): + path = self._get_pdf_path(filename) + await self.library_ctx.get_current_page().get_page().emulateMedia('screen') + await self.library_ctx.get_current_page().get_page().pdf( + path=path + ) + return True + self.info('Print as pdf: '+path) diff --git a/PuppeteerLibrary/playwright/playwright_context.py b/PuppeteerLibrary/playwright/playwright_context.py index 7b11e76..1e6d853 100644 --- a/PuppeteerLibrary/playwright/playwright_context.py +++ b/PuppeteerLibrary/playwright/playwright_context.py @@ -1,6 +1,6 @@ -from PuppeteerLibrary.playwright.async_keywords.playwright_javascript import PlaywrightJavascript import asyncio from PuppeteerLibrary.custom_elements.base_page import BasePage +from PuppeteerLibrary.playwright.custom_elements.playwright_page import PlaywrightPage from PuppeteerLibrary.playwright.async_keywords.playwright_formelement import PlaywrightFormElement from PuppeteerLibrary.playwright.async_keywords.playwright_dropdown import PlaywrightDropdown from PuppeteerLibrary.playwright.async_keywords.playwright_alert import PlaywrightAlert @@ -9,8 +9,9 @@ from PuppeteerLibrary.playwright.async_keywords.playwright_element import PlaywrightElement from PuppeteerLibrary.playwright.async_keywords.playwright_dropdown import PlaywrightDropdown from PuppeteerLibrary.playwright.async_keywords.playwright_mouseevent import PlaywrightMouseEvent -from PuppeteerLibrary.playwright.custom_elements.playwright_page import PlaywrightPage from PuppeteerLibrary.playwright.async_keywords.playwright_browsermanagement import PlaywrightBrowserManagement +from PuppeteerLibrary.playwright.async_keywords.playwright_pdf import PlaywrightPDF +from PuppeteerLibrary.playwright.async_keywords.playwright_javascript import PlaywrightJavascript from PuppeteerLibrary.library_context.ilibrary_context import iLibraryContext try: from playwright import async_playwright @@ -84,6 +85,7 @@ def get_async_keyword_group(self, keyword_group_name: str): "FormElementKeywords": PlaywrightFormElement(self), "JavascriptKeywords": PlaywrightJavascript(self), "MouseEventKeywords": PlaywrightMouseEvent(self), + "PDFKeywords": PlaywrightPDF(self), "ScreenshotKeywords": PlaywrightScreenshot(self), "WaitingKeywords": PlaywrightWaiting(self) } diff --git a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_mouseevent.py b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_mouseevent.py index aeca5c2..39ad689 100644 --- a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_mouseevent.py +++ b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_mouseevent.py @@ -1,4 +1,3 @@ -from robot.libraries.BuiltIn import BuiltIn from PuppeteerLibrary.ikeywords.imouseevent_async import iMouseEventAsync diff --git a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_pdf.py b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_pdf.py new file mode 100644 index 0000000..a7b4f2c --- /dev/null +++ b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_pdf.py @@ -0,0 +1,13 @@ +from PuppeteerLibrary.ikeywords.ipdf_async import iPDFAsync, DEFAULT_FILENAME_PAGE + + +class PuppeteerPDF(iPDFAsync): + + def __init__(self, library_ctx): + super().__init__(library_ctx) + + async def print_as_pdf(self, filename=DEFAULT_FILENAME_PAGE): + path = self._get_pdf_path(filename) + await self.library_ctx.get_current_page().get_page().emulateMedia('screen') + await self.library_ctx.get_current_page().get_page().pdf({'path': path}) + self.info('Print as pdf: '+path) diff --git a/PuppeteerLibrary/puppeteer/puppeteer_context.py b/PuppeteerLibrary/puppeteer/puppeteer_context.py index 2d02389..44acc07 100644 --- a/PuppeteerLibrary/puppeteer/puppeteer_context.py +++ b/PuppeteerLibrary/puppeteer/puppeteer_context.py @@ -12,8 +12,9 @@ from PuppeteerLibrary.puppeteer.async_keywords.puppeteer_formelement import PuppeteerFormElement from PuppeteerLibrary.puppeteer.async_keywords.puppeteer_mouseevent import PuppeteerMouseEvent from PuppeteerLibrary.puppeteer.custom_elements.puppeteer_page import PuppeteerPage -from PuppeteerLibrary.utils.device_descriptors import DEVICE_DESCRIPTORS +from PuppeteerLibrary.puppeteer.async_keywords.puppeteer_pdf import PuppeteerPDF from PuppeteerLibrary.puppeteer.async_keywords.puppeteer_javascript import PuppeteerJavascript +from PuppeteerLibrary.utils.device_descriptors import DEVICE_DESCRIPTORS class PuppeteerContext(iLibraryContext): @@ -103,6 +104,7 @@ def get_async_keyword_group(self, keyword_group_name: str): "FormElementKeywords": PuppeteerFormElement(self), "JavascriptKeywords": PuppeteerJavascript(self), "MouseEventKeywords": PuppeteerMouseEvent(self), + "PDFKeywords": PuppeteerPDF(self), "ScreenshotKeywords": PuppeteerScreenshot(self), "WaitingKeywords": PuppeteerWaiting(self) } From d3f270d77ffc9fe79bb7c88a9d3ae3a8312be5dc Mon Sep 17 00:00:00 2001 From: atthaboons Date: Fri, 30 Oct 2020 07:06:23 +0700 Subject: [PATCH 090/103] Add log messages keywords --- Examples/utilities/log-messages.robot | 12 ++++++++---- .../playwright/async_keywords/playwright_pdf.py | 1 - 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Examples/utilities/log-messages.robot b/Examples/utilities/log-messages.robot index 8fd4153..1f38d85 100644 --- a/Examples/utilities/log-messages.robot +++ b/Examples/utilities/log-messages.robot @@ -2,16 +2,18 @@ Force Tags Ignore Library PuppeteerLibrary Test Setup Open browser to test page -Test Teardown Close Browser +Test Teardown Close All Browser +Suite Teardown Close Puppeteer *** Variables *** +${DEFAULT_BROWSER} chrome ${HOME_PAGE_URL} http://127.0.0.1:7272/basic-html-elements.html *** Test Cases *** No node found when click - Run Keyword And Expect Error REGEXP:.*No node found for selector: #login_button_error Click Element id:login_button_error + Run Keyword And Expect Error REGEXP:.* Click Element id:login_button_error Test log error for sync keywords Run Keyword And Ignore Error Click Element id:login_button_error @@ -21,8 +23,10 @@ Test log error for async keywords ... Click Element id:login_button_error AND ... Click Element id:login_button_2 + *** Keywords *** Open browser to test page - ${HEADLESS} Get variable value ${HEADLESS} ${False} + ${BROWSER} = Get variable value ${BROWSER} ${DEFAULT_BROWSER} + ${HEADLESS} = Get variable value ${HEADLESS} ${True} &{options} = create dictionary headless=${HEADLESS} - Open browser ${HOME_PAGE_URL} options=${options} + Open browser ${HOME_PAGE_URL} browser=${BROWSER} options=${options} diff --git a/PuppeteerLibrary/playwright/async_keywords/playwright_pdf.py b/PuppeteerLibrary/playwright/async_keywords/playwright_pdf.py index d6b4beb..167c6c5 100644 --- a/PuppeteerLibrary/playwright/async_keywords/playwright_pdf.py +++ b/PuppeteerLibrary/playwright/async_keywords/playwright_pdf.py @@ -12,5 +12,4 @@ async def print_as_pdf(self, filename=DEFAULT_FILENAME_PAGE): await self.library_ctx.get_current_page().get_page().pdf( path=path ) - return True self.info('Print as pdf: '+path) From 1faeb5b024df86684a5bb0d3d43b074de8051355 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Fri, 30 Oct 2020 07:17:37 +0700 Subject: [PATCH 091/103] Update screenshot keywords --- Examples/utilities/log-messages.robot | 1 - Examples/utilities/screenshot.robot | 10 ++++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Examples/utilities/log-messages.robot b/Examples/utilities/log-messages.robot index 1f38d85..3d2d8ad 100644 --- a/Examples/utilities/log-messages.robot +++ b/Examples/utilities/log-messages.robot @@ -1,5 +1,4 @@ *** Settings *** -Force Tags Ignore Library PuppeteerLibrary Test Setup Open browser to test page Test Teardown Close All Browser diff --git a/Examples/utilities/screenshot.robot b/Examples/utilities/screenshot.robot index eba7d8e..18ebdd3 100644 --- a/Examples/utilities/screenshot.robot +++ b/Examples/utilities/screenshot.robot @@ -1,11 +1,11 @@ *** Settings *** -Force Tags Ignore Library PuppeteerLibrary Test Setup Open browser to test page Test Teardown Close Browser - +Suite Teardown Close Puppeteer *** Variables *** +${DEFAULT_BROWSER} chrome ${HOME_PAGE_URL} http://127.0.0.1:7272/basic-html-elements.html @@ -14,8 +14,10 @@ Capture page screenshot Capture Page Screenshot Capture Page Screenshot test-{index}.png + *** Keywords *** Open browser to test page - ${HEADLESS} Get variable value ${HEADLESS} ${False} + ${BROWSER} = Get variable value ${BROWSER} ${DEFAULT_BROWSER} + ${HEADLESS} = Get variable value ${HEADLESS} ${True} &{options} = create dictionary headless=${HEADLESS} - Open browser ${HOME_PAGE_URL} options=${options} + Open browser ${HOME_PAGE_URL} browser=${BROWSER} options=${options} From bce8e2488a7907a2ecc6da974270790a9961659e Mon Sep 17 00:00:00 2001 From: atthaboons Date: Fri, 30 Oct 2020 07:44:38 +0700 Subject: [PATCH 092/103] Add support wait http request and response --- Examples/utilities/screenshot.robot | 2 +- Examples/utilities/timeout.robot | 13 +++-- Examples/utilities/wait.robot | 44 +++++++--------- .../async_keywords/puppeteer_waiting.py | 51 ++++++++++++++++++- 4 files changed, 77 insertions(+), 33 deletions(-) diff --git a/Examples/utilities/screenshot.robot b/Examples/utilities/screenshot.robot index 18ebdd3..5209424 100644 --- a/Examples/utilities/screenshot.robot +++ b/Examples/utilities/screenshot.robot @@ -18,6 +18,6 @@ Capture page screenshot *** Keywords *** Open browser to test page ${BROWSER} = Get variable value ${BROWSER} ${DEFAULT_BROWSER} - ${HEADLESS} = Get variable value ${HEADLESS} ${True} + ${HEADLESS} = Get variable value ${HEADLESS} ${False} &{options} = create dictionary headless=${HEADLESS} Open browser ${HOME_PAGE_URL} browser=${BROWSER} options=${options} diff --git a/Examples/utilities/timeout.robot b/Examples/utilities/timeout.robot index 32736ec..227e921 100644 --- a/Examples/utilities/timeout.robot +++ b/Examples/utilities/timeout.robot @@ -1,11 +1,13 @@ *** Settings *** Force Tags Ignore Library PuppeteerLibrary -Test Setup Open test browser +Test Setup Open browser to test page Test Teardown Close Browser +Suite Teardown Close Puppeteer *** Variables *** +${DEFAULT_BROWSER} chrome ${HOME_PAGE_URL} http://127.0.0.1:7272/basic-html-elements.html @@ -21,8 +23,9 @@ Timeout wait for new window open ... Click Element id:open-new-tab *** Keywords *** -Open test browser - ${HEADLESS} Get variable value ${HEADLESS} ${False} +Open browser to test page + ${BROWSER} = Get variable value ${BROWSER} ${DEFAULT_BROWSER} + ${HEADLESS} = Get variable value ${HEADLESS} ${False} &{options} = create dictionary headless=${HEADLESS} - Open browser ${HOME_PAGE_URL} options=${options} - Maximize Browser Window + Open browser ${HOME_PAGE_URL} browser=${BROWSER} options=${options} + diff --git a/Examples/utilities/wait.robot b/Examples/utilities/wait.robot index a8ac211..fbb8980 100644 --- a/Examples/utilities/wait.robot +++ b/Examples/utilities/wait.robot @@ -1,25 +1,22 @@ *** Settings *** -Force Tags Ignore Library PuppeteerLibrary Test Teardown Close Browser +Suite Teardown Close Puppeteer *** Variables *** +${DEFAULT_BROWSER} chrome ${HOME_PAGE_URL} http://127.0.0.1:7272/basic-html-elements.html ${LOGIN_PAGE_URL} http://127.0.0.1:7272/login-form-example.html *** Test Cases *** Wait for element - ${HEADLESS} Get variable value ${HEADLESS} ${False} - &{options} = create dictionary headless=${HEADLESS} - Open browser ${HOME_PAGE_URL} options=${options} + Open browser to test page ${HOME_PAGE_URL} Wait Until Page Contains Element id:get_ajax Run Keyword And Expect Error STARTS: TimeoutError: Wait Until Page Contains Element css:no_element timeout=5s Wait for http request - ${HEADLESS} Get variable value ${HEADLESS} ${False} - &{options} = create dictionary headless=${HEADLESS} - Open browser ${HOME_PAGE_URL} options=${options} + Open browser to test page ${HOME_PAGE_URL} ${results} = Run Async Keywords ... Wait for request url /ajax_info.json AND ... Click Element id:get_ajax @@ -28,9 +25,7 @@ Wait for http request Log ${results[0].body} Wait for http response - ${HEADLESS} Get variable value ${HEADLESS} ${False} - &{options} = create dictionary headless=${HEADLESS} - Open browser ${HOME_PAGE_URL} options=${options} + Open browser to test page ${HOME_PAGE_URL} ${results} = Run Async Keywords ... Wait for response url /ajax_info.json\\?count=3 200 name.*?p1.*?name.*?p2.*?name.*?p3 AND ... Click Element id:get_ajax @@ -39,36 +34,35 @@ Wait for http response Log ${results[0].body} Wait for navigation - ${HEADLESS} Get variable value ${HEADLESS} ${False} - &{options} = create dictionary headless=${HEADLESS} - Open browser ${HOME_PAGE_URL} options=${options} + Open browser to test page ${HOME_PAGE_URL} Run Async Keywords ... Wait For Navigation AND ... Click Element id=goto-login-page Wait for element hidden and visible - ${HEADLESS} Get variable value ${HEADLESS} ${False} - &{options} = create dictionary headless=${HEADLESS} - Open browser ${HOME_PAGE_URL} options=${options} + Open browser to test page ${HOME_PAGE_URL} Click Element id:click_and_hide Wait Until Element Is Hidden id:click_and_hide Wait for element contains text - ${HEADLESS} Get variable value ${HEADLESS} ${False} - &{options} = create dictionary headless=${HEADLESS} - Open browser ${LOGIN_PAGE_URL} options=${options} + Open browser to test page ${LOGIN_PAGE_URL} Wait Until Element Contains id:emailHelp We'll never share your email Wait Until Element Does Not Contains id:emailHelp We'll never share your password Wait for location contains - ${HEADLESS} Get variable value ${HEADLESS} ${False} - &{options} = create dictionary headless=${HEADLESS} - Open browser ${LOGIN_PAGE_URL} options=${options} + Open browser to test page ${LOGIN_PAGE_URL} Wait Until Location Contains login-form-example.html Wait for element is enabled - ${HEADLESS} Get variable value ${HEADLESS} ${False} - &{options} = create dictionary headless=${HEADLESS} - Open browser ${HOME_PAGE_URL} options=${options} + Open browser to test page ${HOME_PAGE_URL} Wait Until Element Is Enabled id=prop-enable Click Element id=prop-enable + + +*** Keywords *** +Open browser to test page + [Arguments] ${url} + ${BROWSER} = Get variable value ${BROWSER} ${DEFAULT_BROWSER} + ${HEADLESS} = Get variable value ${HEADLESS} ${False} + &{options} = create dictionary headless=${HEADLESS} + Open browser ${url} browser=${BROWSER} options=${options} diff --git a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_waiting.py b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_waiting.py index ffd7889..6ef7efa 100644 --- a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_waiting.py +++ b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_waiting.py @@ -1,3 +1,5 @@ +import re +from robot.utils.dotdict import DotDict from PuppeteerLibrary.ikeywords.iwaiting_async import iWaitingAsync @@ -19,10 +21,55 @@ def escape_xpath_value(self, value): return "'%s'" % value async def wait_for_request_url(self, url, method='GET', body=None, timeout=None): - pass + req = await self.library_ctx.get_current_page().get_page().waitForRequest( + lambda req: re.search(url, req.url) is not None + and req.method == method + , options={ + 'timeout': self.timestr_to_secs_for_default_timeout(timeout) * 1000 + }) + + try: + pos_data = (await req.postData()) + except: + pos_data = '' + + if body is None or re.search(body, pos_data.replace('\n', '')): + log_str = 'Wait for request url: '+req.method+' - '+req.url + if pos_data != '': + log_str + '\n' + pos_data + self.info(log_str) + else: + raise Exception('Can\'t match request body with ' + body + ' \n ' + pos_data) + + return DotDict({ + 'url': req.url, + 'method': req.method, + 'body': pos_data + }) async def wait_for_response_url(self, url, status=200, body=None, timeout=None): - pass + res = await self.library_ctx.get_current_page().get_page().waitForResponse( + lambda res: re.search(url, res.url) is not None + and res.status == int(status) + , options={ + 'timeout': self.timestr_to_secs_for_default_timeout(timeout) * 1000 + }) + try: + res_text = (await res.text()) + except: + res_text = '' + if body is None or re.search(body, res_text.replace('\n','')): + log_str = 'Wait for request url: ' + res.url + if res_text != '': + log_str += '\n' + res_text + self.info(log_str) + else: + raise Exception('Can\'t match response body with '+body+' \n '+res_text) + return DotDict({ + 'url': res.url, + 'status': res.status, + 'body': res_text + }) async def wait_for_navigation(self): pass From 4991de020fa7e53ba8932b0c1d2d6341bc62ac62 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Fri, 30 Oct 2020 18:21:26 +0700 Subject: [PATCH 093/103] Add Puppeteer wait keywords --- Examples/utilities/wait.robot | 2 +- PuppeteerLibrary/ikeywords/iwaiting_async.py | 6 +- PuppeteerLibrary/keywords/waiting.py | 28 +++-- .../async_keywords/playwright_waiting.py | 31 +++--- .../async_keywords/puppeteer_waiting.py | 100 +++++++++++++++--- 5 files changed, 115 insertions(+), 52 deletions(-) diff --git a/Examples/utilities/wait.robot b/Examples/utilities/wait.robot index fbb8980..668e7f4 100644 --- a/Examples/utilities/wait.robot +++ b/Examples/utilities/wait.robot @@ -4,7 +4,7 @@ Test Teardown Close Browser Suite Teardown Close Puppeteer *** Variables *** -${DEFAULT_BROWSER} chrome +${DEFAULT_BROWSER} webkit ${HOME_PAGE_URL} http://127.0.0.1:7272/basic-html-elements.html ${LOGIN_PAGE_URL} http://127.0.0.1:7272/login-form-example.html diff --git a/PuppeteerLibrary/ikeywords/iwaiting_async.py b/PuppeteerLibrary/ikeywords/iwaiting_async.py index 63ffea8..8b59152 100644 --- a/PuppeteerLibrary/ikeywords/iwaiting_async.py +++ b/PuppeteerLibrary/ikeywords/iwaiting_async.py @@ -13,7 +13,7 @@ async def wait_for_response_url(self, url, status=200, body=None, timeout=None): pass @abstractmethod - async def wait_for_navigation(self): + async def wait_for_navigation(self, timeout=None): pass @abstractmethod @@ -53,9 +53,9 @@ async def wait_until_location_does_not_contains(self, expected, timeout=None): pass @abstractmethod - async def wait_until_element_is_enabled(self, selenium_locator, timeout=None): + async def wait_until_element_is_enabled(self, locator, timeout=None): pass @abstractmethod - async def wait_until_element_finished_animating(self, selenium_locator, timeout=None): + async def wait_until_element_finished_animating(self, locator, timeout=None): pass diff --git a/PuppeteerLibrary/keywords/waiting.py b/PuppeteerLibrary/keywords/waiting.py index 3704000..c473e3b 100644 --- a/PuppeteerLibrary/keywords/waiting.py +++ b/PuppeteerLibrary/keywords/waiting.py @@ -47,7 +47,7 @@ def wait_for_request_url(self, url, method='GET', body=None, timeout=None): | ... | `Wait For Request Url` | ${URL_API}/login | POST | username=demo | """ - return self.loop.run_until_complete(self.async_func.wait_for_request_url_async(url, method, body, timeout)) + return self.loop.run_until_complete(self.get_async_keyword_group().wait_for_request_url_async(url, method, body, timeout)) @keyword def wait_for_response_url(self, url, status=200, body=None, timeout=None): @@ -77,10 +77,10 @@ def wait_for_response_url(self, url, status=200, body=None, timeout=None): | ... | `Wait For Response Url` | ${URL_API}/login | 200 | username=demo | """ - return self.loop.run_until_complete(self.async_func.wait_for_response_url_async(url, status, body, timeout)) + return self.loop.run_until_complete(self.get_async_keyword_group().wait_for_response_url(url, status, body, timeout)) @keyword - def wait_for_navigation(self): + def wait_for_navigation(self, timeout=None): """ Waits until web page navigates to new url or reloads. @@ -92,7 +92,7 @@ def wait_for_navigation(self): | Run Async Keywords | Click Element | id:login_button | AND | | ... | `Wait For Navigation` | | | """ - return self.loop.run_until_complete(self.async_func.wait_for_navigation_async()) + return self.loop.run_until_complete(self.get_async_keyword_group().wait_for_navigation(timeout)) @keyword def wait_until_page_contains_element(self, locator, timeout=None): @@ -117,7 +117,7 @@ def wait_until_element_is_hidden(self, locator, timeout=None): | ... | Wait For Navigation | | | | `Wait Until Element Is Hidden` | id:login_button | | | """ - return self.loop.run_until_complete(self.async_func.wait_until_element_is_hidden_async(locator, timeout)) + return self.loop.run_until_complete(self.get_async_keyword_group().wait_until_element_is_hidden(locator, timeout)) @keyword def wait_until_element_is_visible(self, locator, timeout=None): @@ -130,7 +130,7 @@ def wait_until_element_is_visible(self, locator, timeout=None): | ... | Wait For Navigation | | | | `Wait Until Element Is Visible` | id:welcome | | | """ - return self.loop.run_until_complete(self.async_func.wait_until_element_is_visible_async(locator, timeout)) + return self.loop.run_until_complete(self.get_async_keyword_group().wait_until_element_is_visible(locator, timeout)) @keyword def wait_until_page_contains(self, text, timeout=None): @@ -157,7 +157,7 @@ def wait_until_page_does_not_contains(self, text, timeout=None): | ... | Wait For Navigation | | | | `Wait Until Page Does Not Contains` | Please input your user name | | | """ - return self.loop.run_until_complete(self.async_func.wait_until_page_does_not_contains_async(text, timeout)) + return self.loop.run_until_complete(self.get_async_keyword_group().wait_until_page_does_not_contains(text, timeout)) @keyword def wait_until_element_contains(self, locator, text, timeout=None): @@ -169,7 +169,7 @@ def wait_until_element_contains(self, locator, text, timeout=None): | Open browser | ${HOME_PAGE_URL} | options=${options} | | `Wait Until Element Contains` | css:#container p | Please input your user name | """ - return self.loop.run_until_complete(self.async_func.wait_until_element_contains_async(locator, text, timeout)) + return self.loop.run_until_complete(self.get_async_keyword_group().wait_until_element_contains(locator, text, timeout)) @keyword def wait_until_element_does_not_contains(self, locator, text, timeout=None): @@ -182,7 +182,7 @@ def wait_until_element_does_not_contains(self, locator, text, timeout=None): | ... | Wait For Navigation | | | | `Wait Until Element Does Not Contains` | css:#container p | Please input your user name | | """ - return self.loop.run_until_complete(self.async_func.wait_until_element_does_not_contains_async(locator, text, timeout)) + return self.loop.run_until_complete(self.get_async_keyword_group().wait_until_element_does_not_contains(locator, text, timeout)) @keyword def wait_until_location_contains(self, expected, timeout=None): @@ -191,7 +191,7 @@ def wait_until_location_contains(self, expected, timeout=None): The `expected` argument contains the expected value in url. """ - return self.loop.run_until_complete(self.async_func.wait_until_location_contains_async(expected, timeout)) + return self.loop.run_until_complete(self.get_async_keyword_group().wait_until_location_contains(expected, timeout)) @keyword def wait_until_location_does_not_contains(self, expected, timeout=None): @@ -200,7 +200,7 @@ def wait_until_location_does_not_contains(self, expected, timeout=None): The `expected` argument contains the expected value must not in url. """ - return self.loop.run_until_complete(self.async_func.wait_until_location_does_not_contains_async(expected, timeout)) + return self.loop.run_until_complete(self.get_async_keyword_group().wait_until_location_does_not_contains(expected, timeout)) @keyword def wait_until_element_is_enabled(self, selenium_locator, timeout=None): @@ -208,8 +208,7 @@ def wait_until_element_is_enabled(self, selenium_locator, timeout=None): Waits until the specific element is Enabled. """ - return self.loop.run_until_complete( - self.async_func.wait_until_element_is_enabled_async(selenium_locator, timeout)) + return self.loop.run_until_complete(self.get_async_keyword_group().wait_until_element_is_enabled(selenium_locator, timeout)) @keyword def wait_until_element_finished_animating(self, selenium_locator, timeout=None): @@ -218,5 +217,4 @@ def wait_until_element_finished_animating(self, selenium_locator, timeout=None): Check by check element position. """ - return self.loop.run_until_complete( - self.async_func.wait_until_element_finished_animating_async(selenium_locator, timeout)) + return self.loop.run_until_complete(self.get_async_keyword_group().wait_until_element_finished_animating(selenium_locator, timeout)) diff --git a/PuppeteerLibrary/playwright/async_keywords/playwright_waiting.py b/PuppeteerLibrary/playwright/async_keywords/playwright_waiting.py index 5724fdb..da7b334 100644 --- a/PuppeteerLibrary/playwright/async_keywords/playwright_waiting.py +++ b/PuppeteerLibrary/playwright/async_keywords/playwright_waiting.py @@ -19,45 +19,44 @@ def escape_xpath_value(self, value): return "'%s'" % value async def wait_for_request_url(self, url, method='GET', body=None, timeout=None): - pass + raise Exception('Not implemented.') async def wait_for_response_url(self, url, status=200, body=None, timeout=None): - pass + raise Exception('Not implemented.') - async def wait_for_navigation(self): - pass + async def wait_for_navigation(self, timeout=None): + raise Exception('Not implemented.') async def wait_until_page_contains_element(self, locator, timeout=None): return await self._wait_for_selenium_selector(locator, timeout, visible=True, hidden=False) async def wait_until_element_is_hidden(self, locator, timeout=None): - pass + raise Exception('Not implemented.') async def wait_until_element_is_visible(self, locator, timeout=None): - pass + raise Exception('Not implemented.') async def wait_until_page_contains(self, text, timeout=None): locator = "xpath://*[contains(., %s)]" % self.escape_xpath_value(text) return await self._wait_for_selenium_selector(locator, timeout, visible=True, hidden=False) async def wait_until_page_does_not_contains(self, text, timeout=None): - pass + raise Exception('Not implemented.') async def wait_until_element_contains(self, locator, text, timeout=None): - pass + raise Exception('Not implemented.') async def wait_until_element_does_not_contains(self, locator, text, timeout=None): - pass + raise Exception('Not implemented.') async def wait_until_location_contains(self, expected, timeout=None): - pass + raise Exception('Not implemented.') async def wait_until_location_does_not_contains(self, expected, timeout=None): - pass + raise Exception('Not implemented.') - async def wait_until_element_is_enabled(self, selenium_locator, timeout=None): - pass - - async def wait_until_element_finished_animating(self, selenium_locator, timeout=None): - pass + async def wait_until_element_is_enabled(self, locator, timeout=None): + raise Exception('Not implemented.') + async def wait_until_element_finished_animating(self, locator, timeout=None): + raise Exception('Not implemented.') diff --git a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_waiting.py b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_waiting.py index 6ef7efa..c23149b 100644 --- a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_waiting.py +++ b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_waiting.py @@ -1,4 +1,6 @@ +import asyncio import re +import time from robot.utils.dotdict import DotDict from PuppeteerLibrary.ikeywords.iwaiting_async import iWaitingAsync @@ -71,42 +73,106 @@ async def wait_for_response_url(self, url, status=200, body=None, timeout=None): 'body': res_text }) - async def wait_for_navigation(self): - pass + async def wait_for_navigation(self, timeout=None): + await self.library_ctx.get_current_page().get_page().waitForNavigation( + options={ + 'timeout': self.timestr_to_secs_for_default_timeout(timeout) * 1000 + }) async def wait_until_page_contains_element(self, locator, timeout=None): return await self._wait_for_selenium_selector(locator, timeout, visible=True, hidden=False) async def wait_until_element_is_hidden(self, locator, timeout=None): - pass + return await self._wait_for_selenium_selector(locator, timeout, visible=False, hidden=True) async def wait_until_element_is_visible(self, locator, timeout=None): - pass + return await self._wait_for_selenium_selector(locator, timeout, visible=True, hidden=False) async def wait_until_page_contains(self, text, timeout=None): locator = "xpath://*[contains(., %s)]" % self.escape_xpath_value(text) return await self._wait_for_selenium_selector(locator, timeout, visible=True, hidden=False) async def wait_until_page_does_not_contains(self, text, timeout=None): - pass + locator = "xpath://*[contains(., %s)]" % self.escape_xpath_value(text) + return await self._wait_for_selenium_selector(locator, timeout, visible=False, hidden=True) async def wait_until_element_contains(self, locator, text, timeout=None): - pass + async def validate_element_contains_text(): + return (text in (await (await ( await self.library_ctx.get_current_page(). + querySelector_with_selenium_locator(locator)).getProperty('textContent')).jsonValue())) + return await self._wait_until_worker( + validate_element_contains_text, + self.timestr_to_secs_for_default_timeout(timeout)) async def wait_until_element_does_not_contains(self, locator, text, timeout=None): - pass + async def validate_element_contains_text(): + return (text not in (await (await ( await self.library_ctx.get_current_page(). + querySelector_with_selenium_locator(locator)).getProperty('textContent')).jsonValue())) + return await self._wait_until_worker( + validate_element_contains_text, + self.timestr_to_secs_for_default_timeout(timeout)) async def wait_until_location_contains(self, expected, timeout=None): - pass + async def validate_url_contains_text(): + return expected in self.library_ctx.get_current_page().get_page().url + return await self._wait_until_worker( + validate_url_contains_text, + self.timestr_to_secs_for_default_timeout(timeout)) async def wait_until_location_does_not_contains(self, expected, timeout=None): - pass - - async def wait_until_element_is_enabled(self, selenium_locator, timeout=None): - pass - - async def wait_until_element_finished_animating(self, selenium_locator, timeout=None): - pass - - + async def validate_url_not_contains_text(): + return expected not in self.library_ctx.get_current_page().get_page().url + return await self._wait_until_worker( + validate_url_not_contains_text, + self.timestr_to_secs_for_default_timeout(timeout)) + + async def wait_until_element_is_enabled(self, locator, timeout=None): + async def validate_is_enabled(): + element = await self.library_ctx.get_current_page().querySelector_with_selenium_locator(locator) + is_disabled = await (await element.getProperty('disabled')).jsonValue() + return is_disabled == False + return await self._wait_until_worker( + validate_is_enabled, + self.timestr_to_secs_for_default_timeout(timeout), + 'Element '+locator+' was not enabled.') + + async def wait_until_element_finished_animating(self, locator, timeout=None): + prev_rect_tmp = { 'value': None } + async def check_finished_animating(): + element = await self.library_ctx.get_current_page().querySelector_with_selenium_locator(locator) + if prev_rect_tmp['value'] is None: + prev_rect_tmp['value'] = await element.boundingBox() + return False + prev_rect = prev_rect_tmp['value'] + next_rect = await element.boundingBox() + if next_rect['x'] == prev_rect['x'] and next_rect['y'] == prev_rect['y']: + return True + else: + prev_rect_tmp['value'] = next_rect + return False + return await self._wait_until_worker( + check_finished_animating, + self.timestr_to_secs_for_default_timeout(timeout), + 'Element '+locator+' was not enabled.') + + async def _wait_until_worker(self, condition, timeout, error=None): + max_time = time.time() + timeout + not_found = None + while time.time() < max_time: + try: + if await condition(): + return + else: + not_found = None + except Exception as err: + not_found = err + await asyncio.sleep(0.2) + raise AssertionError(not_found or error) + def escape_xpath_value(self, value): + if '"' in value and '\'' in value: + parts_wo_apos = value.split('\'') + return "concat('%s')" % "', \"'\", '".join(parts_wo_apos) + if '\'' in value: + return "\"%s\"" % value + return "'%s'" % value From df4b9f9e670dd309285a507b67e10d38248ba8bf Mon Sep 17 00:00:00 2001 From: atthaboons Date: Fri, 30 Oct 2020 18:52:14 +0700 Subject: [PATCH 094/103] Add wait for playwright waiting for http request --- .../async_keywords/playwright_waiting.py | 72 +++++++++++++++---- .../custom_elements/playwright_page.py | 14 ++-- 2 files changed, 65 insertions(+), 21 deletions(-) diff --git a/PuppeteerLibrary/playwright/async_keywords/playwright_waiting.py b/PuppeteerLibrary/playwright/async_keywords/playwright_waiting.py index da7b334..cc59686 100644 --- a/PuppeteerLibrary/playwright/async_keywords/playwright_waiting.py +++ b/PuppeteerLibrary/playwright/async_keywords/playwright_waiting.py @@ -1,3 +1,7 @@ +import asyncio +import re +import time +from robot.utils.dotdict import DotDict from PuppeteerLibrary.ikeywords.iwaiting_async import iWaitingAsync @@ -6,23 +10,51 @@ class PlaywrightWaiting(iWaitingAsync): def __init__(self, library_ctx): super().__init__(library_ctx) - async def _wait_for_selenium_selector(self, selenium_locator, timeout=None, visible=False, hidden=False): - timeout = self.timestr_to_secs_for_default_timeout(timeout) - return await self.library_ctx.get_current_page().waitForSelector_with_selenium_locator(selenium_locator, timeout, visible, hidden) - - def escape_xpath_value(self, value): - if '"' in value and '\'' in value: - parts_wo_apos = value.split('\'') - return "concat('%s')" % "', \"'\", '".join(parts_wo_apos) - if '\'' in value: - return "\"%s\"" % value - return "'%s'" % value - async def wait_for_request_url(self, url, method='GET', body=None, timeout=None): - raise Exception('Not implemented.') + req = await self.library_ctx.get_current_page().get_page().waitForEvent( + "request", lambda request: re.search(url, request.url) is not None and request.method == method, + self.timestr_to_secs_for_default_timeout(timeout) * 1000 + ) + try: + pos_data = (await req.postData()) + except: + pos_data = '' + + if body is None or re.search(body, pos_data.replace('\n', '')): + log_str = 'Wait for request url: '+req.method+' - '+req.url + if pos_data != '': + log_str + '\n' + pos_data + self.info(log_str) + else: + raise Exception('Can\'t match request body with ' + body + ' \n ' + pos_data) + + return DotDict({ + 'url': req.url, + 'method': req.method, + 'body': pos_data + }) async def wait_for_response_url(self, url, status=200, body=None, timeout=None): - raise Exception('Not implemented.') + res = await self.library_ctx.get_current_page().get_page().waitForEvent( + "response", lambda response: re.search(url, response.url) is not None and response.status == int(status), + self.timestr_to_secs_for_default_timeout(timeout) * 1000 + ) + try: + res_text = (await res.text()) + except: + res_text = '' + if body is None or re.search(body, res_text.replace('\n','')): + log_str = 'Wait for request url: ' + res.url + if res_text != '': + log_str += '\n' + res_text + self.info(log_str) + else: + raise Exception('Can\'t match response body with '+body+' \n '+res_text) + return DotDict({ + 'url': res.url, + 'status': res.status, + 'body': res_text + }) async def wait_for_navigation(self, timeout=None): raise Exception('Not implemented.') @@ -60,3 +92,15 @@ async def wait_until_element_is_enabled(self, locator, timeout=None): async def wait_until_element_finished_animating(self, locator, timeout=None): raise Exception('Not implemented.') + + async def _wait_for_selenium_selector(self, selenium_locator, timeout=None, visible=False, hidden=False): + timeout = self.timestr_to_secs_for_default_timeout(timeout) + return await self.library_ctx.get_current_page().waitForSelector_with_selenium_locator(selenium_locator, timeout, visible, hidden) + + def escape_xpath_value(self, value): + if '"' in value and '\'' in value: + parts_wo_apos = value.split('\'') + return "concat('%s')" % "', \"'\", '".join(parts_wo_apos) + if '\'' in value: + return "\"%s\"" % value + return "'%s'" % value diff --git a/PuppeteerLibrary/playwright/custom_elements/playwright_page.py b/PuppeteerLibrary/playwright/custom_elements/playwright_page.py index a46ece7..8693e46 100644 --- a/PuppeteerLibrary/playwright/custom_elements/playwright_page.py +++ b/PuppeteerLibrary/playwright/custom_elements/playwright_page.py @@ -35,25 +35,25 @@ async def set_viewport_size(self, width: int, height: int): # Click ############ async def click_with_selenium_locator(self, selenium_locator: str, options: dict = None, **kwargs: Any): - if options is None: - options = {} selector_value = SelectorAbstraction.get_selector(selenium_locator) - + if options is None: + options = {} if self.selected_iframe is not None: - return await self.selected_iframe.click(selector=selenium_locator, **options) + return await self.selected_iframe.click(selector=selector_value, **options) else: - return await self.page.click(selector=selenium_locator, **options) + return await self.page.click(selector=selector_value, **options) ############ # Type ############ async def type_with_selenium_locator(self, selenium_locator: str, text: str, options: dict = None, **kwargs: Any): + selector_value = SelectorAbstraction.get_selector(selenium_locator) if options is None: options = {} if self.selected_iframe is not None: - return await self.selected_iframe.type(selector=selenium_locator, text=text, **options) + return await self.selected_iframe.type(selector=selector_value, text=text, **options) else: - return await self.page.type(selector=selenium_locator, text=text, **options) + return await self.page.type(selector=selector_value, text=text, **options) ############ # Wait From 043b11d254734cbed6a31ec8e77b28bc171a0507 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Fri, 30 Oct 2020 19:23:03 +0700 Subject: [PATCH 095/103] Add wait for playwright keywords --- .../async_keywords/playwright_waiting.py | 35 +++++++++++++++---- 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/PuppeteerLibrary/playwright/async_keywords/playwright_waiting.py b/PuppeteerLibrary/playwright/async_keywords/playwright_waiting.py index cc59686..d751b23 100644 --- a/PuppeteerLibrary/playwright/async_keywords/playwright_waiting.py +++ b/PuppeteerLibrary/playwright/async_keywords/playwright_waiting.py @@ -57,29 +57,38 @@ async def wait_for_response_url(self, url, status=200, body=None, timeout=None): }) async def wait_for_navigation(self, timeout=None): - raise Exception('Not implemented.') + await self.library_ctx.get_current_page().get_page().waitForNavigation( + timeout=self.timestr_to_secs_for_default_timeout(timeout) * 1000 + ) async def wait_until_page_contains_element(self, locator, timeout=None): return await self._wait_for_selenium_selector(locator, timeout, visible=True, hidden=False) async def wait_until_element_is_hidden(self, locator, timeout=None): - raise Exception('Not implemented.') + return await self._wait_for_selenium_selector(locator, timeout, visible=False, hidden=True) async def wait_until_element_is_visible(self, locator, timeout=None): - raise Exception('Not implemented.') + return await self._wait_for_selenium_selector(locator, timeout, visible=True, hidden=False) async def wait_until_page_contains(self, text, timeout=None): locator = "xpath://*[contains(., %s)]" % self.escape_xpath_value(text) return await self._wait_for_selenium_selector(locator, timeout, visible=True, hidden=False) async def wait_until_page_does_not_contains(self, text, timeout=None): - raise Exception('Not implemented.') + locator = "xpath://*[contains(., %s)]" % self.escape_xpath_value(text) + return await self._wait_for_selenium_selector(locator, timeout, visible=False, hidden=True) async def wait_until_element_contains(self, locator, text, timeout=None): - raise Exception('Not implemented.') + locator = "xpath://*[contains(., %s)]" % self.escape_xpath_value(text) + return await self._wait_for_selenium_selector(locator, timeout, visible=True, hidden=False) async def wait_until_element_does_not_contains(self, locator, text, timeout=None): - raise Exception('Not implemented.') + async def validate_element_contains_text(): + return (text not in (await (await ( await self.library_ctx.get_current_page(). + querySelector_with_selenium_locator(locator)).getProperty('textContent')).jsonValue())) + return await self._wait_until_worker( + validate_element_contains_text, + self.timestr_to_secs_for_default_timeout(timeout)) async def wait_until_location_contains(self, expected, timeout=None): raise Exception('Not implemented.') @@ -97,6 +106,20 @@ async def _wait_for_selenium_selector(self, selenium_locator, timeout=None, visi timeout = self.timestr_to_secs_for_default_timeout(timeout) return await self.library_ctx.get_current_page().waitForSelector_with_selenium_locator(selenium_locator, timeout, visible, hidden) + async def _wait_until_worker(self, condition, timeout, error=None): + max_time = time.time() + timeout + not_found = None + while time.time() < max_time: + try: + if await condition(): + return + else: + not_found = None + except Exception as err: + not_found = err + await asyncio.sleep(0.2) + raise AssertionError(not_found or error) + def escape_xpath_value(self, value): if '"' in value and '\'' in value: parts_wo_apos = value.split('\'') From 0e96d51e2a7e490d3cffe1ab0b94e82d46a9d656 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Fri, 30 Oct 2020 19:24:55 +0700 Subject: [PATCH 096/103] Release playwright keywords --- Examples/utilities/wait.robot | 2 +- .../async_keywords/playwright_waiting.py | 39 +++++++++++++++++-- 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/Examples/utilities/wait.robot b/Examples/utilities/wait.robot index 668e7f4..fbb8980 100644 --- a/Examples/utilities/wait.robot +++ b/Examples/utilities/wait.robot @@ -4,7 +4,7 @@ Test Teardown Close Browser Suite Teardown Close Puppeteer *** Variables *** -${DEFAULT_BROWSER} webkit +${DEFAULT_BROWSER} chrome ${HOME_PAGE_URL} http://127.0.0.1:7272/basic-html-elements.html ${LOGIN_PAGE_URL} http://127.0.0.1:7272/login-form-example.html diff --git a/PuppeteerLibrary/playwright/async_keywords/playwright_waiting.py b/PuppeteerLibrary/playwright/async_keywords/playwright_waiting.py index d751b23..f0515ac 100644 --- a/PuppeteerLibrary/playwright/async_keywords/playwright_waiting.py +++ b/PuppeteerLibrary/playwright/async_keywords/playwright_waiting.py @@ -91,16 +91,47 @@ async def validate_element_contains_text(): self.timestr_to_secs_for_default_timeout(timeout)) async def wait_until_location_contains(self, expected, timeout=None): - raise Exception('Not implemented.') + async def validate_url_contains_text(): + return expected in self.library_ctx.get_current_page().get_page().url + return await self._wait_until_worker( + validate_url_contains_text, + self.timestr_to_secs_for_default_timeout(timeout)) async def wait_until_location_does_not_contains(self, expected, timeout=None): - raise Exception('Not implemented.') + async def validate_url_not_contains_text(): + return expected not in self.library_ctx.get_current_page().get_page().url + return await self._wait_until_worker( + validate_url_not_contains_text, + self.timestr_to_secs_for_default_timeout(timeout)) async def wait_until_element_is_enabled(self, locator, timeout=None): - raise Exception('Not implemented.') + async def validate_is_enabled(): + element = await self.library_ctx.get_current_page().querySelector_with_selenium_locator(locator) + is_disabled = await (await element.getProperty('disabled')).jsonValue() + return is_disabled == False + return await self._wait_until_worker( + validate_is_enabled, + self.timestr_to_secs_for_default_timeout(timeout), + 'Element '+locator+' was not enabled.') async def wait_until_element_finished_animating(self, locator, timeout=None): - raise Exception('Not implemented.') + prev_rect_tmp = { 'value': None } + async def check_finished_animating(): + element = await self.library_ctx.get_current_page().querySelector_with_selenium_locator(locator) + if prev_rect_tmp['value'] is None: + prev_rect_tmp['value'] = await element.boundingBox() + return False + prev_rect = prev_rect_tmp['value'] + next_rect = await element.boundingBox() + if next_rect['x'] == prev_rect['x'] and next_rect['y'] == prev_rect['y']: + return True + else: + prev_rect_tmp['value'] = next_rect + return False + return await self._wait_until_worker( + check_finished_animating, + self.timestr_to_secs_for_default_timeout(timeout), + 'Element '+locator+' was not enabled.') async def _wait_for_selenium_selector(self, selenium_locator, timeout=None, visible=False, hidden=False): timeout = self.timestr_to_secs_for_default_timeout(timeout) From 1ec11a7e9f49167543d5e0517fbb77533821d95c Mon Sep 17 00:00:00 2001 From: atthaboons Date: Sat, 31 Oct 2020 13:09:49 +0700 Subject: [PATCH 097/103] Add support timeout --- Examples/utilities/timeout.robot | 1 - .../keywords/browsermanagement.py | 23 ------------------- PuppeteerLibrary/keywords/utility.py | 22 +++++++++++++++++- 3 files changed, 21 insertions(+), 25 deletions(-) diff --git a/Examples/utilities/timeout.robot b/Examples/utilities/timeout.robot index 227e921..e70c5e7 100644 --- a/Examples/utilities/timeout.robot +++ b/Examples/utilities/timeout.robot @@ -1,5 +1,4 @@ *** Settings *** -Force Tags Ignore Library PuppeteerLibrary Test Setup Open browser to test page Test Teardown Close Browser diff --git a/PuppeteerLibrary/keywords/browsermanagement.py b/PuppeteerLibrary/keywords/browsermanagement.py index 56d0558..3ce1541 100644 --- a/PuppeteerLibrary/keywords/browsermanagement.py +++ b/PuppeteerLibrary/keywords/browsermanagement.py @@ -1,4 +1,3 @@ -from robot.utils import timestr_to_secs from PuppeteerLibrary.base.librarycomponent import LibraryComponent from PuppeteerLibrary.base.robotlibcore import keyword from PuppeteerLibrary.keywords.browsermanagement_async import BrowserManagementKeywordsAsync @@ -103,28 +102,6 @@ def go_to(self, url): def reload_page(self): """Reload the current page""" self.loop.run_until_complete(self.get_async_keyword_group().reload_page()) - # async def reload_page_async(): - # await self.ctx.get_current_page().reload() - # self.loop.run_until_complete(reload_page_async()) - - @keyword - def set_timeout(self, timeout): - """Sets the timeout that is used by various keywords. - The value can be given as a number that is considered to be seconds or as a human-readable string like 1 second. - The previous value is returned and can be used to restore the original value later if needed. - See the Timeout section above for more information. - - Example: - - | ${orig timeout} = | Set Timeout | 15 seconds | - | Open page that loads slowly | | | - | Set Timeout | ${orig timeout} | | - - """ - orig_timeout = self.ctx.timeout - self.ctx.timeout = timestr_to_secs(timeout) - self.info('Original timeout is ' + str(orig_timeout) + ' seconds') - return orig_timeout @keyword def get_window_count(self): diff --git a/PuppeteerLibrary/keywords/utility.py b/PuppeteerLibrary/keywords/utility.py index 5fa0a5c..a47fad3 100644 --- a/PuppeteerLibrary/keywords/utility.py +++ b/PuppeteerLibrary/keywords/utility.py @@ -1,7 +1,8 @@ import asyncio +from robot.utils import timestr_to_secs +from robot.libraries.BuiltIn import _RunKeyword from PuppeteerLibrary.keywords.browsermanagement import BrowserManagementKeywords from PuppeteerLibrary.playwright.async_keywords.playwright_browsermanagement import PlaywrightBrowserManagement -from robot.libraries.BuiltIn import _RunKeyword from PuppeteerLibrary.base.librarycomponent import LibraryComponent from PuppeteerLibrary.base.robotlibcore import keyword @@ -11,6 +12,25 @@ class UtilityKeywords(LibraryComponent): def __init__(self, ctx): super().__init__(ctx) + @keyword + def set_timeout(self, timeout): + """Sets the timeout that is used by various keywords. + The value can be given as a number that is considered to be seconds or as a human-readable string like 1 second. + The previous value is returned and can be used to restore the original value later if needed. + See the Timeout section above for more information. + + Example: + + | ${orig timeout} = | Set Timeout | 15 seconds | + | Open page that loads slowly | | | + | Set Timeout | ${orig timeout} | | + + """ + orig_timeout = self.ctx.timeout + self.ctx.get_current_library_context().timeout = timestr_to_secs(timeout) + self.info('Original timeout is ' + str(orig_timeout) + ' seconds') + return orig_timeout + @keyword def run_async_keywords_and_return_first_completed(self, *keywords): """Executes all the given keywords in a asynchronous and wait until first keyword is completed From 770ea203c7c555e0906193915f5c2b8edae198c1 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Sat, 31 Oct 2020 13:36:06 +0700 Subject: [PATCH 098/103] Add Puppeteer mock response keywords --- Examples/api/mock-api.robot | 8 +++--- .../ikeywords/imockresponse_async.py | 9 +++++++ PuppeteerLibrary/keywords/mockresponse.py | 6 ++++- .../async_keywords/puppeteer_mockresponse.py | 27 +++++++++++++++++++ .../puppeteer/puppeteer_context.py | 2 ++ 5 files changed, 48 insertions(+), 4 deletions(-) create mode 100644 PuppeteerLibrary/ikeywords/imockresponse_async.py create mode 100644 PuppeteerLibrary/puppeteer/async_keywords/puppeteer_mockresponse.py diff --git a/Examples/api/mock-api.robot b/Examples/api/mock-api.robot index 3fbb1de..72b489c 100644 --- a/Examples/api/mock-api.robot +++ b/Examples/api/mock-api.robot @@ -1,11 +1,11 @@ *** Settings *** -Force Tags Ignore Library PuppeteerLibrary Test Setup Open browser to test page Test Teardown Close All Browser Suite Teardown Close Puppeteer *** Variables *** +${DEFAULT_BROWSER} chrome ${HOME_PAGE_URL} http://127.0.0.1:7272/basic-html-elements.html @@ -22,8 +22,10 @@ Mock ajax response with json response Click Element id=get_ajax Wait Until Page Contains I'm a mock response json + *** Keywords *** Open browser to test page - ${HEADLESS} Get variable value ${HEADLESS} ${False} + ${BROWSER} = Get variable value ${BROWSER} ${DEFAULT_BROWSER} + ${HEADLESS} = Get variable value ${HEADLESS} ${False} &{options} = create dictionary headless=${HEADLESS} - Open browser ${HOME_PAGE_URL} options=${options} + Open browser ${HOME_PAGE_URL} browser=${BROWSER} options=${options} diff --git a/PuppeteerLibrary/ikeywords/imockresponse_async.py b/PuppeteerLibrary/ikeywords/imockresponse_async.py new file mode 100644 index 0000000..d39c74a --- /dev/null +++ b/PuppeteerLibrary/ikeywords/imockresponse_async.py @@ -0,0 +1,9 @@ +from abc import ABC, abstractmethod +from PuppeteerLibrary.ikeywords.base_async_keywords import BaseAsyncKeywords + + +class iMockResponseAsync(BaseAsyncKeywords, ABC): + + @abstractmethod + async def mock_current_page_api_response(self, url, mock_response, method='GET', body=None): + pass diff --git a/PuppeteerLibrary/keywords/mockresponse.py b/PuppeteerLibrary/keywords/mockresponse.py index d95dc72..48759d0 100644 --- a/PuppeteerLibrary/keywords/mockresponse.py +++ b/PuppeteerLibrary/keywords/mockresponse.py @@ -1,3 +1,4 @@ +from PuppeteerLibrary.ikeywords.imockresponse_async import iMockResponseAsync from PuppeteerLibrary.base.robotlibcore import keyword from PuppeteerLibrary.base.librarycomponent import LibraryComponent from PuppeteerLibrary.keywords.mockresponse_async import MockResponseKeywordsAsync @@ -9,6 +10,9 @@ def __init__(self, ctx): super().__init__(ctx) self.async_func = MockResponseKeywordsAsync(self.ctx) + def get_async_keyword_group(self) -> iMockResponseAsync: + return self.ctx.get_current_library_context().get_async_keyword_group(type(self).__name__) + @keyword def mock_current_page_api_response(self, url, mock_response, method='GET', body=None): """ @@ -44,4 +48,4 @@ def mock_current_page_api_response(self, url, mock_response, method='GET', body= | Mock Current Page Api Response | /ajax_info.json\\?count=3 | ${response} | """ - return self.loop.run_until_complete(self.async_func.mock_current_page_api_response_async(url, mock_response, method, body)) + return self.loop.run_until_complete(self.get_async_keyword_group().mock_current_page_api_response(url, mock_response, method, body)) diff --git a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_mockresponse.py b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_mockresponse.py new file mode 100644 index 0000000..97532c5 --- /dev/null +++ b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_mockresponse.py @@ -0,0 +1,27 @@ +import asyncio +import re +from pyppeteer.network_manager import Request +from PuppeteerLibrary.base.robotlibcore import keyword +from PuppeteerLibrary.ikeywords.imockresponse_async import iMockResponseAsync + + +class PuppeteerMockResponse(iMockResponseAsync): + + def __init__(self, library_ctx): + super().__init__(library_ctx) + + async def mock_current_page_api_response(self, url, mock_response, method='GET', body=None): + page = self.library_ctx.get_current_page().get_page() + await page.setRequestInterception(True) + page.on('request', lambda request: + asyncio.ensure_future(self.mock_api_response(request, url, mock_response, method, body))) + + async def mock_api_response(self, request: Request, url, mock_response, method, body): + if re.search(url, request.url) is not None and request.method == method: + try: + pos_data = (await request.postData()) + except: + pos_data = '' + if body is None or re.search(body, pos_data.replace('\n', '')): + return await request.respond(mock_response) + await request.continue_() diff --git a/PuppeteerLibrary/puppeteer/puppeteer_context.py b/PuppeteerLibrary/puppeteer/puppeteer_context.py index 44acc07..5301588 100644 --- a/PuppeteerLibrary/puppeteer/puppeteer_context.py +++ b/PuppeteerLibrary/puppeteer/puppeteer_context.py @@ -1,3 +1,4 @@ +from PuppeteerLibrary.puppeteer.async_keywords.puppeteer_mockresponse import PuppeteerMockResponse import sys from pyppeteer import launch from pyppeteer.browser import Browser @@ -103,6 +104,7 @@ def get_async_keyword_group(self, keyword_group_name: str): "ElementKeywords": PuppeteerElement(self), "FormElementKeywords": PuppeteerFormElement(self), "JavascriptKeywords": PuppeteerJavascript(self), + "MockResponseKeywords": PuppeteerMockResponse(self), "MouseEventKeywords": PuppeteerMouseEvent(self), "PDFKeywords": PuppeteerPDF(self), "ScreenshotKeywords": PuppeteerScreenshot(self), From b868943a8244f4d0d34218183cc96cb9a560c224 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Sat, 31 Oct 2020 16:13:14 +0700 Subject: [PATCH 099/103] Add playwright and puppeteer mock response keywords --- Examples/api/mock-api.robot | 6 ++--- .../async_keywords/playwright_mockresponse.py | 26 +++++++++++++++++++ .../playwright/playwright_context.py | 2 ++ .../async_keywords/puppeteer_mockresponse.py | 2 +- 4 files changed, 32 insertions(+), 4 deletions(-) create mode 100644 PuppeteerLibrary/playwright/async_keywords/playwright_mockresponse.py diff --git a/Examples/api/mock-api.robot b/Examples/api/mock-api.robot index 72b489c..bc8d65c 100644 --- a/Examples/api/mock-api.robot +++ b/Examples/api/mock-api.robot @@ -10,15 +10,15 @@ ${HOME_PAGE_URL} http://127.0.0.1:7272/basic-html-elements.html *** Test Cases *** - Mock ajax response with raw text +Mock ajax response with raw text &{response} Create Dictionary body=I'm a mock response text - Mock Current Page Api Response /ajax_info.json\\?count=3 ${response} + Mock Current Page Api Response /ajax_info.json?count=3 ${response} Click Element id=get_ajax Wait Until Page Contains I'm a mock response text Mock ajax response with json response &{response} Create Dictionary body={ 'data': 'I\'m a mock response json'} contentType=application/json - Mock Current Page Api Response /ajax_info.json\\?count=3 ${response} + Mock Current Page Api Response /ajax_info.json?count=3 ${response} Click Element id=get_ajax Wait Until Page Contains I'm a mock response json diff --git a/PuppeteerLibrary/playwright/async_keywords/playwright_mockresponse.py b/PuppeteerLibrary/playwright/async_keywords/playwright_mockresponse.py new file mode 100644 index 0000000..92cc025 --- /dev/null +++ b/PuppeteerLibrary/playwright/async_keywords/playwright_mockresponse.py @@ -0,0 +1,26 @@ +import asyncio +import re +from PuppeteerLibrary.base.robotlibcore import keyword +from PuppeteerLibrary.ikeywords.imockresponse_async import iMockResponseAsync + + +class PlaywrightMockResponse(iMockResponseAsync): + + def __init__(self, library_ctx): + super().__init__(library_ctx) + + async def mock_current_page_api_response(self, url, mock_response, method='GET', body=None): + page = self.library_ctx.get_current_page().get_page() + await page.route(url, lambda route, request: asyncio.ensure_future(self.mock_api_response(route, request, mock_response, method, body))) + + async def mock_api_response(self, route, request, mock_response, method, body): + try: + pos_data = (await request.postData()) + except: + pos_data = '' + if body is None or re.search(body, pos_data.replace('\n', '')): + await route.fulfill( + **mock_response + ) + await request.continue_() + \ No newline at end of file diff --git a/PuppeteerLibrary/playwright/playwright_context.py b/PuppeteerLibrary/playwright/playwright_context.py index 1e6d853..77516d3 100644 --- a/PuppeteerLibrary/playwright/playwright_context.py +++ b/PuppeteerLibrary/playwright/playwright_context.py @@ -1,3 +1,4 @@ +from PuppeteerLibrary.playwright.async_keywords.playwright_mockresponse import PlaywrightMockResponse import asyncio from PuppeteerLibrary.custom_elements.base_page import BasePage from PuppeteerLibrary.playwright.custom_elements.playwright_page import PlaywrightPage @@ -84,6 +85,7 @@ def get_async_keyword_group(self, keyword_group_name: str): "ElementKeywords": PlaywrightElement(self), "FormElementKeywords": PlaywrightFormElement(self), "JavascriptKeywords": PlaywrightJavascript(self), + "MockResponseKeywords": PlaywrightMockResponse(self), "MouseEventKeywords": PlaywrightMouseEvent(self), "PDFKeywords": PlaywrightPDF(self), "ScreenshotKeywords": PlaywrightScreenshot(self), diff --git a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_mockresponse.py b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_mockresponse.py index 97532c5..b857577 100644 --- a/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_mockresponse.py +++ b/PuppeteerLibrary/puppeteer/async_keywords/puppeteer_mockresponse.py @@ -17,7 +17,7 @@ async def mock_current_page_api_response(self, url, mock_response, method='GET', asyncio.ensure_future(self.mock_api_response(request, url, mock_response, method, body))) async def mock_api_response(self, request: Request, url, mock_response, method, body): - if re.search(url, request.url) is not None and request.method == method: + if re.search(re.escape(url), request.url) is not None and request.method == method: try: pos_data = (await request.postData()) except: From 694169a11f614fef35be3b0aec33787286672bf8 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Sat, 31 Oct 2020 16:22:16 +0700 Subject: [PATCH 100/103] Cleanup scripts --- Examples/debug-mode/enable-debug-mode.robot | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/Examples/debug-mode/enable-debug-mode.robot b/Examples/debug-mode/enable-debug-mode.robot index 4297a88..6296c94 100644 --- a/Examples/debug-mode/enable-debug-mode.robot +++ b/Examples/debug-mode/enable-debug-mode.robot @@ -1,20 +1,24 @@ *** Settings *** -Force Tags Ignore Library PuppeteerLibrary Test Teardown Close All Browser Suite Teardown Close Puppeteer +*** Variables *** +${DEFAULT_BROWSER} chrome +# ${DEFAULT_BROWSER} webkit +${HOME_PAGE_URL} http://127.0.0.1:7272/login-form-example.html + *** Test Cases *** Enable debug mode - Open browser to test page http://127.0.0.1:7272/login-form-example.html + Open browser to test page Input Text id=exampleInputEmail1 demo@qahive.com Input Text id=exampleInputPassword1 123456789 *** Keywords *** Open browser to test page - [Arguments] ${url} - ${HEADLESS} Get variable value ${HEADLESS} ${False} - Run Keyword If ${HEADLESS} == ${False} Enable Debug Mode + ${BROWSER} = Get variable value ${BROWSER} ${DEFAULT_BROWSER} + ${HEADLESS} = Get variable value ${HEADLESS} ${False} + Run Keyword If ${HEADLESS} == ${False} Enable Debug Mode &{options} = create dictionary headless=${HEADLESS} - Open browser ${url} options=${options} + Open browser ${HOME_PAGE_URL} browser=${BROWSER} options=${options} From f99805b9efc0a78dbeb06cf925f2828d9994ee4d Mon Sep 17 00:00:00 2001 From: atthaboons Date: Sat, 31 Oct 2020 19:58:25 +0700 Subject: [PATCH 101/103] Add firefox support --- .github/workflows/pythonpackage.yml | 2 +- .../library_context/library_context_factory.py | 2 ++ README.md | 11 ++++++++++- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index 1886ef6..54d1c92 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -16,7 +16,7 @@ jobs: - python-version: 3.8 browser: chrome - python-version: 3.9 - browser: chrome + browser: firefox steps: - uses: actions/checkout@v1 diff --git a/PuppeteerLibrary/library_context/library_context_factory.py b/PuppeteerLibrary/library_context/library_context_factory.py index a396eb9..c812910 100644 --- a/PuppeteerLibrary/library_context/library_context_factory.py +++ b/PuppeteerLibrary/library_context/library_context_factory.py @@ -15,5 +15,7 @@ def create(self, browser_type: str) -> iLibraryContext: return PlaywrightContext(browser_type) elif browser_type.lower() == 'webkit': return PlaywrightContext(browser_type) + elif browser_type.lower() == 'firefox': + return PlaywrightContext(browser_type) else: raise Exception('Sorry, not supported for library type '+str(browser_type)+'.') diff --git a/README.md b/README.md index 9b07698..e58ffb6 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ # robotframework-puppeteer Robot Framework Puppeteer Library powered by [Pyppeteer](https://github.com/pyppeteer/pyppeteer). -Improve automated web testing with native functionality from [Puppeteer](https://github.com/puppeteer/puppeteer) by Google. +Improve automated web testing with chrome native functionality from [Puppeteer](https://github.com/puppeteer/puppeteer) by Google and webkit from [Playwright](https://github.com/microsoft/playwright-python). More detail please visit [Robot Framework Puppeteer Homepage](https://qahive.github.io/robotframework-puppeteer.github.io/) @@ -14,6 +14,15 @@ Example: - _Intercepter javascript function_ +Browser Support +--------------------- +| | Support | Library | +| :--- | :---: | :---: | :---: | +| Chromium | ✅ | Puppeteer | +| WebKit | ✅ | Playwright | +| Firefox | ✅ | Playwright | + + Keyword documentation --------------------- See [`keyword documentation`](https://qahive.github.io/robotframework-puppeteer/PuppeteerLibrary.html) for available keywords and more information about the library in general. From 60cb895ede9dd4cb57302664561a40eb09dbbef2 Mon Sep 17 00:00:00 2001 From: atthaboons Date: Sat, 31 Oct 2020 20:16:17 +0700 Subject: [PATCH 102/103] Cleanup scripts --- Examples/alert-handler/alert-handler.robot | 4 +- Examples/utilities/execute-javascript.robot | 2 +- Examples/utilities/generate-pdf.robot | 2 +- PuppeteerLibrary/__init__.py | 125 +----------- .../ikeywords/iscreenshot_async.py | 3 +- PuppeteerLibrary/keywords/__init__.py | 11 -- PuppeteerLibrary/keywords/alert_async.py | 17 -- .../keywords/browsermanagement.py | 5 +- .../keywords/browsermanagement_async.py | 67 ------- PuppeteerLibrary/keywords/dropdown.py | 4 +- PuppeteerLibrary/keywords/dropdown_async.py | 32 ---- PuppeteerLibrary/keywords/element.py | 4 +- PuppeteerLibrary/keywords/element_async.py | 103 ---------- PuppeteerLibrary/keywords/formelement.py | 6 +- .../keywords/formelement_async.py | 21 -- PuppeteerLibrary/keywords/javascript.py | 3 +- PuppeteerLibrary/keywords/javascript_async.py | 12 -- PuppeteerLibrary/keywords/mockresponse.py | 2 - .../keywords/mockresponse_async.py | 29 --- PuppeteerLibrary/keywords/mouseevent.py | 2 - PuppeteerLibrary/keywords/mouseevent_async.py | 30 --- PuppeteerLibrary/keywords/pdf.py | 1 - PuppeteerLibrary/keywords/pdf_async.py | 38 ---- PuppeteerLibrary/keywords/screenshot.py | 4 +- PuppeteerLibrary/keywords/screenshot_async.py | 44 ----- PuppeteerLibrary/keywords/utility.py | 1 - PuppeteerLibrary/keywords/waiting.py | 4 +- PuppeteerLibrary/keywords/waiting_async.py | 180 ------------------ 28 files changed, 16 insertions(+), 740 deletions(-) delete mode 100644 PuppeteerLibrary/keywords/alert_async.py delete mode 100644 PuppeteerLibrary/keywords/browsermanagement_async.py delete mode 100644 PuppeteerLibrary/keywords/dropdown_async.py delete mode 100644 PuppeteerLibrary/keywords/element_async.py delete mode 100644 PuppeteerLibrary/keywords/formelement_async.py delete mode 100644 PuppeteerLibrary/keywords/javascript_async.py delete mode 100644 PuppeteerLibrary/keywords/mockresponse_async.py delete mode 100644 PuppeteerLibrary/keywords/mouseevent_async.py delete mode 100644 PuppeteerLibrary/keywords/pdf_async.py delete mode 100644 PuppeteerLibrary/keywords/screenshot_async.py delete mode 100644 PuppeteerLibrary/keywords/waiting_async.py diff --git a/Examples/alert-handler/alert-handler.robot b/Examples/alert-handler/alert-handler.robot index 666ea59..7f8ed1c 100644 --- a/Examples/alert-handler/alert-handler.robot +++ b/Examples/alert-handler/alert-handler.robot @@ -12,14 +12,14 @@ ${HOME_PAGE_URL} http://127.0.0.1:7272/basic-html-elements.html *** Test Cases *** Accept alert - [Tags] Ignore_webkit + [Tags] Ignore_webkit Ignore_firefox Run Async Keywords ... Handle Alert ACCEPT AND ... Click Element id=alert_confirm Click Element id:get_ajax Dismiss alert - [Tags] Ignore_webkit + [Tags] Ignore_webkit Ignore_firefox Run Async Keywords ... Handle Alert DISMISS AND ... Click Element id=alert_confirm diff --git a/Examples/utilities/execute-javascript.robot b/Examples/utilities/execute-javascript.robot index 9baf27d..4b2882b 100644 --- a/Examples/utilities/execute-javascript.robot +++ b/Examples/utilities/execute-javascript.robot @@ -13,7 +13,7 @@ ${HOME_PAGE_URL} http://127.0.0.1:7272/basic-html-elements.html *** Test Cases *** Execute javascript command - [Tags] Ignore_webkit + [Tags] Ignore_webkit Ignore_firefox Handle Alert ACCEPT Execute Javascript alert('Hello world'); diff --git a/Examples/utilities/generate-pdf.robot b/Examples/utilities/generate-pdf.robot index d988c09..def3b80 100644 --- a/Examples/utilities/generate-pdf.robot +++ b/Examples/utilities/generate-pdf.robot @@ -12,7 +12,7 @@ ${HOME_PAGE_URL} http://127.0.0.1:7272/basic-html-elements.html *** Test Cases *** Generate pdf file - [Tags] Ignore_webkit + [Tags] Ignore_webkit Ignore_firefox [Documentation] Only support on chrome headless mode Print as pdf diff --git a/PuppeteerLibrary/__init__.py b/PuppeteerLibrary/__init__.py index 6584dd5..c7f2e50 100644 --- a/PuppeteerLibrary/__init__.py +++ b/PuppeteerLibrary/__init__.py @@ -4,35 +4,23 @@ from robot.api.deco import not_keyword from robot.api import logger from robot.libraries.BuiltIn import BuiltIn -from pyppeteer.browser import Browser, BrowserContext +from pyppeteer.browser import Browser from PuppeteerLibrary.library_context.ilibrary_context import iLibraryContext from PuppeteerLibrary.library_context.library_context_factory import LibraryContextFactory -from PuppeteerLibrary.custom_elements.SPage import SPage from PuppeteerLibrary.base.robotlibcore import DynamicCore from PuppeteerLibrary.keywords import ( AlertKeywords, - AlertKeywordsAsync, BrowserManagementKeywords, - BrowserManagementKeywordsAsync, DropdownKeywords, - DropdownKeywordsAsync, ElementKeywords, - ElementKeywordsAsync, FormElementKeywords, - FormElementKeywordsAsync, JavascriptKeywords, - JavascriptKeywordsAsync, MockResponseKeywords, - MockResponseKeywordsAsync, MouseEventKeywords, - MouseEventKeywordsAsync, PDFKeywords, - PDFKeywordsAsync, ScreenshotKeywords, - ScreenshotKeywordsAsync, UtilityKeywords, - WaitingKeywords, - WaitingKeywordsAsync) + WaitingKeywords) # Get the version from the _version.py versioneer file. For a git checkout, @@ -83,9 +71,6 @@ class PuppeteerLibrary(DynamicCore, iPuppeteerLibrary): ROBOT_LISTENER_API_VERSION = 3 loop = None - is_load_async_keywords = False - async_libraries = [] - browser = None puppeteer_browser: iLibraryContext = None playwright_browser: iLibraryContext = None @@ -129,21 +114,6 @@ def __init__(self): WaitingKeywords(self) ] DynamicCore.__init__(self, libraries) - - self.async_libraries = [ - AlertKeywordsAsync(self), - BrowserManagementKeywordsAsync(self), - DropdownKeywordsAsync(self), - ElementKeywordsAsync(self), - FormElementKeywordsAsync(self), - JavascriptKeywordsAsync(self), - MockResponseKeywordsAsync(self), - MouseEventKeywordsAsync(self), - PDFKeywordsAsync(self), - ScreenshotKeywordsAsync(self), - WaitingKeywordsAsync(self) - ] - self.library_factory = LibraryContextFactory() @not_keyword @@ -190,97 +160,6 @@ def remove_library_context(self, alias): else: self.current_libary_context = None - ############################## - # Will obsolted - ############################## - @not_keyword - def load_async_keywords(self): - if self.is_load_async_keywords is True: - return - self.add_library_components(self.async_libraries) - self.is_load_async_keywords = True - - @not_keyword - def clear_browser(self): - self.browser = None - self.contexts = {} - self.current_context_name = None - self.current_page = None - self.clear_current_iframe() - - @not_keyword - async def create_context_async(self, alias) -> BrowserContext: - context = await self.browser.createIncognitoBrowserContext() - if alias in self.contexts.keys(): - await self.contexts[alias].close() - del self.contexts[alias] - self.current_context_name = alias - self.contexts[self.current_context_name] = context - return context - - @not_keyword - async def add_context_async(self, alias, browser_context): - if alias in self.library_contexts.keys(): - del self.library_contexts[alias] - self.current_context_name = alias - self.library_contexts[self.current_context_name] = browser_context - - @not_keyword - def get_current_context(self) -> BrowserContext: - return self.contexts[self.current_context_name] - - @not_keyword - async def set_current_context(self, context_name) -> BrowserContext: - self.current_context_name = context_name - context = self.get_current_context() - pages = await context.pages() - self.current_page = pages[-1] - self.clear_current_iframe() - return context - - @not_keyword - def clear_context(self, context_name): - del self.contexts[context_name] - if self.current_context_name == context_name: - self.current_context_name = None - self.current_page = None - - @not_keyword - def clear_current_context(self): - self.clear_context(self.current_context_name) - - @not_keyword - async def create_page_async(self) -> SPage: - self.current_page = await self.get_current_context().newPage() - return self.get_current_page() - - @not_keyword - def get_current_page(self) -> SPage: - page = self.current_page - page.__class__ = SPage - page.selected_iframe = self.current_iframe - return page - - @not_keyword - def set_current_page(self, page) -> SPage: - self.current_page = page - page.__class__ = SPage - self.clear_current_iframe() - return self.current_page - - @not_keyword - def clear_current_page(self): - self.current_page = None - self.clear_current_iframe() - - @not_keyword - def set_current_iframe(self, iframe): - self.current_iframe = iframe - - @not_keyword - def clear_current_iframe(self): - self.current_iframe = None - @not_keyword def run_keyword(self, name, args, kwargs): self._running_keyword = name diff --git a/PuppeteerLibrary/ikeywords/iscreenshot_async.py b/PuppeteerLibrary/ikeywords/iscreenshot_async.py index 65ad276..02f057e 100644 --- a/PuppeteerLibrary/ikeywords/iscreenshot_async.py +++ b/PuppeteerLibrary/ikeywords/iscreenshot_async.py @@ -1,9 +1,10 @@ from abc import ABC, abstractmethod from PuppeteerLibrary.ikeywords.base_async_keywords import BaseAsyncKeywords +DEFAULT_FILENAME_PAGE = 'puppeteer-screenshot-{index}.png' class iScreenshotAsync(BaseAsyncKeywords, ABC): - + @abstractmethod async def capture_page_screenshot(self, path: str): pass diff --git a/PuppeteerLibrary/keywords/__init__.py b/PuppeteerLibrary/keywords/__init__.py index 61037cf..3560834 100644 --- a/PuppeteerLibrary/keywords/__init__.py +++ b/PuppeteerLibrary/keywords/__init__.py @@ -1,23 +1,12 @@ from .alert import AlertKeywords -from .alert_async import AlertKeywordsAsync from .browsermanagement import BrowserManagementKeywords -from .browsermanagement_async import BrowserManagementKeywordsAsync from .dropdown import DropdownKeywords -from .dropdown_async import DropdownKeywordsAsync from .element import ElementKeywords -from .element_async import ElementKeywordsAsync from .formelement import FormElementKeywords -from .formelement_async import FormElementKeywordsAsync from .javascript import JavascriptKeywords -from .javascript_async import JavascriptKeywordsAsync from .mockresponse import MockResponseKeywords -from .mockresponse_async import MockResponseKeywordsAsync from .mouseevent import MouseEventKeywords -from .mouseevent_async import MouseEventKeywordsAsync from .pdf import PDFKeywords -from .pdf_async import PDFKeywordsAsync from .screenshot import ScreenshotKeywords -from .screenshot_async import ScreenshotKeywordsAsync from .utility import UtilityKeywords from .waiting import WaitingKeywords -from .waiting_async import WaitingKeywordsAsync diff --git a/PuppeteerLibrary/keywords/alert_async.py b/PuppeteerLibrary/keywords/alert_async.py deleted file mode 100644 index be1b89e..0000000 --- a/PuppeteerLibrary/keywords/alert_async.py +++ /dev/null @@ -1,17 +0,0 @@ -import asyncio - -from PuppeteerLibrary.base.robotlibcore import keyword -from PuppeteerLibrary.base.librarycomponent import LibraryComponent - - -class AlertKeywordsAsync(LibraryComponent): - - @keyword - async def handle_alert_async(self, action, prompt_text=''): - return self.ctx.get_current_page().on('dialog', lambda dialog: asyncio.ensure_future(self.handle_dialog(dialog, action, prompt_text))) - - async def handle_dialog(self, dialog, action, prompt_text=''): - if action == 'ACCEPT': - await dialog.accept(prompt_text) - elif action == 'DISMISS': - await dialog.dismiss() diff --git a/PuppeteerLibrary/keywords/browsermanagement.py b/PuppeteerLibrary/keywords/browsermanagement.py index 3ce1541..218567b 100644 --- a/PuppeteerLibrary/keywords/browsermanagement.py +++ b/PuppeteerLibrary/keywords/browsermanagement.py @@ -1,6 +1,5 @@ from PuppeteerLibrary.base.librarycomponent import LibraryComponent from PuppeteerLibrary.base.robotlibcore import keyword -from PuppeteerLibrary.keywords.browsermanagement_async import BrowserManagementKeywordsAsync from PuppeteerLibrary.ikeywords.ibrowsermanagement_async import iBrowserManagementAsync @@ -8,7 +7,6 @@ class BrowserManagementKeywords(LibraryComponent): def __init__(self, ctx): super().__init__(ctx) - self.async_func = BrowserManagementKeywordsAsync(self.ctx) def get_async_keyword_group(self) -> iBrowserManagementAsync: return self.ctx.get_current_library_context().get_async_keyword_group(type(self).__name__) @@ -22,7 +20,7 @@ def open_browser(self, url, browser="chrome", alias=None, options=None): | = Browser = | = Name(s) = | | Google Chrome | chrome | | Webkit (Safari engine) | webkit | - + | Firefox | firefox | The ``options`` argument as a dictionary @@ -32,7 +30,6 @@ def open_browser(self, url, browser="chrome", alias=None, options=None): | height | default 768 | | emulate | iPhone 11 | - Example: | &{options} = | create dictionary | headless=${False} | diff --git a/PuppeteerLibrary/keywords/browsermanagement_async.py b/PuppeteerLibrary/keywords/browsermanagement_async.py deleted file mode 100644 index 24b232b..0000000 --- a/PuppeteerLibrary/keywords/browsermanagement_async.py +++ /dev/null @@ -1,67 +0,0 @@ -import asyncio -import time -from PuppeteerLibrary.base.robotlibcore import keyword -from PuppeteerLibrary.base.librarycomponent import LibraryComponent -from PuppeteerLibrary.utils.device_descriptors import DEVICE_DESCRIPTORS - - -class BrowserManagementKeywordsAsync(LibraryComponent): - - @keyword - async def get_window_count_async(self): - pages = await self.ctx.get_browser().pages() - for page in pages: - # Workaround: for force pages re-cache - try: - await page.title() - except: - return -1 - return len(await self.ctx.get_browser().pages()) - - @keyword - async def wait_for_new_window_open_async(self, timeout=None): - page_len = 0 - # Workaround: - # We get length without force reset. For ensure that when we count page length. - # Page length still not update / same as before open new window - pre_page_len = len(await self.ctx.get_browser().pages()) - timeout = self.timestr_to_secs_for_default_timeout(timeout) - max_time = time.time() + timeout - while time.time() < max_time: - page_len = await self.get_window_count_async() - if page_len > pre_page_len: - return - await asyncio.sleep(0.5) - raise Exception('No new page has been open. pre: ' + str(pre_page_len) + ' current: ' + str(page_len)) - - @keyword - async def close_browser_async(self, alias=None): - if alias is None: - alias = self.ctx.current_context_name - await self.ctx.contexts[alias].close() - self.ctx.clear_context(alias) - if len(self.ctx.contexts.keys()) > 0: - await self.ctx.set_current_context(list(self.ctx.contexts.keys())[-1]) - - @keyword - async def close_all_browser_async(self): - for context in self.ctx.contexts.values(): - await context.close() - self.ctx.contexts = {} - self.ctx.current_context_name = None - self.ctx.current_page = None - - @keyword - async def close_puppeteer_async(self): - await self.ctx.browser.close() - self.ctx.clear_browser() - - @keyword - async def enable_emulate_mode_async(self, emulate_name): - await self.ctx.get_current_page().emulate(DEVICE_DESCRIPTORS[emulate_name]) - - @keyword - async def select_frame_async(self, selenium_locator): - element = await self.ctx.get_current_page().querySelector_with_selenium_locator(selenium_locator) - iframe = await element.contentFrame() - self.ctx.set_current_iframe(iframe) diff --git a/PuppeteerLibrary/keywords/dropdown.py b/PuppeteerLibrary/keywords/dropdown.py index 07bce0d..21050f7 100644 --- a/PuppeteerLibrary/keywords/dropdown.py +++ b/PuppeteerLibrary/keywords/dropdown.py @@ -1,6 +1,5 @@ -from PuppeteerLibrary.base.librarycomponent import LibraryComponent from PuppeteerLibrary.base.robotlibcore import keyword -from PuppeteerLibrary.keywords.dropdown_async import DropdownKeywordsAsync +from PuppeteerLibrary.base.librarycomponent import LibraryComponent from PuppeteerLibrary.ikeywords.idropdown_async import iDropdownAsync @@ -8,7 +7,6 @@ class DropdownKeywords(LibraryComponent): def __init__(self, ctx): super().__init__(ctx) - self.async_func = DropdownKeywordsAsync(self.ctx) def get_async_keyword_group(self) -> iDropdownAsync: return self.ctx.get_current_library_context().get_async_keyword_group(type(self).__name__) diff --git a/PuppeteerLibrary/keywords/dropdown_async.py b/PuppeteerLibrary/keywords/dropdown_async.py deleted file mode 100644 index c14b11c..0000000 --- a/PuppeteerLibrary/keywords/dropdown_async.py +++ /dev/null @@ -1,32 +0,0 @@ -from PuppeteerLibrary.base.robotlibcore import keyword -from PuppeteerLibrary.base.librarycomponent import LibraryComponent -from PuppeteerLibrary.locators import SelectorAbstraction - - -class DropdownKeywordsAsync(LibraryComponent): - - @keyword - async def select_from_list_by_value_async(self, selenium_locator, values): - selector_value = SelectorAbstraction.get_selector(selenium_locator) - if SelectorAbstraction.is_xpath(selenium_locator): - await self.ctx.get_current_page().evaluate(''' - element = document.evaluate('{selector_value}//option[contains(@value, "{values}")]', document, null, XPathResult.ANY_TYPE, null).iterateNext(); - element.selected = true; - '''.format(selector_value=selector_value, values=values)) - else: - await self.ctx.get_current_page().select(selector_value, values) - - @keyword - async def select_from_list_by_label_async(self, selenium_locator, labels): - selector_value = SelectorAbstraction.get_selector(selenium_locator) - if SelectorAbstraction.is_xpath(selenium_locator): - await self.ctx.get_current_page().evaluate(''' - element = document.evaluate('{selector_value}//option[text()=\"{label}\"]', document, null, XPathResult.ANY_TYPE, null).iterateNext(); - element.selected = true; - '''.format(selector_value=selector_value, label=labels)) - else: - await self.ctx.get_current_page().evaluate(''' - selector_element = document.querySelector('{selector_value}'); - element = document.evaluate('//option[text()=\"{label}\"]', selector_element, null, XPathResult.ANY_TYPE, null).iterateNext(); - element.selected = true; - '''.format(selector_value=selector_value, label=labels)) diff --git a/PuppeteerLibrary/keywords/element.py b/PuppeteerLibrary/keywords/element.py index 0b0eb50..b27ff98 100644 --- a/PuppeteerLibrary/keywords/element.py +++ b/PuppeteerLibrary/keywords/element.py @@ -1,6 +1,5 @@ -from PuppeteerLibrary.base.librarycomponent import LibraryComponent from PuppeteerLibrary.base.robotlibcore import keyword -from PuppeteerLibrary.keywords.element_async import ElementKeywordsAsync +from PuppeteerLibrary.base.librarycomponent import LibraryComponent from PuppeteerLibrary.ikeywords.ielement_async import iElementAsync @@ -8,7 +7,6 @@ class ElementKeywords(LibraryComponent): def __init__(self, ctx): super().__init__(ctx) - self.async_func = ElementKeywordsAsync(self.ctx) def get_async_keyword_group(self) -> iElementAsync: return self.ctx.get_current_library_context().get_async_keyword_group(type(self).__name__) diff --git a/PuppeteerLibrary/keywords/element_async.py b/PuppeteerLibrary/keywords/element_async.py deleted file mode 100644 index ec3b333..0000000 --- a/PuppeteerLibrary/keywords/element_async.py +++ /dev/null @@ -1,103 +0,0 @@ -from robot.libraries.BuiltIn import BuiltIn - -from PuppeteerLibrary.base.robotlibcore import keyword -from PuppeteerLibrary.base.librarycomponent import LibraryComponent - - -class ElementKeywordsAsync(LibraryComponent): - - @keyword - async def click_element_async(self, selenium_locator): - return await self.ctx.get_current_page().click_with_selenium_locator(selenium_locator) - - @keyword - async def click_link_async(self, selenium_locator): - elements = await self.ctx.get_current_page().querySelectorAll_with_selenium_locator(selenium_locator) - for element in elements: - tag_name = (await (await element.getProperty('tagName')).jsonValue()).lower() - if tag_name == 'a': - return await element.click() - raise Exception('Not found link with specific locator ' + selenium_locator) - - @keyword - async def click_button_async(self, selenium_locator): - elements = await self.ctx.get_current_page().querySelectorAll_with_selenium_locator(selenium_locator) - for element in elements: - tag_name = (await (await element.getProperty('tagName')).jsonValue()).lower() - if tag_name == 'button': - return await element.click() - raise Exception('Not found button with specific locator ' + selenium_locator) - - @keyword - async def click_image_async(self, selenium_locator): - elements = await self.ctx.get_current_page().querySelectorAll_with_selenium_locator(selenium_locator) - for element in elements: - tag_name = (await (await element.getProperty('tagName')).jsonValue()).lower() - if tag_name == 'img': - return element.click() - raise Exception('Not found button with specific locator ' + selenium_locator) - - @keyword - async def get_text_async(self, selenium_locator): - element = await self.ctx.get_current_page().querySelector_with_selenium_locator(selenium_locator) - return (await (await element.getProperty('textContent')).jsonValue()) - - @keyword - async def get_value_async(self, selenium_locator): - element = await self.ctx.get_current_page().querySelector_with_selenium_locator(selenium_locator) - return (await (await element.getProperty('value')).jsonValue()) - - @keyword - async def element_should_be_disabled_async(self, selenium_locator): - element = await self.ctx.get_current_page().querySelector_with_selenium_locator(selenium_locator) - is_disabled = await (await element.getProperty('disabled')).jsonValue() - if not is_disabled: - raise AssertionError("Element '%s' is enabled. " % selenium_locator) - return element - - @keyword - async def element_should_be_enabled_async(self, selenium_locator): - element = await self.ctx.get_current_page().querySelector_with_selenium_locator(selenium_locator) - is_disabled = await (await element.getProperty('disabled')).jsonValue() - if is_disabled: - raise AssertionError("Element '%s' is disabled. " % selenium_locator) - return element - - @keyword - async def element_should_be_visible_async(self, selenium_locator): - try: - return await self.ctx.get_current_page().waitForSelector_with_selenium_locator(selenium_locator, 0.1, visible=True, hidden=False) - except: - raise AssertionError("Element '%s' is not be visible. " % selenium_locator) - - @keyword - async def element_should_not_be_visible_async(self, selenium_locator): - try: - return await self.ctx.get_current_page().waitForSelector_with_selenium_locator(selenium_locator, 0.1, visible=False, hidden=True) - except: - raise AssertionError("Element '%s' is visible. " % selenium_locator) - - @keyword - async def element_should_contain_async(self, selenium_locator, expected, ignore_case=False): - text = await self.get_text_async(selenium_locator) - return BuiltIn().should_contain(text, expected, ignore_case=ignore_case) - - @keyword - async def element_should_not_contain_async(self, selenium_locator, expected, ignore_case=False): - text = await self.get_text_async(selenium_locator) - return BuiltIn().should_not_contain(text, expected, ignore_case=ignore_case) - - @keyword - async def element_text_should_be_async(self, selenium_locator, expected, ignore_case=False): - text = await self.get_text_async(selenium_locator) - return BuiltIn().should_be_equal_as_strings(text, expected, ignore_case=ignore_case) - - @keyword - async def element_text_should_not_be_async(self, selenium_locator, expected, ignore_case=False): - text = await self.get_text_async(selenium_locator) - return BuiltIn().should_not_be_equal_as_strings(text, expected, ignore_case=ignore_case) - - @keyword - async def upload_file_async(self, selenium_locator, file_path): - element = await self.ctx.get_current_page().querySelector_with_selenium_locator(selenium_locator) - await element.uploadFile(file_path) diff --git a/PuppeteerLibrary/keywords/formelement.py b/PuppeteerLibrary/keywords/formelement.py index dd27165..7b4788e 100644 --- a/PuppeteerLibrary/keywords/formelement.py +++ b/PuppeteerLibrary/keywords/formelement.py @@ -1,14 +1,12 @@ -from PuppeteerLibrary.ikeywords.iformelement_async import iFormElementAsync -from PuppeteerLibrary.base.librarycomponent import LibraryComponent from PuppeteerLibrary.base.robotlibcore import keyword -from PuppeteerLibrary.keywords.formelement_async import FormElementKeywordsAsync +from PuppeteerLibrary.base.librarycomponent import LibraryComponent +from PuppeteerLibrary.ikeywords.iformelement_async import iFormElementAsync class FormElementKeywords(LibraryComponent): def __init__(self, ctx): super().__init__(ctx) - self.async_func = FormElementKeywordsAsync(self.ctx) def get_async_keyword_group(self) -> iFormElementAsync: return self.ctx.get_current_library_context().get_async_keyword_group(type(self).__name__) diff --git a/PuppeteerLibrary/keywords/formelement_async.py b/PuppeteerLibrary/keywords/formelement_async.py deleted file mode 100644 index 2441ffa..0000000 --- a/PuppeteerLibrary/keywords/formelement_async.py +++ /dev/null @@ -1,21 +0,0 @@ -from robot.api.deco import not_keyword -from PuppeteerLibrary.base.librarycomponent import LibraryComponent -from PuppeteerLibrary.base.robotlibcore import keyword - - -class FormElementKeywordsAsync(LibraryComponent): - - @keyword - async def input_text_async(self, selenium_locator, text, clear=True): - if clear: - await self._clear_input_text(selenium_locator) - await self.ctx.get_current_page().type_with_selenium_locator(selenium_locator, text) - - @keyword - async def clear_element_text_async(self, selenium_locator): - await self._clear_input_text(selenium_locator) - - @not_keyword - async def _clear_input_text(self, selenium_locator): - await self.ctx.get_current_page().click_with_selenium_locator(selenium_locator, {'clickCount': 3}) - await self.ctx.get_current_page().keyboard.press('Backspace') diff --git a/PuppeteerLibrary/keywords/javascript.py b/PuppeteerLibrary/keywords/javascript.py index 2811750..74afe19 100644 --- a/PuppeteerLibrary/keywords/javascript.py +++ b/PuppeteerLibrary/keywords/javascript.py @@ -1,7 +1,6 @@ -from PuppeteerLibrary.ikeywords.ijavascript_async import iJavascriptAsync from PuppeteerLibrary.base.robotlibcore import keyword from PuppeteerLibrary.base.librarycomponent import LibraryComponent - +from PuppeteerLibrary.ikeywords.ijavascript_async import iJavascriptAsync class JavascriptKeywords(LibraryComponent): diff --git a/PuppeteerLibrary/keywords/javascript_async.py b/PuppeteerLibrary/keywords/javascript_async.py deleted file mode 100644 index c3b75c6..0000000 --- a/PuppeteerLibrary/keywords/javascript_async.py +++ /dev/null @@ -1,12 +0,0 @@ -from PuppeteerLibrary.base.robotlibcore import keyword -from PuppeteerLibrary.base.librarycomponent import LibraryComponent - - -class JavascriptKeywordsAsync(LibraryComponent): - - def __init__(self, ctx): - self.ctx = ctx - - @keyword - async def execute_javascript_async(self, code): - return await self.ctx.get_current_page().evaluate(code) diff --git a/PuppeteerLibrary/keywords/mockresponse.py b/PuppeteerLibrary/keywords/mockresponse.py index 48759d0..d1a1ee0 100644 --- a/PuppeteerLibrary/keywords/mockresponse.py +++ b/PuppeteerLibrary/keywords/mockresponse.py @@ -1,14 +1,12 @@ from PuppeteerLibrary.ikeywords.imockresponse_async import iMockResponseAsync from PuppeteerLibrary.base.robotlibcore import keyword from PuppeteerLibrary.base.librarycomponent import LibraryComponent -from PuppeteerLibrary.keywords.mockresponse_async import MockResponseKeywordsAsync class MockResponseKeywords(LibraryComponent): def __init__(self, ctx): super().__init__(ctx) - self.async_func = MockResponseKeywordsAsync(self.ctx) def get_async_keyword_group(self) -> iMockResponseAsync: return self.ctx.get_current_library_context().get_async_keyword_group(type(self).__name__) diff --git a/PuppeteerLibrary/keywords/mockresponse_async.py b/PuppeteerLibrary/keywords/mockresponse_async.py deleted file mode 100644 index ce91f41..0000000 --- a/PuppeteerLibrary/keywords/mockresponse_async.py +++ /dev/null @@ -1,29 +0,0 @@ -import asyncio -import re -from pyppeteer.network_manager import Request -from PuppeteerLibrary.base.robotlibcore import keyword -from PuppeteerLibrary.base.librarycomponent import LibraryComponent - - -class MockResponseKeywordsAsync(LibraryComponent): - - def __init__(self, ctx): - self.ctx = ctx - - @keyword - async def mock_current_page_api_response_async(self, url, mock_response, method='GET', body=None): - page = self.ctx.get_current_page() - await page.setRequestInterception(True) - page.on('request', lambda request: - asyncio.ensure_future(self.mock_api_response(request, url, mock_response, method, body))) - - async def mock_api_response(self, request: Request, url, mock_response, method, body): - if re.search(url, request.url) is not None and request.method == method: - try: - pos_data = (await request.postData()) - except: - pos_data = '' - if body is None or re.search(body, pos_data.replace('\n', '')): - return await request.respond(mock_response) - await request.continue_() - diff --git a/PuppeteerLibrary/keywords/mouseevent.py b/PuppeteerLibrary/keywords/mouseevent.py index b79d2b3..e740af1 100644 --- a/PuppeteerLibrary/keywords/mouseevent.py +++ b/PuppeteerLibrary/keywords/mouseevent.py @@ -1,14 +1,12 @@ from PuppeteerLibrary.ikeywords.imouseevent_async import iMouseEventAsync from PuppeteerLibrary.base.robotlibcore import keyword from PuppeteerLibrary.base.librarycomponent import LibraryComponent -from PuppeteerLibrary.keywords.mouseevent_async import MouseEventKeywordsAsync class MouseEventKeywords(LibraryComponent): def __init__(self, ctx): super().__init__(ctx) - self.async_func = MouseEventKeywordsAsync(self.ctx) def get_async_keyword_group(self) -> iMouseEventAsync: return self.ctx.get_current_library_context().get_async_keyword_group(type(self).__name__) diff --git a/PuppeteerLibrary/keywords/mouseevent_async.py b/PuppeteerLibrary/keywords/mouseevent_async.py deleted file mode 100644 index 9183337..0000000 --- a/PuppeteerLibrary/keywords/mouseevent_async.py +++ /dev/null @@ -1,30 +0,0 @@ -from PuppeteerLibrary.base.robotlibcore import keyword -from PuppeteerLibrary.base.librarycomponent import LibraryComponent - - -class MouseEventKeywordsAsync(LibraryComponent): - - def __init__(self, ctx): - self.ctx = ctx - - @keyword - async def mouse_over_async(self, selenium_locator): - element = await self.ctx.get_current_page().querySelector_with_selenium_locator(selenium_locator) - await element.hover() - - @keyword - async def mouse_down_async(self, selenium_locator): - element = await self.ctx.get_current_page().querySelector_with_selenium_locator(selenium_locator) - bounding_box = await element.boundingBox() - await self.ctx.get_current_page().mouse.move( - bounding_box['x'] + bounding_box['width'] / 2, - bounding_box['y'] + bounding_box['height'] / 2) - await self.ctx.get_current_page().mouse.down() - - @keyword - async def mouse_up_async(self): - await self.ctx.get_current_page().mouse.up() - - @keyword - async def mouse_move_async(self, x, y): - await self.ctx.get_current_page().mouse.move(int(x), int(y)) diff --git a/PuppeteerLibrary/keywords/pdf.py b/PuppeteerLibrary/keywords/pdf.py index e6a9b64..bab4507 100644 --- a/PuppeteerLibrary/keywords/pdf.py +++ b/PuppeteerLibrary/keywords/pdf.py @@ -27,4 +27,3 @@ def print_as_pdf(self, filename=DEFAULT_FILENAME_PAGE): """ return self.loop.run_until_complete(self.get_async_keyword_group().print_as_pdf(filename)) - # return self.loop.run_until_complete(self.async_func.print_as_pdf_async(filename)) diff --git a/PuppeteerLibrary/keywords/pdf_async.py b/PuppeteerLibrary/keywords/pdf_async.py deleted file mode 100644 index dbd027f..0000000 --- a/PuppeteerLibrary/keywords/pdf_async.py +++ /dev/null @@ -1,38 +0,0 @@ -import os -from PuppeteerLibrary.base.robotlibcore import keyword -from PuppeteerLibrary.base.librarycomponent import LibraryComponent - - -DEFAULT_FILENAME_PAGE = 'pdf-{index}.pdf' - -class PDFKeywordsAsync(LibraryComponent): - - def __init__(self, ctx): - self.ctx = ctx - self.log_dir = os.curdir - - @keyword - async def print_as_pdf_async(self, filename): - path = self._get_pdf_path(filename) - await self.ctx.current_page.emulateMedia('screen') - await self.ctx.current_page.pdf({'path': path}) - self.info('Print as pdf: '+path) - - def _get_pdf_path(self, filename): - directory = self.log_dir - filename = filename.replace('/', os.sep) - index = 0 - while True: - index += 1 - formatted = self._format_path(filename, index) - path = os.path.join(directory, formatted) - if formatted == filename or not os.path.exists(path): - return path - - def _format_path(self, file_path, index): - return file_path.format_map(_SafeFormatter(index=index)) - -class _SafeFormatter(dict): - - def __missing__(self, key): - return '{%s}' % key diff --git a/PuppeteerLibrary/keywords/screenshot.py b/PuppeteerLibrary/keywords/screenshot.py index c65cde6..94257a3 100644 --- a/PuppeteerLibrary/keywords/screenshot.py +++ b/PuppeteerLibrary/keywords/screenshot.py @@ -2,8 +2,7 @@ from robot.utils import get_link_path from PuppeteerLibrary.base.librarycomponent import LibraryComponent from PuppeteerLibrary.base.robotlibcore import keyword -from PuppeteerLibrary.keywords.screenshot_async import ScreenshotKeywordsAsync, DEFAULT_FILENAME_PAGE -from PuppeteerLibrary.ikeywords.iscreenshot_async import iScreenshotAsync +from PuppeteerLibrary.ikeywords.iscreenshot_async import DEFAULT_FILENAME_PAGE, iScreenshotAsync class ScreenshotKeywords(LibraryComponent): @@ -11,7 +10,6 @@ class ScreenshotKeywords(LibraryComponent): def __init__(self, ctx): super().__init__(ctx) self.log_dir = os.curdir - self.async_func = ScreenshotKeywordsAsync(self.ctx) def get_async_keyword_group(self) -> iScreenshotAsync: return self.ctx.get_current_library_context().get_async_keyword_group(type(self).__name__) diff --git a/PuppeteerLibrary/keywords/screenshot_async.py b/PuppeteerLibrary/keywords/screenshot_async.py deleted file mode 100644 index d097e67..0000000 --- a/PuppeteerLibrary/keywords/screenshot_async.py +++ /dev/null @@ -1,44 +0,0 @@ -import os -from robot.utils import get_link_path -from PuppeteerLibrary.base.robotlibcore import keyword -from PuppeteerLibrary.base.librarycomponent import LibraryComponent - -DEFAULT_FILENAME_PAGE = 'puppeteer-screenshot-{index}.png' - -class ScreenshotKeywordsAsync(LibraryComponent): - - def __init__(self, ctx): - self.ctx = ctx - self.log_dir = os.curdir - - @keyword - async def capture_page_screenshot_async(self, filename=DEFAULT_FILENAME_PAGE): - path = self._get_screenshot_path(filename) - await self.ctx.current_page.screenshot({'path': path}) - self._embed_to_log_as_file(path, 800) - - def _get_screenshot_path(self, filename): - directory = self.log_dir - filename = filename.replace('/', os.sep) - index = 0 - while True: - index += 1 - formatted = self._format_path(filename, index) - path = os.path.join(directory, formatted) - if formatted == filename or not os.path.exists(path): - return path - - def _format_path(self, file_path, index): - return file_path.format_map(_SafeFormatter(index=index)) - - def _embed_to_log_as_file(self, path, width): - # Image is shown on its own row and thus previous row is closed on - # purpose. Depending on Robot's log structure is a bit risky. - self.info('' - '' - .format(src=get_link_path(path, self.log_dir), width=width), html=True) - -class _SafeFormatter(dict): - - def __missing__(self, key): - return '{%s}' % key diff --git a/PuppeteerLibrary/keywords/utility.py b/PuppeteerLibrary/keywords/utility.py index a47fad3..cef1e11 100644 --- a/PuppeteerLibrary/keywords/utility.py +++ b/PuppeteerLibrary/keywords/utility.py @@ -87,7 +87,6 @@ def run_async_keywords(self, *keywords): | ... | Wait for response url | ${HOME_PAGE_URL}/home.html | | """ - self.ctx.load_async_keywords() run_keyword = _RunKeyword() return self.loop.run_until_complete( self._new_run_async_keywords(run_keyword._split_run_keywords(list(keywords))) ) diff --git a/PuppeteerLibrary/keywords/waiting.py b/PuppeteerLibrary/keywords/waiting.py index c473e3b..ddcc951 100644 --- a/PuppeteerLibrary/keywords/waiting.py +++ b/PuppeteerLibrary/keywords/waiting.py @@ -1,14 +1,12 @@ +from PuppeteerLibrary.base.robotlibcore import keyword from PuppeteerLibrary.ikeywords.iwaiting_async import iWaitingAsync -from PuppeteerLibrary.keywords.waiting_async import WaitingKeywordsAsync from PuppeteerLibrary.base.librarycomponent import LibraryComponent -from PuppeteerLibrary.base.robotlibcore import keyword class WaitingKeywords(LibraryComponent): def __init__(self, ctx): super().__init__(ctx) - self.async_func = WaitingKeywordsAsync(self.ctx) def get_async_keyword_group(self) -> iWaitingAsync: return self.ctx.get_current_library_context().get_async_keyword_group(type(self).__name__) diff --git a/PuppeteerLibrary/keywords/waiting_async.py b/PuppeteerLibrary/keywords/waiting_async.py deleted file mode 100644 index 967709f..0000000 --- a/PuppeteerLibrary/keywords/waiting_async.py +++ /dev/null @@ -1,180 +0,0 @@ -import asyncio -import time -import re -from robot.utils import DotDict -from PuppeteerLibrary.base.librarycomponent import LibraryComponent -from PuppeteerLibrary.base.robotlibcore import keyword - - -class WaitingKeywordsAsync(LibraryComponent): - - @keyword - async def wait_for_request_url_async(self, url, method='GET', body=None, timeout=None): - req = await self.ctx.get_current_page().waitForRequest( - lambda req: re.search(url, req.url) is not None - and req.method == method - , options={ - 'timeout': self.timestr_to_secs_for_default_timeout(timeout) * 1000 - }) - - try: - pos_data = (await req.postData()) - except: - pos_data = '' - - if body is None or re.search(body, pos_data.replace('\n', '')): - log_str = 'Wait for request url: '+req.method+' - '+req.url - if pos_data != '': - log_str + '\n' + pos_data - self.info(log_str) - else: - raise Exception('Can\'t match request body with ' + body + ' \n ' + pos_data) - - return DotDict({ - 'url': req.url, - 'method': req.method, - 'body': pos_data - }) - - @keyword - async def wait_for_response_url_async(self, url, status=200, body=None, timeout=None): - res = await self.ctx.get_current_page().waitForResponse( - lambda res: re.search(url, res.url) is not None - and res.status == int(status) - , options={ - 'timeout': self.timestr_to_secs_for_default_timeout(timeout) * 1000 - }) - try: - res_text = (await res.text()) - except: - res_text = '' - if body is None or re.search(body, res_text.replace('\n','')): - log_str = 'Wait for request url: ' + res.url - if res_text != '': - log_str += '\n' + res_text - self.info(log_str) - else: - raise Exception('Can\'t match response body with '+body+' \n '+res_text) - return DotDict({ - 'url': res.url, - 'status': res.status, - 'body': res_text - }) - - @keyword - async def wait_for_navigation_async(self, timeout=None): - await self.ctx.get_current_page().waitForNavigation(options={ - 'timeout': self.timestr_to_secs_for_default_timeout(timeout) * 1000 - }) - - @keyword - async def wait_for_selenium_selector(self, selenium_locator, timeout=None, visible=False, hidden=False): - timeout = self.timestr_to_secs_for_default_timeout(timeout) - return await self.ctx.get_current_page().waitForSelector_with_selenium_locator(selenium_locator, timeout, visible, hidden) - - @keyword - async def wait_until_page_contains_element_async(self, selenium_locator, timeout=None): - return await self.wait_for_selenium_selector(selenium_locator, timeout, visible=False, hidden=False) - - @keyword - async def wait_until_element_is_hidden_async(self, locator, timeout=None): - return await self.wait_for_selenium_selector(locator, timeout, visible=False, hidden=True) - - @keyword - async def wait_until_element_is_visible_async(self, locator, timeout=None): - return await self.wait_for_selenium_selector(locator, timeout, visible=True, hidden=False) - - @keyword - async def wait_until_page_contains_async(self, text, timeout=None): - locator = "xpath://*[contains(., %s)]" % self.escape_xpath_value(text) - return await self.wait_for_selenium_selector(locator, timeout) - - @keyword - async def wait_until_page_does_not_contains_async(self, text, timeout=None): - locator = "xpath://*[contains(., %s)]" % self.escape_xpath_value(text) - return await self.wait_for_selenium_selector(locator, timeout, visible=False, hidden=True) - - @keyword - async def wait_until_element_contains_async(self, selenium_locator, text, timeout=None): - async def validate_element_contains_text(): - return (text in (await (await ( await self.ctx.get_current_page().querySelector_with_selenium_locator(selenium_locator)).getProperty('textContent')).jsonValue())) - return await self._wait_until_worker( - validate_element_contains_text, - self.timestr_to_secs_for_default_timeout(timeout)) - - @keyword - async def wait_until_element_does_not_contains_async(self, selenium_locator, text, timeout=None): - async def validate_element_contains_text(): - return (text not in (await (await ( await self.ctx.get_current_page().querySelector_with_selenium_locator(selenium_locator)).getProperty('textContent')).jsonValue())) - return await self._wait_until_worker( - validate_element_contains_text, - self.timestr_to_secs_for_default_timeout(timeout)) - - @keyword - async def wait_until_location_contains_async(self, expected, timeout=None): - async def validate_url_contains_text(): - return expected in self.ctx.get_current_page().url - return await self._wait_until_worker( - validate_url_contains_text, - self.timestr_to_secs_for_default_timeout(timeout)) - - @keyword - async def wait_until_location_does_not_contains_async(self, expected, timeout=None): - async def validate_url_not_contains_text(): - return expected not in self.ctx.get_current_page().url - return await self._wait_until_worker( - validate_url_not_contains_text, - self.timestr_to_secs_for_default_timeout(timeout)) - - @keyword - async def wait_until_element_is_enabled_async(self, selenium_locator, timeout=None): - async def validate_is_enabled(): - element = await self.ctx.get_current_page().querySelector_with_selenium_locator(selenium_locator) - is_disabled = await (await element.getProperty('disabled')).jsonValue() - return is_disabled == False - return await self._wait_until_worker( - validate_is_enabled, - self.timestr_to_secs_for_default_timeout(timeout), - 'Element '+selenium_locator+' was not enabled.') - - @keyword - async def wait_until_element_finished_animating_async(self, selenium_locator, timeout=None): - prev_rect_tmp = { 'value': None } - async def check_finished_animating(): - element = await self.ctx.get_current_page().querySelector_with_selenium_locator(selenium_locator) - if prev_rect_tmp['value'] is None: - prev_rect_tmp['value'] = await element.boundingBox() - return False - prev_rect = prev_rect_tmp['value'] - next_rect = await element.boundingBox() - if next_rect['x'] == prev_rect['x'] and next_rect['y'] == prev_rect['y']: - return True - else: - prev_rect_tmp['value'] = next_rect - return False - return await self._wait_until_worker( - check_finished_animating, - self.timestr_to_secs_for_default_timeout(timeout), - 'Element '+selenium_locator+' was not enabled.') - - async def _wait_until_worker(self, condition, timeout, error=None): - max_time = time.time() + timeout - not_found = None - while time.time() < max_time: - try: - if await condition(): - return - else: - not_found = None - except Exception as err: - not_found = err - await asyncio.sleep(0.2) - raise AssertionError(not_found or error) - - def escape_xpath_value(self, value): - if '"' in value and '\'' in value: - parts_wo_apos = value.split('\'') - return "concat('%s')" % "', \"'\", '".join(parts_wo_apos) - if '\'' in value: - return "\"%s\"" % value - return "'%s'" % value From d2a4d6dd3db322855af71d620b44332df25998ce Mon Sep 17 00:00:00 2001 From: atthaboons Date: Sat, 31 Oct 2020 20:31:49 +0700 Subject: [PATCH 103/103] Clean up scripts --- Examples/browser-management/emulator-mode.robot | 1 + 1 file changed, 1 insertion(+) diff --git a/Examples/browser-management/emulator-mode.robot b/Examples/browser-management/emulator-mode.robot index 729f5ba..33e1614 100644 --- a/Examples/browser-management/emulator-mode.robot +++ b/Examples/browser-management/emulator-mode.robot @@ -8,6 +8,7 @@ ${DEFAULT_BROWSER} chrome *** Test Cases *** Example enable emulator mode + [Tags] Ignore_firefox [Teardown] Close All Browser ${BROWSER} = Get variable value ${BROWSER} ${DEFAULT_BROWSER} ${HEADLESS} = Get variable value ${HEADLESS} ${False}