Merge pull request #12031 from overleaf/ii-payment-page-migration-three-d-secure-currency-change

[web] 3DS currency change fix

GitOrigin-RevId: e88c773c6576e55803df3b2ec6a6acb1df80e8f2
This commit is contained in:
ilkin-overleaf 2023-03-01 11:33:10 +02:00 committed by Copybot
parent 48587a7a62
commit 8616c53839
6 changed files with 57 additions and 21 deletions

View file

@ -15,7 +15,7 @@ function CardElement({ className, elements, onChange }: CardElementProps) {
const { t } = useTranslation()
const [showCardElementInvalid, setShowCardElementInvalid] =
useState<boolean>()
const cardRef = useRef<HTMLDivElement>(null)
const cardRef = useRef<HTMLDivElement | null>(null)
// Card initialization
useEffect(() => {
@ -38,6 +38,10 @@ function CardElement({ className, elements, onChange }: CardElementProps) {
setShowCardElementInvalid(!state.focus && !state.empty && !state.valid)
onChange(state)
})
return () => {
cardRef.current = null
}
}, [elements, onChange])
return (

View file

@ -12,7 +12,7 @@ type ThreeDSecureProps = {
function ThreeDSecure({ actionTokenId, onToken, onError }: ThreeDSecureProps) {
const { t } = useTranslation()
const container = useRef<HTMLDivElement>(null)
const recurlyContainer = useRef<HTMLDivElement>(null)
const recurlyContainer = useRef<HTMLDivElement | null>(null)
useEffect(() => {
// scroll the UI into view (timeout needed to make sure the element is
@ -36,6 +36,10 @@ function ThreeDSecure({ actionTokenId, onToken, onError }: ThreeDSecureProps) {
threeDSecure.on('token', onToken)
threeDSecure.on('error', onError)
threeDSecure.attach(recurlyContainer.current)
return () => {
recurlyContainer.current = null
}
}, [actionTokenId, onToken, onError])
return (

View file

@ -6,6 +6,7 @@ import {
defaultSubscription,
ElementsBase,
} from '../../fixtures/recurly-mock'
import { fillForm } from '../../helpers/payment'
import { cloneDeep } from 'lodash'
import { TokenHandler, RecurlyError } from 'recurly__recurly-js'
@ -17,19 +18,6 @@ function CheckoutPanelWithPaymentProvider() {
)
}
function fillForm() {
cy.findByTestId('test-card-element').within(() => {
cy.get('input').each(el => {
cy.wrap(el).type('123', { delay: 0 })
})
})
cy.findByLabelText(/first name/i).type('123', { delay: 0 })
cy.findByLabelText(/last name/i).type('123', { delay: 0 })
cy.findByLabelText('Address').type('123', { delay: 0 })
cy.findByLabelText(/postal code/i).type('123', { delay: 0 })
cy.findByLabelText(/country/i).select('Bulgaria')
}
describe('checkout panel', function () {
const itmCampaign = 'fake_itm_campaign'
const itmContent = 'fake_itm_content'
@ -158,10 +146,10 @@ describe('checkout panel', function () {
expect(win.recurly.token).to.be.calledOnceWith(
Cypress.sinon.match.instanceOf(ElementsBase),
{
first_name: '123',
last_name: '123',
postal_code: '123',
address1: '123',
first_name: '1',
last_name: '1',
postal_code: '1',
address1: '1',
address2: '',
state: '',
city: '',
@ -330,7 +318,7 @@ describe('checkout panel', function () {
})
})
describe('3D challenge', function () {
describe('3DS challenge', function () {
it('shows three d secure challenge', function () {
cy.intercept('POST', 'user/subscription/create', {
statusCode: 404,

View file

@ -4,6 +4,9 @@ import {
} from '../../fixtures/recurly-mock'
import { PaymentProvider } from '../../../../../../frontend/js/features/subscription/context/payment-context'
import { plans } from '../../fixtures/plans'
import PaymentPreviewPanel from '../../../../../../frontend/js/features/subscription/components/new/payment-preview/payment-preview-panel'
import CheckoutPanel from '../../../../../../frontend/js/features/subscription/components/new/checkout/checkout-panel'
import { fillForm } from '../../helpers/payment'
describe('common recurly validations', function () {
beforeEach(function () {
@ -39,4 +42,27 @@ describe('common recurly validations', function () {
expect(win.recurly.Pricing.Subscription).to.be.calledOnce
})
})
it('shows three d secure challenge content only once when changing currency', function () {
cy.intercept('POST', 'user/subscription/create', {
statusCode: 404,
body: {
threeDSecureActionTokenId: '123',
},
})
cy.mount(
<PaymentProvider publicKey="0000">
<PaymentPreviewPanel />
<CheckoutPanel />
</PaymentProvider>
)
cy.findByTestId('checkout-form').within(() => fillForm())
cy.findByRole('button', { name: /upgrade now/i }).click()
cy.findByRole('button', { name: /change currency/i }).click()
cy.findByRole('menu').within(() => {
cy.findByRole('menuitem', { name: /gbp/i }).click()
})
cy.findAllByText('3D challenge content').should('have.length', 1)
})
})

View file

@ -154,7 +154,9 @@ export class ThreeDSecureBase {
on(_eventName = 'change', _callback: () => void) {}
attach(el: HTMLElement) {
el.textContent = '3D challenge content'
const div = document.createElement('div')
div.appendChild(document.createTextNode('3D challenge content'))
el.appendChild(div)
}
}

View file

@ -0,0 +1,12 @@
export function fillForm() {
cy.findByTestId('test-card-element').within(() => {
cy.get('input').each(el => {
cy.wrap(el).type('1', { delay: 0 })
})
})
cy.findByLabelText(/first name/i).type('1', { delay: 0 })
cy.findByLabelText(/last name/i).type('1', { delay: 0 })
cy.findByLabelText('Address').type('1', { delay: 0 })
cy.findByLabelText(/postal code/i).type('1', { delay: 0 })
cy.findByLabelText(/country/i).select('Bulgaria')
}