[英]How do I enter data into a form input in an iframe using cypress?
我一直在嘗試使用 cypress.io 測試條紋結帳表單
如果有人設法讓這個工作,請告訴我。 我在這里https://github.com/cypress-io/cypress/issues/136找到了一個關於這個問題的線程,基於此我想出了:
cy.get('iframe.stripe_checkout_app')
.wait(10000)
.then($iframe => {
const iframe = $iframe.contents()
const myInput0 = iframe.find('input:eq(0)')
const myInput1 = iframe.find('input:eq(1)')
const myInput2 = iframe.find('input:eq(2)')
const myButton = iframe.find('button')
cy
.wrap(myInput0)
.invoke('val', 4000056655665556)
.trigger('change')
cy
.wrap(myInput1)
.invoke('val', 112019)
.trigger('change')
cy
.wrap(myInput2)
.invoke('val', 424)
.trigger('change')
cy.wrap(myButton).click({ force: true })
})
但問題是條紋形式仍然沒有注冊輸入值。 這是發生的事情的小 gif http://www.giphy.com/gifs/xT0xeEZ8CmCTVMwOU8 。 基本上,表單不會注冊更改輸入觸發器。
有誰知道如何使用賽普拉斯將數據輸入 iframe 的表格中?
以下代碼段應該適合您。 我從@izaacdb 在此線程中的帖子中復制/粘貼了它。
cy.wait(5000)
cy.get('.__PrivateStripeElement > iframe').then($element => {
const $body = $element.contents().find('body')
let stripe = cy.wrap($body)
stripe.find('.Input .InputElement').eq(0).click().type('4242424242424242')
stripe = cy.wrap($body)
stripe.find('.Input .InputElement').eq(1).click().type('4242')
stripe = cy.wrap($body)
stripe.find('.Input .InputElement').eq(2).click().type('424')
})
但是,為了使上述內容起作用,您需要執行以下操作(從上面鏈接的同一線程中的@nerdmax 的帖子中復制/粘貼):
非常感謝@Vedelopment @brian-mann !
我使用 react-stripe-checkout 組件進行了測試,並且可以正常工作。
只需添加一些解決方案的詳細信息,這樣就可以為其他人節省一些時間。
chromeWebSecurity disable
:// cypress.json { "chromeWebSecurity": false }
--disable-site-isolation-trials
:檢查: https : //docs.cypress.io/api/plugins/browser-launch-api.html# AND #1951
// /plugins/index.js module.exports = (on, config) => { on("before:browser:launch", (browser = {}, args) => { if (browser.name === "chrome") { args.push("--disable-site-isolation-trials"); return args; } }); };
來自@user8888 的'.Input .InputElement'
選擇器對我不起作用。 相反,我通過它的name
屬性訪問每個input
。
cy.get(".__PrivateStripeElement > iframe").then(($element) => {
const $body = $element.contents().find("body");
let stripe = cy.wrap($body);
stripe
.find('[name="cardnumber"]')
.click()
.type(MOCK_CC_NUMBER);
stripe = cy.wrap($body);
stripe
.find('[name="exp-date"]')
.click()
.type(MOCK_CC_EXP);
stripe = cy.wrap($body);
stripe
.find('[name="cvc"]')
.click()
.type(MOCK_CC_CVC);
stripe = cy.wrap($body);
stripe
.find('[name="postal"]')
.click()
.type(MOCK_CC_ZIP);
});
我只是花了太長時間試圖讓這個工作,我找到的答案都不會完全有效。 我將我的解決方案添加到了 iframe 的 cypress github 問題中(那里有更多的上下文),也將它放在這里希望能節省其他人的時間。
我從這個 stackoverflow answer 中竊取了 onIframeReady() 函數。
基本上它正在做的是檢查 iframe 是否已加載,如果 iframe 已加載,它將執行$iframe.contents().find("body");
切換到內容。 如果它尚未加載,它會將相同的代碼掛鈎到load
事件中,因此它會在 iframe 加載后立即運行。
這是作為自定義命令編寫的,以允許在切換到 iframe 后使用 cypress 鏈接,因此將以下內容放入您的support/commands.js
文件中:
Cypress.Commands.add("iframe", { prevSubject: "element" }, $iframe => {
Cypress.log({
name: "iframe",
consoleProps() {
return {
iframe: $iframe,
};
},
});
return new Cypress.Promise(resolve => {
onIframeReady(
$iframe,
() => {
resolve($iframe.contents().find("body"));
},
() => {
$iframe.on("load", () => {
resolve($iframe.contents().find("body"));
});
}
);
});
});
function onIframeReady($iframe, successFn, errorFn) {
try {
const iCon = $iframe.first()[0].contentWindow,
bl = "about:blank",
compl = "complete";
const callCallback = () => {
try {
const $con = $iframe.contents();
if ($con.length === 0) {
// https://git.io/vV8yU
throw new Error("iframe inaccessible");
}
successFn($con);
} catch (e) {
// accessing contents failed
errorFn();
}
};
const observeOnload = () => {
$iframe.on("load.jqueryMark", () => {
try {
const src = $iframe.attr("src").trim(),
href = iCon.location.href;
if (href !== bl || src === bl || src === "") {
$iframe.off("load.jqueryMark");
callCallback();
}
} catch (e) {
errorFn();
}
});
};
if (iCon.document.readyState === compl) {
const src = $iframe.attr("src").trim(),
href = iCon.location.href;
if (href === bl && src !== bl && src !== "") {
observeOnload();
} else {
callCallback();
}
} else {
observeOnload();
}
} catch (e) {
// accessing contentWindow failed
errorFn();
}
}
然后你會在你的測試中這樣稱呼它:
cy.get('iframe.stripe_checkout_app')
.iframe()
.find('input:eq(0)')
.type("4000056655665556")
您可以在調用.iframe()之后調用.iframe()
以在其余輸入中引用它,或者多次調用 iframe 或.get()
,我將把它留給您來解決。
此鏈接中的解決方案對我有用。 基本上,步驟如下:
iframe 工作流程仍然很笨拙(直到實現此功能)。 現在,您可以嘗試強制幾乎每個 DOM 交互:
cy.visit("https://jsfiddle.net/1w9jpnxo/1/");
cy.get("iframe").then( $iframe => {
const $doc = $iframe.contents();
cy.wrap( $doc.find("#input") ).type( "test", { force: true });
cy.wrap( $doc.find("#submit") ).click({ force: true });
});
這並沒有直接回答您的問題,但是在嘗試使用 jQuery 處理 iframe 中的操作元素幾天后,重新實現了 Cypress 已經做過的一堆東西,我打了自己的臉並開始這樣做:
Cypress.Commands.add('openiframe', () => {
return cy.get("iframe[src^='/']").then(iframe => {
cy.visit(Cypress.$(iframe).attr('src'), { timeout: Cypress.config("pageLoadTimeout") });
});
});
這讓我只需要 cy.openiframe().then(() => {}); 然后就好像我正在測試的網站沒有在 iframe 中放置一堆功能一樣繼續。
缺點是你必須在 iframe 中做任何事情之前完成你在 iframe 中沒有做的事情,所以你不能太容易來回。
它可能不適用於您的用例,但如果/當它起作用時,這是我發現的最簡單的解決方法。
為了避免使用:
cy.wait(5000)
我按照 cypress 在本教程中提供的有關如何使用 iframe的說明找到了一種更好的方法
cy.get('iframe[name="__privateStripeFrame5"]')
.its("0.contentDocument.body")
.should("not.be.empty")
.then((body) => {
cy.wrap(body)
.find("[name=cardnumber]")
.type("6011111111111117", { force: true });
});
我昨天發布了一個插件,它添加了一個簡單的 Cypress API 來填充條紋元素:
cy.fillElementsInput('cardNumber', '4242424242424242');
這個插件避免了cy.wait()
調用、手動<iframe>
和其他笨拙的選擇器。
對我來說,這個 ifram 具有隨機行為,所以我使用了一些代碼,但最終使用 force:true 進行了嘗試,因為最后一個值失敗了。 該名稱對我無效,我必須使用更具體的不同屬性
cy.get(".__PrivateStripeElement > iframe").then(($element) => { const $body = $element.contents().find("body");
cy.wrap($body)
.find('[data-elements-stable-field-name="cardNumber"]')
.click()
.type('value')
cy.wrap($body)
.find('[data-elements-stable-field-name="cardExpiry"]')
.click()
.type('value')
cy.wrap($body)
.find('[data-elements-stable-field-name="cardCvc"]')
.click()
.type('value', { force: true });
其他答案對我不起作用,因為名稱屬性已更改。 這是我使用的:
cy.get('.__PrivateStripeElement > iframe').then(($element) => {
const $body = $element.contents().find('body')
let stripe = cy.wrap($body)
stripe.find('input[name="number"]').click().type('4242424242424242')
stripe = cy.wrap($body)
stripe.find('input[name="expiry"]').click().type('4242')
stripe = cy.wrap($body)
stripe.find('input[name="cvc"]').click().type('424')
stripe = cy.wrap($body)
stripe.find('input[name="postalCode"]').click().type('92222')
})
我收到此錯誤:
CypressError: cy.find() failed because this element is detached from the DOM.
<body>...</body>
Cypress requires elements be attached in the DOM to interact with them.
The previous command that ran was:
cy.wrap()
This DOM element likely became detached somewhere between the previous and current command.
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.