import {ProjectFixture} from 'sentry-fixture/project';
import {getAllByRole, render, screen, userEvent} from 'sentry-test/reactTestingLibrary';
import ProjectsStore from 'sentry/stores/projectsStore';
import {SlowestFunctionsWidget} from 'sentry/views/profiling/landing/slowestFunctionsWidget';
describe('SlowestFunctionsWidget', function () {
beforeEach(function () {
const project = ProjectFixture({
id: '1',
slug: 'proj-slug',
});
ProjectsStore.loadInitialData([project]);
});
afterEach(function () {
MockApiClient.clearMockResponses();
});
it('renders errors', async function () {
// return 400 for all queries
MockApiClient.addMockResponse({
url: '/organizations/org-slug/events/',
statusCode: 400,
});
render();
// starts by rendering loading
expect(screen.getByTestId('loading-indicator')).toBeInTheDocument();
// switches to errors once the api responds with an error
expect(await screen.findByTestId('error-indicator')).toBeInTheDocument();
});
it('renders no functions', async function () {
// for the slowest functions query
MockApiClient.addMockResponse({
url: '/organizations/org-slug/events/',
body: {
data: [],
},
match: [
MockApiClient.matchQuery({
dataset: 'profileFunctions',
field: ['project.id', 'fingerprint', 'package', 'function', 'count()', 'sum()'],
}),
],
});
render();
// starts by rendering loading
expect(screen.getByTestId('loading-indicator')).toBeInTheDocument();
// switches to the no functions view
expect(await screen.findByText('No functions found')).toBeInTheDocument();
});
it('renders examples and chart', async function () {
// for the slowest functions query
MockApiClient.addMockResponse({
url: '/organizations/org-slug/events/',
body: {
data: [
{
'project.id': 1,
fingerprint: 123,
package: 'foo',
function: 'bar',
'sum()': 150,
},
{
'project.id': 1,
fingerprint: 456,
package: 'baz',
function: 'qux',
'sum()': 100,
},
],
},
match: [
MockApiClient.matchQuery({
dataset: 'profileFunctions',
field: ['project.id', 'fingerprint', 'package', 'function', 'count()', 'sum()'],
}),
],
});
// for the totals query
MockApiClient.addMockResponse({
url: '/organizations/org-slug/events/',
body: {data: [{'project.id': 1, 'sum()': 2500000}]},
match: [
MockApiClient.matchQuery({
dataset: 'profileFunctions',
field: ['project.id', 'sum()'],
project: [1],
}),
],
});
// for the chart + examples
MockApiClient.addMockResponse({
url: '/organizations/org-slug/events-stats/',
body: {
123: {
'all_examples()': {
order: 0,
start: 0,
end: 1000,
meta: {
fields: {
time: 'date',
fingerprint: 'integer',
p75: 'duration',
all_examples: 'string',
},
units: {
time: null,
fingerprint: null,
p75: 'nanosecond',
all_examples: null,
},
},
data: [
[0, [{count: 0}]],
[500, [{count: [{profile_id: '1'.repeat(32)}]}]],
[
1000,
[
{
count: [
{profiler_id: '2'.repeat(32), thread_id: '0', start: 0, end: 1000},
],
},
],
],
],
},
'p75()': {
order: 1,
start: 0,
end: 1000,
meta: {
fields: {
time: 'date',
fingerprint: 'integer',
p75: 'duration',
all_examples: 'string',
},
units: {
time: null,
fingerprint: null,
p75: 'nanosecond',
all_examples: null,
},
},
data: [
[0, [{count: 1}]],
[500, [{count: 2}]],
[1000, [{count: 3}]],
],
},
},
456: {
'all_examples()': {
order: 0,
start: 0,
end: 1000,
meta: {
fields: {
time: 'date',
fingerprint: 'integer',
p75: 'duration',
all_examples: 'string',
},
units: {
time: null,
fingerprint: null,
p75: 'nanosecond',
all_examples: null,
},
},
data: [
[0, [{count: 0}]],
[500, [{count: [{profile_id: '3'.repeat(32)}]}]],
[
1000,
[
{
count: [
{profiler_id: '4'.repeat(32), thread_id: '0', start: 0, end: 1000},
],
},
],
],
],
},
'p75()': {
order: 1,
start: 0,
end: 1000,
meta: {
fields: {
time: 'date',
fingerprint: 'integer',
p75: 'duration',
all_examples: 'string',
},
units: {
time: null,
fingerprint: null,
p75: 'nanosecond',
all_examples: null,
},
},
data: [
[0, [{count: 1}]],
[500, [{count: 2}]],
[1000, [{count: 3}]],
],
},
},
},
match: [
MockApiClient.matchQuery({
dataset: 'profileFunctions',
field: ['fingerprint', 'all_examples()', 'p75()'],
yAxis: ['all_examples()', 'p75()'],
project: [1],
}),
],
});
render();
// starts by rendering loading
expect(screen.getByTestId('loading-indicator')).toBeInTheDocument();
// switches to the functions-chart once the api responds with data
expect(await screen.findByTestId('function-chart')).toBeInTheDocument();
const items = screen.getAllByRole('listitem', {});
expect(items.length).toEqual(2);
const buttons = getAllByRole(items[0], 'button', {});
expect(buttons.length).toEqual(2);
await userEvent.click(buttons[1]);
expect(screen.getByText('1'.repeat(8))).toBeInTheDocument();
expect(screen.getByText('2'.repeat(8))).toBeInTheDocument();
});
});