Cypress can’t directly "verify" a PDF download in the way you might think, because it operates in the browser and doesn’t have direct access to the file system.
Let’s see what happens when a user triggers a PDF download in a typical web application and how Cypress can interact with that flow.
Imagine a simple web page with a button that, when clicked, initiates a PDF download.
<!DOCTYPE html>
<html>
<head>
<title>PDF Download Test</title>
</head>
<body>
<h1>Download Report</h1>
<button id="downloadButton">Download PDF</button>
<script>
document.getElementById('downloadButton').addEventListener('click', () => {
// In a real app, this would fetch data and generate a PDF
// For demonstration, we simulate a download link
const link = document.createElement('a');
link.href = '/path/to/your/example.pdf'; // Replace with a real PDF path or data URL
link.download = 'report.pdf';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
});
</script>
</body>
</html>
When you click the "Download PDF" button, the browser typically handles the download. Cypress, running in its own browser instance, observes this. The key is that Cypress doesn’t "see" the file itself. Instead, it sees the network request that leads to the download.
Here’s how you’d test this in Cypress:
describe('PDF Download Test', () => {
it('should initiate a PDF download', () => {
cy.visit('/your-page-with-download-button.html'); // Replace with your page URL
// Intercept the network request that triggers the download
cy.intercept('GET', '**/example.pdf').as('downloadRequest'); // Adjust the URL pattern
// Click the button that initiates the download
cy.get('#downloadButton').click();
// Wait for the download request to complete
cy.wait('@downloadRequest').then((interception) => {
// Check the response headers to verify it's a PDF
expect(interception.response.headers['content-type']).to.include('application/pdf');
expect(interception.response.headers['content-disposition']).to.include('attachment; filename="report.pdf"'); // Optional: check filename
// You can also check the response body if it's a data URL or small enough
// For large files or direct downloads, this is less feasible.
// expect(interception.response.body).to.exist;
});
// Important: Cypress doesn't *download* the file to your test runner's filesystem.
// It only observes the network traffic. You cannot directly assert on the
// content of the downloaded file using standard Cypress commands.
// To truly verify PDF content, you'd need an external tool or a different approach:
// 1. If the PDF content is generated dynamically and returned as JSON/data,
// you can assert on that data *before* it's converted to PDF.
// 2. If the PDF is generated on the server and linked, you could potentially
// use Node.js modules within Cypress's plugins file to fetch and parse the PDF.
// This is more complex and often overkill.
// 3. A simpler approach for verifying *that* a download happened is to check
// the network response headers as shown above.
});
});
The core idea is to intercept the network request that the browser makes when the download is initiated. By inspecting the response.headers of that intercepted request, you can confirm that the server is sending back a PDF. The content-type header should be application/pdf, and the content-disposition header often indicates an attachment and the filename.
This verification is indirect. You’re not opening the PDF and reading its text. You’re trusting that if the browser receives a response with the correct content-type and content-disposition headers, it will correctly initiate a PDF download.
The most surprising truth about verifying PDF downloads in Cypress is that you’re not verifying the content of the PDF itself, but rather the network transaction that results in a PDF download. Cypress is a browser automation tool, and the downloaded file lands on the user’s (or your test’s browser instance’s) file system, which Cypress doesn’t have direct access to.
To truly assert on the content of a downloaded PDF (e.g., checking specific text within the PDF), you’d typically need to:
- Store the PDF: Have your Cypress test (or a separate script) download the PDF file to a known location on your CI/CD runner or local machine.
- Use a PDF Parsing Library: Employ a Node.js library (like
pdf-parse) within your Cypress test’ssupportfile orpluginsfile to read and parse the PDF content from the downloaded file. - Make Assertions: Once parsed, you can assert on the extracted text.
This involves a more complex setup, often requiring you to manage file paths and external dependencies for PDF parsing, going beyond the typical browser-level assertions Cypress excels at.
The next hurdle you’ll likely face is dealing with dynamically generated PDFs where the server might return a 200 OK with application/pdf headers, but the PDF itself is malformed or empty.