import {browserHistory} from 'react-router'; import {mountWithTheme} from 'sentry-test/enzyme'; import {initializeOrg} from 'sentry-test/initializeOrg'; import {act, render, screen, userEvent} from 'sentry-test/reactTestingLibrary'; import ProjectsStore from 'sentry/stores/projectsStore'; import TagStore from 'sentry/stores/tagStore'; import EventView from 'sentry/utils/discover/eventView'; import TableView from 'sentry/views/eventsV2/table/tableView'; describe('TableView > CellActions', function () { let initialData, rows, onChangeShowTags; const location = { pathname: '/organizations/org-slug/discover/results/', query: { id: '42', name: 'best query', field: [ 'title', 'transaction', 'count()', 'timestamp', 'release', 'equation|count() + 100', ], sort: ['title'], query: '', project: [123], statsPeriod: '14d', environment: ['staging'], yAxis: 'p95', }, }; const eventView = EventView.fromLocation(location); function makeWrapper(context, tableData, view) { return mountWithTheme( , context.routerContext ); } function openContextMenu(wrapper, cellIndex) { const menu = wrapper.find('CellAction').at(cellIndex); // Hover over the menu menu.find('Container > div').at(0).simulate('mouseEnter'); wrapper.update(); // Open the menu wrapper.find('MenuButton').simulate('click'); // Return the menu wrapper so we can interact with it. return wrapper.find('CellAction').at(cellIndex).find('Menu'); } beforeEach(function () { browserHistory.push.mockReset(); browserHistory.replace.mockReset(); const organization = TestStubs.Organization({ features: ['discover-basic'], projects: [TestStubs.Project()], }); initialData = initializeOrg({ organization, router: {location}, }); act(() => { ProjectsStore.loadInitialData(initialData.organization.projects); TagStore.reset(); TagStore.loadTagsSuccess([ {name: 'size', key: 'size', count: 1}, {name: 'shape', key: 'shape', count: 1}, {name: 'direction', key: 'direction', count: 1}, ]); }); onChangeShowTags = jest.fn(); rows = { meta: { title: 'string', transaction: 'string', 'count()': 'integer', timestamp: 'date', release: 'string', 'equation[0]': 'integer', }, data: [ { title: 'some title', transaction: '/organizations/', 'count()': 9, timestamp: '2019-05-23T22:12:48+00:00', release: 'v1.0.2', 'equation[0]': 109, }, ], }; }); afterEach(() => { ProjectsStore.reset(); }); it('updates sort order on equation fields', function () { const view = eventView.clone(); const wrapper = makeWrapper(initialData, rows, view); const equationSort = wrapper.find('SortLink').last(); expect(equationSort.find('StyledTooltip').props().title).toBe('count() + 100'); expect(equationSort.find('a').props().href).toBe( '/organizations/org-slug/discover/results/?environment=staging&field=title&field=transaction&field=count%28%29&field=timestamp&field=release&field=equation%7Ccount%28%29%20%2B%20100&id=42&name=best%20query&project=123&query=&sort=-equation%5B0%5D&statsPeriod=14d&yAxis=p95' ); }); it('updates sort order on non-equation fields', function () { const view = eventView.clone(); const wrapper = makeWrapper(initialData, rows, view); const equationSort = wrapper.find('SortLink').at(1); expect(equationSort.find('StyledTooltip').props().title).toBe('transaction'); equationSort.simulate('click'); expect(equationSort.find('a').props().href).toBe( '/organizations/org-slug/discover/results/?environment=staging&field=title&field=transaction&field=count%28%29&field=timestamp&field=release&field=equation%7Ccount%28%29%20%2B%20100&id=42&name=best%20query&project=123&query=&sort=-transaction&statsPeriod=14d&yAxis=p95' ); }); it('handles add cell action on null value', function () { rows.data[0].title = null; const wrapper = makeWrapper(initialData, rows, eventView); const menu = openContextMenu(wrapper, 0); menu.find('button[data-test-id="add-to-filter"]').simulate('click'); expect(browserHistory.push).toHaveBeenCalledWith({ pathname: location.pathname, query: expect.objectContaining({ query: '!has:title', }), }); }); it('handles add cell action on null value replace has condition', function () { rows.data[0].title = null; const view = eventView.clone(); view.query = 'tag:value has:title'; const wrapper = makeWrapper(initialData, rows, view); const menu = openContextMenu(wrapper, 0); menu.find('button[data-test-id="add-to-filter"]').simulate('click'); expect(browserHistory.push).toHaveBeenCalledWith({ pathname: location.pathname, query: expect.objectContaining({ query: 'tag:value !has:title', }), }); }); it('handles add cell action on string value replace negation', function () { const view = eventView.clone(); view.query = 'tag:value !title:nope'; const wrapper = makeWrapper(initialData, rows, view); const menu = openContextMenu(wrapper, 0); menu.find('button[data-test-id="add-to-filter"]').simulate('click'); expect(browserHistory.push).toHaveBeenCalledWith({ pathname: location.pathname, query: expect.objectContaining({ query: 'tag:value title:"some title"', }), }); }); it('handles add cell action with multiple y axis', function () { location.query.yAxis = ['count()', 'failure_count()']; const wrapper = makeWrapper(initialData, rows, eventView); const menu = openContextMenu(wrapper, 0); menu.find('button[data-test-id="add-to-filter"]').simulate('click'); expect(browserHistory.push).toHaveBeenCalledWith({ pathname: location.pathname, query: expect.objectContaining({ query: 'title:"some title"', yAxis: ['count()', 'failure_count()'], }), }); }); it('handles exclude cell action on string value', function () { const wrapper = makeWrapper(initialData, rows, eventView); const menu = openContextMenu(wrapper, 0); menu.find('button[data-test-id="exclude-from-filter"]').simulate('click'); expect(browserHistory.push).toHaveBeenCalledWith({ pathname: location.pathname, query: expect.objectContaining({ query: '!title:"some title"', }), }); }); it('handles exclude cell action on string value replace inclusion', function () { const view = eventView.clone(); view.query = 'tag:value title:nope'; const wrapper = makeWrapper(initialData, rows, view); const menu = openContextMenu(wrapper, 0); menu.find('button[data-test-id="exclude-from-filter"]').simulate('click'); expect(browserHistory.push).toHaveBeenCalledWith({ pathname: location.pathname, query: expect.objectContaining({ query: 'tag:value !title:"some title"', }), }); }); it('handles exclude cell action on null value', function () { rows.data[0].title = null; const wrapper = makeWrapper(initialData, rows, eventView); const menu = openContextMenu(wrapper, 0); menu.find('button[data-test-id="exclude-from-filter"]').simulate('click'); expect(browserHistory.push).toHaveBeenCalledWith({ pathname: location.pathname, query: expect.objectContaining({ query: 'has:title', }), }); }); it('handles exclude cell action on null value replace condition', function () { const view = eventView.clone(); view.query = 'tag:value !has:title'; rows.data[0].title = null; const wrapper = makeWrapper(initialData, rows, view); const menu = openContextMenu(wrapper, 0); menu.find('button[data-test-id="exclude-from-filter"]').simulate('click'); expect(browserHistory.push).toHaveBeenCalledWith({ pathname: location.pathname, query: expect.objectContaining({ query: 'tag:value has:title', }), }); }); it('handles greater than cell action on number value', function () { const wrapper = makeWrapper(initialData, rows, eventView); const menu = openContextMenu(wrapper, 2); menu.find('button[data-test-id="show-values-greater-than"]').simulate('click'); expect(browserHistory.push).toHaveBeenCalledWith({ pathname: location.pathname, query: expect.objectContaining({ query: 'count():>9', }), }); }); it('handles less than cell action on number value', function () { const wrapper = makeWrapper(initialData, rows, eventView); const menu = openContextMenu(wrapper, 2); menu.find('button[data-test-id="show-values-less-than"]').simulate('click'); expect(browserHistory.push).toHaveBeenCalledWith({ pathname: location.pathname, query: expect.objectContaining({ query: 'count():<9', }), }); }); it('handles go to transaction without project column selected', function () { rows.data[0]['project.name'] = 'project-slug'; const wrapper = makeWrapper(initialData, rows, eventView); const menu = openContextMenu(wrapper, 1); menu.find('button[data-test-id="transaction-summary"]').simulate('click'); expect(browserHistory.push).toHaveBeenCalledWith({ pathname: '/organizations/org-slug/performance/summary/', query: expect.objectContaining({ transaction: '/organizations/', project: ['2'], }), }); }); it('handles go to transaction with project column selected', function () { rows.data[0].project = 'project-slug'; const wrapper = makeWrapper(initialData, rows, eventView); const menu = openContextMenu(wrapper, 1); menu.find('button[data-test-id="transaction-summary"]').simulate('click'); expect(browserHistory.push).toHaveBeenCalledWith({ pathname: '/organizations/org-slug/performance/summary/', query: expect.objectContaining({ transaction: '/organizations/', project: ['2'], }), }); }); it('handles go to release', function () { const wrapper = makeWrapper(initialData, rows, eventView); const menu = openContextMenu(wrapper, 4); menu.find('button[data-test-id="release"]').simulate('click'); expect(browserHistory.push).toHaveBeenCalledWith({ pathname: '/organizations/org-slug/releases/v1.0.2/', query: expect.objectContaining({ environment: eventView.environment, }), }); }); it('has tooltip on integer value greater than 999', function () { rows.data[0]['count()'] = 1000; const wrapper = makeWrapper(initialData, rows, eventView); const tooltip = wrapper.find('GridBody Tooltip').at(1); expect(wrapper.find('GridBody Tooltip').length).toEqual(3); expect(tooltip.prop('title')).toBe('1,000'); }); it('does not have tooltip on integer value less than 999', function () { const wrapper = makeWrapper(initialData, rows, eventView); expect(wrapper.find('GridBody Tooltip').length).toEqual(2); }); it('renders size columns correctly', function () { const orgWithFeature = TestStubs.Organization({ features: ['discover-frontend-use-events-endpoint'], projects: [TestStubs.Project()], }); render( ); expect(screen.getByText('222.3 KiB')).toBeInTheDocument(); expect(screen.getByText('444.3 KB')).toBeInTheDocument(); }); it('shows events with value less than selected custom performance metric', function () { const orgWithFeature = TestStubs.Organization({ features: ['discover-frontend-use-events-endpoint'], projects: [TestStubs.Project()], }); render( ); userEvent.hover(screen.getByText('444.3 KB')); const buttons = screen.getAllByRole('button'); userEvent.click(buttons[buttons.length - 1]); userEvent.click(screen.getByText('Show values less than')); expect(browserHistory.push).toHaveBeenCalledWith({ pathname: location.pathname, query: expect.objectContaining({ query: 'p99(measurements.custom.kilobyte):<444300', }), }); }); });