Compare commits

..

104 Commits

Author SHA1 Message Date
Steve Gravrock
906f37fe52 Bump version to 3.99.1 2022-02-21 16:30:15 -08:00
Steve Gravrock
4a2b10998a Remove Safari 8 and 9 from CI matrix
These browsers are still nominally supported by Jasmine 3.x, but they no
longer work on Saucelabs.
2022-02-19 14:23:02 -08:00
Steve Gravrock
d8b2efe4d6 Downgrade jasmine-browser-runner for compatibility with IE 2022-02-19 14:21:35 -08:00
Steve Gravrock
9d9e8f0c17 Lint fixes 2022-02-19 12:33:19 -08:00
Steve Gravrock
4059ab7ba6 Don't report a deprecation when a promise is resolved to something
beforeEach(() => somePromiseReturningFn()) is likely a common idiom
and we don't want to treat it as an error.

* Fixes #1958
2022-02-19 12:28:47 -08:00
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
896412367a Bump version to 3.10.0 2021-10-13 15:46:21 -07:00
Steve Gravrock
503a7409f0 Merge branch 'issue-1854-asyncerror' of https://github.com/AndreWillomitzer/jasmine into main
* Improves error message when an async expectation occurs after the spec
  finishes
* Merges #1937 from @AndreWillomitzer
* Fixes #1854
2021-10-12 17:15:53 -07:00
Steve Gravrock
c1db8f2f82 Clarified deprecation message for this in describes 2021-10-12 15:40:13 -07:00
Andre Willomitzer
bb9175cb66 added additional error msg for delayedExpectation
added matching error msgs in jasmine objects

Ran prettier.

removed indenting, formatted column length < 80
2021-10-12 13:17:24 -04: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
469b557828 Merge branch 'fix/ie' of https://github.com/nicojs/jasmine into main
* Merges #1936 from @nicojs
2021-10-07 10:17:16 -07:00
Nico Jansen
503715c275 test(ie): refactor promises to callbacks 2021-10-07 10:23:52 +02:00
Steve Gravrock
4482355885 Removed jsdoc entry for SpecResult#trace
Deferred to 4.0.
2021-10-06 11:31:29 -07:00
Steve Gravrock
6542364381 Merge branch 'feat/support-multiple-runs' of https://github.com/nicojs/jasmine into main
* Merges #1934 from @nicojs
* Fixes #1925
2021-10-06 11:20:34 -07:00
Nico Jansen
1fc911e0fa Support running jasmine multiple times
Add support for running jasmine multiple times.

```js
const Jasmine = require('jasmine');

async function main() {
  const jasmine = new Jasmine({ projectBaseDir: process.cwd() });
  let specId = 'spec0';
  jasmine.loadConfigFile('./spec/support/jasmine.json');
  jasmine.env.configure({
    specFilter(sp) {
      return sp.id === specId;
    },
    autoCleanClosures: false
  });
  jasmine.exit = () => {};
  await jasmine.execute();
  specId = 'spec2';
  await jasmine.execute();
}

main().catch((err) => {
  console.error(err);
  process.exitCode = 1;
});
```

With `jasmine.env.configure({ autoCleanClosures: false })` you disable Jasmine's feature to automatically clean closures (functions) during the test run. This is a requirement to be able to rerun.

When `execute` is called more than once, the `topSuite.reset` is called, which will reset the state for the next run as well as reset any child suites.

Add a function `exclude` to the `Suite` and `Spec` clases. This functions similar to `pend`, but will allow the "pending" state to persist over multiple runs. This is useful when `xit` is used.

Revert changes to jasmine.js

fix: make sure to call hooks during second run

Remove jsdoc from private apis

Fix elint issue

Add new line
2021-10-06 20:12:45 +02:00
Steve Gravrock
7f0087b805 Merge branch 'main' into 3.99 2021-10-02 09:47:30 -07:00
Steve Gravrock
fdad8849df Revert "Added the ability to associate trace information with failing specs"
Pushing this back to 4.0 in hopes of increasing the chance that third
party reporters will notice it and add support.

This reverts commit 7a289f1de7.
2021-10-02 09:45:15 -07:00
Steve Gravrock
7a289f1de7 Added the ability to associate trace information with failing specs
This is meant to aid in debugging failures, particularly intermittent
failures, in cases where interactive debugging or console.log aren't
suitable.
2021-09-25 16:19:28 -07:00
Steve Gravrock
ef981bb794 Run the browser-flakes build on the debugging branch 2021-09-25 15:50:34 -07:00
Steve Gravrock
c3fb3e985a Reject timeout values that are too large for setTimeout
See #1930
2021-09-25 15:43:31 -07:00
Steve Gravrock
7fc3408051 Expanded jsdocs for jasmine.DEFAULT_TIMEOUT_INTERVAL 2021-09-25 13:29:44 -07:00
Steve Gravrock
af1b43eeff Merge branch 'patch-1' of https://github.com/trusktr/jasmine into main
* Merges #1931 from @trusktr
* Adds discussion of max timeout value to jsdocs
2021-09-25 13:28:34 -07:00
Steve Gravrock
4c043717a9 Revert "Dogfood the new jasmine-npm completion interface"
This works, but until the -npm 3.10.0 is out, it creates a chicken and egg
problem where each of core 3.10.0 and -npm 3.10.0 needs to be released
after the other.

This reverts commit 1c9382c990.
2021-09-25 12:11:20 -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
40be00310d Don't immediately move to the next queueable fn on async error
This allows assertion failures and other errors that occcur after the async
error to be routed to the correct spec/suite.

