Compare commits

...

57 Commits

Author SHA1 Message Date
Steve Gravrock
58d13570ac Bump version to 3.99.0 2022-01-01 10:47:59 -08:00
Steve Gravrock
005648acd8 Built distribution 2022-01-01 10:46:15 -08:00
Steve Gravrock
d963be5eec Log a deprecation warning on reentrant calls to Clock#tick
See #1929
2021-12-31 11:38:01 -08:00
Steve Gravrock
57c294b307 Added a migration guide link to multiple done call deprecations 2021-12-14 08:16:06 -08:00
Steve Gravrock
f3b26a0688 Merge branch 'main' into 3.99 2021-11-26 13:25:14 -08:00
Steve Gravrock
8804ddb8cf Updated boot file lists for the Ruby gem and Python egg
This prevents consumers that rely on those lists (especially the Jasmine
gem and egg) from getting a deprecation warning about boot.js.
2021-11-24 15:38:40 -08:00
Steve Gravrock
439be97c34 Rephrased note about verboseDeprecations 2021-11-24 11:45:32 -08:00
Steve Gravrock
c48fb0b0e7 Added Firefox 91 (current ESR) to CI matrix 2021-11-14 14:18:06 -08:00
Steve Gravrock
4c47bf6c0b Merge branch '3.10.1' into main 2021-10-22 16:34:57 -07:00
Steve Gravrock
e86a7f00a6 Bump version to 3.10.1 2021-10-22 16:15:54 -07:00
Jan Molak
504ef27899 Fixed result.pendingReason for specs marked with xit. Closes #1939 2021-10-22 14:12:28 -07:00
Steve Gravrock
2a39339755 Merge branch 'fix/pending-reason' of https://github.com/jan-molak/jasmine into main
* Fixes missing pendingReason in pending spec results
	* Fixes #1939
	* Merges #1940 from @jan-molak
2021-10-22 14:09:48 -07:00
Jan Molak
2c440b8e44 Fixed result.pendingReason for specs marked with xit. Closes #1939 2021-10-22 17:58:31 +01:00
Steve Gravrock
b13329114c Set version to 3.99.0-dev 2021-10-15 10:33:21 -07:00
Steve Gravrock
ab34f272da Merge branch 'main' into 3.99 2021-10-15 10:29:50 -07:00
Steve Gravrock
1af0e62ef7 Revert "Revert "Dogfood the new jasmine-npm completion interface""
This reverts commit 4c043717a9.
2021-10-14 07:07:10 -07:00
Steve Gravrock
572452a15a Added supported environments to 3.10.0 release notes 2021-10-13 16:47:48 -07:00
Steve Gravrock
c1db8f2f82 Clarified deprecation message for this in describes 2021-10-12 15:40:13 -07:00
Steve Gravrock
8cadfbd829 Fixed deprecation warning in spec 2021-10-07 10:51:06 -07:00
Steve Gravrock
86aeb5c88a Merge branch 'main' into 3.99 2021-10-07 10:38:35 -07:00
Steve Gravrock
7f0087b805 Merge branch 'main' into 3.99 2021-10-02 09:47:30 -07:00
Steve Gravrock
fb4c16b23e Merge branch 'main' into 3.99 2021-09-24 14:27:15 -07:00
Steve Gravrock
3b28ee7c29 Fixed extra deprecation when passing custom equality testers to MatchersUtil#contains 2021-09-24 14:25:54 -07:00
Steve Gravrock
64d58ed1f0 Deprecate non-Date arguments to jasmine.clock().mockDate() 2021-09-23 16:04:39 -07:00
Steve Gravrock
497a7fc3e5 Merge branch 'main' into 3.99 2021-09-23 15:49:47 -07:00
Steve Gravrock
af5984d5d6 Fixed flake list 2021-09-10 17:53:59 -07:00
Steve Gravrock
be23836c9d Deprecate multiple calls to done callbacks 2021-09-08 20:58:25 -07:00
Steve Gravrock
7944250290 Merge branch 'main' into 3.99 2021-09-06 17:39:28 -07:00
Steve Gravrock
de9815f436 Merge branch 'main' into 3.99 2021-08-30 18:41:02 -07:00
Steve Gravrock
2fd9d7b13f Merge branch 'main' into 3.99 2021-08-17 17:08:34 -07:00
Steve Gravrock
4e96514634 Deprecated the Promise config setting
4.0 will only support environments that have native promises, so there will
no longer be a need for a user-supplied promise library
2021-08-07 12:04:14 -07:00
Steve Gravrock
9c9836c5b3 Don't use deprecated config prooperties in boot*.js 2021-07-31 09:09:46 -07:00
Steve Gravrock
20b914c554 Deprecated the failFast and oneFailurePerSpec config properties 2021-07-31 08:42:01 -07:00
Steve Gravrock
058e77b824 Merge branch 'main' into 3.99 2021-07-31 08:15:29 -07:00
Steve Gravrock
799d9897fd Deprecated access to non-public members in specs and suites returned from it(), describe(), etc. 2021-07-29 21:28:47 -07:00
Steve Gravrock
2a2a671b65 Don't deprecate access to Suite#id and Spec#id 2021-07-29 20:15:04 -07:00
Steve Gravrock
a0b4f3748d Merge branch 'main' into 3.99 2021-07-29 20:09:25 -07:00
Steve Gravrock
f26b005807 Deprecated the legacy boot.js file 2021-07-26 18:20:07 -07:00
Steve Gravrock
1206952ca6 Merge branch 'main' into 3.99 2021-07-26 18:19:11 -07:00
Steve Gravrock
70d49e5b57 Deprecate non-Error arguments passed to done()
[Finishes #178267600]
2021-07-24 09:18:24 -07:00
Steve Gravrock
10601f5af6 Merge branch 'main' into 3.99 2021-07-20 17:47:17 -07:00
Steve Gravrock
c10ab4e704 Updated deprecation links 2021-07-20 16:50:31 -07:00
Steve Gravrock
17826cd044 Fixed deprecations in matchersUtilSpec 2021-07-10 09:11:10 -07:00
Steve Gravrock
6cb9507f62 Merge branch 'main' into 3.99 2021-07-10 08:58:14 -07:00
Steve Gravrock
00c1e3d608 Deprecate access to non-public Suite and Spec members via Env#topSuite
The deprecation warning relies on Proxy, and won't work in environments
that don't have it. Among Jasmine's supported environments, that's Safari 9,
Safari 8, and all versions of IE.
2021-05-29 15:45:10 -07:00
Steve Gravrock
6a2a30d540 Improved & unified deprecation handling
* De-duplication now happens in core, not in reporters. This ensures that
  the console doesn't get flooded.
* Stack traces are opt-out, not opt-in.
* The current runnable is not reported or logged for certain deprecations
  where it's irrelevant.
* HtmlReporter shows stack traces in expandable widgets.
* Env#deprecated and Env#deprecatedOnceWithStack are merged.
2021-05-29 15:39:28 -07:00
Steve Gravrock
61fb353197 Deprecate access to Suite objects via this in describes
Jasmine 1.x exposed Suite objects to user code as the `this` in describe
functions. That should have been removed in 2.0 but it was missed. It
will be removed in 4.0. This change adds a deprecation warning if anything
on a describe's `this` is accessed.

The deprecation warning relies on Proxy, and won't work in environments
that don't have it. Among Jasmine's supported environments, that's Safari 9,
Safari 8, and all versions of IE. In those browsers, a describe's `this`
will still be a Suite for now, but there will be no deprecation warnings.
2021-05-22 09:07:31 -07:00
Steve Gravrock
3e2872a1df Merge branch 'main' into 3.99 2021-05-18 17:07:34 -07:00
Steve Gravrock
5504965bea Merge branch 'main' into 3.99 2021-04-23 08:40:25 -07:00
Steve Gravrock
fb05da1fc3 Merge branch 'main' into 3.99 2021-04-22 17:23:08 -07:00
Steve Gravrock
8b3a6561b1 Merge branch 'main' into 3.99 2021-04-02 11:35:30 -07:00
Steve Gravrock
7a38db2e32 Fixed deprecations triggered from within asymmetricEqualityTesterArgCompatShim 2020-09-17 13:26:35 -07:00
Steve Gravrock
a1f1b4ae0f Merge branch 'main' into 3.99 2020-09-14 18:39:32 -07:00
Steve Gravrock
c39c110eca Deprecate describes with no children 2020-02-12 16:44:44 -08:00
Steve Gravrock
18b2646d1d Allow libraries to avoid "Passing custom equality testers to MatchersUtil#contains is deprecated" while remaining compatible with older jasmine versions
Previously, a custom matcher library that wanted to remain compatible with
Jasmine <= 3.5.x could not know whether or not Jasmine expected it to pass
custom equality testers to MatchersUtil#contains. Passing them would produce
a deprecation warning in newer versions and not passing them would break
compatibility with older versions. Now we use matcher factory arity to
determine whether to pass custom equality testers to the factory, which
allows libraries to do something like this:

function matcherFactory(util) {
   const customEqualityTesters = arguments[1];
   // customEqualityTesters will be undefined in newer versions of Jasmine
   // and defined in older versions that expect it to be passed back to
   // MatchersUtil#equals.
}
2020-02-12 15:24:43 -08:00
Steve Gravrock
9aed55bb91 Improved readability of matcher-related deprecations
* Include stack traces. This makes it easier to find the matcher that
needs to be updated, particularly when it comes from a library rather
than the user's own code.

* Show each deprecation only once unless `config.verboseDeprecations`
is set. Since matchers are often added in a global `beforeEach`, logging
deprecations every time can be overwhelming.
2020-02-12 15:24:43 -08:00
Steve Gravrock
90d6f9d73c Added deprecation messages to interfaces that will be removed in 4.0
* `jasmine.pp`
* `jasmine.matchersUtil`
* Matchers that expect to receive custom equality testers
* Passing custom equality testers to `matchersUtil.contains`
* Passing custom equality testers to `matchersUtil.equals`
2020-02-12 15:24:42 -08:00
68 changed files with 3775 additions and 468 deletions

View File

@@ -40,11 +40,17 @@ module.exports = function(grunt) {
jasmine = new Jasmine({jasmineCore: jasmineCore});
jasmine.loadConfigFile('./spec/support/jasmine.json');
jasmine.onComplete(function(passed) {
done(passed);
});
jasmine.execute();
jasmine.exitOnCompletion = false;
jasmine.execute().then(
result => {
done(result.overallStatus === 'passed');
},
err => {
console.error(err);
exit(1);
}
);
}
);

View File

