Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] Make PDF testing idiomatic #7822

Open
mxschmitt opened this issue Jul 23, 2021 · 11 comments
Open

[Feature] Make PDF testing idiomatic #7822

mxschmitt opened this issue Jul 23, 2021 · 11 comments

Comments

@mxschmitt
Copy link
Member

mxschmitt commented Jul 23, 2021

Customers are confused, when a PDF results in a PDF viewer and when in a download event. We should explain how to workaround it in the relevant browsers.

To make it work out of the box the following changes are required:

Workaround for Chromium for now:

  await page.route('**/empty.pdf', async route => {
    const response = await route.fetch()
    await route.fulfill({
      response,
      headers: {
        ...response.headers(),
        'Content-Disposition': 'attachment',
      }
    });
  });
@corradin
Copy link

@mxschmitt Did you also take a look at the solution I proposed in case people are not able to change the source code of the application under test? #6342 (comment)

This uses the download event for headless chrome and the page event for all other browsers that use the integrated PDF reader.

@mxschmitt
Copy link
Member Author

@corradin yes I've seen that. Creative solution! Question from our side, what in your opinion gets mostly asserted / tested when working with PDF files?

waitForResponse() seems working in all the cases but it seems important to assert the suggested file name?

@rwoll
Copy link
Member

rwoll commented Oct 6, 2021

I'd love an option on context, like disableNativePDFViewer, to get all the browser to behave the same (including headless v. headful). This has tripped us up a couple times, and right now the best option (IMO), is persistent context with PDF viewer disabled in chrome prefs file, but it would be nice if could be done with a simpler flag in PW API (or even just a command line switch for CR).

Thanks!

@corradin
Copy link

corradin commented Oct 7, 2021

@mxschmitt. Not sure, I would like to assert that the stream a user gets back is of type pdf. File name does not matter. In my case the file name is autogenerated so I could not do an exact match either way.

@dgozman dgozman removed the docs label Feb 8, 2022
@VinayKumarBM
Copy link

Can we expect a simpler solution to PDF Viewer issue any time soon?

@WahyuS002
Copy link

I think there is a typo in the highlighted text below. I think it should say "headed" instead of "headless."

image

@mandras73
Copy link

Do you have a python version of the workaround?

@vincenzo-gasparo
Copy link
Contributor

Here's a python version of the workaround:

import re
from playwright.sync_api import Page, expect


def test_download_pdf(page: Page):
    page.goto("https://www.example.com")

    def handle_pdf(route):
        response = page.context.request.get(route.request)
        route.fulfill(
            response,
            headers={**response.headers, "Content-Disposition": "attachment"},
        )

    page.route(re.compile(r".*\.pdf"), lambda route: handle_pdf(route))

    with page.expect_download() as download_info:
        page.get_by_text("click_here_to_download_pdf").click()

@kinopop
Copy link

kinopop commented Apr 12, 2024

Here's a python version of the workaround:

import re
from playwright.sync_api import Page, expect


def test_download_pdf(page: Page):
    page.goto("https://www.example.com")

    def handle_pdf(route):
        response = page.context.request.get(route.request)
        route.fulfill(
            response,
            headers={**response.headers, "Content-Disposition": "attachment"},
        )

    page.route(re.compile(r".*\.pdf"), lambda route: handle_pdf(route))

    with page.expect_download() as download_info:
        page.get_by_text("click_here_to_download_pdf").click()

What plug-ins do I lack?

        response,

error 1 argument

        response=response,

is that true?
my error :waiting for event " download"

@beegotsy
Copy link

The answer from @vincenzo-gasparo only works if the HTTP method is GET, also it always removes the filename, even if present.

This solution should work for any use case:

from playwright.sync_api import Route, Request # or from async_api

def override_content_disposition_handler(route: Route, request: Request) -> None:
    response = route.fetch() # performs the request
    overridden_headers = {
        **response.headers,
        "content-disposition": response.headers.get('content-disposition', 'attachment').replace('inline', 'attachment')
    }
    route.fulfill(response=response, headers=overridden_headers)

If you need to modify request method, headers or payload use route.continue_(...).

Also, there is no need to wrap the method in a lambda:

page.route("**/*.pdf", handler=override_content_disposition_handler)

@cobaltautomationdev
Copy link

@beegotsy
I have implemented a feature in my code that triggers a Chrome PDF preview popup when a specific button labeled "PO Print for Vendor" is clicked. Upon inspecting the elements within this popup, I found that there is limited interaction available; the primary options are to save the document as a PDF or print it.

async with page.expect_popup() as popup_info:
            await page.locator("#quick-process").get_by_text("PO Print for Vendor").click()
popup_page = await popup_info.value

To automate the process of saving the PDF, I attempted to invoke the print function using evaluate on the popup page object, like so:
await popup_page.evaluate('''() => {window.print();}''')

This approach successfully triggers the print dialog, which includes an option to save the document as a PDF. However, this method requires manual intervention to input a filename and confirm the save action, which prevents the automation from completing without user input.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests