Merge branch '5.99' into 6.0

This commit is contained in:
Steve Gravrock
2025-11-03 17:22:11 -08:00
23 changed files with 508 additions and 51 deletions

View File

@@ -1,5 +1,5 @@
# Run tests against supported Node versions, and (except for pull requests)
# against supported browsers.
# against supported browsers that are available on Saucelabs.
version: 2.1
@@ -89,7 +89,7 @@ jobs:
export SAUCE_TUNNEL_NAME=$CIRCLE_WORKFLOW_JOB_ID
scripts/start-sauce-connect
set +o errexit
scripts/run-all-browsers
scripts/run-sauce-browsers
exitcode=$?
set -o errexit
scripts/stop-sauce-connect

21
.github/workflows/safari.yml vendored Normal file
View File

@@ -0,0 +1,21 @@
name: Test in latest available Safari
on:
push:
pull_request:
jobs:
build:
runs-on: macos-latest
steps:
- name: Report Safari version
run: osascript -e 'get version of application "Safari"'
- uses: actions/checkout@v4
- name: Use Node.js 22.x
uses: actions/setup-node@v4
with:
node-version: 22.x
- run: npm install
- run: npm run build
- run: JASMINE_BROWSER=safari npm run ci

View File

@@ -30,7 +30,7 @@ Microsoft Edge) as well as Node.
| Environment | Supported versions |
|-------------------|----------------------------------|
| Node | 20, 22, 24 |
| Safari | 16*, 17* |
| Safari | 16*, 17*, 26* |
| Chrome | Evergreen |
| Firefox | Evergreen, 102*, 115*, 128*, 140 |
| Edge | Evergreen |

View File

