import {LocationFixture} from 'sentry-fixture/locationFixture';
import {OrganizationFixture} from 'sentry-fixture/organization';
import {ProjectFixture} from 'sentry-fixture/project';
import {initializeOrg} from 'sentry-test/initializeOrg';
import {
render,
renderGlobalModal,
screen,
userEvent,
waitFor,
} from 'sentry-test/reactTestingLibrary';
import * as pageFilterUtils from 'sentry/components/organizations/pageFilters/persistence';
import ProjectsStore from 'sentry/stores/projectsStore';
import {browserHistory} from 'sentry/utils/browserHistory';
import EventView from 'sentry/utils/discover/eventView';
import {DEFAULT_EVENT_VIEW} from './data';
import Homepage from './homepage';
describe('Discover > Homepage', () => {
const features = ['global-views', 'discover-query'];
let initialData, organization, mockHomepage, measurementsMetaMock;
beforeEach(() => {
organization = OrganizationFixture({
features,
});
initialData = initializeOrg({
organization,
router: {
location: LocationFixture(),
},
});
ProjectsStore.loadInitialData(initialData.projects);
MockApiClient.addMockResponse({
url: '/organizations/org-slug/events/',
body: [],
});
MockApiClient.addMockResponse({
url: '/organizations/org-slug/events-meta/',
body: {
count: 2,
},
});
MockApiClient.addMockResponse({
url: '/organizations/org-slug/events-stats/',
body: {data: [[123, []]]},
});
MockApiClient.addMockResponse({
url: '/organizations/org-slug/tags/',
body: [],
});
MockApiClient.addMockResponse({
url: '/organizations/org-slug/releases/stats/',
body: [],
});
MockApiClient.addMockResponse({
url: '/organizations/org-slug/dynamic-sampling/custom-rules/',
body: '',
});
mockHomepage = MockApiClient.addMockResponse({
url: '/organizations/org-slug/discover/homepage/',
method: 'GET',
statusCode: 200,
body: {
id: '2',
name: 'homepage query',
projects: [],
version: 2,
expired: false,
dateCreated: '2021-04-08T17:53:25.195782Z',
dateUpdated: '2021-04-09T12:13:18.567264Z',
createdBy: {
id: '2',
},
environment: ['alpha'],
fields: ['environment'],
widths: ['-1'],
range: '24h',
orderby: '-environment',
display: 'previous',
query: 'event.type:error',
queryDataset: 'discover',
},
});
measurementsMetaMock = MockApiClient.addMockResponse({
url: '/organizations/org-slug/measurements-meta/',
method: 'GET',
body: {},
});
});
it('renders the Discover banner', async () => {
render(
,
{router: initialData.router, organization: initialData.organization}
);
await screen.findByText('Discover Trends');
screen.getByText('Get a Tour');
expect(screen.queryByText('Build a new query')).not.toBeInTheDocument();
});
it('fetches from the homepage URL and renders fields, async page filters, async and chart information', async () => {
render(
,
{router: initialData.router, organization: initialData.organization}
);
expect(mockHomepage).toHaveBeenCalled();
await screen.findByText('environment');
// Only the environment field
expect(screen.getAllByTestId('grid-head-cell').length).toEqual(1);
screen.getByText('Previous Period');
screen.getByText('event.type:error');
expect(screen.queryByText('Dataset')).not.toBeInTheDocument();
});
it('renders event view from URL params over homepage query', async () => {
initialData = initializeOrg({
organization,
router: {
location: {
...LocationFixture(),
query: {
...EventView.fromSavedQuery(DEFAULT_EVENT_VIEW).generateQueryStringObject(),
field: ['project'],
},
},
},
});
render(
,
{router: initialData.router, organization: initialData.organization}
);
expect(mockHomepage).toHaveBeenCalled();
await screen.findByText('project');
// This is the field in the mocked response for the homepage
expect(screen.queryByText('environment')).not.toBeInTheDocument();
});
it('applies URL changes with the homepage pathname', async () => {
render(
,
{router: initialData.router, organization: initialData.organization}
);
renderGlobalModal();
await userEvent.click(await screen.findByText('Columns'));
await userEvent.click(screen.getByTestId('label'));
await userEvent.click(screen.getByText('event.type'));
await userEvent.click(screen.getByText('Apply'));
expect(browserHistory.push).toHaveBeenCalledWith(
expect.objectContaining({
pathname: '/organizations/org-slug/discover/homepage/',
query: expect.objectContaining({
field: 'event.type',
}),
})
);
});
it('does not show an editable header or author information', async () => {
render(
,
{router: initialData.router, organization: initialData.organization}
);
await waitFor(() => {
expect(measurementsMetaMock).toHaveBeenCalled();
});
// 'Discover' is the header for the homepage
expect(screen.getByText('Discover')).toBeInTheDocument();
expect(screen.queryByText(/Created by:/)).not.toBeInTheDocument();
expect(screen.queryByText(/Last edited:/)).not.toBeInTheDocument();
});
it('shows the Remove Default button on initial load', async () => {
MockApiClient.addMockResponse({
url: '/organizations/org-slug/discover/homepage/',
method: 'GET',
statusCode: 200,
body: {
id: '2',
name: 'homepage query',
projects: [],
version: 2,
expired: false,
dateCreated: '2021-04-08T17:53:25.195782Z',
dateUpdated: '2021-04-09T12:13:18.567264Z',
createdBy: {
id: '2',
},
environment: [],
fields: ['environment'],
widths: ['-1'],
range: '14d',
orderby: '-environment',
display: 'previous',
query: 'event.type:error',
topEvents: '5',
},
});
render(
,
{router: initialData.router, organization: initialData.organization}
);
expect(await screen.findByText('Remove Default')).toBeInTheDocument();
expect(screen.queryByText('Set as Default')).not.toBeInTheDocument();
});
it('Disables the Set as Default button when no saved homepage', async () => {
initialData = initializeOrg({
organization,
router: {
location: {
...LocationFixture(),
query: {
...EventView.fromSavedQuery(DEFAULT_EVENT_VIEW).generateQueryStringObject(),
},
},
},
});
mockHomepage = MockApiClient.addMockResponse({
url: '/organizations/org-slug/discover/homepage/',
method: 'GET',
statusCode: 200,
});
render(
,
{router: initialData.router, organization: initialData.organization}
);
expect(mockHomepage).toHaveBeenCalled();
expect(screen.getByRole('button', {name: /set as default/i})).toBeDisabled();
await waitFor(() => {
expect(measurementsMetaMock).toHaveBeenCalled();
});
});
it('follows absolute date selection', async () => {
initialData = initializeOrg({
organization,
router: {
location: {
...LocationFixture(),
query: {
...EventView.fromSavedQuery(DEFAULT_EVENT_VIEW).generateQueryStringObject(),
},
},
},
});
MockApiClient.addMockResponse({
url: '/organizations/org-slug/discover/homepage/',
method: 'GET',
statusCode: 200,
});
render(
,
{router: initialData.router, organization: initialData.organization}
);
await userEvent.click(await screen.findByText('24H'));
await userEvent.click(await screen.findByText('Absolute date'));
await userEvent.click(screen.getByText('Apply'));
expect(screen.queryByText('14D')).not.toBeInTheDocument();
});
it('renders changes to the discover query when no homepage', async () => {
initialData = initializeOrg({
organization,
router: {
location: {
...LocationFixture(),
query: {
...EventView.fromSavedQuery(DEFAULT_EVENT_VIEW).generateQueryStringObject(),
field: ['title'],
},
},
},
});
MockApiClient.addMockResponse({
url: '/organizations/org-slug/discover/homepage/',
method: 'GET',
statusCode: 200,
body: '',
});
const {rerender} = render(
,
{router: initialData.router, organization: initialData.organization}
);
renderGlobalModal();
// Simulate an update to the columns by changing the URL params
const rerenderData = initializeOrg({
organization,
router: {
location: {
...LocationFixture(),
query: {
...EventView.fromSavedQuery(DEFAULT_EVENT_VIEW).generateQueryStringObject(),
field: ['event.type'],
},
},
},
});
rerender(
);
await waitFor(() => {
expect(measurementsMetaMock).toHaveBeenCalled();
});
expect(screen.getByText('event.type')).toBeInTheDocument();
});
it('renders changes to the discover query when loaded with valid event view in url params', async () => {
initialData = initializeOrg({
organization,
router: {
location: {
...LocationFixture(),
query: {
...EventView.fromSavedQuery(DEFAULT_EVENT_VIEW).generateQueryStringObject(),
field: ['title'],
},
},
},
});
const {rerender} = render(
,
{router: initialData.router, organization: initialData.organization}
);
renderGlobalModal();
// Simulate an update to the columns by changing the URL params
const rerenderData = initializeOrg({
organization,
router: {
location: {
...LocationFixture(),
query: {
...EventView.fromSavedQuery(DEFAULT_EVENT_VIEW).generateQueryStringObject(),
field: ['event.type'],
},
},
},
});
rerender(
);
await waitFor(() => {
expect(measurementsMetaMock).toHaveBeenCalled();
});
expect(screen.getByText('event.type')).toBeInTheDocument();
});
it('overrides homepage filters with pinned filters if they exist', async () => {
ProjectsStore.loadInitialData([ProjectFixture({id: '1'}), ProjectFixture({id: '2'})]);
jest.spyOn(pageFilterUtils, 'getPageFilterStorage').mockReturnValueOnce({
pinnedFilters: new Set(['projects']),
state: {
project: [2],
environment: [],
start: null,
end: null,
period: '14d',
utc: null,
},
});
render(
,
{router: initialData.router, organization: initialData.organization}
);
await waitFor(() => {
expect(measurementsMetaMock).toHaveBeenCalled();
});
expect(screen.getByText('project-slug')).toBeInTheDocument();
});
it('allows users to set the All Events query as default', async () => {
initialData = initializeOrg({
organization,
router: {
location: {
...LocationFixture(),
query: {
...EventView.fromSavedQuery(DEFAULT_EVENT_VIEW).generateQueryStringObject(),
},
},
},
});
mockHomepage = MockApiClient.addMockResponse({
url: '/organizations/org-slug/discover/homepage/',
method: 'GET',
statusCode: 200,
});
render(
,
{router: initialData.router, organization: initialData.organization}
);
await waitFor(() => expect(screen.getByTestId('set-as-default')).toBeEnabled());
});
it('uses split decision for homepage query', async () => {
organization = OrganizationFixture({
features: [
'discover-basic',
'discover-query',
'performance-discover-dataset-selector',
],
});
initialData = initializeOrg({
organization: organization,
router: {
location: LocationFixture(),
},
});
MockApiClient.addMockResponse({
url: '/organizations/org-slug/events/',
body: {
meta: {
discoverSplitDecision: 'error-events',
},
data: [],
},
});
MockApiClient.addMockResponse({
url: '/organizations/org-slug/discover/homepage/',
method: 'GET',
statusCode: 200,
body: {
id: '2',
name: 'homepage query',
projects: [],
version: 2,
expired: false,
dateCreated: '2021-04-08T17:53:25.195782Z',
dateUpdated: '2021-04-09T12:13:18.567264Z',
createdBy: {
id: '2',
},
environment: [],
fields: ['environment'],
widths: ['-1'],
range: '14d',
orderby: '-environment',
display: 'previous',
query: 'event.type:error',
topEvents: '5',
queryDataset: 'discover',
},
});
render(
,
{router: initialData.router, organization: initialData.organization}
);
expect(await screen.findByText('Remove Default')).toBeInTheDocument();
expect(screen.queryByText('Set as Default')).not.toBeInTheDocument();
await screen.findByText('environment');
expect(screen.getAllByTestId('grid-head-cell').length).toEqual(1);
screen.getByText('event.type:error');
expect(screen.getByRole('button', {name: 'Dataset Errors'})).toBeInTheDocument();
expect(
screen.getByText(
"We're splitting our datasets up to make it a bit easier to digest. We defaulted this query to Errors. Edit as you see fit."
)
).toBeInTheDocument();
});
it('saves homepage with dataset selection', async () => {
organization = OrganizationFixture({
features: [
'discover-basic',
'discover-query',
'performance-discover-dataset-selector',
],
});
initialData = initializeOrg({
organization: organization,
router: {
location: LocationFixture(),
},
});
MockApiClient.addMockResponse({
url: '/organizations/org-slug/events/',
body: {
meta: {
discoverSplitDecision: 'error-events',
},
data: [],
},
});
MockApiClient.addMockResponse({
url: '/organizations/org-slug/discover/homepage/',
method: 'GET',
statusCode: 200,
body: {
id: '2',
name: 'homepage query',
projects: [],
version: 2,
expired: false,
dateCreated: '2021-04-08T17:53:25.195782Z',
dateUpdated: '2021-04-09T12:13:18.567264Z',
createdBy: {
id: '2',
},
environment: [],
fields: ['environment'],
widths: ['-1'],
range: '14d',
orderby: '-environment',
display: 'previous',
query: 'event.type:error',
topEvents: '5',
queryDataset: 'discover',
},
});
render(
,
{router: initialData.router, organization: initialData.organization}
);
expect(await screen.findByText('Remove Default')).toBeInTheDocument();
expect(screen.queryByText('Set as Default')).not.toBeInTheDocument();
await userEvent.click(screen.getByText('Dataset'));
await userEvent.click(screen.getByRole('option', {name: 'Transactions'}));
expect(initialData.router.push).toHaveBeenCalledWith(
expect.objectContaining({
query: expect.objectContaining({
dataset: 'transactions',
name: 'homepage query',
project: undefined,
query: 'event.type:error',
queryDataset: 'transaction-like',
}),
})
);
});
});