簡體   English   中英

如何使用賽普拉斯將數據輸入到 iframe 的表單輸入中?

[英]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() ,我將把它留給您來解決。

鏈接中的解決方案對我有用。 基本上,步驟如下:

  1. 在 cypress.json 中將 chromeWebSecurity 設置為 false
  2. 在command.js中添加cypress命令獲取iframe
  3. 在腳本中使用 iframe 命令

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM