import {initializeOrg} from 'sentry-test/initializeOrg'; import { render, screen, userEvent, waitForElementToBeRemoved, } from 'sentry-test/reactTestingLibrary'; import EventView from 'sentry/utils/discover/eventView'; import {MutableSearch} from 'sentry/utils/tokenizeSearch'; import {Tags} from 'sentry/views/discover/tags'; // There seem to be no types for this, but it's essentially what is passed to the // EventView constructor const commonQueryConditions = { additionalConditions: new MutableSearch([]), display: '', start: '', end: '', id: '', name: '', project: [1], environment: [], topEvents: '', yAxis: '', createdBy: TestStubs.User(), team: TestStubs.Team(), statsPeriod: '14d', }; describe('Tags', function () { function generateUrl(key, value) { return `/endpoint/${key}/${value}`; } const org = TestStubs.Organization(); beforeEach(function () { MockApiClient.addMockResponse({ url: `/organizations/${org.slug}/events-facets/`, body: [ { key: 'release', topValues: [{count: 30, value: '123abcd', name: '123abcd'}], }, { key: 'environment', topValues: [ {count: 20, value: 'abcd123', name: 'abcd123'}, {count: 10, value: 'anotherOne', name: 'anotherOne'}, ], }, { key: 'color', topValues: [ {count: 10, value: 'red', name: 'red'}, {count: 5, value: 'blue', name: 'blue'}, {count: 5, value: 'green', name: 'green'}, {count: 5, value: 'yellow', name: 'yellow'}, {count: 5, value: 'orange', name: 'orange'}, ], }, ], }); }); afterEach(function () { MockApiClient.clearMockResponses(); }); it('renders', async function () { const view = new EventView({ fields: [], sorts: [], query: 'event.type:csp', ...commonQueryConditions, }); render( ); // component is in loading state expect(screen.getAllByTestId('loading-placeholder')[0]).toBeInTheDocument(); // component has loaded await waitForElementToBeRemoved( () => screen.queryAllByTestId('loading-placeholder')[0] ); }); it('creates URLs with generateUrl', async function () { const view = new EventView({ fields: [], sorts: [], query: 'event.type:csp', ...commonQueryConditions, }); const initialData = initializeOrg({ organization: org, router: { location: {query: {}}, }, }); render( , {context: initialData.routerContext} ); // component has loaded await waitForElementToBeRemoved( () => screen.queryAllByTestId('loading-placeholder')[0] ); await userEvent.click(screen.getByText('environment')); await userEvent.click( screen.getByRole('link', { name: 'environment, abcd123, 66% of all events. View events with this tag value.', }) ); expect(initialData.router.push).toHaveBeenCalledWith('/endpoint/environment/abcd123'); }); it('renders tag keys', async function () { const view = new EventView({ fields: [], sorts: [], query: 'event.type:csp', ...commonQueryConditions, }); render( ); await waitForElementToBeRemoved( () => screen.queryAllByTestId('loading-placeholder')[0] ); expect(screen.getByRole('listitem', {name: 'release'})).toBeInTheDocument(); expect(screen.getByRole('listitem', {name: 'environment'})).toBeInTheDocument(); expect(screen.getByRole('listitem', {name: 'color'})).toBeInTheDocument(); }); it('excludes top tag values on current page query', async function () { const initialData = initializeOrg({ organization: org, router: { location: {pathname: '/organizations/org-slug/discover/homepage/', query: {}}, }, }); const view = new EventView({ fields: [], sorts: [], query: '', ...commonQueryConditions, }); render( , {context: initialData.routerContext} ); await waitForElementToBeRemoved( () => screen.queryAllByTestId('loading-placeholder')[0] ); await userEvent.click( screen.getByRole('button', {name: 'Expand color tag distribution'}) ); expect( screen.getByRole('link', { name: 'Other color tag values, 16% of all events. View other tags.', }) ).toHaveAttribute( 'href', '/organizations/org-slug/discover/homepage/?query=%21color%3A%5Bred%2C%20blue%2C%20green%2C%20yellow%5D' ); }); it('has a Show More button when there are more tags', async () => { MockApiClient.addMockResponse({ url: `/organizations/${org.slug}/events-facets/`, match: [MockApiClient.matchQuery({cursor: undefined})], headers: { Link: '; rel="previous"; results="false"; cursor="0:0:1",' + '; rel="next"; results="true"; cursor="0:10:0"', }, body: [ { key: 'release', topValues: [{count: 30, value: '123abcd', name: '123abcd'}], }, ], }); const mockRequest = MockApiClient.addMockResponse({ url: `/organizations/${org.slug}/events-facets/`, match: [MockApiClient.matchQuery({cursor: '0:10:0'})], body: [], headers: { Link: '; rel="previous"; results="false"; cursor="0:10:1",' + '; rel="next"; results="false"; cursor="0:20:0"', }, }); const view = new EventView({ fields: [], sorts: [], query: '', ...commonQueryConditions, }); render( ); await waitForElementToBeRemoved( () => screen.queryAllByTestId('loading-placeholder')[0] ); expect(screen.getByRole('button', {name: 'Show More'})).toBeInTheDocument(); await userEvent.click(screen.getByRole('button', {name: 'Show More'})); expect(mockRequest).toHaveBeenCalled(); // Button should disappear when there are no more tags to load expect(screen.queryByRole('button', {name: 'Show More'})).not.toBeInTheDocument(); }); });