From 732654dafa828ccb099facb79954b41254809064 Mon Sep 17 00:00:00 2001 From: Thalison Fernandes Date: Sun, 8 Dec 2024 21:57:02 -0300 Subject: [PATCH 1/7] feat: add support for handling JavaScript dialog opening events --- pydoll/connection.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pydoll/connection.py b/pydoll/connection.py index dd17a3c3..f0c6870b 100644 --- a/pydoll/connection.py +++ b/pydoll/connection.py @@ -38,6 +38,7 @@ def __init__(self, connection_port: int, page_id: str = 'browser'): self._callback_id = 0 self._pending_commands: dict[int, asyncio.Future] = {} self.network_logs = [] + self.dialog = {} logger.info('ConnectionHandler initialized.') @property @@ -228,6 +229,9 @@ async def _handle_event(self, event: dict): self.network_logs.append(event) self.network_logs = self.network_logs[-10000:] + if 'Page.javascriptDialogOpening' in event_name: + self.dialog = event + event_callbacks = self._event_callbacks.copy() for callback_id, callback_data in event_callbacks.items(): if callback_data['event'] == event_name: From 863a2a0bf2d146332c0692fe7f3dd787b1133718 Mon Sep 17 00:00:00 2001 From: Thalison Fernandes Date: Sun, 8 Dec 2024 21:57:31 -0300 Subject: [PATCH 2/7] feat: add dialog handling methods to Page class This commit adds new methods to the Page class in the pydoll/browser/page.py file. The methods added are: - `has_dialog()`: Checks if a dialog is present on the page. - `get_dialog_message()`: Retrieves the message of the dialog on the page. - `accept_dialog()`: Accepts the dialog on the page. These methods provide functionality to interact with dialogs in the browser page. --- pydoll/browser/page.py | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/pydoll/browser/page.py b/pydoll/browser/page.py index 4f29e28b..b45ae59a 100644 --- a/pydoll/browser/page.py +++ b/pydoll/browser/page.py @@ -126,6 +126,40 @@ async def delete_all_cookies(self): await self._execute_command(StorageCommands.clear_cookies()) await self._execute_command(NetworkCommands.clear_browser_cookies()) + async def has_dialog(self) -> bool: + """ + Checks if a dialog is present on the page. + + Returns: + bool: True if a dialog is present, False otherwise. + """ + if self._connection_handler.dialog: + return True + return False + + async def get_dialog_message(self) -> str: + """ + Retrieves the message of the dialog on the page. + + Returns: + str: The message of the dialog. + """ + if not await self.has_dialog(): + raise LookupError('No dialog present on the page') + return self._connection_handler.dialog['message'] + + async def accept_dialog(self): + """ + Accepts the dialog on the page. + + Raises: + LookupError: If no dialog is present on the page. + """ + if not await self.has_dialog(): + raise LookupError('No dialog present on the page') + await self._execute_command(PageCommands.handle_dialog(True)) + self._connection_handler.dialog = {} + async def go_to(self, url: str, timeout=300): """ Navigates to a URL in the page. From 24c64d59b413ba2a1bb849e4053a82aaa734b818 Mon Sep 17 00:00:00 2001 From: Thalison Fernandes Date: Sun, 8 Dec 2024 21:58:37 -0300 Subject: [PATCH 3/7] feat: add handle_dialog method to PageCommands class --- pydoll/commands/page.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/pydoll/commands/page.py b/pydoll/commands/page.py index 5256dd11..793d993f 100644 --- a/pydoll/commands/page.py +++ b/pydoll/commands/page.py @@ -30,7 +30,27 @@ class PageCommands: 'method': 'Page.setDownloadBehavior', 'params': {}, } + HANDLE_DIALOG = {'method': 'Page.handleJavaScriptDialog', 'params': {}} + + @classmethod + def handle_dialog(cls, accept: bool = True) -> dict: + """ + Generates the command to handle a JavaScript dialog. + + Args: + accept (bool): Whether to accept the dialog. + If True, the dialog will be accepted. + If False, the dialog will be dismissed. + + Returns: + dict: The command to be sent to the browser, + containing the method and parameters for handling the dialog. + """ + command = cls.HANDLE_DIALOG.copy() + command['params']['accept'] = accept + return command + @classmethod def set_download_path(cls, path: str) -> dict: """ From 0cdd60e027edbf9b46769c0338ed821ff4b6faa1 Mon Sep 17 00:00:00 2001 From: Thalison Fernandes Date: Sun, 8 Dec 2024 22:00:44 -0300 Subject: [PATCH 4/7] refactor: run ruff formatter to ensure code consistency --- pydoll/browser/page.py | 6 +++--- pydoll/commands/page.py | 3 +-- pydoll/connection.py | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/pydoll/browser/page.py b/pydoll/browser/page.py index b45ae59a..dbc90de6 100644 --- a/pydoll/browser/page.py +++ b/pydoll/browser/page.py @@ -136,7 +136,7 @@ async def has_dialog(self) -> bool: if self._connection_handler.dialog: return True return False - + async def get_dialog_message(self) -> str: """ Retrieves the message of the dialog on the page. @@ -147,7 +147,7 @@ async def get_dialog_message(self) -> str: if not await self.has_dialog(): raise LookupError('No dialog present on the page') return self._connection_handler.dialog['message'] - + async def accept_dialog(self): """ Accepts the dialog on the page. @@ -159,7 +159,7 @@ async def accept_dialog(self): raise LookupError('No dialog present on the page') await self._execute_command(PageCommands.handle_dialog(True)) self._connection_handler.dialog = {} - + async def go_to(self, url: str, timeout=300): """ Navigates to a URL in the page. diff --git a/pydoll/commands/page.py b/pydoll/commands/page.py index 793d993f..6e0ad433 100644 --- a/pydoll/commands/page.py +++ b/pydoll/commands/page.py @@ -32,7 +32,6 @@ class PageCommands: } HANDLE_DIALOG = {'method': 'Page.handleJavaScriptDialog', 'params': {}} - @classmethod def handle_dialog(cls, accept: bool = True) -> dict: """ @@ -50,7 +49,7 @@ def handle_dialog(cls, accept: bool = True) -> dict: command = cls.HANDLE_DIALOG.copy() command['params']['accept'] = accept return command - + @classmethod def set_download_path(cls, path: str) -> dict: """ diff --git a/pydoll/connection.py b/pydoll/connection.py index f0c6870b..6b318415 100644 --- a/pydoll/connection.py +++ b/pydoll/connection.py @@ -231,7 +231,7 @@ async def _handle_event(self, event: dict): if 'Page.javascriptDialogOpening' in event_name: self.dialog = event - + event_callbacks = self._event_callbacks.copy() for callback_id, callback_data in event_callbacks.items(): if callback_data['event'] == event_name: From 9704fbf04548338421e55e669b388f2e0e1d6394 Mon Sep 17 00:00:00 2001 From: Thalison Fernandes Date: Sun, 8 Dec 2024 22:03:48 -0300 Subject: [PATCH 5/7] feat: autoremove dialog from connection_handler when closed --- pydoll/browser/page.py | 1 - pydoll/connection.py | 3 +++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/pydoll/browser/page.py b/pydoll/browser/page.py index dbc90de6..89763d97 100644 --- a/pydoll/browser/page.py +++ b/pydoll/browser/page.py @@ -158,7 +158,6 @@ async def accept_dialog(self): if not await self.has_dialog(): raise LookupError('No dialog present on the page') await self._execute_command(PageCommands.handle_dialog(True)) - self._connection_handler.dialog = {} async def go_to(self, url: str, timeout=300): """ diff --git a/pydoll/connection.py b/pydoll/connection.py index 6b318415..447c4f71 100644 --- a/pydoll/connection.py +++ b/pydoll/connection.py @@ -231,6 +231,9 @@ async def _handle_event(self, event: dict): if 'Page.javascriptDialogOpening' in event_name: self.dialog = event + + if 'Page.javascriptDialogClosed' in event_name: + self.dialog = {} event_callbacks = self._event_callbacks.copy() for callback_id, callback_data in event_callbacks.items(): From fdf1d4251303feaf0c0dde3370f63b761e5c6fe1 Mon Sep 17 00:00:00 2001 From: Thalison Fernandes Date: Sun, 8 Dec 2024 22:05:13 -0300 Subject: [PATCH 6/7] refactor: run ruff formatter to ensure code consistency --- pydoll/connection.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pydoll/connection.py b/pydoll/connection.py index 447c4f71..55f2dc03 100644 --- a/pydoll/connection.py +++ b/pydoll/connection.py @@ -231,7 +231,7 @@ async def _handle_event(self, event: dict): if 'Page.javascriptDialogOpening' in event_name: self.dialog = event - + if 'Page.javascriptDialogClosed' in event_name: self.dialog = {} From f98555aa7a4f5599285e7a34b545b9642351408f Mon Sep 17 00:00:00 2001 From: Thalison Fernandes Date: Mon, 9 Dec 2024 09:14:35 -0300 Subject: [PATCH 7/7] fix: index error on method get_dialog_message --- pydoll/browser/page.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pydoll/browser/page.py b/pydoll/browser/page.py index 89763d97..185c9396 100644 --- a/pydoll/browser/page.py +++ b/pydoll/browser/page.py @@ -146,7 +146,7 @@ async def get_dialog_message(self) -> str: """ if not await self.has_dialog(): raise LookupError('No dialog present on the page') - return self._connection_handler.dialog['message'] + return self._connection_handler.dialog['params']['message'] async def accept_dialog(self): """