带条纹的赛普拉斯:未加载元素高度

Cypress with stripe: elements height not loaded

一周以来我一直在使用 cypress,并且成功地与 stripe iframe 进行了集成:我使用了以下代码:

cypress/support/command.js

Cypress.Commands.add('iframeLoaded', { prevSubject: 'element' }, $iframe => {
  const contentWindow = $iframe.prop('contentWindow')
  return new Promise(resolve => {
    if (contentWindow && contentWindow.document.readyState === 'complete') {
      resolve(contentWindow)
    } else {
      $iframe.on('load', () => {
        resolve(contentWindow)
      })
    }
  })
})

Cypress.Commands.add('getInDocument', { prevSubject: 'document' }, (document, selector) =>
  Cypress.$(selector, document),
)

cypress/integration/staging-web/web.test.js

    cy.get('iframe')
      .eq(1)
      .iframeLoaded()
      .its('document')
      .getInDocument('[name="cardnumber"]')
    
      .then($iframe => {
          if ($iframe.is(':visible')) {
              $iframe.type('4242424242424242')
          }
      })
    
  cy.get('iframe')
      .eq(1)
      .iframeLoaded()
      .its('document')
      .getInDocument('[name="exp-date"]')
    
      .then($iframe => {
          if ($iframe.is(':visible')) {
              $iframe.type('1225')
          }
      })
    
  cy.get('iframe')
      .eq(2)
      .iframeLoaded()
      .its('document')
      .getInDocument('[name="cvc"]')
    
          .then($iframe => {
              if ($iframe.is(':visible')) {
                  $iframe.type('123')
              }
          })
    
  cy.get('.mt1 > .relative > .input').type('utente')

我的问题是在页面加载期间,cypress 没有等到 stripe 字段完全加载,我得到了一个错误,因为发生了这个(对不起,不是英语,但它是一个截图):

这些行是:

我试过 .should('be.visibile') 但它什么也没做;另外我试过

cy.get('iframe')
    .eq(1)
    .iframeLoaded()
    .its('document')
    .getInDocument('[name="cardnumber"]')

    .then($iframe => {
        if ($iframe.is(':visible')) {
            $iframe.type('4242424242424242')
        }
    })

但是没办法,总是报错;在后一种情况下,它甚至没有给出错误,它只是在不填写字段的情况下继续进行,此后它停止,因为它无法在测试中继续进行。

如果我在 web.test.js 中的代码之前添加 cy.wait(800) 它工作正常,但我不想使用 wait,因为它基本上是错误的(如果它加载会发生什么5 秒后?)。

有没有办法检查这些元素是否必须有高度? 请记住,他们在 iframe(可悲)。

如果我添加 cy.wait(800) ... 它工作正常.

这是因为您没有在 getInDocument().

中使用带自动重试功能的 Cypress 命令

Cypress.$(selector)是jQuery,只是尝试抓取元素,不会重试异步加载,未找到时不会测试失败。

应该使用正确的重试命令,例如

Cypress.Commands.add('getInDocument', { prevSubject: 'document' }, (document, selector) =>
  cy.wrap(document).find(selector)
)

或者您可能需要从 body

开始工作
Cypress.Commands.add('getInDocument', { prevSubject: 'document' }, (document, selector) =>
  cy.wrap(document).its('body')
    .find(selector)
    .should('be.visible')
)

在没有测试系统的情况下,我不确定哪一个是正确的语法,但你明白了。


此外,自定义命令太多。您总是在 .iframeLoaded() 之后加上 .its('document'),因此只需将其全部包含在 iframeLoaded 自定义命令中即可。

事实上,resolve(contentWindow.document.body)因为它是一个更好的链.find(selector)点。


这是我对 Stripe 演示页面的测试,

Cypress.Commands.add('iframeLoaded', { prevSubject: 'element' }, $iframe => {
  const contentWindow = $iframe.prop('contentWindow')
  return new Promise(resolve => {
    if (contentWindow && contentWindow.document.readyState === 'complete') {
      resolve(contentWindow.document.body)
    } else {
      $iframe.on('load', () => {
        resolve(contentWindow.document.body)
      })
    }
  })
})

it('finds card number', () => {

  cy.viewport(1000, 1000)
  cy.visit('https://stripe-payments-demo.appspot.com/')
  cy.get('iframe')
    .should('have.length.gt', 1)  // sometimes 2nd iframe is slow to load
    .eq(1)
    .iframeLoaded()
    .find('input[name="cardnumber"]')
    .should('be.visible')
})

@Nanker Phelge 顺便更新了我的功能,我把它贴在这里是因为评论中没有space:

更新:我把 waitForMillisecs 放在函数 -_- 里面,它必须留在外面!已更正。

const ADD_MS = 200
const STACK_LIMIT = 15
let stackNumber = 0
let waitForMillisecs = 500

    function checkAgainStripe() {  
      stackNumber++
    
      if (stackNumber >= STACK_LIMIT) {
        throw new Error('Error: too many tries on Stripe iframe. Limit reached is', STACK_LIMIT)
      }
    
      cy.get('.btn').scrollIntoView().should('be.visible').click()
      cy.get('iframe')
        .eq(1)
        .then($elem => {
          //console.log($elem[0].offsetHeight)
          //console.log($elem[0])
          cy.log('now wait for ' + waitForMillisecs + '; stack number is ' + stackNumber)
          cy.wait(waitForMillisecs)
          waitForMillisecs = waitForMillisecs + ADD_MS
          if (!$elem[0] || !$elem[0].offsetHeight || $elem[0].offsetHeight < 19) {
            console.log('entered in if')
            cy.reload()
            return checkAgainStripe()
          }
        })
    }