Main Website
Web Scraping
Web Scraping
Updated on
March 25, 2024

End-to-End Testing with Puppeteer: Getting Started

Get started with E2E testing in Puppeteer:

Introduction

In end-to-end testing, we replicate actual user behaviors and interactions with the application. Therefore, end-to-end testing provides a realistic assessment of the system's functionality. The importance of this testing approach lies in its ability to identify issues that occur when different parts of the application interact. Overall, end-to-end testing verifies the complete flow of the application from start to finish to ensure that all processes work seamlessly as intended.

Puppeteer role in end to end testing

What will you learn?

In this guide, you will learn how to perform end-to-end testing with Puppeteer. We will show you how to set up Puppeteer and write various test cases to test a hypothetical e-commerce application that needs to display content based on user location. Additionally, we will provide tips for improving testing efficiency and debugging with Puppeteer. Furthermore, we will discuss how other frameworks can be integrated with Puppeteer to enhance the testing process. For example, you can integrate Jest with Puppeteer to automatically validate the output obtained by Puppeteer.

Without further ado, let's dive in.

Puppeteer vs other frameworks for end-to-end testing

Puppeteer is a Node library that provides a high-level API to control headless Chrome or Chromium. It is not commonly used for end-to-end testing due to its browser limitation compared to other test frameworks. Selenium is the most widely used framework for end-to-end testing due to its support for multiple programming languages, browsers, and cross browser testing. 

Puppeteer operates only in JavaScript/Node.js environments, making it less flexible than Selenium, which supports languages like Java, C#, Python, Ruby, and more.

Puppeteer is more suitable for applications that require extensive testing of Chrome-specific features, like extensions. It is often chosen for its superior performance when testing Chrome or Chromium-based applications, as it interacts directly with the browser via the DevTools Protocol.

Prerequisites

To end-to-end test an application, you first need an application. For this guide, let's consider a hypothetical e-commerce application designed to target a diverse, global customer base.

Then you need to have Puppeteer installed on your machine so that you can write test cases in Puppeteer. If you don't know how to install Puppeteer, you can follow our guide on how to install Puppeteer. In the project directory, Puppeteer allows automation in multiple browsers, which can be controlled using the 'npm test' command to streamline testing in an automation context.

When testing an application with a global audience, you need to simulate users from different countries. The best option to do that is to take the help of a proxy service. Webshare offers free proxies that give you access to 10 proxies in different countries.

When coding for E2E testing in Puppeteer, you need to have a good knowledge of HTML, CSS, and most importantly JavaScript. We assume you already know the basics of these languages.

Test 1: Page load and Rendering

The speed at which a page loads is important for user experience and SEO ranking. Testing page load times ensures that users are not turned away by slow performance. This can directly impact the success of the application.

It's important to use proxies to test page loads as proxies emulate the diverse experiences of users from different geographical locations.

Here's an example of how you can set up a Puppeteer script to perform location-based tests. We will be using two proxies for this example:


const puppeteer = require('puppeteer');

async function testPageLoad(proxy, username, password) {
  const browser = await puppeteer.launch({
    args: [`--proxy-server=${proxy}`],
    headless: false // Set to true in production for headless mode
  });

  const page = await browser.newPage();

  // Authenticate with the proxy server
  await page.authenticate({
    username: username,
    password: password
  });

  // Measure load time
  const start = Date.now();
  await page.goto('https://your-ecommerce-site.com');
  const loadTime = Date.now() - start;
  console.log(`Load time for proxy at ${proxy}: ${loadTime}ms`);

  // Take a screenshot to verify rendering
  await page.screenshot({ path: `screenshot-${proxy}.png` });
 
  await browser.close();
}

// Test with the US proxy
testPageLoad('38.154.227.167:5868', 'username', 'password');

// Test with the Spain proxy
testPageLoad('185.199.229.156:7492', 'username', 'password');

In the code above, replace 'https://your-ecommerce-site.com' with the URL of your e-commerce application. The testPageLoad function launches a browser, sets the proxy, and navigates to the given URL. It measures the time it takes for the page to load and captures a screenshot for visual verification of rendering.

