Improve AggregateError specs
* Assert that the right inner stack traces are in the right places * Drop the integration tests. All of the AggregateError-specific code is in ExceptionFormatter, so the integration tests just duplicate existing integration tests and the ExceptionFormatter specs.
This commit is contained in:
@@ -350,48 +350,52 @@ describe('ExceptionFormatter', function() {
|
||||
describe('when the error has an errors array (AggregateError)', function() {
|
||||
it('includes all aggregated errors in the stack trace', function() {
|
||||
const subject = new privateUnderTest.ExceptionFormatter();
|
||||
const error1 = new Error('first error');
|
||||
const error2 = new Error('second error');
|
||||
const error3 = new Error('third error');
|
||||
const aggregateError = new Error('Multiple errors occurred');
|
||||
aggregateError.errors = [error1, error2, error3];
|
||||
const error1 = (function fn1() {
|
||||
return new Error('first error');
|
||||
})();
|
||||
const error2 = (function fn2() {
|
||||
return new Error('second error');
|
||||
})();
|
||||
const aggregateError = (function fn3() {
|
||||
return new Error('Multiple errors occurred');
|
||||
})();
|
||||
aggregateError.errors = [error1, error2];
|
||||
|
||||
const lines = subject.stack(aggregateError).split('\n');
|
||||
|
||||
// TODO: be consistent across environments about whether the message is
|
||||
// included in the stack trace
|
||||
if (lines[0] === 'Error: Multiple errors occurred') {
|
||||
lines.shift();
|
||||
}
|
||||
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
jasmine.debugLog(`Line ${i}: ${lines[i]}`);
|
||||
}
|
||||
|
||||
expect(lines[0])
|
||||
.withContext('first stack frame of the overall error')
|
||||
.toMatch(/fn3.*core\/ExceptionFormatterSpec\.js/);
|
||||
|
||||
const error1MsgIx = lines.findIndex(line =>
|
||||
line.includes('Error 1: Error: first error')
|
||||
);
|
||||
expect(error1MsgIx)
|
||||
.withContext('first error message')
|
||||
.withContext('first nested error message')
|
||||
.toBeGreaterThan(-1);
|
||||
expect(lines[error1MsgIx + 1])
|
||||
.withContext('first stack frame of first nested error')
|
||||
.toMatch(/fn1.*core\/ExceptionFormatterSpec\.js/);
|
||||
|
||||
const error2MsgIx = lines.findIndex(line =>
|
||||
line.includes('Error 2: Error: second error')
|
||||
);
|
||||
expect(error2MsgIx)
|
||||
.withContext('second error message')
|
||||
.withContext('second nested error message')
|
||||
.toBeGreaterThan(error1MsgIx);
|
||||
|
||||
const error3MsgIx = lines.findIndex(line =>
|
||||
line.includes('Error 3: Error: third error')
|
||||
);
|
||||
expect(error3MsgIx)
|
||||
.withContext('third error message')
|
||||
.toBeGreaterThan(error2MsgIx);
|
||||
});
|
||||
|
||||
it('handles AggregateError with single error', function() {
|
||||
const subject = new privateUnderTest.ExceptionFormatter();
|
||||
const error1 = new Error('single error');
|
||||
const aggregateError = new Error('One error occurred');
|
||||
aggregateError.errors = [error1];
|
||||
|
||||
const lines = subject.stack(aggregateError).split('\n');
|
||||
|
||||
const error1MsgIx = lines.findIndex(line =>
|
||||
line.includes('Error 1: Error: single error')
|
||||
);
|
||||
expect(error1MsgIx).toBeGreaterThan(-1);
|
||||
expect(lines[error2MsgIx + 1])
|
||||
.withContext('first stack frame of second nested error')
|
||||
.toMatch(/fn2.*core\/ExceptionFormatterSpec\.js/);
|
||||
});
|
||||
|
||||
it('handles empty errors array', function() {
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
describe('Exception formatting (integration)', function() {
|
||||
let env;
|
||||
|
||||
beforeEach(function() {
|
||||
specHelpers.registerIntegrationMatchers();
|
||||
env = new privateUnderTest.Env();
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
env.cleanup_();
|
||||
});
|
||||
|
||||
describe('AggregateError formatting', function() {
|
||||
it('formats AggregateError with individual errors', async function() {
|
||||
env.it('should format AggregateError with individual errors', function() {
|
||||
const errors = [
|
||||
new Error('Database connection failed'),
|
||||
new Error('Invalid configuration'),
|
||||
new Error('Service unavailable')
|
||||
];
|
||||
throw new AggregateError(errors, 'Multiple initialization errors');
|
||||
});
|
||||
|
||||
const reporter = jasmine.createSpyObj('reporter', ['specDone']);
|
||||
env.addReporter(reporter);
|
||||
await env.execute();
|
||||
|
||||
expect(reporter.specDone).toHaveBeenCalledTimes(1);
|
||||
const result = reporter.specDone.calls.argsFor(0)[0];
|
||||
expect(result.status).toEqual('failed');
|
||||
expect(result.failedExpectations.length).toEqual(1);
|
||||
|
||||
const failure = result.failedExpectations[0];
|
||||
expect(failure.message).toContain('AggregateError');
|
||||
expect(failure.message).toContain('Multiple initialization errors');
|
||||
|
||||
expect(failure.stack).toContain(
|
||||
'Error 1: Error: Database connection failed'
|
||||
);
|
||||
expect(failure.stack).toContain('Error 2: Error: Invalid configuration');
|
||||
expect(failure.stack).toContain('Error 3: Error: Service unavailable');
|
||||
});
|
||||
|
||||
it('formats nested AggregateError', async function() {
|
||||
env.it('should format nested AggregateError', function() {
|
||||
const innerErrors = [
|
||||
new Error('Inner error 1'),
|
||||
new Error('Inner error 2')
|
||||
];
|
||||
const innerAggregate = new AggregateError(
|
||||
innerErrors,
|
||||
'Inner operation failed'
|
||||
);
|
||||
|
||||
const outerErrors = [
|
||||
innerAggregate,
|
||||
new Error('Outer error'),
|
||||
new Error('Other outer error')
|
||||
];
|
||||
throw new AggregateError(outerErrors, 'Multiple operations failed');
|
||||
});
|
||||
|
||||
const reporter = jasmine.createSpyObj('reporter', ['specDone']);
|
||||
env.addReporter(reporter);
|
||||
await env.execute();
|
||||
|
||||
expect(reporter.specDone).toHaveBeenCalledTimes(1);
|
||||
const result = reporter.specDone.calls.argsFor(0)[0];
|
||||
expect(result.status).toEqual('failed');
|
||||
|
||||
const failure = result.failedExpectations[0];
|
||||
|
||||
// Firefox & Safari don't preserve types for nested errors
|
||||
expect(failure.stack).toMatch(
|
||||
/Error 1: (AggregateError|Error): Inner operation failed/
|
||||
);
|
||||
expect(failure.stack).toContain('Error 2: Error: Outer error');
|
||||
expect(failure.stack).toContain('Error 3: Error: Other outer error');
|
||||
|
||||
expect(failure.stack).toContain('Error 1: Error: Inner error 1');
|
||||
expect(failure.stack).toContain('Error 2: Error: Inner error 2');
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user