Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3de4512681 | ||
|
|
4bf333ed38 | ||
|
|
4f5ef7c2d7 | ||
|
|
5de03beea1 | ||
|
|
42baa422b3 | ||
|
|
6af5d24b3b | ||
|
|
b88ce2d49f | ||
|
|
c216ae1d13 | ||
|
|
319776d241 | ||
|
|
1d0718dc2f | ||
|
|
929694310e | ||
|
|
4db18aafce |
@@ -30,7 +30,7 @@ Microsoft Edge) as well as Node.
|
||||
| Environment | Supported versions |
|
||||
|-------------------|----------------------------------|
|
||||
| Node | 20, 22, 24 |
|
||||
| Safari | 16*, 17*, 26* |
|
||||
| Safari | 26* |
|
||||
| Chrome | Evergreen |
|
||||
| Firefox | Evergreen, 102*, 115*, 128*, 140 |
|
||||
| Edge | Evergreen |
|
||||
|
||||
@@ -222,7 +222,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
|
||||
* Maximum number of characters to display when pretty printing objects.
|
||||
* Characters past this number will be ellipised.
|
||||
* @name jasmine.MAX_PRETTY_PRINT_CHARS
|
||||
* @default 100
|
||||
* @default 1000
|
||||
* @since 2.9.0
|
||||
*/
|
||||
j$.MAX_PRETTY_PRINT_CHARS = 1000;
|
||||
@@ -4003,7 +4003,8 @@ getJasmineRequireObj().ExceptionFormatter = function(j$) {
|
||||
'lineNumber',
|
||||
'column',
|
||||
'description',
|
||||
'jasmineMessage'
|
||||
'jasmineMessage',
|
||||
'errors'
|
||||
];
|
||||
|
||||
function ExceptionFormatter(options) {
|
||||
@@ -4069,6 +4070,19 @@ getJasmineRequireObj().ExceptionFormatter = function(j$) {
|
||||
lines = lines.concat(substack);
|
||||
}
|
||||
|
||||
if (Array.isArray(error.errors)) {
|
||||
for (let i = 0; i < error.errors.length; i++) {
|
||||
if (error.errors[i] instanceof Error) {
|
||||
lines.push('');
|
||||
const substack = this.stack_(error.errors[i], {
|
||||
messageHandling: 'require'
|
||||
});
|
||||
substack[0] = 'Error ' + (i + 1) + ': ' + substack[0];
|
||||
lines = lines.concat(substack.map(x => ' ' + x));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return lines;
|
||||
};
|
||||
|
||||
@@ -12408,5 +12422,5 @@ getJasmineRequireObj().UserContext = function(j$) {
|
||||
};
|
||||
|
||||
getJasmineRequireObj().version = function() {
|
||||
return '6.0.1';
|
||||
return '6.1.0';
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "jasmine-core",
|
||||
"license": "MIT",
|
||||
"version": "6.0.1",
|
||||
"version": "6.1.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/jasmine/jasmine.git"
|
||||
|
||||
40
release_notes/6.1.0.md
Normal file
40
release_notes/6.1.0.md
Normal file
@@ -0,0 +1,40 @@
|
||||
# Jasmine Core 6.1.0 Release Notes
|
||||
|
||||
## Changes to supported environments
|
||||
|
||||
* Safari 16 and 17 are no longer supported. Although jasmine-core may still work
|
||||
in those versions, we no longer have a reliable way to test them and won't try
|
||||
to maintain compatibility with them in future releases.
|
||||
|
||||
## New features
|
||||
|
||||
* Report the underlying errors that make up an `AggregateError`.
|
||||
* Merges [#2093](https://github.com/jasmine/jasmine/pull/2093) from @puglyfe
|
||||
* Fixes [#2063](https://github.com/jasmine/jasmine/issues/2063)
|
||||
|
||||
## Documentation improvements
|
||||
|
||||
* Fix default MAX_PRETTY_PRINT_CHARS in JsDoc.
|
||||
* Merges [#2091](https://github.com/jasmine/jasmine/pull/2091) from @HolgerJeromin
|
||||
|
||||
## Supported environments
|
||||
|
||||
This version has been tested in the following environments.
|
||||
|
||||
| Environment | Supported versions |
|
||||
|-------------------|--------------------------------|
|
||||
| Node | 20, 22, 24 |
|
||||
| Safari | 26.3** |
|
||||
| Chrome | 144* |
|
||||
| Firefox | 102**, 115**, 128**, 140, 147* |
|
||||
| Edge | 144* |
|
||||
|
||||
\* Evergreen browser. Each version of Jasmine is tested against the latest
|
||||
version available at release time.<br>
|
||||
\** Supported on a best-effort basis. Support for these versions may be dropped
|
||||
if it becomes impractical, and bugs affecting only these versions may not be
|
||||
treated as release blockers.
|
||||
|
||||
------
|
||||
|
||||
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
|
||||
@@ -1,8 +1,8 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Run tests in supported browsers that are available on Saucelabs.
|
||||
# Note: The latest Safari version is tested via GitHub Actions because Saucelabs
|
||||
# only makes it available to paid enterprise accounts. See
|
||||
# Note: Safari is tested via GitHub Actions because Saucelabs only makes Safari
|
||||
# 18 and later available to paid enterprise accounts. See
|
||||
# .github/workflows/safari.yml.
|
||||
|
||||
run_browser() {
|
||||
@@ -44,9 +44,6 @@ else
|
||||
fi
|
||||
run_browser firefox 102
|
||||
|
||||
run_browser safari 17
|
||||
run_browser safari 16
|
||||
|
||||
run_browser MicrosoftEdge latest
|
||||
|
||||
echo
|
||||
|
||||
@@ -346,5 +346,184 @@ describe('ExceptionFormatter', function() {
|
||||
}).not.toThrowError();
|
||||
});
|
||||
});
|
||||
|
||||
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 = (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();
|
||||
}
|
||||
|
||||
// Exclude lines that vary from environment to environment
|
||||
const filteredLines = lines.filter(
|
||||
x =>
|
||||
!x.includes('/jasmine.js:') &&
|
||||
// Some Node 20 and 22 minors when running in parallel
|
||||
!x.includes('process.processTicksAndRejections')
|
||||
);
|
||||
|
||||
for (let i = 0; i < filteredLines.length; i++) {
|
||||
jasmine.debugLog(`Line ${i} after filtering: ${filteredLines[i]}`);
|
||||
}
|
||||
|
||||
// Inexact matching because stack frame formatting varies from runtime
|
||||
// to runtime
|
||||
const expectedPatterns = [
|
||||
// Overall error
|
||||
/fn3.*ExceptionFormatterSpec\.js/,
|
||||
/ExceptionFormatterSpec\.js/,
|
||||
/^$/,
|
||||
|
||||
// First nested error
|
||||
/^ Error 1: Error: first error$/,
|
||||
/^ .*fn1.*ExceptionFormatterSpec\.js/,
|
||||
/^ .*ExceptionFormatterSpec\.js/,
|
||||
/^$/,
|
||||
|
||||
// Second nested error
|
||||
/^ .*Error 2: Error: second error$/,
|
||||
/^ .*fn2.*ExceptionFormatterSpec\.js/,
|
||||
/^ .*ExceptionFormatterSpec\.js/
|
||||
];
|
||||
|
||||
expect(filteredLines).toEqual(
|
||||
expectedPatterns.map(p => jasmine.stringMatching(p))
|
||||
);
|
||||
});
|
||||
|
||||
it('handles empty errors array', function() {
|
||||
const subject = new privateUnderTest.ExceptionFormatter();
|
||||
const aggregateError = new Error('No errors');
|
||||
aggregateError.errors = [];
|
||||
|
||||
expect(function() {
|
||||
subject.stack(aggregateError);
|
||||
}).not.toThrowError();
|
||||
});
|
||||
|
||||
it('handles nested AggregateError', function() {
|
||||
const subject = new privateUnderTest.ExceptionFormatter();
|
||||
const innerError1 = new Error('inner error 1');
|
||||
const innerError2 = new Error('inner error 2');
|
||||
const innerAggregate = new Error('Inner aggregate');
|
||||
innerAggregate.errors = [innerError1, innerError2];
|
||||
|
||||
const outerError = new Error('outer error');
|
||||
const outerAggregate = new Error('Outer aggregate');
|
||||
outerAggregate.errors = [innerAggregate, outerError];
|
||||
|
||||
const lines = subject.stack(outerAggregate).split('\n');
|
||||
|
||||
const innerAggMsgIx = lines.findIndex(line =>
|
||||
line.includes('Error 1: Error: Inner aggregate')
|
||||
);
|
||||
expect(innerAggMsgIx).toBeGreaterThan(-1);
|
||||
|
||||
const innerError1MsgIx = lines.findIndex(line =>
|
||||
line.includes('Error 1: Error: inner error 1')
|
||||
);
|
||||
expect(innerError1MsgIx).toBeGreaterThan(innerAggMsgIx);
|
||||
|
||||
const innerError2MsgIx = lines.findIndex(line =>
|
||||
line.includes('Error 2: Error: inner error 2')
|
||||
);
|
||||
expect(innerError2MsgIx).toBeGreaterThan(innerError1MsgIx);
|
||||
|
||||
const outerErrorMsgIx = lines.findIndex(line =>
|
||||
line.includes('Error 2: Error: outer error')
|
||||
);
|
||||
expect(outerErrorMsgIx).toBeGreaterThan(innerError2MsgIx);
|
||||
});
|
||||
|
||||
it('handles AggregateError containing error with cause', function() {
|
||||
const subject = new privateUnderTest.ExceptionFormatter();
|
||||
const rootCause = new Error('root cause');
|
||||
const errorWithCause = new Error('error with cause', {
|
||||
cause: rootCause
|
||||
});
|
||||
const aggregateError = new Error('Aggregate with cause chain');
|
||||
aggregateError.errors = [errorWithCause];
|
||||
|
||||
const lines = subject.stack(aggregateError).split('\n');
|
||||
|
||||
const error1MsgIx = lines.findIndex(line =>
|
||||
line.includes('Error 1: Error: error with cause')
|
||||
);
|
||||
expect(error1MsgIx).toBeGreaterThan(-1);
|
||||
|
||||
const causeMsgIx = lines.findIndex(line =>
|
||||
line.includes('Caused by: Error: root cause')
|
||||
);
|
||||
expect(causeMsgIx).toBeGreaterThan(error1MsgIx);
|
||||
});
|
||||
|
||||
it('skips non-Error items in errors array', function() {
|
||||
const subject = new privateUnderTest.ExceptionFormatter();
|
||||
const error1 = new Error('real error');
|
||||
const aggregateError = new Error('Mixed array');
|
||||
aggregateError.errors = [
|
||||
error1,
|
||||
'string error',
|
||||
{ message: 'object error' },
|
||||
null,
|
||||
undefined,
|
||||
42
|
||||
];
|
||||
|
||||
const lines = subject.stack(aggregateError).split('\n');
|
||||
|
||||
const error1MsgIx = lines.findIndex(line =>
|
||||
line.includes('Error 1: Error: real error')
|
||||
);
|
||||
expect(error1MsgIx).toBeGreaterThan(-1);
|
||||
|
||||
const hasStringError = lines.some(line =>
|
||||
line.includes('string error')
|
||||
);
|
||||
expect(hasStringError).toBe(false);
|
||||
|
||||
const hasObjectError = lines.some(line =>
|
||||
line.includes('object error')
|
||||
);
|
||||
expect(hasObjectError).toBe(false);
|
||||
});
|
||||
|
||||
it('works with native AggregateError constructor', function() {
|
||||
const subject = new privateUnderTest.ExceptionFormatter();
|
||||
const error1 = new Error('first error');
|
||||
const error2 = new Error('second error');
|
||||
const aggregateError = new AggregateError(
|
||||
[error1, error2],
|
||||
'Multiple errors'
|
||||
);
|
||||
|
||||
const lines = subject.stack(aggregateError).split('\n');
|
||||
|
||||
const error1MsgIx = lines.findIndex(line =>
|
||||
line.includes('Error 1: Error: first error')
|
||||
);
|
||||
expect(error1MsgIx).toBeGreaterThan(-1);
|
||||
|
||||
const error2MsgIx = lines.findIndex(line =>
|
||||
line.includes('Error 2: Error: second error')
|
||||
);
|
||||
expect(error2MsgIx).toBeGreaterThan(error1MsgIx);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
/* eslint-env node, es6 */
|
||||
const path = require('path'),
|
||||
jasmineBrowser = require('jasmine-browser-runner'),
|
||||
jasmineCore = require('../../lib/jasmine-core');
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
/* eslint-env node, es6 */
|
||||
module.exports = {
|
||||
srcDir: 'src',
|
||||
srcFiles: [
|
||||
|
||||
@@ -11,7 +11,8 @@ getJasmineRequireObj().ExceptionFormatter = function(j$) {
|
||||
'lineNumber',
|
||||
'column',
|
||||
'description',
|
||||
'jasmineMessage'
|
||||
'jasmineMessage',
|
||||
'errors'
|
||||
];
|
||||
|
||||
function ExceptionFormatter(options) {
|
||||
@@ -77,6 +78,19 @@ getJasmineRequireObj().ExceptionFormatter = function(j$) {
|
||||
lines = lines.concat(substack);
|
||||
}
|
||||
|
||||
if (Array.isArray(error.errors)) {
|
||||
for (let i = 0; i < error.errors.length; i++) {
|
||||
if (error.errors[i] instanceof Error) {
|
||||
lines.push('');
|
||||
const substack = this.stack_(error.errors[i], {
|
||||
messageHandling: 'require'
|
||||
});
|
||||
substack[0] = 'Error ' + (i + 1) + ': ' + substack[0];
|
||||
lines = lines.concat(substack.map(x => ' ' + x));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return lines;
|
||||
};
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
|
||||
* Maximum number of characters to display when pretty printing objects.
|
||||
* Characters past this number will be ellipised.
|
||||
* @name jasmine.MAX_PRETTY_PRINT_CHARS
|
||||
* @default 100
|
||||
* @default 1000
|
||||
* @since 2.9.0
|
||||
*/
|
||||
j$.MAX_PRETTY_PRINT_CHARS = 1000;
|
||||
|
||||
Reference in New Issue
Block a user