带条纹的赛普拉斯:未加载元素高度
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 字段完全加载,我得到了一个错误,因为发生了这个(对不起,不是英语,但它是一个截图):
这些行是:
- 卡号
- 失效日期,密码
- 第 4 行是持卡人
我试过 .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()
}
})
}
一周以来我一直在使用 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 字段完全加载,我得到了一个错误,因为发生了这个(对不起,不是英语,但它是一个截图):
这些行是:
- 卡号
- 失效日期,密码
- 第 4 行是持卡人
我试过 .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.$(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()
}
})
}