Previously, Jasmine treated global errors and unhandled promise rejections
just like exceptions thrown from a synchronous spec: it recorded the error
as a spec failure and moved on. Now, global errors and uhandled rejections
are recorded as failures but the current queueable fn will continue until
it either signals completion or times out. Global errors and unhandled
rejections are different from synchronous exceptions: it's common for the
queueable fn that caused them to continue executing. Immediately moving on
often meant that the queueable fn would produce expectation failures or
other errors when a different spec or suite was running, thus causing
those failures to be routed to the wrong place.
2021-09-24 11:22:04 -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
1f318c3c93 Added missing @since annotations 2021-09-23 13:38:52 -07:00
Steve Gravrock
be29aa95eb Improved jsdocs for asymmetric equality testers 2021-09-23 11:59:20 -07:00
Steve Gravrock
e3c9a59c6c Added a stringContaining asymmetric equality tester
* Fixes #1923.
2021-09-22 11:28:24 -07:00
Joe Pea
b312ed4940 update base.js docs, mention setting DEFAULT_TIMEOUT_INTERVAL to a high number while debugging
This info is useful because if someone does not set the number to a high enough value while stepping through test code, before or after hooks may be triggered mid-test while the user is debugging which will be confusing.
2021-09-21 21:39:21 -07:00
Steve Gravrock
00f6708e1f Removed unused submodule 2021-09-18 09:43:02 -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
3a47a3bd04 Fixed flaky spec 2021-09-06 15:35:37 -07:00
Steve Gravrock
1c9382c990 Dogfood the new jasmine-npm completion interface 2021-09-04 13:39:17 -07:00
Steve Gravrock
394be99832 Fixed sass deprecation warnings
See <https://sass-lang.com/documentation/breaking-changes/slash-div>.
[#179260511]
2021-09-03 15:51:51 -07:00
Steve Gravrock
de9815f436 Merge branch 'main' into 3.99 2021-08-30 18:41:02 -07:00
Steve Gravrock
62a667a8e3 Added a deprecation notice to the gem's description
[#179330717]
2021-08-30 18:37:31 -07:00
Steve Gravrock
d277827d5e Fixed typo in 3.9.0 release notes 2021-08-21 19:09:01 -07:00
Steve Gravrock
644c175338 Print a deprecation message when the jasmine-core gem is loaded
[#179247158]
[#179247160]
2021-08-21 18:35:38 -07:00
Steve Gravrock
a6d7eb2a06 Bump version to 3.9.0 2021-08-21 12:00:23 -07:00
Steve Gravrock
2fd9d7b13f Merge branch 'main' into 3.99 2021-08-17 17:08:34 -07:00
Steve Gravrock
dd8a65cb60 Better reporting of unhandled promise rejections with truthy but non-Error reasons on Node
[#179227413]
2021-08-14 14:03:03 -07:00
Steve Gravrock
e72d161fab Return a promise from Env#execute in environments that support promises
[#178373231]
2021-08-07 13:05:55 -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
dcaac62a6c Updated deprecaton messages for Env#throwOnExpectationFailure() and Env#stopOnSpecFailure() 2021-07-31 08:02:39 -07:00
Steve Gravrock
b696bec9e3 Renamed failFast and oneFailurePerSpec config props to stopOnSpecFailure and stopSpecOnExpectationFailure
The new names are more self-explanatory and consistent with jasmine-npm. The
old names are deprecated but still work.

[#178682783]
2021-07-31 07:51:50 -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
43073b3bc5 Added API docs for Suite#id and Spec#id
These properties are the only way to obtain runnable IDs, without which
you can't call the form of Env#execute that takes an array of IDs.
2021-07-29 19:32:15 -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
286524959b Split boot.js in two to allow the env to be configured in between
This is mainly intended to support jasmine-browser-runner, which will load
a script that configures the env in between the two boot files (boot0.js and
boot1.js). The single-file boot.js is retained for now but will be removed
in a future release.
2021-07-26 18:05:36 -07:00
Steve Gravrock
70d49e5b57 Deprecate non-Error arguments passed to done()
[Finishes #178267600]
2021-07-24 09:18:24 -07:00
Steve Gravrock
2c32dd5703 Run browser-flakes build before regular cron build 2021-07-20 17:57:54 -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
c1d1d69be2 Fixed test failures in Chrome and Edge 2021-07-19 12:08:40 -07:00
Steve Gravrock
3513249d73 Built distribution 2021-07-19 12:08:18 -07:00
Steve Gravrock
21bfbbb721 Merge branch 'iserror-tt' of https://github.com/bjarkler/jasmine into main
* Fixes Trusted Types error in Chromium-based browsers
* Merges #1921 from @bjarkler
* Fixes #1910
2021-07-19 12:06:12 -07:00
Steve Gravrock
88b90ec258 Backfilled unit tests for j$.isError_ 2021-07-19 10:31:53 -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
50c88e7774 Mark Env#hideDisabled deprecated in jsdocs 2021-07-08 18:53:21 -07:00
Steve Gravrock
3e64ce3310 Removed property tests for MatchersUtil#equals
These might be useful for a function with a more restricted domain. But for
equals, which accepts two of literally anything, the short run was too short
to catch any problems and the long run tended to exceed the CircleCi timeout.
2021-07-03 08:37:15 -07:00
Bjarki
dc80a282ba Make j$.isError_ compatible with Trusted Types
The isError_ check uses a heuristic that calls the Function constructor
to determine if the given value is an Error object. This results in a
runtime violation in test suites that enforce Trusted Types.

Since Trusted Types are only supported in modern browsers (currently,
Chromium-based browsers), we can use a more straightforward heuristic in
environments where Trusted Types are supported.

Fixes #1910. See that thread for more details.
2021-07-01 20:21:44 +00: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
93 changed files with 6278 additions and 994 deletions

View File

@@ -58,13 +58,6 @@ jobs:
name: Run tests
command: npm test
# Warning: Sometimes takes a very long time (>25 minutes) on Circle.
# Probably not a good idea to run it from anything but a nightly.
test_node_with_long_property_tests:
<<: *test_node
environment:
JASMINE_LONG_PROPERTY_TESTS: y
test_browsers: &test_browsers
executor: node14
environment:
@@ -108,7 +101,7 @@ workflows:
triggers:
- schedule:
# Times are UTC.
cron: "0 10 * * *"
cron: "0 11 * * *"
filters:
branches:
only:
@@ -133,10 +126,6 @@ workflows:
name: test_node_16
requires:
- build_node_16
- test_node_with_long_property_tests:
executor: node14
requires:
- build_node_14
- test_node:
executor: node12
name: test_node_12
@@ -199,11 +188,11 @@ workflows:
triggers:
- schedule:
# Times are UTC.
cron: "0 11 * * *"
cron: "0 10 * * *"
filters:
branches:
only:
- main
- browser-flakes
jobs:
- build:
executor: node14

View File

@@ -50,9 +50,13 @@ Note that Jasmine tests itself. The files in `lib` are loaded first, defining th
The tests should always use `jasmineUnderTest` to refer to the objects and functions that are being tested. But the tests can use functions on `jasmine` as needed. _Be careful how you structure any new test code_. Copy the patterns you see in the existing code - this ensures that the code you're testing is not leaking into the `jasmine` reference and vice-versa.
### `boot.js`
### `boot0.js` and `boot1.js`
This file does all of the setup necessary for Jasmine to work. It loads all of the code, creates an `Env`, attaches the global functions, and builds the reporter. It also sets up the execution of the `Env` - for browsers this is in `window.onload`. While the default in `lib` is appropriate for browsers, projects may wish to customize this file.
These files file does all of the setup necessary for Jasmine to work in a
browser. They load all of the code, create an `Env`, attach the global
functions, and build the reporter. It also sets up the execution of the
`Env` - for browsers this is in `window.onload`. While the default in `lib`
is appropriate for browsers, projects may wish to customize this file.
### Compatibility

3
.gitmodules vendored
View File

@@ -1,3 +0,0 @@
[submodule "pages"]
path = pages
url = https://github.com/pivotal/jasmine.git

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

@@ -29,7 +29,7 @@ module.exports = {
cwd: libJasmineCore("")
},
{
src: [ "boot.js" ],
src: [ "boot0.js", "boot1.js" ],
dest: standaloneLibDir,
expand: true,
cwd: libJasmineCore("boot")

View File

@@ -41,6 +41,14 @@ module.exports = {
src: ['lib/jasmine-core/boot/boot.js'],
dest: 'lib/jasmine-core/boot.js'
},
boot0: {
src: ['lib/jasmine-core/boot/boot0.js'],
dest: 'lib/jasmine-core/boot0.js'
},
boot1: {
src: ['lib/jasmine-core/boot/boot1.js'],
dest: 'lib/jasmine-core/boot1.js'
},
nodeBoot: {
src: ['lib/jasmine-core/boot/node_boot.js'],
dest: 'lib/jasmine-core/node_boot.js'

View File

@@ -9,7 +9,9 @@
<script src="lib/jasmine-<%= jasmineVersion %>/jasmine.js"></script>
<script src="lib/jasmine-<%= jasmineVersion %>/jasmine-html.js"></script>
<script src="lib/jasmine-<%= jasmineVersion %>/boot.js"></script>
<script src="lib/jasmine-<%= jasmineVersion %>/boot0.js"></script>
<!-- optional: include a file here that configures the Jasmine env -->
<script src="lib/jasmine-<%= jasmineVersion %>/boot1.js"></script>
<!-- include source files here... -->
<script src="src/Player.js"></script>

View File

@@ -8,7 +8,18 @@ Gem::Specification.new do |s|
s.platform = Gem::Platform::RUBY
s.authors = ["Gregg Van Hove"]
s.summary = %q{JavaScript BDD framework}
s.description = %q{Test your JavaScript without any framework dependencies, in any environment, and with a nice descriptive syntax.}
s.description = <<~DESC
Test your JavaScript without any framework dependencies, in any environment,
and with a nice descriptive syntax.
Jasmine for Ruby is deprecated. The direct replacment for the jasmine-core
gem is the jasmine-core NPM package. If you are also using the jasmine gem,
we recommend using the jasmine-browser-runner NPM package instead. It
supports all the same scenarios as the jasmine gem gem plus Webpacker. See
https://jasmine.github.io/setup/browser.html for setup instructions, and
https://github.com/jasmine/jasmine-gem/blob/main/release_notes/3.9.0.md
for other options.
DESC
s.email = %q{jasmine-js@googlegroups.com}
s.homepage = "http://jasmine.github.io"
s.license = "MIT"

View File

@@ -5,11 +5,12 @@ var path = require('path'),
fs = require('fs');
var rootPath = path.join(__dirname, "jasmine-core"),
bootFiles = ['boot.js'],
bootFiles = ['boot0.js', 'boot1.js'],
legacyBootFiles = ['boot.js'],
nodeBootFiles = ['node_boot.js'],
cssFiles = [],
jsFiles = [],
jsFilesToSkip = ['jasmine.js'].concat(bootFiles, nodeBootFiles);
jsFilesToSkip = ['jasmine.js'].concat(bootFiles, legacyBootFiles, nodeBootFiles);
fs.readdirSync(rootPath).forEach(function(file) {
if(fs.statSync(path.join(rootPath, file)).isFile()) {

View File

@@ -1,3 +1,28 @@
if ENV["SUPPRESS_JASMINE_DEPRECATION"].nil?
puts <<~END_DEPRECATION_MSG
The Jasmine Ruby gems are deprecated. There will be no further releases after
the end of the Jasmine 3.x series. We recommend that most users migrate to the
jasmine-browser-runner npm package, which is the direct replacement for the
jasmine gem. See <https://jasmine.github.io/setup/browser.html> for setup
instructions, including for Rails applications that use either Sprockets or
Webpacker.
If jasmine-browser-runner doesn't meet your needs, one of these might:
* The jasmine npm package to run specs in Node.js:
<https://github.com/jasmine/jasmine-npm>
* The standalone distribution to run specs in browsers with no additional
tools: <https://github.com/jasmine/jasmine#installation>
* The jasmine-core npm package if all you need is the Jasmine assets:
<https://github.com/jasmine/jasmine>. This is the direct equivalent of the
jasmine-core Ruby gem.
To prevent this message from appearing, set the SUPPRESS_JASMINE_DEPRECATION
environment variable.
END_DEPRECATION_MSG
end
module Jasmine
module Core
class << self
@@ -6,7 +31,7 @@ module Jasmine
end
def js_files
(["jasmine.js"] + Dir.glob(File.join(path, "*.js"))).map { |f| File.basename(f) }.uniq - boot_files - node_boot_files
(["jasmine.js"] + Dir.glob(File.join(path, "*.js"))).map { |f| File.basename(f) }.uniq - boot_files - ["boot0.js", "boot1.js"] - node_boot_files
end
SPEC_TYPES = ["core", "html", "node"]
@@ -24,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
@@ -21,6 +21,10 @@ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
NOTE: This file is deprecated and will be removed in a future release.
Include both boot0.js and boot1.js (in that order) instead.
Starting with version 2.0, this file "boots" Jasmine, performing all of the necessary initialization before executing the loaded environment and all of a project's specs. This file should be loaded after `jasmine.js` and `jasmine_html.js`, but before any project source files or spec files are loaded. Thus this file can also be used to customize Jasmine for a project.
If a project is using Jasmine via the standalone distribution, this file can be customized directly. If a project is using Jasmine via the [Ruby gem][jasmine-gem], this file can be copied into the support directory via `jasmine copy_boot_js`. Other environments (e.g., Python) will have different mechanisms.
@@ -77,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")
};
@@ -158,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

@@ -1,4 +1,8 @@
/**
NOTE: This file is deprecated and will be removed in a future release.
Include both boot0.js and boot1.js (in that order) instead.
Starting with version 2.0, this file "boots" Jasmine, performing all of the necessary initialization before executing the loaded environment and all of a project's specs. This file should be loaded after `jasmine.js` and `jasmine_html.js`, but before any project source files or spec files are loaded. Thus this file can also be used to customize Jasmine for a project.
If a project is using Jasmine via the standalone distribution, this file can be customized directly. If a project is using Jasmine via the [Ruby gem][jasmine-gem], this file can be copied into the support directory via `jasmine copy_boot_js`. Other environments (e.g., Python) will have different mechanisms.
@@ -55,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")
};
@@ -136,4 +140,6 @@
return destination;
}
env.deprecated('boot.js is deprecated. Please use boot0.js and boot1.js instead.',
{ ignoreRunnable: true });
}());

View File

@@ -0,0 +1,42 @@
/**
This file starts the process of "booting" Jasmine. It initializes Jasmine,
makes its globals available, and creates the env. This file should be loaded
after `jasmine.js` and `jasmine_html.js`, but before `boot1.js` or any project
source files or spec files are loaded.
*/
(function() {
var jasmineRequire = window.jasmineRequire || require('./jasmine.js');
/**
* ## Require &amp; Instantiate
*
* Require Jasmine's core files. Specifically, this requires and attaches all of Jasmine's code to the `jasmine` reference.
*/
var jasmine = jasmineRequire.core(jasmineRequire),
global = jasmine.getGlobal();
global.jasmine = jasmine;
/**
* Since this is being run in a browser and the results should populate to an HTML page, require the HTML-specific Jasmine code, injecting the same reference.
*/
jasmineRequire.html(jasmine);
/**
* Create the Jasmine environment. This is used to run all specs in a project.
*/
var env = jasmine.getEnv();
/**
* ## The Global Interface
*
* Build up the functions that will be exposed as the Jasmine public interface. A project can customize, rename or alias any of these functions as desired, provided the implementation remains unchanged.
*/
var jasmineInterface = jasmineRequire.interface(jasmine, env);
/**
* Add all of the Jasmine global/public interface to the global scope, so a project can use the public interface directly. For example, calling `describe` in specs instead of `jasmine.getEnv().describe`.
*/
for (var property in jasmineInterface) {
global[property] = jasmineInterface[property];
}
}());

View File

@@ -0,0 +1,111 @@
/**
This file finishes "booting" Jasmine, performing all of the necessary
initialization before executing the loaded environment and all of a project's
specs. This file should be loaded after `boot0.js` but before any project
source files or spec files are loaded. Thus this file can also be used to
customize Jasmine for a project.
If a project is using Jasmine via the standalone distribution, this file can
be customized directly. If you only wish to configure the Jasmine env, you
can load another file that calls `jasmine.getEnv().configure({...})`
after `boot0.js` is loaded and before this file is loaded.
*/
(function() {
var env = jasmine.getEnv();
/**
* ## Runner Parameters
*
* More browser specific code - wrap the query string in an object and to allow for getting/setting parameters from the runner user interface.
*/
var queryString = new jasmine.QueryString({
getWindowLocation: function() { return window.location; }
});
var filterSpecs = !!queryString.getParam("spec");
var config = {
stopOnSpecFailure: queryString.getParam("failFast"),
stopSpecOnExpectationFailure: queryString.getParam("oneFailurePerSpec"),
hideDisabled: queryString.getParam("hideDisabled")
};
var random = queryString.getParam("random");
if (random !== undefined && random !== "") {
config.random = random;
}
var seed = queryString.getParam("seed");
if (seed) {
config.seed = seed;
}
/**
* ## Reporters
* The `HtmlReporter` builds all of the HTML UI for the runner page. This reporter paints the dots, stars, and x's for specs, as well as all spec names and all failures (if any).
*/
var htmlReporter = new jasmine.HtmlReporter({
env: env,
navigateWithNewParam: function(key, value) { return queryString.navigateWithNewParam(key, value); },
addToExistingQueryString: function(key, value) { return queryString.fullStringWithNewParam(key, value); },
getContainer: function() { return document.body; },
createElement: function() { return document.createElement.apply(document, arguments); },
createTextNode: function() { return document.createTextNode.apply(document, arguments); },
timer: new jasmine.Timer(),
filterSpecs: filterSpecs
});
/**
* The `jsApiReporter` also receives spec results, and is used by any environment that needs to extract the results from JavaScript.
*/
env.addReporter(jsApiReporter);
env.addReporter(htmlReporter);
/**
* Filter which specs will be run by matching the start of the full name against the `spec` query param.
*/
var specFilter = new jasmine.HtmlSpecFilter({
filterString: function() { return queryString.getParam("spec"); }
});
config.specFilter = function(spec) {
return specFilter.matches(spec.getFullName());
};
env.configure(config);
/**
* Setting up timing functions to be able to be overridden. Certain browsers (Safari, IE 8, phantomjs) require this hack.
*/
window.setTimeout = window.setTimeout;
window.setInterval = window.setInterval;
window.clearTimeout = window.clearTimeout;
window.clearInterval = window.clearInterval;
/**
* ## Execution
*
* Replace the browser window's `onload`, ensure it's called, and then run all of the loaded specs. This includes initializing the `HtmlReporter` instance and then executing the loaded Jasmine environment. All of this will happen after all of the specs are loaded.
*/
var currentWindowOnload = window.onload;
window.onload = function() {
if (currentWindowOnload) {
currentWindowOnload();
}
htmlReporter.initialize();
env.execute();
};
/**
* Helper function for readability above.
*/
function extend(destination, source) {
for (var property in source) destination[property] = source[property];
return destination;
}
}());

64
lib/jasmine-core/boot0.js Normal file
View File

@@ -0,0 +1,64 @@
/*
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
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
This file starts the process of "booting" Jasmine. It initializes Jasmine,
makes its globals available, and creates the env. This file should be loaded
after `jasmine.js` and `jasmine_html.js`, but before `boot1.js` or any project
source files or spec files are loaded.
*/
(function() {
var jasmineRequire = window.jasmineRequire || require('./jasmine.js');
/**
* ## Require &amp; Instantiate
*
* Require Jasmine's core files. Specifically, this requires and attaches all of Jasmine's code to the `jasmine` reference.
*/
var jasmine = jasmineRequire.core(jasmineRequire),
global = jasmine.getGlobal();
global.jasmine = jasmine;
/**
* Since this is being run in a browser and the results should populate to an HTML page, require the HTML-specific Jasmine code, injecting the same reference.
*/
jasmineRequire.html(jasmine);
/**
* Create the Jasmine environment. This is used to run all specs in a project.
*/
var env = jasmine.getEnv();
/**
* ## The Global Interface
*
* Build up the functions that will be exposed as the Jasmine public interface. A project can customize, rename or alias any of these functions as desired, provided the implementation remains unchanged.
*/
var jasmineInterface = jasmineRequire.interface(jasmine, env);
/**
* Add all of the Jasmine global/public interface to the global scope, so a project can use the public interface directly. For example, calling `describe` in specs instead of `jasmine.getEnv().describe`.
*/
for (var property in jasmineInterface) {
global[property] = jasmineInterface[property];
}
}());

133
lib/jasmine-core/boot1.js Normal file
View File

@@ -0,0 +1,133 @@
/*
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
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
This file finishes "booting" Jasmine, performing all of the necessary
initialization before executing the loaded environment and all of a project's
specs. This file should be loaded after `boot0.js` but before any project
source files or spec files are loaded. Thus this file can also be used to
customize Jasmine for a project.
If a project is using Jasmine via the standalone distribution, this file can
be customized directly. If you only wish to configure the Jasmine env, you
can load another file that calls `jasmine.getEnv().configure({...})`
after `boot0.js` is loaded and before this file is loaded.
*/
(function() {
var env = jasmine.getEnv();
/**
* ## Runner Parameters
*
* More browser specific code - wrap the query string in an object and to allow for getting/setting parameters from the runner user interface.
*/
var queryString = new jasmine.QueryString({
getWindowLocation: function() { return window.location; }
});
var filterSpecs = !!queryString.getParam("spec");
var config = {
stopOnSpecFailure: queryString.getParam("failFast"),
stopSpecOnExpectationFailure: queryString.getParam("oneFailurePerSpec"),
hideDisabled: queryString.getParam("hideDisabled")
};
var random = queryString.getParam("random");
if (random !== undefined && random !== "") {
config.random = random;
}
var seed = queryString.getParam("seed");
if (seed) {
config.seed = seed;
}
/**
* ## Reporters
* The `HtmlReporter` builds all of the HTML UI for the runner page. This reporter paints the dots, stars, and x's for specs, as well as all spec names and all failures (if any).
*/
var htmlReporter = new jasmine.HtmlReporter({
env: env,
navigateWithNewParam: function(key, value) { return queryString.navigateWithNewParam(key, value); },
addToExistingQueryString: function(key, value) { return queryString.fullStringWithNewParam(key, value); },
getContainer: function() { return document.body; },
createElement: function() { return document.createElement.apply(document, arguments); },
createTextNode: function() { return document.createTextNode.apply(document, arguments); },
timer: new jasmine.Timer(),
filterSpecs: filterSpecs
});
/**
* The `jsApiReporter` also receives spec results, and is used by any environment that needs to extract the results from JavaScript.
*/
env.addReporter(jsApiReporter);
env.addReporter(htmlReporter);
/**
* Filter which specs will be run by matching the start of the full name against the `spec` query param.
*/
var specFilter = new jasmine.HtmlSpecFilter({
filterString: function() { return queryString.getParam("spec"); }
});
config.specFilter = function(spec) {
return specFilter.matches(spec.getFullName());
};
env.configure(config);
/**
* Setting up timing functions to be able to be overridden. Certain browsers (Safari, IE 8, phantomjs) require this hack.
*/
window.setTimeout = window.setTimeout;
window.setInterval = window.setInterval;
window.clearTimeout = window.clearTimeout;
window.clearInterval = window.clearInterval;
/**
* ## Execution
*
* Replace the browser window's `onload`, ensure it's called, and then run all of the loaded specs. This includes initializing the `HtmlReporter` instance and then executing the loaded Jasmine environment. All of this will happen after all of the specs are loaded.
*/
var currentWindowOnload = window.onload;
window.onload = function() {
if (currentWindowOnload) {
currentWindowOnload();
}
htmlReporter.initialize();
env.execute();
};
/**
* Helper function for readability above.
*/
function extend(destination, source) {
for (var property in source) destination[property] = source[property];
return destination;
}
}());

View File

@@ -54,9 +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')
# 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)
@@ -86,4 +91,4 @@ class Core(object):
seen[marker] = 1
result.append(item)
return result
return result

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
)
);
}
@@ -558,17 +569,20 @@ jasmineRequire.HtmlReporter = function(j$) {
);
var failFastCheckbox = optionsMenuDom.querySelector('#jasmine-fail-fast');
failFastCheckbox.checked = config.failFast;
failFastCheckbox.checked = config.stopOnSpecFailure;
failFastCheckbox.onclick = function() {
navigateWithNewParam('failFast', !config.failFast);
navigateWithNewParam('failFast', !config.stopOnSpecFailure);
};
var throwCheckbox = optionsMenuDom.querySelector(
'#jasmine-throw-failures'
);
throwCheckbox.checked = config.oneFailurePerSpec;
throwCheckbox.checked = config.stopSpecOnExpectationFailure;
throwCheckbox.onclick = function() {
navigateWithNewParam('oneFailurePerSpec', !config.oneFailurePerSpec);
navigateWithNewParam(
'oneFailurePerSpec',
!config.stopSpecOnExpectationFailure
);
};
var randomCheckbox = optionsMenuDom.querySelector(
@@ -649,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);
}
@@ -673,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.8.0"
VERSION = "3.99.1"
end
end

View File

@@ -1,7 +1,7 @@
{
"name": "jasmine-core",
"license": "MIT",
"version": "3.8.0",
"version": "3.99.1",
"repository": {
"type": "git",
"url": "https://github.com/jasmine/jasmine.git"
@@ -37,7 +37,6 @@
"ejs": "^2.5.5",
"eslint": "^6.8.0",
"eslint-plugin-compat": "^3.8.0",
"fast-check": "^1.21.0",
"fast-glob": "^2.2.6",
"grunt": "^1.0.4",
"grunt-cli": "^1.3.2",
@@ -45,8 +44,8 @@
"grunt-contrib-concat": "^1.0.1",
"grunt-css-url-embed": "^1.11.1",
"grunt-sass": "^3.0.2",
"jasmine": "^3.4.0",
"jasmine-browser-runner": "github:jasmine/jasmine-browser#main",
"jasmine": "^3.10.0",
"jasmine-browser-runner": "^0.10.0",
"jsdom": "^15.0.0",
"load-grunt-tasks": "^4.0.0",
"prettier": "1.17.1",

57
release_notes/3.10.0.md Normal file
View File

@@ -0,0 +1,57 @@
# Jasmine Core 3.10 Release Notes
## New features and bug fixes
* Added support for running Jasmine multiple times
* If the env is configured with `autoCleanClosures: false`, then it can be
executed repeatedly.
* Merges #1934 from @nicojs
* Fixes #1925
* Improved error message when an async expectation occurs after the spec
finishes
* Merges #1937 from @AndreWillomitzer
* Fixes #1854
* Reject timeout values that are too large for setTimeout
* See #1930
* Don't immediately move to the next queueable fn on async error
This allows assertion failures and other errors that occur after the async
error to be routed to the correct spec/suite.
* Added a stringContaining asymmetric equality tester
* Fixes #1923.
* The jasmine-core Ruby gem now prints a deprecation message when loaded unless
the SUPPRESS_JASMINE_DEPRECATION environment variable is set.
## Documentation updates
* Added discussion of max timeout value to jsdocs
* Merges #1931 from @trusktr
* Added missing @since annotations
* Improved jsdocs for asymmetric equality testers
* 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)_

65
release_notes/3.9.0.md Normal file
View File

@@ -0,0 +1,65 @@
# Jasmine Core 3.9 Release Notes
## New features and bug fixes
* Fixed Trusted Types error in `j$.isError_` in Chromium-based browsers
* Merges [#1921](https://github.com/jasmine/jasmine/pull/1921) from @bjarkler
* Fixes [#1910](https://github.com/jasmine/jasmine/issues/1910)
* Fixes [#1653](https://github.com/jasmine/jasmine/issues/1653)
* Better reporting of unhandled promise rejections with truthy but non-`Error`
reasons on Node
* `Env#execute` returns a promise in environments that support promises
* Renamed `failFast` and `oneFailurePerSpec` config props to `stopOnSpecFailure`
and `stopSpecOnExpectationFailure`
The new names are more self-explanatory and consistent with jasmine-npm. The
old names are deprecated but will still work until the next major release.
* Split `boot.js` into two files to allow the env to be configured in between
This is mainly intended to support jasmine-browser-runner, which will load
a script that configures the env in between the two boot files (`boot0.js` and
`boot1.js`). The single-file `boot.js` will still be included until the next
major release.
## Ruby deprecation
The Jasmine Ruby gems are deprecated. There will be no further releases after
the end of the Jasmine 3.x series. We recommend that most users migrate to the
[jasmine-browser-runner](https://github.com/jasmine/jasmine-browser)
npm package, which is the direct replacement for the `jasmine` gem.
If `jasmine-browser-runner` doesn't meet your needs, one of these might:
* The [jasmine](https://github.com/jasmine/jasmine-npm) npm package to run
specs in Node.js.
* The [standalone distribution](https://github.com/jasmine/jasmine#installation)
to run specs in browsers with no additional tools.
* The [jasmine-core](https://github.com/jasmine/jasmine) npm package if all
you need is the Jasmine assets. This is the direct equivalent of the
`jasmine-core` Ruby gem.
## Documentation updates
* Added API docs for `Suite#id` and `Spec#id`
* Marked `Env#hideDisabled` deprecated in jsdocs
------
## Supported environments
jasmine-core 3.9.0 has been tested in the following environments.
| Environment | Supported versions |
|-------------------|--------------------|
| Node | 10, 12, 14, 16 |
| Safari | 8-14 |
| Chrome | 92 |
| Firefox | 91, 78, 68 |
| Edge | 92 |
| Internet Explorer | 10, 11 |
_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)_

22
release_notes/3.99.1.md Normal file
View File

@@ -0,0 +1,22 @@
# Jasmine Core 3.99.1 Release Notes
This release fixes a bug in 3.99.0, which incorrectly reported a deprecation
warning when a promise returned from a function passed to `it`, `beforeEach`,
etc was resolved to a value.
## Supported environments
jasmine-core 3.99.1 has been tested in the following environments.
| Environment | Supported versions |
|-------------------|--------------------|
| Node | 10, 12, 14, 16 |
| Safari | 10-14 |
| Chrome | 98 |
| Firefox | 97, 78, 68 |
| Edge | 98 |
| Internet Explorer | 10, 11 |
------
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_

View File

@@ -27,12 +27,11 @@ 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
run_browser safari 13
run_browser safari 9
run_browser safari 8
run_browser MicrosoftEdge latest
echo

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() {});
@@ -60,6 +279,119 @@ describe('Env', function() {
);
});
it('ignores configuration properties that are present but undefined', function() {
spyOn(env, 'deprecated');
var initialConfig = {
random: true,
seed: '123',
failFast: true,
failSpecWithNoExpectations: true,
oneFailurePerSpec: true,
stopSpecOnExpectationFailure: true,
stopOnSpecFailure: true,
hideDisabled: true
};
env.configure(initialConfig);
env.configure({
random: undefined,
seed: undefined,
failFast: undefined,
failSpecWithNoExpectations: undefined,
oneFailurePerSpec: undefined,
stopSpecOnExpectationFailure: undefined,
stopOnSpecFailure: undefined,
hideDisabled: undefined
});
expect(env.configuration()).toEqual(
jasmine.objectContaining(initialConfig)
);
});
it('sets stopOnSpecFailure when failFast is set, and vice versa', function() {
spyOn(env, 'deprecated');
env.configure({ failFast: true });
expect(env.configuration()).toEqual(
jasmine.objectContaining({
failFast: true,
stopOnSpecFailure: true
})
);
env.configure({ stopOnSpecFailure: false });
expect(env.configuration()).toEqual(
jasmine.objectContaining({
failFast: false,
stopOnSpecFailure: false
})
);
});
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(
'stopOnSpecFailure and failFast are aliases for each ' +
"other. Don't set failFast if you also set stopOnSpecFailure."
);
});
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({
oneFailurePerSpec: true,
stopSpecOnExpectationFailure: true
})
);
env.configure({ stopSpecOnExpectationFailure: false });
expect(env.configuration()).toEqual(
jasmine.objectContaining({
oneFailurePerSpec: false,
stopSpecOnExpectationFailure: false
})
);
});
it('rejects a single call that sets stopSpecOnExpectationFailure and oneFailurePerSpec to different values', function() {
spyOn(env, 'deprecated');
expect(function() {
env.configure({
oneFailurePerSpec: true,
stopSpecOnExpectationFailure: false
});
}).toThrowError(
'stopSpecOnExpectationFailure and oneFailurePerSpec are ' +
"aliases for each other. Don't set oneFailurePerSpec if you also set " +
'stopSpecOnExpectationFailure.'
);
});
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({});
@@ -67,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() {
@@ -141,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() {
@@ -169,12 +520,30 @@ describe('Env', function() {
env.it('async', jasmine.getEnv().makeAsyncAwaitFunction());
}).not.toThrow();
});
it('throws an error when the timeout value is too large for setTimeout', function() {
expect(function() {
env.it('huge timeout', function() {}, 2147483648);
}).toThrowError('Timeout value cannot be greater than 2147483647');
});
});
describe('#xit', function() {
it('calls spec.exclude with "Temporarily disabled with xit"', function() {
var excludeSpy = jasmine.createSpy();
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();
spyOn(env, 'it').and.returnValue({
var realExclude = jasmineUnderTest.Spec.prototype.exclude;
spyOn(env, 'it_').and.returnValue({
exclude: realExclude,
pend: pendSpy
});
env.xit('foo', function() {});
@@ -211,6 +580,12 @@ describe('Env', function() {
/fit expects a function argument; received \[object (Undefined|DOMWindow|Object)\]/
);
});
it('throws an error when the timeout value is too large for setTimeout', function() {
expect(function() {
env.fit('huge timeout', function() {}, 2147483648);
}).toThrowError('Timeout value cannot be greater than 2147483647');
});
});
describe('#beforeEach', function() {
@@ -228,6 +603,12 @@ describe('Env', function() {
env.beforeEach(jasmine.getEnv().makeAsyncAwaitFunction());
}).not.toThrow();
});
it('throws an error when the timeout value is too large for setTimeout', function() {
expect(function() {
env.beforeEach(function() {}, 2147483648);
}).toThrowError('Timeout value cannot be greater than 2147483647');
});
});
describe('#beforeAll', function() {
@@ -245,6 +626,12 @@ describe('Env', function() {
env.beforeAll(jasmine.getEnv().makeAsyncAwaitFunction());
}).not.toThrow();
});
it('throws an error when the timeout value is too large for setTimeout', function() {
expect(function() {
env.beforeAll(function() {}, 2147483648);
}).toThrowError('Timeout value cannot be greater than 2147483647');
});
});
describe('#afterEach', function() {
@@ -262,6 +649,12 @@ describe('Env', function() {
env.afterEach(jasmine.getEnv().makeAsyncAwaitFunction());
}).not.toThrow();
});
it('throws an error when the timeout value is too large for setTimeout', function() {
expect(function() {
env.afterEach(function() {}, 2147483648);
}).toThrowError('Timeout value cannot be greater than 2147483647');
});
});
describe('#afterAll', function() {
@@ -279,6 +672,12 @@ describe('Env', function() {
env.afterAll(jasmine.getEnv().makeAsyncAwaitFunction());
}).not.toThrow();
});
it('throws an error when the timeout value is too large for setTimeout', function() {
expect(function() {
env.afterAll(function() {}, 2147483648);
}).toThrowError('Timeout value cannot be greater than 2147483647');
});
});
describe('when not constructed with suppressLoadErrors: true', function() {
@@ -378,4 +777,90 @@ describe('Env', function() {
done();
});
});
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();
expect(env.execute()).toBeInstanceOf(Promise);
});
it('returns a promise when a custom promise constructor is provided', function() {
function CustomPromise() {}
CustomPromise.resolve = function() {};
CustomPromise.reject = function() {};
spyOn(env, 'deprecated');
env.configure({ Promise: CustomPromise });
expect(env.execute()).toBeInstanceOf(CustomPromise);
});
it('returns undefined when promises are unavailable', function() {
jasmine.getEnv().requireNoPromises();
expect(env.execute()).toBeUndefined();
});
it('should reset the topSuite when run twice', function() {
jasmine.getEnv().requirePromises();
spyOn(jasmineUnderTest.Suite.prototype, 'reset');
return env
.execute() // 1
.then(function() {
return env.execute(); // 2
})
.then(function() {
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

@@ -170,84 +170,118 @@ describe('GlobalErrors', function() {
);
});
it('reports unhandled promise rejections in node.js', function() {
var fakeGlobal = {
process: {
on: jasmine.createSpy('process.on'),
removeListener: jasmine.createSpy('process.removeListener'),
listeners: jasmine
.createSpy('process.listeners')
.and.returnValue(['foo']),
removeAllListeners: jasmine.createSpy('process.removeAllListeners')
}
},
handler = jasmine.createSpy('errorHandler'),
errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
describe('Reporting unhandled promise rejections in node.js', function() {
it('reports rejections with `Error` reasons', function() {
var fakeGlobal = {
process: {
on: jasmine.createSpy('process.on'),
removeListener: jasmine.createSpy('process.removeListener'),
listeners: jasmine
.createSpy('process.listeners')
.and.returnValue(['foo']),
removeAllListeners: jasmine.createSpy('process.removeAllListeners')
}
},
handler = jasmine.createSpy('errorHandler'),
errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
errors.install();
expect(fakeGlobal.process.on).toHaveBeenCalledWith(
'unhandledRejection',
jasmine.any(Function)
);
expect(fakeGlobal.process.listeners).toHaveBeenCalledWith(
'unhandledRejection'
);
expect(fakeGlobal.process.removeAllListeners).toHaveBeenCalledWith(
'unhandledRejection'
);
errors.install();
expect(fakeGlobal.process.on).toHaveBeenCalledWith(
'unhandledRejection',
jasmine.any(Function)
);
expect(fakeGlobal.process.listeners).toHaveBeenCalledWith(
'unhandledRejection'
);
expect(fakeGlobal.process.removeAllListeners).toHaveBeenCalledWith(
'unhandledRejection'
);
errors.pushListener(handler);
errors.pushListener(handler);
var addedListener = fakeGlobal.process.on.calls.argsFor(1)[1];
addedListener(new Error('bar'));
var addedListener = fakeGlobal.process.on.calls.argsFor(1)[1];
addedListener(new Error('bar'));
expect(handler).toHaveBeenCalledWith(new Error('bar'));
expect(handler.calls.argsFor(0)[0].jasmineMessage).toBe(
'Unhandled promise rejection: Error: bar'
);
expect(handler).toHaveBeenCalledWith(new Error('bar'));
expect(handler.calls.argsFor(0)[0].jasmineMessage).toBe(
'Unhandled promise rejection: Error: bar'
);
errors.uninstall();
errors.uninstall();
expect(fakeGlobal.process.removeListener).toHaveBeenCalledWith(
'unhandledRejection',
addedListener
);
expect(fakeGlobal.process.on).toHaveBeenCalledWith(
'unhandledRejection',
'foo'
);
});
expect(fakeGlobal.process.removeListener).toHaveBeenCalledWith(
'unhandledRejection',
addedListener
);
expect(fakeGlobal.process.on).toHaveBeenCalledWith(
'unhandledRejection',
'foo'
);
});
it('reports unhandled promise rejections in node.js when no error is provided', function() {
var fakeGlobal = {
process: {
on: jasmine.createSpy('process.on'),
removeListener: function() {},
listeners: function() {
return [];
},
removeAllListeners: function() {}
}
},
handler = jasmine.createSpy('errorHandler'),
errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
it('reports rejections with non-`Error` reasons', function() {
var fakeGlobal = {
process: {
on: jasmine.createSpy('process.on'),
removeListener: function() {},
listeners: function() {
return [];
},
removeAllListeners: function() {}
}
},
handler = jasmine.createSpy('errorHandler'),
errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
errors.install();
errors.pushListener(handler);
errors.install();
errors.pushListener(handler);
expect(fakeGlobal.process.on.calls.argsFor(1)[0]).toEqual(
'unhandledRejection'
);
var addedListener = fakeGlobal.process.on.calls.argsFor(1)[1];
addedListener(undefined);
expect(fakeGlobal.process.on.calls.argsFor(1)[0]).toEqual(
'unhandledRejection'
);
var addedListener = fakeGlobal.process.on.calls.argsFor(1)[1];
addedListener(17);
expect(handler).toHaveBeenCalledWith(
new Error(
'Unhandled promise rejection with no error or message\n' +
'(Tip: to get a useful stack trace, use ' +
'Promise.reject(new Error(...)) instead of Promise.reject().)'
)
);
expect(handler).toHaveBeenCalledWith(
new Error(
'Unhandled promise rejection: 17\n' +
'(Tip: to get a useful stack trace, use ' +
'Promise.reject(new Error(...)) instead of Promise.reject(...).)'
)
);
});
it('reports rejections with no reason provided', function() {
var fakeGlobal = {
process: {
on: jasmine.createSpy('process.on'),
removeListener: function() {},
listeners: function() {
return [];
},
removeAllListeners: function() {}
}
},
handler = jasmine.createSpy('errorHandler'),
errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
errors.install();
errors.pushListener(handler);
expect(fakeGlobal.process.on.calls.argsFor(1)[0]).toEqual(
'unhandledRejection'
);
var addedListener = fakeGlobal.process.on.calls.argsFor(1)[1];
addedListener(undefined);
expect(handler).toHaveBeenCalledWith(
new Error(
'Unhandled promise rejection with no error or message\n' +
'(Tip: to get a useful stack trace, use ' +
'Promise.reject(new Error(...)) instead of Promise.reject().)'
)
);
});
});
describe('Reporting unhandled promise rejections in the browser', function() {

View File

@@ -149,31 +149,192 @@ 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();
});
});
describe('as a result of a promise', function() {
describe('and the argument is an Error', function() {
// Since promise support was added, Jasmine has failed specs that
// return a promise that resolves to an error. That's probably not
// the desired behavior but it's also not something we should change
// except on a major release and with a deprecation warning in
// advance.
it('explicitly fails and moves to the next function', function(done) {
jasmine.getEnv().requirePromises();
var err = new Error('foo'),
queueableFn1 = {
fn: function() {
// eslint-disable-next-line compat/compat
return Promise.resolve(err);
}
},
queueableFn2 = { fn: jasmine.createSpy('fn2') },
failFn = jasmine.createSpy('fail'),
queueRunner = new jasmineUnderTest.QueueRunner({
queueableFns: [queueableFn1, queueableFn2],
fail: failFn,
onComplete: function() {
expect(failFn).toHaveBeenCalledWith(err);
expect(queueableFn2.fn).toHaveBeenCalled();
done();
}
});
queueRunner.execute();
});
it('does not log a deprecation', function(done) {
jasmine.getEnv().requirePromises();
var err = new Error('foo'),
queueableFn1 = {
fn: function() {
// eslint-disable-next-line compat/compat
return Promise.resolve(err);
}
},
deprecated = jasmine.createSpy('deprecated'),
queueRunner = new jasmineUnderTest.QueueRunner({
queueableFns: [queueableFn1],
deprecated: deprecated,
onComplete: function() {
expect(deprecated).not.toHaveBeenCalled();
done();
}
});
queueRunner.execute();
});
});
describe('and the argument is not an Error', function() {
it('does not log a deprecation or report a failure', function(done) {
jasmine.getEnv().requirePromises();
var queueableFn1 = {
fn: function() {
// eslint-disable-next-line compat/compat
return Promise.resolve('not an error');
}
},
failFn = jasmine.createSpy('fail'),
deprecated = jasmine.createSpy('deprecated'),
queueRunner = new jasmineUnderTest.QueueRunner({
queueableFns: [queueableFn1],
deprecated: deprecated,
fail: failFn,
onComplete: function() {
expect(deprecated).not.toHaveBeenCalled();
expect(failFn).not.toHaveBeenCalled();
done();
}
});
queueRunner.execute();
});
});
});
});
it('does not cause an explicit fail if execution is being stopped', function() {
@@ -225,6 +386,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 +487,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 +507,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 +717,7 @@ describe('QueueRunner', function() {
queueRunner = new jasmineUnderTest.QueueRunner({
queueableFns: [queueableFn],
deprecated: deprecated
}),
env = jasmineUnderTest.getEnv();
});
queueRunner.execute();
@@ -533,7 +726,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 +747,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 }
);
});
});
@@ -669,9 +864,13 @@ describe('QueueRunner', function() {
jasmine.clock().uninstall();
});
it('skips to cleanup functions on the first exception', function() {
it('skips to cleanup functions once the fn completes after an unhandled exception', function() {
var errorListeners = [],
queueableFn = { fn: function(done) {} },
queueableFn = {
fn: function(done) {
queueableFnDone = done;
}
},
nextQueueableFn = { fn: jasmine.createSpy('nextFunction') },
cleanupFn = { fn: jasmine.createSpy('cleanup') },
queueRunner = new jasmineUnderTest.QueueRunner({
@@ -686,10 +885,13 @@ describe('QueueRunner', function() {
queueableFns: [queueableFn, nextQueueableFn],
cleanupFns: [cleanupFn],
completeOnFirstError: true
});
}),
queueableFnDone;
queueRunner.execute();
errorListeners[errorListeners.length - 1](new Error('error'));
expect(cleanupFn.fn).not.toHaveBeenCalled();
queueableFnDone();
expect(nextQueueableFn.fn).not.toHaveBeenCalled();
expect(cleanupFn.fn).toHaveBeenCalled();
});

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

@@ -142,4 +142,130 @@ describe('Suite', function() {
);
});
});
describe('attr.autoCleanClosures', function() {
function arrangeSuite(attrs) {
var suite = new jasmineUnderTest.Suite(attrs);
suite.beforeAll(function() {});
suite.beforeEach(function() {});
suite.afterEach(function() {});
suite.afterAll(function() {});
return suite;
}
it('should clean closures when "attr.autoCleanClosures" is missing', function() {
var suite = arrangeSuite({});
suite.cleanupBeforeAfter();
expect(suite.beforeAllFns[0].fn).toBe(null);
expect(suite.beforeFns[0].fn).toBe(null);
expect(suite.afterFns[0].fn).toBe(null);
expect(suite.afterAllFns[0].fn).toBe(null);
});
it('should clean closures when "attr.autoCleanClosures" is true', function() {
var suite = arrangeSuite({ autoCleanClosures: true });
suite.cleanupBeforeAfter();
expect(suite.beforeAllFns[0].fn).toBe(null);
expect(suite.beforeFns[0].fn).toBe(null);
expect(suite.afterFns[0].fn).toBe(null);
expect(suite.afterAllFns[0].fn).toBe(null);
});
it('should NOT clean closures when "attr.autoCleanClosures" is false', function() {
var suite = arrangeSuite({ autoCleanClosures: false });
suite.cleanupBeforeAfter();
expect(suite.beforeAllFns[0].fn).not.toBe(null);
expect(suite.beforeFns[0].fn).not.toBe(null);
expect(suite.afterFns[0].fn).not.toBe(null);
expect(suite.afterAllFns[0].fn).not.toBe(null);
});
});
describe('#reset', function() {
it('should reset the "pending" status', function() {
var suite = new jasmineUnderTest.Suite({});
suite.pend();
suite.reset();
expect(suite.getResult().status).toBe('passed');
});
it('should not reset the "pending" status when the suite was excluded', function() {
var suite = new jasmineUnderTest.Suite({});
suite.exclude();
suite.reset();
expect(suite.getResult().status).toBe('pending');
});
it('should also reset the children', function() {
var suite = new jasmineUnderTest.Suite({});
var child1 = jasmine.createSpyObj(['reset']);
var child2 = jasmine.createSpyObj(['reset']);
suite.addChild(child1);
suite.addChild(child2);
suite.reset();
expect(child1.reset).toHaveBeenCalled();
expect(child2.reset).toHaveBeenCalled();
});
it('should reset the failedExpectations', function() {
var suite = new jasmineUnderTest.Suite({
expectationResultFactory: function(error) {
return error;
}
});
suite.onException(new Error());
suite.reset();
var result = suite.getResult();
expect(result.status).toBe('passed');
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

@@ -0,0 +1,27 @@
describe('StringContaining', function() {
it('searches for a provided substring when the expected is a String', function() {
var matcher = new jasmineUnderTest.StringContaining('foo');
expect(matcher.asymmetricMatch('barfoobaz')).toBe(true);
expect(matcher.asymmetricMatch('barbaz')).toBe(false);
});
it('raises an Error when the expected is not a String', function() {
expect(function() {
new jasmineUnderTest.StringContaining(/foo/);
}).toThrowError(/not a String/);
});
it('fails when the actual is not a String', function() {
var matcher = new jasmineUnderTest.StringContaining('x');
expect(matcher.asymmetricMatch(['x'])).toBe(false);
});
it("jasmineToString's itself", function() {
var matching = new jasmineUnderTest.StringContaining('foo');
expect(matching.jasmineToString()).toEqual(
'<jasmine.stringContaining("foo")>'
);
});
});

View File

@@ -29,6 +29,43 @@ describe('base helpers', function() {
}
}, 100);
});
it('returns true for an Error subclass', function() {
function MyError() {}
MyError.prototype = new Error();
expect(jasmineUnderTest.isError_(new MyError())).toBe(true);
});
it('returns true for an un-thrown Error with no message in this environment', function() {
expect(jasmineUnderTest.isError_(new Error())).toBe(true);
});
it('returns true for an Error that originated from another frame', function() {
var iframe, error;
if (typeof window === 'undefined') {
pending('This test only runs in browsers.');
}
iframe = document.createElement('iframe');
iframe.style.display = 'none';
document.body.appendChild(iframe);
try {
error = iframe.contentWindow.eval('new Error()');
expect(jasmineUnderTest.isError_(error)).toBe(true);
} finally {
document.body.removeChild(iframe);
}
});
it('returns false for a falsy value', function() {
expect(jasmineUnderTest.isError_(undefined)).toBe(false);
});
it('returns false for a non-Error object', function() {
expect(jasmineUnderTest.isError_({})).toBe(false);
});
});
describe('isAsymmetricEqualityTester_', function() {
@@ -104,4 +141,49 @@ describe('base helpers', function() {
);
});
});
describe('DEFAULT_TIMEOUT_INTERVAL setter', function() {
var max = 2147483647;
beforeEach(function() {
this.initialValue = jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL;
});
afterEach(function() {
jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL = this.initialValue;
});
it('accepts only values <= ' + max, function() {
expect(function() {
jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL = max + 1;
}).toThrowError(
'jasmine.DEFAULT_TIMEOUT_INTERVAL cannot be greater than ' + max
);
jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL = max;
expect(jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL).toEqual(max);
});
it('is consistent with setTimeout in this environment', function(done) {
var f1 = jasmine.createSpy('setTimeout callback for ' + max),
f2 = jasmine.createSpy('setTimeout callback for ' + (max + 1)),
id;
// Suppress printing of TimeoutOverflowWarning in node
spyOn(console, 'error');
id = setTimeout(f1, max);
setTimeout(function() {
clearTimeout(id);
expect(f1).not.toHaveBeenCalled();
id = setTimeout(f2, max + 1);
setTimeout(function() {
clearTimeout(id);
expect(f2).toHaveBeenCalled();
done();
});
});
});
});
});

