Search code examples
jqueryiframecypressone-time-password

How to extract OTP token from a mail service and save it to a fixture


I am trying to save OTP text into my Data.json file and here it is a code.

it.only('Otp Test', function () {
  cy.visit("https://www.mailinator.com/", { timeout: 30000 })
  cy.get("#addOverlay").type("jd")
  cy.get("#go-to-public").click()
  cy.wait(2000)
  cy.xpath("(//table/tbody/tr[1])[2]").click()
  cy.get('#html_msg_body').then(function ($ele) {
    var ifele = $ele.contents().find('body > table > tbody > tr:nth-child(3) > td > h2');
    cy.wrap(ifele).then(function (ele) {
      const OTP = ele.text();
      cy.readFile("cypress/fixtures/Data.json").then((profile) => {
        profile.OTP = OTP
        cy.writeFile("cypress/fixtures/Data.json", profile);
      })
    })
  })
})

Sometimes I'm getting this error

Timed out retrying after 10000ms: Expected to find element: undefined, but never found it

in the cy.wrap(ifele).then(function(ele) {

I don't know what happens. anyone knows please help me.


Solution

  • Firstly, the mail inbox changes so search for your OTP mail by text.

    After clicking the email row, you need to wait for the iframe to load. The standard way is using .its('0.contentDocument.body').should('not.be.empty').

    it.only('Otp Test', function () {
      cy.visit("https://www.mailinator.com/", { timeout: 30000 })
      cy.get("#addOverlay").type("jd")
      cy.get("#go-to-public").click()
      cy.wait(2000)
      cy.contains('table tbody tr', 'OTP').click()  // find the right email
    
      cy.get('#html_msg_body')  // iframe
        .its('0.contentDocument.body').should('not.be.empty')  // wait for loading
        .wait(0)    // some javascript needs to run in the iframe 
        .find('table > tbody > tr:nth-child(3) > td > h2')    
        .then($h2 => {    
          const OTP = $h2.text()
          cy.readFile("cypress/fixtures/Data.json").then((profile) => {
            profile.OTP = OTP
            cy.writeFile("cypress/fixtures/Data.json", profile);
          })
        })
    })
    

    Footnote

    "Sometimes getting this error..." is because the iframe can take time to load it's source (like a browser within the browser).

    Using .should('not.be.empty') repeats the read until it has some content.