1

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;
Fody
  • 23,754
  • 3
  • 20
  • 37
wojnarto
  • 411
  • 4
  • 9
  • Which one is the locator in your `cypress.commands` ? – Alapan Das May 24 '22 at 09:27
  • locator in line3 and locator in line6 - this is the parameter. As the attribute, I want to use the correct one in `cy.commandName(mainElementsPage.chartRect(), 200);` – wojnarto May 24 '22 at 09:31
  • Assuming `mainElementsPage.chartRect()` returns a locator string, Do you get this locator string in your test where you have written the `cy.commandName()` ? Try logging that. – Alapan Das May 24 '22 at 09:46
  • It returns Object{5} o0 – wojnarto May 24 '22 at 09:55
  • Documentations says that Cypress.Command.add accepts only: "Boolean, String or Array" - so yea, probably it is not possible to pass locator as an argument. – wojnarto May 24 '22 at 09:58
  • Please add to the question the function `mainElementsPage` – Alapan Das May 24 '22 at 10:01

4 Answers4

2

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
Fody
  • 23,754
  • 3
  • 20
  • 37
1

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()
Alapan Das
  • 17,144
  • 3
  • 29
  • 52
1

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).
Mikhail Bolotov
  • 976
  • 1
  • 6
  • 13
1

I went this way:

 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.)");
      });
    }
  }
);

And in test it looks:

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

So the thing was about add () to the locator in Cypress.Commands.add() and use locator as string in the test.

wojnarto
  • 411
  • 4
  • 9