playwright-python icon indicating copy to clipboard operation
playwright-python copied to clipboard

[Question] : the "on" function of Page object works for some events but not for others

Open GunjanSheth opened this issue 3 years ago • 2 comments

I was trying to perform 3 things using Playwright with python.

  1. Handle a Dialog
  2. Handle File Download / Upload
  3. Handle a new Window

For Handling a Dialog I can across the following Page Event Dialog

Dialog Opening App The following was my code and it worked well

TestBase.get_page().goto("https://the-internet.herokuapp.com/context_menu")
box = TestBase.get_page().locator("#hot-spot")

def handle_alert_custom(dialog: Dialog):
    print("Your Alert Message is : ", dialog.message)
    # waiting for 2 seconds so you can see the Alert on UI
    time.sleep(2)
    # now you can accept or reject the dialog
    dialog.accept()
    # dialog.dismiss()


TestBase.get_page().on("dialog", handle_alert_custom)

box.click(button='right')
time.sleep(2)
TestBase.get_page().close()

I tried to do something similar for File Download / Upload assuming that will work File Download & File Upload

and also similar for Handling a New Window New Window

for each of the above things i added something like Page.on("download", handle_download) #where handle_download is a valid function Page.on("popup", handle_popup) # where handle_popup is a valid function

but some how i did not work the way I handled the Dialog.

I did found a work around using the following

with TestBase.get_page().expect_download() as download_info:
    download_link.click()
    download_info.value.save_as("theFileYouWant.json")

&

with TestBase.get_page().expect_event("popup") as pop:
    click_here.click()
    new_page = pop.value
    print(new_page.locator("h3").text_content())
    new_page.close()

but why does it not work when i try to put up with the "on" and use appropriate event ?

for my examples i used Multi window & File download

Can someone please tell me what is going on with Page."on" function and Page."expect_event" function

Thanks

GunjanSheth avatar Sep 19 '22 09:09 GunjanSheth

For the cases that aren't working, can you include a minimal script that we can run cleanly/directly. Please explain/paste the output/error you see as well as what you expect to happen.

I'm mostly following your above description, but want to make sure we're working through the same code/issue. Thanks!

rwoll avatar Sep 19 '22 20:09 rwoll

Sure @rwoll

the lib.test_base.py module

from playwright.sync_api import Browser, Page, sync_playwright


class TestBase:
    __browser: Browser = None
    __page: Page = None

    @staticmethod
    def get_browser():
        if TestBase.__browser is None or not(TestBase.__browser.is_connected()):
            TestBase.__browser = sync_playwright().start().chromium.launch(headless=False, channel='chrome', slow_mo=100)
        return TestBase.__browser


    @staticmethod
    def get_page():
        if TestBase.__page is None or (TestBase.__page.is_closed()):
            TestBase.__page = TestBase.get_browser().new_page()
        return TestBase.__page

the downloading_file.py module

import time
from playwright.sync_api import Download
from lib.test_base import TestBase

url = "https://the-internet.herokuapp.com/download"

def handle_download(download: Download):
    time.sleep(1)
    print(f"The file was downloaded at : {download.path()}")
    download.save_as("your_text_file.txt")
    time.sleep(1)

TestBase.get_page().goto(url)
TestBase.get_page().on("download", handle_download)
download_link = TestBase.get_page().locator("xpath=//a[text()='text.txt']")

time.sleep(1)
download_link.click()
time.sleep(1)

the multi_window.py module

import time
from lib.test_base import TestBase

url = "https://the-internet.herokuapp.com/windows"

def handle_pop(pop):
    print(f"New Page Title {pop.title()}")

TestBase.get_page().on("popup", handle_pop)
TestBase.get_page().goto(url)

click_here = TestBase.get_page().locator("a", has_text="Click Here")
click_here.click()

GunjanSheth avatar Sep 20 '22 06:09 GunjanSheth

The following example shows the popup handler firing:

import sys

from playwright.sync_api import Playwright, sync_playwright, expect
def run(playwright: Playwright) -> None:
    browser = playwright.chromium.launch()
    context = browser.new_context()
    page = context.new_page()
    page.goto("https://the-internet.herokuapp.com/windows")

    page.locator("text=Click Here").click()
    waiting_for_popup = True
    def exit_on_popup():
      print("found a popup!")
      nonlocal waiting_for_popup
      waiting_for_popup = False

    page.on("popup", exit_on_popup)
    while waiting_for_popup:
      page.wait_for_timeout(100)  
        
    context.close()
    browser.close()
with sync_playwright() as playwright:
    run(playwright)

and here's it using Playwright's actual expect APIs:

from playwright.sync_api import Playwright, sync_playwright, expect
def run(playwright: Playwright) -> None:
    browser = playwright.chromium.launch()
    context = browser.new_context()
    page = context.new_page()
    page.goto("https://the-internet.herokuapp.com/windows")
    with page.expect_popup() as popup_info:
        page.locator("text=Click Here").click()
    popup = popup_info.value
    expect(popup).to_have_url('https://the-internet.herokuapp.com/windows/new')
    
    context.close()
    browser.close()
with sync_playwright() as playwright:
    run(playwright)

I suggest you change your code so you remove all uses of sleeps (or if you must have them as a last resort, use page.wait_for_timeout instead), and instead use the expect event pattern from the second script above:

    with page.expect_popup() as popup_info:
        page.locator("text=Click Here").click()
    popup = popup_info.value

Your use of sleeps is likely causing you issues in either exiting too soon or otherwise interrupting the flow.

rwoll avatar Sep 22 '22 23:09 rwoll