@@ -28,9 +28,18 @@ should also rev to that version.
When ready to release - specs are all green and the stories are done:
1. Update the release notes in `release_notes` - use the Anchorman gem to generate the markdown file and edit accordingly. Include a list of supported environments.
1. Update the version in `package.json`
1. Run `npm run build`.
1. Update the release notes in `release_notes` - use the Anchorman gem to
generate the Markdown file and edit accordingly. Include a list of supported
environments. Get that information from these places:
* For Node, see .circleci/config.yml or the README.
* For Firefox ESR and Safari <=17, see scripts/run-sauce-browsers or the README.
* For evergreen browsers, trigger a Circle CI run and check the
[Saucelabs dashboard](https://app.saucelabs.com/dashboard/tests?ownerId=90a771d55857492da3bd5251a2d92457&ownerType=user&ownerName=jasmine-js&start=last7days)
once it's finished.
* For Safari >17, trigger the [Safari action](https://github.com/jasmine/jasmine/actions/workflows/safari.yml)
and get the version from the output.
2. Update the version in `package.json`
3. Run `npm run build`.
### Commit and push core changes

View File

@@ -50,6 +50,7 @@ var getJasmineRequireObj = (function() {
j$.private.util = jRequire.util(j$);
j$.private.errors = jRequire.errors();
j$.private.formatErrorMsg = jRequire.formatErrorMsg(j$);
j$.private.AllOf = jRequire.AllOf(j$);
j$.private.Any = jRequire.Any(j$);
j$.private.Anything = jRequire.Anything(j$);
j$.private.CallTracker = jRequire.CallTracker(j$);
@@ -407,6 +408,19 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
);
};
/**
* Get an {@link AsymmetricEqualityTester} that will succeed if the actual
* value being compared matches every provided equality tester.
* @name asymmetricEqualityTesters.allOf
* @emittedName jasmine.allOf
* @since 5.13.0
* @function
* @param {...*} arguments - The asymmetric equality checkers to compare.
*/
j$.allOf = function() {
return new j$.AllOf(...arguments);
};
/**
* Get an {@link AsymmetricEqualityTester} that will succeed if the actual
* value being compared is an instance of the specified class/constructor.
@@ -933,12 +947,11 @@ getJasmineRequireObj().Spec = function(j$) {
* @property {String} description - The description passed to the {@link it} that created this spec.
* @property {String} fullName - The full description including all ancestors of this spec.
* @property {String|null} parentSuiteId - The ID of the suite containing this spec, or null if this spec is not in a describe().
* @property {String} filename - Deprecated. The name of the file the spec was defined in.
* @property {String} filename - The name of the file the spec was defined in.
* Note: The value may be incorrect if zone.js is installed or
* `it`/`fit`/`xit` have been replaced with versions that don't maintain the
* same call stack height as the originals. This property may be removed in
* a future version unless there is enough user interest in keeping it.
* See {@link https://github.com/jasmine/jasmine/issues/2065}.
* same call stack height as the originals. You can fix that by setting
* {@link Configuration#extraItStackFrames}.
* @property {ExpectationResult[]} failedExpectations - The list of expectations that failed during execution of this spec.
* @property {ExpectationResult[]} passedExpectations - The list of expectations that passed during execution of this spec.
* @property {ExpectationResult[]} deprecationWarnings - The list of deprecation warnings that occurred during execution this spec.
@@ -1120,7 +1133,20 @@ getJasmineRequireObj().Spec = function(j$) {
* @returns {Array.<string>}
* @since 5.7.0
*/
getPath: this.getPath.bind(this)
getPath: this.getPath.bind(this),
/**
* The name of the file the spec was defined in.
* Note: The value may be incorrect if zone.js is installed or
* `it`/`fit`/`xit` have been replaced with versions that don't maintain the
* same call stack height as the originals. You can fix that by setting
* {@link Configuration#extraItStackFrames}.
* @name Spec#filename
* @readonly
* @type {string}
* @since 5.13.0
*/
filename: this.filename
};
}
@@ -1199,6 +1225,8 @@ getJasmineRequireObj().Order = function() {
getJasmineRequireObj().Env = function(j$) {
'use strict';
const DEFAULT_IT_DESCRIBE_STACK_DEPTH = 3;
/**
* @class Env
* @since 2.0.0
@@ -1789,14 +1817,14 @@ getJasmineRequireObj().Env = function(j$) {
this.describe = function(description, definitionFn) {
ensureIsNotNested('describe');
const filename = callerCallerFilename();
const filename = indirectCallerFilename(describeStackDepth());
return suiteBuilder.describe(description, definitionFn, filename)
.metadata;
};
this.xdescribe = function(description, definitionFn) {
ensureIsNotNested('xdescribe');
const filename = callerCallerFilename();
const filename = indirectCallerFilename(describeStackDepth());
return suiteBuilder.xdescribe(description, definitionFn, filename)
.metadata;
};
@@ -1804,30 +1832,38 @@ getJasmineRequireObj().Env = function(j$) {
this.fdescribe = function(description, definitionFn) {
ensureIsNotNested('fdescribe');
ensureNonParallel('fdescribe');
const filename = callerCallerFilename();
const filename = indirectCallerFilename(describeStackDepth());
return suiteBuilder.fdescribe(description, definitionFn, filename)
.metadata;
};
this.it = function(description, fn, timeout) {
ensureIsNotNested('it');
const filename = callerCallerFilename();
const filename = indirectCallerFilename(itStackDepth());
return suiteBuilder.it(description, fn, timeout, filename).metadata;
};
this.xit = function(description, fn, timeout) {
ensureIsNotNested('xit');
const filename = callerCallerFilename();
const filename = indirectCallerFilename(itStackDepth());
return suiteBuilder.xit(description, fn, timeout, filename).metadata;
};
this.fit = function(description, fn, timeout) {
ensureIsNotNested('fit');
ensureNonParallel('fit');
const filename = callerCallerFilename();
const filename = indirectCallerFilename(itStackDepth());
return suiteBuilder.fit(description, fn, timeout, filename).metadata;
};
function itStackDepth() {
return DEFAULT_IT_DESCRIBE_STACK_DEPTH + config.extraItStackFrames;
}
function describeStackDepth() {
return DEFAULT_IT_DESCRIBE_STACK_DEPTH + config.extraDescribeStackFrames;
}
/**
* Get a user-defined property as part of the properties field of {@link SpecDoneEvent}
* @name Env#getSpecProperty
@@ -2013,11 +2049,12 @@ getJasmineRequireObj().Env = function(j$) {
};
}
function callerCallerFilename() {
function indirectCallerFilename(depth) {
const frames = new j$.private.StackTrace(new Error()).frames;
// frames[3] should always exist except in Jasmine's own tests, which bypass
// the global it/describe layer, but don't crash if it doesn't.
return frames[3] && frames[3].file;
// The specified frame should always exist except in Jasmine's own tests,
// which bypass the global it/describe layer, but could be absent in case
// of misconfiguration. Don't crash if it's absent.
return frames[depth] && frames[depth].file;
}
return Env;
@@ -2155,6 +2192,34 @@ getJasmineRequireObj().JsApiReporter = function(j$) {
return JsApiReporter;
};
getJasmineRequireObj().AllOf = function(j$) {
function AllOf() {
const expectedValues = Array.from(arguments);
if (expectedValues.length === 0) {
throw new TypeError(
'jasmine.allOf() expects at least one argument to be passed.'
);
}
this.expectedValues = expectedValues;
}
AllOf.prototype.asymmetricMatch = function(other, matchersUtil) {
for (const expectedValue of this.expectedValues) {
if (!matchersUtil.equals(other, expectedValue)) {
return false;
}
}
return true;
};
AllOf.prototype.jasmineToString = function(pp) {
return '<jasmine.allOf(' + pp(this.expectedValues) + ')>';
};
return AllOf;
};
getJasmineRequireObj().Any = function(j$) {
'use strict';
@@ -3510,7 +3575,30 @@ getJasmineRequireObj().Configuration = function(j$) {
* @type Boolean
* @default false
*/
detectLateRejectionHandling: false
detectLateRejectionHandling: false,
/**
* The number of extra stack frames inserted by a wrapper around {@link it}
* or by some other local modification. Jasmine uses this to determine the
* filename for {@link SpecStartedEvent} and {@link SpecDoneEvent}.
* @name Configuration#extraItStackFrames
* @since 5.13.0
* @type number
* @default 0
*/
extraItStackFrames: 0,
/**
* The number of extra stack frames inserted by a wrapper around
* {@link describe} or by some other local modification. Jasmine uses this
* to determine the filename for {@link SpecStartedEvent} and
* {@link SpecDoneEvent}.
* @name Configuration#extraDescribeStackFrames
* @since 5.13.0
* @type number
* @default 0
*/
extraDescribeStackFrames: 0
};
Object.freeze(defaultConfig);
@@ -3561,6 +3649,16 @@ getJasmineRequireObj().Configuration = function(j$) {
if (typeof changes.seed !== 'undefined') {
this.#values.seed = changes.seed;
}
// 0 is a valid value for both of these, so a truthiness check wouldn't work
if (typeof changes.extraItStackFrames !== 'undefined') {
this.#values.extraItStackFrames = changes.extraItStackFrames;
}
if (typeof changes.extraDescribeStackFrames !== 'undefined') {
this.#values.extraDescribeStackFrames =
changes.extraDescribeStackFrames;
}
}
}
@@ -10968,12 +11066,11 @@ getJasmineRequireObj().Suite = function(j$) {
* @property {String} description - The description text passed to the {@link describe} that made this suite.
* @property {String} fullName - The full description including all ancestors of this suite.
* @property {String|null} parentSuiteId - The ID of the suite containing this suite, or null if this is not in another describe().
* @property {String} filename - Deprecated. The name of the file the suite was defined in.
* @property {String} filename - The name of the file the suite was defined in.
* Note: The value may be incorrect if zone.js is installed or
* `describe`/`fdescribe`/`xdescribe` have been replaced with versions that
* don't maintain the same call stack height as the originals. This property
* may be removed in a future version unless there is enough user interest
* in keeping it. See {@link https://github.com/jasmine/jasmine/issues/2065}.
* don't maintain the same call stack height as the originals. You can fix
* that by setting {@link Configuration#extraDescribeStackFrames}.
* @property {ExpectationResult[]} failedExpectations - The list of expectations that failed in an {@link afterAll} for this suite.
* @property {ExpectationResult[]} deprecationWarnings - The list of deprecation warnings that occurred on this suite.
* @property {String} status - Once the suite has completed, this string represents the pass/fail status of this suite.
@@ -11181,6 +11278,19 @@ getJasmineRequireObj().Suite = function(j$) {
* @since 2.0.0
*/
this.description = suite.description;
/**
* The name of the file the suite was defined in.
* Note: The value may be incorrect if zone.js is installed or
* `describe`/`fdescribe`/`xdescribe` have been replaced with versions
* that don't maintain the same call stack height as the originals. You
* can fix that by setting {@link Configuration#extraItStackFrames}.
* @name Suite#filename
* @readonly
* @type {string}
* @since 5.13.0
*/
this.filename = suite.filename;
}
/**
@@ -11860,7 +11970,10 @@ getJasmineRequireObj().TreeRunner = function(j$) {
_executeSpec(spec, specOverallDone) {
const onStart = next => {
this.#currentRunableTracker.setCurrentSpec(spec);
this.#runableResources.initForRunable(spec.id, spec.parentSuiteId);
this.#runableResources.initForRunable(
spec.id,
spec.parentSuiteId || this.#executionTree.topSuite.id
);
this.#reportDispatcher.specStarted(spec.startedEvent()).then(next);
};
const resultCallback = (result, next) => {

29
release_notes/5.12.1.md Normal file
View File

@@ -0,0 +1,29 @@
Jasmine Core 5.12.1 Release Notes
## Bug fixes
* Fix custom matchers in top-level specs
* Merges [#2088](https://github.com/jasmine/jasmine/pull/2088) from @bonkevin
## Supported environments
This version has been tested in the following environments.
| Environment | Supported versions |
|-------------|--------------------------------|
| Node | 18.20.5**, 20, 22, 24 |
| Safari | 16**, 17** |
| Chrome | 141* |
| Firefox | 102**, 115**, 128**, 140, 144* |
| Edge | 141* |
\* 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)_

View File

@@ -1,5 +1,10 @@
#!/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
# .github/workflows/safari.yml.
run_browser() {
browser=$1
version=$2

View File

@@ -10,7 +10,13 @@ describe('Configuration', function() {
'detectLateRejectionHandling',
'verboseDeprecations'
];
const allKeys = [...standardBooleanKeys, 'seed', 'specFilter'];
const allKeys = [
...standardBooleanKeys,
'seed',
'specFilter',
'extraItStackFrames',
'extraDescribeStackFrames'
];
Object.freeze(standardBooleanKeys);
Object.freeze(allKeys);
@@ -28,6 +34,8 @@ describe('Configuration', function() {
expect(subject.forbidDuplicateNames).toEqual(true);
expect(subject.verboseDeprecations).toEqual(false);
expect(subject.detectLateRejectionHandling).toEqual(false);
expect(subject.extraItStackFrames).toEqual(0);
expect(subject.extraDescribeStackFrames).toEqual(0);
});
describe('copy()', function() {
@@ -109,5 +117,25 @@ describe('Configuration', function() {
subject.update({ seed: null });
expect(subject.seed).toBeNull();
});
it('sets extraItStackFrames when not undefined', function() {
const subject = new privateUnderTest.Configuration();
subject.update({ extraItStackFrames: undefined });
expect(subject.extraItStackFrames).toEqual(0);
subject.update({ extraItStackFrames: 100000 });
expect(subject.extraItStackFrames).toEqual(100000);
});
it('sets extraDescribeStackFrames when not undefined', function() {
const subject = new privateUnderTest.Configuration();
subject.update({ extraDescribeStackFrames: undefined });
expect(subject.extraDescribeStackFrames).toEqual(0);
subject.update({ extraDescribeStackFrames: 100000 });
expect(subject.extraDescribeStackFrames).toEqual(100000);
});
});
});

View File

@@ -1,4 +1,3 @@
// TODO: Fix these unit tests!
describe('Env', function() {
let env;
beforeEach(function() {
@@ -95,7 +94,7 @@ describe('Env', function() {
});
});
it('accepts its own current configureation', function() {
it('accepts its own current configuration', function() {
env.configure(env.configuration());
});
@@ -198,6 +197,29 @@ describe('Env', function() {
expect(innerSuite.parentSuite).toBe(suite);
expect(spec.getFullName()).toEqual('outer suite inner suite a spec');
});
it('sets the caller filename correctly when extraDescribeStackFrames is not set', function() {
// IIFE is used to match the stack depth when global describe() is called
const suite = (function() {
return env[methodName]('a suite', function() {
env.it('a spec');
});
})();
expect(suite.filename).toMatch(/EnvSpec\.js$/);
});
it('sets the caller filename correctly when extraDescribeStackFrames is set', function() {
env.configure({ extraDescribeStackFrames: 2 });
// IIFE is used to match the stack depth when global describe() is called
const suite = (function() {
return specHelpers.callerFilenameShim(function() {
return env[methodName]('a suite', function() {
env.it('a spec');
});
});
})();
expect(suite.filename).toMatch(/EnvSpec\.js$/);
});
}
describe('#describe', function() {
@@ -300,6 +322,25 @@ describe('Env', function() {
.not.toEqual('');
expect(spec.pend).toBeFalsy();
});
it('sets the caller filename correctly when extraItStackFrames is not set', function() {
// IIFE is used to match the stack depth when global it() is called
const spec = (function() {
return env[methodName]('a spec', function() {});
})();
expect(spec.filename).toMatch(/EnvSpec\.js$/);
});
it('sets the caller filename correctly when extraItStackFrames is set', function() {
env.configure({ extraItStackFrames: 2 });
// IIFE is used to match the stack depth when global it() is called
const spec = (function() {
return specHelpers.callerFilenameShim(function() {
return env[methodName]('a spec', function() {});
});
})();
expect(spec.filename).toMatch(/EnvSpec\.js$/);
});
}
describe('#it', function() {

View File

@@ -0,0 +1,63 @@
describe('AllOf', function() {
it('matches a single value', function() {
const matchersUtil = new privateUnderTest.MatchersUtil();
const allOf = new privateUnderTest.AllOf('foo');
expect(allOf.asymmetricMatch('foo', matchersUtil)).toBeTrue();
});
it('matches a single matcher', function() {
const matchersUtil = new privateUnderTest.MatchersUtil();
const allOf = new privateUnderTest.AllOf(
new privateUnderTest.StringContaining('oo')
);
expect(allOf.asymmetricMatch('foo', matchersUtil)).toBeTrue();
});
it('matches multiple matchers', function() {
const matchersUtil = new privateUnderTest.MatchersUtil();
const allOf = new privateUnderTest.AllOf(
new privateUnderTest.StringContaining('o'),
new privateUnderTest.StringContaining('f')
);
expect(allOf.asymmetricMatch('foo', matchersUtil)).toBeTrue();
});
it('does not match when value does not match', function() {
const matchersUtil = new privateUnderTest.MatchersUtil();
const allOf = new privateUnderTest.AllOf('bar');
expect(allOf.asymmetricMatch('foo', matchersUtil)).toBeFalse();
});
it('does not match when any matchers fail', function() {
const matchersUtil = new privateUnderTest.MatchersUtil();
const allOf = new privateUnderTest.AllOf(
new privateUnderTest.StringContaining('o'),
new privateUnderTest.StringContaining('x')
);
expect(allOf.asymmetricMatch('foo', matchersUtil)).toBeFalse();
});
it('jasmineToStrings itself', function() {
const matcher = new privateUnderTest.AllOf('o');
const pp = jasmine.createSpy('pp').and.returnValue('sample');
expect(matcher.jasmineToString(pp)).toEqual('<jasmine.allOf(sample)>');
expect(pp).toHaveBeenCalledWith(['o']);
});
describe('when called without an argument', function() {
it('tells the user to pass a constructor argument', function() {
expect(function() {
new privateUnderTest.AllOf();
}).toThrowError(
TypeError,
'jasmine.allOf() expects at least one argument to be passed.'
);
});
});
});

View File

@@ -2278,6 +2278,34 @@ describe('Env integration', function() {
await env.execute();
});
it('Custom matchers set in top-level beforeAll should be available to all specs and suites', async function() {
const matchers = {
toFoo: function() {}
};
env.beforeAll(function() {
env.addMatchers(matchers);
});
env.describe('suite - top-level', function() {
env.it('has access to the custom matcher', function() {
expect(env.expect().toFoo).toBeDefined();
});
env.describe('suite - nested', function() {
env.it('has access to the custom matcher', function() {
expect(env.expect().toFoo).toBeDefined();
});
});
});
env.it('spec - top-level - has access to the custom matcher', function() {
expect(env.expect().toFoo).toBeDefined();
});
await env.execute();
});
it('throws an exception if you try to create a spy outside of a runnable', async function() {
const obj = { fn: function() {} };
let exception;

View File

@@ -30,6 +30,7 @@ describe('The jasmine namespace', function() {
'version',
// Asymmetric equality testers
'allOf',
'any',
'anything',
'arrayContaining',

View File

@@ -0,0 +1,5 @@
(function() {
specHelpers.callerFilenameShim = function(fn) {
return fn();
};
})();

View File

@@ -23,6 +23,7 @@ module.exports = {
'helpers/BrowserFlags.js',
'helpers/domHelpers.js',
'helpers/integrationMatchers.js',
'helpers/callerFilenameShim.js',
'helpers/defineJasmineUnderTest.js',
'helpers/resetEnv.js'
],

View File

@@ -8,6 +8,7 @@
"helpers/init.js",
"helpers/domHelpers.js",
"helpers/integrationMatchers.js",
"helpers/callerFilenameShim.js",
"helpers/overrideConsoleLogForCircleCi.js",
"helpers/nodeDefineJasmineUnderTest.js",
"helpers/resetEnv.js"

View File

@@ -128,7 +128,30 @@ getJasmineRequireObj().Configuration = function(j$) {
* @type Boolean
* @default false
*/
detectLateRejectionHandling: false
detectLateRejectionHandling: false,
/**
* The number of extra stack frames inserted by a wrapper around {@link it}
* or by some other local modification. Jasmine uses this to determine the
* filename for {@link SpecStartedEvent} and {@link SpecDoneEvent}.
* @name Configuration#extraItStackFrames
* @since 5.13.0
* @type number
* @default 0
*/
extraItStackFrames: 0,
/**
* The number of extra stack frames inserted by a wrapper around
* {@link describe} or by some other local modification. Jasmine uses this
* to determine the filename for {@link SpecStartedEvent} and
* {@link SpecDoneEvent}.
* @name Configuration#extraDescribeStackFrames
* @since 5.13.0
* @type number
* @default 0
*/
extraDescribeStackFrames: 0
};
Object.freeze(defaultConfig);
@@ -179,6 +202,16 @@ getJasmineRequireObj().Configuration = function(j$) {
if (typeof changes.seed !== 'undefined') {
this.#values.seed = changes.seed;
}
// 0 is a valid value for both of these, so a truthiness check wouldn't work
if (typeof changes.extraItStackFrames !== 'undefined') {
this.#values.extraItStackFrames = changes.extraItStackFrames;
}
if (typeof changes.extraDescribeStackFrames !== 'undefined') {
this.#values.extraDescribeStackFrames =
changes.extraDescribeStackFrames;
}
}
}

View File

@@ -1,6 +1,8 @@
getJasmineRequireObj().Env = function(j$) {
'use strict';
const DEFAULT_IT_DESCRIBE_STACK_DEPTH = 3;
/**
* @class Env
* @since 2.0.0
@@ -591,14 +593,14 @@ getJasmineRequireObj().Env = function(j$) {
this.describe = function(description, definitionFn) {
ensureIsNotNested('describe');
const filename = callerCallerFilename();
const filename = indirectCallerFilename(describeStackDepth());
return suiteBuilder.describe(description, definitionFn, filename)
.metadata;
};
this.xdescribe = function(description, definitionFn) {
ensureIsNotNested('xdescribe');
const filename = callerCallerFilename();
const filename = indirectCallerFilename(describeStackDepth());
return suiteBuilder.xdescribe(description, definitionFn, filename)
.metadata;
};
@@ -606,30 +608,38 @@ getJasmineRequireObj().Env = function(j$) {
this.fdescribe = function(description, definitionFn) {
ensureIsNotNested('fdescribe');
ensureNonParallel('fdescribe');
const filename = callerCallerFilename();
const filename = indirectCallerFilename(describeStackDepth());
return suiteBuilder.fdescribe(description, definitionFn, filename)
.metadata;
};
this.it = function(description, fn, timeout) {
ensureIsNotNested('it');
const filename = callerCallerFilename();
const filename = indirectCallerFilename(itStackDepth());
return suiteBuilder.it(description, fn, timeout, filename).metadata;
};
this.xit = function(description, fn, timeout) {
ensureIsNotNested('xit');
const filename = callerCallerFilename();
const filename = indirectCallerFilename(itStackDepth());
return suiteBuilder.xit(description, fn, timeout, filename).metadata;
};
this.fit = function(description, fn, timeout) {
ensureIsNotNested('fit');
ensureNonParallel('fit');
const filename = callerCallerFilename();
const filename = indirectCallerFilename(itStackDepth());
return suiteBuilder.fit(description, fn, timeout, filename).metadata;
};
function itStackDepth() {
return DEFAULT_IT_DESCRIBE_STACK_DEPTH + config.extraItStackFrames;
}
function describeStackDepth() {
return DEFAULT_IT_DESCRIBE_STACK_DEPTH + config.extraDescribeStackFrames;
}
/**
* Get a user-defined property as part of the properties field of {@link SpecDoneEvent}
* @name Env#getSpecProperty
@@ -815,11 +825,12 @@ getJasmineRequireObj().Env = function(j$) {
};
}
function callerCallerFilename() {
function indirectCallerFilename(depth) {
const frames = new j$.private.StackTrace(new Error()).frames;
// frames[3] should always exist except in Jasmine's own tests, which bypass
// the global it/describe layer, but don't crash if it doesn't.
return frames[3] && frames[3].file;
// The specified frame should always exist except in Jasmine's own tests,
// which bypass the global it/describe layer, but could be absent in case
// of misconfiguration. Don't crash if it's absent.
return frames[depth] && frames[depth].file;
}
return Env;

View File

@@ -156,12 +156,11 @@ getJasmineRequireObj().Spec = function(j$) {
* @property {String} description - The description passed to the {@link it} that created this spec.
* @property {String} fullName - The full description including all ancestors of this spec.
* @property {String|null} parentSuiteId - The ID of the suite containing this spec, or null if this spec is not in a describe().
* @property {String} filename - Deprecated. The name of the file the spec was defined in.
* @property {String} filename - The name of the file the spec was defined in.
* Note: The value may be incorrect if zone.js is installed or
* `it`/`fit`/`xit` have been replaced with versions that don't maintain the
* same call stack height as the originals. This property may be removed in
* a future version unless there is enough user interest in keeping it.
* See {@link https://github.com/jasmine/jasmine/issues/2065}.
* same call stack height as the originals. You can fix that by setting
* {@link Configuration#extraItStackFrames}.
* @property {ExpectationResult[]} failedExpectations - The list of expectations that failed during execution of this spec.
* @property {ExpectationResult[]} passedExpectations - The list of expectations that passed during execution of this spec.
* @property {ExpectationResult[]} deprecationWarnings - The list of deprecation warnings that occurred during execution this spec.
@@ -343,7 +342,20 @@ getJasmineRequireObj().Spec = function(j$) {
* @returns {Array.<string>}
* @since 5.7.0
*/
getPath: this.getPath.bind(this)
getPath: this.getPath.bind(this),
/**
* The name of the file the spec was defined in.
* Note: The value may be incorrect if zone.js is installed or
* `it`/`fit`/`xit` have been replaced with versions that don't maintain the
* same call stack height as the originals. You can fix that by setting
* {@link Configuration#extraItStackFrames}.
* @name Spec#filename
* @readonly
* @type {string}
* @since 5.13.0
*/
filename: this.filename
};
}

