import {EventFixture} from 'sentry-fixture/event';
import {GroupFixture} from 'sentry-fixture/group';
import {OrganizationFixture} from 'sentry-fixture/organization';
import {ProjectFixture} from 'sentry-fixture/project';
import {RouterFixture} from 'sentry-fixture/routerFixture';
import {UptimeCheckFixture} from 'sentry-fixture/uptimeCheck';
import {UptimeRuleFixture} from 'sentry-fixture/uptimeRule';
import {render, screen} from 'sentry-test/reactTestingLibrary';
import GroupStore from 'sentry/stores/groupStore';
import PageFiltersStore from 'sentry/stores/pageFiltersStore';
import ProjectsStore from 'sentry/stores/projectsStore';
import {IssueCategory, IssueType} from 'sentry/types/group';
import {getShortEventId} from 'sentry/utils/events';
import {statusToText} from 'sentry/views/insights/uptime/timelineConfig';
import GroupUptimeChecks from 'sentry/views/issueDetails/groupUptimeChecks';
describe('GroupUptimeChecks', () => {
const uptimeRuleId = '123';
const event = EventFixture({
tags: [
{
key: 'uptime_rule',
value: uptimeRuleId,
},
],
});
const group = GroupFixture({
issueCategory: IssueCategory.UPTIME,
issueType: IssueType.UPTIME_DOMAIN_FAILURE,
});
const organization = OrganizationFixture();
const project = ProjectFixture();
const router = RouterFixture({
params: {groupId: group.id},
});
beforeEach(() => {
GroupStore.init();
GroupStore.add([group]);
ProjectsStore.init();
ProjectsStore.loadInitialData([project]);
MockApiClient.clearMockResponses();
MockApiClient.addMockResponse({
url: `/organizations/${organization.slug}/issues/${group.id}/`,
body: group,
});
MockApiClient.addMockResponse({
url: `/organizations/${organization.slug}/issues/${group.id}/events/recommended/`,
body: event,
});
MockApiClient.addMockResponse({
url: `/projects/org-slug/project-slug/uptime/123/`,
body: UptimeRuleFixture(),
});
PageFiltersStore.onInitializeUrlState(
{
projects: [Number(project.id)],
environments: [],
datetime: {period: '24h', start: null, end: null, utc: null},
},
new Set()
);
});
it('renders the empty uptime check table', async () => {
MockApiClient.addMockResponse({
url: `/projects/${organization.slug}/${project.slug}/uptime/${uptimeRuleId}/checks/`,
body: [],
});
render(, {organization, router});
expect(await screen.findByText('All Uptime Checks')).toBeInTheDocument();
for (const column of ['Timestamp', 'Status', 'Duration', 'Trace', 'Region']) {
expect(screen.getByText(column)).toBeInTheDocument();
}
expect(screen.getByText('No matching uptime checks found')).toBeInTheDocument();
});
it('renders the uptime check table with data', async () => {
const uptimeCheck = UptimeCheckFixture();
MockApiClient.addMockResponse({
url: `/projects/${organization.slug}/${project.slug}/uptime/${uptimeRuleId}/checks/`,
body: [uptimeCheck],
});
MockApiClient.addMockResponse({
url: `/organizations/${organization.slug}/events/`,
method: 'GET',
body: {
data: [],
},
match: [MockApiClient.matchQuery({referrer: 'api.uptime-checks-grid'})],
});
render(, {organization, router});
expect(await screen.findByText('All Uptime Checks')).toBeInTheDocument();
expect(screen.queryByText('No matching uptime checks found')).not.toBeInTheDocument();
expect(screen.getByText('Showing 1-1 matching uptime checks')).toBeInTheDocument();
expect(screen.getByRole('button', {name: 'Previous Page'})).toBeInTheDocument();
expect(screen.getByRole('button', {name: 'Next Page'})).toBeInTheDocument();
expect(screen.getByRole('time')).toHaveTextContent(/Jan 1, 2025/);
expect(screen.getByText(statusToText[uptimeCheck.checkStatus])).toBeInTheDocument();
expect(screen.getByText(`${uptimeCheck.durationMs}ms`)).toBeInTheDocument();
expect(screen.getByText(getShortEventId(uptimeCheck.traceId))).toBeInTheDocument();
expect(screen.getByText(uptimeCheck.regionName)).toBeInTheDocument();
// Span counts also need to load
expect(await screen.findByText('0 spans')).toBeInTheDocument();
});
it('indicates when there are spans in a trace', async () => {
const uptimeCheck = UptimeCheckFixture();
MockApiClient.addMockResponse({
url: `/projects/${organization.slug}/${project.slug}/uptime/${uptimeRuleId}/checks/`,
body: [uptimeCheck],
});
MockApiClient.addMockResponse({
url: `/organizations/${organization.slug}/events/`,
method: 'GET',
body: {
data: [{trace: uptimeCheck.traceId, 'count()': 10}],
},
match: [MockApiClient.matchQuery({referrer: 'api.uptime-checks-grid'})],
});
render(, {organization, router});
expect(await screen.findByText('All Uptime Checks')).toBeInTheDocument();
const traceId = getShortEventId(uptimeCheck.traceId);
// TraceID is a not link until we know there are spans
expect(screen.getByText(traceId)).toBeInTheDocument();
expect(screen.queryByRole('link', {name: traceId})).not.toBeInTheDocument();
// Once the span count has loaded it will be a link
expect(await screen.findByText('10 spans')).toBeInTheDocument();
expect(screen.getByRole('link', {name: traceId})).toBeInTheDocument();
});
});