Cypress에서 Stripe Elements의 자동 테스트 수행
12364 단어 스트라이프CypressTypeScript
소개
개발하고 있는 웹 어플리케이션으로, Stripe Elements 를 이용한 신용카드 정보 입력 기능💳를 구현했습니다만,
Cypress 을 사용하여 E2E 테스트를 작성할 때 약간의 고려가 필요했기 때문에 비망으로 남겨 둡니다 ✍️
하마리 포인트
stripe-js 을 사용하여 이런 코드에서 카드 번호 입력 요소를 만들었습니다.
덧붙여 앱은 Vuetify + Nuxt.js로 되어 있습니다만, Cypress 사이드에서는 별로 관계가 없는 것이므로 갓트리와 할애합니다 🍛
StripeElements의 구현 이미지// 諸々を定義
// 本旨から逸れるので割愛
const clientSecret = 'xxxxx'
const stripe = await getStripe()
// カード番号を入力する要素を生成
const elements = stripe.elements()
const card = elements.create('card', {
hidePostalCode: true
})
// blurイベント発生時に処理実施
card.on('blur', () => {
// コントロールを入力不可とする
card.update({ disabled: true })
stripe.confirmCardPayment(clientSecret, {
payment_method: {
card
}
}).then((confirmResult) => {
if (confirmResult.error) {
// エラーありの場合、入力完了を示すアラートを表示
// 割愛
// コントロールを再度入力可能とする
card.update({ disabled: false })
} else {
// エラーなしの場合、画面項目を編集不可とする
// 割愛
}
}).catch((error) => {
// システムエラーの場合
// 割愛
})
})
// IdがCardNoの要素の配下にマウント
card.mount('#CardNo')
위의 코드에서 다음과 같은 DOM이 생성됩니다 🌲
포인트는, 카드 번호를 입력하는 input 요소가, Stripe에 의해 생성된 iframe 안에 있는…
본래라면, 카드 정보의 입력이 다른 도메인(Stripe)의 iframe에 고립되어 있는 것으로 안전하게 이용할 수 있는 것이 됩니다만,
너무 안전해서 Cypress에서 DOM에 액세스할 수 없으며 테스트 카드 번호를 입력할 수 없습니다.
1) トップページ -> 検索 -> カートに入れる -> 注文情報入力 -> 購入:
SecurityError: Blocked a frame with origin "http://localhost" from accessing a cross-origin frame.
또한 Cypress에서 요소를 괴롭히는 영향에서 또는 라이브러리에서? 에서 잡히지 않은 예외가 발생하고 거기에 끌려 테스트 케이스도 떨어집니다.
이유를 조사하고 싶은 곳이지만, 보안상의 관점에서 Stripe의 클라이언트 구현의 소스 코드는 공개되어 있지 않고 (stripe-js는 단지 래퍼 & 타입 정의), 정말 말할 수없는 느낌입니다 ...
어떤 이유로 confirmCardPayment
가 여러 번 호출되는 것 같습니다.
제품 코드에서는 비활성화 등은 고려하고 있어 자동 테스트상에서만 발생하는 사건이므로 문제가 되지 않는다면 보지 못한 척을 결정하고 싶은 곳입니다 🙈
1) トップページ -> 検索 -> カートに入れる -> 注文情報入力 -> 購入:
IntegrationError: The following error originated from your application code, not from Cypress.
> You have an in-flight confirmCardPayment! Please be sure to disable your form submit button when confirmCardPayment is called.
When Cypress detects uncaught errors originating from your application it will automatically fail the current test.
This behavior is configurable, and you can choose to turn this off by listening to the `uncaught:exception` event.
https://on.cypress.io/uncaught-exception-from-application
만든 것
라는 곳이었지만,
대처요법적인 형태로 다음과 같이 자동 테스트를 수정하고 무사동할 수 있게 되었습니다 🙄
테스트 코드 이미지it('トップページ -> 検索 -> カートに入れる -> 注文情報入力 -> 購入', () => {
const options = {
timeout: 10000
}
// 他のシナリオは割愛
// クレジットカード情報を設定
// Stripe起因で発生する特定のエラーを無視する
cy.on('uncaught:exception', (error) => {
if (/You have an in-flight confirmCardPayment/gi.test(error.message)) {
return false
}
// 他のエラーは無視しない
return true
})
// 読み込みを確認
cy.frameLoaded('#CardNo iframe')
// カード番号・有効期限・セキュリティコードを入力
cy.iframe('#CardNo iframe')
// カード番号のinputを選択
.find('input[placeholder="カード番号"]')
// 各inputに値をフル桁入力すると、自動的に次のinputにフォーカスされるのでありがたく利用する
.type(['4242424242424242', '01', '50', '123'].join(''))
// Stripeのレスポンスを確認
cy.get('#CardNo')
// 他の要素を適当にクリックし、blurイベントを発火させる
.click()
// waitUntil()は `cypress-wait-until` というプラグインのものですが割愛
.waitUntil(() => cy.contains('お支払い情報を確認しました'), options)
// 他のシナリオは割愛
})
우선, iframe에 대한 크로스 오리진 액세스에 대해서는, cypress.json
에 이하의 설정을 추가하면 동작하게 되었습니다 🧐
cypress.json{
"chromeWebSecurity": false
}
구현으로는 어쩌면 여기 그리고 아마도 각각 아래의 의미라고 생각되지만, 테스트 코드이므로 더 이상의 깊은 추격은 그만두었습니다 ...
stripe-js 을 사용하여 이런 코드에서 카드 번호 입력 요소를 만들었습니다.
덧붙여 앱은 Vuetify + Nuxt.js로 되어 있습니다만, Cypress 사이드에서는 별로 관계가 없는 것이므로 갓트리와 할애합니다 🍛
StripeElements의 구현 이미지
// 諸々を定義
// 本旨から逸れるので割愛
const clientSecret = 'xxxxx'
const stripe = await getStripe()
// カード番号を入力する要素を生成
const elements = stripe.elements()
const card = elements.create('card', {
hidePostalCode: true
})
// blurイベント発生時に処理実施
card.on('blur', () => {
// コントロールを入力不可とする
card.update({ disabled: true })
stripe.confirmCardPayment(clientSecret, {
payment_method: {
card
}
}).then((confirmResult) => {
if (confirmResult.error) {
// エラーありの場合、入力完了を示すアラートを表示
// 割愛
// コントロールを再度入力可能とする
card.update({ disabled: false })
} else {
// エラーなしの場合、画面項目を編集不可とする
// 割愛
}
}).catch((error) => {
// システムエラーの場合
// 割愛
})
})
// IdがCardNoの要素の配下にマウント
card.mount('#CardNo')
위의 코드에서 다음과 같은 DOM이 생성됩니다 🌲
포인트는, 카드 번호를 입력하는 input 요소가, Stripe에 의해 생성된 iframe 안에 있는…
본래라면, 카드 정보의 입력이 다른 도메인(Stripe)의 iframe에 고립되어 있는 것으로 안전하게 이용할 수 있는 것이 됩니다만,
너무 안전해서 Cypress에서 DOM에 액세스할 수 없으며 테스트 카드 번호를 입력할 수 없습니다.
1) トップページ -> 検索 -> カートに入れる -> 注文情報入力 -> 購入:
SecurityError: Blocked a frame with origin "http://localhost" from accessing a cross-origin frame.
또한 Cypress에서 요소를 괴롭히는 영향에서 또는 라이브러리에서? 에서 잡히지 않은 예외가 발생하고 거기에 끌려 테스트 케이스도 떨어집니다.
이유를 조사하고 싶은 곳이지만, 보안상의 관점에서 Stripe의 클라이언트 구현의 소스 코드는 공개되어 있지 않고 (stripe-js는 단지 래퍼 & 타입 정의), 정말 말할 수없는 느낌입니다 ...
어떤 이유로
confirmCardPayment
가 여러 번 호출되는 것 같습니다.제품 코드에서는 비활성화 등은 고려하고 있어 자동 테스트상에서만 발생하는 사건이므로 문제가 되지 않는다면 보지 못한 척을 결정하고 싶은 곳입니다 🙈
1) トップページ -> 検索 -> カートに入れる -> 注文情報入力 -> 購入:
IntegrationError: The following error originated from your application code, not from Cypress.
> You have an in-flight confirmCardPayment! Please be sure to disable your form submit button when confirmCardPayment is called.
When Cypress detects uncaught errors originating from your application it will automatically fail the current test.
This behavior is configurable, and you can choose to turn this off by listening to the `uncaught:exception` event.
https://on.cypress.io/uncaught-exception-from-application
만든 것
라는 곳이었지만,
대처요법적인 형태로 다음과 같이 자동 테스트를 수정하고 무사동할 수 있게 되었습니다 🙄
테스트 코드 이미지it('トップページ -> 検索 -> カートに入れる -> 注文情報入力 -> 購入', () => {
const options = {
timeout: 10000
}
// 他のシナリオは割愛
// クレジットカード情報を設定
// Stripe起因で発生する特定のエラーを無視する
cy.on('uncaught:exception', (error) => {
if (/You have an in-flight confirmCardPayment/gi.test(error.message)) {
return false
}
// 他のエラーは無視しない
return true
})
// 読み込みを確認
cy.frameLoaded('#CardNo iframe')
// カード番号・有効期限・セキュリティコードを入力
cy.iframe('#CardNo iframe')
// カード番号のinputを選択
.find('input[placeholder="カード番号"]')
// 各inputに値をフル桁入力すると、自動的に次のinputにフォーカスされるのでありがたく利用する
.type(['4242424242424242', '01', '50', '123'].join(''))
// Stripeのレスポンスを確認
cy.get('#CardNo')
// 他の要素を適当にクリックし、blurイベントを発火させる
.click()
// waitUntil()は `cypress-wait-until` というプラグインのものですが割愛
.waitUntil(() => cy.contains('お支払い情報を確認しました'), options)
// 他のシナリオは割愛
})
우선, iframe에 대한 크로스 오리진 액세스에 대해서는, cypress.json
에 이하의 설정을 추가하면 동작하게 되었습니다 🧐
cypress.json{
"chromeWebSecurity": false
}
구현으로는 어쩌면 여기 그리고 아마도 각각 아래의 의미라고 생각되지만, 테스트 코드이므로 더 이상의 깊은 추격은 그만두었습니다 ...
it('トップページ -> 検索 -> カートに入れる -> 注文情報入力 -> 購入', () => {
const options = {
timeout: 10000
}
// 他のシナリオは割愛
// クレジットカード情報を設定
// Stripe起因で発生する特定のエラーを無視する
cy.on('uncaught:exception', (error) => {
if (/You have an in-flight confirmCardPayment/gi.test(error.message)) {
return false
}
// 他のエラーは無視しない
return true
})
// 読み込みを確認
cy.frameLoaded('#CardNo iframe')
// カード番号・有効期限・セキュリティコードを入力
cy.iframe('#CardNo iframe')
// カード番号のinputを選択
.find('input[placeholder="カード番号"]')
// 各inputに値をフル桁入力すると、自動的に次のinputにフォーカスされるのでありがたく利用する
.type(['4242424242424242', '01', '50', '123'].join(''))
// Stripeのレスポンスを確認
cy.get('#CardNo')
// 他の要素を適当にクリックし、blurイベントを発火させる
.click()
// waitUntil()は `cypress-wait-until` というプラグインのものですが割愛
.waitUntil(() => cy.contains('お支払い情報を確認しました'), options)
// 他のシナリオは割愛
})
{
"chromeWebSecurity": false
}
게다가 Cypress에서 iframe하의 콘텐츠에의 액세스를 편하게 해 준다 cypress-iframe
cy.frameLoaded()
에서 대상 iframe 로드 확인, cy.iframe()
에서 대상 iframe을 검색할 수 있습니다.Stripe로 인한 미 캐치 예외의 경우,
cy.on()
를 사용하여 예외 메시지를 확인하고, 이번에 보지 못한 것으로 하고 싶은 예외였을 경우만 무시하기로 했습니다 🐞이것 이외의 예외가 발생해, 그것이 자동 테스트 환경에 한정되는 경우는, 무시 대상을 늘려 대응하면 좋을지도 🐝
그러나이 문제에 대해서는 내 코드에 원인이있는 것 같습니다.
덤으로 테스트 시나리오가 잘 실행되는 모습을 붙여 둡니다 🏋️♀️
動いてるからヨシ!
정말 😾참고문헌
Reference
이 문제에 관하여(Cypress에서 Stripe Elements의 자동 테스트 수행), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/yktakaha4/items/13c3c13a0e13d0890371텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)