Skip to content

Commit 92ab0bc

Browse files
feat(tests): Add mobile screenshot tests (#28391)
1 parent 3058025 commit 92ab0bc

File tree

19 files changed

+490
-69
lines changed

19 files changed

+490
-69
lines changed

static/app/components/acl/role.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ class Role extends React.Component<Props> {
3636
const user = ConfigStore.get('user');
3737
const {organization, role} = this.props;
3838
const {availableRoles} = organization;
39+
3940
const currentRole = organization.role ?? '';
4041

4142
if (!user) {

static/app/components/events/attachmentViewers/imageViewer.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,13 @@ import {
66
} from 'app/components/events/attachmentViewers/utils';
77
import {PanelItem} from 'app/components/panels';
88

9-
function ImageViewer({className, ...props}: ViewerProps) {
9+
type Props = Omit<ViewerProps, 'attachment'> & {
10+
attachment: Omit<ViewerProps['attachment'], 'event_id'> & {
11+
event_id?: string;
12+
};
13+
};
14+
15+
function ImageViewer({className, ...props}: Props) {
1016
return (
1117
<Container className={className}>
1218
<img src={getAttachmentUrl(props, true)} />

static/app/components/events/contextSummary/item.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ type Props = {
1111
};
1212

1313
const Item = ({children, icon, className}: Props) => (
14-
<Wrapper className={classNames('context-item', className)}>
14+
<Wrapper className={classNames('context-item', className)} data-test-id="context-item">
1515
{icon}
1616
{children && <Details>{children}</Details>}
1717
</Wrapper>

static/app/components/events/eventAttachments.tsx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import FileSize from 'app/components/fileSize';
1313
import {PanelTable} from 'app/components/panels';
1414
import {t} from 'app/locale';
1515
import overflowEllipsis from 'app/styles/overflowEllipsis';
16-
import {EventAttachment} from 'app/types';
16+
import {IssueAttachment} from 'app/types';
1717
import {Event} from 'app/types/event';
1818
import AttachmentUrl from 'app/utils/attachmentUrl';
1919
import withApi from 'app/utils/withApi';
@@ -26,8 +26,8 @@ type Props = {
2626
orgId: string;
2727
projectId: string;
2828
location: Location;
29-
attachments: EventAttachment[];
30-
onDeleteAttachment: (attachmentId: EventAttachment['id']) => void;
29+
attachments: IssueAttachment[];
30+
onDeleteAttachment: (attachmentId: IssueAttachment['id']) => void;
3131
};
3232

3333
type State = {
@@ -41,7 +41,7 @@ class EventAttachments extends React.Component<Props, State> {
4141
attachmentPreviews: {},
4242
};
4343

44-
getInlineAttachmentRenderer(attachment: EventAttachment) {
44+
getInlineAttachmentRenderer(attachment: IssueAttachment) {
4545
switch (attachment.mimetype) {
4646
case 'text/plain':
4747
return attachment.size > 0 ? LogFileViewer : undefined;
@@ -61,15 +61,15 @@ class EventAttachments extends React.Component<Props, State> {
6161
}
6262
}
6363

64-
hasInlineAttachmentRenderer(attachment: EventAttachment): boolean {
64+
hasInlineAttachmentRenderer(attachment: IssueAttachment): boolean {
6565
return !!this.getInlineAttachmentRenderer(attachment);
6666
}
6767

68-
attachmentPreviewIsOpen = (attachment: EventAttachment) => {
68+
attachmentPreviewIsOpen = (attachment: IssueAttachment) => {
6969
return !!this.state.attachmentPreviews[attachment.id];
7070
};
7171

72-
renderInlineAttachment(attachment: EventAttachment) {
72+
renderInlineAttachment(attachment: IssueAttachment) {
7373
const Component = this.getInlineAttachmentRenderer(attachment);
7474
if (!Component || !this.attachmentPreviewIsOpen(attachment)) {
7575
return null;
@@ -86,7 +86,7 @@ class EventAttachments extends React.Component<Props, State> {
8686
);
8787
}
8888

89-
togglePreview(attachment: EventAttachment) {
89+
togglePreview(attachment: IssueAttachment) {
9090
this.setState(({attachmentPreviews}) => ({
9191
attachmentPreviews: {
9292
...attachmentPreviews,

static/app/components/events/eventDataSection.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,13 @@ class EventDataSection extends React.Component<Props> {
6565
actions,
6666
isCentered,
6767
showPermalink,
68+
...props
6869
} = this.props;
6970

7071
const titleNode = wrapTitle ? <h3>{title}</h3> : title;
7172

7273
return (
73-
<DataSection ref={this.dataSectionDOMRef} className={className || ''}>
74+
<DataSection ref={this.dataSectionDOMRef} className={className || ''} {...props}>
7475
{title && (
7576
<SectionHeader id={type} isCentered={isCentered}>
7677
<Title>

static/app/components/events/eventEntries.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@ import ExternalLink from 'app/components/links/externalLink';
2727
import {t, tct} from 'app/locale';
2828
import space from 'app/styles/space';
2929
import {
30-
EventAttachment,
3130
ExceptionValue,
3231
Group,
32+
IssueAttachment,
3333
Organization,
3434
Project,
3535
SharedViewOrganization,
@@ -48,7 +48,7 @@ import {projectProcessingIssuesMessages} from 'app/views/settings/project/projec
4848
import findBestThread from './interfaces/threads/threadSelector/findBestThread';
4949
import getThreadException from './interfaces/threads/threadSelector/getThreadException';
5050
import EventEntry from './eventEntry';
51-
import EventTagAndScreenshot from './eventTagsAndScreenshot';
51+
import EventTagsAndScreenshot from './eventTagsAndScreenshot';
5252

5353
const MINIFIED_DATA_JAVA_EVENT_REGEX_MATCH =
5454
/^(([\w\$]\.[\w\$]{1,2})|([\w\$]{2}\.[\w\$]\.[\w\$]))(\.|$)/g;
@@ -88,7 +88,7 @@ const EventEntries = memo(
8888
}: Props) => {
8989
const [isLoading, setIsLoading] = useState(true);
9090
const [proGuardErrors, setProGuardErrors] = useState<ProGuardErrors>([]);
91-
const [attachments, setAttachments] = useState<EventAttachment[]>([]);
91+
const [attachments, setAttachments] = useState<IssueAttachment[]>([]);
9292

9393
const orgSlug = organization.slug;
9494
const projectSlug = project.slug;
@@ -325,7 +325,7 @@ const EventEntries = memo(
325325
));
326326
}
327327

328-
async function handleDeleteAttachment(attachmentId: EventAttachment['id']) {
328+
async function handleDeleteAttachment(attachmentId: IssueAttachment['id']) {
329329
if (!event) {
330330
return;
331331
}
@@ -393,7 +393,7 @@ const EventEntries = memo(
393393
)}
394394
{showTagSummary &&
395395
(hasMobileScreenshotsFeature ? (
396-
<EventTagAndScreenshot
396+
<EventTagsAndScreenshot
397397
event={event}
398398
organization={organization as Organization}
399399
projectId={projectSlug}

static/app/components/events/eventTagsAndScreenshot/dataSection.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,11 @@ type Props = {
1313
className?: string;
1414
};
1515

16-
function DataSection({title, description, children, className}: Props) {
16+
function DataSection({title, description, children, className, ...props}: Props) {
1717
const type = kebabCase(title);
1818
return (
1919
<StyledEventDataSection
20+
{...props}
2021
className={className}
2122
type={type}
2223
title={

static/app/components/events/eventTagsAndScreenshot/index.tsx

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,49 +8,56 @@ import Tags from './tags';
88

99
type ScreenshotProps = React.ComponentProps<typeof Screenshot>;
1010

11-
type Props = Omit<React.ComponentProps<typeof Tags>, 'projectSlug'> &
12-
Pick<ScreenshotProps, 'attachments'> & {
13-
projectId: string;
14-
isShare: boolean;
15-
isBorderless: boolean;
16-
onDeleteScreenshot: ScreenshotProps['onDelete'];
17-
};
11+
type Props = Omit<React.ComponentProps<typeof Tags>, 'projectSlug' | 'hasContext'> & {
12+
projectId: string;
13+
onDeleteScreenshot: ScreenshotProps['onDelete'];
14+
attachments: ScreenshotProps['screenshot'][];
15+
isShare?: boolean;
16+
isBorderless?: boolean;
17+
hasContext?: boolean;
18+
};
1819

1920
function EventTagsAndScreenshots({
2021
projectId: projectSlug,
21-
isShare,
22-
hasContext,
2322
location,
24-
isBorderless,
2523
event,
2624
attachments,
2725
onDeleteScreenshot,
28-
...props
26+
organization,
27+
isShare = false,
28+
isBorderless = false,
29+
hasContext = false,
2930
}: Props) {
3031
const {tags = []} = event;
3132

32-
if (!tags.length && !hasContext && isShare) {
33+
const screenshot = attachments.find(
34+
({name}) => name === 'screenshot.jpg' || name === 'screenshot.png'
35+
);
36+
37+
if (!tags.length && !hasContext && (isShare || !screenshot)) {
3338
return null;
3439
}
3540

3641
return (
3742
<Wrapper isBorderless={isBorderless}>
38-
{!isShare && !!attachments.length && (
43+
{!isShare && !!screenshot && (
3944
<Screenshot
40-
{...props}
45+
organization={organization}
4146
event={event}
4247
projectSlug={projectSlug}
43-
attachments={attachments}
48+
screenshot={screenshot}
4449
onDelete={onDeleteScreenshot}
4550
/>
4651
)}
47-
<Tags
48-
{...props}
49-
event={event}
50-
projectSlug={projectSlug}
51-
hasContext={hasContext}
52-
location={location}
53-
/>
52+
{(!!tags.length || hasContext) && (
53+
<Tags
54+
organization={organization}
55+
event={event}
56+
projectSlug={projectSlug}
57+
hasContext={hasContext}
58+
location={location}
59+
/>
60+
)}
5461
</Wrapper>
5562
);
5663
}

static/app/components/events/eventTagsAndScreenshot/screenshot/index.tsx

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -23,18 +23,13 @@ type Props = {
2323
event: Event;
2424
organization: Organization;
2525
projectSlug: Project['slug'];
26-
attachments: EventAttachment[];
26+
screenshot: EventAttachment;
2727
onDelete: (attachmentId: EventAttachment['id']) => void;
2828
};
2929

30-
function Screenshot({event, attachments, organization, projectSlug, onDelete}: Props) {
30+
function Screenshot({event, organization, screenshot, projectSlug, onDelete}: Props) {
3131
const orgSlug = organization.slug;
3232

33-
function hasScreenshot(attachment: EventAttachment) {
34-
const {mimetype} = attachment;
35-
return mimetype === 'image/jpeg' || mimetype === 'image/png';
36-
}
37-
3833
function handleOpenVisualizationModal(
3934
eventAttachment: EventAttachment,
4035
downloadUrl: string
@@ -118,22 +113,20 @@ function Screenshot({event, attachments, organization, projectSlug, onDelete}: P
118113
}
119114

120115
return (
121-
<Role role={organization.attachmentsRole}>
116+
<Role organization={organization} role={organization.attachmentsRole}>
122117
{({hasRole}) => {
123-
const screenshotAttachment = attachments.find(hasScreenshot);
124-
125-
if (!hasRole || !screenshotAttachment) {
118+
if (!hasRole) {
126119
return null;
127120
}
128121

129122
return (
130123
<DataSection
131-
title={t('Screenshots')}
124+
title={t('Screenshot')}
132125
description={t(
133-
'Screenshots help identify what the user saw when the event happened'
126+
'Screenshot help identify what the user saw when the event happened'
134127
)}
135128
>
136-
<StyledPanel>{renderContent(screenshotAttachment)}</StyledPanel>
129+
<StyledPanel>{renderContent(screenshot)}</StyledPanel>
137130
</DataSection>
138131
);
139132
}}

static/app/components/events/eventTagsAndScreenshot/tags.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ function Tags({event, organization, projectSlug, location, hasContext}: Props) {
2626
description={t(
2727
'Tags help you quickly both access related events and view the tag distribution for a set of events'
2828
)}
29+
data-test-id="event-tags"
2930
>
3031
{hasContext && <TagsHighlight event={event} />}
3132
<EventTags

0 commit comments

Comments
 (0)