import React from 'react';
import {render, act} from '@testing-library/react';
import * as EmbeddedCheckoutProviderModule from './EmbeddedCheckoutProvider';
import {EmbeddedCheckout} from './EmbeddedCheckout';
import * as mocks from '../../test/mocks';
const {EmbeddedCheckoutProvider} = EmbeddedCheckoutProviderModule;
describe('EmbeddedCheckout on the client', () => {
let mockStripe: any;
let mockStripePromise: any;
let mockEmbeddedCheckout: any;
let mockEmbeddedCheckoutPromise: any;
const fakeClientSecret = 'cs_123_secret_abc';
const fetchClientSecret = () => Promise.resolve(fakeClientSecret);
const fakeOptions = {fetchClientSecret};
beforeEach(() => {
mockStripe = mocks.mockStripe();
mockStripePromise = Promise.resolve(mockStripe);
mockEmbeddedCheckout = mocks.mockEmbeddedCheckout();
mockEmbeddedCheckoutPromise = Promise.resolve(mockEmbeddedCheckout);
mockStripe.initEmbeddedCheckout.mockReturnValue(
mockEmbeddedCheckoutPromise
);
jest.spyOn(React, 'useLayoutEffect');
});
afterEach(() => {
jest.restoreAllMocks();
});
it('passes id to the wrapping DOM element', async () => {
const {container} = render(
);
await act(async () => await mockStripePromise);
const embeddedCheckoutDiv = container.firstChild as Element;
expect(embeddedCheckoutDiv.id).toBe('foo');
});
it('passes className to the wrapping DOM element', async () => {
const {container} = render(
);
await act(async () => await mockStripePromise);
const embeddedCheckoutDiv = container.firstChild as Element;
expect(embeddedCheckoutDiv).toHaveClass('bar');
});
it('mounts Embedded Checkout', async () => {
const {container} = render(
);
await act(() => mockEmbeddedCheckoutPromise);
expect(mockEmbeddedCheckout.mount).toBeCalledWith(container.firstChild);
});
it('does not mount until Embedded Checkout has been initialized', async () => {
// Render with no stripe instance and client secret
const {container, rerender} = render(
);
expect(mockEmbeddedCheckout.mount).not.toBeCalled();
// Set stripe prop
rerender(
);
expect(mockEmbeddedCheckout.mount).not.toBeCalled();
// Set fetchClientSecret
rerender(
);
expect(mockEmbeddedCheckout.mount).not.toBeCalled();
// Resolve initialization promise
await act(() => mockEmbeddedCheckoutPromise);
expect(mockEmbeddedCheckout.mount).toBeCalledWith(container.firstChild);
});
it('unmounts Embedded Checkout when the component unmounts', async () => {
const {container, rerender} = render(
);
await act(() => mockEmbeddedCheckoutPromise);
expect(mockEmbeddedCheckout.mount).toBeCalledWith(container.firstChild);
rerender(
);
expect(mockEmbeddedCheckout.unmount).toBeCalled();
});
it('does not throw when the Embedded Checkout instance is already destroyed when unmounting', async () => {
const {container, rerender} = render(
);
await act(() => mockEmbeddedCheckoutPromise);
expect(mockEmbeddedCheckout.mount).toBeCalledWith(container.firstChild);
mockEmbeddedCheckout.unmount.mockImplementation(() => {
throw new Error('instance has been destroyed');
});
expect(() => {
rerender(
);
}).not.toThrow();
});
it('still works with clientSecret param (deprecated)', async () => {
const {container} = render(
);
await act(() => mockEmbeddedCheckoutPromise);
expect(mockEmbeddedCheckout.mount).toBeCalledWith(container.firstChild);
});
});