onDemandSpend.spec.tsx 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. import {OrganizationFixture} from 'sentry-fixture/organization';
  2. import {RouteComponentPropsFixture} from 'sentry-fixture/routeComponentPropsFixture';
  3. import {BillingConfigFixture} from 'getsentry-test/fixtures/billingConfig';
  4. import {PlanDetailsLookupFixture} from 'getsentry-test/fixtures/planDetailsLookup';
  5. import {SubscriptionFixture} from 'getsentry-test/fixtures/subscription';
  6. import {render, screen, userEvent, within} from 'sentry-test/reactTestingLibrary';
  7. import SubscriptionStore from 'getsentry/stores/subscriptionStore';
  8. import {PlanTier} from 'getsentry/types';
  9. import AMCheckout from 'getsentry/views/amCheckout';
  10. import OnDemandSpend from 'getsentry/views/amCheckout/steps/onDemandSpend';
  11. import type {StepProps} from 'getsentry/views/amCheckout/types';
  12. describe('OnDemandSpend', function () {
  13. const api = new MockApiClient();
  14. const organization = OrganizationFixture();
  15. const subscription = SubscriptionFixture({organization});
  16. const params = {};
  17. const stepBody = /On-Demand spend allows you to pay for additional data/;
  18. const billingConfig = BillingConfigFixture(PlanTier.AM2);
  19. const bizPlan = PlanDetailsLookupFixture('am1_business')!;
  20. const stepProps: StepProps = {
  21. isActive: true,
  22. stepNumber: 3,
  23. onUpdate: jest.fn(),
  24. onCompleteStep: jest.fn(),
  25. onEdit: jest.fn(),
  26. billingConfig,
  27. formData: {
  28. plan: billingConfig.defaultPlan,
  29. reserved: {},
  30. },
  31. activePlan: bizPlan,
  32. subscription,
  33. isCompleted: false,
  34. prevStepCompleted: false,
  35. organization,
  36. };
  37. async function openPanel() {
  38. const header = await screen.findByTestId('header-on-demand-max-spend');
  39. expect(header).toBeInTheDocument();
  40. await userEvent.click(within(header).getByLabelText('Expand section'));
  41. }
  42. beforeEach(function () {
  43. SubscriptionStore.set(organization.slug, subscription);
  44. MockApiClient.addMockResponse({
  45. url: `/subscriptions/${organization.slug}/`,
  46. method: 'GET',
  47. body: {},
  48. });
  49. MockApiClient.addMockResponse({
  50. url: `/customers/${organization.slug}/billing-config/`,
  51. method: 'GET',
  52. body: BillingConfigFixture(PlanTier.AM2),
  53. });
  54. MockApiClient.addMockResponse({
  55. url: `/organizations/${organization.slug}/promotions/trigger-check/`,
  56. method: 'POST',
  57. });
  58. MockApiClient.addMockResponse({
  59. url: `/customers/${organization.slug}/plan-migrations/?applied=0`,
  60. method: 'GET',
  61. body: [],
  62. });
  63. });
  64. it('renders', async function () {
  65. render(
  66. <AMCheckout
  67. {...RouteComponentPropsFixture()}
  68. params={params}
  69. api={api}
  70. organization={organization}
  71. checkoutTier={PlanTier.AM2}
  72. onToggleLegacy={jest.fn()}
  73. />
  74. );
  75. await openPanel();
  76. expect(screen.getByText(stepBody)).toBeInTheDocument();
  77. expect(screen.getByRole('button', {name: 'Continue'})).toBeInTheDocument();
  78. });
  79. it('renders with placeholder and can change input', async function () {
  80. render(
  81. <AMCheckout
  82. {...RouteComponentPropsFixture()}
  83. params={params}
  84. api={api}
  85. organization={organization}
  86. checkoutTier={PlanTier.AM2}
  87. onToggleLegacy={jest.fn()}
  88. />
  89. );
  90. await openPanel();
  91. expect(screen.getByRole('textbox', {name: 'Monthly Max'})).toBeEnabled();
  92. expect(screen.queryByLabelText(/On-demand is not supported/)).not.toBeInTheDocument();
  93. expect(screen.getByPlaceholderText('e.g. 50')).toBeInTheDocument();
  94. // Can type into the input.
  95. await userEvent.type(screen.getByPlaceholderText('e.g. 50'), '50');
  96. });
  97. it('handles input edge cases', async function () {
  98. render(
  99. <AMCheckout
  100. {...RouteComponentPropsFixture()}
  101. params={params}
  102. api={api}
  103. organization={organization}
  104. checkoutTier={PlanTier.AM2}
  105. onToggleLegacy={jest.fn()}
  106. />
  107. );
  108. await openPanel();
  109. const input = screen.getByRole('textbox', {name: 'Monthly Max'});
  110. await userEvent.type(input, 'a');
  111. expect(input).toHaveValue('');
  112. await userEvent.type(input, '-50');
  113. expect(input).toHaveValue('50');
  114. await userEvent.type(input, '-');
  115. expect(input).toHaveValue('50');
  116. await userEvent.clear(input);
  117. await userEvent.type(input, '10e');
  118. expect(input).toHaveValue('10');
  119. await userEvent.clear(input);
  120. await userEvent.type(input, 'e');
  121. expect(input).toHaveValue('');
  122. await userEvent.clear(input);
  123. await userEvent.type(input, '75..');
  124. expect(input).toHaveValue('75');
  125. await userEvent.clear(input);
  126. await userEvent.type(input, '.');
  127. expect(input).toHaveValue('');
  128. });
  129. it('can complete step', async function () {
  130. render(
  131. <AMCheckout
  132. {...RouteComponentPropsFixture()}
  133. params={params}
  134. api={api}
  135. organization={organization}
  136. checkoutTier={PlanTier.AM2}
  137. onToggleLegacy={jest.fn()}
  138. />
  139. );
  140. await openPanel();
  141. // Body text is present.
  142. expect(screen.getByText(stepBody)).toBeInTheDocument();
  143. // continue to close
  144. await userEvent.click(screen.getByRole('button', {name: 'Continue'}));
  145. expect(screen.queryByText(stepBody)).not.toBeInTheDocument();
  146. expect(screen.queryByRole('textbox', {name: 'Monthly Max'})).not.toBeInTheDocument();
  147. });
  148. it('is disabled if sub does not support ondemand', async function () {
  149. const sub = {...subscription, supportsOnDemand: false};
  150. SubscriptionStore.set(organization.slug, sub);
  151. render(<OnDemandSpend {...stepProps} subscription={sub} />);
  152. // Check tooltip
  153. await userEvent.hover(screen.getByRole('textbox', {name: 'Monthly Max'}));
  154. expect(await screen.findByText(/On-demand is not supported/)).toBeInTheDocument();
  155. const input = screen.getByRole('textbox', {name: 'Monthly Max'});
  156. expect(input).toBeInTheDocument();
  157. expect(input).toBeDisabled();
  158. expect(screen.getByRole('button', {name: 'Continue'})).toBeInTheDocument();
  159. });
  160. it('is disabled if plan does not allow on demand', async function () {
  161. const activePlan = {...bizPlan, allowOnDemand: false};
  162. const props = {...stepProps, activePlan};
  163. render(<OnDemandSpend {...props} />);
  164. // Check tooltip
  165. await userEvent.hover(screen.getByRole('textbox', {name: 'Monthly Max'}));
  166. expect(await screen.findByText(/On-demand is not supported/)).toBeInTheDocument();
  167. const input = screen.getByRole('textbox', {name: 'Monthly Max'});
  168. expect(input).toBeInTheDocument();
  169. expect(input).toBeDisabled();
  170. });
  171. });