By running this script, you can assess how well your e-commerce platform performs under different network conditions, as might be experienced by users in the United States and Spain based on the proxy information provided. remember to finish the script with the await browser close method.

Test 2: Form submission

Testing form submissions is important in e-commerce applications because it directly impacts the ability to capture user data, process orders, and handle payments securely and efficiently.

For this use case, we will continue to use proxies as it is essential to ensure that users worldwide can interact with the website without encountering any issues.

Here's how you can configure Puppeteer to conduct a form submission test using the same proxies as mentioned previously:


const puppeteer = require('puppeteer');

async function testFormSubmission(proxy, username, password) {
  const browser = await puppeteer.launch({
    args: [`--proxy-server=${proxy}`],
    headless: false
  });

  const page = await browser.newPage();

  await page.authenticate({
    username: username,
    password: password
  });

  // Go to the form page
  await page.goto('https://your-ecommerce-site.com/login');

  // Fill in the login form
  await page.type('#username', 'testuser');
  await page.type('#password', 'testpass');

  // Click the submit button and wait for navigation
  await Promise.all([
    page.waitForNavigation(),
    page.click('#login-button')
  ]);

  // Check for successful submission by checking the URL or a success message
  const url = page.url();
  const success = url.includes('dashboard'); // Replace with the expected URL part or success condition
  console.log(`Form submission through proxy at ${proxy} was ${success ? 'successful' : 'unsuccessful'}.`);

  await browser.close();
}

// Proxy details
const usProxy = '38.154.227.167:5868';
const spainProxy = '185.199.229.156:7492';
const proxyUsername = 'username';
const proxyPassword = 'password';

// Test using the US proxy
testFormSubmission(usProxy, proxyUsername, proxyPassword);

// Test using the Spain proxy
testFormSubmission(spainProxy, proxyUsername, proxyPassword);\

