Browse Source

ref(tests): Convert tests to rtl and tsx (#40886)

Priscila Oliveira 2 years ago
parent
commit
b36f071097

+ 4 - 4
static/app/actionCreators/modal.tsx

@@ -254,11 +254,11 @@ export async function openReprocessEventModal({
   onClose,
   ...options
 }: ReprocessEventModalOptions & {onClose?: () => void}) {
-  const mod = await import('sentry/components/modals/reprocessEventModal');
+  const {ReprocessingEventModal} = await import(
+    'sentry/components/modals/reprocessEventModal'
+  );
 
-  const {default: Modal} = mod;
-
-  openModal(deps => <Modal {...deps} {...options} />, {onClose});
+  openModal(deps => <ReprocessingEventModal {...deps} {...options} />, {onClose});
 }
 
 export async function demoSignupModal(options: ModalOptions = {}) {

+ 81 - 66
static/app/components/modals/reprocessEventModal.spec.tsx

@@ -1,7 +1,14 @@
-import {mountGlobalModal} from 'sentry-test/modal';
-
-import {openReprocessEventModal} from 'sentry/actionCreators/modal';
-import ModalStore from 'sentry/stores/modalStore';
+import {initializeOrg} from 'sentry-test/initializeOrg';
+import {render, screen, userEvent, waitFor} from 'sentry-test/reactTestingLibrary';
+import {textWithMarkupMatcher} from 'sentry-test/utils';
+
+import {
+  makeClosableHeader,
+  makeCloseButton,
+  ModalBody,
+  ModalFooter,
+} from 'sentry/components/globalModal/components';
+import {ReprocessingEventModal} from 'sentry/components/modals/reprocessEventModal';
 
 const group = TestStubs.Group({
   id: '1337',
@@ -9,68 +16,67 @@ const group = TestStubs.Group({
   pluginIssues: [],
 });
 
-const organization = TestStubs.Organization({
-  id: '4660',
-  slug: 'org',
-  features: ['reprocessing-v2'],
-});
-
-async function mountComponent() {
-  const modal = await mountGlobalModal();
-
-  openReprocessEventModal({organization, groupId: group.id});
-
-  await tick();
-  await tick();
-  modal.update();
-
-  return modal;
-}
-
 describe('ReprocessEventModal', function () {
-  let wrapper: any;
-
-  beforeEach(async function () {
-    wrapper = await mountComponent();
-  });
-
-  it('modal is open', () => {
-    expect(wrapper.find('Header').text()).toEqual('Reprocess Events');
-  });
+  it('form fields & info', function () {
+    const {organization} = initializeOrg({
+      ...initializeOrg(),
+      organization: {
+        id: '4660',
+        slug: 'org',
+        features: ['reprocessing-v2'],
+      },
+    });
 
-  it('form fields & info', () => {
-    // some info about reprocessing
-    const introduction = wrapper.find('Introduction');
-    expect(introduction).toBeTruthy();
-    expect(introduction).toHaveLength(2);
+    render(
+      <ReprocessingEventModal
+        Body={ModalBody}
+        closeModal={jest.fn()}
+        CloseButton={makeCloseButton(jest.fn())}
+        Header={makeClosableHeader(jest.fn())}
+        Footer={ModalFooter}
+        groupId="1337"
+        organization={organization}
+      />
+    );
 
     // Reprocess impacts
-    expect(introduction.at(0).text()).toEqual(
-      'Reprocessing applies new debug files and grouping enhancements to this Issue. Please consider these impacts:'
-    );
-    const impacts = wrapper.find('StyledList');
-    expect(impacts).toBeTruthy();
-    expect(impacts.length).toBeGreaterThan(0);
+    expect(
+      screen.getByText(
+        'Reprocessing applies new debug files and grouping enhancements to this Issue. Please consider these impacts:'
+      )
+    ).toBeInTheDocument();
 
-    // Docs info
-    expect(introduction.at(1).text()).toEqual(
-      'For more information, please refer to the documentation.'
-    );
+    // Reprocess impacts list
+    expect(screen.getAllByRole('listitem')).toHaveLength(3);
 
-    // Form
-    const form = wrapper.find('Form');
-    expect(form).toBeTruthy();
+    // Docs info
+    expect(
+      screen.getByText(
+        textWithMarkupMatcher('For more information, please refer to the documentation.')
+      )
+    ).toBeInTheDocument();
 
     // Number of events to be reprocessed field
-    const reprocessQuantityField = form.find('NumberField');
-    expect(reprocessQuantityField).toBeTruthy();
+    expect(
+      screen.getByRole('spinbutton', {name: 'Number of events to be reprocessed'})
+    ).toBeInTheDocument();
 
     // Remaining events action field
-    const remainingEventsActionField = form.find('RadioField');
-    expect(remainingEventsActionField).toBeTruthy();
+    expect(
+      screen.getByRole('radiogroup', {name: 'Remaining events'})
+    ).toBeInTheDocument();
   });
 
-  it('reprocess all events', async () => {
+  it('reprocess all events', async function () {
+    const {organization} = initializeOrg({
+      ...initializeOrg(),
+      organization: {
+        id: '4660',
+        slug: 'org',
+        features: ['reprocessing-v2'],
+      },
+    });
+
     MockApiClient.addMockResponse({
       url: `/organizations/${organization.slug}/issues/${group.id}/reprocessing/`,
       method: 'POST',
@@ -78,21 +84,30 @@ describe('ReprocessEventModal', function () {
     });
 
     jest.spyOn(window.location, 'reload').mockImplementation(() => {});
-    const closeModalFunc = jest.spyOn(ModalStore, 'closeModal');
-
-    // Number of events to be reprocessed field
-    const reprocessQuantityField = wrapper.find('NumberField input');
-    expect(reprocessQuantityField.props().placeholder).toEqual('Reprocess all events');
-    expect(reprocessQuantityField.props().value).toEqual(undefined);
+    const handleCloseModal = jest.fn();
+
+    render(
+      <ReprocessingEventModal
+        Body={ModalBody}
+        closeModal={handleCloseModal}
+        CloseButton={makeCloseButton(jest.fn())}
+        Header={makeClosableHeader(jest.fn())}
+        Footer={ModalFooter}
+        groupId="1337"
+        organization={organization}
+      />
+    );
 
-    const submitButton = wrapper.find('[data-test-id="form-submit"]').hostNodes();
+    expect(screen.getByRole('heading', {name: 'Reprocess Events'})).toBeInTheDocument();
 
-    submitButton.simulate('submit');
+    // Number of events to be reprocessed field
+    expect(
+      screen.getByRole('spinbutton', {name: 'Number of events to be reprocessed'})
+    ).toHaveAttribute('placeholder', 'Reprocess all events');
 
-    await tick();
-    wrapper.update();
+    userEvent.click(screen.getByRole('button', {name: 'Reprocess Events'}));
 
-    expect(window.location.reload).toHaveBeenCalled();
-    expect(closeModalFunc).toHaveBeenCalled();
+    await waitFor(() => expect(window.location.reload).toHaveBeenCalled());
+    expect(handleCloseModal).toHaveBeenCalled();
   });
 });

+ 86 - 104
static/app/components/modals/reprocessEventModal.tsx

@@ -1,4 +1,4 @@
-import {Component, Fragment} from 'react';
+import {Fragment, useState} from 'react';
 import styled from '@emotion/styled';
 
 import {addErrorMessage} from 'sentry/actionCreators/indicator';
@@ -13,123 +13,105 @@ import {t, tct} from 'sentry/locale';
 import space from 'sentry/styles/space';
 import {Group, Organization} from 'sentry/types';
 
-const impacts = [
-  tct(
-    "[strong:Quota applies.] Every event you choose to reprocess counts against your plan's quota. Rate limits and spike protection do not apply.",
-    {strong: <strong />}
-  ),
-  tct(
-    '[strong:Attachment storage required.] If your events come from minidumps or unreal crash reports, you must have [link:attachment storage] enabled.',
-    {
-      strong: <strong />,
-      link: (
-        <ExternalLink href="https://docs.sentry.io/platforms/native/enriching-events/attachments/#crash-reports-and-privacy" />
-      ),
-    }
-  ),
-  t(
-    'Please wait one hour after upload before attempting to reprocess missing debug files.'
-  ),
-];
-
-const remainingEventsChoices: [string, string][] = [
-  ['keep', t('Keep')],
-  ['delete', t('Delete')],
-];
-
 export type ReprocessEventModalOptions = {
   groupId: Group['id'];
   organization: Organization;
 };
 
-type Props = ModalRenderProps & ReprocessEventModalOptions;
-
-type State = {
-  maxEvents?: number;
-};
-
-class ReprocessingEventModal extends Component<Props, State> {
-  state: State = {maxEvents: undefined};
-
-  handleSuccess = () => {
-    const {closeModal} = this.props;
+export function ReprocessingEventModal({
+  Header,
+  Body,
+  organization,
+  closeModal,
+  groupId,
+}: ModalRenderProps & ReprocessEventModalOptions) {
+  const [maxEvents, setMaxEvents] = useState<number | undefined>(undefined);
 
+  function handleSuccess() {
     closeModal();
     window.location.reload();
-  };
-
-  handleError() {
-    addErrorMessage(t('Failed to reprocess. Please check your input.'));
   }
 
-  handleMaxEventsChange = (maxEvents: string) => {
-    this.setState({maxEvents: Number(maxEvents) || undefined});
-  };
-
-  render() {
-    const {organization, Header, Body, closeModal, groupId} = this.props;
-    const {maxEvents} = this.state;
-    const orgSlug = organization.slug;
-    const endpoint = `/organizations/${orgSlug}/issues/${groupId}/reprocessing/`;
-    const title = t('Reprocess Events');
-
-    return (
-      <Fragment>
-        <Header closeButton>{title}</Header>
-        <Body>
-          <Introduction>
+  return (
+    <Fragment>
+      <Header closeButton>
+        <h4>{t('Reprocess Events')}</h4>
+      </Header>
+      <Body>
+        <Introduction>
+          {t(
+            'Reprocessing applies new debug files and grouping enhancements to this Issue. Please consider these impacts:'
+          )}
+        </Introduction>
+        <StyledList symbol="bullet">
+          <ListItem>
+            {tct(
+              "[strong:Quota applies.] Every event you choose to reprocess counts against your plan's quota. Rate limits and spike protection do not apply.",
+              {strong: <strong />}
+            )}
+          </ListItem>
+          <ListItem>
+            {tct(
+              '[strong:Attachment storage required.] If your events come from minidumps or unreal crash reports, you must have [link:attachment storage] enabled.',
+              {
+                strong: <strong />,
+                link: (
+                  <ExternalLink href="https://docs.sentry.io/platforms/native/enriching-events/attachments/#crash-reports-and-privacy" />
+                ),
+              }
+            )}
+          </ListItem>
+          <ListItem>
             {t(
-              'Reprocessing applies new debug files and grouping enhancements to this Issue. Please consider these impacts:'
+              'Please wait one hour after upload before attempting to reprocess missing debug files.'
             )}
-          </Introduction>
-          <StyledList symbol="bullet">
-            {impacts.map((impact, index) => (
-              <ListItem key={index}>{impact}</ListItem>
-            ))}
-          </StyledList>
-          <Introduction>
-            {tct('For more information, please refer to [link:the documentation.]', {
-              link: (
-                <ExternalLink href="https://docs.sentry.io/product/error-monitoring/reprocessing/" />
-              ),
-            })}
-          </Introduction>
-          <Form
-            submitLabel={title}
-            apiEndpoint={endpoint}
-            apiMethod="POST"
-            initialData={{maxEvents: undefined, remainingEvents: 'keep'}}
-            onSubmitSuccess={this.handleSuccess}
-            onSubmitError={this.handleError}
-            onCancel={closeModal}
-            footerClass="modal-footer"
-          >
-            <NumberField
-              name="maxEvents"
-              label={t('Number of events to be reprocessed')}
-              help={t('If you set a limit, we will reprocess your most recent events.')}
-              placeholder={t('Reprocess all events')}
-              onChange={this.handleMaxEventsChange}
-              min={1}
-            />
-
-            <RadioField
-              orientInline
-              label={t('Remaining events')}
-              help={t('What to do with the events that are not reprocessed.')}
-              name="remainingEvents"
-              choices={remainingEventsChoices}
-              disabled={maxEvents === undefined}
-            />
-          </Form>
-        </Body>
-      </Fragment>
-    );
-  }
+          </ListItem>
+        </StyledList>
+        <Introduction>
+          {tct('For more information, please refer to [link:the documentation.]', {
+            link: (
+              <ExternalLink href="https://docs.sentry.io/product/error-monitoring/reprocessing/" />
+            ),
+          })}
+        </Introduction>
+        <Form
+          submitLabel={t('Reprocess Events')}
+          apiEndpoint={`/organizations/${organization.slug}/issues/${groupId}/reprocessing/`}
+          apiMethod="POST"
+          initialData={{maxEvents: undefined, remainingEvents: 'keep'}}
+          onSubmitSuccess={handleSuccess}
+          onSubmitError={() =>
+            addErrorMessage(t('Failed to reprocess. Please check your input.'))
+          }
+          onCancel={closeModal}
+          footerClass="modal-footer"
+        >
+          <NumberField
+            name="maxEvents"
+            label={t('Number of events to be reprocessed')}
+            help={t('If you set a limit, we will reprocess your most recent events.')}
+            placeholder={t('Reprocess all events')}
+            onChange={value => setMaxEvents(!isNaN(value) ? Number(value) : undefined)}
+            min={1}
+          />
+
+          <RadioField
+            orientInline
+            label={t('Remaining events')}
+            help={t('What to do with the events that are not reprocessed.')}
+            name="remainingEvents"
+            choices={[
+              ['keep', t('Keep')],
+              ['delete', t('Delete')],
+            ]}
+            disabled={maxEvents === undefined}
+          />
+        </Form>
+      </Body>
+    </Fragment>
+  );
 }
 
-export default ReprocessingEventModal;
-
 const Introduction = styled('p')`
   font-size: ${p => p.theme.fontSizeLarge};
 `;

+ 2 - 2
static/app/views/dashboardsV2/widgetBuilder/widgetBuilder.spec.tsx

@@ -2,11 +2,11 @@ import selectEvent from 'react-select-event';
 import {urlEncode} from '@sentry/utils';
 
 import {initializeOrg} from 'sentry-test/initializeOrg';
-import {mountGlobalModal} from 'sentry-test/modal';
 import {
   act,
   fireEvent,
   render,
+  renderGlobalModal,
   screen,
   userEvent,
   waitFor,
@@ -1021,7 +1021,7 @@ describe('WidgetBuilder', function () {
 
       userEvent.click(await screen.findByText('Delete'));
 
-      await mountGlobalModal();
+      renderGlobalModal();
       userEvent.click(await screen.findByText('Confirm'));
 
       await waitFor(() => {

+ 9 - 3
static/app/views/dashboardsV2/widgetCard/index.spec.tsx

@@ -1,6 +1,12 @@
 import {initializeOrg} from 'sentry-test/initializeOrg';
-import {mountGlobalModal} from 'sentry-test/modal';
-import {act, render, screen, userEvent, waitFor} from 'sentry-test/reactTestingLibrary';
+import {
+  act,
+  render,
+  renderGlobalModal,
+  screen,
+  userEvent,
+  waitFor,
+} from 'sentry-test/reactTestingLibrary';
 
 import * as modal from 'sentry/actionCreators/modal';
 import {Client} from 'sentry/api';
@@ -427,7 +433,7 @@ describe('Dashboards > WidgetCard', function () {
     expect(screen.getByText('Delete Widget')).toBeInTheDocument();
     userEvent.click(screen.getByText('Delete Widget'));
     // Confirm Modal
-    await mountGlobalModal();
+    renderGlobalModal();
     await screen.findByRole('dialog');
 
     userEvent.click(screen.getByTestId('confirm-button'));

+ 0 - 32
static/app/views/settings/organizationApiKeys/organizationApiKeysList.spec.jsx

@@ -1,32 +0,0 @@
-import {mountGlobalModal} from 'sentry-test/modal';
-import {render, screen} from 'sentry-test/reactTestingLibrary';
-
-import OrganizationApiKeysList from 'sentry/views/settings/organizationApiKeys/organizationApiKeysList';
-
-jest.unmock('sentry/utils/recreateRoute');
-
-const routes = [
-  {path: '/'},
-  {path: '/:orgId/'},
-  {path: '/organizations/:orgId/'},
-  {path: 'api-keys/', name: 'API Key'},
-];
-
-describe('OrganizationApiKeysList', function () {
-  it('opens a modal when trying to delete a key', async function () {
-    render(
-      <OrganizationApiKeysList
-        params={{orgId: 'org-slug'}}
-        routes={routes}
-        keys={[TestStubs.ApiKey()]}
-      />
-    );
-
-    // Click remove button
-    (await screen.findByTitle('Remove API Key?')).click();
-
-    // expect a modal
-    const modal = await mountGlobalModal();
-    expect(modal.find('GlobalModal[visible=true]').exists()).toBe(true);
-  });
-});

+ 48 - 0
static/app/views/settings/organizationApiKeys/organizationApiKeysList.spec.tsx

@@ -0,0 +1,48 @@
+import {initializeOrg} from 'sentry-test/initializeOrg';
+import {
+  render,
+  renderGlobalModal,
+  screen,
+  userEvent,
+} from 'sentry-test/reactTestingLibrary';
+
+import OrganizationApiKeysList from 'sentry/views/settings/organizationApiKeys/organizationApiKeysList';
+
+jest.unmock('sentry/utils/recreateRoute');
+
+describe('OrganizationApiKeysList', function () {
+  it('opens a modal when trying to delete a key', async function () {
+    const routes = [
+      {path: '/'},
+      {path: '/:orgId/'},
+      {path: '/organizations/:orgId/'},
+      {path: 'api-keys/', name: 'API Key'},
+    ];
+
+    const {router, route} = initializeOrg({...initializeOrg(), router: {routes}});
+
+    render(
+      <OrganizationApiKeysList
+        params={{orgId: 'org-slug'}}
+        routes={routes}
+        keys={[TestStubs.ApiKey()]}
+        router={router}
+        routeParams={{}}
+        route={route}
+        busy={false}
+        loading={false}
+        location={router.location}
+        onRemove={jest.fn()}
+        onAddApiKey={jest.fn()}
+      />
+    );
+
+    // Click remove button
+    userEvent.click(await screen.findByTitle('Remove API Key?'));
+
+    // expect a modal
+    renderGlobalModal();
+
+    expect(screen.getByRole('dialog')).toBeInTheDocument();
+  });
+});