Home Manual Reference Source

src/page_objects/web/general/globalSearch.page.js

import BasePage from "../../base.page.js";

/**
 * GlobalSearchSection
 * @extends BasePage
 */
class GlobalSearchPage extends BasePage {
  /**
   * @param {*} browser Browser from controller
   */
  constructor(browser) {
    super(browser);
  }

  // PAGE ELEMENTS

  /* eslint-disable require-jsdoc */

  searchInput() {
    return this.element("#globalSearch");
  }

  scrollDivision() {
    return this.element("[class*='GlobalSearch__infiniteScroll']");
  }

  contactListElements() {
    return this.elements("[class*='GlobalSearch__contactListItem']");
  }

  emptyMessage() {
    return this.element("[class*='components-EmptyMessage']");
  }

  /* eslint-enable require-jsodoc */

  /**
   * Internal function to scroll the scrolling division to an offset
   * @param {Number} offset offset to scroll, by default scrolls to top
   */
  async _scrollContainerToPosition(offset = 0) {
    const element = this.scrollDivision();
    await element.waitForVisible();

    await this.browser.execute(
      (selector, offset) => {
        // eslint-disable-next-line
        var ele = document.querySelector(selector);
        ele.scrollTop = offset;
      },
      element.selector,
      offset
    );
    await this.browser.pause(1000);
  }

  /**
   * Internal function that gives if the scroll division is at bottom
   * @return {Boolean} scroll division at bottom or not
   */
  async _isBottomOfScroll() {
    const element = this.scrollDivision();
    await element.waitForVisible();
    const result = await this.browser.execute(selector => {
      // eslint-disable-next-line
      var ele = document.querySelector(selector);
      return ele.scrollHeight - ele.offsetHeight === ele.scrollTop;
    }, element.selector);
    return result.value;
  }

  /**
   * Internal function to scroll contact to the top in scroll division
   * @param {PageElement} contactElement Contact element to scroll to
   */
  async _scrollToContact(contactElement) {
    const elementOffset = await contactElement.getAttribute("offsetTop");
    await this._scrollContainerToPosition(elementOffset);
  }

  /**
   * Internal function that returns the name selector within an element
   * @param {String} name name of the contact
   * @return {String} selector for name of the contact
   */
  _nameSelector(name) {
    // eslint-disable-next-line
    return `.//div[contains(@class,'ContactListItem__overflowContainer') and string()='${name}']`;
  }

  /**
   * Internal method that checks if the name element is found in  parent element
   * @param {PageElement} parentElement parent element to llok for
   * @param {String} name name to be searched within parentElement
   * @return {Boolean} element found or not
   */
  async _isContactFoundInElement(parentElement, name) {
    let subElement;
    try {
      subElement = await parentElement.element(this._nameSelector(name));
    } catch (error) {
      if (error.message.includes("Unable to locate sub-element")) return false;
      throw error;
    }
    return await subElement.isVisible();
  }

  /**
   * Internal method to find and return contact element
   * @param {String} name name of the contact
   * @return {PageElement} Contact list element
   */
  async _findContact(name) {
    // Search for the element within container
    // to avoid looping for each list element
    // if not load the next set of elements by scrolling
    if (!await this._isContactFoundInElement(this.scrollDivision(), name)) {
      if (await this._isBottomOfScroll()) return null;
      const lastContact = await this.contactListElements().last();
      await this._scrollToContact(lastContact);
      return await this._findContact(name);
    } else {
      return await this._getContactElementFromList(name);
    }
  }

  /**
   * Internal method to get contacts from the list of visible entries
   * @param {String} name Name of the contact
   * @return {PageElement} PageElement of the contact or null
   */
  async _getContactElementFromList(name) {
    const contactElements = await this.contactListElements().all();
    let contactElement = null;
    for (const eachElement of contactElements) {
      if (await this._isContactFoundInElement(eachElement, name)) {
        contactElement = eachElement;
        await this._scrollToContact(contactElement);
      }
    }
    return contactElement;
  }

  /**
   * Type in global search field
   * @param {String} name Name to search for
   */
  async typeInSearchField(name) {
    await this.searchInput().setValue(name);
  }

  /**
   * Scroll and find contact in global search dropdown
   * @param {String} name name of the contact to search for
   * @return {PageElement} contact PageElement
   */
  async scrollAndfindContact(name) {
    await this._scrollContainerToPosition(0); // scrolls to top of the container
    return await this._findContact(name);
  }

  /**
   * Search and return contact element if found
   * @param {name} name Name of the contact to search for
   * @return {PageElement} contact page element
   */
  async searchContact(name) {
    await this.typeInSearchField(name);
    const contact = await this.scrollAndfindContact(name);
    return contact;
  }

  /**
   * Search and select a contact from global search
   * @param {String} name name of the contact
   */
  async selectContact(name) {
    const contact = await this.searchContact(name);
    await contact.click();
  }

  /**
   * Checks if chat icon is available within the contact element
   * @param {String} name name of the contact
   * @return {Boolean} whether chat icon exists or not
   */
  async isContactChattable(name) {
    const contact = await this.searchContact(name);
    await contact.hover();
    try {
      await contact.element("button.icon-chat");
      return true;
    } catch (error) {
      if (error.message.includes("Unable to locate sub-element")) return false;
      throw error;
    }
  }
}

export default GlobalSearchPage;