From 517e0121bc1bf2fd01ec71f82eb2ebe6bfcb04f9 Mon Sep 17 00:00:00 2001 From: Bill Randall Date: Fri, 6 Dec 2024 14:27:10 -0500 Subject: [PATCH] Separate out the creation of the Recaptcha script so we can put it on pages that the action is not being run on --- src/app/branded/branded-checkout.component.js | 4 ++ src/app/branded/branded-checkout.spec.js | 10 +++- src/app/checkout/checkout.component.js | 4 ++ src/app/checkout/checkout.spec.js | 6 +- .../Recaptcha/RecaptchaWrapper.test.tsx | 55 ------------------- .../components/Recaptcha/RecaptchaWrapper.tsx | 11 +--- .../checkoutHelpers/checkout.service.js | 8 +++ .../checkoutHelpers/checkout.service.spec.js | 42 ++++++++++++++ 8 files changed, 73 insertions(+), 67 deletions(-) create mode 100644 src/common/services/checkoutHelpers/checkout.service.js create mode 100644 src/common/services/checkoutHelpers/checkout.service.spec.js diff --git a/src/app/branded/branded-checkout.component.js b/src/app/branded/branded-checkout.component.js index 065ac52df..c7d06d355 100644 --- a/src/app/branded/branded-checkout.component.js +++ b/src/app/branded/branded-checkout.component.js @@ -13,6 +13,7 @@ import thankYouSummary from 'app/thankYou/summary/thankYouSummary.component' import sessionService from 'common/services/session/session.service' import orderService from 'common/services/api/order.service' +import * as checkoutService from 'common/services/checkoutHelpers/checkout.service' import brandedAnalyticsFactory from './analytics/branded-analytics.factory' import 'common/lib/fakeLocalStorage' @@ -33,6 +34,7 @@ class BrandedCheckoutController { this.envService = envService this.orderService = orderService this.$translate = $translate + this.checkoutService = checkoutService this.orderService.clearCoverFees() } @@ -57,6 +59,8 @@ class BrandedCheckoutController { console.error(err) }) this.$translate.use(this.language || 'en') + + this.checkoutService.initializeRecaptcha.call(this) } formatDonorDetails () { diff --git a/src/app/branded/branded-checkout.spec.js b/src/app/branded/branded-checkout.spec.js index 9f099e65c..5502e4370 100644 --- a/src/app/branded/branded-checkout.spec.js +++ b/src/app/branded/branded-checkout.spec.js @@ -50,7 +50,10 @@ describe('branded checkout', () => { onOrderCompleted: jest.fn(), onOrderFailed: jest.fn(), }, - ); + ) + $ctrl.checkoutService = { + initializeRecaptcha: jest.fn() + } })) describe('$onInit', () => { @@ -74,6 +77,11 @@ describe('branded checkout', () => { expect($ctrl.formatDonorDetails).toHaveBeenCalled() expect($ctrl.$window.sessionStorage.removeItem).toHaveBeenCalledWith('initialLoadComplete') }) + + it('should initialize recaptcha', () => { + $ctrl.$onInit() + expect($ctrl.checkoutService.initializeRecaptcha).toHaveBeenCalled() + }) }) describe('formatDonorDetails', () => { diff --git a/src/app/checkout/checkout.component.js b/src/app/checkout/checkout.component.js index bb67848db..2bbbb9356 100644 --- a/src/app/checkout/checkout.component.js +++ b/src/app/checkout/checkout.component.js @@ -14,6 +14,7 @@ import showErrors from 'common/filters/showErrors.filter' import cartService from 'common/services/api/cart.service' import orderService from 'common/services/api/order.service' import designationsService from 'common/services/api/designations.service' +import * as checkoutService from 'common/services/checkoutHelpers/checkout.service' import sessionEnforcerService, { EnforcerCallbacks } from 'common/services/session/sessionEnforcer.service' import { Roles, SignOutEvent } from 'common/services/session/session.service' @@ -40,6 +41,7 @@ class CheckoutController { this.loadingCartData = true this.analyticsFactory = analyticsFactory this.selfReference = this + this.checkoutService = checkoutService } $onInit () { @@ -56,6 +58,8 @@ class CheckoutController { this.initStepParam(true) this.listenForLocationChange() this.analyticsFactory.pageLoaded(true) + + this.checkoutService.initializeRecaptcha.call(this) } $onDestroy () { diff --git a/src/app/checkout/checkout.spec.js b/src/app/checkout/checkout.spec.js index a62319cf1..47ab200a0 100644 --- a/src/app/checkout/checkout.spec.js +++ b/src/app/checkout/checkout.spec.js @@ -19,6 +19,9 @@ describe('checkout', function () { search: '' }, scrollTo: jest.fn() } }) + self.controller.checkoutService = { + initializeRecaptcha: jest.fn() + } })) it('to be defined', function () { @@ -53,6 +56,7 @@ describe('checkout', function () { self.controller.$rootScope.$on.mock.calls[0][1]() expect(self.controller.signedOut).toHaveBeenCalled() + expect(self.controller.checkoutService.initializeRecaptcha).toHaveBeenCalled() }) describe('sessionEnforcerService success', () => { @@ -118,7 +122,7 @@ describe('checkout', function () { it('should watch the url and update the state', () => { jest.spyOn(self.controller, 'initStepParam').mockImplementation(() => {}) jest.spyOn(self.controller.cartService, 'get').mockReturnValue(Observable.of('cartData')) - jest.spyOn(self.controller.analyticsFactory, 'checkoutStepEvent').mockImplementation(() => {}) + jest.spyOn(self.controller.analyticsFactory, 'checkoutStepEvent').mockImplementation(() => {}) self.controller.listenForLocationChange() self.controller.$location.search('step', 'review') self.controller.$rootScope.$digest() diff --git a/src/common/components/Recaptcha/RecaptchaWrapper.test.tsx b/src/common/components/Recaptcha/RecaptchaWrapper.test.tsx index 43a48a39a..9b323650b 100644 --- a/src/common/components/Recaptcha/RecaptchaWrapper.test.tsx +++ b/src/common/components/Recaptcha/RecaptchaWrapper.test.tsx @@ -23,20 +23,9 @@ describe('RecaptchaWrapper component', () => { execute: mockExecuteRecaptcha } - const script = document.createElement('script') - beforeEach(() => { $translate.instant.mockImplementation((input) => input) global.window.grecaptcha = mockRecaptcha - script.src = 'https://www.google.com/recaptcha/api.js?render=123' - script.id = 'test-script' - }) - - afterEach(() => { - const foundScript = document.getElementById('give-checkout-recaptcha') - if (foundScript) { - document.head.removeChild(foundScript) - } }) it('should render', () => { @@ -62,49 +51,5 @@ describe('RecaptchaWrapper component', () => { expect(recaptchaEnabledButton.className).toEqual('btn') expect((recaptchaEnabledButton as HTMLButtonElement).disabled).toEqual(false) expect(recaptchaEnabledButton.innerHTML).toEqual('Label') - expect(document.getElementById('give-checkout-recaptcha')).not.toBeNull() - }) - - it('should add a script even if one already exists', () => { - document.head.appendChild(script) - render( - - ) - expect(document.getElementById('give-checkout-recaptcha')).not.toBeNull() - expect(document.getElementById('test-script')).not.toBeNull() - }) - - it('should only add this script once', () => { - script.id = 'give-checkout-recaptcha' - document.head.appendChild(script) - expect(document.getElementById('give-checkout-recaptcha')).not.toBeNull() - render( - - ) - expect(document.querySelectorAll('#give-checkout-recaptcha')).toHaveLength(1) }) }) diff --git a/src/common/components/Recaptcha/RecaptchaWrapper.tsx b/src/common/components/Recaptcha/RecaptchaWrapper.tsx index aba24e734..aecc6fd59 100644 --- a/src/common/components/Recaptcha/RecaptchaWrapper.tsx +++ b/src/common/components/Recaptcha/RecaptchaWrapper.tsx @@ -1,6 +1,6 @@ import angular from 'angular' import { react2angular } from 'react2angular' -import React, { useMemo } from 'react' +import React from 'react' import { ButtonType, Recaptcha } from './Recaptcha' const componentName = 'recaptchaWrapper' @@ -40,15 +40,6 @@ export const RecaptchaWrapper = ({ }: RecaptchaWrapperProps): JSX.Element => { const recaptchaKey = envService.read('recaptchaKey') - useMemo(() => { - const script = document.createElement('script') - script.src = `https://www.google.com/recaptcha/enterprise.js?render=${recaptchaKey}` - script.id = 'give-checkout-recaptcha' - if (!document.getElementById(script.id)) { - document.head.appendChild(script) - } - }, []) - return ( { + const $ctrl = { + $window: { + document: document + }, + envService: { + read: jest.fn() + } + } + const script = document.createElement('script') + + beforeEach(() => { + script.src = 'https://www.google.com/recaptcha/enterprise.js?render=123' + script.id = 'test-script' + $ctrl.envService.read.mockReturnValue('123') + }) + + afterEach(() => { + const foundScript = document.getElementById('give-checkout-recaptcha') + if (foundScript) { + document.head.removeChild(foundScript) + } + }) + + it('should add a script even if one already exists', () => { + document.head.appendChild(script) + checkoutService.initializeRecaptcha.call($ctrl) + expect(document.getElementById('give-checkout-recaptcha')).not.toBeNull() + expect(document.getElementById('test-script')).not.toBeNull() + }) + + it('should only add this script once', () => { + script.id = 'give-checkout-recaptcha' + document.head.appendChild(script) + expect(document.getElementById('give-checkout-recaptcha')).not.toBeNull() + checkoutService.initializeRecaptcha.call($ctrl) + expect(document.querySelectorAll('#give-checkout-recaptcha')).toHaveLength(1) + }) +}) +