Search code examples
cypress

Cypress: How to show a PDF and continue the test?


Before you read any further: It turned out that my problem was specific to the Cypress version I was using. That page load timeout on PDFs does not happen with Cypress 14, but did with those before (I tried 13.17.0, 13.16.1, 13.15.2, 13.14.2).

I will reopen the question in order to provide the correct solution.


First of all:

  • This is not about parsing PDF, it is about visual feedback.
  • This is not about building web pages to display PDF. (Now I added "Cypress" to the title. Hope this helps a little.)
  • So this is not a duplicate.

This is about showing a PDF during a Cypress test, just for visual feedback. So please stop the close requests and actually start reading.

I am testing a web app which at some point produces a PDF. I know Cypress is not much about PDFs, but you can do cy.request(x).then(pdfContent => and then examine the content (e.g. using some PDF library such as pdfjs-dist). But please remember, parsing is not what this question is about.

While the examination of the PDF happens, I would like the user to actually see the PDF in the browser (both in open mode but also for run in error screenshots and in the video). So if the test e.g. does not find a certain string on the first page, this can be somewhat verified visually by users.

Now the problem is:

  • If I actually cy.visit the PDF, I get an error, because Cypress expects content-type: 'text/html' and not application/pdf.
  • If I let Cypress click on the link, the PDF is shown, but I get a Timed out error, I guess because loading of the PDF does not trigger some page load event like a web page. I tried to trick around by kind of catching be error like in following code. I can see that on("fail" matches (because it looks different during the test, and also the test gets a green ✓) but the error still stops the test (which is also stated it the docs):
let pdfUrl = ""
cy.get(pdfSelector).as("pdfLink").invoke("attr", "target", "").invoke("attr", "href").then((href) => {
  pdfUrl = href
}).then(() => {
  Cypress.config("pageLoadTimeout", 500)
  Cypress.on("fail", () => {
    cy.request(pdfUrl).then(pdfContent => cy.log("FIXME never happens"))
  })
  cy.get("@pdfLink").click()
  cy.request(pdfUrl).then(pdfContent => cy.log("FIXME never happens"))
})

enter image description here

How can I do better?

Edit: As requested, here comes some detail about the page which contains the link. It is generated by MailDev and contains a simple link:

<a target="" ng-href="foo.pdf" href="foo.pdf">
  <strong class="ng-binding">foo.pdf</strong>
</a>

This is how Cypress shows it after "_blank" is removed from target (see code above). I don't see how this might help, but who knows. Again: This is not about parsing. The parsing works fine (as long as I don't try to show the PDF while parsing it).


Solution

  • I ran the example DOM you gave:

    <a href="foo.pdf" target="_blank">Link to PDF</href>
    

    against a very simple PDF from w3c and it opened ok. The target="_blank" part opens a new tab, but if you want to open in the same tab you can do so by removing the target attribute.

    cy.get('a')
      .invoke('removeAttr', 'target')
      .click()
    

    enter image description here

    Either the pdf itself is causing the issue, or there is more to the web page that we need for a reproducible example.

    Both my app and pdf are localhost domain - you may need an origin command if the domains differ.