123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399 |
- import React from 'react';
- import {browserHistory} from 'react-router';
- import {initializeOrg} from 'sentry-test/initializeOrg';
- import {mountWithTheme} from 'sentry-test/enzyme';
- import PerformanceLanding from 'app/views/performance/landing';
- import ProjectsStore from 'app/stores/projectsStore';
- import {
- TRENDS_FUNCTIONS,
- getTrendAliasedFieldPercentage,
- getTrendAliasedQueryPercentage,
- getTrendAliasedMinus,
- } from 'app/views/performance/trends/utils';
- import {TrendFunctionField} from 'app/views/performance/trends/types';
- const trendsViewQuery = {
- view: 'TRENDS',
- };
- function selectTrendFunction(wrapper, field) {
- const menu = wrapper.find('TrendsDropdown DropdownMenu');
- expect(menu).toHaveLength(1);
- menu.find('DropdownButton').simulate('click');
- const option = menu.find(`DropdownItem[data-test-id="${field}"] span`);
- expect(option).toHaveLength(1);
- option.simulate('click');
- wrapper.update();
- }
- function initializeData(projects, query) {
- const features = ['transaction-event', 'performance-view', 'trends'];
- const organization = TestStubs.Organization({
- features,
- projects,
- });
- const initialData = initializeOrg({
- organization,
- router: {
- location: {
- query: {...trendsViewQuery, ...query},
- },
- },
- });
- ProjectsStore.loadInitialData(initialData.organization.projects);
- return initialData;
- }
- describe('Performance > Trends', function() {
- let trendsMock;
- let baselineMock;
- beforeEach(function() {
- MockApiClient.addMockResponse({
- url: '/organizations/org-slug/projects/',
- body: [],
- });
- MockApiClient.addMockResponse({
- url: '/organizations/org-slug/tags/',
- body: [],
- });
- MockApiClient.addMockResponse({
- url: '/organizations/org-slug/users/',
- body: [],
- });
- MockApiClient.addMockResponse({
- url: '/organizations/org-slug/recent-searches/',
- body: [],
- });
- MockApiClient.addMockResponse({
- url: '/organizations/org-slug/recent-searches/',
- method: 'POST',
- body: [],
- });
- MockApiClient.addMockResponse({
- url: '/organizations/org-slug/releases/',
- body: [],
- });
- trendsMock = MockApiClient.addMockResponse({
- url: '/organizations/org-slug/events-trends/',
- body: {
- stats: {
- 'internal,/organizations/:orgId/performance/': {
- data: [[123, []]],
- },
- order: 0,
- },
- events: {
- meta: {
- count_range_1: 'integer',
- count_range_2: 'integer',
- percentage_count_range_2_count_range_1: 'percentage',
- percentage_percentile_range_2_percentile_range_1: 'percentage',
- minus_percentile_range_2_percentile_range_1: 'number',
- percentile_range_1: 'duration',
- percentile_range_2: 'duration',
- transaction: 'string',
- },
- data: [
- {
- count: 8,
- project: 'internal',
- count_range_1: 2,
- count_range_2: 6,
- percentage_count_range_2_count_range_1: 3,
- percentage_percentile_range_2_percentile_range_1: 1.9235225955967554,
- minus_percentile_range_2_percentile_range_1: 797,
- percentile_range_1: 863,
- percentile_range_2: 1660,
- transaction: '/organizations/:orgId/performance/',
- },
- {
- count: 60,
- project: 'internal',
- count_range_1: 20,
- count_range_2: 40,
- percentage_count_range_2_count_range_1: 2,
- percentage_percentile_range_2_percentile_range_1: 1.204968944099379,
- minus_percentile_range_2_percentile_range_1: 66,
- percentile_range_1: 322,
- percentile_range_2: 388,
- transaction: '/api/0/internal/health/',
- },
- ],
- },
- },
- });
- baselineMock = MockApiClient.addMockResponse({
- url: '/organizations/org-slug/event-baseline/',
- body: {
- project: 'sentry',
- id: '66877921c6ff440b8b891d3734f074e7',
- },
- });
- });
- afterEach(function() {
- MockApiClient.clearMockResponses();
- ProjectsStore.reset();
- });
- it('renders basic UI elements', async function() {
- const projects = [TestStubs.Project()];
- const data = initializeData(projects, {});
- const wrapper = mountWithTheme(
- <PerformanceLanding
- organization={data.organization}
- location={data.router.location}
- />,
- data.routerContext
- );
- await tick();
- wrapper.update();
- // Trends dropdown and transaction widgets should render.
- expect(wrapper.find('TrendsDropdown')).toHaveLength(1);
- expect(wrapper.find('ChangedTransactions')).toHaveLength(2);
- });
- it('transaction list items are rendered', async function() {
- const projects = [TestStubs.Project()];
- const data = initializeData(projects, {project: ['-1']});
- const wrapper = mountWithTheme(
- <PerformanceLanding
- organization={data.organization}
- location={data.router.location}
- />,
- data.routerContext
- );
- await tick();
- wrapper.update();
- expect(wrapper.find('TrendsListItem')).toHaveLength(4);
- });
- it('view summary menu action links to the correct view', async function() {
- const projects = [TestStubs.Project({id: 1, slug: 'internal'}), TestStubs.Project()];
- const data = initializeData(projects, {project: ['1']});
- const wrapper = mountWithTheme(
- <PerformanceLanding
- organization={data.organization}
- location={data.router.location}
- />,
- data.routerContext
- );
- await tick();
- wrapper.update();
- wrapper
- .find('TransactionMenuButton')
- .first()
- .simulate('click');
- const firstTransaction = wrapper.find('TrendsListItem').first();
- const summaryLink = firstTransaction.find('StyledSummaryLink');
- expect(summaryLink).toHaveLength(1);
- expect(summaryLink.text()).toEqual('View Summary');
- expect(summaryLink.props().to.pathname).toEqual(
- '/organizations/org-slug/performance/summary/'
- );
- expect(summaryLink.props().to.query.project).toEqual(1);
- });
- it('transaction link calls comparison view', async function() {
- const projects = [TestStubs.Project({id: 1, slug: 'internal'}), TestStubs.Project()];
- const data = initializeData(projects, {project: ['1']});
- const wrapper = mountWithTheme(
- <PerformanceLanding
- organization={data.organization}
- location={data.router.location}
- />,
- data.routerContext
- );
- await tick();
- wrapper.update();
- const firstTransaction = wrapper.find('TrendsListItem').first();
- const transactionLink = firstTransaction.find('StyledLink').first();
- transactionLink.simulate('click');
- await tick();
- wrapper.update();
- expect(baselineMock).toHaveBeenCalledTimes(2);
- expect(browserHistory.push).toHaveBeenCalledWith({
- pathname:
- '/organizations/org-slug/performance/compare/sentry:66877921c6ff440b8b891d3734f074e7/sentry:66877921c6ff440b8b891d3734f074e7/',
- query: expect.anything(),
- });
- });
- it('choosing a trend function changes location', async function() {
- const projects = [TestStubs.Project()];
- const data = initializeData(projects, {project: ['-1']});
- const wrapper = mountWithTheme(
- <PerformanceLanding
- organization={data.organization}
- location={data.router.location}
- />,
- data.routerContext
- );
- for (const trendFunction of TRENDS_FUNCTIONS) {
- selectTrendFunction(wrapper, trendFunction.field);
- await tick();
- expect(browserHistory.push).toHaveBeenCalledWith({
- query: expect.objectContaining({
- trendFunction: trendFunction.field,
- }),
- });
- }
- });
- it('clicking project trend view transactions changes location', async function() {
- const projectId = 42;
- const projects = [TestStubs.Project({id: projectId, slug: 'internal'})];
- const data = initializeData(projects, {project: ['-1']});
- const wrapper = mountWithTheme(
- <PerformanceLanding
- organization={data.organization}
- location={data.router.location}
- />,
- data.routerContext
- );
- await tick();
- wrapper.update();
- const mostImprovedProject = wrapper.find('ChangedProjectsContainer').first();
- const viewTransactions = mostImprovedProject.find('Button').first();
- viewTransactions.simulate('click');
- expect(browserHistory.push).toHaveBeenCalledWith({
- query: expect.objectContaining({
- project: [projectId],
- }),
- });
- });
- it('trend functions in location make api calls', async function() {
- const projects = [TestStubs.Project(), TestStubs.Project()];
- const data = initializeData(projects, {project: ['-1']});
- const wrapper = mountWithTheme(
- <PerformanceLanding
- organization={data.organization}
- location={data.router.location}
- />,
- data.routerContext
- );
- await tick();
- wrapper.update();
- for (const trendFunction of TRENDS_FUNCTIONS) {
- trendsMock.mockReset();
- wrapper.setProps({
- location: {query: {...trendsViewQuery, trendFunction: trendFunction.field}},
- });
- wrapper.update();
- await tick();
- expect(trendsMock).toHaveBeenCalledTimes(4);
- const aliasedFieldDivide = getTrendAliasedFieldPercentage(trendFunction.alias);
- const aliasedQueryDivide = getTrendAliasedQueryPercentage(trendFunction.alias);
- const sort =
- trendFunction.field === TrendFunctionField.USER_MISERY
- ? getTrendAliasedMinus(trendFunction.alias)
- : aliasedFieldDivide;
- const defaultTrendsFields = ['project', 'count()'];
- const trendFunctionFields = TRENDS_FUNCTIONS.map(({field}) => field);
- const transactionFields = [
- ...trendFunctionFields,
- 'transaction',
- ...defaultTrendsFields,
- ];
- const projectFields = [...trendFunctionFields, ...defaultTrendsFields];
- expect(transactionFields).toHaveLength(8);
- expect(projectFields).toHaveLength(transactionFields.length - 1);
- // Improved projects call
- expect(trendsMock).toHaveBeenNthCalledWith(
- 1,
- expect.anything(),
- expect.objectContaining({
- query: expect.objectContaining({
- trendFunction: trendFunction.field,
- sort,
- query: expect.stringContaining(aliasedQueryDivide + ':<1'),
- interval: '12h',
- field: projectFields,
- statsPeriod: '14d',
- }),
- })
- );
- // Improved transactions call
- expect(trendsMock).toHaveBeenNthCalledWith(
- 2,
- expect.anything(),
- expect.objectContaining({
- query: expect.objectContaining({
- trendFunction: trendFunction.field,
- sort,
- query: expect.stringContaining(aliasedQueryDivide + ':<1'),
- interval: '12h',
- field: transactionFields,
- statsPeriod: '14d',
- }),
- })
- );
- // Regression projects call
- expect(trendsMock).toHaveBeenNthCalledWith(
- 3,
- expect.anything(),
- expect.objectContaining({
- query: expect.objectContaining({
- trendFunction: trendFunction.field,
- sort: '-' + sort,
- query: expect.stringContaining(aliasedQueryDivide + ':>1'),
- interval: '12h',
- field: projectFields,
- statsPeriod: '14d',
- }),
- })
- );
- // Regression transactions call
- expect(trendsMock).toHaveBeenNthCalledWith(
- 4,
- expect.anything(),
- expect.objectContaining({
- query: expect.objectContaining({
- trendFunction: trendFunction.field,
- sort: '-' + sort,
- query: expect.stringContaining(aliasedQueryDivide + ':>1'),
- interval: '12h',
- field: transactionFields,
- statsPeriod: '14d',
- }),
- })
- );
- }
- });
- });
|