skip to Main Content

I am pointing to the middle table cell and I can able to get text of the next cell using the next() method but when I tried to use parent() I am getting full row text which is three cells. Below is the HTML code. Kindly help.

cy.get('[name="courses"] > tbody >tr >td:nth-child(2)').each((e1, index) => {
  const course = e1.text()
  
  if (course.includes('Python')) {
    cy.get('[name="courses"] > tbody >tr >td:nth-child(2)').eq(index).parent()
        .then((price) => {
      const courseprice = price.text()
      // expect(courseprice).to.be.equal('25')
      cy.log(courseprice)
    })
  }
})

enter image description here

enter image description here

enter image description here

5

Answers


  1. The reason the text is the entire text is that it combines the text of all child elements. To avoid this, we can take a few different routes:

    First solution: we can just check if the parent contains the value:

    cy.get('[name="courses"] > tbody >tr >td:nth-child(2)')
      .eq(index)
      .parent()
      .should('contain.text', 25);
    

    Second solution: grab the third row TD directly

    cy.get('[name="courses"] > tbody >tr >td:nth-child(3)') // nth-child is index-1
      .should('have.text', 25);
    
    Login or Signup to reply.
  2. After using parent, you can use within to go inside the parent tr and access each td elements like this:

    cy.get('[name="courses"] > tbody >tr >td:nth-child(2)')
      .eq(index)
      .parent()
      .within(() => {
        cy.get('td').eq(0).should('have.text', 'Rahul Shetty')
        cy.get('td')
          .eq(1)
          .should(
            'have.text',
            'Master Selenium Automation is simple Python Language'
          )
        cy.get('td').eq(2).should('have.text', '25')
      })
    

    You can reach the first td based on the second td like this:

    cy.contains('td', 'Master Selenium Automation is simple Python Language')
      .parent()
      .within(() => {
        cy.get('td').eq(0).should('have.text', 'Rahul Shetty')
      })
    
    Login or Signup to reply.
  3. It would be easier to iterate over the rows and check the 2nd instead of iterating over the 2nd and then travers up and down the DOM to get the price and then use cypress-if

    cy.get('[name="courses"] > tbody >tr')
      .should("have.length.greaterThan", 0)
      .each($row =>{
        cy.wrap($row)
          .contains("td", "Python", { timeout: 0 })
          .if("visible")
          .then(() => {
            cy.log("Price of Python course");
            cy.wrap($row).contains("td", "25").should("be.visible");
          })
          .else()
          .log("Instructor does NOT sell Python");
       }
    })
    

    Here is a minimal reproducible example.

    Login or Signup to reply.
  4. Another option, and my preferred way is to use find I would also recommend not using then or or other nested function like each if you don’t need it. And even though you can use jquery selectors like nth-child(), using the eq() makes it a bit more readable (IMHO). Also nth-child index is not 0-based but 1-based, so nth-child(2) returns the 2nd column, not the 3rd.

    for example, this will give you the 8th row and 3rd column

    cy.get('[name="courses"] > tbody >tr')
      .eq(7)
      .find('td')
      .eq(2)
    

    if I repeat anything more than twice in a test, I tend to write helper functions in the spec.

    // define somewhere at the beginning of the file (or add to commands.js)
    const getTableCell(r,c) => cy.get('[name="courses"] > tbody >tr')
      .eq(r)
      .find('td')
      .eq(c)
    
    describe('🤷‍♂️', () => {
      it('😉', () => {
        getTableCell(0,0).should('have.text', 'Instructor')
        getTableCell(0,1).should('have.text', 'Course')
        getTableCell(0,2).should('have.text', 'Price')
        getTableCell(1,0).should('have.text', 'Rahul Shetty')
        getTableCell(1,1).should('contain.text', 'Appium')
        getTableCell(1,2).should('have.text', '25')
        // etc...
      })
    })
    

    in some cases, depending on your html markup, the text might be padded with white space. In that case you might want to use contain.text instead of have.text but that could also cause issues, eg. 125 would match contain.text("25").


    another option

    cy.get('[name="courses"] > tbody >tr') // select all rows
      .contains("Python") // find 1st matched row
      .find("td") // find all columns in row
      .eq(2) // pick 3rd column
      .should("have.text", "25")  // make asserion
    

    Additionally, you can use find if you want to find a child element from a selector. In this case I added .find('td').eq(2). But note that this example shows a really convoluted way to search up and down the DOM.

    cy.get('[name="courses"] > tbody >tr >td:nth-child(2)').each((e1, index)=>{
            const course = e1.text()
            if(course.includes('Python')){
                cy.get('[name="courses"] > tbody >tr >td:nth-child(2)').eq(index).parent().find('td').eq(2).then((price)=>{
                    const courseprice = price.text()
                    // expect(courseprice).to.be.equal('25')
                    cy.log(courseprice)
                })
            }
        })
    
    Login or Signup to reply.
  5. For the first row containing "Python", .contains(selector, text) is the shortest and .next() gives you the price column.

    cy.contains('[name="courses"] tbody tr td:nth-child(2)', 'Python') // first match
      .prev()                                             // move left one cell
      .invoke('text')
      .as('instructor')
    
    cy.get('@instructor').then(instructorName => {   // "Rahul Shetty"
      ...
    })
    

    For multiple rows containing "Python", change to the pseudo-selector :contains()

    cy.get('[name="courses"] tbody tr td:nth-child(2):contains("Python")')   // all matches
      .prev()
      .then($instructors => {
        const names = [...$instructors].map(el => el.innerText)
        cy.wrap(names).as('instructors')
      })
    
    cy.get('@instructor').then(instructorName => {   // ["Rahul Shetty", ...]
      ...
    })
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search