mirror of
https://github.com/elastic/kibana.git
synced 2025-04-19 15:35:00 -04:00
[ES|QL] unskip autocomplete tests (#182273)
## Summary A `.only` snuck into the autocomplete tests a few PRs back and this PR fixes that... FOR GOOD :D
This commit is contained in:
parent
15d2235a73
commit
b694a894ba
4 changed files with 146 additions and 113 deletions
|
@ -16,12 +16,7 @@ module.exports = {
|
|||
files: ['**/*.{ts,tsx}'],
|
||||
parser: '@typescript-eslint/parser',
|
||||
|
||||
plugins: [
|
||||
'@typescript-eslint',
|
||||
'ban',
|
||||
'import',
|
||||
'eslint-comments'
|
||||
],
|
||||
plugins: ['@typescript-eslint', 'ban', 'import', 'eslint-comments'],
|
||||
|
||||
env: {
|
||||
es6: true,
|
||||
|
@ -34,7 +29,7 @@ module.exports = {
|
|||
sourceType: 'module',
|
||||
ecmaVersion: 2018,
|
||||
ecmaFeatures: {
|
||||
jsx: true
|
||||
jsx: true,
|
||||
},
|
||||
// NOTE: That is to avoid a known performance issue related with the `ts.Program` used by
|
||||
// typescript eslint. As we are not using rules that need types information, we can safely
|
||||
|
@ -43,7 +38,7 @@ module.exports = {
|
|||
// https://github.com/typescript-eslint/typescript-eslint/issues/389
|
||||
// https://github.com/typescript-eslint/typescript-eslint/issues/243
|
||||
// https://github.com/typescript-eslint/typescript-eslint/pull/361
|
||||
project: undefined
|
||||
project: undefined,
|
||||
},
|
||||
|
||||
// NOTE: we can't override the extends option here to apply
|
||||
|
@ -60,32 +55,38 @@ module.exports = {
|
|||
//
|
||||
// Old recommended tslint rules
|
||||
'@typescript-eslint/adjacent-overload-signatures': 'error',
|
||||
'@typescript-eslint/array-type': ['error', { default: 'array-simple', readonly: 'array-simple' }],
|
||||
'@typescript-eslint/ban-types': ['error', {
|
||||
types: {
|
||||
SFC: {
|
||||
message: 'Use FC or FunctionComponent instead.',
|
||||
fixWith: 'FC'
|
||||
'@typescript-eslint/array-type': [
|
||||
'error',
|
||||
{ default: 'array-simple', readonly: 'array-simple' },
|
||||
],
|
||||
'@typescript-eslint/ban-types': [
|
||||
'error',
|
||||
{
|
||||
types: {
|
||||
SFC: {
|
||||
message: 'Use FC or FunctionComponent instead.',
|
||||
fixWith: 'FC',
|
||||
},
|
||||
'React.SFC': {
|
||||
message: 'Use FC or FunctionComponent instead.',
|
||||
fixWith: 'React.FC',
|
||||
},
|
||||
StatelessComponent: {
|
||||
message: 'Use FunctionComponent instead.',
|
||||
fixWith: 'FunctionComponent',
|
||||
},
|
||||
'React.StatelessComponent': {
|
||||
message: 'Use FunctionComponent instead.',
|
||||
fixWith: 'React.FunctionComponent',
|
||||
},
|
||||
// used in the codebase in the wild
|
||||
'{}': false,
|
||||
object: false,
|
||||
Function: false,
|
||||
},
|
||||
'React.SFC': {
|
||||
message: 'Use FC or FunctionComponent instead.',
|
||||
fixWith: 'React.FC'
|
||||
},
|
||||
StatelessComponent: {
|
||||
message: 'Use FunctionComponent instead.',
|
||||
fixWith: 'FunctionComponent'
|
||||
},
|
||||
'React.StatelessComponent': {
|
||||
message: 'Use FunctionComponent instead.',
|
||||
fixWith: 'React.FunctionComponent'
|
||||
},
|
||||
// used in the codebase in the wild
|
||||
'{}': false,
|
||||
'object': false,
|
||||
'Function': false,
|
||||
}
|
||||
}],
|
||||
'camelcase': 'off',
|
||||
},
|
||||
],
|
||||
camelcase: 'off',
|
||||
'@typescript-eslint/naming-convention': [
|
||||
'error',
|
||||
{
|
||||
|
@ -93,8 +94,8 @@ module.exports = {
|
|||
format: ['camelCase'],
|
||||
filter: {
|
||||
regex: allowedNameRegexp,
|
||||
match: false
|
||||
}
|
||||
match: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
selector: 'variable',
|
||||
|
@ -105,19 +106,16 @@ module.exports = {
|
|||
],
|
||||
filter: {
|
||||
regex: allowedNameRegexp,
|
||||
match: false
|
||||
}
|
||||
match: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
selector: 'parameter',
|
||||
format: [
|
||||
'camelCase',
|
||||
'PascalCase',
|
||||
],
|
||||
format: ['camelCase', 'PascalCase'],
|
||||
filter: {
|
||||
regex: allowedNameRegexp,
|
||||
match: false
|
||||
}
|
||||
match: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
selector: 'memberLike',
|
||||
|
@ -125,23 +123,23 @@ module.exports = {
|
|||
'camelCase',
|
||||
'PascalCase',
|
||||
'snake_case', // keys in elasticsearch requests / responses
|
||||
'UPPER_CASE'
|
||||
'UPPER_CASE',
|
||||
],
|
||||
filter: {
|
||||
regex: allowedNameRegexp,
|
||||
match: false
|
||||
}
|
||||
match: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
selector: 'function',
|
||||
format: [
|
||||
'camelCase',
|
||||
'PascalCase' // React.FunctionComponent =
|
||||
'PascalCase', // React.FunctionComponent =
|
||||
],
|
||||
filter: {
|
||||
regex: allowedNameRegexp,
|
||||
match: false
|
||||
}
|
||||
match: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
selector: 'typeLike',
|
||||
|
@ -164,27 +162,31 @@ module.exports = {
|
|||
'objectLiteralMethod',
|
||||
'typeMethod',
|
||||
'accessor',
|
||||
'enumMember'
|
||||
'enumMember',
|
||||
],
|
||||
format: null,
|
||||
modifiers: ['requiresQuotes']
|
||||
}
|
||||
modifiers: ['requiresQuotes'],
|
||||
},
|
||||
],
|
||||
'@typescript-eslint/explicit-member-accessibility': ['error',
|
||||
'@typescript-eslint/explicit-member-accessibility': [
|
||||
'error',
|
||||
{
|
||||
accessibility: 'off',
|
||||
overrides: {
|
||||
accessors: 'explicit',
|
||||
constructors: 'no-public',
|
||||
parameterProperties: 'explicit'
|
||||
}
|
||||
}
|
||||
parameterProperties: 'explicit',
|
||||
},
|
||||
},
|
||||
],
|
||||
'@typescript-eslint/prefer-function-type': 'error',
|
||||
'@typescript-eslint/consistent-type-definitions': ['error', 'interface'],
|
||||
'@typescript-eslint/member-ordering': ['error', {
|
||||
'default': ['public-static-field', 'static-field', 'instance-field']
|
||||
}],
|
||||
'@typescript-eslint/member-ordering': [
|
||||
'error',
|
||||
{
|
||||
default: ['public-static-field', 'static-field', 'instance-field'],
|
||||
},
|
||||
],
|
||||
'@typescript-eslint/consistent-type-assertions': 'error',
|
||||
'@typescript-eslint/no-empty-interface': 'error',
|
||||
'@typescript-eslint/no-extra-non-null-assertion': 'error',
|
||||
|
@ -195,24 +197,26 @@ module.exports = {
|
|||
'@typescript-eslint/no-undef': 'off',
|
||||
'no-undef': 'off',
|
||||
|
||||
'@typescript-eslint/triple-slash-reference': ['error', {
|
||||
path: 'never',
|
||||
types: 'never',
|
||||
lib: 'never'
|
||||
}],
|
||||
'@typescript-eslint/triple-slash-reference': [
|
||||
'error',
|
||||
{
|
||||
path: 'never',
|
||||
types: 'never',
|
||||
lib: 'never',
|
||||
},
|
||||
],
|
||||
'@typescript-eslint/no-var-requires': 'error',
|
||||
'@typescript-eslint/unified-signatures': 'error',
|
||||
'constructor-super': 'error',
|
||||
'dot-notation': 'error',
|
||||
'eqeqeq': ['error', 'always', {'null': 'ignore'}],
|
||||
eqeqeq: ['error', 'always', { null: 'ignore' }],
|
||||
'guard-for-in': 'error',
|
||||
'import/order': ['error', {
|
||||
'groups': [
|
||||
['external', 'builtin'],
|
||||
'internal',
|
||||
['parent', 'sibling', 'index'],
|
||||
],
|
||||
}],
|
||||
'import/order': [
|
||||
'error',
|
||||
{
|
||||
groups: [['external', 'builtin'], 'internal', ['parent', 'sibling', 'index']],
|
||||
},
|
||||
],
|
||||
'max-classes-per-file': ['error', 1],
|
||||
'no-bitwise': 'error',
|
||||
'no-caller': 'error',
|
||||
|
@ -233,22 +237,27 @@ module.exports = {
|
|||
'no-unused-labels': 'error',
|
||||
'no-var': 'error',
|
||||
'object-shorthand': 'error',
|
||||
'one-var': [ 'error', 'never' ],
|
||||
'one-var': ['error', 'never'],
|
||||
'prefer-const': 'error',
|
||||
'prefer-rest-params': 'error',
|
||||
'radix': 'error',
|
||||
'spaced-comment': ["error", "always", {
|
||||
"exceptions": ["/"]
|
||||
}],
|
||||
radix: 'error',
|
||||
'spaced-comment': [
|
||||
'error',
|
||||
'always',
|
||||
{
|
||||
exceptions: ['/'],
|
||||
},
|
||||
],
|
||||
'use-isnan': 'error',
|
||||
|
||||
// Old tslint yml override or defined rules
|
||||
'ban/ban': [
|
||||
2,
|
||||
{'name': ['describe', 'only'], 'message': 'No exclusive suites.'},
|
||||
{'name': ['it', 'only'], 'message': 'No exclusive tests.'},
|
||||
{'name': ['test', 'only'], 'message': 'No exclusive tests.'},
|
||||
|
||||
{ name: ['describe', 'only'], message: 'No exclusive suites.' },
|
||||
{ name: ['it', 'only'], message: 'No exclusive tests.' },
|
||||
{ name: ['test', 'only'], message: 'No exclusive tests.' },
|
||||
{ name: ['testSuggestions', 'only'], message: 'No exclusive tests.' },
|
||||
{ name: ['testErrorsAndWarnings', 'only'], message: 'No exclusive tests.' },
|
||||
],
|
||||
'import/no-default-export': 'error',
|
||||
|
||||
|
@ -257,13 +266,13 @@ module.exports = {
|
|||
'no-restricted-syntax': [
|
||||
'error',
|
||||
{
|
||||
"selector": "TSEnumDeclaration[const=true]",
|
||||
"message": "Do not use `const` with enum declarations"
|
||||
}
|
||||
]
|
||||
selector: 'TSEnumDeclaration[const=true]',
|
||||
message: 'Do not use `const` with enum declarations',
|
||||
},
|
||||
],
|
||||
},
|
||||
eslintConfigPrettierRules
|
||||
)
|
||||
),
|
||||
},
|
||||
]
|
||||
],
|
||||
};
|
||||
|
|
|
@ -12,10 +12,9 @@ import { builtinFunctions } from '../definitions/builtin';
|
|||
import { statsAggregationFunctionDefinitions } from '../definitions/aggs';
|
||||
import { chronoLiterals, timeLiterals } from '../definitions/literals';
|
||||
import { commandDefinitions } from '../definitions/commands';
|
||||
import { TRIGGER_SUGGESTION_COMMAND } from './factories';
|
||||
import { getUnitDuration, TRIGGER_SUGGESTION_COMMAND } from './factories';
|
||||
import { camelCase } from 'lodash';
|
||||
import { getAstAndSyntaxErrors } from '@kbn/esql-ast';
|
||||
import { SuggestionRawDefinition } from './types';
|
||||
import { groupingFunctionDefinitions } from '../definitions/grouping';
|
||||
|
||||
const triggerCharacters = [',', '(', '=', ' '];
|
||||
|
@ -231,14 +230,14 @@ function getPolicyFields(policyName: string) {
|
|||
describe('autocomplete', () => {
|
||||
type TestArgs = [
|
||||
string,
|
||||
Array<string | Partial<SuggestionRawDefinition>>,
|
||||
string[],
|
||||
(string | number)?,
|
||||
Parameters<typeof createCustomCallbackMocks>?
|
||||
];
|
||||
|
||||
const testSuggestionsFn = (
|
||||
statement: string,
|
||||
expected: Array<string | Partial<SuggestionRawDefinition>>,
|
||||
expected: string[],
|
||||
triggerCharacter: string | number = '',
|
||||
customCallbacksArgs: Parameters<typeof createCustomCallbackMocks> = [
|
||||
undefined,
|
||||
|
@ -271,28 +270,20 @@ describe('autocomplete', () => {
|
|||
async (text) => (text ? getAstAndSyntaxErrors(text) : { ast: [], errors: [] }),
|
||||
callbackMocks
|
||||
);
|
||||
const suggestionInertTextSorted = suggestions
|
||||
// simulate the editor behaviour for sorting suggestions
|
||||
// copied from https://github.com/microsoft/vscode/blob/0a141d23179c76c5771df25a43546d9d9b6ed71c/src/vs/workbench/contrib/testing/browser/testingDecorations.ts#L971-L972
|
||||
// still not sure how accurate this is...
|
||||
.sort((a, b) => (a.sortText || a.label).localeCompare(b.sortText || b.label));
|
||||
|
||||
expect(suggestionInertTextSorted).toHaveLength(expected.length);
|
||||
for (const [index, receivedSuggestion] of suggestionInertTextSorted.entries()) {
|
||||
if (typeof expected[index] !== 'object') {
|
||||
expect(receivedSuggestion.text).toEqual(expected[index]);
|
||||
} else {
|
||||
// check all properties that are defined in the expected suggestion
|
||||
for (const [key, value] of Object.entries(expected[index])) {
|
||||
expect(receivedSuggestion[key as keyof SuggestionRawDefinition]).toEqual(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
const sortedSuggestions = suggestions.map((suggestion) => suggestion.text).sort();
|
||||
const sortedExpected = expected.sort();
|
||||
|
||||
expect(sortedSuggestions).toEqual(sortedExpected);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
// Enrich the function to work with .only and .skip as regular test function
|
||||
//
|
||||
// DO NOT CHANGE THE NAME OF THIS FUNCTION WITHOUT ALSO CHANGING
|
||||
// THE LINTER RULE IN packages/kbn-eslint-config/typescript.js
|
||||
//
|
||||
const testSuggestions = Object.assign(testSuggestionsFn, {
|
||||
skip: (...args: TestArgs) => {
|
||||
const paddingArgs = ['', [undefined, undefined, undefined]].slice(args.length - 2);
|
||||
|
@ -616,6 +607,16 @@ describe('autocomplete', () => {
|
|||
'any',
|
||||
{
|
||||
evalMath: true,
|
||||
grouping: false,
|
||||
},
|
||||
undefined,
|
||||
undefined,
|
||||
'by'
|
||||
);
|
||||
const allGroupingFunctions = getFunctionSignaturesByReturnType(
|
||||
'stats',
|
||||
'any',
|
||||
{
|
||||
grouping: true,
|
||||
},
|
||||
undefined,
|
||||
|
@ -623,25 +624,26 @@ describe('autocomplete', () => {
|
|||
'by'
|
||||
);
|
||||
testSuggestions('from a | stats ', ['var0 =', ...allAggFunctions, ...allEvaFunctions]);
|
||||
testSuggestions('from a | stats a ', [
|
||||
{ text: '= $0', asSnippet: true, command: TRIGGER_SUGGESTION_COMMAND },
|
||||
]);
|
||||
testSuggestions('from a | stats a ', ['= $0']);
|
||||
testSuggestions('from a | stats a=', [...allAggFunctions, ...allEvaFunctions]);
|
||||
testSuggestions.only('from a | stats a=max(b) by ', [
|
||||
testSuggestions('from a | stats a=max(b) by ', [
|
||||
'var0 =',
|
||||
...getFieldNamesByType('any'),
|
||||
...allEvaFunctions,
|
||||
...allGroupingFunctions,
|
||||
]);
|
||||
testSuggestions('from a | stats a=max(b) BY ', [
|
||||
'var0 =',
|
||||
...getFieldNamesByType('any'),
|
||||
...allEvaFunctions,
|
||||
...allGroupingFunctions,
|
||||
]);
|
||||
testSuggestions('from a | stats a=c by d ', [',', '|']);
|
||||
testSuggestions('from a | stats a=c by d, ', [
|
||||
'var0 =',
|
||||
...getFieldNamesByType('any'),
|
||||
...allEvaFunctions,
|
||||
...allGroupingFunctions,
|
||||
]);
|
||||
testSuggestions('from a | stats a=max(b), ', [
|
||||
'var0 =',
|
||||
|
@ -663,6 +665,7 @@ describe('autocomplete', () => {
|
|||
'var0 =',
|
||||
...getFieldNamesByType('any'),
|
||||
...allEvaFunctions,
|
||||
...allGroupingFunctions,
|
||||
]);
|
||||
testSuggestions('from a | stats a=min(b),', ['var0 =', ...allAggFunctions, ...allEvaFunctions]);
|
||||
testSuggestions('from a | stats var0=min(b),var1=c,', [
|
||||
|
@ -705,19 +708,23 @@ describe('autocomplete', () => {
|
|||
...getFieldNamesByType('number'),
|
||||
'`avg(b)`',
|
||||
...getFunctionSignaturesByReturnType('eval', 'number', { evalMath: true }),
|
||||
...allGroupingFunctions,
|
||||
]);
|
||||
testSuggestions('from a | stats avg(b) by var0 = ', [
|
||||
...getFieldNamesByType('any'),
|
||||
...allEvaFunctions,
|
||||
...allGroupingFunctions,
|
||||
]);
|
||||
testSuggestions('from a | stats avg(b) by c, ', [
|
||||
'var0 =',
|
||||
...getFieldNamesByType('any'),
|
||||
...getFunctionSignaturesByReturnType('eval', 'any', { evalMath: true }),
|
||||
...allGroupingFunctions,
|
||||
]);
|
||||
testSuggestions('from a | stats avg(b) by c, var0 = ', [
|
||||
...getFieldNamesByType('any'),
|
||||
...allEvaFunctions,
|
||||
...allGroupingFunctions,
|
||||
]);
|
||||
testSuggestions('from a | stats avg(b) by numberField % 2 ', [',', '|']);
|
||||
|
||||
|
@ -1160,7 +1167,7 @@ describe('autocomplete', () => {
|
|||
}
|
||||
}
|
||||
|
||||
testSuggestions('from a | eval var0 = bucket(@timestamp,', []);
|
||||
testSuggestions('from a | eval var0 = bucket(@timestamp,', getUnitDuration(1));
|
||||
|
||||
describe('date math', () => {
|
||||
const dateSuggestions = timeLiterals.map(({ name }) => name);
|
||||
|
|
|
@ -289,7 +289,7 @@ export const buildNoPoliciesAvailableDefinition = (): SuggestionRawDefinition =>
|
|||
},
|
||||
});
|
||||
|
||||
function getUnitDuration(unit: number = 1) {
|
||||
export function getUnitDuration(unit: number = 1) {
|
||||
const filteredTimeLiteral = timeLiterals.filter(({ name }) => {
|
||||
const result = /s$/.test(name);
|
||||
return unit > 1 ? result : !result;
|
||||
|
@ -297,6 +297,19 @@ function getUnitDuration(unit: number = 1) {
|
|||
return filteredTimeLiteral.map(({ name }) => `${unit} ${name}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given information about the current command and the parameter type, suggest
|
||||
* some literals that may make sense.
|
||||
*
|
||||
* TODO — this currently tries to cover both command-specific suggestions and type
|
||||
* suggestions. We could consider separating the two... or just using parameter types
|
||||
* and forgetting about command-specific suggestions altogether.
|
||||
*
|
||||
* Another thought... should literal suggestions be defined in the definitions file?
|
||||
* That approach might allow for greater specificity in the suggestions and remove some
|
||||
* "magical" logic. Maybe this is really the same thing as the literalOptions parameter
|
||||
* definition property...
|
||||
*/
|
||||
export function getCompatibleLiterals(commandName: string, types: string[], names?: string[]) {
|
||||
const suggestions: SuggestionRawDefinition[] = [];
|
||||
if (types.includes('number')) {
|
||||
|
|
|
@ -362,6 +362,10 @@ describe('validation logic', () => {
|
|||
type TestArgs = [string, string[], string[]?];
|
||||
|
||||
// Make only and skip work with our custom wrapper
|
||||
//
|
||||
// DO NOT CHANGE THE NAME OF THIS FUNCTION WITHOUT ALSO CHANGING
|
||||
// THE LINTER RULE IN packages/kbn-eslint-config/typescript.js
|
||||
//
|
||||
const testErrorsAndWarnings = Object.assign(testErrorsAndWarningsFn, {
|
||||
skip: (...args: TestArgs) => {
|
||||
const warningArgs = [[]].slice(args.length - 2);
|
||||
|
|
Loading…
Add table
Reference in a new issue