import {BillingConfigFixture} from 'getsentry-test/fixtures/billingConfig';
import {SubscriptionFixture} from 'getsentry-test/fixtures/subscription';
import {initializeOrg} from 'sentry-test/initializeOrg';
import {
act,
render,
renderGlobalModal,
screen,
userEvent,
waitFor,
} from 'sentry-test/reactTestingLibrary';
import {ProductSolution} from 'sentry/components/onboarding/gettingStartedDoc/types';
import type {Organization} from 'sentry/types/organization';
import {PlanFixture} from 'getsentry/__fixtures__/plan';
import {PreviewDataFixture} from 'getsentry/__fixtures__/previewData';
import {ProductSelectionAvailability} from 'getsentry/components/productSelectionAvailability';
import type {Reservations} from 'getsentry/components/upgradeNowModal/types';
import usePreviewData from 'getsentry/components/upgradeNowModal/usePreviewData';
import SubscriptionStore from 'getsentry/stores/subscriptionStore';
import {PlanTier} from 'getsentry/types';
jest.mock('getsentry/components/upgradeNowModal/usePreviewData');
function renderMockRequests({
planTier,
organization,
canSelfServe,
}: {
organization: Organization;
planTier: PlanTier;
canSelfServe?: boolean;
}) {
const subscription = SubscriptionFixture({
organization,
planTier,
canSelfServe,
});
act(() => SubscriptionStore.set(organization.slug, subscription));
MockApiClient.addMockResponse({
url: `/subscriptions/org-slug/`,
body: {
planTier,
canSelfServe,
},
});
MockApiClient.addMockResponse({
url: `/customers/${organization.slug}/billing-config/`,
body: BillingConfigFixture(planTier),
});
}
describe('ProductSelectionAvailability', function () {
describe('with no billing access', function () {
it('with performance and session replay', async function () {
const {organization, router} = initializeOrg({
organization: {
features: ['performance-view', 'session-replay'],
},
router: {
location: {
query: {
product: [
ProductSolution.PERFORMANCE_MONITORING,
ProductSolution.SESSION_REPLAY,
],
},
},
},
});
renderMockRequests({planTier: PlanTier.AM2, organization});
render(
,
{
router,
}
);
// Error Monitoring
// disabled: false - it's not disabled because of the styles, but it behaves as if it were disabled
// checked: true
expect(await screen.findByRole('button', {name: 'Error Monitoring'})).toBeEnabled();
expect(screen.getByRole('checkbox', {name: 'Error Monitoring'})).toBeChecked();
// Tooltip
await userEvent.hover(screen.getByRole('button', {name: 'Error Monitoring'}));
expect(
await screen.findByText(/let's admit it, we all have errors/i)
).toBeInTheDocument();
// Tracing
// disabled: false
// checked: true - by default, it's checked
expect(screen.getByRole('button', {name: 'Tracing'})).toBeEnabled();
expect(screen.getByRole('checkbox', {name: 'Tracing'})).toBeChecked();
// Tooltip
await userEvent.hover(screen.getByRole('button', {name: 'Tracing'}));
expect(
await screen.findByText(/automatic performance issue detection/i)
).toBeInTheDocument();
// Session Replay
// disabled: false
// checked: true - by default, it's checked
expect(screen.getByRole('button', {name: 'Session Replay'})).toBeEnabled();
expect(screen.getByRole('checkbox', {name: 'Session Replay'})).toBeChecked();
// Tooltip
await userEvent.hover(screen.getByRole('button', {name: 'Session Replay'}));
expect(
await screen.findByText(/video-like reproductions of user sessions/i)
).toBeInTheDocument();
});
it('without performance and session replay', async function () {
const {organization, router} = initializeOrg();
renderMockRequests({planTier: PlanTier.MM2, organization, canSelfServe: true});
render(
,
{
router,
}
);
// Error Monitoring
// disabled: false - it's not disabled because of the styles, but it behaves as if it were disabled
// checked: true
expect(await screen.findByRole('button', {name: 'Error Monitoring'})).toBeEnabled();
expect(screen.getByRole('checkbox', {name: 'Error Monitoring'})).toBeChecked();
// Tracing
// disabled: true
// checked: false
expect(screen.getByRole('button', {name: 'Tracing'})).toBeDisabled();
expect(screen.getByRole('checkbox', {name: 'Tracing'})).not.toBeChecked();
// Tooltip
await userEvent.hover(screen.getByRole('button', {name: 'Tracing'}));
expect(
await screen.findByText(/to use performance, request an owner/i)
).toBeInTheDocument();
// Session Replay
// disabled: true
// checked: false
expect(screen.getByRole('button', {name: 'Session Replay'})).toBeDisabled();
expect(screen.getByRole('checkbox', {name: 'Session Replay'})).not.toBeChecked();
// Tooltip
await userEvent.hover(screen.getByRole('button', {name: 'Session Replay'}));
expect(
await screen.findByText(/to use session replay, request an owner/i)
).toBeInTheDocument();
});
it('without session replay', async function () {
const {organization, router} = initializeOrg({
organization: {
features: ['performance-view'],
},
router: {
location: {
query: {
product: [ProductSolution.PERFORMANCE_MONITORING],
},
},
},
});
renderMockRequests({planTier: PlanTier.AM1, organization});
render(
,
{
router,
}
);
// Error Monitoring
// disabled: false - it's not disabled because of the styles, but it behaves as if it were disabled
// checked: true
expect(await screen.findByRole('button', {name: 'Error Monitoring'})).toBeEnabled();
expect(screen.getByRole('checkbox', {name: 'Error Monitoring'})).toBeChecked();
// Tracing
// disabled: false
// checked: true - by default, it's checked
expect(screen.getByRole('button', {name: 'Tracing'})).toBeEnabled();
expect(screen.getByRole('checkbox', {name: 'Tracing'})).toBeChecked();
// Session Replay
// disabled: true
// checked: false
expect(screen.getByRole('button', {name: 'Session Replay'})).toBeDisabled();
expect(screen.getByRole('checkbox', {name: 'Session Replay'})).not.toBeChecked();
});
});
describe('with billing access', function () {
it('with performance and session replay', async function () {
const {organization, router} = initializeOrg({
organization: {
features: ['performance-view', 'session-replay'],
access: ['org:billing'] as any, // TODO(ts): Fix this type for organizations on a plan
},
router: {
location: {
query: {
product: [
ProductSolution.PERFORMANCE_MONITORING,
ProductSolution.SESSION_REPLAY,
],
},
},
},
});
renderMockRequests({planTier: PlanTier.AM2, organization});
render(
,
{
router,
}
);
// Error Monitoring
// disabled: false - it's not disabled because of the styles, but it behaves as if it were disabled
// checked: true
expect(await screen.findByRole('button', {name: 'Error Monitoring'})).toBeEnabled();
expect(screen.getByRole('checkbox', {name: 'Error Monitoring'})).toBeChecked();
// Tooltip
await userEvent.hover(screen.getByRole('button', {name: 'Error Monitoring'}));
expect(
await screen.findByText(/let's admit it, we all have errors/i)
).toBeInTheDocument();
// Tracing
// disabled: false
// checked: true - by default, it's checked
expect(screen.getByRole('button', {name: 'Tracing'})).toBeEnabled();
expect(screen.getByRole('checkbox', {name: 'Tracing'})).toBeChecked();
// Tooltip
await userEvent.hover(screen.getByRole('button', {name: 'Tracing'}));
expect(
await screen.findByText(/automatic performance issue detection/i)
).toBeInTheDocument();
// Session Replay
// disabled: false
// checked: true - by default, it's checked
expect(screen.getByRole('button', {name: 'Session Replay'})).toBeEnabled();
expect(screen.getByRole('checkbox', {name: 'Session Replay'})).toBeChecked();
// Tooltip
await userEvent.hover(screen.getByRole('button', {name: 'Session Replay'}));
expect(
await screen.findByText(/video-like reproductions of user sessions/i)
).toBeInTheDocument();
});
it('without performance, session replay and profiling', async function () {
const {organization, router} = initializeOrg({
organization: {
access: ['org:billing'] as any, // TODO(ts): Fix this type for organizations on a plan
},
});
renderMockRequests({planTier: PlanTier.MM2, organization});
render(
,
{
router,
}
);
// Error Monitoring
// disabled: false - it's not disabled because of the styles, but it behaves as if it were disabled
// checked: true
expect(await screen.findByRole('button', {name: 'Error Monitoring'})).toBeEnabled();
expect(screen.getByRole('checkbox', {name: 'Error Monitoring'})).toBeChecked();
// Tracing
// disabled: true
// checked: false
expect(screen.getByRole('button', {name: 'Tracing'})).toBeDisabled();
expect(screen.getByRole('checkbox', {name: 'Tracing'})).not.toBeChecked();
// Tooltip
await userEvent.hover(screen.getByRole('button', {name: 'Tracing'}));
expect(
await screen.findByText(/to use performance, update your organization's plan/i)
).toBeInTheDocument();
// Session Replay
// disabled: true - We don't display an upsell modal to users on MM* plans
// checked: false
expect(screen.getByRole('button', {name: 'Session Replay'})).toBeDisabled();
expect(screen.getByRole('checkbox', {name: 'Session Replay'})).not.toBeChecked();
expect(screen.getByRole('checkbox', {name: 'Session Replay'})).toBeDisabled();
// Tooltip
await userEvent.hover(screen.getByRole('button', {name: 'Session Replay'}));
expect(
await screen.findByText(/to use session replay, update your organization's plan/i)
).toBeInTheDocument();
});
it('without session replay', async function () {
const {organization, router} = initializeOrg({
organization: {
access: ['org:billing'] as any, // TODO(ts): Fix this type for organizations on a plan
features: ['performance-view'],
},
router: {
location: {
query: {
product: [ProductSolution.PERFORMANCE_MONITORING],
},
},
},
});
const MockUsePreviewData = usePreviewData as jest.MockedFunction<
typeof usePreviewData
>;
const mockReservations: Reservations = {
reservedErrors: 50000,
reservedTransactions: 0,
reservedReplays: 500,
reservedAttachments: 0,
reservedMonitorSeats: 0,
reservedUptime: 0,
};
const mockPlan = PlanFixture({});
const mockPreview = PreviewDataFixture({});
MockUsePreviewData.mockReturnValue({
loading: false,
error: false,
plan: mockPlan,
previewData: mockPreview,
reservations: mockReservations,
});
// can self-serve
renderMockRequests({planTier: PlanTier.AM1, organization, canSelfServe: true});
const {rerender} = render(
,
{
router,
}
);
// Error Monitoring
// disabled: false - it's not disabled because of the styles, but it behaves as if it were disabled
// checked: true
expect(await screen.findByRole('button', {name: 'Error Monitoring'})).toBeEnabled();
expect(screen.getByRole('checkbox', {name: 'Error Monitoring'})).toBeChecked();
// Tracing
// disabled: false
// checked: true - by default, it's checked
expect(screen.getByRole('button', {name: 'Tracing'})).toBeEnabled();
expect(screen.getByRole('checkbox', {name: 'Tracing'})).toBeChecked();
// Session Replay
// disabled: false - By clicking on the button, an upsell modal is shown
// checked: false
expect(screen.getByRole('button', {name: 'Session Replay'})).toBeEnabled();
expect(screen.getByRole('checkbox', {name: 'Session Replay'})).not.toBeChecked();
expect(screen.getByRole('checkbox', {name: 'Session Replay'})).toBeDisabled();
// Tooltip
await userEvent.hover(screen.getByRole('button', {name: 'Session Replay'}));
expect(
await screen.findByText(/to use session replay, update your organization's plan/i)
).toBeInTheDocument();
renderGlobalModal();
// Modal
await userEvent.click(screen.getByRole('button', {name: 'Session Replay'}));
expect(
await screen.findByRole('heading', {name: /enable session replays now/i})
).toBeInTheDocument();
// can't self-serve
renderMockRequests({planTier: PlanTier.AM1, organization, canSelfServe: false});
rerender(
);
// Session Replay
// disabled: true - We don't display an upsell modal to users who has access to billing but cannot self-serve
// checked: false
expect(await screen.findByRole('button', {name: 'Session Replay'})).toBeDisabled();
// Tooltip
await userEvent.hover(screen.getByRole('button', {name: 'Session Replay'}));
expect(await screen.findByText(/Manage Subscription/i)).toBeInTheDocument();
});
it('with profiling and without session replay', async function () {
const {organization, router} = initializeOrg({
organization: {
features: ['performance-view', 'profiling-view'],
},
router: {
location: {
query: {
product: [
ProductSolution.PERFORMANCE_MONITORING,
ProductSolution.PROFILING,
],
},
},
},
});
renderMockRequests({planTier: PlanTier.AM2, organization});
render(
,
{
router,
}
);
// Error Monitoring
// disabled: false - it's not disabled because of the styles, but it behaves as if it were disabled
// checked: true
expect(await screen.findByRole('button', {name: 'Error Monitoring'})).toBeEnabled();
expect(screen.getByRole('checkbox', {name: 'Error Monitoring'})).toBeChecked();
// Tracing
// disabled: false
// checked: true - by default, it's checked
expect(screen.getByRole('button', {name: 'Tracing'})).toBeEnabled();
expect(screen.getByRole('checkbox', {name: 'Tracing'})).toBeChecked();
// Session Replay (not rendered)
expect(
screen.queryByRole('button', {name: 'Session Replay'})
).not.toBeInTheDocument();
// Profiling
// disabled: false
// checked: true - by default, it's checked
expect(screen.getByRole('button', {name: 'Profiling'})).toBeEnabled();
expect(screen.getByRole('checkbox', {name: 'Profiling'})).toBeChecked();
});
it('without profiling and without session replay', async function () {
const {organization, router} = initializeOrg({
organization: {
features: ['performance-view'],
},
router: {
location: {
query: {
product: [ProductSolution.PERFORMANCE_MONITORING],
},
},
},
});
renderMockRequests({planTier: PlanTier.AM2, organization});
render(
,
{
router,
}
);
// Error Monitoring
// disabled: false - it's not disabled because of the styles, but it behaves as if it were disabled
// checked: true
expect(await screen.findByRole('button', {name: 'Error Monitoring'})).toBeEnabled();
expect(screen.getByRole('checkbox', {name: 'Error Monitoring'})).toBeChecked();
// Tracing
// disabled: false
// checked: true - by default, it's checked
expect(screen.getByRole('button', {name: 'Tracing'})).toBeEnabled();
expect(screen.getByRole('checkbox', {name: 'Tracing'})).toBeChecked();
// Session Replay (not rendered)
expect(
screen.queryByRole('button', {name: 'Session Replay'})
).not.toBeInTheDocument();
// Profiling
// disabled: false
// checked: false
expect(screen.getByRole('button', {name: 'Profiling'})).toBeDisabled();
expect(screen.getByRole('checkbox', {name: 'Profiling'})).not.toBeChecked();
expect(screen.getByRole('checkbox', {name: 'Profiling'})).toBeDisabled();
// Tooltip
await userEvent.hover(screen.getByRole('button', {name: 'Profiling'}));
expect(
await screen.findByText(/to use profiling, update your organization's plan/i)
).toBeInTheDocument();
});
// TODO: This test does not play well with deselected products by default
// eslint-disable-next-line jest/no-disabled-tests
it.skip('enabling Profiling, shall check and "disabled" Tracing', async function () {
const {router, organization} = initializeOrg({
organization: {
features: ['performance-view', 'profiling-view'],
},
router: {
location: {
query: {
product: [ProductSolution.PROFILING],
},
},
},
});
renderMockRequests({planTier: PlanTier.AM2, organization});
render(
,
{
router,
}
);
// Performance is added to the query string, so it will be checked
await waitFor(() => {
expect(router.replace).toHaveBeenCalledWith(
expect.objectContaining({
query: expect.objectContaining({
product: [
ProductSolution.PERFORMANCE_MONITORING,
ProductSolution.PROFILING,
],
}),
})
);
});
// Tracing
// disabled: false - it's not disabled because of the styles, but it behaves as if it were disabled
expect(screen.getByRole('button', {name: 'Tracing'})).toBeEnabled();
});
it('with Profiling and Tracing', async function () {
const {router, organization} = initializeOrg({
organization: {
features: ['performance-view', 'profiling-view'],
},
router: {
location: {
query: {
product: [
ProductSolution.PROFILING,
ProductSolution.PERFORMANCE_MONITORING,
],
},
},
},
});
renderMockRequests({planTier: PlanTier.AM2, organization});
render(
,
{
router,
}
);
// Tracing
expect(screen.getByRole('button', {name: 'Tracing'})).toBeEnabled();
expect(screen.getByRole('checkbox', {name: 'Tracing'})).toBeChecked();
// Profiling
expect(screen.getByRole('button', {name: 'Profiling'})).toBeEnabled();
expect(screen.getByRole('checkbox', {name: 'Profiling'})).toBeChecked();
await userEvent.click(screen.getByRole('button', {name: 'Profiling'}));
// profiling is removed from the query string
await waitFor(() => {
expect(router.replace).toHaveBeenCalledWith(
expect.objectContaining({
query: expect.objectContaining({
product: [ProductSolution.PERFORMANCE_MONITORING],
}),
})
);
});
});
});
});