/* eslint-disable @typescript-eslint/no-var-requires */ const dispatchScriptEvent = (eventType: string, stripeJs?: boolean): void => { // StripeOnramp depends on Stripe.js being loaded first if (!stripeJs) { dispatchScriptEvent('load', true); } const injectedScript = document.querySelector( stripeJs ? 'script[src="https://js.stripe.com/v3"]' : 'script[src="https://crypto-js.stripe.com/crypto-onramp-outer.js"]' ); if (!injectedScript) { throw new Error('could not find Stripe.js script element'); } injectedScript.dispatchEvent(new Event(eventType)); }; describe('StripeOnramp module loader', () => { const ONRAMP_SCRIPT_SELECTOR = 'script[src^="https://crypto-js.stripe.com/crypto-onramp-outer.js"]'; const SCRIPT_SELECTOR = 'script[src^="https://js.stripe.com/v3"]'; afterEach(() => { const scripts = Array.from( document.querySelectorAll(`${SCRIPT_SELECTOR}, ${ONRAMP_SCRIPT_SELECTOR}`) ); for (const script of scripts) { if (script.parentElement) { script.parentElement.removeChild(script); } } delete window.Stripe; delete window.StripeOnramp; jest.resetModules(); }); it('injects the Stripe script as a side effect after a tick', () => { require('./index'); expect(document.querySelector(SCRIPT_SELECTOR)).toBe(null); expect(document.querySelector(ONRAMP_SCRIPT_SELECTOR)).toBe(null); return Promise.resolve().then(() => { expect(document.querySelector(SCRIPT_SELECTOR)).not.toBe(null); expect(document.querySelector(ONRAMP_SCRIPT_SELECTOR)).not.toBe(null); }); }); it('does not inject the script when StripeOnramp is already loaded', () => { require('./index'); window.Stripe = jest.fn((key) => ({key})) as any; window.StripeOnramp = jest.fn((key) => ({key})) as any; return new Promise((resolve) => setTimeout(resolve)).then(() => { expect(document.querySelector(SCRIPT_SELECTOR)).toBe(null); expect(document.querySelector(ONRAMP_SCRIPT_SELECTOR)).toBe(null); }); }); it('skip injecting Stripe.js when Stripe is already loaded', () => { require('./index'); window.Stripe = jest.fn((key) => ({key})) as any; expect(document.querySelector(SCRIPT_SELECTOR)).toBe(null); expect(document.querySelector(ONRAMP_SCRIPT_SELECTOR)).toBe(null); return new Promise((resolve) => setTimeout(resolve)).then(() => { expect(document.querySelector(SCRIPT_SELECTOR)).toBe(null); expect(document.querySelector(ONRAMP_SCRIPT_SELECTOR)).not.toBe(null); }); }); it('does not inject a duplicate script when one is already present', () => { require('./index'); const script = document.createElement('script'); script.src = 'https://crypto-js.stripe.com/crypto-onramp-outer.js'; document.body.appendChild(script); return Promise.resolve().then(() => { expect(document.querySelectorAll(ONRAMP_SCRIPT_SELECTOR)).toHaveLength(1); }); }); describe.each(['./index', './pure'])( 'loadStripeOnramp (%s.ts)', (requirePath) => { beforeEach(() => { jest.restoreAllMocks(); jest.spyOn(console, 'warn').mockReturnValue(); }); it('resolves loadStripe with Stripe object', async () => { const {loadStripeOnramp} = require(requirePath); const stripeOnrampPromise = loadStripeOnramp('pk_test_foo'); await new Promise((resolve) => setTimeout(resolve)); window.Stripe = jest.fn((key) => ({key})) as any; window.StripeOnramp = jest.fn((key) => ({key})) as any; dispatchScriptEvent('load'); return expect(stripeOnrampPromise).resolves.toEqual({ key: 'pk_test_foo', }); }); it('rejects when the script fails', async () => { const {loadStripeOnramp} = require(requirePath); const stripeOnrampPromise = loadStripeOnramp('pk_test_foo'); await Promise.resolve(); dispatchScriptEvent('error'); await expect(stripeOnrampPromise).rejects.toEqual( new Error('Failed to load StripeOnramp') ); expect(console.warn).not.toHaveBeenCalled(); }); it('rejects when the Stripe.js script fails', async () => { const {loadStripeOnramp} = require(requirePath); const stripeOnrampPromise = loadStripeOnramp('pk_test_foo'); await Promise.resolve(); dispatchScriptEvent('error', true); await expect(stripeOnrampPromise).rejects.toEqual( new Error('Failed to load Stripe.js') ); expect(console.warn).not.toHaveBeenCalled(); }); it('rejects when StripeOnramp is not added to the window for some reason', async () => { const {loadStripeOnramp} = require(requirePath); const stripeOnrampPromise = loadStripeOnramp('pk_test_foo'); await Promise.resolve(); dispatchScriptEvent('load'); return expect(stripeOnrampPromise).rejects.toEqual( new Error('StripeOnramp not available') ); }); } ); describe('loadStripeOnramp (index.ts)', () => { it('does not cause unhandled rejects when the script fails', async () => { require('./index'); await Promise.resolve(); dispatchScriptEvent('error'); // Turn the task loop to make sure the internal promise handler has been invoked await new Promise((resolve) => setTimeout(resolve, 0)); expect(console.warn).toHaveBeenCalledWith( new Error('Failed to load StripeOnramp') ); }); }); });