|
|
@ -1,40 +1,18 @@ |
|
|
|
import { render, screen } from '@testing-library/react'; |
|
|
|
import { render, screen, waitFor } from '@testing-library/react'; |
|
|
|
import userEvent from '@testing-library/user-event'; |
|
|
|
import userEvent from '@testing-library/user-event'; |
|
|
|
import React from 'react'; |
|
|
|
import React from 'react'; |
|
|
|
import { initTemplateSrv } from 'test/helpers/initTemplateSrv'; |
|
|
|
import { initTemplateSrv } from 'test/helpers/initTemplateSrv'; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import { LanguageProvider } from '@grafana/data'; |
|
|
|
import { FetchError, setTemplateSrv } from '@grafana/runtime'; |
|
|
|
import { FetchError, setTemplateSrv } from '@grafana/runtime'; |
|
|
|
|
|
|
|
|
|
|
|
import { TraceqlFilter, TraceqlSearchScope } from '../dataquery.gen'; |
|
|
|
import { TraceqlFilter, TraceqlSearchScope } from '../dataquery.gen'; |
|
|
|
import { TempoDatasource } from '../datasource'; |
|
|
|
import { TempoDatasource } from '../datasource'; |
|
|
|
|
|
|
|
import TempoLanguageProvider from '../language_provider'; |
|
|
|
|
|
|
|
import { keywordOperators, numberOperators, operators, stringOperators } from '../traceql/traceql'; |
|
|
|
|
|
|
|
|
|
|
|
import SearchField from './SearchField'; |
|
|
|
import SearchField from './SearchField'; |
|
|
|
|
|
|
|
|
|
|
|
const getOptionsV2 = jest.fn().mockImplementation(() => { |
|
|
|
|
|
|
|
return new Promise((resolve) => { |
|
|
|
|
|
|
|
setTimeout(() => { |
|
|
|
|
|
|
|
resolve([ |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
value: 'customer', |
|
|
|
|
|
|
|
label: 'customer', |
|
|
|
|
|
|
|
type: 'string', |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
value: 'driver', |
|
|
|
|
|
|
|
label: 'driver', |
|
|
|
|
|
|
|
type: 'string', |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
]); |
|
|
|
|
|
|
|
}, 1000); |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
jest.mock('../language_provider', () => { |
|
|
|
|
|
|
|
return jest.fn().mockImplementation(() => { |
|
|
|
|
|
|
|
return { getOptionsV2 }; |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
describe('SearchField', () => { |
|
|
|
describe('SearchField', () => { |
|
|
|
let templateSrv = initTemplateSrv('key', [{ name: 'templateVariable1' }, { name: 'templateVariable2' }]); |
|
|
|
let templateSrv = initTemplateSrv('key', [{ name: 'templateVariable1' }, { name: 'templateVariable2' }]); |
|
|
|
let user: ReturnType<typeof userEvent.setup>; |
|
|
|
let user: ReturnType<typeof userEvent.setup>; |
|
|
@ -51,7 +29,7 @@ describe('SearchField', () => { |
|
|
|
jest.useRealTimers(); |
|
|
|
jest.useRealTimers(); |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
it('should not render tag if hideTag is true', () => { |
|
|
|
it('should not render tag if hideTag is true', async () => { |
|
|
|
const updateFilter = jest.fn((val) => { |
|
|
|
const updateFilter = jest.fn((val) => { |
|
|
|
return val; |
|
|
|
return val; |
|
|
|
}); |
|
|
|
}); |
|
|
@ -59,9 +37,11 @@ describe('SearchField', () => { |
|
|
|
|
|
|
|
|
|
|
|
const { container } = renderSearchField(updateFilter, filter, [], true); |
|
|
|
const { container } = renderSearchField(updateFilter, filter, [], true); |
|
|
|
|
|
|
|
|
|
|
|
expect(container.querySelector(`input[aria-label="select test1 tag"]`)).not.toBeInTheDocument(); |
|
|
|
await waitFor(async () => { |
|
|
|
expect(container.querySelector(`input[aria-label="select test1 operator"]`)).toBeInTheDocument(); |
|
|
|
expect(container.querySelector(`input[aria-label="select test1 tag"]`)).not.toBeInTheDocument(); |
|
|
|
expect(container.querySelector(`input[aria-label="select test1 value"]`)).toBeInTheDocument(); |
|
|
|
expect(container.querySelector(`input[aria-label="select test1 operator"]`)).toBeInTheDocument(); |
|
|
|
|
|
|
|
expect(container.querySelector(`input[aria-label="select test1 value"]`)).toBeInTheDocument(); |
|
|
|
|
|
|
|
}); |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
it('should update operator when new value is selected in operator input', async () => { |
|
|
|
it('should update operator when new value is selected in operator input', async () => { |
|
|
@ -71,7 +51,7 @@ describe('SearchField', () => { |
|
|
|
const filter: TraceqlFilter = { id: 'test1', operator: '=', valueType: 'string', tag: 'test-tag' }; |
|
|
|
const filter: TraceqlFilter = { id: 'test1', operator: '=', valueType: 'string', tag: 'test-tag' }; |
|
|
|
const { container } = renderSearchField(updateFilter, filter); |
|
|
|
const { container } = renderSearchField(updateFilter, filter); |
|
|
|
|
|
|
|
|
|
|
|
const select = await container.querySelector(`input[aria-label="select test1 operator"]`); |
|
|
|
const select = container.querySelector(`input[aria-label="select test1 operator"]`); |
|
|
|
expect(select).not.toBeNull(); |
|
|
|
expect(select).not.toBeNull(); |
|
|
|
expect(select).toBeInTheDocument(); |
|
|
|
expect(select).toBeInTheDocument(); |
|
|
|
if (select) { |
|
|
|
if (select) { |
|
|
@ -95,7 +75,7 @@ describe('SearchField', () => { |
|
|
|
}; |
|
|
|
}; |
|
|
|
const { container } = renderSearchField(updateFilter, filter); |
|
|
|
const { container } = renderSearchField(updateFilter, filter); |
|
|
|
|
|
|
|
|
|
|
|
const select = await container.querySelector(`input[aria-label="select test1 value"]`); |
|
|
|
const select = container.querySelector(`input[aria-label="select test1 value"]`); |
|
|
|
expect(select).not.toBeNull(); |
|
|
|
expect(select).not.toBeNull(); |
|
|
|
expect(select).toBeInTheDocument(); |
|
|
|
expect(select).toBeInTheDocument(); |
|
|
|
if (select) { |
|
|
|
if (select) { |
|
|
@ -178,14 +158,112 @@ describe('SearchField', () => { |
|
|
|
expect(await screen.findByText('$templateVariable2')).toBeInTheDocument(); |
|
|
|
expect(await screen.findByText('$templateVariable2')).toBeInTheDocument(); |
|
|
|
} |
|
|
|
} |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
it('should only show keyword operators if options tag type is keyword', async () => { |
|
|
|
|
|
|
|
const filter: TraceqlFilter = { id: 'test1', operator: '=', valueType: 'string', tag: 'test-tag' }; |
|
|
|
|
|
|
|
const lp = { |
|
|
|
|
|
|
|
getOptionsV2: jest.fn().mockReturnValue([ |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
value: 'ok', |
|
|
|
|
|
|
|
label: 'ok', |
|
|
|
|
|
|
|
type: 'keyword', |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
]), |
|
|
|
|
|
|
|
} as unknown as TempoLanguageProvider; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const { container } = renderSearchField(jest.fn(), filter, [], false, lp); |
|
|
|
|
|
|
|
const select = container.querySelector(`input[aria-label="select test1 operator"]`); |
|
|
|
|
|
|
|
if (select) { |
|
|
|
|
|
|
|
await user.click(select); |
|
|
|
|
|
|
|
await waitFor(async () => { |
|
|
|
|
|
|
|
expect(screen.getByText('Equals')).toBeInTheDocument(); |
|
|
|
|
|
|
|
expect(screen.getByText('Not equals')).toBeInTheDocument(); |
|
|
|
|
|
|
|
operators |
|
|
|
|
|
|
|
.filter((op) => !keywordOperators.includes(op)) |
|
|
|
|
|
|
|
.forEach((op) => { |
|
|
|
|
|
|
|
expect(screen.queryByText(op)).not.toBeInTheDocument(); |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
it('should only show string operators if options tag type is string', async () => { |
|
|
|
|
|
|
|
const filter: TraceqlFilter = { id: 'test1', operator: '=', valueType: 'string', tag: 'test-tag' }; |
|
|
|
|
|
|
|
const { container } = renderSearchField(jest.fn(), filter); |
|
|
|
|
|
|
|
const select = container.querySelector(`input[aria-label="select test1 operator"]`); |
|
|
|
|
|
|
|
if (select) { |
|
|
|
|
|
|
|
await user.click(select); |
|
|
|
|
|
|
|
await waitFor(async () => { |
|
|
|
|
|
|
|
expect(screen.getByText('Equals')).toBeInTheDocument(); |
|
|
|
|
|
|
|
expect(screen.getByText('Not equals')).toBeInTheDocument(); |
|
|
|
|
|
|
|
expect(screen.getByText('Matches regex')).toBeInTheDocument(); |
|
|
|
|
|
|
|
expect(screen.getByText('Does not match regex')).toBeInTheDocument(); |
|
|
|
|
|
|
|
operators |
|
|
|
|
|
|
|
.filter((op) => !stringOperators.includes(op)) |
|
|
|
|
|
|
|
.forEach((op) => { |
|
|
|
|
|
|
|
expect(screen.queryByText(op)).not.toBeInTheDocument(); |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
it('should only show number operators if options tag type is number', async () => { |
|
|
|
|
|
|
|
const filter: TraceqlFilter = { id: 'test1', operator: '=', valueType: 'string', tag: 'test-tag' }; |
|
|
|
|
|
|
|
const lp = { |
|
|
|
|
|
|
|
getOptionsV2: jest.fn().mockReturnValue([ |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
value: 200, |
|
|
|
|
|
|
|
label: 200, |
|
|
|
|
|
|
|
type: 'int', |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
]), |
|
|
|
|
|
|
|
} as unknown as TempoLanguageProvider; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const { container } = renderSearchField(jest.fn(), filter, [], false, lp); |
|
|
|
|
|
|
|
const select = container.querySelector(`input[aria-label="select test1 operator"]`); |
|
|
|
|
|
|
|
if (select) { |
|
|
|
|
|
|
|
await user.click(select); |
|
|
|
|
|
|
|
await waitFor(async () => { |
|
|
|
|
|
|
|
expect(screen.getByText('Equals')).toBeInTheDocument(); |
|
|
|
|
|
|
|
expect(screen.getByText('Not equals')).toBeInTheDocument(); |
|
|
|
|
|
|
|
expect(screen.getByText('Greater')).toBeInTheDocument(); |
|
|
|
|
|
|
|
expect(screen.getByText('Less')).toBeInTheDocument(); |
|
|
|
|
|
|
|
expect(screen.getByText('Greater or Equal')).toBeInTheDocument(); |
|
|
|
|
|
|
|
expect(screen.getByText('Less or Equal')).toBeInTheDocument(); |
|
|
|
|
|
|
|
operators |
|
|
|
|
|
|
|
.filter((op) => !numberOperators.includes(op)) |
|
|
|
|
|
|
|
.forEach((op) => { |
|
|
|
|
|
|
|
expect(screen.queryByText(op)).not.toBeInTheDocument(); |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}); |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
const renderSearchField = ( |
|
|
|
const renderSearchField = ( |
|
|
|
updateFilter: (f: TraceqlFilter) => void, |
|
|
|
updateFilter: (f: TraceqlFilter) => void, |
|
|
|
filter: TraceqlFilter, |
|
|
|
filter: TraceqlFilter, |
|
|
|
tags?: string[], |
|
|
|
tags?: string[], |
|
|
|
hideTag?: boolean |
|
|
|
hideTag?: boolean, |
|
|
|
|
|
|
|
lp?: LanguageProvider |
|
|
|
) => { |
|
|
|
) => { |
|
|
|
|
|
|
|
const languageProvider = |
|
|
|
|
|
|
|
lp || |
|
|
|
|
|
|
|
({ |
|
|
|
|
|
|
|
getOptionsV2: jest.fn().mockReturnValue([ |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
value: 'customer', |
|
|
|
|
|
|
|
label: 'customer', |
|
|
|
|
|
|
|
type: 'string', |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
value: 'driver', |
|
|
|
|
|
|
|
label: 'driver', |
|
|
|
|
|
|
|
type: 'string', |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
]), |
|
|
|
|
|
|
|
} as unknown as TempoLanguageProvider); |
|
|
|
|
|
|
|
|
|
|
|
const datasource: TempoDatasource = { |
|
|
|
const datasource: TempoDatasource = { |
|
|
|
search: { |
|
|
|
search: { |
|
|
|
filters: [ |
|
|
|
filters: [ |
|
|
@ -198,7 +276,9 @@ const renderSearchField = ( |
|
|
|
{ id: 'span-name', type: 'static', tag: 'name', operator: '=', scope: TraceqlSearchScope.Span }, |
|
|
|
{ id: 'span-name', type: 'static', tag: 'name', operator: '=', scope: TraceqlSearchScope.Span }, |
|
|
|
], |
|
|
|
], |
|
|
|
}, |
|
|
|
}, |
|
|
|
|
|
|
|
languageProvider, |
|
|
|
} as TempoDatasource; |
|
|
|
} as TempoDatasource; |
|
|
|
|
|
|
|
|
|
|
|
return render( |
|
|
|
return render( |
|
|
|
<SearchField |
|
|
|
<SearchField |
|
|
|
datasource={datasource} |
|
|
|
datasource={datasource} |
|
|
|