@@ -54,7 +54,7 @@ Jasmine tests itself across many browsers (Safari, Chrome, Firefox, Microsoft Ed
| Node | 10, 12, 14, 16 |
| Safari | 8-14 |
| Chrome | Evergreen |
| Firefox | Evergreen, 68, 78 |
| Firefox | Evergreen, 68, 78, 91 |
| Edge | Evergreen |
| Internet Explorer | 10, 11 |

View File

@@ -49,7 +49,7 @@ module Jasmine
end
def boot_files
["boot.js"]
["boot0.js", "boot1.js"]
end
def node_boot_files

View File

@@ -1,5 +1,5 @@
/*
Copyright (c) 2008-2021 Pivotal Labs
Copyright (c) 2008-2022 Pivotal Labs
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@@ -81,8 +81,8 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
var filterSpecs = !!queryString.getParam("spec");
var config = {
failFast: queryString.getParam("failFast"),
oneFailurePerSpec: queryString.getParam("oneFailurePerSpec"),
stopOnSpecFailure: queryString.getParam("failFast"),
stopSpecOnExpectationFailure: queryString.getParam("oneFailurePerSpec"),
hideDisabled: queryString.getParam("hideDisabled")
};
@@ -162,4 +162,6 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
return destination;
}
env.deprecated('boot.js is deprecated. Please use boot0.js and boot1.js instead.',
{ ignoreRunnable: true });
}());

View File

@@ -59,8 +59,8 @@
var filterSpecs = !!queryString.getParam("spec");
var config = {
failFast: queryString.getParam("failFast"),
oneFailurePerSpec: queryString.getParam("oneFailurePerSpec"),
stopOnSpecFailure: queryString.getParam("failFast"),
stopSpecOnExpectationFailure: queryString.getParam("oneFailurePerSpec"),
hideDisabled: queryString.getParam("hideDisabled")
};
@@ -140,4 +140,6 @@
return destination;
}
env.deprecated('boot.js is deprecated. Please use boot0.js and boot1.js instead.',
{ ignoreRunnable: true });
}());

View File

@@ -27,8 +27,8 @@
var filterSpecs = !!queryString.getParam("spec");
var config = {
failFast: queryString.getParam("failFast"),
oneFailurePerSpec: queryString.getParam("oneFailurePerSpec"),
stopOnSpecFailure: queryString.getParam("failFast"),
stopSpecOnExpectationFailure: queryString.getParam("oneFailurePerSpec"),
hideDisabled: queryString.getParam("hideDisabled")
};

View File

@@ -1,5 +1,5 @@
/*
Copyright (c) 2008-2021 Pivotal Labs
Copyright (c) 2008-2022 Pivotal Labs
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the

View File

@@ -1,5 +1,5 @@
/*
Copyright (c) 2008-2021 Pivotal Labs
Copyright (c) 2008-2022 Pivotal Labs
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@@ -49,8 +49,8 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
var filterSpecs = !!queryString.getParam("spec");
var config = {
failFast: queryString.getParam("failFast"),
oneFailurePerSpec: queryString.getParam("oneFailurePerSpec"),
stopOnSpecFailure: queryString.getParam("failFast"),
stopSpecOnExpectationFailure: queryString.getParam("oneFailurePerSpec"),
hideDisabled: queryString.getParam("hideDisabled")
};

View File

@@ -54,14 +54,14 @@ class Core(object):
# jasmine.js needs to be first
js_files.insert(0, 'jasmine.js')
# boot needs to be last
# Remove the legacy boot file
js_files.remove('boot.js')
js_files.append('boot.js')
# Remove the new boot files. jasmine-py will continue to use the legacy
# boot.js.
# boot files need to be last
js_files.remove('boot0.js')
js_files.remove('boot1.js')
js_files.append('boot0.js')
js_files.append('boot1.js')
return cls._uniq(js_files)

View File

@@ -1,5 +1,5 @@
/*
Copyright (c) 2008-2021 Pivotal Labs
Copyright (c) 2008-2022 Pivotal Labs
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@@ -311,7 +311,8 @@ jasmineRequire.HtmlReporter = function(j$) {
addDeprecationWarnings(doneResult);
for (i = 0; i < deprecationWarnings.length; i++) {
var context;
var children = [],
context;
switch (deprecationWarnings[i].runnableType) {
case 'spec':
@@ -324,13 +325,23 @@ jasmineRequire.HtmlReporter = function(j$) {
context = '';
}
deprecationWarnings[i].message.split('\n').forEach(function(line) {
children.push(line);
children.push(createDom('br'));
});
children[0] = 'DEPRECATION: ' + children[0];
children.push(context);
if (deprecationWarnings[i].stack) {
children.push(createExpander(deprecationWarnings[i].stack));
}
alert.appendChild(
createDom(
'span',
{ className: 'jasmine-bar jasmine-warning' },
'DEPRECATION: ' + deprecationWarnings[i].message,
createDom('br'),
context
children
)
);
}
@@ -652,17 +663,44 @@ jasmineRequire.HtmlReporter = function(j$) {
if (result && result.deprecationWarnings) {
for (var i = 0; i < result.deprecationWarnings.length; i++) {
var warning = result.deprecationWarnings[i].message;
if (!j$.util.arrayContains(warning)) {
deprecationWarnings.push({
message: warning,
runnableName: result.fullName,
runnableType: runnableType
});
}
deprecationWarnings.push({
message: warning,
stack: result.deprecationWarnings[i].stack,
runnableName: result.fullName,
runnableType: runnableType
});
}
}
}
function createExpander(stackTrace) {
var expandLink = createDom('a', { href: '#' }, 'Show stack trace');
var root = createDom(
'div',
{ className: 'jasmine-expander' },
expandLink,
createDom(
'div',
{ className: 'jasmine-expander-contents jasmine-stack-trace' },
stackTrace
)
);
expandLink.addEventListener('click', function(e) {
e.preventDefault();
if (root.classList.contains('jasmine-expanded')) {
root.classList.remove('jasmine-expanded');
expandLink.textContent = 'Show stack trace';
} else {
root.classList.add('jasmine-expanded');
expandLink.textContent = 'Hide stack trace';
}
});
return root;
}
function find(selector) {
return getContainer().querySelector('.jasmine_html-reporter ' + selector);
}
@@ -676,11 +714,23 @@ jasmineRequire.HtmlReporter = function(j$) {
}
}
function createDom(type, attrs, childrenVarArgs) {
var el = createElement(type);
function createDom(type, attrs, childrenArrayOrVarArgs) {
var el = createElement(type),
children,
i;
for (var i = 2; i < arguments.length; i++) {
var child = arguments[i];
if (j$.isArray_(childrenArrayOrVarArgs)) {
children = childrenArrayOrVarArgs;
} else {
children = [];
for (i = 2; i < arguments.length; i++) {
children.push(arguments[i]);
}
}
for (i = 0; i < children.length; i++) {
var child = children[i];
if (typeof child === 'string') {
el.appendChild(createTextNode(child));

View File

@@ -165,6 +165,8 @@ body {
background-color: #bababa;
}
.jasmine_html-reporter .jasmine-bar.jasmine-warning {
margin-top: 14px;
margin-bottom: 14px;
background-color: #ba9d37;
color: #333;
}
@@ -268,4 +270,21 @@ body {
border: 1px solid #ddd;
background: white;
white-space: pre;
}
.jasmine_html-reporter .jasmine-expander a {
display: block;
margin-left: 14px;
color: blue;
text-decoration: underline;
}
.jasmine_html-reporter .jasmine-expander-contents {
display: none;
}
.jasmine_html-reporter .jasmine-expanded {
padding-bottom: 10px;
}
.jasmine_html-reporter .jasmine-expanded .jasmine-expander-contents {
display: block;
margin-left: 14px;
padding: 5px;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
/*
Copyright (c) 2008-2021 Pivotal Labs
Copyright (c) 2008-2022 Pivotal Labs
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the

View File

@@ -4,6 +4,6 @@
#
module Jasmine
module Core
VERSION = "3.10.0"
VERSION = "3.99.0"
end
end

View File

@@ -1,7 +1,7 @@
{
"name": "jasmine-core",
"license": "MIT",
"version": "3.10.0",
"version": "3.99.0",
"repository": {
"type": "git",
"url": "https://github.com/jasmine/jasmine.git"
@@ -44,7 +44,7 @@
"grunt-contrib-concat": "^1.0.1",
"grunt-css-url-embed": "^1.11.1",
"grunt-sass": "^3.0.2",
"jasmine": "^3.4.0",
"jasmine": "^3.10.0",
"jasmine-browser-runner": "github:jasmine/jasmine-browser#main",
"jsdom": "^15.0.0",
"load-grunt-tasks": "^4.0.0",

View File

@@ -39,6 +39,19 @@
* Added a deprecation notice to the jasmine-core Ruby gem's description
## Supported environments
jasmine-core 3.10.0 has been tested in the following environments.
| Environment | Supported versions |
|-------------------|--------------------|
| Node | 10, 12, 14, 16 |
| Safari | 8-14 |
| Chrome | 94 |
| Firefox | 93, 78, 68 |
| Edge | 94 |
| Internet Explorer | 10, 11 |
------
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_

12
release_notes/3.10.1.md Normal file
View File

@@ -0,0 +1,12 @@
# Jasmine Core 3.10.1 Release Notes
## Bugfixes
* Fixed missing pendingReason in pending spec results
* Fixes [#1939](https://github.com/jasmine/jasmine/issues/1939)
* Merges [#1940](https://github.com/jasmine/jasmine/pull/1940) from @jan-molak
------
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_

15
release_notes/3.99.0.md Normal file
View File

@@ -0,0 +1,15 @@
# Jasmine Core 3.99.0 Release Notes
## Summary
This release adds deprecation warnings for breaking changes that will be
introduced in Jasmine 4.0. Please see the
[migration guide](https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0)
for more information.
This is the last planned release of jasmine-core for Ruby or Python. Versions
4.0 and later will be offered only via NPM and the standalone distribution.
------
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_

View File

@@ -27,6 +27,7 @@ run_browser "internet explorer" 11
run_browser "internet explorer" 10
run_browser chrome latest
run_browser firefox latest
run_browser firefox 91
run_browser firefox 78
run_browser firefox 68
run_browser safari 14

View File

@@ -269,23 +269,18 @@ describe('AsyncExpectation', function() {
matchersUtil = {
buildFailureMessage: jasmine.createSpy('buildFailureMessage')
},
customEqualityTesters = ['a'],
addExpectationResult = jasmine.createSpy('addExpectationResult'),
expectation;
expectation = jasmineUnderTest.Expectation.asyncFactory({
matchersUtil: matchersUtil,
customAsyncMatchers: matchers,
customEqualityTesters: customEqualityTesters,
actual: 'an actual',
addExpectationResult: addExpectationResult
});
return expectation.toFoo('hello').then(function() {
expect(matcherFactory).toHaveBeenCalledWith(
matchersUtil,
customEqualityTesters
);
expect(matcherFactory).toHaveBeenCalledWith(matchersUtil);
});
});

View File

@@ -950,6 +950,28 @@ describe('Clock (acceptance)', function() {
expect(timeoutDate).toEqual(baseTime.getTime() + 150);
});
it('logs a deprecation when mockDate is called with a non-Date', function() {
var delayedFunctionScheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
global = { Date: Date },
mockDate = new jasmineUnderTest.MockDate(global),
clock = new jasmineUnderTest.Clock(
{ setTimeout: setTimeout },
function() {
return delayedFunctionScheduler;
},
mockDate
),
env = jasmineUnderTest.getEnv();
spyOn(env, 'deprecated');
clock.mockDate(12345);
expect(env.deprecated).toHaveBeenCalledWith(
'The argument to jasmine.clock().mockDate(), if specified, should be ' +
'a Date instance. Passing anything other than a Date will be ' +
'treated as an error in a future release.'
);
});
it('mocks the Date object and updates the date per delayed function', function() {
var delayedFunctionScheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
global = { Date: Date },

329
spec/core/DeprecatorSpec.js Normal file
View File

@@ -0,0 +1,329 @@
/* eslint no-console: 0 */
describe('Deprecator', function() {
describe('#deprecate', function() {
beforeEach(function() {
spyOn(console, 'error');
});
it('logs the mesage without context when the runnable is the top suite', function() {
var runnable = { addDeprecationWarning: function() {} };
var deprecator = new jasmineUnderTest.Deprecator(runnable);
deprecator.verboseDeprecations(true);
deprecator.addDeprecationWarning(runnable, 'the message', {
omitStackTrace: true
});
expect(console.error).toHaveBeenCalledWith('DEPRECATION: the message');
});
it('logs the message in a descendant suite', function() {
var runnable = {
addDeprecationWarning: function() {},
getFullName: function() {
return 'the suite';
},
children: []
};
var deprecator = new jasmineUnderTest.Deprecator({});
deprecator.verboseDeprecations(true);
deprecator.addDeprecationWarning(runnable, 'the message', {
omitStackTrace: true
});
expect(console.error).toHaveBeenCalledWith(
'DEPRECATION: the message (in suite: the suite)'
);
});
it('logs and reports the message in a spec', function() {
var runnable = {
addDeprecationWarning: function() {},
getFullName: function() {
return 'the spec';
}
};
var deprecator = new jasmineUnderTest.Deprecator({});
deprecator.verboseDeprecations(true);
deprecator.addDeprecationWarning(runnable, 'the message', {
omitStackTrace: true
});
expect(console.error).toHaveBeenCalledWith(
'DEPRECATION: the message (in spec: the spec)'
);
});
it('logs and reports the message without runnable info when ignoreRunnable is true', function() {
var topSuite = jasmine.createSpyObj('topSuite', [
'addDeprecationWarning',
'getFullName'
]);
var deprecator = new jasmineUnderTest.Deprecator(topSuite);
var runnable = jasmine.createSpyObj('spec', [
'addDeprecationWarning',
'getFullName'
]);
runnable.getFullName.and.returnValue('a spec');
deprecator.addDeprecationWarning(runnable, 'the message', {
ignoreRunnable: true
});
expect(topSuite.addDeprecationWarning).toHaveBeenCalledWith(
jasmine.objectContaining({
message: jasmine.stringMatching(/^the message/)
})
);
expect(runnable.addDeprecationWarning).not.toHaveBeenCalled();
expect(console.error).toHaveBeenCalledWith(
jasmine.stringMatching(/the message/)
);
expect(console.error).not.toHaveBeenCalledWith(
jasmine.stringMatching(/a spec/)
);
});
describe('with no options', function() {
it('includes the stack trace', function() {
testStackTrace(undefined);
});
});
it('omits the stack trace when omitStackTrace is true', function() {
testNoStackTrace({ omitStackTrace: true });
});
it('includes the stack trace when omitStackTrace is false', function() {
testStackTrace({ omitStackTrace: false });
});
it('includes the stack trace when omitStackTrace is undefined', function() {
testStackTrace({ includeStackTrace: undefined });
});
it('emits the deprecation only once when verboseDeprecations is not set', function() {
var deprecator = new jasmineUnderTest.Deprecator({});
var runnable1 = jasmine.createSpyObj('runnable1', [
'addDeprecationWarning',
'getFullName'
]);
var runnable2 = jasmine.createSpyObj('runnable2', [
'addDeprecationWarning',
'getFullName'
]);
deprecator.addDeprecationWarning(runnable1, 'the message');
deprecator.addDeprecationWarning(runnable1, 'the message');
deprecator.addDeprecationWarning(runnable2, 'the message');
expect(runnable1.addDeprecationWarning).toHaveBeenCalledTimes(1);
expect(runnable2.addDeprecationWarning).not.toHaveBeenCalled();
});
it('emits the deprecation only once when verboseDeprecations is false', function() {
var deprecator = new jasmineUnderTest.Deprecator({});
var runnable1 = jasmine.createSpyObj('runnable1', [
'addDeprecationWarning',
'getFullName'
]);
var runnable2 = jasmine.createSpyObj('runnable2', [
'addDeprecationWarning',
'getFullName'
]);
deprecator.verboseDeprecations(false);
deprecator.addDeprecationWarning(runnable1, 'the message');
deprecator.addDeprecationWarning(runnable1, 'the message');
deprecator.addDeprecationWarning(runnable2, 'the message');
expect(runnable1.addDeprecationWarning).toHaveBeenCalledTimes(1);
expect(runnable2.addDeprecationWarning).not.toHaveBeenCalled();
});
it('emits the deprecation for each call when verboseDeprecations is true', function() {
var deprecator = new jasmineUnderTest.Deprecator({});
var runnable1 = jasmine.createSpyObj('runnable1', [
'addDeprecationWarning',
'getFullName'
]);
var runnable2 = jasmine.createSpyObj('runnable2', [
'addDeprecationWarning',
'getFullName'
]);
deprecator.verboseDeprecations(true);
deprecator.addDeprecationWarning(runnable1, 'the message');
deprecator.addDeprecationWarning(runnable1, 'the message');
deprecator.addDeprecationWarning(runnable2, 'the message');
expect(runnable1.addDeprecationWarning).toHaveBeenCalledTimes(2);
expect(runnable2.addDeprecationWarning).toHaveBeenCalled();
});
it('includes a note about verboseDeprecations', function() {
var deprecator = new jasmineUnderTest.Deprecator({});
var runnable = jasmine.createSpyObj('runnable', [
'addDeprecationWarning',
'getFullName'
]);
deprecator.addDeprecationWarning(runnable, 'the message');
expect(runnable.addDeprecationWarning).toHaveBeenCalledTimes(1);
expect(
runnable.addDeprecationWarning.calls.argsFor(0)[0].message
).toContain(verboseDeprecationsNote());
expect(console.error).toHaveBeenCalledTimes(1);
expect(console.error.calls.argsFor(0)[0]).toContain(
verboseDeprecationsNote()
);
});
it('omits the note about verboseDeprecations when verboseDeprecations is true', function() {
var deprecator = new jasmineUnderTest.Deprecator({});
var runnable = jasmine.createSpyObj('runnable', [
'addDeprecationWarning',
'getFullName'
]);
deprecator.verboseDeprecations(true);
deprecator.addDeprecationWarning(runnable, 'the message');
expect(runnable.addDeprecationWarning).toHaveBeenCalledTimes(1);
expect(
runnable.addDeprecationWarning.calls.argsFor(0)[0].message
).not.toContain(verboseDeprecationsNote());
expect(console.error).toHaveBeenCalledTimes(1);
expect(console.error.calls.argsFor(0)[0]).not.toContain(
verboseDeprecationsNote()
);
});
describe('When the deprecation is an Error', function() {
// This form is used by external systems like atom-jasmine3-test-runner
// to report their own deprecations through Jasmine. See
// <https://github.com/jasmine/jasmine/pull/1498>.
it('passes the error through unchanged', function() {
var deprecator = new jasmineUnderTest.Deprecator({});
var runnable = jasmine.createSpyObj('runnable', [
'addDeprecationWarning',
'getFullName'
]);
var exceptionFormatter = new jasmineUnderTest.ExceptionFormatter();
var deprecation, originalStack;
try {
throw new Error('the deprecation');
} catch (err) {
deprecation = err;
originalStack = err.stack;
}
deprecator.addDeprecationWarning(runnable, deprecation);
expect(runnable.addDeprecationWarning).toHaveBeenCalledTimes(1);
expect(
runnable.addDeprecationWarning.calls.argsFor(0)[0].message
).toEqual('the deprecation');
expect(runnable.addDeprecationWarning.calls.argsFor(0)[0].stack).toBe(
originalStack
);
expect(console.error).toHaveBeenCalledTimes(1);
expect(console.error.calls.argsFor(0)[0].message).toEqual(
'the deprecation'
);
expect(console.error.calls.argsFor(0)[0].stack).toEqual(originalStack);
});
it('reports the deprecation every time, regardless of config.verboseDeprecations', function() {
var deprecator = new jasmineUnderTest.Deprecator({});
var runnable = jasmine.createSpyObj('runnable', [
'addDeprecationWarning',
'getFullName'
]);
var deprecation;
try {
throw new Error('the deprecation');
} catch (err) {
deprecation = err;
}
deprecator.addDeprecationWarning(runnable, deprecation);
deprecator.addDeprecationWarning(runnable, deprecation);
expect(runnable.addDeprecationWarning).toHaveBeenCalledTimes(2);
expect(console.error).toHaveBeenCalledTimes(2);
});
it('omits the note about verboseDeprecations', function() {
var deprecator = new jasmineUnderTest.Deprecator({});
var runnable = jasmine.createSpyObj('runnable', [
'addDeprecationWarning',
'getFullName'
]);
var deprecation;
try {
throw new Error('the deprecation');
} catch (err) {
deprecation = err;
}
deprecator.addDeprecationWarning(runnable, deprecation);
expect(runnable.addDeprecationWarning).toHaveBeenCalledTimes(1);
expect(
runnable.addDeprecationWarning.calls.argsFor(0)[0].message
).not.toContain(verboseDeprecationsNote());
expect(console.error).toHaveBeenCalledTimes(1);
expect(console.error.calls.argsFor(0)[0]).not.toContain(
verboseDeprecationsNote()
);
});
});
function verboseDeprecationsNote() {
return (
'Note: This message will be shown only once. Set the ' +
'verboseDeprecations config property to true to see every occurrence.'
);
}
function testStackTrace(options) {
var deprecator = new jasmineUnderTest.Deprecator({});
var runnable = jasmine.createSpyObj('runnable', [
'addDeprecationWarning',
'getFullName'
]);
deprecator.addDeprecationWarning(runnable, 'the message', options);
expect(runnable.addDeprecationWarning).toHaveBeenCalledWith({
message: jasmine.stringMatching(/^the message/),
omitStackTrace: false
});
expect(console.error).toHaveBeenCalledTimes(1);
expect(console.error.calls.argsFor(0)[0]).toContain('the message');
expect(console.error.calls.argsFor(0)[0]).toContain('DeprecatorSpec.js');
}
function testNoStackTrace(options) {
var deprecator = new jasmineUnderTest.Deprecator({});
var runnable = jasmine.createSpyObj('runnable', [
'addDeprecationWarning',
'getFullName'
]);
deprecator.addDeprecationWarning(runnable, 'the message', options);
expect(runnable.addDeprecationWarning).toHaveBeenCalledWith({
message: jasmine.stringMatching(/^the message/),
omitStackTrace: true
});
}
});
});

View File

@@ -26,9 +26,228 @@ describe('Env', function() {
});
describe('#topSuite', function() {
it('returns the Jasmine top suite for users to traverse the spec tree', function() {
var suite = env.topSuite();
it('returns an object that describes the tree of suites and specs', function() {
var suite;
spyOn(env, 'deprecated');
env.it('a top level spec');
env.describe('a suite', function() {
env.it('a spec');
env.describe('a nested suite', function() {
env.it('a nested spec');
});
});
suite = env.topSuite();
expect(suite.description).toEqual('Jasmine__TopLevel__Suite');
expect(suite.getFullName()).toEqual('');
expect(suite.children.length).toEqual(2);
expect(suite.children[0].description).toEqual('a top level spec');
expect(suite.children[0].getFullName()).toEqual('a top level spec');
expect(suite.children[0].children).toBeFalsy();
expect(suite.children[1].description).toEqual('a suite');
expect(suite.children[1].getFullName()).toEqual('a suite');
expect(suite.children[1].parentSuite).toBe(suite);
expect(suite.children[1].children.length).toEqual(2);
expect(suite.children[1].children[0].description).toEqual('a spec');
expect(suite.children[1].children[0].getFullName()).toEqual(
'a suite a spec'
);
expect(suite.children[1].children[0].children).toBeFalsy();
expect(suite.children[1].children[1].description).toEqual(
'a nested suite'
);
expect(suite.children[1].children[1].getFullName()).toEqual(
'a suite a nested suite'
);
expect(suite.children[1].children[1].parentSuite).toBe(suite.children[1]);
expect(suite.children[1].children[1].children.length).toEqual(1);
expect(suite.children[1].children[1].children[0].description).toEqual(
'a nested spec'
);
expect(suite.children[1].children[1].children[0].getFullName()).toEqual(
'a suite a nested suite a nested spec'
);
expect(suite.children[1].children[1].children[0].children).toBeFalsy();
});
it('does not deprecate access to public Suite and Spec members', function() {
jasmine.getEnv().requireProxy();
var suite;
spyOn(env, 'deprecated');
env.it('a top level spec');
env.describe('a suite', function() {
env.it('a spec');
});
suite = env.topSuite();
suite.id;
suite.description;
suite.getFullName();
suite.children;
suite.parentSuite;
suite.children[0].id;
suite.children[0].description;
suite.children[0].getFullName();
suite.children[0].children;
suite.children[1].id;
suite.children[1].description;
suite.children[1].getFullName();
suite.children[1].parentSuite;
suite.children[1].children;
expect(env.deprecated).not.toHaveBeenCalled();
});
it('deprecates access to internal Spec members via it(), fit(), and xit()', function() {
jasmine.getEnv().requireProxy();
spyOn(env, 'deprecated');
['it', 'fit', 'xit'].forEach(function(method) {
var spec = env[method]('a spec', function() {});
expect(env.deprecated).not.toHaveBeenCalled();
spec.pend();
expect(env.deprecated)
.withContext('via ' + method)
.toHaveBeenCalledWith(
'Access to private Spec members (in this case `pend`) is not ' +
'supported and will break in a future release. See ' +
'<https://jasmine.github.io/api/edge/Spec.html> for correct usage.'
);
env.deprecated.calls.reset();
spec.expectationFactory = {};
expect(env.deprecated)
.withContext('via ' + method)
.toHaveBeenCalledWith(
'Access to private Spec members (in this case `expectationFactory`) is not ' +
'supported and will break in a future release. See ' +
'<https://jasmine.github.io/api/edge/Spec.html> for correct usage.'
);
env.deprecated.calls.reset();
spec.expectationFactory = {};
expect(env.deprecated)
.withContext('via ' + method)
.toHaveBeenCalledWith(
'Access to private Spec members (in this case `expectationFactory`) is not ' +
'supported and will break in a future release. See ' +
'<https://jasmine.github.io/api/edge/Spec.html> for correct usage.'
);
env.deprecated.calls.reset();
});
});
it('deprecates access to internal Spec and Suite members via describe(), fdescribe(), and xdescribe()', function() {
jasmine.getEnv().requireProxy();
spyOn(env, 'deprecated');
['describe', 'fdescribe', 'xdescribe'].forEach(function(method) {
var suite = env[method]('a suite', function() {
env.it('a spec');
});
suite.expectationFactory;
expect(env.deprecated)
.withContext('via ' + method)
.toHaveBeenCalledWith(
'Access to private Suite ' +
'members (in this case `expectationFactory`) is ' +
'not supported and will break in a future release. See ' +
'<https://jasmine.github.io/api/edge/Suite.html> for correct usage.'
);
env.deprecated.calls.reset();
suite.expectationFactory = {};
expect(env.deprecated)
.withContext('via ' + method)
.toHaveBeenCalledWith(
'Access to private Suite ' +
'members (in this case `expectationFactory`) is ' +
'not supported and will break in a future release. See ' +
'<https://jasmine.github.io/api/edge/Suite.html> for correct usage.'
);
env.deprecated.calls.reset();
suite.status();
expect(env.deprecated)
.withContext('via ' + method)
.toHaveBeenCalledWith(
'Access to private Suite ' +
'members (in this case `status`) is ' +
'not supported and will break in a future release. See ' +
'<https://jasmine.github.io/api/edge/Suite.html> for correct usage.'
);
env.deprecated.calls.reset();
});
});
it('deprecates access to internal Suite and Spec members via topSuite', function() {
jasmine.getEnv().requireProxy();
var topSuite, expectationFactory, spec;
env.it('a top level spec');
spyOn(env, 'deprecated');
topSuite = env.topSuite();
topSuite.expectationFactory;
expect(env.deprecated).toHaveBeenCalledWith(
'Access to private Suite ' +
'members (in this case `expectationFactory`) is ' +
'not supported and will break in a future release. See ' +
'<https://jasmine.github.io/api/edge/Suite.html> for correct usage.'
);
env.deprecated.calls.reset();
topSuite.expectationFactory = expectationFactory;
expect(env.deprecated).toHaveBeenCalledWith(
'Access to private Suite ' +
'members (in this case `expectationFactory`) is ' +
'not supported and will break in a future release. See ' +
'<https://jasmine.github.io/api/edge/Suite.html> for correct usage.'
);
topSuite.status();
expect(env.deprecated).toHaveBeenCalledWith(
'Access to private Suite ' +
'members (in this case `status`) is ' +
'not supported and will break in a future release. See ' +
'<https://jasmine.github.io/api/edge/Suite.html> for correct usage.'
);
spec = topSuite.children[0];
spec.pend();
expect(env.deprecated).toHaveBeenCalledWith(
'Access to private Spec ' +
'members (in this case `pend`) ' +
'is not supported and will break in a future release. See ' +
'<https://jasmine.github.io/api/edge/Spec.html> for correct usage.'
);
expectationFactory = spec.expectationFactory;
expect(env.deprecated).toHaveBeenCalledWith(
'Access to private Spec ' +
'members (in this case `expectationFactory`) ' +
'is not supported and will break in a future release. See ' +
'<https://jasmine.github.io/api/edge/Spec.html> for correct usage.'
);
env.deprecated.calls.reset();
spec.expectationFactory = expectationFactory;
expect(env.deprecated).toHaveBeenCalledWith(
'Access to private Spec ' +
'members (in this case `expectationFactory`) ' +
'is not supported and will break in a future release. See ' +
'<https://jasmine.github.io/api/edge/Spec.html> for correct usage.'
);
});
});
@@ -37,7 +256,7 @@ describe('Env', function() {
});
it('can configure specs to throw errors on expectation failures', function() {
env.configure({ oneFailurePerSpec: true });
env.configure({ stopSpecOnExpectationFailure: true });
spyOn(jasmineUnderTest, 'Spec');
env.it('foo', function() {});
@@ -49,7 +268,7 @@ describe('Env', function() {
});
it('can configure suites to throw errors on expectation failures', function() {
env.configure({ oneFailurePerSpec: true });
env.configure({ stopSpecOnExpectationFailure: true });
spyOn(jasmineUnderTest, 'Suite');
env.describe('foo', function() {});
@@ -61,6 +280,7 @@ describe('Env', function() {
});
it('ignores configuration properties that are present but undefined', function() {
spyOn(env, 'deprecated');
var initialConfig = {
random: true,
seed: '123',
@@ -90,6 +310,7 @@ describe('Env', function() {
});
it('sets stopOnSpecFailure when failFast is set, and vice versa', function() {
spyOn(env, 'deprecated');
env.configure({ failFast: true });
expect(env.configuration()).toEqual(
jasmine.objectContaining({
@@ -108,6 +329,7 @@ describe('Env', function() {
});
it('rejects a single call that sets stopOnSpecFailure and failFast to different values', function() {
spyOn(env, 'deprecated');
expect(function() {
env.configure({ failFast: true, stopOnSpecFailure: false });
}).toThrowError(
@@ -116,7 +338,18 @@ describe('Env', function() {
);
});
it('deprecates the failFast config property', function() {
spyOn(env, 'deprecated');
env.configure({ failFast: true });
expect(env.deprecated).toHaveBeenCalledWith(
'The `failFast` config property is deprecated and will be removed in a ' +
'future version of Jasmine. Please use `stopOnSpecFailure` instead.',
{ ignoreRunnable: true }
);
});
it('sets stopSpecOnExpectationFailure when oneFailurePerSpec is set, and vice versa', function() {
spyOn(env, 'deprecated');
env.configure({ oneFailurePerSpec: true });
expect(env.configuration()).toEqual(
jasmine.objectContaining({
@@ -135,6 +368,7 @@ describe('Env', function() {
});
it('rejects a single call that sets stopSpecOnExpectationFailure and oneFailurePerSpec to different values', function() {
spyOn(env, 'deprecated');
expect(function() {
env.configure({
oneFailurePerSpec: true,
@@ -147,6 +381,17 @@ describe('Env', function() {
);
});
it('deprecates the oneFailurePerSpec config property', function() {
spyOn(env, 'deprecated');
env.configure({ oneFailurePerSpec: true });
expect(env.deprecated).toHaveBeenCalledWith(
'The `oneFailurePerSpec` config property is deprecated and will be ' +
'removed in a future version of Jasmine. Please use ' +
'`stopSpecOnExpectationFailure` instead.',
{ ignoreRunnable: true }
);
});
describe('promise library', function() {
it('can be configured without a custom library', function() {
env.configure({});
@@ -154,11 +399,17 @@ describe('Env', function() {
});
it('can be configured with a custom library', function() {
spyOn(env, 'deprecated');
var myLibrary = {
resolve: jasmine.createSpy(),
reject: jasmine.createSpy()
};
env.configure({ Promise: myLibrary });
expect(env.deprecated).toHaveBeenCalledWith(
'The `Promise` config property is deprecated. Future versions of ' +
'Jasmine will create native promises even if the `Promise` config ' +
'property is set. Please remove it.'
);
});
it('cannot be configured with an invalid promise library', function() {
@@ -228,11 +479,24 @@ describe('Env', function() {
);
expect(function() {
env.describe('fn arg', function() {});
env.describe('fn arg', function() {
env.it('has a spec', function() {});
});
}).not.toThrowError(
'describe expects a function argument; received [object Function]'
);
});
it('logs a deprecation when it has no children', function() {
spyOn(env, 'deprecated');
env.describe('no children', function() {});
expect(env.deprecated).toHaveBeenCalledWith(
'describe with no children' +
' (describe() or it()) is deprecated and will be removed in a future ' +
'version of Jasmine. Please either remove the describe or add ' +
'children to it.'
);
});
});
describe('#it', function() {
@@ -267,13 +531,25 @@ describe('Env', function() {
describe('#xit', function() {
it('calls spec.exclude with "Temporarily disabled with xit"', function() {
var excludeSpy = jasmine.createSpy();
spyOn(env, 'it').and.returnValue({
spyOn(env, 'it_').and.returnValue({
exclude: excludeSpy
});
env.xit('foo', function() {});
expect(excludeSpy).toHaveBeenCalledWith('Temporarily disabled with xit');
});
it('calls spec.pend with "Temporarily disabled with xit"', function() {
var pendSpy = jasmine.createSpy();
var realExclude = jasmineUnderTest.Spec.prototype.exclude;
spyOn(env, 'it_').and.returnValue({
exclude: realExclude,
pend: pendSpy
});
env.xit('foo', function() {});
expect(pendSpy).toHaveBeenCalledWith('Temporarily disabled with xit');
});
it('throws an error when it receives a non-fn argument', function() {
expect(function() {
env.xit('undefined arg', null);
@@ -502,6 +778,51 @@ describe('Env', function() {
});
});
it("deprecates access to 'this' in describes", function() {
jasmine.getEnv().requireProxy();
var msg =
"Access to 'this' in describe functions (and in arrow " +
'functions inside describe functions) is deprecated.',
ran = false;
spyOn(env, 'deprecated');
env.describe('a suite', function() {
expect(this.description).toEqual('a suite');
expect(env.deprecated).toHaveBeenCalledWith(msg);
env.deprecated.calls.reset();
this.foo = 1;
expect(env.deprecated).toHaveBeenCalledWith(msg);
expect(this.foo).toEqual(1);
env.deprecated.calls.reset();
expect(this.getFullName()).toEqual('a suite');
expect(env.deprecated).toHaveBeenCalledWith(msg);
env.deprecated.calls.reset();
env.it('has a spec');
ran = true;
});
expect(ran).toBeTrue();
});
// TODO: Remove this in the next major version. Suites were never meant to be
// exposed via describe 'this' in >= 2.0, and user code should not rely on it.
// This spec is just here to make sure we don't break user code that *does*
// rely on it in older browsers (without Proxy) while deprecating it.
it("sets 'this' to the Suite in describes", function() {
var suiteThis;
spyOn(env, 'deprecated');
env.describe('a suite', function() {
suiteThis = this;
env.it('has a spec');
});
expect(suiteThis).toBeInstanceOf(jasmineUnderTest.Suite);
});
describe('#execute', function() {
it('returns a promise when the environment supports promises', function() {
jasmine.getEnv().requirePromises();
@@ -513,6 +834,7 @@ describe('Env', function() {
CustomPromise.resolve = function() {};
CustomPromise.reject = function() {};
spyOn(env, 'deprecated');
env.configure({ Promise: CustomPromise });
expect(env.execute()).toBeInstanceOf(CustomPromise);
});
@@ -524,14 +846,20 @@ describe('Env', function() {
it('should reset the topSuite when run twice', function() {
jasmine.getEnv().requirePromises();
spyOn(env.topSuite(), 'reset');
spyOn(jasmineUnderTest.Suite.prototype, 'reset');
return env
.execute() // 1
.then(function() {
return env.execute(); // 2
})
.then(function() {
expect(env.topSuite().reset).toHaveBeenCalledOnceWith();
var id;
expect(
jasmineUnderTest.Suite.prototype.reset
).toHaveBeenCalledOnceWith();
id = jasmineUnderTest.Suite.prototype.reset.calls.thisFor(0).id;
expect(id).toBeTruthy();
expect(id).toEqual(env.topSuite().id);
});
});
});

View File

@@ -33,7 +33,11 @@ describe('Exceptions:', function() {
});
it('should handle exceptions thrown directly in top-level describe blocks and continue', function(done) {
var secondDescribe = jasmine.createSpy('second describe');
var secondDescribe = jasmine
.createSpy('second describe')
.and.callFake(function() {
env.it('has a test', function() {});
});
env.describe('a suite that throws an exception', function() {
env.it('is a test that should pass', function() {
this.expect(true).toEqual(true);

View File

@@ -40,6 +40,38 @@ describe('Expectation', function() {
matchersUtil = {
buildFailureMessage: jasmine.createSpy('buildFailureMessage')
},
addExpectationResult = jasmine.createSpy('addExpectationResult'),
expectation;
expectation = jasmineUnderTest.Expectation.factory({
matchersUtil: matchersUtil,
customMatchers: matchers,
actual: 'an actual',
addExpectationResult: addExpectationResult
});
expectation.toFoo('hello');
expect(matcherFactory).toHaveBeenCalledWith(matchersUtil);
});
// TODO: remove this in the next major release
it('passes custom equality testers when the matcher factory takes two arguments', function() {
var fakeCompare = function() {
return { pass: true };
},
matcherFactory = function(matchersUtil, customTesters) {
return { compare: fakeCompare };
},
matcherFactorySpy = jasmine
.createSpy('matcher', matcherFactory)
.and.callThrough(),
matchers = {
toFoo: matcherFactorySpy
},
matchersUtil = {
buildFailureMessage: jasmine.createSpy('buildFailureMessage')
},
customEqualityTesters = ['a'],
addExpectationResult = jasmine.createSpy('addExpectationResult'),
expectation;
@@ -54,7 +86,7 @@ describe('Expectation', function() {
expectation.toFoo('hello');
expect(matcherFactory).toHaveBeenCalledWith(
expect(matcherFactorySpy).toHaveBeenCalledWith(
matchersUtil,
customEqualityTesters
);

View File

@@ -149,31 +149,111 @@ describe('QueueRunner', function() {
expect(queueableFn2.fn).toHaveBeenCalled();
});
it('explicitly fails an async function when next is called with an Error and moves to the next function', function() {
var err = new Error('foo'),
queueableFn1 = {
fn: function(done) {
setTimeout(function() {
done(err);
}, 100);
}
},
queueableFn2 = { fn: jasmine.createSpy('fn2') },
failFn = jasmine.createSpy('fail'),
queueRunner = new jasmineUnderTest.QueueRunner({
queueableFns: [queueableFn1, queueableFn2],
fail: failFn
describe('When next is called with an argument', function() {
describe('that is an Error', function() {
it('explicitly fails and moves to the next function', function() {
var err = new Error('foo'),
queueableFn1 = {
fn: function(done) {
setTimeout(function() {
done(err);
}, 100);
}
},
queueableFn2 = { fn: jasmine.createSpy('fn2') },
failFn = jasmine.createSpy('fail'),
queueRunner = new jasmineUnderTest.QueueRunner({
queueableFns: [queueableFn1, queueableFn2],
fail: failFn
});
queueRunner.execute();
expect(failFn).not.toHaveBeenCalled();
expect(queueableFn2.fn).not.toHaveBeenCalled();
jasmine.clock().tick(100);
expect(failFn).toHaveBeenCalledWith(err);
expect(queueableFn2.fn).toHaveBeenCalled();
});
queueRunner.execute();
it('does not log a deprecation', function() {
var err = new Error('foo'),
queueableFn1 = {
fn: function(done) {
setTimeout(function() {
done(err);
}, 100);
}
},
deprecated = jasmine.createSpy('deprecated'),
queueRunner = new jasmineUnderTest.QueueRunner({
queueableFns: [queueableFn1],
deprecated: deprecated
});
expect(failFn).not.toHaveBeenCalled();
expect(queueableFn2.fn).not.toHaveBeenCalled();
queueRunner.execute();
jasmine.clock().tick(100);
jasmine.clock().tick(100);
expect(failFn).toHaveBeenCalledWith(err);
expect(queueableFn2.fn).toHaveBeenCalled();
expect(deprecated).not.toHaveBeenCalled();
});
});
describe('that is not an Error', function() {
it('logs a deprecation', function() {
var queueableFn1 = {
fn: function(done) {
setTimeout(function() {
done('not an Error');
}, 100);
}
},
deprecated = jasmine.createSpy('deprecated'),
queueRunner = new jasmineUnderTest.QueueRunner({
queueableFns: [queueableFn1],
deprecated: deprecated
});
queueRunner.execute();
jasmine.clock().tick(100);
expect(deprecated).toHaveBeenCalledWith(
'Any argument passed to a done callback will be treated as an ' +
'error in a future release. Call the done callback without ' +
"arguments if you don't want to trigger a spec failure."
);
});
it('moves to the next function without failing', function() {
var queueableFn1 = {
fn: function(done) {
setTimeout(function() {
done('not an Error');
}, 100);
}
},
queueableFn2 = { fn: jasmine.createSpy('fn2') },
failFn = jasmine.createSpy('fail'),
queueRunner = new jasmineUnderTest.QueueRunner({
queueableFns: [queueableFn1, queueableFn2],
fail: failFn,
deprecated: function() {}
});
queueRunner.execute();
expect(failFn).not.toHaveBeenCalled();
expect(queueableFn2.fn).not.toHaveBeenCalled();
jasmine.clock().tick(100);
expect(failFn).not.toHaveBeenCalled();
expect(queueableFn2.fn).toHaveBeenCalled();
});
});
});
it('does not cause an explicit fail if execution is being stopped', function() {
@@ -225,6 +305,32 @@ describe('QueueRunner', function() {
expect(onComplete).toHaveBeenCalled();
});
it('does not call onMultipleDone if an asynchrnous function completes after timing out', function() {
var timeout = 3,
queueableFn = {
fn: function(done) {
queueableFnDone = done;
},
type: 'queueable',
timeout: timeout
},
onComplete = jasmine.createSpy('onComplete'),
onMultipleDone = jasmine.createSpy('onMultipleDone'),
queueRunner = new jasmineUnderTest.QueueRunner({
queueableFns: [queueableFn],
onComplete: onComplete,
onMultipleDone: onMultipleDone
}),
queueableFnDone;
queueRunner.execute();
jasmine.clock().tick(timeout);
queueableFnDone();
expect(onComplete).toHaveBeenCalled();
expect(onMultipleDone).not.toHaveBeenCalled();
});
it('by default does not set a timeout for asynchronous functions', function() {
var beforeFn = { fn: function(done) {} },
queueableFn = { fn: jasmine.createSpy('fn') },
@@ -300,13 +406,16 @@ describe('QueueRunner', function() {
}
},
nextQueueableFn = { fn: jasmine.createSpy('nextFn') },
onMultipleDone = jasmine.createSpy('onMultipleDone'),
queueRunner = new jasmineUnderTest.QueueRunner({
queueableFns: [queueableFn, nextQueueableFn]
queueableFns: [queueableFn, nextQueueableFn],
onMultipleDone: onMultipleDone
});
queueRunner.execute();
jasmine.clock().tick(1);
expect(nextQueueableFn.fn.calls.count()).toEqual(1);
expect(onMultipleDone).toHaveBeenCalled();
});
it('does not move to the next spec if done is called after an exception has ended the spec', function() {
@@ -317,13 +426,17 @@ describe('QueueRunner', function() {
}
},
nextQueueableFn = { fn: jasmine.createSpy('nextFn') },
deprecated = jasmine.createSpy('deprecated'),
queueRunner = new jasmineUnderTest.QueueRunner({
deprecated: deprecated,
queueableFns: [queueableFn, nextQueueableFn]
});
queueRunner.execute();
jasmine.clock().tick(1);
expect(nextQueueableFn.fn.calls.count()).toEqual(1);
// Don't issue a deprecation. The error already tells the user that
// something went wrong.
expect(deprecated).not.toHaveBeenCalled();
});
it('should return a null when you call done', function() {
@@ -523,8 +636,7 @@ describe('QueueRunner', function() {
queueRunner = new jasmineUnderTest.QueueRunner({
queueableFns: [queueableFn],
deprecated: deprecated
}),
env = jasmineUnderTest.getEnv();
});
queueRunner.execute();
@@ -533,7 +645,8 @@ describe('QueueRunner', function() {
'before/it/after function took a done callback but also returned a ' +
'promise. This is not supported and will stop working in the future. ' +
'Either remove the done callback (recommended) or change the function ' +
'to not return a promise.'
'to not return a promise.',
{ omitStackTrace: true }
);
});
@@ -553,7 +666,8 @@ describe('QueueRunner', function() {
'before/it/after function was defined with the async keyword but ' +
'also took a done callback. This is not supported and will stop ' +
'working in the future. Either remove the done callback ' +
'(recommended) or remove the async keyword.'
'(recommended) or remove the async keyword.',
{ omitStackTrace: true }
);
});
});

View File

@@ -516,4 +516,33 @@ describe('Spec', function() {
args.cleanupFns[0].fn();
expect(resultCallback.calls.first().args[0].failedExpectations).toEqual([]);
});
it('passes an onMultipleDone that logs a deprecation', function() {
var queueRunnerFactory = jasmine.createSpy('queueRunnerFactory'),
deprecated = jasmine.createSpy('depredated'),
spec = new jasmineUnderTest.Spec({
deprecated: deprecated,
queueableFn: { fn: function() {} },
queueRunnerFactory: queueRunnerFactory,
getSpecName: function() {
return 'a spec';
}
});
spec.execute();
expect(queueRunnerFactory).toHaveBeenCalled();
queueRunnerFactory.calls.argsFor(0)[0].onMultipleDone();
expect(deprecated).toHaveBeenCalledWith(
"An asynchronous function called its 'done' " +
'callback more than once. This is a bug in the spec, beforeAll, ' +
'beforeEach, afterAll, or afterEach function in question. This will ' +
'be treated as an error in a future version. See' +
'<https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0#deprecations-due-to-calling-done-multiple-times> ' +
'for more information.\n' +
'(in spec: a spec)',
{ ignoreRunnable: true }
);
});
});

View File

@@ -271,6 +271,7 @@ describe('Spies', function() {
reject: jasmine.createSpy()
};
customPromise.resolve.and.returnValue('resolved');
spyOn(env, 'deprecated');
env.configure({ Promise: customPromise });
var spy = env.createSpy('foo').and.resolveTo(42);

View File

@@ -224,4 +224,48 @@ describe('Suite', function() {
expect(result.failedExpectations).toHaveSize(0);
});
});
describe('#onMultipleDone', function() {
it('logs a special deprecation when it is the top suite', function() {
var env = jasmine.createSpyObj('env', ['deprecated']);
var suite = new jasmineUnderTest.Suite({ env: env, parentSuite: null });
suite.onMultipleDone();
expect(env.deprecated).toHaveBeenCalledWith(
'A top-level beforeAll or afterAll function called its ' +
"'done' callback more than once. This is a bug in the beforeAll " +
'or afterAll function in question. This will be treated as an ' +
'error in a future version. See' +
'<https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0#deprecations-due-to-calling-done-multiple-times> ' +
'for more information.',
{ ignoreRunnable: true }
);
});
it('logs a deprecation including the suite name when it is a normal suite', function() {
var env = jasmine.createSpyObj('env', ['deprecated']);
var suite = new jasmineUnderTest.Suite({
env: env,
description: 'the suite',
parentSuite: {
description: 'the parent suite',
parentSuite: {}
}
});
suite.onMultipleDone();
expect(env.deprecated).toHaveBeenCalledWith(
"An asynchronous function called its 'done' callback more than " +
'once. This is a bug in the spec, beforeAll, beforeEach, afterAll, ' +
'or afterEach function in question. This will be treated as an error ' +
'in a future version. See' +
'<https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0#deprecations-due-to-calling-done-multiple-times> ' +
'for more information.\n' +
'(in suite: the parent suite the suite)',
{ ignoreRunnable: true }
);
});
});
});

View File

@@ -291,7 +291,8 @@ describe('TreeProcessor', function() {
onComplete: treeComplete,
onException: jasmine.any(Function),
userContext: { root: 'context' },
queueableFns: [{ fn: jasmine.any(Function) }]
queueableFns: [{ fn: jasmine.any(Function) }],
onMultipleDone: null
});
queueRunner.calls.mostRecent().args[0].queueableFns[0].fn('foo');
@@ -321,16 +322,19 @@ describe('TreeProcessor', function() {
onComplete: treeComplete,
onException: jasmine.any(Function),
userContext: { root: 'context' },
queueableFns: [{ fn: jasmine.any(Function) }]
queueableFns: [{ fn: jasmine.any(Function) }],
onMultipleDone: null
});
queueRunner.calls.mostRecent().args[0].queueableFns[0].fn(nodeDone);
expect(queueRunner).toHaveBeenCalledWith({
onComplete: jasmine.any(Function),
onMultipleDone: null,
queueableFns: [{ fn: jasmine.any(Function) }],
userContext: { node: 'context' },
onException: jasmine.any(Function)
onException: jasmine.any(Function),
onMultipleDone: null
});
queueRunner.calls.mostRecent().args[0].queueableFns[0].fn('foo');

View File

@@ -13,27 +13,54 @@ describe('asymmetricEqualityTesterArgCompatShim', function() {
expect(shim.bar).toBe(matchersUtil.bar);
});
it('provides all the properties of the customEqualityTesters', function() {
it('provides and deprecates all the properties of the customEqualityTesters', function() {
var customEqualityTesters = [function() {}, function() {}],
shim = jasmineUnderTest.asymmetricEqualityTesterArgCompatShim(
{},
customEqualityTesters
);
),
deprecated = spyOn(jasmineUnderTest.getEnv(), 'deprecated'),
expectedMessage =
'The second argument to asymmetricMatch is now a MatchersUtil. ' +
'Using it as an array of custom equality testers is deprecated and will stop ' +
'working in a future release. ' +
'See <https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0#asymmetricMatch-cet> for details.';
expect(shim.length).toBe(2);
expect(deprecated).toHaveBeenCalledWith(expectedMessage);
deprecated.calls.reset();
expect(shim[0]).toBe(customEqualityTesters[0]);
expect(deprecated).toHaveBeenCalledWith(expectedMessage);
deprecated.calls.reset();
expect(shim[1]).toBe(customEqualityTesters[1]);
expect(deprecated).toHaveBeenCalledWith(expectedMessage);
});
it('provides all the properties of Array.prototype', function() {
var shim = jasmineUnderTest.asymmetricEqualityTesterArgCompatShim({}, []);
it('provides and deprecates all the properties of Array.prototype', function() {
var shim = jasmineUnderTest.asymmetricEqualityTesterArgCompatShim({}, []),
deprecated = spyOn(jasmineUnderTest.getEnv(), 'deprecated'),
expectedMessage =
'The second argument to asymmetricMatch is now a MatchersUtil. ' +
'Using it as an array of custom equality testers is deprecated and will stop ' +
'working in a future release. ' +
'See <https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0#asymmetricMatch-cet> for details.';
expect(shim.filter).toBe(Array.prototype.filter);
expect(deprecated).toHaveBeenCalledWith(expectedMessage);
deprecated.calls.reset();
expect(shim.forEach).toBe(Array.prototype.forEach);
expect(deprecated).toHaveBeenCalledWith(expectedMessage);
deprecated.calls.reset();
expect(shim.map).toBe(Array.prototype.map);
expect(deprecated).toHaveBeenCalledWith(expectedMessage);
deprecated.calls.reset();
});
it('provides properties of Array.prototype', function() {
it('provides and deprecates properties of Array.prototype', function() {
var keys = [
'concat',
'every',
@@ -69,6 +96,7 @@ describe('asymmetricEqualityTesterArgCompatShim', function() {
'values'
],
shim = jasmineUnderTest.asymmetricEqualityTesterArgCompatShim({}, []),
deprecated = spyOn(jasmineUnderTest.getEnv(), 'deprecated'),
i,
k;
@@ -81,6 +109,8 @@ describe('asymmetricEqualityTesterArgCompatShim', function() {
expect(shim[k])
.withContext(k)
.toBe(Array.prototype[k]);
expect(deprecated).toHaveBeenCalled();
deprecated.calls.reset();
}
// Properties that are present on only some supported runtimes
@@ -91,10 +121,24 @@ describe('asymmetricEqualityTesterArgCompatShim', function() {
expect(shim[k])
.withContext(k)
.toBe(Array.prototype[k]);
expect(deprecated)
.withContext(k)
.toHaveBeenCalled();
deprecated.calls.reset();
}
}
});
it('does not deprecate properties of Object.prototype', function() {
var shim = jasmineUnderTest.asymmetricEqualityTesterArgCompatShim({}, []),
deprecated = spyOn(jasmineUnderTest.getEnv(), 'deprecated');
expect(shim.hasOwnProperty).toBe(Object.prototype.hasOwnProperty);
expect(shim.isPrototypeOf).toBe(Object.prototype.isPrototypeOf);
expect(deprecated).not.toHaveBeenCalled();
});
describe('When Array.prototype additions collide with MatchersUtil methods', function() {
function keys() {
return [
@@ -136,4 +180,18 @@ describe('asymmetricEqualityTesterArgCompatShim', function() {
});
});
});
describe('When the matchersUtil is already an asymmetricEqualityTesterArgCompatShim', function() {
it('does not trigger any deprecations', function() {
var shim1 = jasmineUnderTest.asymmetricEqualityTesterArgCompatShim(
{},
[]
);
spyOn(jasmineUnderTest.getEnv(), 'deprecated');
jasmineUnderTest.asymmetricEqualityTesterArgCompatShim(shim1, []);
expect(jasmineUnderTest.getEnv().deprecated).not.toHaveBeenCalled();
});
});
});

View File

@@ -91,26 +91,22 @@ describe('Custom Async Matchers (Integration)', function() {
env.execute(null, done);
});
// TODO: remove this in the next major release.
it('passes the jasmine utility and current equality testers to the matcher factory', function(done) {
it('passes the jasmine utility to the matcher factory', function(done) {
jasmine.getEnv().requirePromises();
var matcherFactory = function() {
var matcherFactory = function(util) {
return {
compare: function() {
return Promise.resolve({ pass: true });
}
};
},
matcherFactorySpy = jasmine
.createSpy('matcherFactorySpy')
.and.callFake(matcherFactory),
customEqualityFn = function() {
return true;
};
matcherFactorySpy = jasmine.createSpy(
'matcherFactorySpy',
matcherFactory
);
env.it('spec with expectation', function() {
env.addCustomEqualityTester(customEqualityFn);
env.addAsyncMatchers({
toBeReal: matcherFactorySpy
});
@@ -120,8 +116,7 @@ describe('Custom Async Matchers (Integration)', function() {
var specExpectations = function() {
expect(matcherFactorySpy).toHaveBeenCalledWith(
jasmine.any(jasmineUnderTest.MatchersUtil),
[customEqualityFn]
jasmine.any(jasmineUnderTest.MatchersUtil)
);
};
@@ -129,6 +124,53 @@ describe('Custom Async Matchers (Integration)', function() {
env.execute(null, done);
});
// TODO: remove this in the next major release.
describe('When a matcher factory takes at least two arguments', function() {
it('passes the jasmine utility and current equality testers to the matcher factory', function(done) {
jasmine.getEnv().requirePromises();
var matcherFactory = function(util, customTesters) {
return {
compare: function() {
return Promise.resolve({ pass: true });
}
};
},
matcherFactorySpy = jasmine.createSpy(
'matcherFactorySpy',
matcherFactory
),
customEqualityFn = function() {
return true;
};
env.it('spec with expectation', function() {
env.addCustomEqualityTester(customEqualityFn);
env.addAsyncMatchers({
toBeReal: matcherFactorySpy
});
return env.expectAsync(true).toBeReal();
});
var specExpectations = function() {
expect(matcherFactorySpy).toHaveBeenCalledWith(
jasmine.any(jasmineUnderTest.MatchersUtil),
[customEqualityFn]
);
};
spyOn(env, 'deprecated');
env.addReporter({
specDone: specExpectations,
jasmineDone: function() {
done();
}
});
env.execute();
});
});
it('provides custom equality testers to the matcher factory via matchersUtil', function(done) {
jasmine.getEnv().requirePromises();
@@ -164,4 +206,41 @@ describe('Custom Async Matchers (Integration)', function() {
env.addReporter({ specDone: specExpectations });
env.execute(null, done);
});
it('logs a distinct deprecation for each matcher if the matcher factory takes two arguments', function(done) {
var matcherFactory = function(matchersUtil, customEqualityTesters) {
return { compare: function() {} };
};
spyOn(env, 'deprecated');
env.beforeEach(function() {
env.addAsyncMatchers({ toBeFoo: matcherFactory });
env.addAsyncMatchers({ toBeBar: matcherFactory });
});
env.it('a spec', function() {});
env.it('another spec', function() {});
function jasmineDone() {
expect(env.deprecated).toHaveBeenCalledWith(
jasmine.stringMatching(
'The matcher factory for "toBeFoo" accepts custom equality testers, ' +
'but this parameter will no longer be passed in a future release. ' +
'See <https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0#matchers-cet> for details.'
)
);
expect(env.deprecated).toHaveBeenCalledWith(
jasmine.stringMatching(
'The matcher factory for "toBeBar" accepts custom equality testers, ' +
'but this parameter will no longer be passed in a future release. ' +
'See <https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0#matchers-cet> for details.'
)
);
done();
}
env.addReporter({ jasmineDone: jasmineDone });
env.execute();
});
});

View File

@@ -111,6 +111,7 @@ describe('Custom Matchers (Integration)', function() {
it('supports asymmetric equality testers that take a list of custom equality testers', function(done) {
// TODO: remove this in the next major release.
spyOn(jasmineUnderTest, 'getEnv').and.returnValue(env);
spyOn(env, 'deprecated'); // suppress warnings
env.it('spec using custom asymmetric equality tester', function() {
var customEqualityFn = function(a, b) {
@@ -143,6 +144,8 @@ describe('Custom Matchers (Integration)', function() {
});
it('displays an appropriate failure message if a custom equality matcher fails', function(done) {
spyOn(env, 'deprecated');
env.it('spec using custom equality matcher', function() {
var customEqualityFn = function(a, b) {
// "foo" is not equal to anything
@@ -244,9 +247,8 @@ describe('Custom Matchers (Integration)', function() {
env.execute(null, done);
});
// TODO: remove this in the next major release.
it('passes the jasmine utility and current equality testers to the matcher factory', function(done) {
var matcherFactory = function() {
it('passes the jasmine utility to the matcher factory', function(done) {
var matcherFactory = function(util) {
return {
compare: function() {
return { pass: true };
@@ -255,13 +257,9 @@ describe('Custom Matchers (Integration)', function() {
},
matcherFactorySpy = jasmine
.createSpy('matcherFactorySpy')
.and.callFake(matcherFactory),
customEqualityFn = function() {
return true;
};
.and.callFake(matcherFactory);
env.it('spec with expectation', function() {
env.addCustomEqualityTester(customEqualityFn);
env.addMatchers({
toBeReal: matcherFactorySpy
});
@@ -271,8 +269,7 @@ describe('Custom Matchers (Integration)', function() {
var specExpectations = function() {
expect(matcherFactorySpy).toHaveBeenCalledWith(
jasmine.any(jasmineUnderTest.MatchersUtil),
[customEqualityFn]
jasmine.any(jasmineUnderTest.MatchersUtil)
);
};
@@ -280,6 +277,52 @@ describe('Custom Matchers (Integration)', function() {
env.execute(null, done);
});
// TODO: remove this in the next major release.
describe('When a matcher factory takes at least two arguments', function() {
it('passes the jasmine utility and current equality testers to the matcher factory', function(done) {
spyOn(env, 'deprecated');
var matcherFactory = function(util, customTesters) {
return {
compare: function() {
return { pass: true };
}
};
},
matcherFactorySpy = jasmine.createSpy(
'matcherFactorySpy',
matcherFactory
),
customEqualityFn = function() {
return true;
};
env.it('spec with expectation', function() {
env.addCustomEqualityTester(customEqualityFn);
env.addMatchers({
toBeReal: matcherFactorySpy
});
env.expect(true).toBeReal();
});
var specExpectations = function() {
expect(matcherFactorySpy).toHaveBeenCalledWith(
jasmine.any(jasmineUnderTest.MatchersUtil),
[customEqualityFn]
);
};
env.addReporter({
specDone: specExpectations,
jasmineDone: function() {
done();
}
});
env.execute();
});
});
it('provides custom equality testers to the matcher factory via matchersUtil', function(done) {
var matcherFactory = function(matchersUtil) {
return {
@@ -311,4 +354,41 @@ describe('Custom Matchers (Integration)', function() {
env.addReporter({ specDone: specExpectations });
env.execute(null, done);
});
it('logs a distinct deprecation per matcher if the matcher factory takes two arguments', function(done) {
var matcherFactory = function(matchersUtil, customEqualityTesters) {
return { compare: function() {} };
};
spyOn(env, 'deprecated');
env.beforeEach(function() {
env.addMatchers({ toBeFoo: matcherFactory });
env.addMatchers({ toBeBar: matcherFactory });
});
env.it('a spec', function() {});
env.it('another spec', function() {});
function jasmineDone() {
expect(env.deprecated).toHaveBeenCalledWith(
jasmine.stringMatching(
'The matcher factory for "toBeFoo" accepts custom equality testers, ' +
'but this parameter will no longer be passed in a future release. ' +
'See <https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0#matchers-cet> for details.'
)
);
expect(env.deprecated).toHaveBeenCalledWith(
jasmine.stringMatching(
'The matcher factory for "toBeBar" accepts custom equality testers, ' +
'but this parameter will no longer be passed in a future release. ' +
'See <https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0#matchers-cet> for details.'
)
);
done();
}
env.addReporter({ jasmineDone: jasmineDone });
env.execute();
});
});

View File

@@ -0,0 +1,322 @@
/* eslint no-console: 0 */
describe('Deprecation (integration)', function() {
var env;
beforeEach(function() {
env = new jasmineUnderTest.Env();
});
afterEach(function() {
env.cleanup_();
});
it('reports a deprecation on the top suite', function(done) {
var reporter = jasmine.createSpyObj('reporter', ['jasmineDone']);
env.addReporter(reporter);
spyOn(console, 'error');
env.beforeAll(function() {
env.deprecated('the message');
});
env.it('a spec', function() {});
env.execute(null, function() {
expect(reporter.jasmineDone).toHaveBeenCalledWith(
jasmine.objectContaining({
deprecationWarnings: [
jasmine.objectContaining({
message: jasmine.stringMatching(/^the message/)
})
]
})
);
expect(console.error).toHaveBeenCalledWith(
jasmine.stringMatching(/^DEPRECATION: the message/)
);
done();
});
});
it('reports a deprecation on a descendent suite', function(done) {
var reporter = jasmine.createSpyObj('reporter', ['suiteDone']);
env.addReporter(reporter);
spyOn(console, 'error');
env.describe('a suite', function() {
env.beforeAll(function() {
env.deprecated('the message');
});
env.it('a spec', function() {});
});
env.execute(null, function() {
expect(reporter.suiteDone).toHaveBeenCalledWith(
jasmine.objectContaining({
deprecationWarnings: [
jasmine.objectContaining({
message: jasmine.stringMatching(/^the message/)
})
]
})
);
expect(console.error).toHaveBeenCalledWith(
jasmine.stringMatching(
/^DEPRECATION: the message \(in suite: a suite\)/
)
);
done();
});
});
it('reports a deprecation on a spec', function(done) {
var reporter = jasmine.createSpyObj('reporter', ['specDone']);
env.addReporter(reporter);
spyOn(console, 'error');
env.describe('a suite', function() {
env.it('a spec', function() {
env.deprecated('the message');
});
});
env.execute(null, function() {
expect(reporter.specDone).toHaveBeenCalledWith(
jasmine.objectContaining({
deprecationWarnings: [
jasmine.objectContaining({
message: jasmine.stringMatching(/^the message/)
})
]
})
);
expect(console.error).toHaveBeenCalledWith(
jasmine.stringMatching(
/^DEPRECATION: the message \(in spec: a suite a spec\)/
)
);
done();
});
});
it('omits the suite or spec context when ignoreRunnable is true', function(done) {
var reporter = jasmine.createSpyObj('reporter', ['jasmineDone']);
env.addReporter(reporter);
spyOn(console, 'error');
env.it('a spec', function() {
env.deprecated('the message', { ignoreRunnable: true });
});
env.execute(null, function() {
expect(reporter.jasmineDone).toHaveBeenCalledWith(
jasmine.objectContaining({
deprecationWarnings: [
jasmine.objectContaining({
message: jasmine.stringMatching(/^the message/)
})
]
})
);
expect(console.error).toHaveBeenCalledWith(
jasmine.stringMatching(/the message/)
);
expect(console.error).not.toHaveBeenCalledWith(
jasmine.stringMatching(/a spec/)
);
done();
});
});
it('includes the stack trace', function(done) {
var reporter = jasmine.createSpyObj('reporter', ['specDone']);
env.addReporter(reporter);
spyOn(console, 'error');
env.describe('a suite', function() {
env.it('a spec', function() {
env.deprecated('the message');
});
});
env.execute(null, function() {
expect(reporter.specDone).toHaveBeenCalledWith(
jasmine.objectContaining({
deprecationWarnings: [
jasmine.objectContaining({
stack: jasmine.stringMatching(/DeprecationSpec.js/)
})
]
})
);
expect(console.error).toHaveBeenCalled();
expect(console.error.calls.argsFor(0)[0].replace(/\n/g, 'NL')).toMatch(
/^DEPRECATION: the message \(in spec: a suite a spec\)NL.*DeprecationSpec.js/
);
done();
});
});
it('excludes the stack trace when omitStackTrace is true', function(done) {
var reporter = jasmine.createSpyObj('reporter', ['specDone']);
env.addReporter(reporter);
spyOn(console, 'error');
env.describe('a suite', function() {
env.it('a spec', function() {
env.deprecated('the message', { omitStackTrace: true });
});
});
env.execute(null, function() {
expect(reporter.specDone).toHaveBeenCalledWith(
jasmine.objectContaining({
deprecationWarnings: [
jasmine.objectContaining({
stack: jasmine.falsy()
})
]
})
);
expect(console.error).toHaveBeenCalled();
expect(console.error).not.toHaveBeenCalledWith(
jasmine.stringMatching(/DeprecationSpec.js/)
);
done();
});
});
it('emits a given deprecation only once', function(done) {
var reporter = jasmine.createSpyObj('reporter', ['specDone', 'suiteDone']);
env.addReporter(reporter);
spyOn(console, 'error');
env.describe('a suite', function() {
env.beforeAll(function() {
env.deprecated('the message');
env.deprecated('the message');
});
env.it('a spec', function() {
env.deprecated('the message');
env.deprecated('a different message');
});
});
env.execute(null, function() {
expect(reporter.suiteDone).toHaveBeenCalledWith(
jasmine.objectContaining({
deprecationWarnings: [
// only one
jasmine.objectContaining({
message: jasmine.stringMatching(/^the message/)
})
]
})
);
expect(reporter.specDone).toHaveBeenCalledWith(
jasmine.objectContaining({
deprecationWarnings: [
// only the other one
jasmine.objectContaining({
message: jasmine.stringMatching(/^a different message/)
})
]
})
);
expect(console.error).toHaveBeenCalledTimes(2);
expect(console.error).toHaveBeenCalledWith(
jasmine.stringMatching(
/^DEPRECATION: the message \(in suite: a suite\)/
)
);
expect(console.error).toHaveBeenCalledWith(
jasmine.stringMatching(
/^DEPRECATION: a different message \(in spec: a suite a spec\)/
)
);
done();
});
});
it('emits a given deprecation each time when config.verboseDeprecations is true', function(done) {
var reporter = jasmine.createSpyObj('reporter', ['specDone', 'suiteDone']);
env.addReporter(reporter);
spyOn(console, 'error');
env.configure({ verboseDeprecations: true });
env.describe('a suite', function() {
env.beforeAll(function() {
env.deprecated('the message');
env.deprecated('the message');
});
env.it('a spec', function() {
env.deprecated('the message');
});
});
env.execute(null, function() {
expect(reporter.suiteDone).toHaveBeenCalledWith(
jasmine.objectContaining({
deprecationWarnings: [
jasmine.objectContaining({
message: jasmine.stringMatching(/^the message/)
}),
jasmine.objectContaining({
message: jasmine.stringMatching(/^the message/)
})
]
})
);
expect(reporter.specDone).toHaveBeenCalledWith(
jasmine.objectContaining({
deprecationWarnings: [
jasmine.objectContaining({
message: jasmine.stringMatching(/^the message/)
})
]
})
);
expect(console.error).toHaveBeenCalledTimes(3);
expect(console.error.calls.argsFor(0)[0]).toMatch(
/^DEPRECATION: the message \(in suite: a suite\)/
);
expect(console.error.calls.argsFor(1)[0]).toMatch(
/^DEPRECATION: the message \(in suite: a suite\)/
);
expect(console.error.calls.argsFor(2)[0]).toMatch(
/^DEPRECATION: the message \(in spec: a suite a spec\)/
);
expect(console.error.calls.argsFor(2)[0]).toMatch(
/^DEPRECATION: the message \(in spec: a suite a spec\)/
);
done();
});
});
it('handles deprecations that occur before execute() is called', function(done) {
var reporter = jasmine.createSpyObj('reporter', ['jasmineDone']);
env.addReporter(reporter);
spyOn(console, 'error');
env.deprecated('the message');
env.it('a spec', function() {});
env.execute(null, function() {
expect(reporter.jasmineDone).toHaveBeenCalledWith(
jasmine.objectContaining({
deprecationWarnings: [
jasmine.objectContaining({
message: jasmine.stringMatching(/^the message/)
})
]
})
);
expect(console.error).toHaveBeenCalledWith(
jasmine.stringMatching(/^DEPRECATION: the message/)
);
done();
});
});
});

View File

@@ -513,6 +513,200 @@ describe('Env integration', function() {
env.execute(null, assertions);
});
it('deprecates multiple calls to done in the top suite', function(done) {
var reporter = jasmine.createSpyObj('fakeReporter', ['jasmineDone']);
var message =
'A top-level beforeAll or afterAll function called its ' +
"'done' callback more than once. This is a bug in the beforeAll " +
'or afterAll function in question. This will be treated as an ' +
'error in a future version. See' +
'<https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0#deprecations-due-to-calling-done-multiple-times> ' +
'for more information.';
spyOn(console, 'error');
env.addReporter(reporter);
env.configure({ verboseDeprecations: true });
env.beforeAll(function(innerDone) {
innerDone();
innerDone();
});
env.it('a spec, so the beforeAll runs', function() {});
env.afterAll(function(innerDone) {
innerDone();
innerDone();
});
env.execute(null, function() {
var warnings;
expect(reporter.jasmineDone).toHaveBeenCalled();
warnings = reporter.jasmineDone.calls.argsFor(0)[0].deprecationWarnings;
expect(warnings.length).toEqual(2);
expect(warnings[0])
.withContext('top beforeAll')
.toEqual(jasmine.objectContaining({ message: message }));
expect(warnings[1])
.withContext('top afterAll')
.toEqual(jasmine.objectContaining({ message: message }));
done();
});
});
it('deprecates multiple calls to done in a non-top suite', function(done) {
var reporter = jasmine.createSpyObj('fakeReporter', ['jasmineDone']);
var message =
"An asynchronous function called its 'done' " +
'callback more than once. This is a bug in the spec, beforeAll, ' +
'beforeEach, afterAll, or afterEach function in question. This will ' +
'be treated as an error in a future version. See' +
'<https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0#deprecations-due-to-calling-done-multiple-times> ' +
'for more information.';
spyOn(console, 'error');
env.addReporter(reporter);
env.configure({ verboseDeprecations: true });
env.describe('a suite', function() {
env.beforeAll(function(innerDone) {
innerDone();
innerDone();
});
env.it('a spec, so that before/afters run', function() {});
env.afterAll(function(innerDone) {
innerDone();
innerDone();
});
});
env.execute(null, function() {
var warnings;
expect(reporter.jasmineDone).toHaveBeenCalled();
warnings = reporter.jasmineDone.calls.argsFor(0)[0].deprecationWarnings;
expect(warnings.length).toEqual(2);
expect(warnings[0])
.withContext('suite beforeAll')
.toEqual(
jasmine.objectContaining({
message: message + '\n(in suite: a suite)'
})
);
expect(warnings[1])
.withContext('suite afterAll')
.toEqual(
jasmine.objectContaining({
message: message + '\n(in suite: a suite)'
})
);
done();
});
});
it('deprecates multiple calls to done in a spec', function(done) {
var reporter = jasmine.createSpyObj('fakeReporter', ['jasmineDone']);
var message =
"An asynchronous function called its 'done' " +
'callback more than once. This is a bug in the spec, beforeAll, ' +
'beforeEach, afterAll, or afterEach function in question. This will ' +
'be treated as an error in a future version. See' +
'<https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0#deprecations-due-to-calling-done-multiple-times> ' +
'for more information.\n' +
'(in spec: a suite a spec)';
spyOn(console, 'error');
env.addReporter(reporter);
env.configure({ verboseDeprecations: true });
env.describe('a suite', function() {
env.beforeEach(function(innerDone) {
innerDone();
innerDone();
});
env.it('a spec', function(innerDone) {
innerDone();
innerDone();
});
env.afterEach(function(innerDone) {
innerDone();
innerDone();
});
});
env.execute(null, function() {
var warnings;
expect(reporter.jasmineDone).toHaveBeenCalled();
warnings = reporter.jasmineDone.calls.argsFor(0)[0].deprecationWarnings;
expect(warnings.length).toEqual(3);
expect(warnings[0])
.withContext('warning caused by beforeEach')
.toEqual(jasmine.objectContaining({ message: message }));
expect(warnings[1])
.withContext('warning caused by it')
.toEqual(jasmine.objectContaining({ message: message }));
expect(warnings[2])
.withContext('warning caused by afterEach')
.toEqual(jasmine.objectContaining({ message: message }));
done();
});
});
it('deprecates multiple calls to done in reporters', function(done) {
var message =
"An asynchronous reporter callback called its 'done' callback more " +
'than once. This is a bug in the reporter callback in question. This ' +
'will be treated as an error in a future version. See' +
'<https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0#deprecations-due-to-calling-done-multiple-times> ' +
'for more information.\nNote: This message ' +
'will be shown only once. Set the verboseDeprecations config property ' +
'to true to see every occurrence.';
var reporter = jasmine.createSpyObj('fakeReport', ['jasmineDone']);
reporter.specDone = function(result, done) {
done();
done();
};
env.addReporter(reporter);
env.it('a spec', function() {});
spyOn(console, 'error');
env.execute(null, function() {
expect(reporter.jasmineDone).toHaveBeenCalled();
warnings = reporter.jasmineDone.calls.argsFor(0)[0].deprecationWarnings;
expect(warnings.length).toEqual(1);
expect(warnings[0]).toEqual(
jasmine.objectContaining({ message: message })
);
done();
});
});
it('does not deprecate a call to done that comes after a timeout', function(done) {
var reporter = jasmine.createSpyObj('fakeReporter', ['jasmineDone']),
firstSpecDone;
reporter.specDone = function(result, reporterDone) {
setTimeout(function() {
firstSpecDone();
reporterDone();
});
};
env.addReporter(reporter);
env.it(
'a spec',
function(innerDone) {
firstSpecDone = innerDone;
},
1
);
env.execute(null, function() {
expect(reporter.jasmineDone).toHaveBeenCalledWith(
jasmine.objectContaining({
deprecationWarnings: []
})
);
done();
});
});
describe('suiteDone reporting', function() {
it('reports when an afterAll fails an expectation', function(done) {
var reporter = jasmine.createSpyObj('fakeReport', ['suiteDone']);
@@ -1065,6 +1259,42 @@ describe('Env integration', function() {
});
});
it('logs a deprecation warning when the mock clock is ticked reentrantly', function(done) {
var ticked = false,
env = jasmineUnderTest.getEnv();
spyOn(env, 'deprecated');
env.beforeEach(function() {
env.clock.install();
});
env.afterEach(function() {
env.clock.uninstall();
});
env.it('ticks inside tick', function() {
setTimeout(function() {
ticked = true;
env.clock.tick();
}, 1);
env.clock.tick(1);
});
env.execute(null, function() {
expect(ticked).toBeTrue();
expect(env.deprecated).toHaveBeenCalledWith(
'The behavior of reentrant calls to jasmine.clock().tick() will ' +
'change in a future version. Either modify the affected spec to ' +
'not call tick() from within a setTimeout or setInterval handler, ' +
'or be aware that it may behave differently in the future. See ' +
'<https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0#deprecations-due-to-reentrant-calls-to-jasmine-clock-tick> ' +
'for details.'
);
done();
});
});
it('should run async specs in order, waiting for them to complete', function(done) {
var mutatedVar;
@@ -1964,6 +2194,7 @@ describe('Env integration', function() {
} catch (e) {
exception = e;
}
env.it('has a test', function() {});
});
env.execute(null, function() {
@@ -1988,6 +2219,7 @@ describe('Env integration', function() {
} catch (e) {
exception = e;
}
env.it('has a test', function() {});
});
env.execute(null, function() {
@@ -2010,6 +2242,7 @@ describe('Env integration', function() {
} catch (e) {
exception = e;
}
env.it('has a test', function() {});
});
env.execute(null, function() {
@@ -2516,7 +2749,7 @@ describe('Env integration', function() {
return setTimeout(fn, delay);
},
clearTimeout: function(fn, delay) {
clearTimeout(fn, delay);
return clearTimeout(fn, delay);
}
};
spyOn(jasmineUnderTest, 'getGlobal').and.returnValue(global);
@@ -2623,70 +2856,6 @@ describe('Env integration', function() {
});
});
it('should report deprecation warnings on the correct specs and suites', function(done) {
var reporter = jasmine.createSpyObj('reporter', [
'jasmineDone',
'suiteDone',
'specDone'
]);
// prevent deprecation from being displayed, as well as letting us observe calls
spyOn(console, 'error');
env.addReporter(reporter);
env.deprecated('top level deprecation');
env.describe('suite', function() {
env.beforeAll(function() {
env.deprecated('suite level deprecation');
});
env.it('spec', function() {
env.deprecated('spec level deprecation');
});
});
env.execute(null, function() {
var result = reporter.jasmineDone.calls.argsFor(0)[0];
expect(result.deprecationWarnings).toEqual([
jasmine.objectContaining({ message: 'top level deprecation' })
]);
/* eslint-disable-next-line no-console */
expect(console.error).toHaveBeenCalledWith(
'DEPRECATION: top level deprecation'
);
expect(reporter.suiteDone).toHaveBeenCalledWith(
jasmine.objectContaining({
fullName: 'suite',
deprecationWarnings: [
jasmine.objectContaining({ message: 'suite level deprecation' })
]
})
);
/* eslint-disable-next-line no-console */
expect(console.error).toHaveBeenCalledWith(
'DEPRECATION: suite level deprecation (in suite: suite)'
);
expect(reporter.specDone).toHaveBeenCalledWith(
jasmine.objectContaining({
fullName: 'suite spec',
deprecationWarnings: [
jasmine.objectContaining({ message: 'spec level deprecation' })
]
})
);
/* eslint-disable-next-line no-console */
expect(console.error).toHaveBeenCalledWith(
'DEPRECATION: spec level deprecation (in spec: suite spec)'
);
done();
});
});
it('should report deprecation stack with an error object', function(done) {
var exceptionFormatter = new jasmineUnderTest.ExceptionFormatter(),
reporter = jasmine.createSpyObj('reporter', [

View File

@@ -550,10 +550,17 @@ describe('spec running', function() {
var pendingSpec,
suite = env.describe('default current suite', function() {
pendingSpec = env.it('I am a pending spec');
});
}),
reporter = jasmine.createSpyObj('reporter', ['specDone']);
env.addReporter(reporter);
env.execute(null, function() {
expect(pendingSpec.status()).toBe('pending');
expect(reporter.specDone).toHaveBeenCalledWith(
jasmine.objectContaining({
status: 'pending'
})
);
done();
});
});
@@ -785,7 +792,7 @@ describe('spec running', function() {
});
});
describe('When throwOnExpectationFailure is set', function() {
describe('When stopSpecOnExpectationFailure is set', function() {
it('skips to cleanup functions after an error', function(done) {
var actions = [];
@@ -814,7 +821,7 @@ describe('spec running', function() {
});
});
env.configure({ oneFailurePerSpec: true });
env.configure({ stopSpecOnExpectationFailure: true });
env.execute(null, function() {
expect(actions).toEqual([
@@ -845,7 +852,7 @@ describe('spec running', function() {
});
});
env.configure({ oneFailurePerSpec: true });
env.configure({ stopSpecOnExpectationFailure: true });
env.execute(null, function() {
expect(actions).toEqual(['beforeEach', 'afterEach']);
@@ -870,7 +877,7 @@ describe('spec running', function() {
});
});
env.configure({ oneFailurePerSpec: true });
env.configure({ stopSpecOnExpectationFailure: true });
env.execute(null, function() {
expect(actions).toEqual(['beforeEach', 'afterEach']);
@@ -1010,6 +1017,7 @@ describe('spec running', function() {
describe('when failFast is on', function() {
behavesLikeStopOnSpecFailureIsOn(function(env) {
spyOn(env, 'deprecated');
env.configure({ failFast: true });
});
});

View File

@@ -434,6 +434,8 @@ describe('matchersUtil', function() {
},
matchersUtil = new jasmineUnderTest.MatchersUtil();
spyOn(jasmineUnderTest.getEnv(), 'deprecated'); // suppress warning
expect(matchersUtil.equals(1, 2, [tester])).toBe(true);
});
@@ -462,6 +464,7 @@ describe('matchersUtil', function() {
it('passes for two empty Objects', function() {
var matchersUtil = new jasmineUnderTest.MatchersUtil();
spyOn(jasmineUnderTest.getEnv(), 'deprecated'); // suppress warning
expect(matchersUtil.equals({}, {}, [tester])).toBe(true);
});
});
@@ -487,6 +490,8 @@ describe('matchersUtil', function() {
},
matchersUtil = new jasmineUnderTest.MatchersUtil();
spyOn(jasmineUnderTest.getEnv(), 'deprecated'); // suppress warning
expect(matchersUtil.equals(1, 1, [tester])).toBe(false);
});
@@ -514,6 +519,8 @@ describe('matchersUtil', function() {
},
matchersUtil = new jasmineUnderTest.MatchersUtil();
spyOn(jasmineUnderTest.getEnv(), 'deprecated'); // suppress warning
expect(
matchersUtil.equals(asymmetricTester, true, [symmetricTester])
).toBe(true);
@@ -550,6 +557,7 @@ describe('matchersUtil', function() {
matchersUtil = new jasmineUnderTest.MatchersUtil(),
shim;
spyOn(jasmineUnderTest.getEnv(), 'deprecated'); // suppress warning
matchersUtil.equals(true, asymmetricTester, [symmetricTester]);
shim = asymmetricTester.asymmetricMatch.calls.argsFor(0)[1];
expect(shim).toEqual(jasmine.any(jasmineUnderTest.MatchersUtil));
@@ -570,6 +578,7 @@ describe('matchersUtil', function() {
}),
shim;
spyOn(jasmineUnderTest.getEnv(), 'deprecated'); // suppress warning
matchersUtil.equals(true, asymmetricTester);
shim = asymmetricTester.asymmetricMatch.calls.argsFor(0)[1];
expect(shim).toEqual(jasmine.any(jasmineUnderTest.MatchersUtil));
@@ -817,7 +826,8 @@ describe('matchersUtil', function() {
jasmine.getEnv().requireFunctioningArrayBuffers();
var buffer1 = new ArrayBuffer(4); // eslint-disable-line compat/compat
var buffer2 = new ArrayBuffer(4); // eslint-disable-line compat/compat
expect(jasmineUnderTest.matchersUtil.equals(buffer1, buffer2)).toBe(true);
var matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(matchersUtil.equals(buffer1, buffer2)).toBe(true);
});
it('fails for ArrayBuffers with same length but different content', function() {
@@ -826,19 +836,19 @@ describe('matchersUtil', function() {
var buffer2 = new ArrayBuffer(4); // eslint-disable-line compat/compat
var array1 = new Uint8Array(buffer1); // eslint-disable-line compat/compat
array1[0] = 1;
expect(jasmineUnderTest.matchersUtil.equals(buffer1, buffer2)).toBe(
false
);
var matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(matchersUtil.equals(buffer1, buffer2)).toBe(false);
});
describe('Typed arrays', function() {
it('fails for typed arrays of same length and contents but different types', function() {
var matchersUtil = new jasmineUnderTest.MatchersUtil();
// eslint-disable-next-line compat/compat
var a1 = new Int8Array(1);
// eslint-disable-next-line compat/compat
var a2 = new Uint8Array(1);
a1[0] = a2[0] = 0;
expect(jasmineUnderTest.matchersUtil.equals(a1, a2)).toBe(false);
expect(matchersUtil.equals(a1, a2)).toBe(false);
});
// eslint-disable-next-line compat/compat
@@ -867,41 +877,45 @@ describe('matchersUtil', function() {
'passes for ' + typeName + 's with same length and content',
function() {
var TypedArrayCtor = requireType();
var matchersUtil = new jasmineUnderTest.MatchersUtil();
var a1 = new TypedArrayCtor(2);
var a2 = new TypedArrayCtor(2);
a1[0] = a2[0] = 0;
a1[1] = a2[1] = 1;
expect(jasmineUnderTest.matchersUtil.equals(a1, a2)).toBe(true);
expect(matchersUtil.equals(a1, a2)).toBe(true);
}
);
it('fails for ' + typeName + 's with different length', function() {
var TypedArrayCtor = requireType();
var matchersUtil = new jasmineUnderTest.MatchersUtil();
var a1 = new TypedArrayCtor(2);
var a2 = new TypedArrayCtor(1);
a1[0] = a1[1] = a2[0] = 0;
expect(jasmineUnderTest.matchersUtil.equals(a1, a2)).toBe(false);
expect(matchersUtil.equals(a1, a2)).toBe(false);
});
it(
'fails for ' + typeName + 's with same length but different content',
function() {
var TypedArrayCtor = requireType();
var matchersUtil = new jasmineUnderTest.MatchersUtil();
var a1 = new TypedArrayCtor(1);
var a2 = new TypedArrayCtor(1);
a1[0] = 0;
a2[0] = 1;
expect(jasmineUnderTest.matchersUtil.equals(a1, a2)).toBe(false);
expect(matchersUtil.equals(a1, a2)).toBe(false);
}
);
it('checks nonstandard properties of ' + typeName, function() {
var TypedArrayCtor = requireType();
var matchersUtil = new jasmineUnderTest.MatchersUtil();
var a1 = new TypedArrayCtor(1);
var a2 = new TypedArrayCtor(1);
a1[0] = a2[0] = 0;
a1.extra = 'yes';
expect(jasmineUnderTest.matchersUtil.equals(a1, a2)).toBe(false);
expect(matchersUtil.equals(a1, a2)).toBe(false);
});
it('works with custom equality testers with ' + typeName, function() {
@@ -936,36 +950,39 @@ describe('matchersUtil', function() {
'passes for ' + typeName + 's with same length and content',
function() {
var TypedArrayCtor = requireType();
var matchersUtil = new jasmineUnderTest.MatchersUtil();
var a1 = new TypedArrayCtor(2);
var a2 = new TypedArrayCtor(2);
// eslint-disable-next-line compat/compat
a1[0] = a2[0] = BigInt(0);
// eslint-disable-next-line compat/compat
a1[1] = a2[1] = BigInt(1);
expect(jasmineUnderTest.matchersUtil.equals(a1, a2)).toBe(true);
expect(matchersUtil.equals(a1, a2)).toBe(true);
}
);
it('fails for ' + typeName + 's with different length', function() {
var TypedArrayCtor = requireType();
var matchersUtil = new jasmineUnderTest.MatchersUtil();
var a1 = new TypedArrayCtor(2);
var a2 = new TypedArrayCtor(1);
// eslint-disable-next-line compat/compat
a1[0] = a1[1] = a2[0] = BigInt(0);
expect(jasmineUnderTest.matchersUtil.equals(a1, a2)).toBe(false);
expect(matchersUtil.equals(a1, a2)).toBe(false);
});
it(
'fails for ' + typeName + 's with same length but different content',
function() {
var TypedArrayCtor = requireType();
var matchersUtil = new jasmineUnderTest.MatchersUtil();
var a1 = new TypedArrayCtor(2);
var a2 = new TypedArrayCtor(2);
// eslint-disable-next-line compat/compat
a1[0] = a1[1] = a2[0] = BigInt(0);
// eslint-disable-next-line compat/compat
a2[1] = BigInt(1);
expect(jasmineUnderTest.matchersUtil.equals(a1, a2)).toBe(false);
expect(matchersUtil.equals(a1, a2)).toBe(false);
}
);
});
@@ -1043,12 +1060,13 @@ describe('matchersUtil', function() {
'recordMismatch',
'withPath',
'setRoots'
]);
]),
matchersUtil = new jasmineUnderTest.MatchersUtil();
diffBuilder.withPath.and.callFake(function(p, block) {
block();
});
jasmineUnderTest.matchersUtil.equals(actual, expected, [], diffBuilder);
matchersUtil.equals(actual, expected, diffBuilder);
expect(diffBuilder.setRoots).toHaveBeenCalledWith(actual, expected);
expect(diffBuilder.withPath).toHaveBeenCalledWith(
@@ -1070,11 +1088,13 @@ describe('matchersUtil', function() {
'recordMismatch',
'withPath',
'setRoots'
]);
]),
matchersUtil = new jasmineUnderTest.MatchersUtil();
diffBuilder.withPath.and.callFake(function(p, block) {
block();
});
jasmineUnderTest.matchersUtil.equals(actual, expected, [], diffBuilder);
matchersUtil.equals(actual, expected, diffBuilder);
expect(diffBuilder.setRoots).toHaveBeenCalledWith(actual, expected);
expect(diffBuilder.withPath).toHaveBeenCalledWith(
@@ -1085,11 +1105,42 @@ describe('matchersUtil', function() {
});
});
it('logs a deprecation warning when custom equality testers are passed', function() {
var matchersUtil = new jasmineUnderTest.MatchersUtil(),
deprecated = spyOn(jasmineUnderTest.getEnv(), 'deprecated');
matchersUtil.equals(0, 0, []);
expect(deprecated).toHaveBeenCalledWith(
jasmine.stringMatching(
'Passing custom equality testers ' +
'to MatchersUtil#equals is deprecated. ' +
'See <https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0#matchers-cet> for details.'
)
);
});
it('logs a deprecation warning when a diffBuilder is provided as the fourth argument', function() {
var matchersUtil = new jasmineUnderTest.MatchersUtil(),
deprecated = spyOn(jasmineUnderTest.getEnv(), 'deprecated');
matchersUtil.equals(0, 0, null, new jasmineUnderTest.NullDiffBuilder());
expect(deprecated).toHaveBeenCalledWith(
jasmine.stringMatching(
'Diff builder should be passed as the ' +
'third argument to MatchersUtil#equals, not the fourth. ' +
'See <https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0#matchers-cet> for details.'
)
);
});
it('uses a diffBuilder if one is provided as the fourth argument', function() {
// TODO: remove this in the next major release.
var diffBuilder = new jasmineUnderTest.DiffBuilder(),
matchersUtil = new jasmineUnderTest.MatchersUtil();
spyOn(jasmineUnderTest.getEnv(), 'deprecated'); // suppress warning
spyOn(diffBuilder, 'recordMismatch');
spyOn(diffBuilder, 'withPath').and.callThrough();
@@ -1159,9 +1210,17 @@ describe('matchersUtil', function() {
var customTester = function(a, b) {
return true;
},
matchersUtil = new jasmineUnderTest.MatchersUtil();
matchersUtil = new jasmineUnderTest.MatchersUtil(),
deprecated = spyOn(jasmineUnderTest.getEnv(), 'deprecated');
expect(matchersUtil.contains([1, 2], 3, [customTester])).toBe(true);
expect(deprecated).toHaveBeenCalledWith(
jasmine.stringMatching(
'Passing custom equality testers to MatchersUtil#contains is deprecated. ' +
'See <https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0#matchers-cet> for details.'
)
);
});
it('uses custom equality testers if passed to the constructor and actual is an Array', function() {
@@ -1176,6 +1235,22 @@ describe('matchersUtil', function() {
expect(matchersUtil.contains([1, 2], 3)).toBe(true);
});
it('logs a single deprecation warning when custom equality testers are passed', function() {
// TODO: remove this in the next major release.
var matchersUtil = new jasmineUnderTest.MatchersUtil(),
deprecated = spyOn(jasmineUnderTest.getEnv(), 'deprecated');
matchersUtil.contains([0], 0, []);
expect(deprecated).toHaveBeenCalledOnceWith(
jasmine.stringMatching(
'Passing custom equality testers ' +
'to MatchersUtil#contains is deprecated. ' +
'See <https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0#matchers-cet> for details.'
)
);
});
it('fails when actual is undefined', function() {
var matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(matchersUtil.contains(undefined, 'A')).toBe(false);

View File

@@ -0,0 +1,17 @@
/* eslint-disable compat/compat */
(function(env) {
function hasProxyConstructor() {
try {
new Proxy({}, {});
return true;
} catch (e) {
return false;
}
}
env.requireProxy = function() {
if (!hasProxyConstructor()) {
env.pending('Environment does not support Proxy');
}
};
})(jasmine.getEnv());

View File

@@ -42,9 +42,9 @@
: 'Expected runnable "' +
fullName +
'" to have failures ' +
jasmine.pp(expectedFailures) +
jasmine.basicPrettyPrinter_(expectedFailures) +
' but it had ' +
jasmine.pp(foundFailures)
jasmine.basicPrettyPrinter_(foundFailures)
};
}
};

4
spec/helpers/resetEnv.js Normal file
View File

@@ -0,0 +1,4 @@
beforeEach(function() {
// env is stateful. Ensure that it does not leak between tests.
jasmineUnderTest.currentEnv_ = null;
});

View File

@@ -303,6 +303,128 @@ describe('HtmlReporter', function() {
expect(alertBars[3].innerHTML).toMatch(/global deprecation/);
expect(alertBars[3].innerHTML).not.toMatch(/in /);
});
it('displays expandable stack traces', function() {
var container = document.createElement('div'),
getContainer = function() {
return container;
},
reporter = new jasmineUnderTest.HtmlReporter({
env: env,
getContainer: getContainer,
createElement: function() {
return document.createElement.apply(document, arguments);
},
createTextNode: function() {
return document.createTextNode.apply(document, arguments);
}
}),
expander,
expanderLink,
expanderContents;
reporter.initialize();
reporter.jasmineStarted({});
reporter.jasmineDone({
deprecationWarnings: [
{
message: 'a deprecation',
stack: 'a stack trace'
}
],
failedExpectations: []
});
expander = container.querySelector(
'.jasmine-alert .jasmine-bar .jasmine-expander'
);
expanderContents = expander.querySelector('.jasmine-expander-contents');
expect(expanderContents.textContent).toMatch(/a stack trace/);
expanderLink = expander.querySelector('a');
expect(expander).not.toHaveClass('jasmine-expanded');
expect(expanderLink.textContent).toMatch(/Show stack trace/);
expanderLink.click();
expect(expander).toHaveClass('jasmine-expanded');
expect(expanderLink.textContent).toMatch(/Hide stack trace/);
expanderLink.click();
expect(expander).not.toHaveClass('jasmine-expanded');
expect(expanderLink.textContent).toMatch(/Show stack trace/);
});
it('omits the expander when there is no stack trace', function() {
var container = document.createElement('div'),
getContainer = function() {
return container;
},
reporter = new jasmineUnderTest.HtmlReporter({
env: env,
getContainer: getContainer,
createElement: function() {
return document.createElement.apply(document, arguments);
},
createTextNode: function() {
return document.createTextNode.apply(document, arguments);
}
}),
warningBar;
reporter.initialize();
reporter.jasmineStarted({});
reporter.jasmineDone({
deprecationWarnings: [
{
message: 'a deprecation',
stack: ''
}
],
failedExpectations: []
});
warningBar = container.querySelector('.jasmine-warning');
expect(warningBar.querySelector('.jasmine-expander')).toBeFalsy();
});
it('nicely formats the verboseDeprecations note', function() {
var container = document.createElement('div'),
getContainer = function() {
return container;
},
reporter = new jasmineUnderTest.HtmlReporter({
env: env,
getContainer: getContainer,
createElement: function() {
return document.createElement.apply(document, arguments);
},
createTextNode: function() {
return document.createTextNode.apply(document, arguments);
}
}),
alertBar;
reporter.initialize();
reporter.jasmineStarted({});
reporter.jasmineDone({
deprecationWarnings: [
{
message:
'a deprecation\nNote: This message will be shown only once. Set config.verboseDeprecations to true to see every occurrence.'
}
],
failedExpectations: []
});
alertBar = container.querySelector('.jasmine-warning');
expect(alertBar.innerHTML).toMatch(
/a deprecation<br>Note: This message will be shown only once/
);
});
});
describe('when Jasmine is done', function() {

View File

@@ -22,13 +22,15 @@ module.exports = {
'helpers/BrowserFlags.js',
'helpers/checkForArrayBuffer.js',
'helpers/checkForMap.js',
'helpers/checkForProxy.js',
'helpers/checkForSet.js',
'helpers/checkForSymbol.js',
'helpers/checkForUrl.js',
'helpers/domHelpers.js',
'helpers/integrationMatchers.js',
'helpers/promises.js',
'helpers/defineJasmineUnderTest.js'
'helpers/defineJasmineUnderTest.js',
'helpers/resetEnv.js'
],
random: true,
browser: {

View File

@@ -9,6 +9,7 @@
"helpers/generator.js",
"helpers/checkForArrayBuffer.js",
"helpers/checkForMap.js",
"helpers/checkForProxy.js",
"helpers/checkForSet.js",
"helpers/checkForSymbol.js",
"helpers/checkForUrl.js",
@@ -16,7 +17,8 @@
"helpers/integrationMatchers.js",
"helpers/promises.js",
"helpers/overrideConsoleLogForCircleCi.js",
"helpers/nodeDefineJasmineUnderTest.js"
"helpers/nodeDefineJasmineUnderTest.js",
"helpers/resetEnv.js"
],
"random": true
}

View File

@@ -6,13 +6,31 @@ getJasmineRequireObj().DelayedFunctionScheduler = function(j$) {
var currentTime = 0;
var delayedFnCount = 0;
var deletedKeys = [];
var ticking = false;
self.tick = function(millis, tickDate) {
millis = millis || 0;
var endTime = currentTime + millis;
if (ticking) {
j$.getEnv().deprecated(
'The behavior of reentrant calls to jasmine.clock().tick() will ' +
'change in a future version. Either modify the affected spec to ' +
'not call tick() from within a setTimeout or setInterval handler, ' +
'or be aware that it may behave differently in the future. See ' +
'<https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0#deprecations-due-to-reentrant-calls-to-jasmine-clock-tick> ' +
'for details.'
);
}
runScheduledFunctions(endTime, tickDate);
currentTime = endTime;
ticking = true;
try {
millis = millis || 0;
var endTime = currentTime + millis;
runScheduledFunctions(endTime, tickDate);
currentTime = endTime;
} finally {
ticking = false;
}
};
self.scheduleFunction = function(

90
src/core/Deprecator.js Normal file
View File

@@ -0,0 +1,90 @@
getJasmineRequireObj().Deprecator = function(j$) {
function Deprecator(topSuite) {
this.topSuite_ = topSuite;
this.verbose_ = false;
this.toSuppress_ = [];
}
var verboseNote =
'Note: This message will be shown only once. Set the verboseDeprecations ' +
'config property to true to see every occurrence.';
Deprecator.prototype.verboseDeprecations = function(enabled) {
this.verbose_ = enabled;
};
// runnable is a spec or a suite.
// deprecation is a string or an Error.
// See Env#deprecated for a description of the options argument.
Deprecator.prototype.addDeprecationWarning = function(
runnable,
deprecation,
options
) {
options = options || {};
if (!this.verbose_ && !j$.isError_(deprecation)) {
if (this.toSuppress_.indexOf(deprecation) !== -1) {
return;
}
this.toSuppress_.push(deprecation);
}
this.log_(runnable, deprecation, options);
this.report_(runnable, deprecation, options);
};
Deprecator.prototype.log_ = function(runnable, deprecation, options) {
var context;
if (j$.isError_(deprecation)) {
console.error(deprecation);
return;
}
if (runnable === this.topSuite_ || options.ignoreRunnable) {
context = '';
} else if (runnable.children) {
context = ' (in suite: ' + runnable.getFullName() + ')';
} else {
context = ' (in spec: ' + runnable.getFullName() + ')';
}
if (!options.omitStackTrace) {
context += '\n' + this.stackTrace_();
}
if (!this.verbose_) {
context += '\n' + verboseNote;
}
console.error('DEPRECATION: ' + deprecation + context);
};
Deprecator.prototype.stackTrace_ = function() {
var formatter = new j$.ExceptionFormatter();
return formatter.stack(j$.util.errorWithStack()).replace(/^Error\n/m, '');
};
Deprecator.prototype.report_ = function(runnable, deprecation, options) {
if (options.ignoreRunnable) {
runnable = this.topSuite_;
}
if (j$.isError_(deprecation)) {
runnable.addDeprecationWarning(deprecation);
return;
}
if (!this.verbose_) {
deprecation += '\n' + verboseNote;
}
runnable.addDeprecationWarning({
message: deprecation,
omitStackTrace: options.omitStackTrace || false
});
};
return Deprecator;
};

View File

@@ -137,6 +137,8 @@ getJasmineRequireObj().Env = function(j$) {
* @since 3.5.0
* @type function
* @default undefined
* @deprecated In a future version, Jasmine will ignore the Promise config
* property and always create native promises instead.
*/
Promise: undefined,
/**
@@ -147,7 +149,19 @@ getJasmineRequireObj().Env = function(j$) {
* @type boolean
* @default true
*/
autoCleanClosures: true
autoCleanClosures: true,
/**
* Whether or not to issue warnings for certain deprecated functionality
* every time it's used. If not set or set to false, deprecation warnings
* for methods that tend to be called frequently will be issued only once
* or otherwise throttled to to prevent the suite output from being flooded
* with warnings.
* @name Configuration#verboseDeprecations
* @since 3.6.0
* @type Boolean
* @default false
*/
verboseDeprecations: false
};
var currentSuite = function() {
@@ -211,6 +225,18 @@ getJasmineRequireObj().Env = function(j$) {
});
if (typeof configuration.failFast !== 'undefined') {
// We can't unconditionally issue a warning here because then users who
// get the configuration from Jasmine, modify it, and pass it back would
// see the warning.
if (configuration.failFast !== config.failFast) {
this.deprecated(
'The `failFast` config property is deprecated and will be removed ' +
'in a future version of Jasmine. Please use `stopOnSpecFailure` ' +
'instead.',
{ ignoreRunnable: true }
);
}
if (typeof configuration.stopOnSpecFailure !== 'undefined') {
if (configuration.stopOnSpecFailure !== configuration.failFast) {
throw new Error(
@@ -228,6 +254,18 @@ getJasmineRequireObj().Env = function(j$) {
}
if (typeof configuration.oneFailurePerSpec !== 'undefined') {
// We can't unconditionally issue a warning here because then users who
// get the configuration from Jasmine, modify it, and pass it back would
// see the warning.
if (configuration.oneFailurePerSpec !== config.oneFailurePerSpec) {
this.deprecated(
'The `oneFailurePerSpec` config property is deprecated and will be ' +
'removed in a future version of Jasmine. Please use ' +
'`stopSpecOnExpectationFailure` instead.',
{ ignoreRunnable: true }
);
}
if (typeof configuration.stopSpecOnExpectationFailure !== 'undefined') {
if (
configuration.stopSpecOnExpectationFailure !==
@@ -267,12 +305,22 @@ getJasmineRequireObj().Env = function(j$) {
typeof configuration.Promise.reject === 'function'
) {
customPromise = configuration.Promise;
self.deprecated(
'The `Promise` config property is deprecated. Future versions ' +
'of Jasmine will create native promises even if the `Promise` ' +
'config property is set. Please remove it.'
);
} else {
throw new Error(
'Custom promise library missing `resolve`/`reject` functions'
);
}
}
if (configuration.hasOwnProperty('verboseDeprecations')) {
config.verboseDeprecations = configuration.verboseDeprecations;
deprecator.verboseDeprecations(config.verboseDeprecations);
}
};
/**
@@ -293,13 +341,19 @@ getJasmineRequireObj().Env = function(j$) {
Object.defineProperty(this, 'specFilter', {
get: function() {
self.deprecated(
'Getting specFilter directly from Env is deprecated and will be removed in a future version of Jasmine, please check the specFilter option from `configuration`'
'Getting specFilter directly from Env is deprecated and will be ' +
'removed in a future version of Jasmine. Please check the ' +
'specFilter option from `configuration` instead.',
{ ignoreRunnable: true }
);
return config.specFilter;
},
set: function(val) {
self.deprecated(
'Setting specFilter directly on Env is deprecated and will be removed in a future version of Jasmine, please use the specFilter option in `configure`'
'Setting specFilter directly on Env is deprecated and will be ' +
'removed in a future version of Jasmine. Please use the ' +
'specFilter option in `configure` instead.',
{ ignoreRunnable: true }
);
config.specFilter = val;
}
@@ -346,6 +400,17 @@ getJasmineRequireObj().Env = function(j$) {
runnableResources[currentRunnable().id].customMatchers;
for (var matcherName in matchersToAdd) {
if (matchersToAdd[matcherName].length > 1) {
self.deprecated(
'The matcher factory for "' +
matcherName +
'" ' +
'accepts custom equality testers, but this parameter will no longer be ' +
'passed in a future release. ' +
'See <https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0#matchers-cet> for details.'
);
}
customMatchers[matcherName] = matchersToAdd[matcherName];
}
};
@@ -360,6 +425,17 @@ getJasmineRequireObj().Env = function(j$) {
runnableResources[currentRunnable().id].customAsyncMatchers;
for (var matcherName in matchersToAdd) {
if (matchersToAdd[matcherName].length > 1) {
self.deprecated(
'The matcher factory for "' +
matcherName +
'" ' +
'accepts custom equality testers, but this parameter will no longer be ' +
'passed in a future release. ' +
'See <https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0#matchers-cet> for details.'
);
}
customAsyncMatchers[matcherName] = matchersToAdd[matcherName];
}
};
@@ -562,7 +638,8 @@ getJasmineRequireObj().Env = function(j$) {
this.deprecated(
'Setting throwOnExpectationFailure directly on Env is deprecated and ' +
'will be removed in a future version of Jasmine. Please use the ' +
'stopSpecOnExpectationFailure option in `configure`.'
'stopSpecOnExpectationFailure option in `configure`.',
{ ignoreRunnable: true }
);
this.configure({ oneFailurePerSpec: !!value });
};
@@ -571,7 +648,8 @@ getJasmineRequireObj().Env = function(j$) {
this.deprecated(
'Getting throwingExpectationFailures directly from Env is deprecated ' +
'and will be removed in a future version of Jasmine. Please check ' +
'the stopSpecOnExpectationFailure option from `configuration`.'
'the stopSpecOnExpectationFailure option from `configuration`.',
{ ignoreRunnable: true }
);
return config.oneFailurePerSpec;
};
@@ -588,7 +666,8 @@ getJasmineRequireObj().Env = function(j$) {
this.deprecated(
'Setting stopOnSpecFailure directly is deprecated and will be ' +
'removed in a future version of Jasmine. Please use the ' +
'stopOnSpecFailure option in `configure`.'
'stopOnSpecFailure option in `configure`.',
{ ignoreRunnable: true }
);
this.configure({ stopOnSpecFailure: !!value });
};
@@ -597,7 +676,8 @@ getJasmineRequireObj().Env = function(j$) {
this.deprecated(
'Getting stoppingOnSpecFailure directly from Env is deprecated and ' +
'will be removed in a future version of Jasmine. Please check the ' +
'stopOnSpecFailure option from `configuration`.'
'stopOnSpecFailure option from `configuration`.',
{ ignoreRunnable: true }
);
return config.failFast;
};
@@ -612,14 +692,20 @@ getJasmineRequireObj().Env = function(j$) {
*/
this.randomizeTests = function(value) {
this.deprecated(
'Setting randomizeTests directly is deprecated and will be removed in a future version of Jasmine, please use the random option in `configure`'
'Setting randomizeTests directly is deprecated and will be removed ' +
'in a future version of Jasmine. Please use the random option in ' +
'`configure` instead.',
{ ignoreRunnable: true }
);
config.random = !!value;
};
this.randomTests = function() {
this.deprecated(
'Getting randomTests directly from Env is deprecated and will be removed in a future version of Jasmine, please check the random option from `configuration`'
'Getting randomTests directly from Env is deprecated and will be ' +
'removed in a future version of Jasmine. Please check the random ' +
'option from `configuration` instead.',
{ ignoreRunnable: true }
);
return config.random;
};
@@ -634,7 +720,10 @@ getJasmineRequireObj().Env = function(j$) {
*/
this.seed = function(value) {
this.deprecated(
'Setting seed directly is deprecated and will be removed in a future version of Jasmine, please use the seed option in `configure`'
'Setting seed directly is deprecated and will be removed in a ' +
'future version of Jasmine. Please use the seed option in ' +
'`configure` instead.',
{ ignoreRunnable: true }
);
if (value) {
config.seed = value;
@@ -644,7 +733,10 @@ getJasmineRequireObj().Env = function(j$) {
this.hidingDisabled = function(value) {
this.deprecated(
'Getting hidingDisabled directly from Env is deprecated and will be removed in a future version of Jasmine, please check the hideDisabled option from `configuration`'
'Getting hidingDisabled directly from Env is deprecated and will ' +
'be removed in a future version of Jasmine. Please check the ' +
'hideDisabled option from `configuration` instead.',
{ ignoreRunnable: true }
);
return config.hideDisabled;
};
@@ -657,30 +749,39 @@ getJasmineRequireObj().Env = function(j$) {
*/
this.hideDisabled = function(value) {
this.deprecated(
'Setting hideDisabled directly is deprecated and will be removed in a future version of Jasmine, please use the hideDisabled option in `configure`'
'Setting hideDisabled directly is deprecated and will be removed ' +
'in a future version of Jasmine. Please use the hideDisabled option ' +
'in `configure` instead.',
{ ignoreRunnable: true }
);
config.hideDisabled = !!value;
};
this.deprecated = function(deprecation) {
/**
* Causes a deprecation warning to be logged to the console and reported to
* reporters.
*
* The optional second parameter is an object that can have either of the
* following properties:
*
* omitStackTrace: Whether to omit the stack trace. Optional. Defaults to
* false. This option is ignored if the deprecation is an Error. Set this
* when the stack trace will not contain anything that helps the user find
* the source of the deprecation.
*
* ignoreRunnable: Whether to log the deprecation on the root suite, ignoring
* the spec or suite that's running when it happens. Optional. Defaults to
* false.
*
* @name Env#deprecated
* @since 2.99
* @function
* @param {String|Error} deprecation The deprecation message
* @param {Object} [options] Optional extra options, as described above
*/
this.deprecated = function(deprecation, options) {
var runnable = currentRunnable() || topSuite;
var context;
if (runnable === topSuite) {
context = '';
} else if (runnable === currentSuite()) {
context = ' (in suite: ' + runnable.getFullName() + ')';
} else {
context = ' (in spec: ' + runnable.getFullName() + ')';
}
runnable.addDeprecationWarning(deprecation);
if (
typeof console !== 'undefined' &&
typeof console.error === 'function'
) {
console.error('DEPRECATION: ' + deprecation + context);
}
deprecator.addDeprecationWarning(runnable, deprecation, options);
};
var queueRunnerFactory = function(options, args) {
@@ -717,6 +818,7 @@ getJasmineRequireObj().Env = function(j$) {
expectationResultFactory: expectationResultFactory,
autoCleanClosures: config.autoCleanClosures
});
var deprecator = new j$.Deprecator(topSuite);
currentDeclarationSuite = topSuite;
/**
@@ -728,7 +830,7 @@ getJasmineRequireObj().Env = function(j$) {
* @since 2.0.0
*/
this.topSuite = function() {
return topSuite;
return j$.deprecatingSuiteProxy(topSuite, null, this);
};
/**
@@ -803,7 +905,8 @@ getJasmineRequireObj().Env = function(j$) {
*/
'specDone'
],
queueRunnerFactory
queueRunnerFactory,
self.deprecated
);
/**
@@ -1143,7 +1246,14 @@ getJasmineRequireObj().Env = function(j$) {
suite.exclude();
}
addSpecsToSuite(suite, specDefinitions);
return suite;
if (suite.parentSuite && !suite.children.length) {
this.deprecated(
'describe with no children (describe() or it()) is ' +
'deprecated and will be removed in a future version of Jasmine. ' +
'Please either remove the describe or add children to it.'
);
}
return j$.deprecatingSuiteProxy(suite, suite.parentSuite, this);
};
this.xdescribe = function(description, specDefinitions) {
@@ -1152,7 +1262,7 @@ getJasmineRequireObj().Env = function(j$) {
var suite = suiteFactory(description);
suite.exclude();
addSpecsToSuite(suite, specDefinitions);
return suite;
return j$.deprecatingSuiteProxy(suite, suite.parentSuite, this);
};
var focusedRunnables = [];
@@ -1167,7 +1277,7 @@ getJasmineRequireObj().Env = function(j$) {
unfocusAncestor();
addSpecsToSuite(suite, specDefinitions);
return suite;
return j$.deprecatingSuiteProxy(suite, suite.parentSuite, this);
};
function addSpecsToSuite(suite, specDefinitions) {
@@ -1177,7 +1287,7 @@ getJasmineRequireObj().Env = function(j$) {
var declarationError = null;
try {
specDefinitions.call(suite);
specDefinitions.call(j$.deprecatingThisProxy(suite, self));
} catch (e) {
declarationError = e;
}
@@ -1219,6 +1329,7 @@ getJasmineRequireObj().Env = function(j$) {
beforeAndAfterFns: beforeAndAfterFns(suite),
expectationFactory: expectationFactory,
asyncExpectationFactory: specAsyncExpectationFactory,
deprecated: self.deprecated,
resultCallback: specResultCallback,
getSpecName: function(spec) {
return getSpecName(spec, suite);
@@ -1258,7 +1369,7 @@ getJasmineRequireObj().Env = function(j$) {
}
};
this.it = function(description, fn, timeout) {
this.it_ = function(description, fn, timeout) {
ensureIsNotNested('it');
// it() sometimes doesn't have a fn argument, so only check the type if
// it's given.
@@ -1275,9 +1386,15 @@ getJasmineRequireObj().Env = function(j$) {
spec.exclude();
}
currentDeclarationSuite.addChild(spec);
return spec;
};
this.it = function(description, fn, timeout) {
var spec = this.it_(description, fn, timeout);
return j$.deprecatingSpecProxy(spec, this);
};
this.xit = function(description, fn, timeout) {
ensureIsNotNested('xit');
// xit(), like it(), doesn't always have a fn argument, so only check the
@@ -1285,9 +1402,9 @@ getJasmineRequireObj().Env = function(j$) {
if (arguments.length > 1 && typeof fn !== 'undefined') {
ensureIsFunctionOrAsync(fn, 'xit');
}
var spec = this.it.apply(this, arguments);
var spec = this.it_.apply(this, arguments);
spec.exclude('Temporarily disabled with xit');
return spec;
return j$.deprecatingSpecProxy(spec, this);
};
this.fit = function(description, fn, timeout) {
@@ -1301,7 +1418,7 @@ getJasmineRequireObj().Env = function(j$) {
currentDeclarationSuite.addChild(spec);
focusedRunnables.push(spec.id);
unfocusAncestor();
return spec;
return j$.deprecatingSpecProxy(spec, this);
};
/**

View File

@@ -90,7 +90,7 @@ getJasmineRequireObj().ExceptionFormatter = function(j$) {
}
if (!empty) {
return 'error properties: ' + j$.pp(result) + '\n';
return 'error properties: ' + j$.basicPrettyPrinter_(result) + '\n';
}
return '';

View File

@@ -16,7 +16,7 @@ getJasmineRequireObj().buildExpectationResult = function(j$) {
var result = {
matcherName: options.matcherName,
message: message(),
stack: stack(),
stack: options.omitStackTrace ? '' : stack(),
passed: options.passed
};

View File

@@ -20,7 +20,15 @@ getJasmineRequireObj().Expector = function(j$) {
this.args.unshift(this.actual);
var matcher = matcherFactory(this.matchersUtil, this.customEqualityTesters);
// TODO: Remove support for passing customEqualityTesters in the next major release.
var matcher;
if (matcherFactory.length >= 2) {
matcher = matcherFactory(this.matchersUtil, this.customEqualityTesters);
} else {
matcher = matcherFactory(this.matchersUtil);
}
var comparisonFunc = this.filters.selectComparisonFunc(matcher);
return comparisonFunc || matcher.compare;
};

View File

@@ -1,4 +1,4 @@
getJasmineRequireObj().MockDate = function() {
getJasmineRequireObj().MockDate = function(j$) {
function MockDate(global) {
var self = this;
var currentTime = 0;
@@ -16,6 +16,14 @@ getJasmineRequireObj().MockDate = function() {
if (mockDate instanceof GlobalDate) {
currentTime = mockDate.getTime();
} else {
if (!j$.util.isUndefined(mockDate)) {
j$.getEnv().deprecated(
'The argument to jasmine.clock().mockDate(), if specified, ' +
'should be a Date instance. Passing anything other than a Date ' +
'will be treated as an error in a future release.'
);
}
currentTime = new GlobalDate().getTime();
}

View File

@@ -5,10 +5,14 @@ getJasmineRequireObj().QueueRunner = function(j$) {
StopExecutionError.prototype = new Error();
j$.StopExecutionError = StopExecutionError;
function once(fn) {
function once(fn, onTwice) {
var called = false;
return function(arg) {
if (!called) {
if (called) {
if (onTwice) {
onTwice();
}
} else {
called = true;
// Direct call using single parameter, because cleanup/next does not need more
fn(arg);
@@ -17,6 +21,16 @@ getJasmineRequireObj().QueueRunner = function(j$) {
};
}
function fallbackOnMultipleDone() {
console.error(
new Error(
"An asynchronous function called its 'done' " +
'callback more than once, in a QueueRunner without a onMultipleDone ' +
'handler.'
)
);
}
function emptyFn() {}
function QueueRunner(attrs) {
@@ -31,6 +45,7 @@ getJasmineRequireObj().QueueRunner = function(j$) {
fn();
};
this.onException = attrs.onException || emptyFn;
this.onMultipleDone = attrs.onMultipleDone || fallbackOnMultipleDone;
this.userContext = attrs.userContext || new j$.UserContext();
this.timeout = attrs.timeout || {
setTimeout: setTimeout,
@@ -88,6 +103,8 @@ getJasmineRequireObj().QueueRunner = function(j$) {
var self = this,
completedSynchronously = true,
handleError = function handleError(error) {
// TODO probably shouldn't next() right away here.
// That makes debugging async failures much more confusing.
onException(error);
},
cleanup = once(function cleanup() {
@@ -96,31 +113,52 @@ getJasmineRequireObj().QueueRunner = function(j$) {
}
self.globalErrors.popListener(handleError);
}),
next = once(function next(err) {
cleanup();
next = once(
function next(err) {
cleanup();
if (j$.isError_(err)) {
if (!(err instanceof StopExecutionError) && !err.jasmineMessage) {
self.fail(err);
if (j$.isError_(err)) {
if (!(err instanceof StopExecutionError) && !err.jasmineMessage) {
self.fail(err);
}
self.errored = errored = true;
} else if (typeof err !== 'undefined' && !self.errored) {
self.deprecated(
'Any argument passed to a done callback will be treated as an ' +
'error in a future release. Call the done callback without ' +
"arguments if you don't want to trigger a spec failure."
);
}
self.errored = errored = true;
}
function runNext() {
if (self.completeOnFirstError && errored) {
self.skipToCleanup(iterativeIndex);
function runNext() {
if (self.completeOnFirstError && errored) {
self.skipToCleanup(iterativeIndex);
} else {
self.run(iterativeIndex + 1);
}
}
if (completedSynchronously) {
self.setTimeout(runNext);
} else {
self.run(iterativeIndex + 1);
runNext();
}
},
function() {
try {
if (!timedOut) {
self.onMultipleDone();
}
} catch (error) {
// Any error we catch here is probably due to a bug in Jasmine,
// and it's not likely to end up anywhere useful if we let it
// propagate. Log it so it can at least show up when debugging.
console.error(error);
}
}
if (completedSynchronously) {
self.setTimeout(runNext);
} else {
runNext();
}
}),
),
errored = false,
timedOut = false,
queueableFn = self.queueableFns[iterativeIndex],
timeoutId,
maybeThenable;
@@ -136,6 +174,7 @@ getJasmineRequireObj().QueueRunner = function(j$) {
if (queueableFn.timeout !== undefined) {
var timeoutInterval = queueableFn.timeout || j$.DEFAULT_TIMEOUT_INTERVAL;
timeoutId = self.setTimeout(function() {
timedOut = true;
var error = new Error(
'Timeout - Async function did not complete within ' +
timeoutInterval +
@@ -144,6 +183,9 @@ getJasmineRequireObj().QueueRunner = function(j$) {
? '(custom timeout)'
: '(set by jasmine.DEFAULT_TIMEOUT_INTERVAL)')
);
// TODO Need to decide what to do about a successful completion after a
// timeout. That should probably not be a deprecation, and maybe not
// an error in 4.0. (But a diagnostic of some sort might be helpful.)
onException(error);
next();
}, timeoutInterval);
@@ -209,30 +251,39 @@ getJasmineRequireObj().QueueRunner = function(j$) {
this.clearStack(function() {
self.globalErrors.popListener(self.handleFinalError);
self.onComplete(self.errored && new StopExecutionError());
if (self.errored) {
self.onComplete(new StopExecutionError());
} else {
self.onComplete();
}
});
};
QueueRunner.prototype.diagnoseConflictingAsync_ = function(fn, retval) {
var msg;
if (retval && j$.isFunction_(retval.then)) {
// Issue a warning that matches the user's code
// Issue a warning that matches the user's code.
// Omit the stack trace because there's almost certainly no user code
// on the stack at this point.
if (j$.isAsyncFunction_(fn)) {
this.deprecated(
msg =
'An asynchronous before/it/after ' +
'function was defined with the async keyword but also took a ' +
'done callback. This is not supported and will stop working in' +
' the future. Either remove the done callback (recommended) or ' +
'remove the async keyword.'
);
'function was defined with the async keyword but also took a ' +
'done callback. This is not supported and will stop working in' +
' the future. Either remove the done callback (recommended) or ' +
'remove the async keyword.';
} else {
this.deprecated(
msg =
'An asynchronous before/it/after ' +
'function took a done callback but also returned a promise. ' +
'This is not supported and will stop working in the future. ' +
'Either remove the done callback (recommended) or change the ' +
'function to not return a promise.'
);
'function took a done callback but also returned a promise. ' +
'This is not supported and will stop working in the future. ' +
'Either remove the done callback (recommended) or change the ' +
'function to not return a promise.';
}
this.deprecated(msg, { omitStackTrace: true });
}
};

View File

@@ -1,5 +1,5 @@
getJasmineRequireObj().ReportDispatcher = function(j$) {
function ReportDispatcher(methods, queueRunnerFactory) {
function ReportDispatcher(methods, queueRunnerFactory, deprecated) {
var dispatchedMethods = methods || [];
for (var i = 0; i < dispatchedMethods.length; i++) {
@@ -43,7 +43,18 @@ getJasmineRequireObj().ReportDispatcher = function(j$) {
queueRunnerFactory({
queueableFns: fns,
onComplete: onComplete,
isReporter: true
isReporter: true,
onMultipleDone: function() {
deprecated(
"An asynchronous reporter callback called its 'done' callback " +
'more than once. This is a bug in the reporter callback in ' +
'question. This will be treated as an error in a future ' +
'version. See' +
'<https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0#deprecations-due-to-calling-done-multiple-times> ' +
'for more information.',
{ ignoreRunnable: true }
);
}
});
}

View File

@@ -45,6 +45,7 @@ getJasmineRequireObj().Spec = function(j$) {
};
this.expectationResultFactory =
attrs.expectationResultFactory || function() {};
this.deprecated = attrs.deprecated || function() {};
this.queueRunnerFactory = attrs.queueRunnerFactory || function() {};
this.catchingExceptions =
attrs.catchingExceptions ||
@@ -142,13 +143,32 @@ x */
onException: function() {
self.onException.apply(self, arguments);
},
onComplete: function() {
onComplete(
self.result.status === 'failed' &&
new j$.StopExecutionError('spec failed')
onMultipleDone: function() {
// Issue a deprecation. Include the context ourselves and pass
// ignoreRunnable: true, since getting here always means that we've already
// moved on and the current runnable isn't the one that caused the problem.
self.deprecated(
"An asynchronous function called its 'done' " +
'callback more than once. This is a bug in the spec, beforeAll, ' +
'beforeEach, afterAll, or afterEach function in question. This will ' +
'be treated as an error in a future version. See' +
'<https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0#deprecations-due-to-calling-done-multiple-times> ' +
'for more information.\n' +
'(in spec: ' +
self.getFullName() +
')',
{ ignoreRunnable: true }
);
},
userContext: this.userContext()
onComplete: function() {
if (self.result.status === 'failed') {
onComplete(new j$.StopExecutionError('spec failed'));
} else {
onComplete();
}
},
userContext: this.userContext(),
runnableName: this.getFullName.bind(this)
};
if (this.markedPending || excluded === true) {
@@ -236,7 +256,7 @@ x */
if (this.message) {
this.excludeMessage = message;
}
this.pend();
this.pend(message);
};
Spec.prototype.getResult = function() {

View File

@@ -167,7 +167,7 @@ getJasmineRequireObj().Spy = function(j$) {
"Spy '" +
strategyArgs.name +
"' received a call with arguments " +
j$.pp(Array.prototype.slice.call(args)) +
j$.basicPrettyPrinter_(Array.prototype.slice.call(args)) +
' but all configured strategies specify other arguments.'
);
} else {

View File

@@ -231,6 +231,36 @@ getJasmineRequireObj().Suite = function(j$) {
this.result.failedExpectations.push(failedExpectation);
};
Suite.prototype.onMultipleDone = function() {
var msg;
// Issue a deprecation. Include the context ourselves and pass
// ignoreRunnable: true, since getting here always means that we've already
// moved on and the current runnable isn't the one that caused the problem.
if (this.parentSuite) {
msg =
"An asynchronous function called its 'done' callback more than " +
'once. This is a bug in the spec, beforeAll, beforeEach, afterAll, ' +
'or afterEach function in question. This will be treated as an error ' +
'in a future version. See' +
'<https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0#deprecations-due-to-calling-done-multiple-times> ' +
'for more information.\n' +
'(in suite: ' +
this.getFullName() +
')';
} else {
msg =
'A top-level beforeAll or afterAll function called its ' +
"'done' callback more than once. This is a bug in the beforeAll " +
'or afterAll function in question. This will be treated as an ' +
'error in a future version. See' +
'<https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0#deprecations-due-to-calling-done-multiple-times> ' +
'for more information.';
}
this.env.deprecated(msg, { ignoreRunnable: true });
};
Suite.prototype.addExpectationResult = function() {
if (isFailure(arguments)) {
var data = arguments[1];

View File

@@ -44,7 +44,10 @@ getJasmineRequireObj().TreeProcessor = function() {
onException: function() {
tree.onException.apply(tree, arguments);
},
onComplete: done
onComplete: done,
onMultipleDone: tree.onMultipleDone
? tree.onMultipleDone.bind(tree)
: null
});
};
@@ -216,7 +219,10 @@ getJasmineRequireObj().TreeProcessor = function() {
userContext: node.sharedUserContext(),
onException: function() {
node.onException.apply(node, arguments);
}
},
onMultipleDone: node.onMultipleDone
? node.onMultipleDone.bind(node)
: null
});
}
};

View File

@@ -51,34 +51,49 @@ getJasmineRequireObj().asymmetricEqualityTesterArgCompatShim = function(j$) {
matchersUtil,
customEqualityTesters
) {
var self = Object.create(matchersUtil),
props,
i,
k;
var self = Object.create(matchersUtil);
copy(self, customEqualityTesters, 'length');
copyAndDeprecate(self, customEqualityTesters, 'length');
for (i = 0; i < customEqualityTesters.length; i++) {
copy(self, customEqualityTesters, i);
copyAndDeprecate(self, customEqualityTesters, i);
}
var props = arrayProps();
for (i = 0; i < props.length; i++) {
k = props[i];
// Skip length (dealt with above), and anything that collides with
// MatchesUtil e.g. an Array.prototype.contains method added by user code
if (k !== 'length' && !self[k]) {
copy(self, Array.prototype, k);
}
// Avoid copying array props if we've previously done so,
// to avoid triggering our own deprecation warnings.
if (!self.isAsymmetricEqualityTesterArgCompatShim_) {
copyAndDeprecateArrayMethods(self);
}
self.isAsymmetricEqualityTesterArgCompatShim_ = true;
return self;
}
function copy(dest, src, propName) {
function copyAndDeprecateArrayMethods(dest) {
var props = arrayProps(),
i,
k;
for (i = 0; i < props.length; i++) {
k = props[i];
// Skip length (dealt with above), and anything that collides with
// MatchesUtil e.g. an Array.prototype.contains method added by user code
if (k !== 'length' && !dest[k]) {
copyAndDeprecate(dest, Array.prototype, k);
}
}
}
function copyAndDeprecate(dest, src, propName) {
Object.defineProperty(dest, propName, {
get: function() {
j$.getEnv().deprecated(
'The second argument to asymmetricMatch is now a ' +
'MatchersUtil. Using it as an array of custom equality testers is ' +
'deprecated and will stop working in a future release. ' +
'See <https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0#asymmetricMatch-cet> for details.'
);
return src[propName];
}
});

View File

@@ -7,7 +7,7 @@ getJasmineRequireObj().ArrayContaining = function(j$) {
if (!j$.isArray_(this.sample)) {
throw new Error(
'You must provide an array to arrayContaining, not ' +
j$.pp(this.sample) +
j$.basicPrettyPrinter_(this.sample) +
'.'
);
}

View File

@@ -10,7 +10,7 @@ getJasmineRequireObj().ArrayWithExactContents = function(j$) {
if (!j$.isArray_(this.sample)) {
throw new Error(
'You must provide an array to arrayWithExactContents, not ' +
j$.pp(this.sample) +
j$.basicPrettyPrinter_(this.sample) +
'.'
);
}

View File

@@ -2,7 +2,8 @@ getJasmineRequireObj().MapContaining = function(j$) {
function MapContaining(sample) {
if (!j$.isMap(sample)) {
throw new Error(
'You must provide a map to `mapContaining`, not ' + j$.pp(sample)
'You must provide a map to `mapContaining`, not ' +
j$.basicPrettyPrinter_(sample)
);
}

View File

@@ -2,7 +2,8 @@ getJasmineRequireObj().SetContaining = function(j$) {
function SetContaining(sample) {
if (!j$.isSet(sample)) {
throw new Error(
'You must provide a set to `setContaining`, not ' + j$.pp(sample)
'You must provide a set to `setContaining`, not ' +
j$.basicPrettyPrinter_(sample)
);
}

View File

@@ -0,0 +1,70 @@
/* eslint-disable compat/compat */
// TODO: Remove this in the next major release.
getJasmineRequireObj().deprecatingSpecProxy = function(j$) {
function isMember(target, prop) {
return (
Object.keys(target).indexOf(prop) !== -1 ||
Object.keys(j$.Spec.prototype).indexOf(prop) !== -1
);
}
function isAllowedMember(prop) {
return prop === 'id' || prop === 'description' || prop === 'getFullName';
}
function msg(member) {
var memberName = member.toString().replace(/^Symbol\((.+)\)$/, '$1');
return (
'Access to private Spec members (in this case `' +
memberName +
'`) is not supported and will break in ' +
'a future release. See <https://jasmine.github.io/api/edge/Spec.html> ' +
'for correct usage.'
);
}
try {
new Proxy({}, {});
} catch (e) {
// Environment does not support Poxy.
return function(spec) {
return spec;
};
}
function DeprecatingSpecProxyHandler(env) {
this._env = env;
}
DeprecatingSpecProxyHandler.prototype.get = function(target, prop, receiver) {
this._maybeDeprecate(target, prop);
if (prop === 'getFullName') {
// getFullName calls a private method. Re-bind 'this' to avoid a bogus
// deprecation warning.
return target.getFullName.bind(target);
} else {
return target[prop];
}
};
DeprecatingSpecProxyHandler.prototype.set = function(target, prop, value) {
this._maybeDeprecate(target, prop);
return (target[prop] = value);
};
DeprecatingSpecProxyHandler.prototype._maybeDeprecate = function(
target,
prop
) {
if (isMember(target, prop) && !isAllowedMember(prop)) {
this._env.deprecated(msg(prop));
}
};
function deprecatingSpecProxy(spec, env) {
return new Proxy(spec, new DeprecatingSpecProxyHandler(env));
}
return deprecatingSpecProxy;
};

View File

@@ -0,0 +1,98 @@
/* eslint-disable compat/compat */
// TODO: Remove this in the next major release.
getJasmineRequireObj().deprecatingSuiteProxy = function(j$) {
var allowedMembers = [
'id',
'children',
'description',
'parentSuite',
'getFullName'
];
function isMember(target, prop) {
return (
Object.keys(target).indexOf(prop) !== -1 ||
Object.keys(j$.Suite.prototype).indexOf(prop) !== -1
);
}
function isAllowedMember(prop) {
return allowedMembers.indexOf(prop) !== -1;
}
function msg(member) {
var memberName = member.toString().replace(/^Symbol\((.+)\)$/, '$1');
return (
'Access to private Suite members (in this case `' +
memberName +
'`) is not supported and will break in ' +
'a future release. See <https://jasmine.github.io/api/edge/Suite.html> ' +
'for correct usage.'
);
}
try {
new Proxy({}, {});
} catch (e) {
// Environment does not support Poxy.
return function(suite) {
return suite;
};
}
function DeprecatingSuiteProxyHandler(parentSuite, env) {
this._parentSuite = parentSuite;
this._env = env;
}
DeprecatingSuiteProxyHandler.prototype.get = function(
target,
prop,
receiver
) {
if (prop === 'children') {
if (!this._children) {
this._children = target.children.map(
this._proxyForChild.bind(this, receiver)
);
}
return this._children;
} else if (prop === 'parentSuite') {
return this._parentSuite;
} else {
this._maybeDeprecate(target, prop);
return target[prop];
}
};
DeprecatingSuiteProxyHandler.prototype.set = function(target, prop, value) {
this._maybeDeprecate(target, prop);
return (target[prop] = value);
};
DeprecatingSuiteProxyHandler.prototype._maybeDeprecate = function(
target,
prop
) {
if (isMember(target, prop) && !isAllowedMember(prop)) {
this._env.deprecated(msg(prop));
}
};
DeprecatingSuiteProxyHandler.prototype._proxyForChild = function(
ownProxy,
child
) {
if (child.children) {
return deprecatingSuiteProxy(child, ownProxy, this._env);
} else {
return j$.deprecatingSpecProxy(child, this._env);
}
};
function deprecatingSuiteProxy(suite, parentSuite, env) {
return new Proxy(suite, new DeprecatingSuiteProxyHandler(parentSuite, env));
}
return deprecatingSuiteProxy;
};

View File

@@ -0,0 +1,34 @@
/* eslint-disable compat/compat */
// TODO: Remove this in the next major release.
getJasmineRequireObj().deprecatingThisProxy = function(j$) {
var msg =
"Access to 'this' in describe functions (and in arrow functions " +
'inside describe functions) is deprecated.';
try {
new Proxy({}, {});
} catch (e) {
// Environment does not support Poxy.
return function(suite) {
return suite;
};
}
function DeprecatingThisProxyHandler(env) {
this._env = env;
}
DeprecatingThisProxyHandler.prototype.get = function(target, prop, receiver) {
this._env.deprecated(msg);
return target[prop];
};
DeprecatingThisProxyHandler.prototype.set = function(target, prop, value) {
this._env.deprecated(msg);
return (target[prop] = value);
};
return function(suite, env) {
return new Proxy(suite, new DeprecatingThisProxyHandler(env));
};
};

View File

@@ -1,6 +1,4 @@
getJasmineRequireObj().MatchersUtil = function(j$) {
// TODO: convert all uses of j$.pp to use the injected pp
/**
* @class MatchersUtil
* @classdesc Utilities for use in implementing matchers.<br>
@@ -31,10 +29,19 @@ getJasmineRequireObj().MatchersUtil = function(j$) {
* @since 2.0.0
* @param {*} haystack The collection to search
* @param {*} needle The value to search for
* @param [customTesters] An array of custom equality testers
* @param [customTesters] An array of custom equality testers. Deprecated.
* As of 3.6 this parameter no longer needs to be passed. It will be removed in 4.0.
* @returns {boolean} True if `needle` was found in `haystack`
*/
MatchersUtil.prototype.contains = function(haystack, needle, customTesters) {
if (customTesters) {
j$.getEnv().deprecated(
'Passing custom equality testers ' +
'to MatchersUtil#contains is deprecated. ' +
'See <https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0#matchers-cet> for details.'
);
}
if (j$.isSet(haystack)) {
return haystack.has(needle);
}
@@ -44,8 +51,13 @@ getJasmineRequireObj().MatchersUtil = function(j$) {
(!!haystack && !haystack.indexOf)
) {
for (var i = 0; i < haystack.length; i++) {
if (this.equals(haystack[i], needle, customTesters)) {
return true;
try {
this.suppressDeprecation_ = true;
if (this.equals(haystack[i], needle, customTesters)) {
return true;
}
} finally {
this.suppressDeprecation_ = false;
}
}
return false;
@@ -149,7 +161,8 @@ getJasmineRequireObj().MatchersUtil = function(j$) {
* @since 2.0.0
* @param {*} a The first value to compare
* @param {*} b The second value to compare
* @param [customTesters] An array of custom equality testers
* @param [customTesters] An array of custom equality testers. Deprecated.
* As of 3.6 this parameter no longer needs to be passed. It will be removed in 4.0.
* @returns {boolean} True if the values are equal
*/
MatchersUtil.prototype.equals = function(
@@ -163,6 +176,22 @@ getJasmineRequireObj().MatchersUtil = function(j$) {
if (isDiffBuilder(customTestersOrDiffBuilder)) {
diffBuilder = customTestersOrDiffBuilder;
} else {
if (customTestersOrDiffBuilder && !this.suppressDeprecation_) {
j$.getEnv().deprecated(
'Passing custom equality testers ' +
'to MatchersUtil#equals is deprecated. ' +
'See <https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0#matchers-cet> for details.'
);
}
if (diffBuilderOrNothing) {
j$.getEnv().deprecated(
'Diff builder should be passed ' +
'as the third argument to MatchersUtil#equals, not the fourth. ' +
'See <https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0#matchers-cet> for details.'
);
}
customTesters = customTestersOrDiffBuilder;
diffBuilder = diffBuilderOrNothing;
}

View File

@@ -38,11 +38,15 @@ var getJasmineRequireObj = (function(jasmineGlobal) {
j$.Any = jRequire.Any(j$);
j$.Anything = jRequire.Anything(j$);
j$.CallTracker = jRequire.CallTracker(j$);
j$.MockDate = jRequire.MockDate();
j$.MockDate = jRequire.MockDate(j$);
j$.getClearStack = jRequire.clearStack(j$);
j$.Clock = jRequire.Clock();
j$.DelayedFunctionScheduler = jRequire.DelayedFunctionScheduler(j$);
j$.Deprecator = jRequire.Deprecator(j$);
j$.Env = jRequire.Env(j$);
j$.deprecatingThisProxy = jRequire.deprecatingThisProxy(j$);
j$.deprecatingSuiteProxy = jRequire.deprecatingSuiteProxy(j$);
j$.deprecatingSpecProxy = jRequire.deprecatingSpecProxy(j$);
j$.StackTrace = jRequire.StackTrace(j$);
j$.ExceptionFormatter = jRequire.ExceptionFormatter(j$);
j$.ExpectationFilterChain = jRequire.ExpectationFilterChain();
@@ -54,11 +58,34 @@ var getJasmineRequireObj = (function(jasmineGlobal) {
j$
);
j$.makePrettyPrinter = jRequire.makePrettyPrinter(j$);
j$.pp = j$.makePrettyPrinter();
j$.basicPrettyPrinter_ = j$.makePrettyPrinter();
Object.defineProperty(j$, 'pp', {
get: function() {
j$.getEnv().deprecated(
'jasmine.pp is deprecated and will be removed in a future release. ' +
'Use the pp method of the matchersUtil passed to the matcher factory ' +
"or the asymmetric equality tester's `asymmetricMatch` method " +
'instead. See ' +
'<https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0#static-utils> for details.'
);
return j$.basicPrettyPrinter_;
}
});
j$.MatchersUtil = jRequire.MatchersUtil(j$);
j$.matchersUtil = new j$.MatchersUtil({
var staticMatchersUtil = new j$.MatchersUtil({
customTesters: [],
pp: j$.pp
pp: j$.basicPrettyPrinter_
});
Object.defineProperty(j$, 'matchersUtil', {
get: function() {
j$.getEnv().deprecated(
'jasmine.matchersUtil is deprecated and will be removed ' +
'in a future release. Use the instance passed to the matcher factory or ' +
"the asymmetric equality tester's `asymmetricMatch` method instead. " +
'See <https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0#static-utils> for details.'
);
return staticMatchersUtil;
}
});
j$.ObjectContaining = jRequire.ObjectContaining(j$);

View File

@@ -280,7 +280,8 @@ jasmineRequire.HtmlReporter = function(j$) {
addDeprecationWarnings(doneResult);
for (i = 0; i < deprecationWarnings.length; i++) {
var context;
var children = [],
context;
switch (deprecationWarnings[i].runnableType) {
case 'spec':
@@ -293,13 +294,23 @@ jasmineRequire.HtmlReporter = function(j$) {
context = '';
}
deprecationWarnings[i].message.split('\n').forEach(function(line) {
children.push(line);
children.push(createDom('br'));
});
children[0] = 'DEPRECATION: ' + children[0];
children.push(context);
if (deprecationWarnings[i].stack) {
children.push(createExpander(deprecationWarnings[i].stack));
}
alert.appendChild(
createDom(
'span',
{ className: 'jasmine-bar jasmine-warning' },
'DEPRECATION: ' + deprecationWarnings[i].message,
createDom('br'),
context
children
)
);
}
@@ -621,17 +632,44 @@ jasmineRequire.HtmlReporter = function(j$) {
if (result && result.deprecationWarnings) {
for (var i = 0; i < result.deprecationWarnings.length; i++) {
var warning = result.deprecationWarnings[i].message;
if (!j$.util.arrayContains(warning)) {
deprecationWarnings.push({
message: warning,
runnableName: result.fullName,
runnableType: runnableType
});
}
deprecationWarnings.push({
message: warning,
stack: result.deprecationWarnings[i].stack,
runnableName: result.fullName,
runnableType: runnableType
});
}
}
}
function createExpander(stackTrace) {
var expandLink = createDom('a', { href: '#' }, 'Show stack trace');
var root = createDom(
'div',
{ className: 'jasmine-expander' },
expandLink,
createDom(
'div',
{ className: 'jasmine-expander-contents jasmine-stack-trace' },
stackTrace
)
);
expandLink.addEventListener('click', function(e) {
e.preventDefault();
if (root.classList.contains('jasmine-expanded')) {
root.classList.remove('jasmine-expanded');
expandLink.textContent = 'Show stack trace';
} else {
root.classList.add('jasmine-expanded');
expandLink.textContent = 'Hide stack trace';
}
});
return root;
}
function find(selector) {
return getContainer().querySelector('.jasmine_html-reporter ' + selector);
}
@@ -645,11 +683,23 @@ jasmineRequire.HtmlReporter = function(j$) {
}
}
function createDom(type, attrs, childrenVarArgs) {
var el = createElement(type);
function createDom(type, attrs, childrenArrayOrVarArgs) {
var el = createElement(type),
children,
i;
for (var i = 2; i < arguments.length; i++) {
var child = arguments[i];
if (j$.isArray_(childrenArrayOrVarArgs)) {
children = childrenArrayOrVarArgs;
} else {
children = [];
for (i = 2; i < arguments.length; i++) {
children.push(arguments[i]);
}
}
for (i = 0; i < children.length; i++) {
var child = children[i];
if (typeof child === 'string') {
el.appendChild(createTextNode(child));

View File

@@ -233,6 +233,8 @@ body {
}
&.jasmine-warning {
margin-top: $margin-unit;
margin-bottom: $margin-unit;
background-color: $pending-color;
color: $text-color;
}
@@ -388,4 +390,27 @@ body {
background: white;
white-space: pre;
}
.jasmine-expander {
a {
display: block;
margin-left: $margin-unit;
color: blue;
text-decoration: underline;
}
}
.jasmine-expander-contents {
display: none;
}
.jasmine-expanded {
padding-bottom: 10px;
}
.jasmine-expanded .jasmine-expander-contents {
display: block;
margin-left: $margin-unit;
padding: 5px;
}
}