diff --git a/static/app/views/projectDetail/projectCharts.spec.tsx b/static/app/views/projectDetail/projectCharts.spec.tsx index 739ee440a802b1..84cf1bd2c0c52f 100644 --- a/static/app/views/projectDetail/projectCharts.spec.tsx +++ b/static/app/views/projectDetail/projectCharts.spec.tsx @@ -87,7 +87,7 @@ describe('ProjectDetail > ProjectCharts', () => { screen.getByRole('button', {name: 'Display Crash Free Sessions'}) ); - expect(screen.getByText('ANR Rate')).toBeInTheDocument(); + expect(screen.getByText('App Hang Rate')).toBeInTheDocument(); expect(screen.queryByText('Foreground ANR Rate')).not.toBeInTheDocument(); }); @@ -98,7 +98,7 @@ describe('ProjectDetail > ProjectCharts', () => { screen.getByRole('button', {name: 'Display Crash Free Sessions'}) ); - expect(screen.getByText('ANR Rate')).toBeInTheDocument(); + expect(screen.getByText('App Hang Rate')).toBeInTheDocument(); expect(screen.queryByText('Foreground ANR Rate')).not.toBeInTheDocument(); }); @@ -109,7 +109,7 @@ describe('ProjectDetail > ProjectCharts', () => { screen.getByRole('button', {name: 'Display Crash Free Sessions'}) ); - expect(screen.queryByText('ANR Rate')).not.toBeInTheDocument(); + expect(screen.queryByText('App Hang Rate')).not.toBeInTheDocument(); expect(screen.queryByText('Foreground ANR Rate')).not.toBeInTheDocument(); }); diff --git a/static/app/views/projectDetail/projectCharts.tsx b/static/app/views/projectDetail/projectCharts.tsx index 54ca8f75aed324..972e85be9e224c 100644 --- a/static/app/views/projectDetail/projectCharts.tsx +++ b/static/app/views/projectDetail/projectCharts.tsx @@ -38,6 +38,7 @@ import {decodeScalar} from 'sentry/utils/queryString'; import {MutableSearch} from 'sentry/utils/tokenizeSearch'; import withApi from 'sentry/utils/withApi'; import { + getANRRateText, isPlatformANRCompatible, isPlatformForegroundANRCompatible, } from 'sentry/views/projectDetail/utils'; @@ -225,7 +226,7 @@ class ProjectCharts extends Component { const anrRateOptions = [ { value: DisplayModes.ANR_RATE, - label: t('ANR Rate'), + label: getANRRateText(project?.platform), disabled: this.otherActiveDisplayModes.includes(DisplayModes.ANR_RATE) || !hasSessions, tooltip: hasSessions ? undefined : noHealthTooltip, @@ -449,8 +450,11 @@ class ProjectCharts extends Component { )} {hasAnrRateFeature && displayMode === DisplayModes.ANR_RATE && ( ; diff --git a/static/app/views/projectDetail/projectScoreCards/projectScoreCards.tsx b/static/app/views/projectDetail/projectScoreCards/projectScoreCards.tsx index f10227d4fda38f..b337a244a6cb87 100644 --- a/static/app/views/projectDetail/projectScoreCards/projectScoreCards.tsx +++ b/static/app/views/projectDetail/projectScoreCards/projectScoreCards.tsx @@ -68,6 +68,7 @@ function ProjectScoreCards({ isProjectStabilized={isProjectStabilized} query={query} location={location} + platform={project?.platform} /> ) : ( { + it('returns correct query text for apple platforms', () => { + expect(getANRIssueQueryText('apple')).toBe( + 'error.type:["Fatal App Hang Fully Blocked","Fatal App Hang Non Fully Blocked"]' + ); + expect(getANRIssueQueryText('apple-ios')).toBe( + 'error.type:["Fatal App Hang Fully Blocked","Fatal App Hang Non Fully Blocked"]' + ); + }); + + it('returns correct query text for android platform', () => { + expect(getANRIssueQueryText('android')).toBe('mechanism:[ANR,AppExitInfo]'); + }); + + it('returns correct query text for other platforms', () => { + expect(getANRIssueQueryText('windows')).toBe('mechanism:[ANR,AppExitInfo]'); + expect(getANRIssueQueryText()).toBe('mechanism:[ANR,AppExitInfo]'); + }); + }); }); diff --git a/static/app/views/projectDetail/utils.tsx b/static/app/views/projectDetail/utils.tsx index e494e5aadd5060..ade082a7139cf5 100644 --- a/static/app/views/projectDetail/utils.tsx +++ b/static/app/views/projectDetail/utils.tsx @@ -13,10 +13,11 @@ export function isPlatformANRCompatible(platform?: PlatformKey, features?: strin if (isPlatformForegroundANRCompatible(platform)) { return true; } - if (platform === 'apple' || platform === 'apple-ios') { - if (features?.includes('project-detail-apple-app-hang-rate')) { - return true; - } + if ( + isAppHangPlatform(platform) && + features?.includes('project-detail-apple-app-hang-rate') + ) { + return true; } return false; } @@ -24,3 +25,25 @@ export function isPlatformANRCompatible(platform?: PlatformKey, features?: strin export function isPlatformForegroundANRCompatible(platform?: PlatformKey) { return platform === 'javascript-electron' || platform === 'android'; } + +export function getANRRateText(platform?: PlatformKey) { + if (isAppHangPlatform(platform)) { + return 'App Hang Rate'; + } + + return 'ANR Rate'; +} + +export function getANRIssueQueryText(platform?: PlatformKey) { + if (isAppHangPlatform(platform)) { + return 'error.type:["Fatal App Hang Fully Blocked","Fatal App Hang Non Fully Blocked"]'; + } + + return 'mechanism:[ANR,AppExitInfo]'; +} + +// Don't include apple-macos because the ANR rate requires app hangs V2, +// which is not available on macos, when writing this comment on 2025-03-17. +const isAppHangPlatform = (platform?: PlatformKey): boolean => { + return platform === 'apple' || platform === 'apple-ios'; +}; diff --git a/static/app/views/releases/utils/sessionTerm.spec.tsx b/static/app/views/releases/utils/sessionTerm.spec.tsx index 74663f3da7a515..571649af60d501 100644 --- a/static/app/views/releases/utils/sessionTerm.spec.tsx +++ b/static/app/views/releases/utils/sessionTerm.spec.tsx @@ -470,6 +470,15 @@ describe('Release Health Session Term', function () { 'apple-macos' ); expect(unhandledSessionTerm).toEqual(mobileTermsDescription.unhandled); + + // ANR Rate + const anrRateSessionTerm = getSessionTermDescription( + SessionTerm.ANR_RATE, + 'apple-ios' + ); + expect(anrRateSessionTerm).toBe( + 'Percentage of unique users that experienced a fatal App Hang.' + ); }); it('node-express terms', function () { diff --git a/static/app/views/releases/utils/sessionTerm.tsx b/static/app/views/releases/utils/sessionTerm.tsx index 90491b7f63da15..2388a0a94f8318 100644 --- a/static/app/views/releases/utils/sessionTerm.tsx +++ b/static/app/views/releases/utils/sessionTerm.tsx @@ -123,6 +123,9 @@ function getTermDescriptions(platform: PlatformKey | null) { ...commonTermsDescription, ...mobileTermsDescription, [SessionTerm.CRASHED]: t('An error that resulted in the application crashing'), + [SessionTerm.ANR_RATE]: t( + 'Percentage of unique users that experienced a fatal App Hang.' + ), }; } case 'node':