View File

@@ -231,6 +231,16 @@ describe('Asymmetric equality testers (Integration)', function() {
});
});
describe('stringContaining', function() {
verifyPasses(function(env) {
env.expect('foo').toEqual(jasmineUnderTest.stringContaining('o'));
});
verifyFails(function(env) {
env.expect('bar').toEqual(jasmineUnderTest.stringContaining('o'));
});
});
describe('truthy', function() {
verifyPasses(function(env) {
env.expect(true).toEqual(jasmineUnderTest.truthy());

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

@@ -465,7 +465,7 @@ describe('Env integration', function() {
var global = {
setTimeout: function(fn, delay) {
setTimeout(fn, delay);
return setTimeout(fn, delay);
},
clearTimeout: function(fn, delay) {
clearTimeout(fn, delay);
@@ -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']);
@@ -1018,7 +1212,7 @@ describe('Env integration', function() {
var globalSetTimeout = jasmine
.createSpy('globalSetTimeout')
.and.callFake(function(cb, t) {
setTimeout(cb, t);
return setTimeout(cb, t);
}),
delayedFunctionForGlobalClock = jasmine.createSpy(
'delayedFunctionForGlobalClock'
@@ -1033,7 +1227,7 @@ describe('Env integration', function() {
setTimeout: globalSetTimeout,
clearTimeout: clearTimeout,
setImmediate: function(cb) {
setTimeout(cb, 0);
return setTimeout(cb, 0);
}
}
});
@@ -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;
@@ -1108,7 +1338,7 @@ describe('Env integration', function() {
setInterval: setInterval,
clearInterval: clearInterval,
setImmediate: function(cb) {
realSetTimeout(cb, 0);
return realSetTimeout(cb, 0);
}
}
});
@@ -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() {
@@ -2255,7 +2488,7 @@ describe('Env integration', function() {
it('reports errors that occur during loading', function(done) {
var global = {
setTimeout: function(fn, delay) {
setTimeout(fn, delay);
return setTimeout(fn, delay);
},
clearTimeout: function(fn, delay) {
clearTimeout(fn, delay);
@@ -2312,7 +2545,7 @@ describe('Env integration', function() {
var originalOnerror = jasmine.createSpy('original onerror');
var global = {
setTimeout: function(fn, delay) {
setTimeout(fn, delay);
return setTimeout(fn, delay);
},
clearTimeout: function(fn, delay) {
clearTimeout(fn, delay);
@@ -2513,10 +2746,10 @@ describe('Env integration', function() {
it('is "failed"', function(done) {
var global = {
setTimeout: function(fn, delay) {
setTimeout(fn, delay);
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', [
@@ -2835,10 +3004,6 @@ describe('Env integration', function() {
});
it('provides custom equality testers to async matchers', function(done) {
if (jasmine.getEnv().skipBrowserFlake) {
jasmine.getEnv().skipBrowserFlake();
}
jasmine.getEnv().requirePromises();
var specDone = jasmine.createSpy('specDone');
@@ -2936,7 +3101,9 @@ describe('Env integration', function() {
message:
'Spec "a suite does not wait" ran a "toBeResolved" expectation ' +
'after it finished.\n' +
'Did you forget to return or await the result of expectAsync?',
'1. Did you forget to return or await the result of expectAsync?\n' +
'2. Was done() invoked before an async operation completed?\n' +
'3. Did an expectation follow a call to done()?',
matcherName: 'toBeResolved'
}),
jasmine.objectContaining({
@@ -2947,7 +3114,9 @@ describe('Env integration', function() {
'after it finished.\n' +
"Message: \"Expected a promise to be resolved to 'something else' " +
'but it was resolved to undefined."\n' +
'Did you forget to return or await the result of expectAsync?',
'1. Did you forget to return or await the result of expectAsync?\n' +
'2. Was done() invoked before an async operation completed?\n' +
'3. Did an expectation follow a call to done()?',
matcherName: 'toBeResolvedTo'
})
]);
@@ -3000,7 +3169,9 @@ describe('Env integration', function() {
message:
'Suite "a suite" ran a "toBeResolved" expectation ' +
'after it finished.\n' +
'Did you forget to return or await the result of expectAsync?',
'1. Did you forget to return or await the result of expectAsync?\n' +
'2. Was done() invoked before an async operation completed?\n' +
'3. Did an expectation follow a call to done()?',
matcherName: 'toBeResolved'
})
]);
@@ -3038,6 +3209,112 @@ describe('Env integration', function() {
env.execute(null, done);
});
describe('The promise returned by #execute', function() {
beforeEach(function() {
this.savedInterval = jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL;
});
afterEach(function() {
jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL = this.savedInterval;
});
it('is resolved after reporter events are dispatched', function() {
jasmine.getEnv().requirePromises();
var reporter = jasmine.createSpyObj('reporter', [
'specDone',
'suiteDone',
'jasmineDone'
]);
env.addReporter(reporter);
env.describe('suite', function() {
env.it('spec', function() {});
});
return env.execute(null).then(function() {
expect(reporter.specDone).toHaveBeenCalled();
expect(reporter.suiteDone).toHaveBeenCalled();
expect(reporter.jasmineDone).toHaveBeenCalled();
});
});
it('is resolved after the stack is cleared', function(done) {
jasmine.getEnv().requirePromises();
var realClearStack = jasmineUnderTest.getClearStack(
jasmineUnderTest.getGlobal()
),
clearStackSpy = jasmine
.createSpy('clearStack')
.and.callFake(realClearStack);
spyOn(jasmineUnderTest, 'getClearStack').and.returnValue(clearStackSpy);
// Create a new env that has the clearStack defined above
env.cleanup_();
env = new jasmineUnderTest.Env();
env.describe('suite', function() {
env.it('spec', function() {});
});
env.execute(null).then(function() {
expect(clearStackSpy).toHaveBeenCalled(); // (many times)
clearStackSpy.calls.reset();
setTimeout(function() {
expect(clearStackSpy).not.toHaveBeenCalled();
done();
});
});
});
it('is resolved after QueueRunner timeouts are cleared', function() {
jasmine.getEnv().requirePromises();
var setTimeoutSpy = spyOn(
jasmineUnderTest.getGlobal(),
'setTimeout'
).and.callThrough();
var clearTimeoutSpy = spyOn(
jasmineUnderTest.getGlobal(),
'clearTimeout'
).and.callThrough();
jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL = 123456; // a distinctive value
env = new jasmineUnderTest.Env();
env.describe('suite', function() {
env.it('spec', function() {});
});
return env.execute(null).then(function() {
var timeoutIds = setTimeoutSpy.calls
.all()
.filter(function(call) {
return call.args[1] === 123456;
})
.map(function(call) {
return call.returnValue;
});
expect(timeoutIds.length).toBeGreaterThan(0);
timeoutIds.forEach(function(timeoutId) {
expect(clearTimeoutSpy).toHaveBeenCalledWith(timeoutId);
});
});
});
it('is resolved even if specs fail', function() {
jasmine.getEnv().requirePromises();
env.describe('suite', function() {
env.it('spec', function() {
env.expect(true).toBe(false);
});
});
return expectAsync(env.execute(null)).toBeResolved();
});
});
describe('The optional callback argument to #execute', function() {
beforeEach(function() {
this.savedInterval = jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL;

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']);
@@ -980,35 +987,10 @@ describe('spec running', function() {
});
});
describe('when stopOnSpecFailure is on', function() {
function behavesLikeStopOnSpecFailureIsOn(configureFn) {
it('does not run further specs when one fails', function(done) {
var actions = [];
env.describe('wrapper', function() {
env.it('fails', function() {
actions.push('fails');
env.expect(1).toBe(2);
});
});
env.describe('holder', function() {
env.it('does not run', function() {
actions.push('does not run');
});
});
env.configure({ random: false, failFast: true });
env.execute(null, function() {
expect(actions).toEqual(['fails']);
done();
});
});
it('does not run further specs when one fails when configured with deprecated option', function(done) {
var actions = [];
spyOn(env, 'deprecated');
var actions = [],
config;
env.describe('wrapper', function() {
env.it('fails', function() {
@@ -1024,13 +1006,239 @@ describe('spec running', function() {
});
env.configure({ random: false });
env.stopOnSpecFailure(true);
configureFn(env);
env.execute(null, function() {
expect(actions).toEqual(['fails']);
expect(env.deprecated).toHaveBeenCalled();
done();
});
});
}
describe('when failFast is on', function() {
behavesLikeStopOnSpecFailureIsOn(function(env) {
spyOn(env, 'deprecated');
env.configure({ failFast: true });
});
});
describe('when stopOnSpecFailure is on', function() {
behavesLikeStopOnSpecFailureIsOn(function(env) {
env.configure({ stopOnSpecFailure: true });
});
});
describe('when stopOnSpecFailure is enabled via the deprecated method', function() {
behavesLikeStopOnSpecFailureIsOn(function(env) {
spyOn(env, 'deprecated');
env.stopOnSpecFailure(true);
});
});
describe('run multiple times', function() {
beforeEach(function() {
env.configure({ autoCleanClosures: false, random: false });
});
it('should be able to run multiple times', function(done) {
var actions = [];
env.describe('Suite', function() {
env.it('spec1', function() {
actions.push('spec1');
});
env.describe('inner suite', function() {
env.it('spec2', function() {
actions.push('spec2');
});
});
});
env.execute(null, function() {
expect(actions).toEqual(['spec1', 'spec2']);
env.execute(null, function() {
expect(actions).toEqual(['spec1', 'spec2', 'spec1', 'spec2']);
done();
});
});
});
it('should reset results between runs', function(done) {
var specResults = {};
var suiteResults = {};
var firstExecution = true;
env.addReporter({
specDone: function(spec) {
specResults[spec.description] = spec.status;
},
suiteDone: function(suite) {
suiteResults[suite.description] = suite.status;
},
jasmineDone: function() {
firstExecution = false;
}
});
env.describe('suite0', function() {
env.it('spec1', function() {
if (firstExecution) {
env.expect(1).toBe(2);
}
});
env.describe('suite1', function() {
env.it('spec2', function() {
if (firstExecution) {
env.pending();
}
});
env.xit('spec3', function() {}); // Always pending
});
env.describe('suite2', function() {
env.it('spec4', function() {
if (firstExecution) {
throw new Error('spec 3 fails');
}
});
});
env.describe('suite3', function() {
env.beforeEach(function() {
throw new Error('suite 3 fails');
});
env.it('spec5', function() {});
});
env.xdescribe('suite4', function() {
// Always pending
env.it('spec6', function() {});
});
env.describe('suite5', function() {
env.it('spec7');
});
});
env.execute(null, function() {
expect(specResults).toEqual({
spec1: 'failed',
spec2: 'pending',
spec3: 'pending',
spec4: 'failed',
spec5: 'failed',
spec6: 'pending',
spec7: 'pending'
});
expect(suiteResults).toEqual({
suite0: 'passed',
suite1: 'passed',
suite2: 'passed',
suite3: 'passed',
suite4: 'pending',
suite5: 'passed'
});
env.execute(null, function() {
expect(specResults).toEqual({
spec1: 'passed',
spec2: 'passed',
spec3: 'pending',
spec4: 'passed',
spec5: 'failed',
spec6: 'pending',
spec7: 'pending'
});
expect(suiteResults).toEqual({
suite0: 'passed',
suite1: 'passed',
suite2: 'passed',
suite3: 'passed',
suite4: 'pending',
suite5: 'passed'
});
done();
});
});
});
it('should execute before and after hooks per run', function(done) {
var timeline = [];
var timelineFn = function(hookName) {
return function() {
timeline.push(hookName);
};
};
var expectedTimeLine = [
'beforeAll',
'beforeEach',
'spec1',
'afterEach',
'beforeEach',
'spec2',
'afterEach',
'afterAll'
];
env.describe('suite0', function() {
env.beforeAll(timelineFn('beforeAll'));
env.beforeEach(timelineFn('beforeEach'));
env.afterEach(timelineFn('afterEach'));
env.afterAll(timelineFn('afterAll'));
env.it('spec1', timelineFn('spec1'));
env.it('spec2', timelineFn('spec2'));
});
env.execute(null, function() {
expect(timeline).toEqual(expectedTimeLine);
timeline = [];
env.execute(null, function() {
expect(timeline).toEqual(expectedTimeLine);
done();
});
});
});
it('should be able to filter out different tests in subsequent runs', function(done) {
var specResults = {};
var focussedSpec = 'spec1';
env.configure({
specFilter: function(spec) {
return spec.description === focussedSpec;
}
});
env.addReporter({
specDone: function(spec) {
specResults[spec.description] = spec.status;
}
});
env.describe('suite0', function() {
env.it('spec1', function() {});
env.it('spec2', function() {});
env.it('spec3', function() {});
});
env.execute(null, function() {
expect(specResults).toEqual({
spec1: 'passed',
spec2: 'excluded',
spec3: 'excluded'
});
focussedSpec = 'spec2';
env.execute(null, function() {
expect(specResults).toEqual({
spec1: 'excluded',
spec2: 'passed',
spec3: 'excluded'
});
focussedSpec = 'spec3';
env.execute(null, function() {
expect(specResults).toEqual({
spec1: 'excluded',
spec2: 'excluded',
spec3: 'passed'
});
done();
});
});
});
});
});
});

View File

@@ -7,78 +7,6 @@ describe('matchersUtil', function() {
});
describe('equals', function() {
describe('Properties', function() {
var fc;
beforeEach(function() {
fc = jasmine.getEnv().requireFastCheck();
});
function basicAnythingSettings() {
return {
key: fc.oneof(fc.string(), fc.constantFrom('k1', 'k2', 'k3')),
// Limiting depth & number of keys allows fast-check to try
// a lot more scalar values.
maxDepth: 2,
maxKeys: 5,
withBoxedValues: true,
withMap: true,
withSet: true
};
}
function numRuns() {
var many = 5000000;
// Be thorough but very slow when specified (usually on CI).
if (process.env.JASMINE_LONG_PROPERTY_TESTS) {
/* eslint-disable-next-line no-console */
console.log(
'Using',
many,
'runs of fc.assert because JASMINE_LONG_PROPERTY_TESTS was set. This may take several minutes.'
);
return many;
} else {
return undefined;
}
}
it('is symmetric', function() {
fc.assert(
fc.property(
fc.anything(basicAnythingSettings()),
fc.anything(basicAnythingSettings()),
function(a, b) {
return (
jasmineUnderTest.matchersUtil.equals(a, b) ===
jasmineUnderTest.matchersUtil.equals(b, a)
);
}
),
{
numRuns: numRuns(),
examples: [[0, 5e-324]]
}
);
});
it('is reflexive', function() {
var anythingSettings = basicAnythingSettings();
anythingSettings.withMap = false;
fc.assert(
fc.property(fc.dedup(fc.anything(anythingSettings), 2), function(
values
) {
return jasmineUnderTest.matchersUtil.equals(values[0], values[1]);
}),
{
numRuns: numRuns()
}
);
});
});
it('passes for literals that are triple-equal', function() {
var matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(matchersUtil.equals(null, null)).toBe(true);
@@ -506,6 +434,8 @@ describe('matchersUtil', function() {
},
matchersUtil = new jasmineUnderTest.MatchersUtil();
spyOn(jasmineUnderTest.getEnv(), 'deprecated'); // suppress warning
expect(matchersUtil.equals(1, 2, [tester])).toBe(true);
});
@@ -534,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);
});
});
@@ -559,6 +490,8 @@ describe('matchersUtil', function() {
},
matchersUtil = new jasmineUnderTest.MatchersUtil();
spyOn(jasmineUnderTest.getEnv(), 'deprecated'); // suppress warning
expect(matchersUtil.equals(1, 1, [tester])).toBe(false);
});
@@ -586,6 +519,8 @@ describe('matchersUtil', function() {
},
matchersUtil = new jasmineUnderTest.MatchersUtil();
spyOn(jasmineUnderTest.getEnv(), 'deprecated'); // suppress warning
expect(
matchersUtil.equals(asymmetricTester, true, [symmetricTester])
).toBe(true);
@@ -622,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));
@@ -642,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));
@@ -889,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() {
@@ -898,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
@@ -939,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() {
@@ -1008,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);
}
);
});
@@ -1115,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(
@@ -1142,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(
@@ -1157,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();
@@ -1231,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() {
@@ -1248,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)
};
}
};

View File

@@ -4,4 +4,10 @@
env.pending('Environment does not support promises');
}
};
env.requireNoPromises = function() {
if (typeof Promise === 'function') {
env.pending('Environment supports promises');
}
};
})(jasmine.getEnv());

View File

@@ -1,16 +0,0 @@
(function(env) {
var NODE_JS =
typeof process !== 'undefined' &&
process.versions &&
typeof process.versions.node === 'string';
env.requireFastCheck = function() {
if (!NODE_JS) {
env.pending(
"Property tests don't run in the browser. Use `npm test` to run them."
);
}
return require('fast-check');
};
})(jasmine.getEnv());

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() {
@@ -663,7 +785,7 @@ describe('HtmlReporter', function() {
}
});
env.configure({ failFast: true });
env.configure({ stopOnSpecFailure: true });
reporter.initialize();
reporter.jasmineDone({});
@@ -717,7 +839,7 @@ describe('HtmlReporter', function() {
}
});
env.configure({ failFast: true });
env.configure({ stopOnSpecFailure: true });
reporter.initialize();
reporter.jasmineDone({});
@@ -769,7 +891,7 @@ describe('HtmlReporter', function() {
}
});
env.configure({ oneFailurePerSpec: true });
env.configure({ stopSpecOnExpectationFailure: true });
reporter.initialize();
reporter.jasmineDone({});
@@ -823,7 +945,7 @@ describe('HtmlReporter', function() {
}
});
env.configure({ oneFailurePerSpec: true });
env.configure({ stopSpecOnExpectationFailure: true });
reporter.initialize();
reporter.jasmineDone({});

View File

@@ -75,7 +75,7 @@ describe('npm package', function() {
});
it('has bootFiles', function() {
expect(this.packagedCore.files.bootFiles).toEqual(['boot.js']);
expect(this.packagedCore.files.bootFiles).toEqual(['boot0.js', 'boot1.js']);
expect(this.packagedCore.files.nodeBootFiles).toEqual(['node_boot.js']);
var packagedCore = this.packagedCore;
@@ -83,6 +83,10 @@ describe('npm package', function() {
expect(fileName).toExistInPath(packagedCore.files.bootDir);
});
// For backwards compatibility, boot.js should be packaged even though
// it is no longer in bootFiles.
expect('boot.js').toExistInPath(packagedCore.files.bootDir);
var packagedCore = this.packagedCore;
this.packagedCore.files.nodeBootFiles.forEach(function(fileName) {
expect(fileName).toExistInPath(packagedCore.files.bootDir);

View File

@@ -22,14 +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/requireFastCheck.js',
'helpers/defineJasmineUnderTest.js'
'helpers/defineJasmineUnderTest.js',
'helpers/resetEnv.js'
],
random: true,
browser: {

View File

@@ -9,15 +9,16 @@
"helpers/generator.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/requireFastCheck.js",
"helpers/overrideConsoleLogForCircleCi.js",
"helpers/nodeDefineJasmineUnderTest.js"
"helpers/nodeDefineJasmineUnderTest.js",
"helpers/resetEnv.js"
],
"random": true
}

View File

@@ -52,6 +52,7 @@ getJasmineRequireObj().CallTracker = function(j$) {
/**
* Get the "this" object that was passed to a specific invocation of this spy.
* @name Spy#calls#thisFor
* @since 3.8.0
* @function
* @param {Integer} index The 0-based invocation index.
* @return {Object?}

View File

@@ -7,6 +7,7 @@ getJasmineRequireObj().Clock = function() {
/**
* @class Clock
* @since 1.3.0
* @classdesc Jasmine's mock clock is used when testing time dependent code.<br>
* _Note:_ Do not construct this directly. You can get the current clock with
* {@link jasmine.clock}.

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

@@ -65,8 +65,17 @@ getJasmineRequireObj().Env = function(j$) {
* @since 3.3.0
* @type Boolean
* @default false
* @deprecated Use the `stopOnSpecFailure` config property instead.
*/
failFast: false,
/**
* Whether to stop execution of the suite after the first spec failure
* @name Configuration#stopOnSpecFailure
* @since 3.9.0
* @type Boolean
* @default false
*/
stopOnSpecFailure: false,
/**
* Whether to fail the spec if it ran no expectations. By default
* a spec that ran no expectations is reported as passed. Setting this
@@ -83,8 +92,17 @@ getJasmineRequireObj().Env = function(j$) {
* @since 3.3.0
* @type Boolean
* @default false
* @deprecated Use the `stopSpecOnExpectationFailure` config property instead.
*/
oneFailurePerSpec: false,
/**
* Whether to cause specs to only have one expectation failure.
* @name Configuration#stopSpecOnExpectationFailure
* @since 3.3.0
* @type Boolean
* @default false
*/
stopSpecOnExpectationFailure: false,
/**
* A function that takes a spec and returns true if it should be executed
* or false if it should be skipped.
@@ -119,8 +137,31 @@ 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
Promise: undefined,
/**
* Clean closures when a suite is done running (done by clearing the stored function reference).
* This prevents memory leaks, but you won't be able to run jasmine multiple times.
* @name Configuration#autoCleanClosures
* @since 3.10.0
* @type boolean
* @default 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() {
@@ -170,35 +211,91 @@ getJasmineRequireObj().Env = function(j$) {
* @function
*/
this.configure = function(configuration) {
var booleanProps = [
'random',
'failSpecWithNoExpectations',
'hideDisabled',
'autoCleanClosures'
];
booleanProps.forEach(function(prop) {
if (typeof configuration[prop] !== 'undefined') {
config[prop] = !!configuration[prop];
}
});
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(
'stopOnSpecFailure and failFast are aliases for ' +
"each other. Don't set failFast if you also set stopOnSpecFailure."
);
}
}
config.failFast = configuration.failFast;
config.stopOnSpecFailure = configuration.failFast;
} else if (typeof configuration.stopOnSpecFailure !== 'undefined') {
config.failFast = configuration.stopOnSpecFailure;
config.stopOnSpecFailure = configuration.stopOnSpecFailure;
}
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 !==
configuration.oneFailurePerSpec
) {
throw new Error(
'stopSpecOnExpectationFailure and oneFailurePerSpec are aliases for ' +
"each other. Don't set oneFailurePerSpec if you also set stopSpecOnExpectationFailure."
);
}
}
config.oneFailurePerSpec = configuration.oneFailurePerSpec;
config.stopSpecOnExpectationFailure = configuration.oneFailurePerSpec;
} else if (
typeof configuration.stopSpecOnExpectationFailure !== 'undefined'
) {
config.oneFailurePerSpec = configuration.stopSpecOnExpectationFailure;
config.stopSpecOnExpectationFailure =
configuration.stopSpecOnExpectationFailure;
}
if (configuration.specFilter) {
config.specFilter = configuration.specFilter;
}
if (configuration.hasOwnProperty('random')) {
config.random = !!configuration.random;
}
if (configuration.hasOwnProperty('seed')) {
if (typeof configuration.seed !== 'undefined') {
config.seed = configuration.seed;
}
if (configuration.hasOwnProperty('failFast')) {
config.failFast = configuration.failFast;
}
if (configuration.hasOwnProperty('failSpecWithNoExpectations')) {
config.failSpecWithNoExpectations =
configuration.failSpecWithNoExpectations;
}
if (configuration.hasOwnProperty('oneFailurePerSpec')) {
config.oneFailurePerSpec = configuration.oneFailurePerSpec;
}
if (configuration.hasOwnProperty('hideDisabled')) {
config.hideDisabled = configuration.hideDisabled;
}
// Don't use hasOwnProperty to check for Promise existence because Promise
// can be initialized to undefined, either explicitly or by using the
// object returned from Env#configuration. In particular, Karma does this.
@@ -208,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);
}
};
/**
@@ -234,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;
}
@@ -287,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];
}
};
@@ -301,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];
}
};
@@ -383,7 +518,9 @@ getJasmineRequireObj().Env = function(j$) {
}
delayedExpectationResult.message +=
'Did you forget to return or await the result of expectAsync?';
'1. Did you forget to return or await the result of expectAsync?\n' +
'2. Was done() invoked before an async operation completed?\n' +
'3. Did an expectation follow a call to done()?';
topSuite.result.failedExpectations.push(delayedExpectationResult);
}
@@ -448,10 +585,11 @@ getJasmineRequireObj().Env = function(j$) {
delete runnableResources[id];
};
var beforeAndAfterFns = function(suite) {
var beforeAndAfterFns = function(targetSuite) {
return function() {
var befores = [],
afters = [];
afters = [],
suite = targetSuite;
while (suite) {
befores = befores.concat(suite.beforeFns);
@@ -494,18 +632,24 @@ getJasmineRequireObj().Env = function(j$) {
* @since 2.3.0
* @function
* @param {Boolean} value Whether to throw when a expectation fails
* @deprecated Use the `oneFailurePerSpec` option with {@link Env#configure}
* @deprecated Use the `stopSpecOnExpectationFailure` option with {@link Env#configure}
*/
this.throwOnExpectationFailure = function(value) {
this.deprecated(
'Setting throwOnExpectationFailure directly on Env is deprecated and will be removed in a future version of Jasmine, please use the oneFailurePerSpec option in `configure`'
'Setting throwOnExpectationFailure directly on Env is deprecated and ' +
'will be removed in a future version of Jasmine. Please use the ' +
'stopSpecOnExpectationFailure option in `configure`.',
{ ignoreRunnable: true }
);
this.configure({ oneFailurePerSpec: !!value });
};
this.throwingExpectationFailures = function() {
this.deprecated(
'Getting throwingExpectationFailures directly from Env is deprecated and will be removed in a future version of Jasmine, please check the oneFailurePerSpec option from `configuration`'
'Getting throwingExpectationFailures directly from Env is deprecated ' +
'and will be removed in a future version of Jasmine. Please check ' +
'the stopSpecOnExpectationFailure option from `configuration`.',
{ ignoreRunnable: true }
);
return config.oneFailurePerSpec;
};
@@ -516,18 +660,24 @@ getJasmineRequireObj().Env = function(j$) {
* @since 2.7.0
* @function
* @param {Boolean} value Whether to stop suite execution when a spec fails
* @deprecated Use the `failFast` option with {@link Env#configure}
* @deprecated Use the `stopOnSpecFailure` option with {@link Env#configure}
*/
this.stopOnSpecFailure = function(value) {
this.deprecated(
'Setting stopOnSpecFailure directly is deprecated and will be removed in a future version of Jasmine, please use the failFast option in `configure`'
'Setting stopOnSpecFailure directly is deprecated and will be ' +
'removed in a future version of Jasmine. Please use the ' +
'stopOnSpecFailure option in `configure`.',
{ ignoreRunnable: true }
);
this.configure({ failFast: !!value });
this.configure({ stopOnSpecFailure: !!value });
};
this.stoppingOnSpecFailure = function() {
this.deprecated(
'Getting stoppingOnSpecFailure directly from Env is deprecated and will be removed in a future version of Jasmine, please check the failFast option from `configuration`'
'Getting stoppingOnSpecFailure directly from Env is deprecated and ' +
'will be removed in a future version of Jasmine. Please check the ' +
'stopOnSpecFailure option from `configuration`.',
{ ignoreRunnable: true }
);
return config.failFast;
};
@@ -542,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;
};
@@ -564,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;
@@ -574,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;
};
@@ -583,41 +745,51 @@ getJasmineRequireObj().Env = function(j$) {
* @name Env#hideDisabled
* @since 3.2.0
* @function
* @deprecated Use the `hideDisabled` option with {@link Env#configure}
*/
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) {
var failFast = false;
if (options.isLeaf) {
failFast = config.oneFailurePerSpec;
failFast = config.stopSpecOnExpectationFailure;
} else if (!options.isReporter) {
failFast = config.failFast;
failFast = config.stopOnSpecFailure;
}
options.clearStack = options.clearStack || clearStack;
options.timeout = {
@@ -643,9 +815,10 @@ getJasmineRequireObj().Env = function(j$) {
description: 'Jasmine__TopLevel__Suite',
expectationFactory: expectationFactory,
asyncExpectationFactory: suiteAsyncExpectationFactory,
expectationResultFactory: expectationResultFactory
expectationResultFactory: expectationResultFactory,
autoCleanClosures: config.autoCleanClosures
});
defaultResourcesForRunnable(topSuite.id);
var deprecator = new j$.Deprecator(topSuite);
currentDeclarationSuite = topSuite;
/**
@@ -654,9 +827,10 @@ getJasmineRequireObj().Env = function(j$) {
* @function
* @name Env#topSuite
* @return {Suite} the root suite
* @since 2.0.0
*/
this.topSuite = function() {
return topSuite;
return j$.deprecatingSuiteProxy(topSuite, null, this);
};
/**
@@ -731,7 +905,8 @@ getJasmineRequireObj().Env = function(j$) {
*/
'specDone'
],
queueRunnerFactory
queueRunnerFactory,
self.deprecated
);
/**
@@ -749,13 +924,24 @@ getJasmineRequireObj().Env = function(j$) {
*
* execute should not be called more than once.
*
* If the environment supports promises, execute will return a promise that
* is resolved after the suite finishes executing. The promise will be
* resolved (not rejected) as long as the suite runs to completion. Use a
* {@link Reporter} to determine whether or not the suite passed.
*
* @name Env#execute
* @since 2.0.0
* @function
* @param {(string[])=} runnablesToRun IDs of suites and/or specs to run
* @param {Function=} onComplete Function that will be called after all specs have run
* @return {Promise<undefined>}
*/
this.execute = function(runnablesToRun, onComplete) {
if (this._executedBefore) {
topSuite.reset();
}
this._executedBefore = true;
defaultResourcesForRunnable(topSuite.id);
installGlobalErrors();
if (!runnablesToRun) {
@@ -813,65 +999,88 @@ getJasmineRequireObj().Env = function(j$) {
var jasmineTimer = new j$.Timer();
jasmineTimer.start();
/**
* Information passed to the {@link Reporter#jasmineStarted} event.
* @typedef JasmineStartedInfo
* @property {Int} totalSpecsDefined - The total number of specs defined in this suite.
* @property {Order} order - Information about the ordering (random or not) of this execution of the suite.
*/
reporter.jasmineStarted(
{
totalSpecsDefined: totalSpecsDefined,
order: order
},
function() {
currentlyExecutingSuites.push(topSuite);
var Promise = customPromise || global.Promise;
processor.execute(function() {
clearResourcesForRunnable(topSuite.id);
currentlyExecutingSuites.pop();
var overallStatus, incompleteReason;
if (hasFailures || topSuite.result.failedExpectations.length > 0) {
overallStatus = 'failed';
} else if (focusedRunnables.length > 0) {
overallStatus = 'incomplete';
incompleteReason = 'fit() or fdescribe() was found';
} else if (totalSpecsDefined === 0) {
overallStatus = 'incomplete';
incompleteReason = 'No specs found';
} else {
overallStatus = 'passed';
if (Promise) {
return new Promise(function(resolve) {
runAll(function() {
if (onComplete) {
onComplete();
}
/**
* Information passed to the {@link Reporter#jasmineDone} event.
* @typedef JasmineDoneInfo
* @property {OverallStatus} overallStatus - The overall result of the suite: 'passed', 'failed', or 'incomplete'.
* @property {Int} totalTime - The total time (in ms) that it took to execute the suite
* @property {IncompleteReason} incompleteReason - Explanation of why the suite was incomplete.
* @property {Order} order - Information about the ordering (random or not) of this execution of the suite.
* @property {Expectation[]} failedExpectations - List of expectations that failed in an {@link afterAll} at the global level.
* @property {Expectation[]} deprecationWarnings - List of deprecation warnings that occurred at the global level.
*/
reporter.jasmineDone(
{
overallStatus: overallStatus,
totalTime: jasmineTimer.elapsed(),
incompleteReason: incompleteReason,
order: order,
failedExpectations: topSuite.result.failedExpectations,
deprecationWarnings: topSuite.result.deprecationWarnings
},
function() {
if (onComplete) {
onComplete();
}
}
);
resolve();
});
}
);
});
} else {
runAll(function() {
if (onComplete) {
onComplete();
}
});
}
function runAll(done) {
/**
* Information passed to the {@link Reporter#jasmineStarted} event.
* @typedef JasmineStartedInfo
* @property {Int} totalSpecsDefined - The total number of specs defined in this suite.
* @property {Order} order - Information about the ordering (random or not) of this execution of the suite.
* @since 2.0.0
*/
reporter.jasmineStarted(
{
totalSpecsDefined: totalSpecsDefined,
order: order
},
function() {
currentlyExecutingSuites.push(topSuite);
processor.execute(function() {
clearResourcesForRunnable(topSuite.id);
currentlyExecutingSuites.pop();
var overallStatus, incompleteReason;
if (
hasFailures ||
topSuite.result.failedExpectations.length > 0
) {
overallStatus = 'failed';
} else if (focusedRunnables.length > 0) {
overallStatus = 'incomplete';
incompleteReason = 'fit() or fdescribe() was found';
} else if (totalSpecsDefined === 0) {
overallStatus = 'incomplete';
incompleteReason = 'No specs found';
} else {
overallStatus = 'passed';
}
/**
* Information passed to the {@link Reporter#jasmineDone} event.
* @typedef JasmineDoneInfo
* @property {OverallStatus} overallStatus - The overall result of the suite: 'passed', 'failed', or 'incomplete'.
* @property {Int} totalTime - The total time (in ms) that it took to execute the suite
* @property {IncompleteReason} incompleteReason - Explanation of why the suite was incomplete.
* @property {Order} order - Information about the ordering (random or not) of this execution of the suite.
* @property {Expectation[]} failedExpectations - List of expectations that failed in an {@link afterAll} at the global level.
* @property {Expectation[]} deprecationWarnings - List of deprecation warnings that occurred at the global level.
* @since 2.4.0
*/
reporter.jasmineDone(
{
overallStatus: overallStatus,
totalTime: jasmineTimer.elapsed(),
incompleteReason: incompleteReason,
order: order,
failedExpectations: topSuite.result.failedExpectations,
deprecationWarnings: topSuite.result.deprecationWarnings
},
done
);
});
}
);
}
};
/**
@@ -1019,7 +1228,8 @@ getJasmineRequireObj().Env = function(j$) {
expectationFactory: expectationFactory,
asyncExpectationFactory: suiteAsyncExpectationFactory,
expectationResultFactory: expectationResultFactory,
throwOnExpectationFailure: config.oneFailurePerSpec
throwOnExpectationFailure: config.oneFailurePerSpec,
autoCleanClosures: config.autoCleanClosures
});
return suite;
@@ -1032,20 +1242,27 @@ getJasmineRequireObj().Env = function(j$) {
if (specDefinitions.length > 0) {
throw new Error('describe does not expect any arguments');
}
if (currentDeclarationSuite.markedPending) {
suite.pend();
if (currentDeclarationSuite.markedExcluding) {
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) {
ensureIsNotNested('xdescribe');
ensureIsFunction(specDefinitions, 'xdescribe');
var suite = suiteFactory(description);
suite.pend();
suite.exclude();
addSpecsToSuite(suite, specDefinitions);
return suite;
return j$.deprecatingSuiteProxy(suite, suite.parentSuite, this);
};
var focusedRunnables = [];
@@ -1060,7 +1277,7 @@ getJasmineRequireObj().Env = function(j$) {
unfocusAncestor();
addSpecsToSuite(suite, specDefinitions);
return suite;
return j$.deprecatingSuiteProxy(suite, suite.parentSuite, this);
};
function addSpecsToSuite(suite, specDefinitions) {
@@ -1070,7 +1287,7 @@ getJasmineRequireObj().Env = function(j$) {
var declarationError = null;
try {
specDefinitions.call(suite);
specDefinitions.call(j$.deprecatingThisProxy(suite, self));
} catch (e) {
declarationError = e;
}
@@ -1112,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);
@@ -1128,6 +1346,7 @@ getJasmineRequireObj().Env = function(j$) {
timeout: timeout || 0
},
throwOnExpectationFailure: config.oneFailurePerSpec,
autoCleanClosures: config.autoCleanClosures,
timer: new j$.Timer()
});
return spec;
@@ -1150,21 +1369,32 @@ 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.
if (arguments.length > 1 && typeof fn !== 'undefined') {
ensureIsFunctionOrAsync(fn, 'it');
}
if (timeout) {
j$.util.validateTimeout(timeout);
}
var spec = specFactory(description, fn, currentDeclarationSuite, timeout);
if (currentDeclarationSuite.markedPending) {
spec.pend();
if (currentDeclarationSuite.markedExcluding) {
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
@@ -1172,19 +1402,23 @@ getJasmineRequireObj().Env = function(j$) {
if (arguments.length > 1 && typeof fn !== 'undefined') {
ensureIsFunctionOrAsync(fn, 'xit');
}
var spec = this.it.apply(this, arguments);
spec.pend('Temporarily disabled with xit');
return spec;
var spec = this.it_.apply(this, arguments);
spec.exclude('Temporarily disabled with xit');
return j$.deprecatingSpecProxy(spec, this);
};
this.fit = function(description, fn, timeout) {
ensureIsNotNested('fit');
ensureIsFunctionOrAsync(fn, 'fit');
if (timeout) {
j$.util.validateTimeout(timeout);
}
var spec = specFactory(description, fn, currentDeclarationSuite, timeout);
currentDeclarationSuite.addChild(spec);
focusedRunnables.push(spec.id);
unfocusAncestor();
return spec;
return j$.deprecatingSpecProxy(spec, this);
};
/**
@@ -1244,6 +1478,11 @@ getJasmineRequireObj().Env = function(j$) {
this.beforeEach = function(beforeEachFunction, timeout) {
ensureIsNotNested('beforeEach');
ensureIsFunctionOrAsync(beforeEachFunction, 'beforeEach');
if (timeout) {
j$.util.validateTimeout(timeout);
}
currentDeclarationSuite.beforeEach({
fn: beforeEachFunction,
timeout: timeout || 0
@@ -1253,6 +1492,11 @@ getJasmineRequireObj().Env = function(j$) {
this.beforeAll = function(beforeAllFunction, timeout) {
ensureIsNotNested('beforeAll');
ensureIsFunctionOrAsync(beforeAllFunction, 'beforeAll');
if (timeout) {
j$.util.validateTimeout(timeout);
}
currentDeclarationSuite.beforeAll({
fn: beforeAllFunction,
timeout: timeout || 0
@@ -1262,6 +1506,11 @@ getJasmineRequireObj().Env = function(j$) {
this.afterEach = function(afterEachFunction, timeout) {
ensureIsNotNested('afterEach');
ensureIsFunctionOrAsync(afterEachFunction, 'afterEach');
if (timeout) {
j$.util.validateTimeout(timeout);
}
afterEachFunction.isCleanup = true;
currentDeclarationSuite.afterEach({
fn: afterEachFunction,
@@ -1272,6 +1521,11 @@ getJasmineRequireObj().Env = function(j$) {
this.afterAll = function(afterAllFunction, timeout) {
ensureIsNotNested('afterAll');
ensureIsFunctionOrAsync(afterAllFunction, 'afterAll');
if (timeout) {
j$.util.validateTimeout(timeout);
}
currentDeclarationSuite.afterAll({
fn: afterAllFunction,
timeout: timeout || 0

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

@@ -126,6 +126,7 @@ getJasmineRequireObj().Expectation = function(j$) {
* Otherwise evaluate the matcher.
* @member
* @name async-matchers#already
* @since 3.8.0
* @type {async-matchers}
* @example
* await expectAsync(myPromise).already.toBeResolved();

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

@@ -19,16 +19,22 @@ getJasmineRequireObj().GlobalErrors = function(j$) {
function taggedOnError(error) {
var substituteMsg;
if (error) {
if (j$.isError_(error)) {
error.jasmineMessage = jasmineMessage + ': ' + error;
} else {
substituteMsg = jasmineMessage + ' with no error or message';
if (error) {
substituteMsg = jasmineMessage + ': ' + error;
} else {
substituteMsg = jasmineMessage + ' with no error or message';
}
if (errorType === 'unhandledRejection') {
substituteMsg +=
'\n' +
'(Tip: to get a useful stack trace, use ' +
'Promise.reject(new Error(...)) instead of Promise.reject().)';
'Promise.reject(new Error(...)) instead of Promise.reject(' +
(error ? '...' : '') +
').)';
}
error = new Error(substituteMsg);

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,8 +103,9 @@ 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);
next(error);
},
cleanup = once(function cleanup() {
if (timeoutId !== void 0) {
@@ -97,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;
@@ -137,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 +
@@ -145,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);
@@ -155,7 +196,10 @@ getJasmineRequireObj().QueueRunner = function(j$) {
maybeThenable = queueableFn.fn.call(self.userContext);
if (maybeThenable && j$.isFunction_(maybeThenable.then)) {
maybeThenable.then(next, onPromiseRejection);
maybeThenable.then(
wrapInPromiseResolutionHandler(next),
onPromiseRejection
);
completedSynchronously = false;
return { completedSynchronously: false };
}
@@ -210,32 +254,51 @@ 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 });
}
};
function wrapInPromiseResolutionHandler(fn) {
return function(maybeArg) {
if (j$.isError_(maybeArg)) {
fn(maybeArg);
} else {
fn();
}
};
}
return QueueRunner;
};

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

@@ -2,17 +2,26 @@ getJasmineRequireObj().Spec = function(j$) {
/**
* @interface Spec
* @see Configuration#specFilter
* @since 2.0.0
*/
function Spec(attrs) {
this.expectationFactory = attrs.expectationFactory;
this.asyncExpectationFactory = attrs.asyncExpectationFactory;
this.resultCallback = attrs.resultCallback || function() {};
/**
* The unique ID of this spec.
* @name Spec#id
* @readonly
* @type {string}
* @since 2.0.0
*/
this.id = attrs.id;
/**
* The description passed to the {@link it} that created this spec.
* @name Spec#description
* @readonly
* @type {string}
* @since 2.0.0
*/
this.description = attrs.description || '';
this.queueableFn = attrs.queueableFn;
@@ -27,6 +36,8 @@ getJasmineRequireObj().Spec = function(j$) {
return {};
};
this.onStart = attrs.onStart || function() {};
this.autoCleanClosures =
attrs.autoCleanClosures === undefined ? true : !!attrs.autoCleanClosures;
this.getSpecName =
attrs.getSpecName ||
function() {
@@ -34,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 ||
@@ -44,7 +56,7 @@ getJasmineRequireObj().Spec = function(j$) {
this.timer = attrs.timer || new j$.Timer();
if (!this.queueableFn.fn) {
this.pend();
this.exclude();
}
/**
@@ -59,7 +71,8 @@ getJasmineRequireObj().Spec = function(j$) {
* @property {String} status - Once the spec has completed, this string represents the pass/fail status of this spec.
* @property {number} duration - The time in ms used by the spec execution, including any before/afterEach.
* @property {Object} properties - User-supplied properties, if any, that were set using {@link Env#setSpecProperty}
*/
* @since 2.0.0
x */
this.result = {
id: this.id,
description: this.description,
@@ -111,7 +124,9 @@ getJasmineRequireObj().Spec = function(j$) {
var complete = {
fn: function(done) {
self.queueableFn.fn = null;
if (self.autoCleanClosures) {
self.queueableFn.fn = null;
}
self.result.status = self.status(excluded, failSpecWithNoExp);
self.result.duration = self.timer.elapsed();
self.resultCallback(self.result, done);
@@ -128,13 +143,32 @@ getJasmineRequireObj().Spec = function(j$) {
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) {
@@ -148,6 +182,36 @@ getJasmineRequireObj().Spec = function(j$) {
this.queueRunnerFactory(runnerConfig);
};
Spec.prototype.reset = function() {
/**
* @typedef SpecResult
* @property {Int} id - The unique id of this spec.
* @property {String} description - The description passed to the {@link it} that created this spec.
* @property {String} fullName - The full description including all ancestors of this spec.
* @property {Expectation[]} failedExpectations - The list of expectations that failed during execution of this spec.
* @property {Expectation[]} passedExpectations - The list of expectations that passed during execution of this spec.
* @property {Expectation[]} deprecationWarnings - The list of deprecation warnings that occurred during execution this spec.
* @property {String} pendingReason - If the spec is {@link pending}, this will be the reason.
* @property {String} status - Once the spec has completed, this string represents the pass/fail status of this spec.
* @property {number} duration - The time in ms used by the spec execution, including any before/afterEach.
* @property {Object} properties - User-supplied properties, if any, that were set using {@link Env#setSpecProperty}
* @since 2.0.0
*/
this.result = {
id: this.id,
description: this.description,
fullName: this.getFullName(),
failedExpectations: [],
passedExpectations: [],
deprecationWarnings: [],
pendingReason: this.excludeMessage,
duration: null,
properties: null,
trace: null
};
this.markedPending = this.markedExcluding;
};
Spec.prototype.onException = function onException(e) {
if (Spec.isPendingSpecException(e)) {
this.pend(extractCustomPendingMessage(e));
@@ -171,6 +235,10 @@ getJasmineRequireObj().Spec = function(j$) {
);
};
/*
* Marks state as pending
* @param {string} [message] An optional reason message
*/
Spec.prototype.pend = function(message) {
this.markedPending = true;
if (message) {
@@ -178,6 +246,19 @@ getJasmineRequireObj().Spec = function(j$) {
}
};
/*
* Like {@link Spec#pend}, but pending state will survive {@link Spec#reset}
* Useful for fit, xit, where pending state remains.
* @param {string} [message] An optional reason message
*/
Spec.prototype.exclude = function(message) {
this.markedExcluding = true;
if (this.message) {
this.excludeMessage = message;
}
this.pend(message);
};
Spec.prototype.getResult = function() {
this.result.status = this.status();
return this.result;
@@ -210,6 +291,7 @@ getJasmineRequireObj().Spec = function(j$) {
* @name Spec#getFullName
* @function
* @returns {string}
* @since 2.0.0
*/
Spec.prototype.getFullName = function() {
return this.getSpecName(this);

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

@@ -2,9 +2,17 @@ getJasmineRequireObj().Suite = function(j$) {
/**
* @interface Suite
* @see Env#topSuite
* @since 2.0.0
*/
function Suite(attrs) {
this.env = attrs.env;
/**
* The unique ID of this suite.
* @name Suite#id
* @readonly
* @type {string}
* @since 2.0.0
*/
this.id = attrs.id;
/**
* The parent of this suite, or null if this is the top suite.
@@ -18,12 +26,15 @@ getJasmineRequireObj().Suite = function(j$) {
* @name Suite#description
* @readonly
* @type {string}
* @since 2.0.0
*/
this.description = attrs.description;
this.expectationFactory = attrs.expectationFactory;
this.asyncExpectationFactory = attrs.asyncExpectationFactory;
this.expectationResultFactory = attrs.expectationResultFactory;
this.throwOnExpectationFailure = !!attrs.throwOnExpectationFailure;
this.autoCleanClosures =
attrs.autoCleanClosures === undefined ? true : !!attrs.autoCleanClosures;
this.beforeFns = [];
this.afterFns = [];
@@ -36,29 +47,11 @@ getJasmineRequireObj().Suite = function(j$) {
* The suite's children.
* @name Suite#children
* @type {Array.<(Spec|Suite)>}
* @since 2.0.0
*/
this.children = [];
/**
* @typedef SuiteResult
* @property {Int} id - The unique id of this suite.
* @property {String} description - The description text passed to the {@link describe} that made this suite.
* @property {String} fullName - The full description including all ancestors of this suite.
* @property {Expectation[]} failedExpectations - The list of expectations that failed in an {@link afterAll} for this suite.
* @property {Expectation[]} deprecationWarnings - The list of deprecation warnings that occurred on this suite.
* @property {String} status - Once the suite has completed, this string represents the pass/fail status of this suite.
* @property {number} duration - The time in ms for Suite execution, including any before/afterAll, before/afterEach.
* @property {Object} properties - User-supplied properties, if any, that were set using {@link Env#setSuiteProperty}
*/
this.result = {
id: this.id,
description: this.description,
fullName: this.getFullName(),
failedExpectations: [],
deprecationWarnings: [],
duration: null,
properties: null
};
this.reset();
}
Suite.prototype.setSuiteProperty = function(key, value) {
@@ -79,6 +72,7 @@ getJasmineRequireObj().Suite = function(j$) {
* @name Suite#getFullName
* @function
* @returns {string}
* @since 2.0.0
*/
Suite.prototype.getFullName = function() {
var fullName = [];
@@ -94,10 +88,22 @@ getJasmineRequireObj().Suite = function(j$) {
return fullName.join(' ');
};
/*
* Mark the suite with "pending" status
*/
Suite.prototype.pend = function() {
this.markedPending = true;
};
/*
* Like {@link Suite#pend}, but pending state will survive {@link Spec#reset}
* Useful for fdescribe, xdescribe, where pending state should remain.
*/
Suite.prototype.exclude = function() {
this.pend();
this.markedExcluding = true;
};
Suite.prototype.beforeEach = function(fn) {
this.beforeFns.unshift(fn);
};
@@ -129,10 +135,40 @@ getJasmineRequireObj().Suite = function(j$) {
}
Suite.prototype.cleanupBeforeAfter = function() {
removeFns(this.beforeAllFns);
removeFns(this.afterAllFns);
removeFns(this.beforeFns);
removeFns(this.afterFns);
if (this.autoCleanClosures) {
removeFns(this.beforeAllFns);
removeFns(this.afterAllFns);
removeFns(this.beforeFns);
removeFns(this.afterFns);
}
};
Suite.prototype.reset = function() {
/**
* @typedef SuiteResult
* @property {Int} id - The unique id of this suite.
* @property {String} description - The description text passed to the {@link describe} that made this suite.
* @property {String} fullName - The full description including all ancestors of this suite.
* @property {Expectation[]} failedExpectations - The list of expectations that failed in an {@link afterAll} for this suite.
* @property {Expectation[]} deprecationWarnings - The list of deprecation warnings that occurred on this suite.
* @property {String} status - Once the suite has completed, this string represents the pass/fail status of this suite.
* @property {number} duration - The time in ms for Suite execution, including any before/afterAll, before/afterEach.
* @property {Object} properties - User-supplied properties, if any, that were set using {@link Env#setSuiteProperty}
* @since 2.0.0
*/
this.result = {
id: this.id,
description: this.description,
fullName: this.getFullName(),
failedExpectations: [],
deprecationWarnings: [],
duration: null,
properties: null
};
this.markedPending = this.markedExcluding;
this.children.forEach(function(child) {
child.reset();
});
};
Suite.prototype.addChild = function(child) {
@@ -195,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,24 @@
getJasmineRequireObj().StringContaining = function(j$) {
function StringContaining(expected) {
if (!j$.isString_(expected)) {
throw new Error('Expected is not a String');
}
this.expected = expected;
}
StringContaining.prototype.asymmetricMatch = function(other) {
if (!j$.isString_(other)) {
// Arrays, etc. don't match no matter what their indexOf returns.
return false;
}
return other.indexOf(this.expected) !== -1;
};
StringContaining.prototype.jasmineToString = function() {
return '<jasmine.stringContaining("' + this.expected + '")>';
};
return StringContaining;
};

View File

@@ -7,6 +7,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
* Maximum object depth the pretty printer will print to.
* Set this to a lower value to speed up pretty printing if you have large objects.
* @name jasmine.MAX_PRETTY_PRINT_DEPTH
* @default 8
* @since 1.3.0
*/
j$.MAX_PRETTY_PRINT_DEPTH = 8;
@@ -15,6 +16,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
* This will also limit the number of keys and values displayed for an object.
* Elements past this number will be ellipised.
* @name jasmine.MAX_PRETTY_PRINT_ARRAY_LENGTH
* @default 50
* @since 2.7.0
*/
j$.MAX_PRETTY_PRINT_ARRAY_LENGTH = 50;
@@ -22,15 +24,35 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
* Maximum number of characters to display when pretty printing objects.
* Characters past this number will be ellipised.
* @name jasmine.MAX_PRETTY_PRINT_CHARS
* @default 100
* @since 2.9.0
*/
j$.MAX_PRETTY_PRINT_CHARS = 1000;
/**
* Default number of milliseconds Jasmine will wait for an asynchronous spec to complete.
* Default number of milliseconds Jasmine will wait for an asynchronous spec,
* before, or after function to complete. This can be overridden on a case by
* case basis by passing a time limit as the third argument to {@link it},
* {@link beforeEach}, {@link afterEach}, {@link beforeAll}, or
* {@link afterAll}. The value must be no greater than the largest number of
* milliseconds supported by setTimeout, which is usually 2147483647.
*
* While debugging tests, you may want to set this to a large number (or pass
* a large number to one of the functions mentioned above) so that Jasmine
* does not move on to after functions or the next spec while you're debugging.
* @name jasmine.DEFAULT_TIMEOUT_INTERVAL
* @default 5000
* @since 1.3.0
*/
j$.DEFAULT_TIMEOUT_INTERVAL = 5000;
var DEFAULT_TIMEOUT_INTERVAL = 5000;
Object.defineProperty(j$, 'DEFAULT_TIMEOUT_INTERVAL', {
get: function() {
return DEFAULT_TIMEOUT_INTERVAL;
},
set: function(newValue) {
j$.util.validateTimeout(newValue, 'jasmine.DEFAULT_TIMEOUT_INTERVAL');
DEFAULT_TIMEOUT_INTERVAL = newValue;
}
});
j$.getGlobal = function() {
return jasmineGlobal;
@@ -99,9 +121,21 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
};
j$.isError_ = function(value) {
if (!value) {
return false;
}
if (value instanceof Error) {
return true;
}
if (
typeof window !== 'undefined' &&
typeof window.trustedTypes !== 'undefined'
) {
return (
typeof value.stack === 'string' && typeof value.message === 'string'
);
}
if (value && value.constructor && value.constructor.constructor) {
var valueGlobal = value.constructor.constructor('return this');
if (j$.isFunction_(valueGlobal)) {
@@ -217,7 +251,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
};
/**
* Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
* Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
* that will succeed if the actual value being compared is an instance of the specified class/constructor.
* @name jasmine.any
* @since 1.3.0
@@ -229,7 +263,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
};
/**
* Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
* Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
* that will succeed if the actual value being compared is not `null` and not `undefined`.
* @name jasmine.anything
* @since 2.2.0
@@ -240,7 +274,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
};
/**
* Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
* Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
* that will succeed if the actual value being compared is `true` or anything truthy.
* @name jasmine.truthy
* @since 3.1.0
@@ -251,7 +285,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
};
/**
* Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
* Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
* that will succeed if the actual value being compared is `null`, `undefined`, `0`, `false` or anything falsey.
* @name jasmine.falsy
* @since 3.1.0
@@ -262,7 +296,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
};
/**
* Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
* Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
* that will succeed if the actual value being compared is empty.
* @name jasmine.empty
* @since 3.1.0
@@ -273,7 +307,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
};
/**
* Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
* Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
* that will succeed if the actual value being compared is not empty.
* @name jasmine.notEmpty
* @since 3.1.0
@@ -284,7 +318,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
};
/**
* Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
* Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
* that will succeed if the actual value being compared contains at least the keys and values.
* @name jasmine.objectContaining
* @since 1.3.0
@@ -296,7 +330,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
};
/**
* Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
* Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
* that will succeed if the actual value is a `String` that matches the `RegExp` or `String`.
* @name jasmine.stringMatching
* @since 2.2.0
@@ -308,7 +342,19 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
};
/**
* Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
* Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
* that will succeed if the actual value is a `String` that contains the specified `String`.
* @name jasmine.stringContaining
* @since 3.10.0
* @function
* @param {String} expected
*/
j$.stringContaining = function(expected) {
return new j$.StringContaining(expected);
};
/**
* Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
* that will succeed if the actual value is an `Array` that contains at least the elements in the sample.
* @name jasmine.arrayContaining
* @since 2.2.0
@@ -320,7 +366,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
};
/**
* Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
* Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
* that will succeed if the actual value is an `Array` that contains all of the elements in the sample in any order.
* @name jasmine.arrayWithExactContents
* @since 2.8.0
@@ -332,7 +378,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
};
/**
* Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
* Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
* that will succeed if every key/value pair in the sample passes the deep equality comparison
* with at least one key/value pair in the actual value being compared
* @name jasmine.mapContaining
@@ -345,7 +391,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
};
/**
* Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
* Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
* that will succeed if every item in the sample passes the deep equality comparison
* with at least one item in the actual value being compared
* @name jasmine.setContaining

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;
}
@@ -659,9 +688,33 @@ getJasmineRequireObj().MatchersUtil = function(j$) {
/**
* @interface AsymmetricEqualityTester
* @classdesc An asymmetric equality tester is an object that can match multiple
* objects. Examples include jasmine.any() and jasmine.stringMatching().
* User-defined asymmetric equality testers can also be defined and used in
* expectations.
* objects. Examples include jasmine.any() and jasmine.stringMatching(). Jasmine
* includes a number of built-in asymmetric equality testers, such as
* {@link jasmine.objectContaining}. User-defined asymmetric equality testers are
* also supported.
*
* Asymmetric equality testers work with any matcher, including user-defined
* custom matchers, that uses {@link MatchersUtil#equals} or
* {@link MatchersUtil#contains}.
*
* @example
* function numberDivisibleBy(divisor) {
* return {
* asymmetricMatch: function(n) {
* return typeof n === 'number' && n % divisor === 0;
* },
* jasmineToString: function() {
* return `<a number divisible by ${divisor}>`;
* }
* };
* }
*
* var actual = {
* n: 2,
* otherFields: "don't care"
* };
*
* expect(actual).toEqual(jasmine.objectContaining({n: numberDivisibleBy(2)}));
* @see custom_asymmetric_equality_testers
* @since 2.0.0
*/

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$);
@@ -74,6 +101,7 @@ var getJasmineRequireObj = (function(jasmineGlobal) {
j$.SpyRegistry = jRequire.SpyRegistry(j$);
j$.SpyStrategy = jRequire.SpyStrategy(j$);
j$.StringMatching = jRequire.StringMatching(j$);
j$.StringContaining = jRequire.StringContaining(j$);
j$.UserContext = jRequire.UserContext(j$);
j$.Suite = jRequire.Suite(j$);
j$.Timer = jRequire.Timer();

View File

@@ -142,5 +142,20 @@ getJasmineRequireObj().util = function(j$) {
}
};
util.validateTimeout = function(timeout, msgPrefix) {
// Timeouts are implemented with setTimeout, which only supports a limited
// range of values. The limit is unspecified, as is the behavior when it's
// exceeded. But on all currently supported JS runtimes, setTimeout calls
// the callback immediately when the timeout is greater than 2147483647
// (the maximum value of a signed 32 bit integer).
var max = 2147483647;
if (timeout > max) {
throw new Error(
(msgPrefix || 'Timeout value') + ' cannot be greater than ' + max
);
}
};
return util;
};

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
)
);
}
@@ -527,17 +538,20 @@ jasmineRequire.HtmlReporter = function(j$) {
);
var failFastCheckbox = optionsMenuDom.querySelector('#jasmine-fail-fast');
failFastCheckbox.checked = config.failFast;
failFastCheckbox.checked = config.stopOnSpecFailure;
failFastCheckbox.onclick = function() {
navigateWithNewParam('failFast', !config.failFast);
navigateWithNewParam('failFast', !config.stopOnSpecFailure);
};
var throwCheckbox = optionsMenuDom.querySelector(
'#jasmine-throw-failures'
);
throwCheckbox.checked = config.oneFailurePerSpec;
throwCheckbox.checked = config.stopSpecOnExpectationFailure;
throwCheckbox.onclick = function() {
navigateWithNewParam('oneFailurePerSpec', !config.oneFailurePerSpec);
navigateWithNewParam(
'oneFailurePerSpec',
!config.stopSpecOnExpectationFailure
);
};
var randomCheckbox = optionsMenuDom.querySelector(
@@ -618,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);
}
@@ -642,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

@@ -1,3 +1,5 @@
@use "sass:math";
$line-height: 14px;
$margin-unit: 14px;
@@ -117,7 +119,7 @@ body {
li {
display: inline-block;
height: ($line-height / 2) + 3;
height: math.div($line-height, 2) + 3;
width: $line-height;
font-size: 16px;
@@ -132,7 +134,7 @@ body {
}
&.jasmine-failed {
line-height: ($line-height / 2) + 2;
line-height: math.div($line-height, 2) + 2;
&:before {
color: $failing-color;
@@ -231,6 +233,8 @@ body {
}
&.jasmine-warning {
margin-top: $margin-unit;
margin-bottom: $margin-unit;
background-color: $pending-color;
color: $text-color;
}
@@ -282,8 +286,8 @@ body {
padding-left: 0;
&.jasmine-suite {
margin-top: $margin-unit/2;
margin-bottom: $margin-unit/2
margin-top: math.div($margin-unit, 2);
margin-bottom: math.div($margin-unit, 2)
}
}
@@ -386,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;
}
}