Browse Source

tests(events-v2) Add acceptance tests and percy for events modal (#13690)

With the modal approaching completion it would be good to have
acceptance tests and percy snapshots to help keep it working in the
future.

Emit a smaller query and skip queries when we would otherwise not find
a record.

Refs SEN-731
Mark Story 5 years ago
parent
commit
063b281d0b

+ 5 - 1
src/sentry/static/sentry/app/components/modalDialog.jsx

@@ -63,7 +63,11 @@ class ModalDialog extends React.Component {
     return (
       <ModalScrollTrap>
         <ModalOverlay />
-        <ModalContainer aria-modal="true" className={className}>
+        <ModalContainer
+          data-test-id="modal-dialog"
+          aria-modal="true"
+          className={className}
+        >
           {this.renderDismiss()}
           {children}
         </ModalContainer>

+ 1 - 1
src/sentry/static/sentry/app/views/organizationEventsV2/eventModalContent.jsx

@@ -90,7 +90,7 @@ const EventMetadata = props => {
 
   return (
     <SidebarBlock withSeparator>
-      <MetadataContainer>ID {event.eventID}</MetadataContainer>
+      <MetadataContainer data-test-id="event-id">ID {event.eventID}</MetadataContainer>
       <MetadataContainer>
         <DateTime
           date={getDynamicText({value: event.dateCreated, fixed: 'Dummy timestamp'})}

+ 10 - 2
src/sentry/static/sentry/app/views/organizationEventsV2/modalPagination.jsx

@@ -54,10 +54,18 @@ const ModalPagination = props => {
         <StyledLink to={oldestUrl} disabled={previousEventUrl === null}>
           <InlineSvg src="icon-prev" size="14px" />
         </StyledLink>
-        <StyledLink to={previousEventUrl} disabled={previousEventUrl === null}>
+        <StyledLink
+          data-test-id="older-event"
+          to={previousEventUrl}
+          disabled={previousEventUrl === null}
+        >
           {t('Older Event')}
         </StyledLink>
-        <StyledLink to={nextEventUrl} disabled={nextEventUrl === null}>
+        <StyledLink
+          data-test-id="newer-event"
+          to={nextEventUrl}
+          disabled={nextEventUrl === null}
+        >
           {t('Newer Event')}
         </StyledLink>
         <StyledLink to={newestUrl} disabled={nextEventUrl === null} isLast>

+ 7 - 3
src/sentry/tagstore/snuba/utils.py

@@ -47,11 +47,15 @@ def handle_non_tag_keys(keys, top_values, **kwargs):
         data = query_non_tag_data(NON_TAG_KEYS[key], **kwargs)
 
         if key == 'project.name':
-            projects = Project.objects.filter(id__in=kwargs['filter_keys']['project_id'])
             for value in data:
-                project_slug = projects.filter(id=value['project_id'])[0].slug
-                value['tags_value'] = project_slug
+                # Skip the project as the current user might not be able to see it.
+                if value['project_id'] not in kwargs['filter_keys']['project_id']:
+                    continue
+                project_slug = (Project.objects
+                                .values_list('slug', flat=True)
+                                .get(id=value['project_id']))
                 value['tags_key'] = key
+                value['tags_value'] = project_slug
         else:
             for value in data:
                 tag_value = value[NON_TAG_KEYS[key]]

+ 91 - 3
tests/acceptance/test_organization_events_v2.py

@@ -4,7 +4,9 @@ from datetime import datetime, timedelta
 from django.utils import timezone
 import pytz
 from mock import patch
+
 from sentry.testutils import AcceptanceTestCase, SnubaTestCase
+from sentry.utils.samples import load_data
 
 
 FEATURE_NAME = 'organizations:events-v2'
@@ -31,10 +33,14 @@ class OrganizationEventsTest(AcceptanceTestCase, SnubaTestCase):
         self.login_as(self.user)
         self.path = u'/organizations/{}/events/'.format(self.org.slug)
 
+    def wait_until_loaded(self):
+        self.browser.wait_until_not('.loading-indicator')
+        self.browser.wait_until_not('[data-test-id="loading-placeholder"]')
+
     def test_all_events_empty(self):
         with self.feature(FEATURE_NAME):
             self.browser.get(self.path)
-            self.browser.wait_until_not('.loading-indicator')
+            self.wait_until_loaded()
             self.browser.snapshot('events-v2 - all events empty state')
 
     @patch('django.utils.timezone.now')
@@ -54,7 +60,7 @@ class OrganizationEventsTest(AcceptanceTestCase, SnubaTestCase):
 
         with self.feature(FEATURE_NAME):
             self.browser.get(self.path)
-            self.browser.wait_until_not('.loading-indicator')
+            self.wait_until_loaded()
             self.browser.snapshot('events-v2 - all events')
 
     @patch('django.utils.timezone.now')
@@ -81,8 +87,90 @@ class OrganizationEventsTest(AcceptanceTestCase, SnubaTestCase):
             project_id=self.project.id,
             assert_no_errors=False,
         )
+        self.store_event(
+            data={
+                'event_id': 'c' * 32,
+                'message': 'this is bad.',
+                'timestamp': min_ago,
+                'fingerprint': ['group-2']
+            },
+            project_id=self.project.id,
+            assert_no_errors=False,
+        )
 
         with self.feature(FEATURE_NAME):
             self.browser.get(self.path + '?view=errors')
-            self.browser.wait_until_not('.loading-indicator')
+            self.wait_until_loaded()
             self.browser.snapshot('events-v2 - errors')
+
+    @patch('django.utils.timezone.now')
+    def test_modal_from_all_events(self, mock_now):
+        mock_now.return_value = datetime.utcnow().replace(tzinfo=pytz.utc)
+        min_ago = (timezone.now() - timedelta(minutes=1)).isoformat()[:19]
+
+        event_data = load_data('python')
+        event_data['timestamp'] = min_ago
+        event_data['received'] = min_ago
+        event_data['fingerprint'] = ['group-1']
+        self.store_event(
+            data=event_data,
+            project_id=self.project.id,
+            assert_no_errors=False
+        )
+
+        with self.feature(FEATURE_NAME):
+            # Get the list page.
+            self.browser.get(self.path)
+            self.wait_until_loaded()
+
+            # Click the event link to open the modal
+            self.browser.element('[data-test-id="event-title"]').click()
+            self.wait_until_loaded()
+
+            header = self.browser.element('[data-test-id="modal-dialog"] h2')
+            assert event_data['message'] in header.text
+
+            self.browser.snapshot('events-v2 - single error modal')
+
+    @patch('django.utils.timezone.now')
+    def test_modal_from_errors_view(self, mock_now):
+        mock_now.return_value = datetime.utcnow().replace(tzinfo=pytz.utc)
+
+        event_source = (
+            ('a', 1), ('b', 39), ('c', 69),
+        )
+        event_ids = []
+        event_data = load_data('javascript')
+        event_data['fingerprint'] = ['group-1']
+        for id_prefix, offset in event_source:
+            event_time = (timezone.now() - timedelta(minutes=offset)).isoformat()[:19]
+            event_data.update({
+                'timestamp': event_time,
+                'received': event_time,
+                'event_id': id_prefix * 32,
+                'type': 'error'
+            })
+            event = self.store_event(
+                data=event_data,
+                project_id=self.project.id,
+            )
+            event_ids.append(event.event_id)
+
+        with self.feature(FEATURE_NAME):
+            # Get the list page
+            self.browser.get(self.path + '?view=errors&statsPeriod=24h')
+            self.wait_until_loaded()
+
+            # Click the event link to open the modal
+            self.browser.element('[data-test-id="event-title"]').click()
+            self.wait_until_loaded()
+
+            self.browser.snapshot('events-v2 - grouped error modal')
+
+            # Check that the newest event is loaded first and that pagination
+            # controls display
+            display_id = self.browser.element('[data-test-id="event-id"]')
+            assert event_ids[0] in display_id.text
+
+            assert self.browser.element_exists_by_test_id('older-event')
+            assert self.browser.element_exists_by_test_id('newer-event')