Skip to content

Commit b9e45fe

Browse files
authored
[7.x] Correctly process paths in map_of and record_of. Do not swallow and use indent for nested one_of error messages. (#49507)
1 parent bbca758 commit b9e45fe

File tree

8 files changed

+67
-7
lines changed

8 files changed

+67
-7
lines changed

packages/kbn-config-schema/src/errors/validation_error.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,18 @@
2020
import { SchemaError, SchemaTypeError, SchemaTypesError } from '.';
2121

2222
export class ValidationError extends SchemaError {
23-
public static extractMessage(error: SchemaTypeError, namespace?: string) {
23+
private static extractMessage(error: SchemaTypeError, namespace?: string, level?: number) {
2424
const path = typeof namespace === 'string' ? [namespace, ...error.path] : error.path;
2525

2626
let message = error.message;
2727
if (error instanceof SchemaTypesError) {
28+
const indentLevel = level || 0;
2829
const childErrorMessages = error.errors.map(childError =>
29-
ValidationError.extractMessage(childError, namespace)
30+
ValidationError.extractMessage(childError, namespace, indentLevel + 1)
3031
);
3132

3233
message = `${message}\n${childErrorMessages
33-
.map(childErrorMessage => `- ${childErrorMessage}`)
34+
.map(childErrorMessage => `${' '.repeat(indentLevel)}- ${childErrorMessage}`)
3435
.join('\n')}`;
3536
}
3637

packages/kbn-config-schema/src/types/map_of_type.test.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,3 +108,23 @@ test('object within mapOf', () => {
108108

109109
expect(type.validate(value)).toEqual(expected);
110110
});
111+
112+
test('error preserves full path', () => {
113+
const type = schema.object({
114+
grandParentKey: schema.object({
115+
parentKey: schema.mapOf(schema.string({ minLength: 2 }), schema.number()),
116+
}),
117+
});
118+
119+
expect(() =>
120+
type.validate({ grandParentKey: { parentKey: { a: 'some-value' } } })
121+
).toThrowErrorMatchingInlineSnapshot(
122+
`"[grandParentKey.parentKey.key(\\"a\\")]: value is [a] but it must have a minimum length of [2]."`
123+
);
124+
125+
expect(() =>
126+
type.validate({ grandParentKey: { parentKey: { ab: 'some-value' } } })
127+
).toThrowErrorMatchingInlineSnapshot(
128+
`"[grandParentKey.parentKey.ab]: expected value of type [number] but got [string]"`
129+
);
130+
});

packages/kbn-config-schema/src/types/map_type.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ export class MapOfType<K, V> extends Type<Map<K, V>> {
5050
return `expected value of type [Map] or [object] but got [${typeDetect(value)}]`;
5151
case 'map.key':
5252
case 'map.value':
53-
const childPathWithIndex = reason.path.slice();
53+
const childPathWithIndex = path.slice();
5454
childPathWithIndex.splice(
5555
path.length,
5656
0,

packages/kbn-config-schema/src/types/one_of_type.test.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,3 +125,20 @@ test('fails if not matching literal', () => {
125125

126126
expect(() => type.validate('bar')).toThrowErrorMatchingSnapshot();
127127
});
128+
129+
test('fails if nested union type fail', () => {
130+
const type = schema.oneOf([
131+
schema.oneOf([schema.boolean()]),
132+
schema.oneOf([schema.oneOf([schema.object({}), schema.number()])]),
133+
]);
134+
135+
expect(() => type.validate('aaa')).toThrowErrorMatchingInlineSnapshot(`
136+
"types that failed validation:
137+
- [0]: types that failed validation:
138+
- [0]: expected value of type [boolean] but got [string]
139+
- [1]: types that failed validation:
140+
- [0]: types that failed validation:
141+
- [0]: expected a plain object value, but found [string] instead.
142+
- [1]: expected value of type [number] but got [string]"
143+
`);
144+
});

packages/kbn-config-schema/src/types/record_of_type.test.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,3 +120,23 @@ test('object within recordOf', () => {
120120

121121
expect(type.validate(value)).toEqual({ foo: { bar: 123 } });
122122
});
123+
124+
test('error preserves full path', () => {
125+
const type = schema.object({
126+
grandParentKey: schema.object({
127+
parentKey: schema.recordOf(schema.string({ minLength: 2 }), schema.number()),
128+
}),
129+
});
130+
131+
expect(() =>
132+
type.validate({ grandParentKey: { parentKey: { a: 'some-value' } } })
133+
).toThrowErrorMatchingInlineSnapshot(
134+
`"[grandParentKey.parentKey.key(\\"a\\")]: value is [a] but it must have a minimum length of [2]."`
135+
);
136+
137+
expect(() =>
138+
type.validate({ grandParentKey: { parentKey: { ab: 'some-value' } } })
139+
).toThrowErrorMatchingInlineSnapshot(
140+
`"[grandParentKey.parentKey.ab]: expected value of type [number] but got [string]"`
141+
);
142+
});

packages/kbn-config-schema/src/types/record_type.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ export class RecordOfType<K extends string, V> extends Type<Record<K, V>> {
4242
return `expected value of type [object] but got [${typeDetect(value)}]`;
4343
case 'record.key':
4444
case 'record.value':
45-
const childPathWithIndex = reason.path.slice();
45+
const childPathWithIndex = path.slice();
4646
childPathWithIndex.splice(
4747
path.length,
4848
0,

packages/kbn-config-schema/src/types/union_type.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,9 @@ export class UnionType<RTS extends Array<Type<any>>, T> extends Type<T> {
4141
const childPathWithIndex = e.path.slice();
4242
childPathWithIndex.splice(path.length, 0, index.toString());
4343

44-
return new SchemaTypeError(e.message, childPathWithIndex);
44+
return e instanceof SchemaTypesError
45+
? new SchemaTypesError(e.message, childPathWithIndex, e.errors)
46+
: new SchemaTypeError(e.message, childPathWithIndex);
4547
})
4648
);
4749
}

x-pack/plugins/spaces/server/routes/api/external/copy_to_space.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,7 @@ describe('copy to space', () => {
337337
expect(() =>
338338
resolveConflicts.routeValidation.body!.validate(payload)
339339
).toThrowErrorMatchingInlineSnapshot(
340-
`"[key(\\"invalid-space-id!@#$%^&*()\\")]: Invalid space id: invalid-space-id!@#$%^&*()"`
340+
`"[retries.key(\\"invalid-space-id!@#$%^&*()\\")]: Invalid space id: invalid-space-id!@#$%^&*()"`
341341
);
342342
});
343343

0 commit comments

Comments
 (0)