import {LocationFixture} from 'sentry-fixture/locationFixture';
import {OrganizationFixture} from 'sentry-fixture/organization';
import {ProjectFixture} from 'sentry-fixture/project';
import {render, screen, waitFor} from 'sentry-test/reactTestingLibrary';
import {useLocation} from 'sentry/utils/useLocation';
import usePageFilters from 'sentry/utils/usePageFilters';
import {SpanOperationTable} from 'sentry/views/insights/mobile/appStarts/components/tables/spanOperationTable';
jest.mock('sentry/utils/usePageFilters');
jest.mock('sentry/utils/useLocation');
describe('SpanOpSelector', function () {
const organization = OrganizationFixture();
const project = ProjectFixture();
let mockEventsRequest;
jest.mocked(usePageFilters).mockReturnValue({
isReady: true,
desyncedFilters: new Set(),
pinnedFilters: new Set(),
shouldPersist: true,
selection: {
datetime: {
period: '10d',
start: null,
end: null,
utc: false,
},
environments: [],
projects: [parseInt(project.id, 10)],
},
});
jest.mocked(useLocation).mockReturnValue(LocationFixture());
beforeEach(function () {
MockApiClient.clearMockResponses();
mockEventsRequest = MockApiClient.addMockResponse({
url: `/organizations/${organization.slug}/events/`,
body: {
meta: {
fields: {
'project.id': 'integer',
'span.op': 'string',
'span.description': 'string',
'span.group': 'string',
'avg_if(span.self_time,release,release1)': 'duration',
'avg_compare(span.self_time,release,release1,release2)': 'percent_change',
'count()': 'integer',
'avg_if(span.self_time,release,release2)': 'duration',
'sum(span.self_time)': 'duration',
},
},
data: [
{
'project.id': parseInt(project.id, 10),
'span.op': 'app.start.warm',
'span.description': 'Application Init',
'span.group': '7f4be68f08c0455f',
'avg_if(span.self_time,release,release1)': 22.549867,
'avg_compare(span.self_time,release,release1,release2)': 0.5,
'count()': 14,
'avg_if(span.self_time,release,release2)': 12504.931908384617,
'sum(span.self_time)': 162586.66467600001,
},
],
},
});
});
it('renders data properly', async function () {
render(
);
expect(await screen.findByRole('link', {name: 'Operation'})).toBeInTheDocument();
expect(screen.getByRole('link', {name: 'Span Description'})).toBeInTheDocument();
expect(screen.getByRole('link', {name: 'Avg Duration (R1)'})).toBeInTheDocument();
expect(screen.getByRole('link', {name: 'Avg Duration (R2)'})).toBeInTheDocument();
expect(screen.getByRole('link', {name: 'Change'})).toBeInTheDocument();
expect(await screen.findByRole('cell', {name: 'app.start.warm'})).toBeInTheDocument();
expect(screen.getByRole('cell', {name: 'Application Init'})).toBeInTheDocument();
expect(screen.getByRole('cell', {name: '22.55ms'})).toBeInTheDocument();
expect(screen.getByRole('cell', {name: '12.50s'})).toBeInTheDocument();
expect(screen.getByRole('cell', {name: '+50%'})).toBeInTheDocument();
expect(screen.getByRole('link', {name: 'Application Init'})).toHaveAttribute(
'href',
'/organizations/org-slug/insights/mobile/app-startup/spans/?spanDescription=Application%20Init&spanGroup=7f4be68f08c0455f&spanOp=app.start.warm&transaction=foo-bar'
);
});
it('displays the infinity symbol for new spans with null percent change', async function () {
mockEventsRequest = MockApiClient.addMockResponse({
url: `/organizations/${organization.slug}/events/`,
body: {
meta: {
fields: {
'project.id': 'integer',
'span.op': 'string',
'span.description': 'string',
'span.group': 'string',
'avg_if(span.self_time,release,release1)': 'duration',
'avg_compare(span.self_time,release,release1,release2)': 'percent_change',
'count()': 'integer',
'avg_if(span.self_time,release,release2)': 'duration',
'sum(span.self_time)': 'duration',
},
},
data: [
{
'project.id': parseInt(project.id, 10),
'span.op': 'app.start.warm',
'span.description': 'Application Init',
'span.group': '7f4be68f08c0455f',
'count()': 14,
'sum(span.self_time)': 162586.66467600001,
// simulate a scenario where a span was added in release 2
'avg_if(span.self_time,release,release1)': 0,
'avg_if(span.self_time,release,release2)': 12504.931908384617,
'avg_compare(span.self_time,release,release1,release2)': null,
},
],
},
});
render(
);
expect(await screen.findByRole('cell', {name: '+∞%'})).toBeInTheDocument();
});
it('modifies the request to events when a span operation is selected', async function () {
// Mock useLocation to simulate the span op query param
jest.mocked(useLocation).mockReturnValue(
LocationFixture({
query: {
'span.op': 'app.start.cold',
},
})
);
MockApiClient.addMockResponse({
url: `/organizations/${organization.slug}/events/`,
body: {
meta: {
fields: {
'span.op': 'string',
'count()': 'integer',
},
},
data: [
{
'span.op': 'app.start.cold',
'count()': 1,
},
],
},
match: [
function (_url: string, options: Record) {
return options?.query?.referrer === 'api.starfish.get-span-operations';
},
],
});
render(
);
await waitFor(function () {
expect(mockEventsRequest).toHaveBeenCalledWith(
'/organizations/org-slug/events/',
expect.objectContaining({
query: expect.objectContaining({
query: expect.stringContaining('span.op:app.start.cold'),
}),
})
);
});
});
});