'How to pass locator as parameter in cypress?

I wonder if it is possible to pass locators as a parameter to make my function reusable. I tried to do it myself but I am getting "undefined" instead of working test. Cypress error: cy.click() failed because it requires a DOM element. The subject received was:

undefined

My code:

 Cypress.Commands.add(
  "commandName",
  (locator, chartValue1) => {
    const chartValues = [150, 250, 350, 450, 550, 750, 900];
    for (const value of chartValues) {
      locator.click(value, chartValue1).then(() => {
        mainElementsPage
          .mainSideBarHeader()
          .should("not.include.text", "(pon.)")
          .should("not.include.text", "(wt.)")
          .should("not.include.text", "(śr.)");
      });
    }
  }
);

I am using this command in test:

    it("should do something", () => {
    cy.commandName(mainElementsPage.chartRect(), 200);
  });

mainElementsPage content:

class mainElementsPage {

  chartRect() {
    return cy.get("#chart-grid-rect");
  }
}

export default mainElementsPage;


Solution 1:[1]

It looks like you want to make a child command.

Whatever precedes your custom command is passed in as subject (equivalent to locator)

Cypress.Commands.add("commandName", {prevSubject: true}, 
  (subject, chartValue1) => {
    const chartValues = [150, 250, 350, 450, 550, 750, 900];
    for (const value of chartValues) {
      subject.click(value, chartValue1).then(() => {
        mainElementsPage.mainSideBarHeader()
          .should("not.include.text", "(pon.)")
          .should("not.include.text", "(wt.)")
          .should("not.include.text", "(?r.)");
      });
    }
  }
)


cy.get("#chart-grid-rect").commandName(200);

// or

mainElementsPage.chartRect().commandName(200);
class MainElementsPage {

  chartRect() {
    return cy.get("#chart-grid-rect");
  }
}

export default new MainElementsPage;   // note - new keyword here

Solution 2:[2]

To make sure you you can use mainElementsPage you have to first import this file into your test like this:

import mainElementsPage from '../<some path>/mainElementsPage.js'

Then you have to create a object for this, like

const mainElements = new mainElementsPage();

Then you can use it as:

mainElements.chartRect()

Solution 3:[3]

In Cypress, it's impossible to have 2 active command chains simultaneously. So you cannot pass a command chain into another command ( including a custom command as you do). So I see 4 different ways of how you can fix the problem:

  1. Use a plain function instead of custom command. So you will be able to pass a chain from your POM object.
  2. Return a string locator instead of a chain from your POM object
  3. Use a child command and chain your logic (see @Fody's answer).
  4. Pass a function reference pointing to your POM object function and call this function inside the custom command (see @wojnarto' answer).

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Fody
Solution 2 Alapan Das
Solution 3