import {ProjectFixture} from 'sentry-fixture/project'; import {TeamFixture} from 'sentry-fixture/team'; import {SubscriptionFixture} from 'getsentry-test/fixtures/subscription'; import {initializeOrg} from 'sentry-test/initializeOrg'; import { render, renderGlobalModal, screen, userEvent, } from 'sentry-test/reactTestingLibrary'; import type {Organization} from 'sentry/types/organization'; import {browserHistory} from 'sentry/utils/browserHistory'; import {openUpsellModal} from 'getsentry/actionCreators/modal'; import UpsellProvider from 'getsentry/components/upsellProvider'; import SubscriptionStore from 'getsentry/stores/subscriptionStore'; import type {Subscription} from 'getsentry/types'; jest.mock('getsentry/actionCreators/modal'); const createRenderer = () => { return jest.fn(({onClick, defaultButtonText}) => (
{defaultButtonText}
)); }; describe('UpsellProvider', function () { let org!: Organization; let sub!: Subscription; let router: any; const populateOrg = (orgProps = {}, subProps = {}) => { ({router, organization: org} = initializeOrg({organization: orgProps})); sub = SubscriptionFixture({organization: org, ...subProps}); SubscriptionStore.set(org.slug, sub); // might re-load the org/sub after a trial starts MockApiClient.addMockResponse({ url: `/organizations/org-slug/`, body: org, }); MockApiClient.addMockResponse({ url: '/organizations/org-slug/projects/', body: [ProjectFixture()], }); MockApiClient.addMockResponse({ url: '/organizations/org-slug/teams/', body: [TeamFixture()], }); MockApiClient.addMockResponse({ url: `/subscriptions/${org.slug}/`, body: sub, }); return org; }; beforeEach(function () { MockApiClient.clearMockResponses(); (browserHistory.push as jest.Mock).mockClear(); }); it('with billing scope starts a trial if available', async function () { populateOrg({access: ['org:billing']}); const renderer = createRenderer(); const handleTrialStarted = jest.fn(); render( {renderer} , {router, organization: org} ); expect(screen.getByText('Start Trial')).toBeInTheDocument(); expect(renderer).toHaveBeenCalled(); // Setup to start subscription const startTrialMock = MockApiClient.addMockResponse({ url: `/customers/${org.slug}/`, method: 'PUT', }); await userEvent.click(screen.getByTestId('test-render')); await tick(); expect(startTrialMock).toHaveBeenCalled(); expect(handleTrialStarted).toHaveBeenCalled(); }); it('with billing scope redirect to sub page', async function () { populateOrg({access: ['org:billing']}, {canTrial: false}); const renderer = createRenderer(); render({renderer}, { router, organization: org, }); expect(screen.getByText('Upgrade Plan')).toBeInTheDocument(); expect(renderer).toHaveBeenCalled(); await userEvent.click(screen.getByTestId('test-render')); expect(browserHistory.push).toHaveBeenCalledWith( `/settings/${org.slug}/billing/checkout/?referrer=upsell-test-abc` ); }); it('no billing scope opens modal', async function () { populateOrg(); const renderer = createRenderer(); render({renderer}, { organization: org, }); expect(screen.getByText('Start Trial')).toBeInTheDocument(); await userEvent.click(screen.getByTestId('test-render')); expect(openUpsellModal).toHaveBeenCalled(); }); it('request trial with triggerMemberRequests', async function () { populateOrg(); const renderer = createRenderer(); const requestTrialMock = MockApiClient.addMockResponse({ url: `/organizations/${org.slug}/trial-request/`, method: 'POST', }); render( {renderer} , {router, organization: org} ); expect(screen.getByText('Request Trial')).toBeInTheDocument(); await userEvent.click(screen.getByTestId('test-render')); expect(requestTrialMock).toHaveBeenCalled(); }); it('request plan upgrade with triggerMemberRequests', async function () { populateOrg(undefined, {canTrial: false}); const renderer = createRenderer(); const requestTrialMock = MockApiClient.addMockResponse({ url: `/organizations/${org.slug}/plan-upgrade-request/`, method: 'POST', }); render( {renderer} , {router, organization: org} ); expect(screen.getByText('Request Upgrade')).toBeInTheDocument(); await userEvent.click(screen.getByTestId('test-render')); expect(requestTrialMock).toHaveBeenCalled(); }); it('opens modal with showConfirmation', async function () { populateOrg( { access: ['org:billing'], }, { canTrial: true, } ); const renderer = createRenderer(); const handleTrialStarted = jest.fn(); const startTrialMock = MockApiClient.addMockResponse({ url: `/customers/${org.slug}/`, method: 'PUT', }); const {waitForModalToHide} = renderGlobalModal(); render( {renderer} , {router, organization: org} ); await userEvent.click(screen.getByTestId('test-render')); await tick(); expect(screen.getByTestId('confirm-content')).toBeInTheDocument(); expect(handleTrialStarted).not.toHaveBeenCalled(); expect(startTrialMock).not.toHaveBeenCalled(); const button = screen.getByRole('button', {name: 'Start Trial'}); expect(button).toBeInTheDocument(); await userEvent.click(button); await waitForModalToHide(); expect(handleTrialStarted).toHaveBeenCalled(); expect(startTrialMock).toHaveBeenCalled(); }); it('render nothing if non-self serve for non-billing with triggering member requests', function () { populateOrg({}, {canSelfServe: false}); const renderer = createRenderer(); MockApiClient.addMockResponse({ url: `/organizations/${org.slug}/trial-request/`, method: 'POST', }); const {container} = render( {renderer} , {router, organization: org} ); expect(container).toBeEmptyDOMElement(); }); });