Locate the closest common ancestor of multiple locators in Playwright


import { Locator, Page } from "@playwright/test";

/**
 * Get the closest common ancestor among the locators
 * @param {Page} page Playwright's page instance
 * @param {Locator[]} locators An array of locators to find the closest common ancestor
 * @return {Locator} A locator of the closest common ancestor among the given locators
 */
export const getClosestCommonAncestor = (
  page: Page,
  locators: Locator[]
): Locator => {
  let output = page.locator("*");
  for (const locator of locators) {
    output = output.filter({ has: locator });
  }
  return output.last();
};

Explanation

1. Find all elements

To get every element on the document, we can use page.locator('*'). The result locator, when executed, will match every elements on the page. This gives us a universal set of all elements in the page which we can filter later on.

2. Filter for common ancestors

We chain .filter({ has: locator }) for every locators. For each .filter({ has: locator }), we get a subset of the universal set of elements that has the specified locator as a descendant.

Once we iterate through all of the locators, we are left with a subset of the universal set that are ancestors of all locators.

3. Get the closest ancestor

From filtering, we have multiple common ancestors ranging from the furthest to closest ones. We can get the closest common ancestor with .last().