mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 01:13:23 -04:00
[7.x] Correctly process paths in map_of
and record_of
. Do not swallow and use indent for nested one_of
error messages. (#49507)
This commit is contained in:
parent
bbca758a09
commit
b9e45fedf3
8 changed files with 67 additions and 7 deletions
|
@ -20,17 +20,18 @@
|
|||
import { SchemaError, SchemaTypeError, SchemaTypesError } from '.';
|
||||
|
||||
export class ValidationError extends SchemaError {
|
||||
public static extractMessage(error: SchemaTypeError, namespace?: string) {
|
||||
private static extractMessage(error: SchemaTypeError, namespace?: string, level?: number) {
|
||||
const path = typeof namespace === 'string' ? [namespace, ...error.path] : error.path;
|
||||
|
||||
let message = error.message;
|
||||
if (error instanceof SchemaTypesError) {
|
||||
const indentLevel = level || 0;
|
||||
const childErrorMessages = error.errors.map(childError =>
|
||||
ValidationError.extractMessage(childError, namespace)
|
||||
ValidationError.extractMessage(childError, namespace, indentLevel + 1)
|
||||
);
|
||||
|
||||
message = `${message}\n${childErrorMessages
|
||||
.map(childErrorMessage => `- ${childErrorMessage}`)
|
||||
.map(childErrorMessage => `${' '.repeat(indentLevel)}- ${childErrorMessage}`)
|
||||
.join('\n')}`;
|
||||
}
|
||||
|
||||
|
|
|
@ -108,3 +108,23 @@ test('object within mapOf', () => {
|
|||
|
||||
expect(type.validate(value)).toEqual(expected);
|
||||
});
|
||||
|
||||
test('error preserves full path', () => {
|
||||
const type = schema.object({
|
||||
grandParentKey: schema.object({
|
||||
parentKey: schema.mapOf(schema.string({ minLength: 2 }), schema.number()),
|
||||
}),
|
||||
});
|
||||
|
||||
expect(() =>
|
||||
type.validate({ grandParentKey: { parentKey: { a: 'some-value' } } })
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
`"[grandParentKey.parentKey.key(\\"a\\")]: value is [a] but it must have a minimum length of [2]."`
|
||||
);
|
||||
|
||||
expect(() =>
|
||||
type.validate({ grandParentKey: { parentKey: { ab: 'some-value' } } })
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
`"[grandParentKey.parentKey.ab]: expected value of type [number] but got [string]"`
|
||||
);
|
||||
});
|
||||
|
|
|
@ -50,7 +50,7 @@ export class MapOfType<K, V> extends Type<Map<K, V>> {
|
|||
return `expected value of type [Map] or [object] but got [${typeDetect(value)}]`;
|
||||
case 'map.key':
|
||||
case 'map.value':
|
||||
const childPathWithIndex = reason.path.slice();
|
||||
const childPathWithIndex = path.slice();
|
||||
childPathWithIndex.splice(
|
||||
path.length,
|
||||
0,
|
||||
|
|
|
@ -125,3 +125,20 @@ test('fails if not matching literal', () => {
|
|||
|
||||
expect(() => type.validate('bar')).toThrowErrorMatchingSnapshot();
|
||||
});
|
||||
|
||||
test('fails if nested union type fail', () => {
|
||||
const type = schema.oneOf([
|
||||
schema.oneOf([schema.boolean()]),
|
||||
schema.oneOf([schema.oneOf([schema.object({}), schema.number()])]),
|
||||
]);
|
||||
|
||||
expect(() => type.validate('aaa')).toThrowErrorMatchingInlineSnapshot(`
|
||||
"types that failed validation:
|
||||
- [0]: types that failed validation:
|
||||
- [0]: expected value of type [boolean] but got [string]
|
||||
- [1]: types that failed validation:
|
||||
- [0]: types that failed validation:
|
||||
- [0]: expected a plain object value, but found [string] instead.
|
||||
- [1]: expected value of type [number] but got [string]"
|
||||
`);
|
||||
});
|
||||
|
|
|
@ -120,3 +120,23 @@ test('object within recordOf', () => {
|
|||
|
||||
expect(type.validate(value)).toEqual({ foo: { bar: 123 } });
|
||||
});
|
||||
|
||||
test('error preserves full path', () => {
|
||||
const type = schema.object({
|
||||
grandParentKey: schema.object({
|
||||
parentKey: schema.recordOf(schema.string({ minLength: 2 }), schema.number()),
|
||||
}),
|
||||
});
|
||||
|
||||
expect(() =>
|
||||
type.validate({ grandParentKey: { parentKey: { a: 'some-value' } } })
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
`"[grandParentKey.parentKey.key(\\"a\\")]: value is [a] but it must have a minimum length of [2]."`
|
||||
);
|
||||
|
||||
expect(() =>
|
||||
type.validate({ grandParentKey: { parentKey: { ab: 'some-value' } } })
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
`"[grandParentKey.parentKey.ab]: expected value of type [number] but got [string]"`
|
||||
);
|
||||
});
|
||||
|
|
|
@ -42,7 +42,7 @@ export class RecordOfType<K extends string, V> extends Type<Record<K, V>> {
|
|||
return `expected value of type [object] but got [${typeDetect(value)}]`;
|
||||
case 'record.key':
|
||||
case 'record.value':
|
||||
const childPathWithIndex = reason.path.slice();
|
||||
const childPathWithIndex = path.slice();
|
||||
childPathWithIndex.splice(
|
||||
path.length,
|
||||
0,
|
||||
|
|
|
@ -41,7 +41,9 @@ export class UnionType<RTS extends Array<Type<any>>, T> extends Type<T> {
|
|||
const childPathWithIndex = e.path.slice();
|
||||
childPathWithIndex.splice(path.length, 0, index.toString());
|
||||
|
||||
return new SchemaTypeError(e.message, childPathWithIndex);
|
||||
return e instanceof SchemaTypesError
|
||||
? new SchemaTypesError(e.message, childPathWithIndex, e.errors)
|
||||
: new SchemaTypeError(e.message, childPathWithIndex);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
|
|
@ -337,7 +337,7 @@ describe('copy to space', () => {
|
|||
expect(() =>
|
||||
resolveConflicts.routeValidation.body!.validate(payload)
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
`"[key(\\"invalid-space-id!@#$%^&*()\\")]: Invalid space id: invalid-space-id!@#$%^&*()"`
|
||||
`"[retries.key(\\"invalid-space-id!@#$%^&*()\\")]: Invalid space id: invalid-space-id!@#$%^&*()"`
|
||||
);
|
||||
});
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue