123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629 |
- 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(
- <ProductSelectionAvailability
- organization={organization}
- platform="javascript-react"
- />,
- {
- 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(
- <ProductSelectionAvailability
- organization={organization}
- platform="javascript-react"
- />,
- {
- 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(
- <ProductSelectionAvailability
- organization={organization}
- platform="javascript-react"
- />,
- {
- 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(
- <ProductSelectionAvailability
- organization={organization}
- platform="javascript-react"
- />,
- {
- 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(
- <ProductSelectionAvailability
- organization={organization}
- platform="javascript-react"
- />,
- {
- 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(
- <ProductSelectionAvailability
- organization={organization}
- platform="javascript-react"
- />,
- {
- 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(
- <ProductSelectionAvailability
- organization={organization}
- platform="javascript-react"
- />
- );
- // 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(
- <ProductSelectionAvailability
- organization={organization}
- platform="python-django"
- />,
- {
- 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(
- <ProductSelectionAvailability
- organization={organization}
- platform="python-django"
- />,
- {
- 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(
- <ProductSelectionAvailability
- organization={organization}
- platform="python-django"
- />,
- {
- 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(
- <ProductSelectionAvailability
- organization={organization}
- platform="python-django"
- />,
- {
- 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],
- }),
- })
- );
- });
- });
- });
- });
|