Source: widgets/popup.js

'use strict';

const popupRoles = new Set(['menu', 'listbox', 'tree', 'grid', 'dialog']);

const AriaDriverError = require('../error');
const momentWhen = require('../util/moment-when');

/**
 * @lends AriaDriver.prototype
 */
module.exports = {
  /**
   * Open {@link https://w3c.github.io/aria/#aria-haspopup an interactive popup
   * element}.
   *
   * @param {string} selector - a CSS selector describing the element to {@link
   *                            AriaDriver#use use} in order to open the popup.
   *
   * @see {@link https://w3c.github.io/aria/#aria-haspopup}
   * @see {@link https://www.w3.org/TR/wai-aria-1.1/#usage_intro}
   *
   * @throws When {@link https://w3c.github.io/aria/#aria-haspopup the
   *         aria-haspopup attribute} of the target element is unspecified or
   *         invalid
   * @throws When the number of visible popups does not increase within {@link
   *         AriaDriver#patience the "patience" duration}
   */
  async openPopup(selector) {
    const target = await this._findOne(selector);
    const attrValue = await target.getAttribute('aria-haspopup');
    // > To provide backward compatibility with ARIA 1.0 content, user agents
    // > MUST treat an `aria-haspopup` value of true as equivalent to a value
    // > of `menu`.
    //
    // https://www.w3.org/TR/wai-aria-1.1/#aria-haspopup
    const role = attrValue === 'true' ? 'menu' : attrValue;

    if (!popupRoles.has(role)) {
      throw new AriaDriverError(
        'ARIADRIVER-INVALID-MARKUP',
        null,
        'Specify a valid value for the `aria-haspopup` attribute',
        'https://www.w3.org/TR/wai-aria-1.1/#aria-haspopup'
      );
    }

    const popupLocator = `[role="${role}"]:not([aria-hidden="true"])`;
    const count = () => this.count(popupLocator);
    const initialCount = await count();

    await this._use(selector, target);

    const hasOpened = async () => (await count()) === initialCount + 1;
    await momentWhen(`${role} popup has opened`, hasOpened, this._patience);
  }
};