import moment from 'moment-timezone'; import {OrganizationFixture} from 'sentry-fixture/organization'; import {MetricHistoryFixture} from 'getsentry-test/fixtures/metricHistory'; import { InvoicedSubscriptionFixture, SubscriptionFixture, } from 'getsentry-test/fixtures/subscription'; import { act, render, renderGlobalModal, screen, userEvent, waitFor, } from 'sentry-test/reactTestingLibrary'; import {textWithMarkupMatcher} from 'sentry-test/utils'; import ConfigStore from 'sentry/stores/configStore'; import ModalStore from 'sentry/stores/modalStore'; import {DataCategory} from 'sentry/types/core'; import {browserHistory} from 'sentry/utils/browserHistory'; import {PendingChangesFixture} from 'getsentry/__fixtures__/pendingChanges'; import {PlanFixture} from 'getsentry/__fixtures__/plan'; import { openForcedTrialModal, openPartnerPlanEndingModal, openTrialEndingModal, } from 'getsentry/actionCreators/modal'; import GSBanner from 'getsentry/components/gsBanner'; import SubscriptionStore from 'getsentry/stores/subscriptionStore'; jest.mock('getsentry/actionCreators/modal'); const guideMock = jest.requireMock('sentry/stores/guideStore'); jest.mock('sentry/stores/guideStore', () => ({ state: {}, })); describe('GSBanner', function () { beforeEach(() => { ModalStore.reset(); jest.clearAllMocks(); delete window.pendo; MockApiClient.clearMockResponses(); MockApiClient.addMockResponse({ method: 'POST', url: '/_experiment/log_exposure/', body: {}, }); MockApiClient.addMockResponse({ url: `/organizations/org-slug/projects/`, body: [], }); MockApiClient.addMockResponse({ url: `/organizations/org-slug/teams/`, body: [], }); MockApiClient.addMockResponse({ url: `/subscriptions/org-slug/`, body: {}, }); MockApiClient.addMockResponse({ url: `/organizations/org-slug/`, body: {}, }); [ 'another-slug-1', 'another-slug-2', 'another-slug-3', 'another-slug-4', 'org-slug', 'promotion-platform', 'forced-trial', 'soft-cap', 'grace-period', 'trial-ending', 'partner-plan-ending', 'suspended', 'exceeded', 'past-due', 'past-due-2', 'past-due-3', 'past-due-4', ].forEach(slug => { SubscriptionStore.set(slug, {}); MockApiClient.addMockResponse({ url: `/organizations/${slug}/promotions/trigger-check/`, method: 'POST', }); MockApiClient.addMockResponse({ method: 'GET', url: `/organizations/${slug}/prompts-activity/`, body: {}, }); }); }); it('renders empty', async function () { const organization = OrganizationFixture(); SubscriptionStore.set(organization.slug, {}); const {container} = render(, {organization}); // wait for requests to finish await act(tick); expect(container).toBeEmptyDOMElement(); }); it('shows overage notification banner and request more events btn for members', async function () { const organization = OrganizationFixture(); const subscription = SubscriptionFixture({ organization, plan: 'am2_team', categories: { errors: MetricHistoryFixture({usageExceeded: false}), transactions: MetricHistoryFixture({usageExceeded: true}), replays: MetricHistoryFixture({usageExceeded: false}), attachments: MetricHistoryFixture({usageExceeded: true}), monitorSeats: MetricHistoryFixture({usageExceeded: false}), }, canSelfServe: true, }); SubscriptionStore.set(organization.slug, subscription); render(, {organization}); expect( await screen.findByTestId('overage-banner-transaction-attachment') ).toBeInTheDocument(); expect(screen.getByText('performance unit')).toBeInTheDocument(); expect(screen.queryByText('transaction')).not.toBeInTheDocument(); expect(screen.getByTestId('btn-request_add_events')).toBeInTheDocument(); }); it('shows overage notification banner for multiple categories', async function () { const organization = OrganizationFixture(); const subscription = SubscriptionFixture({ organization, plan: 'am1_t', categories: { errors: MetricHistoryFixture({usageExceeded: true}), transactions: MetricHistoryFixture({usageExceeded: true}), replays: MetricHistoryFixture({usageExceeded: false}), attachments: MetricHistoryFixture({usageExceeded: true}), monitorSeats: MetricHistoryFixture({usageExceeded: true}), }, canSelfServe: true, }); SubscriptionStore.set(organization.slug, subscription); render(, {organization}); expect( await screen.findByTestId('overage-banner-error-transaction-attachment-monitorSeat') ).toBeInTheDocument(); expect(screen.getByText('transaction')).toBeInTheDocument(); expect(screen.getByText('cron monitor')).toBeInTheDocument(); expect(screen.queryByText('performance unit')).not.toBeInTheDocument(); }); it('does not show overage notification banner if is not self served', async function () { const organization = OrganizationFixture(); const subscription = SubscriptionFixture({ organization, plan: 'am1_t', categories: {attachments: MetricHistoryFixture({usageExceeded: true})}, canSelfServe: false, }); SubscriptionStore.set(organization.slug, subscription); const {container} = render(, {organization}); await act(tick); expect(container).toBeEmptyDOMElement(); }); it('does not show overage notification banner if active product trial', async function () { const organization = OrganizationFixture(); const subscription = SubscriptionFixture({ organization, plan: 'am2_team', categories: {replays: MetricHistoryFixture({usageExceeded: true})}, canSelfServe: true, productTrials: [ { category: DataCategory.REPLAYS, isStarted: true, reasonCode: 1001, startDate: moment().utc().subtract(10, 'days').format(), endDate: moment().utc().add(20, 'days').format(), }, ], }); SubscriptionStore.set(organization.slug, subscription); const {container} = render(, {organization}); await act(tick); expect(container).toBeEmptyDOMElement(); }); it('shows overage notification banner even if other category is on active trial', async function () { const organization = OrganizationFixture(); const subscription = SubscriptionFixture({ organization, plan: 'am2_team', categories: { attachments: MetricHistoryFixture({usageExceeded: true}), replays: MetricHistoryFixture({usageExceeded: true}), }, canSelfServe: true, productTrials: [ { category: DataCategory.REPLAYS, isStarted: true, reasonCode: 1001, startDate: moment().utc().subtract(10, 'days').format(), endDate: moment().utc().add(20, 'days').format(), }, ], }); SubscriptionStore.set(organization.slug, subscription); render(, {organization}); expect(await screen.findByTestId('overage-banner-attachment')).toBeInTheDocument(); expect(screen.queryByTestId('overage-banner-replay')).not.toBeInTheDocument(); }); it('shows start trial btn for billing admins if can trial', async function () { const organization = OrganizationFixture({ access: ['org:billing'], }); const subscription = SubscriptionFixture({ organization, plan: 'am1_f', categories: { errors: MetricHistoryFixture({usageExceeded: false}), transactions: MetricHistoryFixture({usageExceeded: true}), attachments: MetricHistoryFixture({usageExceeded: true}), }, canSelfServe: true, canTrial: true, }); SubscriptionStore.set(organization.slug, subscription); render(, {organization}); expect( await screen.findByTestId('overage-banner-transaction-attachment') ).toBeInTheDocument(); expect(screen.getByTestId('btn-start_trial')).toBeInTheDocument(); }); it('shows upgrade plan btn for free plans for admins', async function () { const organization = OrganizationFixture({ access: ['org:billing'], }); const subscription = SubscriptionFixture({ organization, plan: 'am1_f', categories: { errors: MetricHistoryFixture({usageExceeded: true}), transactions: MetricHistoryFixture({usageExceeded: false}), attachments: MetricHistoryFixture({usageExceeded: true}), }, canSelfServe: true, canTrial: false, }); SubscriptionStore.set(organization.slug, subscription); render(, {organization}); expect( await screen.findByTestId('overage-banner-error-attachment') ).toBeInTheDocument(); expect(screen.getByRole('button', {name: /upgrade plan/i})).toBeInTheDocument(); }); it('shows add quota btn for paid plans for admins', async function () { const organization = OrganizationFixture({ access: ['org:billing'], }); const subscription = SubscriptionFixture({ organization, plan: 'am1_team', categories: { errors: MetricHistoryFixture({usageExceeded: true}), transactions: MetricHistoryFixture({usageExceeded: true}), replays: MetricHistoryFixture({usageExceeded: true}), attachments: MetricHistoryFixture({usageExceeded: true}), monitorSeats: MetricHistoryFixture({usageExceeded: true}), }, canSelfServe: true, canTrial: false, }); SubscriptionStore.set(organization.slug, subscription); render(, {organization}); expect( await screen.findByTestId( 'overage-banner-error-transaction-replay-attachment-monitorSeat' ) ).toBeInTheDocument(); expect( screen.getByRole('button', {name: /increase reserved limits/i}) ).toBeInTheDocument(); }); it('shows add quota button for paid plans without active product trial', async function () { const organization = OrganizationFixture({ access: ['org:billing'], }); const subscription = SubscriptionFixture({ organization, plan: 'am3_team', categories: { errors: MetricHistoryFixture({usageExceeded: false}), spans: MetricHistoryFixture({usageExceeded: true}), replays: MetricHistoryFixture({usageExceeded: false}), attachments: MetricHistoryFixture({usageExceeded: false}), monitorSeats: MetricHistoryFixture({usageExceeded: false}), profileDuration: MetricHistoryFixture({usageExceeded: false}), }, canSelfServe: true, productTrials: [ { category: 'spans', reasonCode: 1001, isStarted: false, lengthDays: undefined, startDate: undefined, endDate: undefined, }, ], }); SubscriptionStore.set(organization.slug, subscription); render(, {organization}); expect( await screen.findByRole('button', {name: /increase reserved limits/i}) ).toBeInTheDocument(); }); it('does not show add quota button for paid plans with active product trial', async function () { const organization = OrganizationFixture({ access: ['org:billing'], }); const subscription = SubscriptionFixture({ organization, plan: 'am3_team', categories: { errors: MetricHistoryFixture({usageExceeded: false}), spans: MetricHistoryFixture({usageExceeded: true}), replays: MetricHistoryFixture({usageExceeded: false}), attachments: MetricHistoryFixture({usageExceeded: false}), monitorSeats: MetricHistoryFixture({usageExceeded: false}), profileDuration: MetricHistoryFixture({usageExceeded: false}), }, canSelfServe: true, productTrials: [ { category: 'spans', reasonCode: 1001, isStarted: true, lengthDays: 20, startDate: moment().utc().subtract(10, 'days').format(), endDate: moment().utc().add(10, 'days').format(), }, ], }); SubscriptionStore.set(organization.slug, subscription); render(, {organization}); await act(tick); expect( screen.queryByRole('button', {name: /increase reserved limits/i}) ).not.toBeInTheDocument(); }); it('user can dismiss notification', async function () { const organization = OrganizationFixture(); const subscription = SubscriptionFixture({ organization, plan: 'am1_t', categories: { errors: MetricHistoryFixture({usageExceeded: true}), transactions: MetricHistoryFixture({usageExceeded: true}), replays: MetricHistoryFixture({usageExceeded: true}), attachments: MetricHistoryFixture({usageExceeded: true}), monitorSeats: MetricHistoryFixture({usageExceeded: true}), spans: MetricHistoryFixture({usageExceeded: true}), profileDuration: MetricHistoryFixture({usageExceeded: true}), }, canSelfServe: true, }); SubscriptionStore.set(organization.slug, subscription); const snoozeEndpoint = MockApiClient.addMockResponse({ method: 'PUT', url: `/organizations/${organization.slug}/prompts-activity/`, body: {}, }); render(, {organization}); expect( await screen.findByTestId( 'overage-banner-error-transaction-replay-attachment-monitorSeat-span-profileDuration' ) ).toBeInTheDocument(); expect(screen.getByTestId('btn-overage-notification-snooze')).toBeInTheDocument(); await userEvent.click(screen.getByTestId('btn-overage-notification-snooze')); for (const feature of [ 'errors_overage_alert', 'transactions_overage_alert', 'replays_overage_alert', 'attachments_overage_alert', 'spans_overage_alert', 'profile_duration_overage_alert', ]) { expect(snoozeEndpoint).toHaveBeenCalledWith( `/organizations/${organization.slug}/prompts-activity/`, expect.objectContaining({ data: { feature, organization_id: organization.id, status: 'snoozed', }, }) ); } expect(screen.queryByTestId(/overage-banner/)).not.toBeInTheDocument(); }); it('do not show banner when dismissed', async function () { const organization = OrganizationFixture(); const snoozeTime = new Date('2020-02-02'); snoozeTime.setHours(23, 59, 59); MockApiClient.addMockResponse({ method: 'GET', url: `/organizations/${organization.slug}/prompts-activity/`, body: { features: { transactions_overage_alert: { snoozed_ts: snoozeTime.getTime() / 1000, }, replays_overage_alert: { snoozed_ts: snoozeTime.getTime() / 1000, }, }, }, }); const subscription = SubscriptionFixture({ organization, plan: 'am1_t', categories: { errors: MetricHistoryFixture({usageExceeded: false}), transactions: MetricHistoryFixture({usageExceeded: true}), replays: MetricHistoryFixture({usageExceeded: true}), attachments: MetricHistoryFixture({usageExceeded: false}), monitorSeats: MetricHistoryFixture({usageExceeded: false}), }, canSelfServe: true, onDemandPeriodEnd: '2020-02-02', }); SubscriptionStore.set(organization.slug, subscription); const {container} = render(, {organization}); await act(tick); expect(container).toBeEmptyDOMElement(); }); it('shows add quota btn for paid plans for admins for warnings', async function () { const organization = OrganizationFixture({ access: ['org:billing'], slug: 'another-slug-1', }); const subscription = SubscriptionFixture({ organization, plan: 'am1_team', categories: { errors: MetricHistoryFixture({sentUsageWarning: true}), transactions: MetricHistoryFixture({sentUsageWarning: false}), replays: MetricHistoryFixture({usageExceeded: false}), attachments: MetricHistoryFixture({sentUsageWarning: false}), monitorSeats: MetricHistoryFixture({sentUsageWarning: false}), }, canSelfServe: true, }); SubscriptionStore.set(organization.slug, subscription); render(, {organization}); expect( await screen.findByRole('button', {name: /increase reserved limits/i}) ).toBeInTheDocument(); }); it('shows add quota button for paid plans warnings with no active product trial', async function () { const organization = OrganizationFixture({ access: ['org:billing'], slug: 'another-slug-1', }); const subscription = SubscriptionFixture({ organization, plan: 'am3_team', categories: { errors: MetricHistoryFixture({sentUsageWarning: false}), spans: MetricHistoryFixture({sentUsageWarning: false}), replays: MetricHistoryFixture({usageExceeded: true}), attachments: MetricHistoryFixture({sentUsageWarning: false}), monitorSeats: MetricHistoryFixture({sentUsageWarning: false}), profileDuration: MetricHistoryFixture({sentUsageWarning: false}), }, canSelfServe: true, productTrials: [ { category: 'replays', reasonCode: 1001, isStarted: false, lengthDays: undefined, startDate: undefined, endDate: undefined, }, ], }); SubscriptionStore.set(organization.slug, subscription); render(, {organization}); expect( await screen.findByRole('button', {name: /increase reserved limits/i}) ).toBeInTheDocument(); }); it('does not show add quota btn for paid plans warnings with active product trial', async function () { const organization = OrganizationFixture({ access: ['org:billing'], slug: 'another-slug-1', }); const subscription = SubscriptionFixture({ organization, plan: 'am3_team', categories: { errors: MetricHistoryFixture({sentUsageWarning: false}), spans: MetricHistoryFixture({sentUsageWarning: false}), replays: MetricHistoryFixture({usageExceeded: true}), attachments: MetricHistoryFixture({sentUsageWarning: false}), monitorSeats: MetricHistoryFixture({sentUsageWarning: false}), }, canSelfServe: true, productTrials: [ { category: 'replays', reasonCode: 1001, isStarted: true, lengthDays: 20, startDate: moment().utc().subtract(10, 'days').format(), endDate: moment().utc().add(10, 'days').format(), }, ], }); SubscriptionStore.set(organization.slug, subscription); render(, {organization}); await act(tick); expect( screen.queryByRole('button', {name: /increase reserved limits/i}) ).not.toBeInTheDocument(); }); it('does not show warning if on-demand is set', async function () { const organization = OrganizationFixture({ access: ['org:billing'], slug: 'another-slug-1', }); const subscription = SubscriptionFixture({ organization, plan: 'am1_team', categories: {errors: MetricHistoryFixture({sentUsageWarning: true})}, canSelfServe: true, onDemandMaxSpend: 10, }); SubscriptionStore.set(organization.slug, subscription); render(, {organization}); await act(tick); expect( screen.queryByRole('button', {name: /increase reserved limits/i}) ).not.toBeInTheDocument(); }); it('does not show warning if active product trial', async function () { const organization = OrganizationFixture({ access: ['org:billing'], slug: 'another-slug-1', }); const subscription = SubscriptionFixture({ organization, plan: 'am1_team', categories: {monitorSeats: MetricHistoryFixture({sentUsageWarning: true})}, canSelfServe: true, productTrials: [ { category: DataCategory.MONITOR_SEATS, isStarted: true, reasonCode: 1001, startDate: moment().utc().subtract(10, 'days').format(), endDate: moment().utc().add(20, 'days').format(), }, ], }); SubscriptionStore.set(organization.slug, subscription); const {container} = render(, {organization}); await act(tick); expect(container).toBeEmptyDOMElement(); }); it('shows warning even if other category is on active trial', async function () { const organization = OrganizationFixture({ access: ['org:billing'], slug: 'another-slug-1', }); const subscription = SubscriptionFixture({ organization, plan: 'am1_team', categories: { errors: MetricHistoryFixture({sentUsageWarning: true}), monitorSeats: MetricHistoryFixture({sentUsageWarning: true}), }, canSelfServe: true, productTrials: [ { category: DataCategory.MONITOR_SEATS, isStarted: true, reasonCode: 1001, startDate: moment().utc().subtract(10, 'days').format(), endDate: moment().utc().add(20, 'days').format(), }, ], }); SubscriptionStore.set(organization.slug, subscription); render(, {organization}); expect(await screen.findByTestId('overage-banner-error')).toBeInTheDocument(); expect(screen.queryByTestId('overage-banner-monitorSeat')).not.toBeInTheDocument(); }); it('does not show alert if hasOverageNotificationsDisabled is set', async function () { const organization = OrganizationFixture({ access: ['org:billing'], slug: 'another-slug-2', }); const subscription = SubscriptionFixture({ organization, plan: 'am1_team', categories: { errors: MetricHistoryFixture({usageExceeded: true}), transactions: MetricHistoryFixture({usageExceeded: true}), replays: MetricHistoryFixture({usageExceeded: true}), attachments: MetricHistoryFixture({usageExceeded: true}), monitorSeats: MetricHistoryFixture({usageExceeded: true}), }, canSelfServe: true, hasOverageNotificationsDisabled: true, }); SubscriptionStore.set(organization.slug, subscription); render(, {organization}); await act(tick); expect( screen.queryByRole('button', {name: /increase reserved limits/i}) ).not.toBeInTheDocument(); }); it('does not show notification if hasOverageNotificationsDisabled is set', async function () { const organization = OrganizationFixture({ access: ['org:billing'], slug: 'another-slug-3', }); const subscription = SubscriptionFixture({ organization, plan: 'am1_team', categories: { errors: MetricHistoryFixture({usageExceeded: true}), transactions: MetricHistoryFixture({usageExceeded: true}), replays: MetricHistoryFixture({usageExceeded: true}), attachments: MetricHistoryFixture({usageExceeded: true}), monitorSeats: MetricHistoryFixture({usageExceeded: true}), }, canSelfServe: true, hasOverageNotificationsDisabled: true, }); SubscriptionStore.set(organization.slug, subscription); render(, {organization}); await act(tick); expect( screen.queryByRole('button', {name: /increase reserved limits/i}) ).not.toBeInTheDocument(); }); it('does not show warning if hasOverageNotificationsDisabled is set', async function () { const organization = OrganizationFixture({ access: ['org:billing'], slug: 'another-slug-4', }); const subscription = SubscriptionFixture({ organization, plan: 'am1_team', categories: { errors: MetricHistoryFixture({ category: DataCategory.ERRORS, sentUsageWarning: true, }), transactions: MetricHistoryFixture({ category: DataCategory.TRANSACTIONS, sentUsageWarning: true, }), replays: MetricHistoryFixture({ category: DataCategory.REPLAYS, sentUsageWarning: true, }), attachments: MetricHistoryFixture({ category: DataCategory.ATTACHMENTS, sentUsageWarning: true, }), monitorSeats: MetricHistoryFixture({ category: DataCategory.MONITOR_SEATS, sentUsageWarning: true, }), }, canSelfServe: true, hasOverageNotificationsDisabled: true, }); SubscriptionStore.set(organization.slug, subscription); render(, { organization, }); await act(tick); expect(screen.queryByTestId('overage-banner-error')).not.toBeInTheDocument(); expect(screen.queryByTestId('overage-banner-transaction')).not.toBeInTheDocument(); expect(screen.queryByTestId('overage-banner-replay')).not.toBeInTheDocument(); expect(screen.queryByTestId('overage-banner-attachment')).not.toBeInTheDocument(); expect(screen.queryByTestId('overage-banner-monitorSeat')).not.toBeInTheDocument(); }); it('renders suspension modal', async function () { const organization = OrganizationFixture({slug: 'suspended'}); SubscriptionStore.set( organization.slug, SubscriptionFixture({organization, isSuspended: true}) ); render(, {organization}); renderGlobalModal(); expect(await screen.findByRole('dialog')).toBeInTheDocument(); }); it('renders usage exceeded modal', async function () { const organization = OrganizationFixture({slug: 'exceeded'}); SubscriptionStore.set( organization.slug, SubscriptionFixture({organization, usageExceeded: true}) ); render(, {organization}); renderGlobalModal(); expect(await screen.findByTestId('modal-usage-exceeded')).toBeInTheDocument(); }); it('renders grace period modal with billing access', async function () { const organization = OrganizationFixture({ slug: 'grace-period', access: ['org:billing'], }); SubscriptionStore.set( organization.slug, SubscriptionFixture({organization, isGracePeriod: true}) ); render(, {organization}); renderGlobalModal(); expect(await screen.findByTestId('modal-grace-period')).toBeInTheDocument(); }); it('does not render overage banner without grace period and usage exceeded', async function () { const organization = OrganizationFixture({ slug: 'soft-cap', access: ['org:billing'], }); SubscriptionStore.set( organization.slug, SubscriptionFixture({ organization, isGracePeriod: false, usageExceeded: false, }) ); render(, {organization}); await act(tick); expect(screen.queryByTestId('grace-period-banner')).not.toBeInTheDocument(); expect(screen.queryByTestId('usage-exceeded-banner')).not.toBeInTheDocument(); expect(screen.queryByTestId('modal-usage-exceeded')).not.toBeInTheDocument(); expect(screen.queryByTestId('modal-grace-period')).not.toBeInTheDocument(); }); it('opens the trialEndingModal within 3 days of ending', async function () { const now = moment(); const organization = OrganizationFixture({ slug: 'trial-ending', }); SubscriptionStore.set( organization.slug, SubscriptionFixture({ organization, isTrial: true, hasDismissedTrialEndingNotice: false, plan: 'am1_t', trialEnd: now.add(2, 'day').toString(), }) ); render(, {organization}); await waitFor(() => expect(openTrialEndingModal).toHaveBeenCalled()); }); it('does not display trial ending modal more than 3 days', async function () { const now = moment(); const organization = OrganizationFixture({}); SubscriptionStore.set( organization.slug, SubscriptionFixture({ organization, hasDismissedTrialEndingNotice: false, plan: 'am1_t', trialEnd: now.add(5, 'day').toString(), }) ); render(, {organization}); await act(tick); expect(openTrialEndingModal).not.toHaveBeenCalled(); }); it('does not display trial ending modal to free plan', async function () { const organization = OrganizationFixture({}); SubscriptionStore.set( organization.slug, SubscriptionFixture({ organization, hasDismissedTrialEndingNotice: false, plan: 'am1_f', }) ); render(, {organization}); await act(tick); expect(openTrialEndingModal).not.toHaveBeenCalled(); }); it('does not display trial ending modal to plan trial', async function () { const now = moment(); const organization = OrganizationFixture({}); SubscriptionStore.set( organization.slug, SubscriptionFixture({ organization, hasDismissedTrialEndingNotice: false, plan: 'am1_team', trialEnd: now.add(2, 'day').toString(), }) ); render(, {organization}); await act(tick); expect(openTrialEndingModal).not.toHaveBeenCalled(); }); it('does not display trial ending modal to enterprise trial', async function () { const now = moment(); const organization = OrganizationFixture({ slug: 'trial-ending', }); SubscriptionStore.set( organization.slug, SubscriptionFixture({ organization, isTrial: true, hasDismissedTrialEndingNotice: false, plan: 'am1_business', trialEnd: now.add(2, 'day').toString(), isEnterpriseTrial: true, }) ); render(, {organization}); await act(tick); expect(openTrialEndingModal).not.toHaveBeenCalled(); }); it('opens the partnerPlanEndingModal within 30 days of ending', async function () { const now = moment(); const organization = OrganizationFixture({ slug: 'partner-plan-ending', features: ['partner-billing-migration'], }); SubscriptionStore.set( organization.slug, SubscriptionFixture({ organization, contractPeriodEnd: now.add(30, 'day').toString(), isTrial: true, plan: 'am2_sponsored_team_auf', partner: { externalId: '123', name: 'FOO', partnership: { id: 'FOO', displayName: 'FOO', supportNote: '', }, isActive: true, }, }) ); render(, {organization}); await waitFor(() => expect(openPartnerPlanEndingModal).toHaveBeenCalled()); }); it('opens the partnerPlanEndingModal within 7 days of ending', async function () { const now = moment(); const organization = OrganizationFixture({ slug: 'partner-plan-ending', features: ['partner-billing-migration'], }); SubscriptionStore.set( organization.slug, SubscriptionFixture({ organization, contractPeriodEnd: now.add(7, 'day').toString(), isTrial: true, plan: 'am2_sponsored_team_auf', partner: { externalId: '123', name: 'FOO', partnership: { id: 'FOO', displayName: 'FOO', supportNote: '', }, isActive: true, }, }) ); render(, {organization}); await waitFor(() => expect(openPartnerPlanEndingModal).toHaveBeenCalled()); }); it('opens the partnerPlanEndingModal with 2 days left', async function () { const now = moment(); const organization = OrganizationFixture({ slug: 'partner-plan-ending', features: ['partner-billing-migration'], }); SubscriptionStore.set( organization.slug, SubscriptionFixture({ organization, contractPeriodEnd: now.add(2, 'days').toString(), isTrial: true, plan: 'am2_sponsored_team_auf', partner: { externalId: '123', name: 'FOO', partnership: { id: 'FOO', displayName: 'FOO', supportNote: '', }, isActive: true, }, }) ); render(, {organization}); await waitFor(() => expect(openPartnerPlanEndingModal).toHaveBeenCalled()); }); it('opens the partnerPlanEndingModal on day that plan ends', async function () { const now = moment(); const organization = OrganizationFixture({ slug: 'partner-plan-ending', features: ['partner-billing-migration'], }); SubscriptionStore.set( organization.slug, SubscriptionFixture({ organization, contractPeriodEnd: now.toString(), isTrial: true, plan: 'am2_sponsored_team_auf', partner: { externalId: '123', name: 'FOO', partnership: { id: 'FOO', displayName: 'FOO', supportNote: '', }, isActive: true, }, }) ); render(, {organization}); await waitFor(() => expect(openPartnerPlanEndingModal).toHaveBeenCalled()); }); it('does not open the partnerPlanEndingModal without feature flag', async function () { const now = moment(); const organization = OrganizationFixture({ slug: 'partner-plan-ending', }); SubscriptionStore.set( organization.slug, SubscriptionFixture({ organization, contractPeriodEnd: now.add(7, 'day').toString(), isTrial: true, plan: 'am2_sponsored_team_auf', partner: { externalId: '123', name: 'FOO', partnership: { id: 'FOO', displayName: 'FOO', supportNote: '', }, isActive: true, }, }) ); render(, {organization}); await waitFor(() => expect(openPartnerPlanEndingModal).not.toHaveBeenCalled()); }); it('does not open the partnerPlanEndingModal with pending upgrade', async function () { const now = moment(); const organization = OrganizationFixture({ slug: 'partner-plan-ending', features: ['partner-billing-migration'], }); SubscriptionStore.set( organization.slug, SubscriptionFixture({ organization, contractPeriodEnd: now.add(7, 'day').toString(), isTrial: true, plan: 'am2_sponsored_team_auf', partner: { externalId: '123', name: 'FOO', partnership: { id: 'FOO', displayName: 'FOO', supportNote: '', }, isActive: true, }, pendingChanges: PendingChangesFixture({ plan: 'am3_business', planDetails: PlanFixture({ name: 'Business', price: 100, }), }), }) ); render(, {organization}); await waitFor(() => expect(openPartnerPlanEndingModal).not.toHaveBeenCalled()); }); it('opens the partnerPlanEndingModal with pending downgrade', async function () { const now = moment(); const organization = OrganizationFixture({ slug: 'partner-plan-ending', features: ['partner-billing-migration'], }); SubscriptionStore.set( organization.slug, SubscriptionFixture({ organization, contractPeriodEnd: now.add(7, 'day').toString(), isTrial: true, plan: 'am2_sponsored_team_auf', partner: { externalId: '123', name: 'FOO', partnership: { id: 'FOO', displayName: 'FOO', supportNote: '', }, isActive: true, }, pendingChanges: PendingChangesFixture({ plan: 'am3_f', planDetails: PlanFixture({ name: 'Developer', price: 0, }), }), }) ); render(, {organization}); await waitFor(() => expect(openPartnerPlanEndingModal).toHaveBeenCalled()); }); it('does not open the partnerPlanEndingModal with more than 30 days before ending', async function () { const now = moment(); const organization = OrganizationFixture({ slug: 'partner-plan-ending', features: ['partner-billing-migration'], }); SubscriptionStore.set( organization.slug, SubscriptionFixture({ organization, contractPeriodEnd: now.add(31, 'day').toString(), isTrial: true, plan: 'am2_sponsored_team_auf', partner: { externalId: '123', name: 'FOO', partnership: { id: 'FOO', displayName: 'FOO', supportNote: '', }, isActive: true, }, }) ); render(, {organization}); await waitFor(() => expect(openPartnerPlanEndingModal).not.toHaveBeenCalled()); }); it('does not open the partnerPlanEndingModal if dismissed', async function () { const now = moment(); const organization = OrganizationFixture({ slug: 'partner-plan-ending', features: ['partner-billing-migration'], }); MockApiClient.addMockResponse({ method: 'GET', url: `/organizations/${organization.slug}/prompts-activity/`, body: { data: { dismissed_ts: moment().subtract(2, 'days').unix(), }, }, }); SubscriptionStore.set( organization.slug, SubscriptionFixture({ organization, contractPeriodEnd: now.add(20, 'day').toString(), isTrial: true, plan: 'am2_sponsored_team_auf', partner: { externalId: '123', name: 'FOO', partnership: { id: 'FOO', displayName: 'FOO', supportNote: '', }, isActive: true, }, }) ); render(, {organization}); await waitFor(() => expect(openPartnerPlanEndingModal).not.toHaveBeenCalled()); }); it('opens partnerPlanEndingModal if dismissed in different time period', async function () { const now = moment(); const organization = OrganizationFixture({ slug: 'partner-plan-ending', features: ['partner-billing-migration'], }); MockApiClient.addMockResponse({ method: 'GET', url: `/organizations/${organization.slug}/prompts-activity/`, body: { data: { dismissed_ts: moment().subtract(20, 'days').unix(), }, }, }); SubscriptionStore.set( organization.slug, SubscriptionFixture({ organization, contractPeriodEnd: now.add(1, 'day').toString(), isTrial: true, plan: 'am2_sponsored_team_auf', partner: { externalId: '123', name: 'FOO', partnership: { id: 'FOO', displayName: 'FOO', supportNote: '', }, isActive: true, }, }) ); render(, {organization}); await waitFor(() => expect(openPartnerPlanEndingModal).toHaveBeenCalled()); }); it('opens partnerPlanEndingModal if dismissed with 2 days left on day plan ends', async function () { const now = moment(); const organization = OrganizationFixture({ slug: 'partner-plan-ending', features: ['partner-billing-migration'], }); MockApiClient.addMockResponse({ method: 'GET', url: `/organizations/${organization.slug}/prompts-activity/`, body: { data: { dismissed_ts: moment().subtract(2, 'days').unix(), }, }, }); SubscriptionStore.set( organization.slug, SubscriptionFixture({ organization, contractPeriodEnd: now.toString(), isTrial: true, plan: 'am2_sponsored_team_auf', partner: { externalId: '123', name: 'FOO', partnership: { id: 'FOO', displayName: 'FOO', supportNote: '', }, isActive: true, }, }) ); render(, {organization}); await waitFor(() => expect(openPartnerPlanEndingModal).toHaveBeenCalled()); }); it('does not open partnerPlanEndingModal if dismissed with two days left and logs in with one day left', async function () { const now = moment(); const organization = OrganizationFixture({ slug: 'partner-plan-ending', features: ['partner-billing-migration'], }); MockApiClient.addMockResponse({ method: 'GET', url: `/organizations/${organization.slug}/prompts-activity/`, body: { data: { dismissed_ts: moment().subtract(1, 'days').unix(), }, }, }); SubscriptionStore.set( organization.slug, SubscriptionFixture({ organization, contractPeriodEnd: now.add(1, 'day').toString(), isTrial: true, plan: 'am2_sponsored_team_auf', partner: { externalId: '123', name: 'FOO', partnership: { id: 'FOO', displayName: 'FOO', supportNote: '', }, isActive: true, }, }) ); render(, {organization}); await waitFor(() => expect(openPartnerPlanEndingModal).not.toHaveBeenCalled()); }); it('show disabled member header', async function () { const organization = OrganizationFixture({ access: ['org:billing'], }); SubscriptionStore.set( organization.slug, SubscriptionFixture({ organization, membersDeactivatedFromLimit: 2, }) ); render(, {organization}); expect( await screen.findByText(textWithMarkupMatcher(/2 members have been deactivated/i)) ).toBeInTheDocument(); }); it('loads pendo', async function () { guideMock.state.currentGuide = false; const organization = OrganizationFixture({ slug: 'forced-trial', orgRole: 'admin', }); SubscriptionStore.set( organization.slug, SubscriptionFixture({ organization, plan: 'am1_business', onDemandMaxSpend: 1000, totalMembers: 26, reservedErrors: 5_000_000, reservedTransactions: 10_000_001, planDetails: PlanFixture({ totalPrice: 100_000 * 12, billingInterval: 'annual', }), }) ); MockApiClient.addMockResponse({ method: 'POST', url: `/organizations/${organization.slug}/promotions/lorem-ipsum/claim/`, body: {}, }); const now = moment(); const promotionData = { availablePromotions: [ { endDate: null, name: 'Lorem Ipsum', slug: 'lorem-ipsum', startDate: now.add(-14, 'day'), timeLimit: 'null', autoOptIn: true, }, ], }; MockApiClient.addMockResponse({ method: 'POST', url: `/organizations/${organization.slug}/promotions/trigger-check/`, body: promotionData, }); window.pendo = { initialize: jest.fn(), }; MockApiClient.addMockResponse({ method: 'GET', url: `/organizations/${organization.slug}/pendo-details/`, body: { userDetails: { fieldA: 'valueA', }, organizationDetails: { fieldB: 'valueB', }, }, }); const user = ConfigStore.get('user'); render(, { organization, }); await waitFor(() => { expect(window.pendo.initialize).toHaveBeenCalledWith({ visitor: { id: `${organization.id}.${user.id}`, userId: user.id, role: 'admin', isDarkMode: false, fieldA: 'valueA', }, account: expect.objectContaining({ id: organization.id, hasOnDemandSpend: true, reservedErrors: 'indigo', reservedTransactions: 'violet', totalMembers: 'blue', arr: 'yellow', fieldB: 'valueB', plan: 'am1_business', }), guides: { delay: false, }, }); }); delete window.pendo; }); it('delay pendo guides if other guides are active', async function () { guideMock.state.currentGuide = true; const organization = OrganizationFixture(); SubscriptionStore.set( organization.slug, SubscriptionFixture({ organization, }) ); MockApiClient.addMockResponse({ method: 'POST', url: `/organizations/${organization.slug}/promotions/lorem-ipsum/claim/`, body: {}, }); window.pendo = { initialize: jest.fn(), }; const now = moment(); const promotionData = { availablePromotions: [ { endDate: null, name: 'Lorem Ipsum', slug: 'lorem-ipsum', startDate: now.add(-14, 'day'), timeLimit: 'null', autoOptIn: true, }, ], }; MockApiClient.addMockResponse({ method: 'POST', url: `/organizations/${organization.slug}/promotions/trigger-check/`, body: promotionData, }); MockApiClient.addMockResponse({ method: 'GET', url: `/organizations/${organization.slug}/pendo-details/`, body: { userDetails: { fieldA: 'valueA', }, organizationDetails: { fieldB: 'valueB', }, }, }); render(, { organization, }); await waitFor(() => { expect(window.pendo.initialize).toHaveBeenCalledWith( expect.objectContaining({ guides: { delay: true, }, }) ); }); }); it('forced trial automatically starts', async function () { const organization = OrganizationFixture({ access: ['org:billing'], }); const subscription = SubscriptionFixture({ plan: 'am1_f', organization, totalLicenses: 1, usedLicenses: 2, }); SubscriptionStore.set(organization.slug, subscription); const mockForceTrial = MockApiClient.addMockResponse({ method: 'POST', url: `/organizations/${organization.slug}/over-member-limit-trial/`, body: {}, }); render(, { organization, }); await waitFor(() => { expect(mockForceTrial).toHaveBeenCalledWith( `/organizations/${organization.slug}/over-member-limit-trial/`, expect.objectContaining({ method: 'POST', }) ); }); expect(openForcedTrialModal).toHaveBeenCalled(); }); it('forced trial automatically starts for restricted integration', async function () { const organization = OrganizationFixture({ access: ['org:billing'], }); SubscriptionStore.set( organization.slug, SubscriptionFixture({ plan: 'am1_f', organization, totalLicenses: 1, usedLicenses: 1, hasRestrictedIntegration: true, }) ); const mockForceTrial = MockApiClient.addMockResponse({ method: 'POST', url: `/organizations/${organization.slug}/restricted-integration-trial/`, body: {}, }); render(, { organization, }); await waitFor(() => { expect(mockForceTrial).toHaveBeenCalledWith( `/organizations/${organization.slug}/restricted-integration-trial/`, expect.objectContaining({ method: 'POST', }) ); }); expect(openForcedTrialModal).toHaveBeenCalled(); }); it('open the forced trial modal', async function () { const now = moment(); const organization = OrganizationFixture({ slug: 'forced-trial', }); SubscriptionStore.set( organization.slug, SubscriptionFixture({ organization, hasDismissedForcedTrialNotice: false, plan: 'am1_t', trialEnd: now.add(14, 'day').toString(), isForcedTrial: true, isTrial: true, }) ); render(, { organization, }); await waitFor(() => expect(openForcedTrialModal).toHaveBeenCalled()); }); it('does not open forced trial modal if dismissed', async function () { const now = moment(); const organization = OrganizationFixture({ slug: 'forced-trial', }); SubscriptionStore.set( organization.slug, SubscriptionFixture({ organization, hasDismissedForcedTrialNotice: true, plan: 'am1_t', trialEnd: now.add(14, 'day').toString(), isForcedTrial: true, isTrial: true, }) ); render(, { organization, }); await act(tick); expect(openForcedTrialModal).not.toHaveBeenCalled(); }); it('activates the first available promotion', async function () { const now = moment(); const organization = OrganizationFixture({ slug: 'promotion-platform', }); const promotionData = { availablePromotions: [ { endDate: null, name: 'Lorem Ipsum', slug: 'lorem-ipsum', startDate: now.add(-14, 'day'), timeLimit: 'null', autoOptIn: true, }, ], }; MockApiClient.addMockResponse({ method: 'POST', url: `/organizations/${organization.slug}/promotions/trigger-check/`, body: promotionData, }); const activatePromoEndpoint = MockApiClient.addMockResponse({ method: 'POST', url: `/organizations/${organization.slug}/promotions/lorem-ipsum/claim/`, body: {}, }); SubscriptionStore.set( organization.slug, SubscriptionFixture({ organization, plan: 'am1_team', }) ); render(, { organization, }); await waitFor(() => { expect(activatePromoEndpoint).toHaveBeenCalledWith( `/organizations/${organization.slug}/promotions/lorem-ipsum/claim/`, expect.objectContaining({ method: 'POST', }) ); }); }); it("doesn't activate non auto-opt-in promos", async function () { const now = moment(); const organization = OrganizationFixture({ slug: 'promotion-platform', }); const promotionData = { availablePromotions: [ { endDate: null, name: 'Lorem Ipsum', slug: 'lorem-ipsum', startDate: now.add(-14, 'day'), timeLimit: 'null', autoOptIn: false, }, ], }; MockApiClient.addMockResponse({ method: 'POST', url: `/organizations/${organization.slug}/promotions/trigger-check/`, body: promotionData, }); const activatePromoEndpoint = MockApiClient.addMockResponse({ method: 'POST', url: `/organizations/${organization.slug}/promotions/lorem-ipsum/claim/`, body: {}, }); SubscriptionStore.set( organization.slug, SubscriptionFixture({ organization, plan: 'am1_team', }) ); render(, { organization, }); await waitFor(() => { expect(activatePromoEndpoint).not.toHaveBeenCalledWith( `/organizations/${organization.slug}/promotions/lorem-ipsum/claim/`, expect.objectContaining({ method: 'POST', }) ); }); }); it('shows correct past due modal and banner for billing admins', async function () { const organization = OrganizationFixture({ slug: 'past-due', access: ['org:billing'], }); const subscription = SubscriptionFixture({ organization, plan: 'am1_team', isPastDue: true, }); SubscriptionStore.set(organization.slug, subscription); render(, {organization}); renderGlobalModal(); expect(await screen.findByTestId('banner-alert-past-due')).toBeInTheDocument(); expect( screen.getByRole('button', {name: /update payment information/i}) ).toHaveAttribute( 'href', `/settings/past-due/billing/details/?referrer=banner-billing-failure` ); expect(await screen.findByTestId('modal-past-due')).toBeInTheDocument(); expect(screen.getByTestId('modal-continue-button')).toBeInTheDocument(); expect( screen.getByText( 'There was an issue with your payment. Update your payment information to ensure uniterrupted access to Sentry.' ) ).toBeInTheDocument(); await userEvent.click(screen.getByTestId('modal-continue-button')); expect(browserHistory.push).toHaveBeenCalledWith( `/settings/past-due/billing/details/?referrer=banner-billing-failure` ); }); it('shows past due modal and banner for non-billing users', async function () { const organization = OrganizationFixture({ slug: 'past-due-4', access: ['org:read'], }); const subscription = SubscriptionFixture({ organization, plan: 'am1_team', isPastDue: true, }); SubscriptionStore.set(organization.slug, subscription); render(, {organization}); renderGlobalModal(); expect(await screen.findByTestId('banner-alert-past-due')).toBeInTheDocument(); expect(await screen.findByTestId('modal-past-due')).toBeInTheDocument(); expect(screen.getByTestId('modal-continue-button')).toBeInTheDocument(); }); it('does not show past due modal for users without access', async function () { const organization = OrganizationFixture({ slug: 'past-due-4', access: [], }); const subscription = SubscriptionFixture({ organization, plan: 'am1_team', isPastDue: true, }); SubscriptionStore.set(organization.slug, subscription); render(, {organization}); renderGlobalModal(); await act(tick); expect(screen.queryByTestId('modal-past-due')).not.toBeInTheDocument(); expect(screen.queryByTestId('modal-continue-button')).not.toBeInTheDocument(); }); it('shows specific banner text just for cron overages', async function () { const organization = OrganizationFixture({access: ['org:billing']}); const subscription = SubscriptionFixture({ organization, plan: 'am2_team', categories: { errors: MetricHistoryFixture({usageExceeded: false}), transactions: MetricHistoryFixture({usageExceeded: false}), replays: MetricHistoryFixture({usageExceeded: false}), attachments: MetricHistoryFixture({usageExceeded: false}), monitorSeats: MetricHistoryFixture({usageExceeded: true}), profileDuration: MetricHistoryFixture({usageExceeded: false}), }, canSelfServe: true, }); SubscriptionStore.set(organization.slug, subscription); render(, {organization}); expect( await screen.findByText( "We can't enable additional Cron Monitors because you don't have a sufficient on-demand budget." ) ).toBeInTheDocument(); expect(await screen.findByRole('button', {name: 'Update Plan'})).toBeInTheDocument(); }); it('shows specific banner text just for uptime overages', async function () { const organization = OrganizationFixture({access: ['org:billing']}); const subscription = SubscriptionFixture({ organization, plan: 'am2_team', categories: { errors: MetricHistoryFixture({usageExceeded: false}), transactions: MetricHistoryFixture({usageExceeded: false}), replays: MetricHistoryFixture({usageExceeded: false}), attachments: MetricHistoryFixture({usageExceeded: false}), monitorSeats: MetricHistoryFixture({usageExceeded: false}), profileDuration: MetricHistoryFixture({usageExceeded: false}), uptime: MetricHistoryFixture({usageExceeded: true}), }, canSelfServe: true, }); SubscriptionStore.set(organization.slug, subscription); render(, {organization}); expect( await screen.findByText( "We can't enable additional Uptime Monitors because you don't have a sufficient on-demand budget." ) ).toBeInTheDocument(); expect( await screen.findByRole('button', {name: 'Increase Reserved Limits'}) ).toBeInTheDocument(); }); it('does not show past due modal for enterprise orgs', async function () { const organization = OrganizationFixture({ slug: 'past-due-3', access: ['org:billing'], }); const subscription = InvoicedSubscriptionFixture({ organization, plan: 'am2_business_ent', isPastDue: true, canSelfServe: false, }); SubscriptionStore.set(organization.slug, subscription); render(, {organization}); renderGlobalModal(); await act(tick); expect(screen.queryByTestId('banner-alert-past-due')).not.toBeInTheDocument(); expect( screen.queryByRole('button', {name: /update payment information/i}) ).not.toBeInTheDocument(); expect( screen.queryByRole('button', {name: /update billing details/i}) ).not.toBeInTheDocument(); }); it('shows overage notification banner for the spans category', async function () { const organization = OrganizationFixture(); const subscription = SubscriptionFixture({ organization, plan: 'am1_t', categories: { errors: MetricHistoryFixture({usageExceeded: false}), transactions: MetricHistoryFixture({usageExceeded: false}), replays: MetricHistoryFixture({usageExceeded: false}), attachments: MetricHistoryFixture({usageExceeded: false}), monitorSeats: MetricHistoryFixture({usageExceeded: false}), spans: MetricHistoryFixture({usageExceeded: true}), }, canSelfServe: true, }); SubscriptionStore.set(organization.slug, subscription); render(, {organization}); expect(await screen.findByTestId('overage-banner-span')).toBeInTheDocument(); expect(screen.getByText('span')).toBeInTheDocument(); }); it('shows overage notification banner for multiple categories including spans', async function () { const organization = OrganizationFixture(); const subscription = SubscriptionFixture({ organization, plan: 'am1_t', categories: { errors: MetricHistoryFixture({usageExceeded: true}), transactions: MetricHistoryFixture({usageExceeded: true}), spans: MetricHistoryFixture({usageExceeded: true}), replays: MetricHistoryFixture({usageExceeded: false}), attachments: MetricHistoryFixture({usageExceeded: true}), monitorSeats: MetricHistoryFixture({usageExceeded: true}), uptime: MetricHistoryFixture({usageExceeded: true}), }, canSelfServe: true, }); SubscriptionStore.set(organization.slug, subscription); render(, {organization}); expect( await screen.findByTestId( 'overage-banner-error-transaction-attachment-monitorSeat-span-uptime' ) ).toBeInTheDocument(); expect(screen.getByText('span')).toBeInTheDocument(); }); it('does not show overage notification banner for spans if overage notifications are disabled', async function () { const organization = OrganizationFixture({ access: ['org:billing'], slug: 'another-slug-2', }); const subscription = SubscriptionFixture({ organization, plan: 'am1_team', categories: { spans: MetricHistoryFixture({usageExceeded: true}), }, canSelfServe: true, hasOverageNotificationsDisabled: true, }); SubscriptionStore.set(organization.slug, subscription); render(, {organization}); await act(tick); expect( screen.queryByRole('button', {name: /increase reserved limits/i}) ).not.toBeInTheDocument(); }); it('shows overage warning banner for spans', async function () { const organization = OrganizationFixture({ access: ['org:billing'], slug: 'another-slug-1', }); const subscription = SubscriptionFixture({ organization, plan: 'am1_team', categories: { errors: MetricHistoryFixture({sentUsageWarning: false}), spans: MetricHistoryFixture({sentUsageWarning: true}), replays: MetricHistoryFixture({usageExceeded: false}), attachments: MetricHistoryFixture({sentUsageWarning: false}), monitorSeats: MetricHistoryFixture({sentUsageWarning: false}), }, canSelfServe: true, }); SubscriptionStore.set(organization.slug, subscription); render(, {organization}); expect( await screen.findByRole('button', {name: /increase reserved limits/i}) ).toBeInTheDocument(); }); it('does not show overage warning banner for spans if on-demand is set', async function () { const organization = OrganizationFixture({ access: ['org:billing'], slug: 'another-slug-1', }); const subscription = SubscriptionFixture({ organization, plan: 'am1_team', categories: {spans: MetricHistoryFixture({sentUsageWarning: true})}, canSelfServe: true, onDemandMaxSpend: 10, }); SubscriptionStore.set(organization.slug, subscription); render(, {organization}); await act(tick); expect( screen.queryByRole('button', {name: /increase reserved limits/i}) ).not.toBeInTheDocument(); }); it('does not show overage notification banner for spans if active product trial', async function () { const organization = OrganizationFixture(); const subscription = SubscriptionFixture({ organization, plan: 'am3_team', categories: {spans: MetricHistoryFixture({usageExceeded: true})}, canSelfServe: true, productTrials: [ { category: DataCategory.SPANS, isStarted: true, reasonCode: 1001, startDate: moment().utc().subtract(10, 'days').format(), endDate: moment().utc().add(20, 'days').format(), }, ], }); SubscriptionStore.set(organization.slug, subscription); const {container} = render(, {organization}); await act(tick); expect(container).toBeEmptyDOMElement(); }); it('shows overage notification banner for spans even if other category is on active trial', async function () { const organization = OrganizationFixture(); const subscription = SubscriptionFixture({ organization, plan: 'am3_team', categories: { spans: MetricHistoryFixture({usageExceeded: true}), replays: MetricHistoryFixture({usageExceeded: true}), }, canSelfServe: true, productTrials: [ { category: DataCategory.REPLAYS, isStarted: true, reasonCode: 1001, startDate: moment().utc().subtract(10, 'days').format(), endDate: moment().utc().add(20, 'days').format(), }, ], }); SubscriptionStore.set(organization.slug, subscription); render(, {organization}); expect(await screen.findByTestId('overage-banner-span')).toBeInTheDocument(); expect(screen.queryByTestId('overage-banner-replay')).not.toBeInTheDocument(); }); it('shows overage warning banner for profileDuration', async function () { const organization = OrganizationFixture({ access: ['org:billing'], slug: 'another-slug-1', }); const subscription = SubscriptionFixture({ organization, plan: 'am1_team', categories: { errors: MetricHistoryFixture({sentUsageWarning: false}), spans: MetricHistoryFixture({sentUsageWarning: false}), profileDuration: MetricHistoryFixture({sentUsageWarning: true}), // Warning sent replays: MetricHistoryFixture({usageExceeded: false}), attachments: MetricHistoryFixture({sentUsageWarning: false}), monitorSeats: MetricHistoryFixture({sentUsageWarning: false}), }, canSelfServe: true, }); SubscriptionStore.set(organization.slug, subscription); render(, {organization}); expect( await screen.findByRole('button', {name: /increase reserved limits/i}) ).toBeInTheDocument(); }); });