diff --git a/src/lib/error/bad-data-error.ts b/src/lib/error/bad-data-error.ts index 468b01d079..5baf4a7318 100644 --- a/src/lib/error/bad-data-error.ts +++ b/src/lib/error/bad-data-error.ts @@ -4,7 +4,6 @@ import getProp from 'lodash.get'; import { type ApiErrorSchema, UnleashError } from './unleash-error'; type ValidationErrorDescription = { - description?: string; message: string; path?: string; }; @@ -24,7 +23,7 @@ class BadDataError extends UnleashError { }`; super(topLevelMessage); - this.details = errors ?? [{ message: message, description: message }]; + this.details = errors ?? [{ message: message }]; } toJSON(): ApiErrorSchema { @@ -45,11 +44,10 @@ const missingRequiredPropertyMessage = ( missingPropertyName: string, ) => { const path = constructPath(pathToParentObject, missingPropertyName); - const description = `The \`${path}\` property is required. It was not present on the data you sent.`; + const message = `The \`${path}\` property is required. It was not present on the data you sent.`; return { path, - description, - message: description, + message, }; }; @@ -58,14 +56,13 @@ const additionalPropertiesMessage = ( additionalPropertyName: string, ) => { const path = constructPath(pathToParentObject, additionalPropertyName); - const description = `The ${ + const message = `The ${ pathToParentObject ? `\`${pathToParentObject}\`` : 'root' } object of the request body does not allow additional properties. Your request included the \`${path}\` property.`; return { path, - description, - message: description, + message, }; }; @@ -77,10 +74,9 @@ const genericErrorMessage = ( const input = getProp(requestBody, propertyName.split('/')); const youSent = JSON.stringify(input); - const description = `The \`${propertyName}\` property ${errorMessage}. You sent ${youSent}.`; + const message = `The \`${propertyName}\` property ${errorMessage}. You sent ${youSent}.`; return { - description, - message: description, + message, path: propertyName, }; }; @@ -92,11 +88,10 @@ const oneOfMessage = ( const errorPosition = propertyName === '' ? 'root object' : `"${propertyName}" property`; - const description = `The ${errorPosition} ${errorMessage}. The data you provided matches more than one option in the schema. These options are mutually exclusive. Please refer back to the schema and remove any excess properties.`; + const message = `The ${errorPosition} ${errorMessage}. The data you provided matches more than one option in the schema. These options are mutually exclusive. Please refer back to the schema and remove any excess properties.`; return { - description, - message: description, + message, path: propertyName, }; }; @@ -107,7 +102,7 @@ const enumMessage = ( allowedValues: string[], suppliedValue: string | null | undefined, ) => { - const description = `The \`${propertyName}\` property ${ + const fullMessage = `The \`${propertyName}\` property ${ message ?? 'must match one of the allowed values' }: ${allowedValues .map((value) => `"${value}"`) @@ -116,8 +111,7 @@ const enumMessage = ( )}. You provided "${suppliedValue}", which is not valid. Please use one of the allowed values instead..`; return { - description, - message: description, + message: fullMessage, path: propertyName, }; }; @@ -176,10 +170,9 @@ export const fromJoiError = (err: ValidationError): BadDataError => { const messageEnd = detail.context?.value ? `. You provided ${JSON.stringify(detail.context.value)}.` : '.'; - const description = detail.message + messageEnd; + const message = detail.message + messageEnd; return { - description, - message: description, + message, }; }); diff --git a/src/lib/error/incompatible-project-error.ts b/src/lib/error/incompatible-project-error.ts index 5b8e8ef9f5..59758cd7c7 100644 --- a/src/lib/error/incompatible-project-error.ts +++ b/src/lib/error/incompatible-project-error.ts @@ -14,7 +14,6 @@ export default class IncompatibleProjectError extends UnleashError { { validationErrors: [], message: this.message, - description: this.message, }, ], }; diff --git a/src/lib/error/password-undefined.ts b/src/lib/error/password-undefined.ts index acb27bd82d..919b728f77 100644 --- a/src/lib/error/password-undefined.ts +++ b/src/lib/error/password-undefined.ts @@ -14,7 +14,6 @@ export default class PasswordUndefinedError extends UnleashError { { validationErrors: [], message: this.message, - description: this.message, }, ], }; diff --git a/src/lib/error/project-without-owner-error.ts b/src/lib/error/project-without-owner-error.ts index ab93ef98b4..ad2bf6d19c 100644 --- a/src/lib/error/project-without-owner-error.ts +++ b/src/lib/error/project-without-owner-error.ts @@ -12,7 +12,6 @@ export default class ProjectWithoutOwnerError extends UnleashError { ...super.toJSON(), details: [ { - description: this.message, message: this.message, validationErrors: [], }, diff --git a/src/lib/error/unleash-error.test.ts b/src/lib/error/unleash-error.test.ts index 3b6f2dc358..a2ecb0412a 100644 --- a/src/lib/error/unleash-error.test.ts +++ b/src/lib/error/unleash-error.test.ts @@ -25,7 +25,6 @@ describe('v5 deprecation: backwards compatibility', () => { details: [ { message, - description: message, }, ], }); @@ -40,7 +39,6 @@ describe('Standard/legacy error conversion', () => { expect(result.details).toStrictEqual([ { message, - description: message, }, ]); }); @@ -61,14 +59,14 @@ describe('OpenAPI error conversion', () => { const result = fromOpenApiValidationError({})(error); expect(result).toMatchObject({ - description: + message: // it tells the user that the property is required expect.stringContaining('required'), path: 'enabled', }); // it tells the user the name of the missing property - expect(result.description).toContain(error.params.missingProperty); + expect(result.message).toContain(error.params.missingProperty); }); it('Gives useful error messages for type errors', () => { @@ -89,14 +87,14 @@ describe('OpenAPI error conversion', () => { })(error); expect(result).toMatchObject({ - description: + message: // it provides the message expect.stringContaining(error.message), path: 'parameters', }); // it tells the user what they provided - expect(result.description).toContain(JSON.stringify(parameterValue)); + expect(result.message).toContain(JSON.stringify(parameterValue)); }); it.each(['/body', '/body/subObject'])( @@ -119,18 +117,16 @@ describe('OpenAPI error conversion', () => { })(error); expect(result).toMatchObject({ - description: + message: // it provides the message expect.stringContaining(error.message), path: instancePath.substring('/body/'.length), }); // it tells the user what happened - expect(result.description).toContain( - 'matches more than one option', - ); + expect(result.message).toContain('matches more than one option'); // it tells the user what part of the request body this pertains to - expect(result.description).toContain( + expect(result.message).toContain( instancePath === '/body' ? 'root object' : `"${instancePath.substring('/body/'.length)}" property`, @@ -156,11 +152,10 @@ describe('OpenAPI error conversion', () => { })(error); expect(result).toMatchObject({ - description: expect.stringContaining(error.params.pattern), + message: expect.stringContaining(error.params.pattern), path: 'description', }); - expect(result.description).toContain('description'); - expect(result.description).toContain(requestDescription); + expect(result.message).toContain('description'); }); it('Gives useful enum error messages', () => { @@ -184,13 +179,13 @@ describe('OpenAPI error conversion', () => { const result = fromOpenApiValidationError(request)(error); expect(result).toMatchObject({ - description: expect.stringContaining('weightType'), + message: expect.stringContaining('weightType'), path: 'weightType', }); - expect(result.description).toContain('one of the allowed values'); - expect(result.description).toContain('fix'); - expect(result.description).toContain('variable'); - expect(result.description).toContain('party'); + expect(result.message).toContain('one of the allowed values'); + expect(result.message).toContain('fix'); + expect(result.message).toContain('variable'); + expect(result.message).toContain('party'); }); it('Gives useful min/maxlength error messages', () => { @@ -211,15 +206,15 @@ describe('OpenAPI error conversion', () => { })(error); expect(result).toMatchObject({ - description: + message: // it tells the user what the limit is expect.stringContaining(error.params.limit.toString()), }); // it tells the user which property it pertains to - expect(result.description).toContain('description'); + expect(result.message).toContain('description'); // it tells the user what they provided - expect(result.description).toContain(requestDescription); + expect(result.message).toContain(requestDescription); }); it('Handles numerical min/max errors', () => { @@ -242,17 +237,17 @@ describe('OpenAPI error conversion', () => { })(error); expect(result).toMatchObject({ - description: + message: // it tells the user what the limit is expect.stringContaining(error.params.limit.toString()), }); // it tells the user what kind of comparison it performed - expect(result.description).toContain(error.params.comparison); + expect(result.message).toContain(error.params.comparison); // it tells the user which property it pertains to - expect(result.description).toContain('newprop'); + expect(result.message).toContain('newprop'); // it tells the user what they provided - expect(result.description).toContain(propertyValue.toString()); + expect(result.message).toContain(propertyValue.toString()); }); it('Handles multiple errors', () => { @@ -290,10 +285,10 @@ describe('OpenAPI error conversion', () => { message: expect.stringContaining('`details`'), details: [ { - description: expect.stringContaining('newprop'), + message: expect.stringContaining('newprop'), }, { - description: expect.stringContaining('enabled'), + message: expect.stringContaining('enabled'), }, ], }); @@ -315,14 +310,14 @@ describe('OpenAPI error conversion', () => { ); expect(error).toMatchObject({ - description: expect.stringContaining( + message: expect.stringContaining( openApiError.params.additionalProperty, ), path: 'bogus', }); - expect(error.description).toMatch(/\broot\b/i); - expect(error.description).toMatch(/\badditional properties\b/i); + expect(error.message).toMatch(/\broot\b/i); + expect(error.message).toMatch(/\badditional properties\b/i); }); it('gives useful messages for nested properties', () => { @@ -343,14 +338,14 @@ describe('OpenAPI error conversion', () => { const error = fromOpenApiValidationError(request2)(openApiError); expect(error).toMatchObject({ - description: expect.stringContaining('nestedObject/nested2'), + message: expect.stringContaining('nestedObject/nested2'), path: 'nestedObject/nested2/extraPropertyName', }); - expect(error.description).toContain( + expect(error.message).toContain( openApiError.params.additionalProperty, ); - expect(error.description).toMatch(/\badditional properties\b/i); + expect(error.message).toMatch(/\badditional properties\b/i); }); }); @@ -369,11 +364,11 @@ describe('OpenAPI error conversion', () => { })(error); expect(result).toMatchObject({ - description: expect.stringMatching(/\bnestedObject\/a\/b\b/), + message: expect.stringMatching(/\bnestedObject\/a\/b\b/), path: 'nestedObject/a/b', }); - expect(result.description).toContain('[]'); + expect(result.message).toContain('[]'); }); it('Handles deeply nested properties on referenced schemas', () => { @@ -391,11 +386,11 @@ describe('OpenAPI error conversion', () => { })(error); expect(result).toMatchObject({ - description: expect.stringContaining(illegalValue), + message: expect.stringContaining(illegalValue), path: 'nestedObject/a/b', }); - expect(result.description).toMatch(/\bnestedObject\/a\/b\b/); + expect(result.message).toMatch(/\bnestedObject\/a\/b\b/); }); }); @@ -430,7 +425,7 @@ describe('Error serialization special cases', () => { message: expect.stringContaining('details'), details: [ { - description: + message: '"value" must contain at least 1 items. You provided [].', }, ], @@ -494,14 +489,13 @@ describe('Error serialization special cases', () => { }); it('BadDataError: adds `details` with error details', () => { - const description = 'You did **this** wrong'; - const error = new BadDataError(description).toJSON(); + const message = 'You did **this** wrong'; + const error = new BadDataError(message).toJSON(); expect(error).toMatchObject({ details: [ { - message: description, - description, + message, }, ], }); diff --git a/src/lib/error/unleash-error.ts b/src/lib/error/unleash-error.ts index b8a1c3ec89..a3409bf3b8 100644 --- a/src/lib/error/unleash-error.ts +++ b/src/lib/error/unleash-error.ts @@ -60,7 +60,7 @@ export abstract class UnleashError extends Error { id: this.id, name: this.name, message: this.message, - details: [{ message: this.message, description: this.message }], + details: [{ message: this.message }], }; } diff --git a/src/lib/features/export-import-toggles/export-import.e2e.test.ts b/src/lib/features/export-import-toggles/export-import.e2e.test.ts index e47b69e53d..e700b7862e 100644 --- a/src/lib/features/export-import-toggles/export-import.e2e.test.ts +++ b/src/lib/features/export-import-toggles/export-import.e2e.test.ts @@ -966,7 +966,7 @@ test('reject import with unknown context fields', async () => { 400, ); - expect(body.details[0].description).toMatch(/\bContextField1\b/); + expect(body.details[0].message).toMatch(/\bContextField1\b/); }); test('reject import with unsupported strategies', async () => { @@ -989,7 +989,7 @@ test('reject import with unsupported strategies', async () => { 400, ); - expect(body.details[0].description).toMatch(/\bcustomStrategy\b/); + expect(body.details[0].message).toMatch(/\bcustomStrategy\b/); }); test('reject import with duplicate features', async () => { @@ -1007,7 +1007,7 @@ test('reject import with duplicate features', async () => { 409, ); - expect(body.details[0].description).toBe( + expect(body.details[0].message).toBe( 'A flag with that name already exists', ); }); diff --git a/src/lib/features/project-environments/environments.e2e.test.ts b/src/lib/features/project-environments/environments.e2e.test.ts index 094ca3da39..89e8c56aa0 100644 --- a/src/lib/features/project-environments/environments.e2e.test.ts +++ b/src/lib/features/project-environments/environments.e2e.test.ts @@ -101,7 +101,7 @@ test('Should not remove environment from project if project only has one environ .delete(`/api/admin/projects/default/environments/default`) .expect(400) .expect((r) => { - expect(r.body.details[0].description).toBe( + expect(r.body.details[0].message).toBe( 'You must always have one active environment', ); }); diff --git a/src/lib/features/tag-type/tag-types.e2e.test.ts b/src/lib/features/tag-type/tag-types.e2e.test.ts index bef86e1876..35331871fb 100644 --- a/src/lib/features/tag-type/tag-types.e2e.test.ts +++ b/src/lib/features/tag-type/tag-types.e2e.test.ts @@ -90,7 +90,7 @@ test('Invalid tag types gets rejected', async () => { .set('Content-Type', 'application/json') .expect(400) .expect((res) => { - expect(res.body.details[0].description).toMatch( + expect(res.body.details[0].message).toMatch( '"name" must be URL friendly', ); }); @@ -164,7 +164,7 @@ test('Invalid tag-types get refused by validator', async () => { .set('Content-Type', 'application/json') .expect(400) .expect((res) => { - expect(res.body.details[0].description).toMatch( + expect(res.body.details[0].message).toMatch( '"name" must be URL friendly', ); }); diff --git a/src/lib/routes/admin-api/strategy.test.ts b/src/lib/routes/admin-api/strategy.test.ts index d21225f098..91ad441419 100644 --- a/src/lib/routes/admin-api/strategy.test.ts +++ b/src/lib/routes/admin-api/strategy.test.ts @@ -44,7 +44,7 @@ test('require a name when creating a new strategy', async () => { .expect((res) => { expect( ['name', 'property', 'required'].every((word) => - res.body.details[0].description.includes(word), + res.body.details[0].message.includes(word), ), ).toBeTruthy(); }); @@ -57,7 +57,7 @@ test('require parameters array when creating a new strategy', async () => { .send({ name: 'TestStrat' }) .expect(400); - const detailsDescription = body.details[0].description; + const detailsDescription = body.details[0].message; expect(detailsDescription).toEqual(expect.stringMatching('parameters')); expect(detailsDescription).toEqual(expect.stringMatching('required')); }); diff --git a/src/test/e2e/api/admin/api-token.e2e.test.ts b/src/test/e2e/api/admin/api-token.e2e.test.ts index 40ca4f1681..93d120d13e 100644 --- a/src/test/e2e/api/admin/api-token.e2e.test.ts +++ b/src/test/e2e/api/admin/api-token.e2e.test.ts @@ -289,7 +289,7 @@ test('should not create token for invalid projectId', async () => { .set('Content-Type', 'application/json') .expect(400) .expect((res) => { - expect(res.body.details[0].description).toMatch( + expect(res.body.details[0].message).toMatch( /bogus-project-something/, ); }); @@ -306,7 +306,7 @@ test('should not create token for invalid environment', async () => { .set('Content-Type', 'application/json') .expect(400) .expect((res) => { - expect(res.body.details[0].description).toMatch( + expect(res.body.details[0].message).toMatch( /bogus-environment-something/, ); }); diff --git a/src/test/e2e/api/admin/project/variants.e2e.test.ts b/src/test/e2e/api/admin/project/variants.e2e.test.ts index e37e3fa039..c35e4a19e0 100644 --- a/src/test/e2e/api/admin/project/variants.e2e.test.ts +++ b/src/test/e2e/api/admin/project/variants.e2e.test.ts @@ -519,7 +519,7 @@ test('PUTing an invalid variant throws 400 exception', async () => { .expect(400) .expect((res) => { expect(res.body.details).toHaveLength(1); - expect(res.body.details[0].description).toMatch( + expect(res.body.details[0].message).toMatch( /.*weightType` property must be equal to one of the allowed values/, ); }); @@ -555,7 +555,7 @@ test('Invalid variant in PATCH also throws 400 exception', async () => { .expect(400) .expect((res) => { expect(res.body.details).toHaveLength(1); - expect(res.body.details[0].description).toMatch( + expect(res.body.details[0].message).toMatch( /.*weight" must be less than or equal to 1000/, ); }); @@ -685,7 +685,7 @@ test('PATCHING with no variable variants fails with 400', async () => { .expect(400) .expect((res) => { expect(res.body.details).toHaveLength(1); - expect(res.body.details[0].description).toEqual( + expect(res.body.details[0].message).toEqual( 'There must be at least one "variable" variant', ); }); @@ -883,7 +883,7 @@ test('If sum of fixed variant weight exceed 1000 fails with 400', async () => { .expect(400) .expect((res) => { expect(res.body.details).toHaveLength(1); - expect(res.body.details[0].description).toEqual( + expect(res.body.details[0].message).toEqual( 'The traffic distribution total must equal 100%', ); }); @@ -998,7 +998,7 @@ test('PATCH endpoint validates uniqueness of variant names', async () => { .send(patch) .expect(400) .expect((res) => { - expect(res.body.details[0].description).toMatch( + expect(res.body.details[0].message).toMatch( /contains a duplicate value/, ); }); @@ -1035,7 +1035,7 @@ test('PUT endpoint validates uniqueness of variant names', async () => { ]) .expect(400) .expect((res) => { - expect(res.body.details[0].description).toMatch( + expect(res.body.details[0].message).toMatch( /contains a duplicate value/, ); }); diff --git a/src/test/e2e/api/admin/tags.e2e.test.ts b/src/test/e2e/api/admin/tags.e2e.test.ts index 8b1721de3c..db17cfe42e 100644 --- a/src/test/e2e/api/admin/tags.e2e.test.ts +++ b/src/test/e2e/api/admin/tags.e2e.test.ts @@ -89,7 +89,7 @@ test('Can validate a tag', async () => .expect(400) .expect((res) => { expect(res.body.details.length).toBe(1); - expect(res.body.details[0].description).toMatch( + expect(res.body.details[0].message).toMatch( '"type" must be URL friendly', ); })); diff --git a/src/test/e2e/api/admin/user-admin.e2e.test.ts b/src/test/e2e/api/admin/user-admin.e2e.test.ts index 0de7efd2ce..df670db168 100644 --- a/src/test/e2e/api/admin/user-admin.e2e.test.ts +++ b/src/test/e2e/api/admin/user-admin.e2e.test.ts @@ -155,7 +155,7 @@ test('should require username or email on create', async () => { .set('Content-Type', 'application/json') .expect(400) .expect((res) => { - expect(res.body.details[0].description).toEqual( + expect(res.body.details[0].message).toEqual( 'You must specify username or email', ); }); diff --git a/src/test/e2e/api/auth/reset-password-controller.e2e.test.ts b/src/test/e2e/api/auth/reset-password-controller.e2e.test.ts index 0e0823471a..79dcad26fd 100644 --- a/src/test/e2e/api/auth/reset-password-controller.e2e.test.ts +++ b/src/test/e2e/api/auth/reset-password-controller.e2e.test.ts @@ -188,7 +188,7 @@ test('Trying to reset password with same token twice does not work', async () => }) .expect(401) .expect((res) => { - expect(res.body.details[0].description).toBeTruthy(); + expect(res.body.details[0].message).toBeTruthy(); }); });