Tirath Sojitra
Tirath Sojitra

Reputation: 449

How can I use regex on an attribute value in cy.get()?

The application has list of items in a table and items have [id=item[0].setupCost, id=item[1].setupCost, id=item[2].setupCost] etc.

There's a functionality to add items also, so the index keeps on increasing.

I want to get input field regardless of using magic numbers. For eg (cy.get('[id=item[some_regex].setupCost]')

Upvotes: 1

Views: 1799

Answers (4)

kegne
kegne

Reputation: 853

In case you need another answer:

You can use a regex if you add a jQuery extension.

It works because Cypress uses jQuery internally, and you can modify selector behavior by extending jQuery.

it('finds multiple ids by regex', () => {

  const $ = Cypress.$
  $.extend(
    $.expr[':'], {
      idRegex: function(a, i, m) {
        const regex = new RegExp(m[3], 'i');
        return regex.test(a.getAttribute('id'));
      }
    }
  )

  const regex = 'item\\[\\d+\\].setupCost' 

  cy.get(`input:idRegex(${regex})`)
    .its('length')
    .should('eq', 3)   // ✅
})

Put the jQuery extension in /cypress/support/index.js to use it globally.

Note in the regex we have to double-escaped because we pass in a string not a regex.

Upvotes: 4

agoff
agoff

Reputation: 7164

You could create a custom Cypress command that would insert the index for you. Below, I'm assuming the id you're referencing is the ID of the element and is a standard CSS selector

Cypress.Commands.add('getItemById', (index) => {
  return cy.get(`#item\\[${index}\\].setupCost`)
});


cy.getItemById(0)...

Upvotes: 0

Fody
Fody

Reputation: 32118

The regex that applies is \[id="item\[\d+\].setupCost\].

Enclose the regex in forward slashes, not quotes.

cy.get(/\[id="item\[\d+\].setupCost\]/)

But don't use it

This syntax is undocumented - it works (in Cypress v9.5.0) but it only returns one result.

So if you want to count your items, this will fail

cy.get(/\[id="item\[\d+\].setupCost\]/)
  .its('length')
  .should('eq', 3)   // ❌

Partial attribute selector

If you want to use partial attribute selectors, this is strongest as it includes .setupCost

Ref Find the element with id that starts with "local-" and ends with "-remote"

cy.get('[id^="item"][id$=".setupCost"]')  // use "starts-with" and "ends-with" selectors

This succeeds with the count test

cy.get('[id^="item"][id$=".setupCost"]')
  .its('length')
  .should('eq', 3)   // ✅

Upvotes: 6

Alapan Das
Alapan Das

Reputation: 18618

Instead of Regex you can use ^ with your selector. This denotes the start of the text. So you can write:

cy.get('[id^="item"]')

Now if you want to access any particular element you can use eq like this:

cy.get('[id^="item"]').eq(0) //gets id=item[0].setupCost
cy.get('[id^="item"]').eq(1) //gets id=item[1].setupCost

If you want to loop over each element you can use each()

cy.get('[id^="item"]').each(($ele) => {
  cy.wrap($ele)
})

Upvotes: 0

Related Questions