123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692 |
- import {DiscoverSavedQueryFixture} from 'sentry-fixture/discover';
- import {OrganizationFixture} from 'sentry-fixture/organization';
- import {RouterFixture} from 'sentry-fixture/routerFixture';
- import {initializeOrg} from 'sentry-test/initializeOrg';
- import {
- render,
- screen,
- userEvent,
- waitFor,
- within,
- } from 'sentry-test/reactTestingLibrary';
- import {openAddToDashboardModal} from 'sentry/actionCreators/modal';
- import {browserHistory} from 'sentry/utils/browserHistory';
- import {DisplayModes, SavedQueryDatasets} from 'sentry/utils/discover/types';
- import {DashboardWidgetSource, DisplayType} from 'sentry/views/dashboards/types';
- import QueryList from 'sentry/views/discover/queryList';
- jest.mock('sentry/actionCreators/modal');
- describe('Discover > QueryList', function () {
- let location,
- savedQueries,
- organization,
- deleteMock,
- duplicateMock,
- queryChangeMock,
- updateHomepageMock,
- eventsStatsMock,
- wrapper;
- const {router} = initializeOrg();
- beforeAll(async function () {
- await import('sentry/components/modals/widgetBuilder/addToDashboardModal');
- });
- beforeEach(function () {
- organization = OrganizationFixture({
- features: ['discover-basic', 'discover-query'],
- });
- savedQueries = [
- DiscoverSavedQueryFixture(),
- DiscoverSavedQueryFixture({name: 'saved query 2', id: '2'}),
- ];
- eventsStatsMock = MockApiClient.addMockResponse({
- url: '/organizations/org-slug/events-stats/',
- method: 'GET',
- statusCode: 200,
- body: {data: []},
- });
- deleteMock = MockApiClient.addMockResponse({
- url: '/organizations/org-slug/discover/saved/2/',
- method: 'DELETE',
- statusCode: 200,
- body: {},
- });
- duplicateMock = MockApiClient.addMockResponse({
- url: '/organizations/org-slug/discover/saved/',
- method: 'POST',
- body: {
- id: '3',
- name: 'Saved query copy',
- },
- });
- updateHomepageMock = MockApiClient.addMockResponse({
- url: '/organizations/org-slug/discover/homepage/',
- method: 'PUT',
- statusCode: 204,
- });
- location = {
- pathname: '/organizations/org-slug/discover/queries/',
- query: {cursor: '0:1:1', statsPeriod: '14d'},
- };
- queryChangeMock = jest.fn();
- });
- afterEach(() => {
- jest.clearAllMocks();
- wrapper?.unmount();
- wrapper = null;
- });
- it('renders an empty list', function () {
- render(
- <QueryList
- router={RouterFixture()}
- organization={organization}
- savedQueries={[]}
- savedQuerySearchQuery="no matches"
- pageLinks=""
- renderPrebuilt={false}
- onQueryChange={queryChangeMock}
- location={location}
- />
- );
- expect(screen.getByText('No saved queries match that filter')).toBeInTheDocument();
- });
- it('renders pre-built queries and saved ones', async function () {
- render(
- <QueryList
- savedQuerySearchQuery=""
- router={RouterFixture()}
- organization={organization}
- savedQueries={savedQueries}
- renderPrebuilt
- pageLinks=""
- onQueryChange={queryChangeMock}
- location={location}
- />
- );
- await waitFor(() => {
- expect(screen.getAllByTestId(/card-.*/)).toHaveLength(5);
- });
- expect(eventsStatsMock).toHaveBeenCalledWith(
- '/organizations/org-slug/events-stats/',
- expect.objectContaining({
- query: {
- environment: [],
- interval: '30m',
- partial: '1',
- project: [],
- query: '',
- referrer: 'api.discover.default-chart',
- statsPeriod: '14d',
- yAxis: ['count()'],
- },
- })
- );
- });
- it('renders pre-built queries with dataset', async function () {
- organization = OrganizationFixture({
- features: [
- 'discover-basic',
- 'discover-query',
- 'performance-view',
- 'performance-discover-dataset-selector',
- ],
- });
- render(
- <QueryList
- savedQuerySearchQuery=""
- router={RouterFixture()}
- organization={organization}
- savedQueries={[]}
- renderPrebuilt
- pageLinks=""
- onQueryChange={queryChangeMock}
- location={location}
- />,
- {router}
- );
- await waitFor(() => {
- expect(screen.getAllByTestId(/card-.*/)).toHaveLength(5);
- });
- expect(eventsStatsMock).toHaveBeenCalledWith(
- '/organizations/org-slug/events-stats/',
- expect.objectContaining({
- query: expect.objectContaining({
- dataset: 'transactions',
- query: '',
- referrer: 'api.discover.homepage.prebuilt',
- statsPeriod: '24h',
- yAxis: 'count()',
- }),
- })
- );
- expect(eventsStatsMock).toHaveBeenCalledWith(
- '/organizations/org-slug/events-stats/',
- expect.objectContaining({
- query: expect.objectContaining({
- dataset: 'errors',
- environment: [],
- field: ['url', 'count()', 'count_unique(issue)'],
- query: 'has:url',
- referrer: 'api.discover.homepage.prebuilt',
- statsPeriod: '24h',
- topEvents: 5,
- yAxis: 'count()',
- }),
- })
- );
- await userEvent.click(screen.getAllByTestId(/card-*/).at(0)!);
- expect(router.push).toHaveBeenLastCalledWith({
- pathname: '/organizations/org-slug/discover/results/',
- query: expect.objectContaining({queryDataset: 'error-events'}),
- });
- });
- it('passes dataset to the query if flag is enabled', async function () {
- const org = OrganizationFixture({
- features: [
- 'discover-basic',
- 'discover-query',
- 'performance-discover-dataset-selector',
- ],
- });
- render(
- <QueryList
- savedQuerySearchQuery=""
- router={RouterFixture()}
- organization={org}
- savedQueries={savedQueries}
- renderPrebuilt
- pageLinks=""
- onQueryChange={queryChangeMock}
- location={location}
- />
- );
- await waitFor(() => {
- expect(screen.getAllByTestId(/card-.*/)).toHaveLength(5);
- });
- expect(eventsStatsMock).toHaveBeenCalledWith(
- '/organizations/org-slug/events-stats/',
- expect.objectContaining({
- query: {
- environment: [],
- interval: '30m',
- partial: '1',
- project: [],
- query: '',
- referrer: 'api.discover.default-chart',
- statsPeriod: '14d',
- yAxis: ['count()'],
- dataset: 'transactions',
- },
- })
- );
- });
- it('can duplicate and trigger change callback', async function () {
- render(
- <QueryList
- savedQuerySearchQuery=""
- router={RouterFixture()}
- organization={organization}
- savedQueries={savedQueries}
- pageLinks=""
- renderPrebuilt={false}
- onQueryChange={queryChangeMock}
- location={location}
- />
- );
- const card = screen.getAllByTestId(/card-*/).at(0)!;
- const withinCard = within(card!);
- expect(withinCard.getByText('Saved query #1')).toBeInTheDocument();
- await userEvent.click(withinCard.getByTestId('menu-trigger'));
- await userEvent.click(withinCard.getByText('Duplicate Query'));
- await waitFor(() => {
- expect(browserHistory.push).toHaveBeenCalledWith({
- pathname: location.pathname,
- query: {},
- });
- });
- expect(duplicateMock).toHaveBeenCalled();
- expect(queryChangeMock).toHaveBeenCalled();
- });
- it('can delete and trigger change callback', async function () {
- render(
- <QueryList
- savedQuerySearchQuery=""
- renderPrebuilt={false}
- router={RouterFixture()}
- organization={organization}
- savedQueries={savedQueries}
- pageLinks=""
- onQueryChange={queryChangeMock}
- location={location}
- />
- );
- const card = screen.getAllByTestId(/card-*/).at(1);
- const withinCard = within(card!);
- await userEvent.click(withinCard.getByTestId('menu-trigger'));
- await userEvent.click(withinCard.getByText('Delete Query'));
- await waitFor(() => {
- expect(queryChangeMock).toHaveBeenCalled();
- });
- expect(deleteMock).toHaveBeenCalled();
- });
- it('redirects to Discover on card click', async function () {
- render(
- <QueryList
- savedQuerySearchQuery=""
- router={RouterFixture()}
- organization={organization}
- savedQueries={savedQueries}
- pageLinks=""
- renderPrebuilt={false}
- onQueryChange={queryChangeMock}
- location={location}
- />,
- {router}
- );
- await userEvent.click(screen.getAllByTestId(/card-*/).at(0)!);
- expect(router.push).toHaveBeenLastCalledWith({
- pathname: '/organizations/org-slug/discover/results/',
- query: {id: '1', statsPeriod: '14d'},
- });
- });
- it('can redirect on last query deletion', async function () {
- render(
- <QueryList
- savedQuerySearchQuery=""
- router={RouterFixture()}
- organization={organization}
- savedQueries={savedQueries.slice(1)}
- renderPrebuilt={false}
- pageLinks=""
- onQueryChange={queryChangeMock}
- location={location}
- />,
- {router}
- );
- const card = screen.getAllByTestId(/card-*/).at(0)!;
- const withinCard = within(card!);
- await userEvent.click(withinCard.getByTestId('menu-trigger'));
- await userEvent.click(withinCard.getByText('Delete Query'));
- expect(deleteMock).toHaveBeenCalled();
- expect(queryChangeMock).not.toHaveBeenCalled();
- await waitFor(() => {
- expect(browserHistory.push).toHaveBeenCalledWith({
- pathname: location.pathname,
- query: {cursor: undefined, statsPeriod: '14d'},
- });
- });
- });
- it('renders Add to Dashboard in context menu', async function () {
- const featuredOrganization = OrganizationFixture({
- features: ['dashboards-edit'],
- });
- render(
- <QueryList
- savedQuerySearchQuery=""
- router={RouterFixture()}
- organization={featuredOrganization}
- savedQueries={savedQueries.slice(1)}
- pageLinks=""
- onQueryChange={queryChangeMock}
- renderPrebuilt={false}
- location={location}
- />
- );
- const card = screen.getAllByTestId(/card-*/).at(0)!;
- const withinCard = within(card!);
- await userEvent.click(withinCard.getByTestId('menu-trigger'));
- expect(
- screen.getByRole('menuitemradio', {name: 'Add to Dashboard'})
- ).toBeInTheDocument();
- expect(
- screen.getByRole('menuitemradio', {name: 'Set as Default'})
- ).toBeInTheDocument();
- expect(
- screen.getByRole('menuitemradio', {name: 'Duplicate Query'})
- ).toBeInTheDocument();
- expect(screen.getByRole('menuitemradio', {name: 'Delete Query'})).toBeInTheDocument();
- });
- it('only renders Delete Query and Duplicate Query in context menu', async function () {
- render(
- <QueryList
- savedQuerySearchQuery=""
- router={RouterFixture()}
- organization={organization}
- savedQueries={savedQueries.slice(1)}
- pageLinks=""
- renderPrebuilt={false}
- onQueryChange={queryChangeMock}
- location={location}
- />
- );
- const card = screen.getAllByTestId(/card-*/).at(0)!;
- const withinCard = within(card!);
- await userEvent.click(withinCard.getByTestId('menu-trigger'));
- expect(
- screen.queryByRole('menuitemradio', {name: 'Add to Dashboard'})
- ).not.toBeInTheDocument();
- expect(
- screen.getByRole('menuitemradio', {name: 'Set as Default'})
- ).toBeInTheDocument();
- expect(
- screen.getByRole('menuitemradio', {name: 'Duplicate Query'})
- ).toBeInTheDocument();
- expect(screen.getByRole('menuitemradio', {name: 'Delete Query'})).toBeInTheDocument();
- });
- it('passes yAxis from the savedQuery to MiniGraph', async function () {
- const featuredOrganization = OrganizationFixture({
- features: ['dashboards-edit'],
- });
- const yAxis = ['count()', 'failure_count()'];
- const savedQueryWithMultiYAxis = {
- ...savedQueries.slice(1)[0],
- yAxis,
- };
- render(
- <QueryList
- savedQuerySearchQuery=""
- router={RouterFixture()}
- organization={featuredOrganization}
- savedQueries={[savedQueryWithMultiYAxis]}
- pageLinks=""
- renderPrebuilt={false}
- onQueryChange={queryChangeMock}
- location={location}
- />
- );
- const chart = await screen.findByTestId('area-chart');
- expect(chart).toBeInTheDocument();
- expect(eventsStatsMock).toHaveBeenCalledWith(
- '/organizations/org-slug/events-stats/',
- expect.objectContaining({
- query: expect.objectContaining({
- yAxis: ['count()', 'failure_count()'],
- }),
- })
- );
- });
- it('Set as Default updates the homepage query', async function () {
- render(
- <QueryList
- savedQuerySearchQuery=""
- router={RouterFixture()}
- organization={organization}
- savedQueries={savedQueries.slice(1)}
- renderPrebuilt={false}
- pageLinks=""
- onQueryChange={queryChangeMock}
- location={location}
- />
- );
- await userEvent.click(screen.getByTestId('menu-trigger'));
- await userEvent.click(screen.getByText('Set as Default'));
- expect(updateHomepageMock).toHaveBeenCalledWith(
- '/organizations/org-slug/discover/homepage/',
- expect.objectContaining({
- data: expect.objectContaining({fields: ['test'], range: '14d'}),
- })
- );
- });
- describe('Add to Dashboard modal', () => {
- it('opens a modal with the correct params for Top 5 chart', async function () {
- const featuredOrganization = OrganizationFixture({
- features: ['dashboards-edit'],
- });
- render(
- <QueryList
- savedQuerySearchQuery=""
- router={RouterFixture()}
- organization={featuredOrganization}
- renderPrebuilt={false}
- savedQueries={[
- DiscoverSavedQueryFixture({
- display: DisplayModes.TOP5,
- orderby: 'test',
- fields: ['test', 'count()'],
- yAxis: ['count()'],
- }),
- ]}
- pageLinks=""
- onQueryChange={queryChangeMock}
- location={location}
- />
- );
- const contextMenu = await screen.findByTestId('menu-trigger');
- expect(contextMenu).toBeInTheDocument();
- expect(screen.queryByTestId('add-to-dashboard')).not.toBeInTheDocument();
- await userEvent.click(contextMenu);
- const addToDashboardMenuItem = await screen.findByTestId('add-to-dashboard');
- await userEvent.click(addToDashboardMenuItem);
- await waitFor(() => {
- expect(openAddToDashboardModal).toHaveBeenCalledWith(
- expect.objectContaining({
- widget: {
- title: 'Saved query #1',
- displayType: DisplayType.AREA,
- limit: 5,
- queries: [
- {
- aggregates: ['count()'],
- columns: ['test'],
- conditions: '',
- fields: ['test', 'count()', 'count()'],
- name: '',
- orderby: 'test',
- },
- ],
- },
- widgetAsQueryParams: expect.objectContaining({
- defaultTableColumns: ['test', 'count()'],
- defaultTitle: 'Saved query #1',
- defaultWidgetQuery:
- 'name=&aggregates=count()&columns=test&fields=test%2Ccount()%2Ccount()&conditions=&orderby=test',
- displayType: DisplayType.AREA,
- source: DashboardWidgetSource.DISCOVERV2,
- }),
- })
- );
- });
- });
- it('opens a modal with the correct params for other chart', async function () {
- const featuredOrganization = OrganizationFixture({
- features: ['dashboards-edit'],
- });
- render(
- <QueryList
- savedQuerySearchQuery=""
- router={RouterFixture()}
- renderPrebuilt={false}
- organization={featuredOrganization}
- savedQueries={[
- DiscoverSavedQueryFixture({
- display: DisplayModes.DEFAULT,
- orderby: 'count()',
- fields: ['test', 'count()'],
- yAxis: ['count()'],
- queryDataset: SavedQueryDatasets.TRANSACTIONS,
- }),
- ]}
- pageLinks=""
- onQueryChange={queryChangeMock}
- location={location}
- />
- );
- const contextMenu = await screen.findByTestId('menu-trigger');
- expect(contextMenu).toBeInTheDocument();
- expect(screen.queryByTestId('add-to-dashboard')).not.toBeInTheDocument();
- await userEvent.click(contextMenu);
- const addToDashboardMenuItem = await screen.findByTestId('add-to-dashboard');
- await userEvent.click(addToDashboardMenuItem);
- await waitFor(() => {
- expect(openAddToDashboardModal).toHaveBeenCalledWith(
- expect.objectContaining({
- widget: {
- title: 'Saved query #1',
- displayType: DisplayType.LINE,
- queries: [
- {
- aggregates: ['count()'],
- columns: [],
- conditions: '',
- fields: ['count()'],
- name: '',
- // Orderby gets dropped because ordering only applies to
- // Top-N and tables
- orderby: '',
- },
- ],
- },
- widgetAsQueryParams: expect.objectContaining({
- defaultTableColumns: ['test', 'count()'],
- defaultTitle: 'Saved query #1',
- defaultWidgetQuery:
- 'name=&aggregates=count()&columns=&fields=count()&conditions=&orderby=',
- displayType: DisplayType.LINE,
- source: DashboardWidgetSource.DISCOVERV2,
- }),
- })
- );
- });
- });
- });
- it('passes dataset to open modal', async function () {
- const featuredOrganization = OrganizationFixture({
- features: ['dashboards-edit', 'performance-discover-dataset-selector'],
- });
- render(
- <QueryList
- savedQuerySearchQuery=""
- router={RouterFixture()}
- renderPrebuilt={false}
- organization={featuredOrganization}
- savedQueries={[
- DiscoverSavedQueryFixture({
- display: DisplayModes.DEFAULT,
- orderby: 'count()',
- fields: ['test', 'count()'],
- yAxis: ['count()'],
- queryDataset: SavedQueryDatasets.TRANSACTIONS,
- }),
- ]}
- pageLinks=""
- onQueryChange={queryChangeMock}
- location={location}
- />
- );
- const contextMenu = await screen.findByTestId('menu-trigger');
- expect(contextMenu).toBeInTheDocument();
- expect(screen.queryByTestId('add-to-dashboard')).not.toBeInTheDocument();
- await userEvent.click(contextMenu);
- const addToDashboardMenuItem = await screen.findByTestId('add-to-dashboard');
- await userEvent.click(addToDashboardMenuItem);
- await waitFor(() => {
- expect(openAddToDashboardModal).toHaveBeenCalledWith(
- expect.objectContaining({
- widget: {
- displayType: 'line',
- interval: undefined,
- limit: undefined,
- queries: [
- {
- aggregates: ['count()'],
- columns: [],
- conditions: '',
- fields: ['count()'],
- name: '',
- orderby: '',
- },
- ],
- title: 'Saved query #1',
- widgetType: 'transaction-like',
- },
- widgetAsQueryParams: expect.objectContaining({
- cursor: '0:1:1',
- dataset: 'transaction-like',
- defaultTableColumns: ['test', 'count()'],
- defaultTitle: 'Saved query #1',
- defaultWidgetQuery:
- 'name=&aggregates=count()&columns=&fields=count()&conditions=&orderby=',
- displayType: 'line',
- source: 'discoverv2',
- statsPeriod: '14d',
- }),
- })
- );
- });
- });
- });
|