Add object property validation in parser #369
This commit introduces stricter type validation across the application to reject objects with unexpected properties, enhancing the robustness and predictability of data handling. Changes include: - Implement a common utility to validate object types. - Refactor across various parsers and data handlers to utilize the new validations. - Update error messages for better clarity and troubleshooting.
This commit is contained in:
121
tests/unit/application/Parser/Common/ContextualError.spec.ts
Normal file
121
tests/unit/application/Parser/Common/ContextualError.spec.ts
Normal file
@@ -0,0 +1,121 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { CustomError } from '@/application/Common/CustomError';
|
||||
import { wrapErrorWithAdditionalContext } from '@/application/Parser/Common/ContextualError';
|
||||
|
||||
describe('wrapErrorWithAdditionalContext', () => {
|
||||
it('preserves the original error when wrapped', () => {
|
||||
// arrange
|
||||
const expectedError = new Error();
|
||||
const context = new TestContext()
|
||||
.withError(expectedError);
|
||||
// act
|
||||
const error = context.wrap();
|
||||
// assert
|
||||
const actualError = extractInnerErrorFromContextualError(error);
|
||||
expect(actualError).to.equal(expectedError);
|
||||
});
|
||||
it('maintains the original error when re-wrapped', () => {
|
||||
// arrange
|
||||
const expectedError = new Error();
|
||||
|
||||
// act
|
||||
const firstError = new TestContext()
|
||||
.withError(expectedError)
|
||||
.withAdditionalContext('first error')
|
||||
.wrap();
|
||||
const secondError = new TestContext()
|
||||
.withError(firstError)
|
||||
.withAdditionalContext('second error')
|
||||
.wrap();
|
||||
|
||||
// assert
|
||||
const actualError = extractInnerErrorFromContextualError(secondError);
|
||||
expect(actualError).to.equal(expectedError);
|
||||
});
|
||||
it(`the object extends ${CustomError.name}`, () => {
|
||||
// arrange
|
||||
const expected = CustomError;
|
||||
// act
|
||||
const error = new TestContext()
|
||||
.wrap();
|
||||
// assert
|
||||
expect(error).to.be.an.instanceof(expected);
|
||||
});
|
||||
describe('error message construction', () => {
|
||||
it('includes the message from the original error', () => {
|
||||
// arrange
|
||||
const expectedOriginalErrorMessage = 'Message from the inner error';
|
||||
|
||||
// act
|
||||
const error = new TestContext()
|
||||
.withError(new Error(expectedOriginalErrorMessage))
|
||||
.wrap();
|
||||
|
||||
// assert
|
||||
expect(error.message).contains(expectedOriginalErrorMessage);
|
||||
});
|
||||
it('appends provided additional context to the error message', () => {
|
||||
// arrange
|
||||
const expectedAdditionalContext = 'Expected additional context message';
|
||||
|
||||
// act
|
||||
const error = new TestContext()
|
||||
.withAdditionalContext(expectedAdditionalContext)
|
||||
.wrap();
|
||||
|
||||
// assert
|
||||
expect(error.message).contains(expectedAdditionalContext);
|
||||
});
|
||||
it('appends multiple contexts to the error message in sequential order', () => {
|
||||
// arrange
|
||||
const expectedFirstContext = 'First context';
|
||||
const expectedSecondContext = 'Second context';
|
||||
|
||||
// act
|
||||
const firstError = new TestContext()
|
||||
.withAdditionalContext(expectedFirstContext)
|
||||
.wrap();
|
||||
const secondError = new TestContext()
|
||||
.withError(firstError)
|
||||
.withAdditionalContext(expectedSecondContext)
|
||||
.wrap();
|
||||
|
||||
// assert
|
||||
const messageLines = secondError.message.split('\n');
|
||||
expect(messageLines).to.contain(`1: ${expectedFirstContext}`);
|
||||
expect(messageLines).to.contain(`2: ${expectedSecondContext}`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
class TestContext {
|
||||
private error: Error = new Error();
|
||||
|
||||
private additionalContext = `[${TestContext.name}] additional context`;
|
||||
|
||||
public withError(error: Error) {
|
||||
this.error = error;
|
||||
return this;
|
||||
}
|
||||
|
||||
public withAdditionalContext(additionalContext: string) {
|
||||
this.additionalContext = additionalContext;
|
||||
return this;
|
||||
}
|
||||
|
||||
public wrap(): ReturnType<typeof wrapErrorWithAdditionalContext> {
|
||||
return wrapErrorWithAdditionalContext(
|
||||
this.error,
|
||||
this.additionalContext,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function extractInnerErrorFromContextualError(error: Error): Error {
|
||||
const innerErrorProperty = 'innerError';
|
||||
if (!(innerErrorProperty in error)) {
|
||||
throw new Error(`${innerErrorProperty} property is missing`);
|
||||
}
|
||||
const actualError = error[innerErrorProperty];
|
||||
return actualError as Error;
|
||||
}
|
||||
Reference in New Issue
Block a user