Dushan Anuradha
Dushan Anuradha

Reputation: 31

Text assertion in Cypress with nested query

I am new to Cypress, and trying to write an assertion for some text inputs for a username. A valid text for a username should fulfill two conditions, which are,

  1. Text should contain ONLY English letters.
  2. Text length should be greater than 1, and less than 20.

My code is as follows.

getUserFirstName(textInput) {
  cy.get('[testid="user-self-update-form"]')
    .get('input[name="firstName"]')
    .clear()
    .type(textInput)
    .blur()
    .invoke('val')
    .should(($el) => {
      expect($el).to
                 .match(/[a-zA-Z]+$/)
                 .to
                 .have
                 .greaterThan(1)
                 .to
                 .be
                 .lessThan(20)
    }).then(() => {
      cy.log("Invalid text input");
    })
}

My requirement: When a username text is inserted, the above test should check whether it meets with imposed conditions, if not, log a message in the console. I am now trying to do the above test for 4 inputs separately, which are 'abcd123', '123', 'textwithmorethantwentyletters', and 'belowtwenty'. When running this test for the first input text of 'abcd123'. How may I correct this code? Highly appreciate your help.

I get the following error, and the test is failed:

enter image description here

Upvotes: 2

Views: 1149

Answers (3)

Michael Hines
Michael Hines

Reputation: 1098

To get elegant log of conditions, use Cypress.log

getUserFirstName(textInput) {
  cy.get('[testid="user-self-update-form"]')
    .find('input[name="firstName"]')
    .clear().type(textInput).blur()
    .invoke('val')
    .then(val => {

      // Conditions
      const lettersOnly = val.match(/[a-zA-Z]+$/)
      const correctLength = val.length > 1 && val.length < 20

      Cypress.log({
        name: 'firstNameCheck',
        displayName: `Testing "${textInput}"`,
        message: ` - lettersOnly: ${lettersOnly ? 'pass' : 'fail'}`
      })
      Cypress.log({
        name: 'firstNameCheck',
        displayName: `Testing "${textInput}"`,
        message: ` - correctLength : ${correctLength ? 'pass' : 'fail'}`
      })

      // now fail if you want, or omit this to perform next textInput
      expect( lettersOnly && correctLength ).to.eq(true)
    })
}

const textInputs = ['abcd123', '123', 'textwithmorethantwentyletters', 'belowtwenty']

textInputs.forEach(textInput => getUserFirstName(textInput))

enter image description here

You can also suppress the log of find, type, invoke with {log:false} option.

Upvotes: 2

Alapan Das
Alapan Das

Reputation: 18650

Your answer is mostly correct, but it just needs a few changes.

  1. You are applying two assertions - to check that the username text matches the regex value and the text length is between 1 and 20. In your case, two different assertions will work better.
expect($el).to.match(/[a-zA-Z]+$/)
expect($el.length).to.have.greaterThan(1).to.be.lessThan(20)

You can also use within which basically checks for greater and less than.

expect($el.length).to.be.within(1,20)
  1. Instead of using cy.log("Invalid text input"); you can directly pass custom log messages in expect statements.
expect($el.length).to.be.within(1,20, "Some Log message")

So implementing these two changes your code should look like:

cy.get('[testid="user-self-update-form"]')
  .get('input[name="firstName"]')
  .clear()
  .type(textInput)
  .blur()
  .invoke('val')
  .should((val) => {
    expect(val.trim()).to.match(/[a-zA-Z]+$/,
      `Checking username ${val} for regex match`
    )
    expect(val.trim().length).to.be.within(1,20,
      `Checking username ${val} for length match`
    )
  })

Upvotes: 1

user16695029
user16695029

Reputation: 4430

You can try chaining the conditions with Cypress .and()

getUserFirstName(textInput) {
  cy.get('[testid="user-self-update-form"]')
    .find('input[name="firstName"]')
    .clear()
    .type(textInput).blur()
    .invoke('val')
    .should('match', /[a-zA-Z]+$/)
    .and('have.length.gt', 1)
    .and('have.length.lt', 20)
}

The input abc123 does not meet the first criteria, why did you think the test would pass?

If you want to just log bu not fail the test, try

getUserFirstName(textInput) {
  cy.get('[testid="user-self-update-form"]')
    .find('input[name="firstName"]')
    .clear()
    .type(textInput).blur()
    .invoke('val')
    .then(val => {
      const lettersOnly = val.match(/[a-zA-Z]+$/)
      const gt1 = val.length > 1
      const lt20 = val.length < 20
      if (!lettersOnly || !gt1 || !lt20) {
        cy.log('Failed conditions')
        // to fail the test now, throw an error
        throw 'Failed conditions'
      })
     })
}

In the 2nd example I did not use .should(), .and() or expect() because if any of those fail Cypress will fail the test at that point (and not check the other conditions).

Note also, .find(('input[name="firstName"]') instead of .get('input[name="firstName"]') because your intention is to find the firstname input within the form.

.get() also may work if there is only one 'input[name="firstName"]' on the page, but be aware that it ignores the line before and queries DOM from the root element <body>.

Upvotes: 2

Related Questions