import {render, screen, userEvent, waitFor} from 'sentry-test/reactTestingLibrary';
import {SlowestFunctionsTable} from 'sentry/views/profiling/landing/slowestFunctionsTable';
describe('SlowestFunctionsTable', () => {
it('shows loading state', () => {
MockApiClient.addMockResponse({
url: '/organizations/org-slug/profiling/flamegraph/',
body: [],
});
render();
expect(screen.getByTestId('loading-indicator')).toBeInTheDocument();
});
it('shows error state', async () => {
MockApiClient.addMockResponse({
url: '/organizations/org-slug/profiling/flamegraph/',
body: [],
statusCode: 500,
});
render();
expect(await screen.findByTestId('error-indicator')).toBeInTheDocument();
});
it('shows no functions state', async () => {
// @ts-expect-error partial schema mock
const schema: Profiling.Schema = {
metrics: [],
};
MockApiClient.addMockResponse({
url: '/organizations/org-slug/profiling/flamegraph/',
match: [
MockApiClient.matchQuery({
expand: 'metrics',
}),
],
body: schema,
});
render();
expect(await screen.findByText('No functions found')).toBeInTheDocument();
});
it('renders function fields', async () => {
// @ts-expect-error partial schema mock
const schema: Profiling.Schema = {
metrics: [
{
name: 'slow-function',
package: 'slow-package',
p75: 1500 * 1e6,
p95: 2000 * 1e6,
p99: 3000 * 1e6,
sum: 60_000 * 1e6,
count: 5000,
avg: 0.5 * 1e6,
in_app: true,
fingerprint: 12345,
examples: [
{
project_id: 1,
profile_id: 'profile-id',
},
],
},
],
};
MockApiClient.addMockResponse({
url: '/organizations/org-slug/profiling/flamegraph/',
match: [
MockApiClient.matchQuery({
expand: 'metrics',
}),
],
body: schema,
});
render();
for (const value of ['slow-function', 'slow-package', '1.50s', '2.00s', '3.00s']) {
expect(await screen.findByText(value)).toBeInTheDocument();
}
});
it('paginates response', async () => {
// @ts-expect-error partial schema mock
const schema: Profiling.Schema = {
metrics: [],
};
for (let i = 0; i < 10; i++) {
schema.metrics?.push({
name: 'slow-function',
package: 'slow-package',
p75: 1500 * 1e6,
p95: 2000 * 1e6,
p99: 3000 * 1e6,
sum: 60_000 * 1e6,
count: 5000,
avg: 0.5 * 1e6,
in_app: true,
fingerprint: 12345,
examples: [
{
project_id: 1,
profile_id: 'profile-id',
},
],
});
}
MockApiClient.addMockResponse({
url: '/organizations/org-slug/profiling/flamegraph/',
match: [
MockApiClient.matchQuery({
expand: 'metrics',
}),
],
body: schema,
});
render();
expect(await screen.findAllByText('slow-function')).toHaveLength(5);
});
it('paginates results', async () => {
// @ts-expect-error partial schema mock
const schema: Profiling.Schema = {
metrics: [],
};
for (let i = 0; i < 10; i++) {
schema.metrics?.push({
name: 'slow-function-' + i,
package: 'slow-package',
p75: 1500 * 1e6,
p95: 2000 * 1e6,
p99: 3000 * 1e6,
sum: 60_000 * 1e6,
count: 5000,
avg: 0.5 * 1e6,
in_app: true,
fingerprint: 12345,
examples: [
{
project_id: 1,
profile_id: 'profile-id',
},
],
});
}
MockApiClient.addMockResponse({
url: '/organizations/org-slug/profiling/flamegraph/',
match: [
MockApiClient.matchQuery({
expand: 'metrics',
}),
],
body: schema,
});
render();
expect(await screen.findAllByText('slow-package')).toHaveLength(5);
await userEvent.click(screen.getByLabelText('Next'));
for (let i = 6; i < 10; i++) {
expect(await screen.findByText('slow-function-' + i)).toBeInTheDocument();
}
expect(screen.getByLabelText('Next')).toBeDisabled();
await userEvent.click(screen.getByLabelText('Previous'));
for (let i = 0; i < 5; i++) {
expect(await screen.findByText('slow-function-' + i)).toBeInTheDocument();
}
expect(screen.getByLabelText('Previous')).toBeDisabled();
});
it('fetches function metrics', async () => {
// @ts-expect-error partial schema mock
const schema: Profiling.Schema = {
metrics: [],
};
for (let i = 0; i < 10; i++) {
schema.metrics?.push({
name: 'slow-function-' + i,
package: 'slow-package',
p75: 1500 * 1e6,
p95: 2000 * 1e6,
p99: 3000 * 1e6,
sum: 60_000 * 1e6,
count: 5000,
avg: 0.5 * 1e6,
in_app: true,
fingerprint: 12345,
examples: [
{
project_id: 1,
profile_id: 'profile-id',
},
],
});
}
MockApiClient.addMockResponse({
url: '/organizations/org-slug/profiling/flamegraph/',
match: [
MockApiClient.matchQuery({
expand: 'metrics',
}),
],
body: schema,
});
const functionMetricsRequest = MockApiClient.addMockResponse({
url: '/organizations/org-slug/events-stats/',
match: [
MockApiClient.matchQuery({
query: 'fingerprint:12345',
dataset: 'profileFunctionsMetrics',
}),
],
body: [],
});
render();
const expandButtons = await screen.findAllByLabelText('View Function Metrics');
expect(expandButtons).toHaveLength(5);
await userEvent.click(expandButtons[0]);
await waitFor(() => {
expect(functionMetricsRequest).toHaveBeenCalled();
});
});
});