E2E Search

On this page

Searching a website is an everyday action for most internet users. For most services, the speed at which their customers are able to get to the products they are looking for is directly tied to revenue. To enable that, a performant and reliable search function is needed.

Steps

The example below, which is running against our test webshop, shows how we can verify the correctness of a search’s result from an end-to-end perspective. In short, we will:

  1. Enter a known search term
  2. Firstly, assert the expected number of results is being shown
  3. If the previous point is true, assert that all expected search results are shown

We will use Chai as an assertion library for points 2 and 3.


const { chromium } = require("playwright");
const assert = require("chai").assert;

(async () => {
  const browser = await chromium.launch();
  const page = await browser.newPage();

  const bookList = [
    "The Foreigner",
    "The Transformation",
    "For Whom the Ball Tells",
    "Baiting for Robot",
  ];

  await page.goto("https://danube-webshop.herokuapp.com/");

  await page.click(".topbar > input");
  await page.type(".topbar > input", "for");
  await page.click("#button-search");

  await page.waitForSelector(
    ".shop-content > ul > .preview:nth-child(1) > .preview-title"
  );

  // Halt immediately if results do not equal expected number
  let resultsNumber = (await page.$$(".preview-title")).length;
  assert.equal(resultsNumber, bookList.length);

  // Remove every element found from the original array...
  for (i = 0; i < resultsNumber; i++) {
    const resultTitle = await page.$eval(
      `.preview:nth-child(${i + 1}) > .preview-title`,
      (e) => e.innerText
    );

    const index = bookList.indexOf(resultTitle);
    bookList.splice(index, 1);
  }

  // ...then assert that the original array is now empty
  assert.equal(bookList.length, 0);

  await browser.close();
})();


Run in Checkly

const puppeteer = require("puppeteer");
const assert = require("chai").assert;

(async () => {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();

  const bookList = [
    "The Foreigner",
    "The Transformation",
    "For Whom the Ball Tells",
    "Baiting for Robot",
  ];

  await page.goto("https://danube-webshop.herokuapp.com/");

  await page.setViewport({ width: 1200, height: 800 });

  await page.waitForSelector(".topbar > input");
  await page.click(".topbar > input");

  await page.type(".topbar > input", "for");

  await page.waitForSelector("#button-search");
  await page.click("#button-search");

  await page.waitForSelector(
    ".shop-content > ul > .preview:nth-child(1) > .preview-title"
  );

  // Halt immediately if results do not equal expected number
  let resultsNumber = (await page.$$(".preview-title")).length;
  assert.equal(resultsNumber, bookList.length);

  // Remove every element found from the original array...
  for (i = 0; i < resultsNumber; i++) {
    const resultTitle = await page.$eval(
      `.preview:nth-child(${i + 1}) > .preview-title`,
      (e) => e.innerText
    );

    const index = bookList.indexOf(resultTitle);
    bookList.splice(index, 1);
  }

  // ...then assert that the original array is now empty
  assert.equal(bookList.length, 0);

  await browser.close();
})();


Run in Checkly

Run this example as follows:

node search.js

When testing search on large sets of data, you might additionally need to handle result pagination, together with the possibility of duplicate results.

Listing search terms and their corresponding expected results in a file could be helpful for additional, more thorough testing. The contents of the file would be then used to drive the searches and comparisons. An example could look like the following JSON:

[
    {
        "search": "pen",
        "results": [
            "red pen",
            "blue pen",
            "fountain pen"
        ]
    },
    {
        "search": "pencil",
        "results": [
            "short pencil",
            "pencil sharpener",
            "pencil case"
        ]
    }
]

Takeaways

  1. Moving test data to a separate file can help when running more thorough comparisons.
  2. Assertion libraries help us cleanly verify multiple constraints in our test.