View File

@@ -149,12 +149,11 @@ getJasmineRequireObj().Suite = function(j$) {
* @property {String} description - The description text passed to the {@link describe} that made this suite.
* @property {String} fullName - The full description including all ancestors of this suite.
* @property {String|null} parentSuiteId - The ID of the suite containing this suite, or null if this is not in another describe().
* @property {String} filename - Deprecated. The name of the file the suite was defined in.
* @property {String} filename - The name of the file the suite was defined in.
* Note: The value may be incorrect if zone.js is installed or
* `describe`/`fdescribe`/`xdescribe` have been replaced with versions that
* don't maintain the same call stack height as the originals. This property
* may be removed in a future version unless there is enough user interest
* in keeping it. See {@link https://github.com/jasmine/jasmine/issues/2065}.
* don't maintain the same call stack height as the originals. You can fix
* that by setting {@link Configuration#extraDescribeStackFrames}.
* @property {ExpectationResult[]} failedExpectations - The list of expectations that failed in an {@link afterAll} for this suite.
* @property {ExpectationResult[]} deprecationWarnings - The list of deprecation warnings that occurred on this suite.
* @property {String} status - Once the suite has completed, this string represents the pass/fail status of this suite.
@@ -362,6 +361,19 @@ getJasmineRequireObj().Suite = function(j$) {
* @since 2.0.0
*/
this.description = suite.description;
/**
* The name of the file the suite was defined in.
* Note: The value may be incorrect if zone.js is installed or
* `describe`/`fdescribe`/`xdescribe` have been replaced with versions
* that don't maintain the same call stack height as the originals. You
* can fix that by setting {@link Configuration#extraItStackFrames}.
* @name Suite#filename
* @readonly
* @type {string}
* @since 5.13.0
*/
this.filename = suite.filename;
}
/**

View File

@@ -49,7 +49,10 @@ getJasmineRequireObj().TreeRunner = function(j$) {
_executeSpec(spec, specOverallDone) {
const onStart = next => {
this.#currentRunableTracker.setCurrentSpec(spec);
this.#runableResources.initForRunable(spec.id, spec.parentSuiteId);
this.#runableResources.initForRunable(
spec.id,
spec.parentSuiteId || this.#executionTree.topSuite.id
);
this.#reportDispatcher.specStarted(spec.startedEvent()).then(next);
};
const resultCallback = (result, next) => {

View File

@@ -0,0 +1,27 @@
getJasmineRequireObj().AllOf = function(j$) {
function AllOf() {
const expectedValues = Array.from(arguments);
if (expectedValues.length === 0) {
throw new TypeError(
'jasmine.allOf() expects at least one argument to be passed.'
);
}
this.expectedValues = expectedValues;
}
AllOf.prototype.asymmetricMatch = function(other, matchersUtil) {
for (const expectedValue of this.expectedValues) {
if (!matchersUtil.equals(other, expectedValue)) {
return false;
}
}
return true;
};
AllOf.prototype.jasmineToString = function(pp) {
return '<jasmine.allOf(' + pp(this.expectedValues) + ')>';
};
return AllOf;
};

View File

@@ -229,6 +229,19 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
);
};
/**
* Get an {@link AsymmetricEqualityTester} that will succeed if the actual
* value being compared matches every provided equality tester.
* @name asymmetricEqualityTesters.allOf
* @emittedName jasmine.allOf
* @since 5.13.0
* @function
* @param {...*} arguments - The asymmetric equality checkers to compare.
*/
j$.allOf = function() {
return new j$.AllOf(...arguments);
};
/**
* Get an {@link AsymmetricEqualityTester} that will succeed if the actual
* value being compared is an instance of the specified class/constructor.

View File

@@ -26,6 +26,7 @@ var getJasmineRequireObj = (function() {
j$.private.util = jRequire.util(j$);
j$.private.errors = jRequire.errors();
j$.private.formatErrorMsg = jRequire.formatErrorMsg(j$);
j$.private.AllOf = jRequire.AllOf(j$);
j$.private.Any = jRequire.Any(j$);
j$.private.Anything = jRequire.Anything(j$);
j$.private.CallTracker = jRequire.CallTracker(j$);