This script automates logging into your e-commerce platform. It goes to the login page, fills in the credentials, submits the form, and checks for successful login based on the resulting URL or page content. Remember to replace the selectors (#username, #password, #login-button) and the URLs with the actual values from your application.

Recommended reading for advanced cases of using Click: Click in Puppeteer: Guide to Master Puppeteer’s Clicking Methods

Test 3: Detecting user's country

You may have noticed that some e-commerce applications can detect a user's country even before the user logs in. This is important for keeping users engaged on the website by displaying relevant offers or testing location-based currency display, optimized specifically for the user's country. As mentioned earlier, we require proxies to test this feature, as we need to simulate users from various countries.

You can implement this feature with Puppeteer by writing code similar to the example below:


const puppeteer = require('puppeteer');

async function testCountryDetection(proxy, username, password) {
  const browser = await puppeteer.launch({
    args: [`--proxy-server=${proxy}`],
    headless: true
  });

  const page = await browser.newPage();

  await page.authenticate({
    username: username,
    password: password
  });

  await page.goto('https://your-ecommerce-site.com');

  // Wait for the element that indicates the detected country to load
  await page.waitForSelector('#country-indicator');

  // Extract the country name from the page
  const detectedCountry = await page.evaluate(() => {
    return document.querySelector('#country-indicator').textContent; // Replace with the actual element ID or class
  });

  console.log(`Country detected for proxy at ${proxy}: ${detectedCountry.trim()}`);

  await browser.close();
}

// Test with the given proxy details
const proxyDetails = [
  { address: '38.154.227.167:5868', countryExpected: 'USA' },
  { address: '185.199.229.156:7492', countryExpected: 'Spain' }
];

proxyDetails.forEach(({ address, countryExpected }) => {
  testCountryDetection(address, 'username', 'password')
    .then(countryDetected => {
      const success = countryDetected.trim() === countryExpected;
      console.log(`Country detection test for ${countryExpected}: ${success ? 'PASSED' : 'FAILED'}`);
    });
});

In this code, #country-indicator is a placeholder selector for the element where your application shows the detected country. This should be replaced with the actual identifier used in your application. The script goes to your application's homepage and checks if the country displayed matches the expected country for the given proxy location.

If you want to learn about advanced techniques of using WaitForSelector read more here: waitForSelector in Puppeteer: Basic and Advanced Configuration.

Test 4: Multilingual Support Test

Multilingual support is essential for e-commerce applications that serve an international user base. Here is how you can structure a Puppeteer script to test the multilingual support by using proxies from different countries.


const puppeteer = require('puppeteer');

async function testMultilingualSupport(proxy, username, password, expectedLanguage) {
  const browser = await puppeteer.launch({
    args: [`--proxy-server=${proxy}`],
    headless: true
  });

  const page = await browser.newPage();

  await page.authenticate({
    username: username,
    password: password
  });

  await page.goto('https://your-hypothetical-app.com');

  // Wait for the language toggle element and click it
  await page.waitForSelector('#language-toggle');
  await page.click('#language-toggle');
 
  // You can also directly navigate to a URL that includes a language parameter if that's how your app handles language changes
 
  // Wait for the page to load content in the selected language
  await page.waitForFunction(lang => document.body.textContent.includes(lang), {}, expectedLanguage);

  // Check if the content is in the expected language
  const pageContent = await page.content();
  const isLanguageCorrect = pageContent.includes(expectedLanguage); // Replace with a more precise check relevant to your app's content

  console.log(`Language detected for proxy at ${proxy}: ${isLanguageCorrect ? 'correct' : 'incorrect'}`);

  await browser.close();
}

// Proxy details and expected languages
const proxyDetails = [
  { address: '38.154.227.167:5868', expectedLanguage: 'English' },
  { address: '185.199.229.156:7492', expectedLanguage: 'Español' }
];

proxyDetails.forEach(({ address, expectedLanguage }) => {
  testMultilingualSupport(address, 'username', 'password', expectedLanguage)
    .then(() => {
      console.log(`Finished testing multilingual support for ${expectedLanguage}.`);
    });
});

In this Puppeteer test, #language-toggle is a placeholder for the actual selector used by your application for users to change the language. The script clicks this button and waits for the web page to load content in the new language. The expectedLanguage variable should correspond to a unique string that would only appear on the page when it's in that language.

Tips for debugging

Automated testing web applications can sometimes be cumbersome as issues abound when writing automated test scripts. It would be helpful if you could streamline the debugging process more efficiently. Here are some tips that you can use to simplify your debugging process.

Enable Verbose Logging: Use Puppeteer's --enable-logging and --v=1 flags to get more detailed logs from the browser. This can help in pinpointing issues in your test suite.

Use Puppeteer's Debugger in Node: Take advantage of Node's inspect feature by running your automated tests with node --inspect-brk and using Chrome DevTools for a step-by-step debugging session.

Intercept Network Requests: Use Puppeteer's page.setRequestInterception(true) to intercept and log network requests and responses. This is important in Puppeteer tests for understanding how your application interacts with backend services.

Monitor Console Output Within the Browser Context: Capture console.log, console.error, and other console events from the browser context by adding event listeners with page.on('console', message => console.log(message.text())).

Evaluate Runtime Exceptions: Implement event listeners for page.on('pageerror', error => {...}) to catch unhandled exceptions within the page context. This helps to identify runtime errors that may not be obvious during testing.

Visual Debugging with Screenshots: Automate the taking of screenshots on failed tests using page.screenshot() to capture the state of the application at the point of error.

Assess Performance with Puppeteer's Tracing Feature: Use Puppeteer's page.tracing.start() and page.tracing.stop() to record and analyze the performance of your application during the test.

Conclusion

We hope this article helped you understand the basics of setting up end-to-end testing operations in Puppeteer. Most common tests involve page load and location-based testing of elements like currency, price displayed and site multilingual support functions.

Related Articles

Fill & Submit Form in Puppeteer: Guide With Examples

Wait For Page to Load in Puppeteer: 4 Methods Compared

Timeout in Puppeteer: Setup Methods & Error Fixes