Compare commits

...

348 Commits

Author SHA1 Message Date
Steve Gravrock
a67b7276be Fixed jsdocs for throwUnless and throwUnlessAsync 2023-07-22 09:36:16 -07:00
Steve Gravrock
47f3105ef0 Bump version to 5.1.0 2023-07-22 09:12:36 -07:00
Steve Gravrock
aeb56539c9 Built distribution 2023-07-22 09:12:18 -07:00
Steve Gravrock
75d45efa16 Exclude inherited Error properties from stack trace
These are likely to be methods or other things that aren't meaningful in
Jasmine's output.
2023-07-19 19:13:24 -07:00
Steve Gravrock
59d1c5bebb Use "bug report" tag, not "unconfirmed bug" 2023-07-19 18:29:51 -07:00
Steve Gravrock
040983c979 Merge branch 'skip-non-error-cause' of https://github.com/angrycat9000/jasmine
* Merges #2013 from @angrycat9000
* Fixes #2011
2023-07-19 18:28:56 -07:00
angrycat9000
2ddb344bac Skip parsing cause if it is not an Error object 2023-07-19 10:00:50 -04:00
Steve Gravrock
e56bd3918b Added throwUnless and throwUnlessAsync
These are similar to `expect` and `expectAsync` except that they throw
exceptions rather than recording matcher failures as spec/suite failures.
They're intended to support using Jasmine matchers in testing-library's
`waitFor`, and also provide a way to integration-test custom matchers.

These funtions are not equivalent to `expect` and `expectAsync` and should
not be used in situations where you want a matcher failure to reliably fail
the spec. Whether that happens depends on the structure of the surrounding
code. In general, you should only use `throwUnless` when you expect
something (which could be your own code or library code like `waitFor`) to
catch the resulting exception.

Fixes #2003.
Fixes #1980.
2023-07-15 12:08:11 -07:00
Steve Gravrock
59600a1c29 Removed expect/expectAsync indirection through spec/suite 2023-07-15 12:08:11 -07:00
Steve Gravrock
f8e4ea868f CI: Use a globally-unique Sauce tunnel ID
CIRCLE_BUILD_NUM is only unique per-repo, and we have multiple repos
that can concurrently run Sauce builds.
2023-07-01 11:05:04 -07:00
Steve Gravrock
0ff56c53b1 Dogfood remote Selenium grid support 2023-07-01 10:17:05 -07:00
Steve Gravrock
b617d983de Bump version to 5.0.1 2023-06-09 16:24:00 -07:00
Steve Gravrock
8e0f0e8e8c Optionally restore the pre-5.0 behavior of boot() always creating a new instance
This is needed by jasmine-npm (and likely other tools like it) that may
need to create and use multiple envs in sequence.
2023-06-05 19:44:06 -07:00
Steve Gravrock
d745d6b5f0 Bump version to 5.0.0 2023-05-13 15:14:53 -07:00
Steve Gravrock
fc2c2a477d Updated most dev dependencies
Not updating Prettier because newer versions impose significant formatting
changes. In particular, 2.0 changes every function definition from
`function() {` to `function () {` with no way to opt out. I'm not willing
to accept that kind of churn just becuse the Prettier devs changed their
mind about what color the bikeshed should be.

We'll most likely stay on Prettier 1.17 for as long as it remains viable,
then either switch to an autoformatter that offers stability or just
remove it.
2023-05-13 12:03:45 -07:00
Steve Gravrock
ff93277c0f Accessibility: Always provide a non-color indication that a spec is pending 2023-04-29 11:45:21 -07:00
Steve Gravrock
90741b3cee Accessibility: Improved contrast of version number and inactive tab links 2023-04-29 11:45:16 -07:00
Steve Gravrock
d1de59f0ed Updated jasmine dev dependency 2023-04-29 10:53:03 -07:00
Steve Gravrock
73f8e001ad Bump version to 5.0.0-beta-0 2023-04-29 10:10:05 -07:00
Steve Gravrock
390cc45af2 Dropped support for Node 16
Node 16 will reach EOL no later than a few months after Jasmine 5 is
released. Experience with Node 12 and Node 14 has shown that our
dependencies, especially dev dependencies, move on from past-EOL Node
versions fairly quickly. That can make it difficult to continue supporting
them. Since long term support for past EOL Node versions is a non-goal and
many users expect that Node versions will only be dropped in major
releases, it's better to drop it in 5.0.
2023-04-27 19:32:18 -07:00
Steve Gravrock
33118ac6e2 Merge branch 'main' into 5.0 2023-04-27 19:22:30 -07:00
Steve Gravrock
31ff9a300c Added Node 20 to supported environments 2023-04-22 08:12:49 -07:00
Steve Gravrock
5cc739d879 Bump version to 5.0.0-alpha.1 2023-04-08 13:02:21 -07:00
Steve Gravrock
1e7f07259e API docs for parallel support things that jasmine-npm uses 2023-04-08 12:37:40 -07:00
Steve Gravrock
c36a5cfd96 Parallel: Cleaner interface for reporter dispatching
This gets jasmine-npm out of having to deal with QueueRunner, GlobalErrors,
and ReportDispatcher directly.
2023-04-08 11:41:15 -07:00
Steve Gravrock
299fd1f770 Removed unnecessary TODO 2023-03-25 11:21:04 -07:00
Steve Gravrock
656427d328 Parallel: Disallow calls to Env#config from spec and helper files
Such configuration changes only affect one worker, which is almost certainly
not the intent.
2023-03-25 11:16:54 -07:00
Steve Gravrock
621522fdd4 Updated Glob 2023-03-21 22:35:15 -07:00
Steve Gravrock
6e3589bf52 Updated most dev dependencies 2023-03-21 22:33:24 -07:00
Steve Gravrock
df2d9b282e Bump version to 5.0.0-alpha.0 2023-03-18 11:25:32 -07:00
Steve Gravrock
726d35c5c5 Merge remote-tracking branch 'origin/main' into 5.0 2023-03-15 17:53:08 -07:00
Steve Gravrock
f509078020 Bump version to 4.6.0 2023-03-15 17:21:56 -07:00
Steve Gravrock
8308515210 Ignore the number of CPUs reported by Circle CI 2023-03-12 15:31:28 -07:00
Steve Gravrock
ed838b3cbf Dropped support for Node <16.14
To match jasmine-npm.
2023-03-11 21:19:30 -08:00
Steve Gravrock
04fac300e8 Uninstall the global error at the end of env execution
jasmine-npm needs this so that it can do its own error handling during
globalTeardown.
2023-03-11 17:45:31 -08:00
Steve Gravrock
ff237f4b66 Fixed sass version pinning 2023-03-11 14:26:22 -08:00
Steve Gravrock
e42e3d9e00 Pin sass to the last version that works on Node 12 2023-03-11 14:19:16 -08:00
Steve Gravrock
61505f4c59 Fixed post-merge test failures 2023-03-04 14:10:05 -08:00
Steve Gravrock
86eddb05b4 Merge remote-tracking branch 'origin/main' into 5.0 2023-03-04 14:06:43 -08:00
Steve Gravrock
8af5509581 Added a parallel flag to the jasmineStarted reporter event 2023-03-03 20:49:10 -08:00
Steve Gravrock
166e5f4d6c Report the ID of each suite/spec's parent
This is intended to support parallel execution, which is planned for a
future release of Jasmine. Because the execution of unrelated suites will
interleave when run in parallel, reporters will not be able to assume
that the most recent `suiteStarted` event identifies the parent of the
current suite/spec. By adding this feature now, we allow reporters to
support both parallel execution and at least some 4.x versions without
having to implement two different ways of finding the parent suite.
2023-02-25 10:24:14 -08:00
Steve Gravrock
6ad8d20694 Report the path/url of the file that the spec/suite was defined in
Fixes #1884
2023-02-15 21:39:21 -08:00
Steve Gravrock
cbc03feb52 Merge branch 'main' into 5.0 2023-02-12 13:08:42 -08:00
Steve Gravrock
bc3a495160 Pin eslint-plugin-compat to <4.1.0 to fix import error on CI
See <https://github.com/amilajack/eslint-plugin-compat/issues/528>.
2023-02-07 18:46:17 -08:00
Steve Gravrock
b323631611 Pin Grunt to <1.6.0 for compatiblity with Node 12 2023-01-30 17:57:47 -08:00
Steve Gravrock
e8767ba660 Removed "Does the problem occur with the latest version of jasmine-core" from issue templates 2023-01-25 20:50:51 -08:00
Steve Gravrock
af9a4114f4 Parallel: Improved error messages for top-level before/afterAll 2022-11-25 13:13:05 -08:00
Steve Gravrock
75f97961f5 Dropped support for Safari 14 and Firefox 91 2022-11-24 13:25:39 -08:00
Steve Gravrock
25a7168286 Merge remote-tracking branch 'origin/main' into 5.0 2022-11-24 12:50:39 -08:00
Steve Gravrock
494e81f436 Document that stopOnSpecFailure is best-effort in parallel mode 2022-11-24 12:48:40 -08:00
Steve Gravrock
169a2a8ad2 Upgraded to new issue templates 2022-11-20 14:01:43 -08:00
Steve Gravrock
b267029301 Revert "Upgraded to new issue templates"
This reverts commit cf574634b8.
2022-11-20 13:58:20 -08:00
Steve Gravrock
cf574634b8 Upgraded to new issue templates 2022-11-20 13:56:47 -08:00
Steve Gravrock
f8c01574e6 Added Firefox 102 (current ESR) to browser list in README 2022-10-29 15:26:30 -07:00
Steve Gravrock
481f1e7c5c Bump version to 4.5.0 2022-10-29 14:48:32 -07:00
Steve Gravrock
5e650953cd Added Safari 16 to supported browsers 2022-10-22 13:08:10 -07:00
Steve Gravrock
ed5e902106 Parallel: Don't allow reporters to be added or removed in worker processes 2022-10-22 09:56:52 -07:00
Steve Gravrock
87f9ab29df Fixed the jsdoc types of SuiteResult and SpecResult ids 2022-10-19 17:20:24 -07:00
Steve Gravrock
47c64a86d5 Parallel: fail if randomization is disabled or a seed is specified 2022-10-12 20:08:42 -07:00
Steve Gravrock
bb497beeff Parallel: throw if Env#topSuite is called 2022-10-11 20:16:36 -07:00
Steve Gravrock
e14d9c4be3 Parallel: forbid beforeAll/afterAll at the top level
Either running these once total or running them once per process
would be the wrong choice for a significant chunk of users, so do
neither. Later we'll add a new API for exactly-once setup and teardown
in parallel mode.
2022-10-11 20:10:02 -07:00
Steve Gravrock
89e0b35c53 Parallel: throw an error if fit/fdescribe are used in parallel mode 2022-10-11 19:35:59 -07:00
Steve Gravrock
1e7b68236b Parallel: forbid beforeEach/afterEach at the top level of spec files
Each spec file is only loaded in a single worker, so top level
before/afterEach can't behave consistently.

beforeEach/afterEach are still supported in:
* Helper files
* describe() blocks
* At the top level of spec files in non-parallel mode
2022-10-11 19:25:39 -07:00
Steve Gravrock
394068f863 Depend on -npm 5.0 2022-10-08 15:39:57 -07:00
Steve Gravrock
b831e81074 Include inner exceptions in stack traces 2022-09-24 12:12:21 -07:00
Steve Gravrock
4c13c2b00b Replaced var with const in API doc examples 2022-09-24 10:12:22 -07:00
Steve Gravrock
dd98a45003 Use lcoal core when running our own tests in parallel 2022-09-18 19:59:21 -07:00
Steve Gravrock
fe6762b470 Merge branch '5.0' into parallel 2022-09-18 16:42:25 -07:00
Steve Gravrock
fa16b74500 Merge branch 'main' into 5.0 2022-09-18 13:39:05 -07:00
Steve Gravrock
4cd190b232 Merge branch 'internal-async' 2022-09-18 13:31:43 -07:00
Steve Gravrock
6ada55ff77 Parallel: Fixed reporting of exceptions thrown by a describe 2022-09-18 12:10:34 -07:00
Steve Gravrock
735ce6f758 Merge remote-tracking branch 'origin/5.0' into parallel 2022-09-18 09:43:31 -07:00
Steve Gravrock
430324885b Merge branch 'main' into 5.0 2022-09-18 09:41:45 -07:00
Steve Gravrock
7c2e8ce7ca Merge branch 'main' into parallel 2022-09-17 13:26:37 -07:00
Steve Gravrock
d4025999b7 Report exceptions thrown by a describe before any it calls
Previously, these were masked by the "describe with no children" error.
Now they're reported as suite level errors on an empty suite.
2022-09-17 13:24:45 -07:00
Steve Gravrock
871111424d Use one worker per CPU when running own specs in parallel 2022-09-17 12:20:05 -07:00
Steve Gravrock
44f331f43d Updated the style of the examples
* const/let instead of var
* classes
* pass our own eslint checks
2022-09-17 12:00:20 -07:00
Steve Gravrock
213144413f Test parallel operation in CI 2022-09-17 11:44:24 -07:00
Steve Gravrock
2272f9aead Parallel: run our own specs in parallel 2022-09-17 11:35:03 -07:00
Steve Gravrock
59848ca151 Coerce the random string to a seed before sending it to reporters
This fixes an error in HTMLReporter when the configured seed is a
number rather than a string, which has been allowed since 3.8.0
2022-09-03 12:36:35 -07:00
Steve Gravrock
c14bfe3e5f Updated release process doc
* Fixed description of patch releases
* Moved -npm release docmentation to that repo
* Refer to -npm specifically rather than "binding libraries" generally,
  now that we only have one of those that versions in lockstep with core.
2022-09-03 11:02:13 -07:00
Steve Gravrock
26c48ab324 Bump version to 4.4.0 2022-09-03 09:42:39 -07:00
Steve Gravrock
4c8d57e14c Dropped support for Node 14 2022-08-27 10:47:40 -07:00
Steve Gravrock
543689e206 Depend on -npm from github 2022-08-27 10:46:25 -07:00
Steve Gravrock
ee524831f4 Merge branch 'main' into parallel 2022-08-27 10:30:21 -07:00
Steve Gravrock
cfecab9f79 Updated contributing guide 2022-08-22 18:10:33 -07:00
Steve Gravrock
b3d9435dbb Convreted TreeProcessor to async/await 2022-08-22 17:04:44 -07:00
Steve Gravrock
fec8dd37b0 Merge branch 'main' into internal-async 2022-08-22 10:46:03 -07:00
Steve Gravrock
0690500a0d Breaking change: Made Env#execute async
Errors related to invalid spec order are now reported via promise
rejection rather than synchronous throw.
2022-08-21 16:40:03 -07:00
Steve Gravrock
0bfbda720d Breaking change: Env#execute no longer takes a callback
Use the returned promise instead.
2022-08-21 16:35:12 -07:00
Steve Gravrock
4fcdbd39fb Breaking change: use addEventListener rather than setting window.onerror
* Generally simplifies error handling in browsers
* Makes Jasmine's own integration tests easier to debug
* Stack traces will be provided for more global errors
* ... but less error information will be provided in some browsers if the
  error comes from a file:// URL (use `npx serve` or similar instead)
* Jasmine will no longer override existing onerror handlers in browsers
* Setting window.onerror will no longer override Jasmine's global error
  handling (use jasmine.spyOnGlobalErrors instead)
2022-08-21 16:17:18 -07:00
Steve Gravrock
f934e6d816 Assume that addEventListener/removeEventListener are present in browsers
Jasmine 3.0 dropped support for the last browser that didn't support
the standard event handler methods (IE 9).
2022-08-20 10:27:44 -07:00
Steve Gravrock
79c6bbc189 clearStack optimizations
* Avoid setTimeout in Node, because we don't need the overhead there.
* Still call setTimeout in browsers to prevent the tab from being killed.
* Use queueMicrotask in Safari, because it's dramatically faster than
  MessageChannel there.
* Continue to use MessageChannel in other supported browsers becuase it's
  somewhat faster than queueMicrotask there.
* Don't use setImmediate any more because there's a faster alternative in
  all supported envs.

In jasmine-core's own test suite, this yields a roughly 50-70% speedup
in Node, ~20% in Edge, and 75-90%(!) in Safari.
2022-08-15 17:50:49 -07:00
Steve Gravrock
2e80ec0c22 Rm dead code for QueueRunner deprecations 2022-08-11 19:51:08 -07:00
Steve Gravrock
588283cfe5 Breaking change: support for -npm reporter handling in parallel mode
* The `boot` function exported by the core module returns the same object
  every time it's called.
* Removed node_boot.js. Use the exported `boot` function instead
* JasmineStartedInfo does not have totalSpecsDefined or order in parallel mode
* JasmineDoneInfo does not have order in parallel mode
* Added incompleteCode and numWorkers to JasmineDoneInfo
2022-08-10 18:23:38 -07:00
Steve Gravrock
3a43871901 Reset the env state between parallel batches 2022-08-06 10:55:02 -07:00
Steve Gravrock
fcbab02b2d Droped support for Node 12 2022-08-06 10:55:02 -07:00
Steve Gravrock
5f3475342e Re-added missing JasmineStartedInfo jsdoc 2022-08-06 10:53:28 -07:00
Steve Gravrock
e022e6199c Bump version to 4.3.0 2022-07-23 10:27:19 -07:00
Steve Gravrock
140c12e8fc Added Firefox 102 (current ESR) to CI 2022-07-23 10:17:21 -07:00
Steve Gravrock
21f25972bb Converted ReportDispatcher to promises 2022-07-01 17:25:22 -07:00
Steve Gravrock
d0e1bd96fb README updates
* Removed redundancy
* Added a link to the FAQ
* Removed obsolete support channels
2022-07-01 16:58:38 -07:00
Steve Gravrock
6c56ebc984 Added jasmine.spyOnGlobalErrorsAsync
* Allows testing code that's expected to prodeuce global errors or
  unhandled promise rejections
* Fixes #1843
* Fixes #1453
2022-06-30 18:09:56 -07:00
Steve Gravrock
d0a9931ae6 Separated reporter- and runable-specific queue runner configuration 2022-06-12 15:52:14 -07:00
Steve Gravrock
93c5f654d9 Extracted most suite-running code out of Env 2022-06-12 15:46:03 -07:00
Steve Gravrock
d8b65028a1 Pass queue runner factory to Spec#execute, not ctor 2022-06-12 12:34:46 -07:00
Steve Gravrock
d6cdc1841c Extracted suite building out of Env 2022-06-12 09:49:01 -07:00
Steve Gravrock
72b39220e5 Runable, not runnable 2022-06-11 15:41:29 -07:00
Steve Gravrock
55dce7d119 Extracted runnable resource management out of Env 2022-06-11 15:28:37 -07:00
Steve Gravrock
789736dd02 Additional test coverage for default spy strategies 2022-06-11 15:08:02 -07:00
Steve Gravrock
c7ca3b0101 Converted integration specs to async/await 2022-06-11 13:43:44 -07:00
Steve Gravrock
96000220b1 Use arrow fns rather than self = this 2022-06-11 12:12:11 -07:00
Steve Gravrock
e2e2275d41 Removed obsolete and unused utility fns 2022-06-11 11:17:16 -07:00
Steve Gravrock
135ff20123 Replaced uses of var with const/let 2022-06-09 20:00:23 -07:00
Steve Gravrock
4af86f5398 Added supported envs to releasen notes 2022-06-09 18:25:04 -07:00
Steve Gravrock
e5e0e6481d Bump version to 4.2.0 2022-06-09 18:18:45 -07:00
Steve Gravrock
bcf69b86b4 Removed duplicate Suite and Spec jsdocs 2022-06-03 12:22:58 -07:00
Steve Gravrock
a5f79fac81 Removed remaining jshint config comments 2022-06-02 18:22:23 -07:00
Steve Gravrock
18a00822c5 Built distribution 2022-06-02 11:37:10 -07:00
Steve Gravrock
4cc8437f79 Call buildExpectationResult directly from Suite and Spec
This removes quite a bit of indirection from result processing, at the
cost of making a few of the tests more awkward.
2022-06-01 10:18:23 -07:00
Steve Gravrock
8e58305b0a ExpectationResult.js -> buildExpectationResult.js 2022-06-01 09:26:21 -07:00
Steve Gravrock
bd368aceee Replaced var with const and let in expectation related code 2022-06-01 09:22:03 -07:00
Steve Gravrock
8f16021887 Replaced var with const and let in ExpectationResult 2022-06-01 09:02:43 -07:00
Steve Gravrock
bbb1b69b2e More reliably report errors that occur late in the suite/spec lifecycle
Previously, an error that occurred after Jasmine started to report the
suiteDone or specDone event for the current runable would not be reliably
reported. Now such an error is reported on the nearest ancestor suite whose
suiteDone event has not yet been reported.
2022-05-28 18:10:55 -07:00
Steve Gravrock
9ea8a2096f Additional integration tests for existing async error handling 2022-05-28 18:01:19 -07:00
Steve Gravrock
66340e2b19 Updated browserslist to match 4.0 envs 2022-05-28 18:00:45 -07:00
Steve Gravrock
fe29dfa89c Update release process instructions
* Need to tag the release manually since the Ruby tooling for that was
  removed
* Windows CI works again, so no need to manually test on Windows
2022-05-21 09:43:43 -07:00
Steve Gravrock
41f7fabe2f Renamed jasmine.exactly to jasmine.is, for similarity with toBe 2022-05-21 08:30:53 -07:00
Steve Gravrock
856a040a2d Fixed flaky spec 2022-05-19 16:39:48 -07:00
Steve Gravrock
f7eaa5ec29 Fixed failing CI builds for Node 12 and 14
See https://github.com/npm/cli/issues/4896
2022-05-16 19:53:20 -07:00
Steve Gravrock
0c87d47318 Added a jasmine.exactly asymmetric equality tester 2022-05-14 17:01:38 -07:00
Steve Gravrock
c24b2f5a73 Converted some integration specs to async/await 2022-05-14 12:05:53 -07:00
Steve Gravrock
774c83a36e Don't report a deprecation when a runnable uses two forms of async
This was made into an error in 4.0, so the deprecation is redundant
(and broken).
2022-05-14 11:21:40 -07:00
Steve Gravrock
751cf6ab5b Converted DiffBuilder, ObjectPath, MismatchTree, and SinglePrettyPrintRun to ES6 classes 2022-05-14 11:15:08 -07:00
Steve Gravrock
2fd76c954c Replaced var with let and const in PrettyPrinter, DiffBuilder, and friends 2022-05-14 09:42:07 -07:00
Steve Gravrock
bb4d18f959 Include property getter values in pretty-printed objects
We already call getters when comparing objects for equality and generating
diffs, so it should be safe to do it here too.

See #1966.
2022-05-12 17:14:13 -07:00
Steve Gravrock
68eaa64c31 Bump version to 4.1.1 2022-05-09 17:49:42 -07:00
Steve Gravrock
81f6eb45ea Cleaned up specs for symbol property filtering
* Removed redundant spec
* Test the behavior of jasmineUnderTest, not the host jasmine
2022-05-09 17:11:36 -07:00
Steve Gravrock
841b212c66 Merge branch 'patch-1' of https://github.com/suke/jasmine
* Merges #1963 from @suke
* Excludes non-enumerable symbol properties from equality comparison
2022-05-09 16:51:47 -07:00
Steve Gravrock
9a27407d35 Folded util.objectDifference into MatchersUtil
This was always an implementation detail of objectKeysAreDifferentFormatter,
and didn't really do what its name suggested.

* #1966
2022-05-07 14:03:26 -07:00
Steve Gravrock
468e9577cd Include symbol properties in matcher diffs
* #1966
2022-05-07 13:26:15 -07:00
Steve Gravrock
9d80377fe3 Fixed exception when comparing arrays with Symbol keys
* Fixes #1966
2022-05-07 10:42:29 -07:00
Steve Gravrock
270344bd38 Include symbol keys when pretty-printing objects
* Fixes #1966
2022-05-07 10:05:18 -07:00
suke
dfa94c70c1 toEqual does not compare symbols that cannot be enumerated 2022-04-27 10:51:03 +09:00
Steve Gravrock
694375e4ea Added Node 18 to CI matrix 2022-04-23 12:39:44 -07:00
Steve Gravrock
1166d10e43 Use const/let in specs, not var 2022-04-16 13:41:44 -07:00
Steve Gravrock
482dc883eb Check for unused vars and params in specs 2022-04-16 10:58:25 -07:00
Steve Gravrock
364cf35474 Fixed shared example for describe-like fns 2022-04-16 10:26:07 -07:00
Steve Gravrock
2e8732f30f Added supported envs to 4.1.0 release notes 2022-04-11 21:08:07 -07:00
Steve Gravrock
04133264e0 Bump version to 4.1.0 2022-04-11 20:24:42 -07:00
Steve Gravrock
d2bf6062cb README updates
* Replaced redundant installation instructions with link to docs
* Added links to usage instructions
* Fixes #1941
2022-04-09 11:20:54 -07:00
Steve Gravrock
fb639d0f55 toBeCloseTo treats Infinity and -Infinity as close to themselves
* Fixes #1957
2022-04-09 11:14:24 -07:00
Steve Gravrock
52b1a3a7f8 Merge branch 'refactor/rm-deprecated-substr' of https://github.com/CommanderRoot/jasmine
* Merges #1962 from @CommanderRoot
2022-04-02 10:32:59 -07:00
Steve Gravrock
1f7880ee8c Updated Sauce Connect 2022-03-29 20:57:49 -07:00
Steve Gravrock
a6e1aef8d7 Added debug logging to flaky spec 2022-03-29 20:57:49 -07:00
Steve Gravrock
d2815982ce Removed obsolete vendor-specific background-size rules
* Fixes #1961
2022-03-29 07:20:02 -07:00
Tobias Speicher
aa979277fb refactor: replace deprecated String.prototype.substr()
.substr() is deprecated so we replace it with functions which work similarily but aren't deprecated

Signed-off-by: Tobias Speicher <rootcommander@gmail.com>
2022-03-25 16:03:46 +01:00
Steve Gravrock
1e0c312f9f Merge branch 'main' of https://github.com/nitobuendia/jasmine
* Adds toHaveSpyInteractions matcher
* Merges #1959 from @nitobuenida
* Fixes #1568
2022-03-18 11:10:39 -07:00
Nito Buendia
c5db939886 Run cleanup 2022-03-17 21:09:14 +08:00
Nito Buendia
e470fb56d7 Refactor error message to account for negate comparisons
The message return on negate clause was not expected. This makes it negative to match expectation. This also add tests for the change, and renames some tests to make it more clear.
2022-03-17 21:06:51 +08:00
Nito Buendia
a8a6577cd7 Replace parameterized test with different expectations
This approach makes it hard to scale and goes against DRY and debuggability vs the previous approach which followed Python parameterized testing, but this was the recommendation of the Jasmine team to keep it consistent with other tests.

Further tests here could be adding other types like Array, Map, WeakMap, Set, WeakSet...
2022-03-17 20:16:22 +08:00
Nito Buendia
1660015c12 Run formatter 2022-03-16 23:01:20 +08:00
Nito Buendia
faf210ab4c Remove dependency on matchersUtil for test 2022-03-16 23:00:27 +08:00
Nito Buendia
00fd4a819f Refactor tests to depend on jasmineUnderTest 2022-03-16 21:48:03 +08:00
Nito Buendia
091cd8c3b6 Remove spyObj setup from test that does not require it 2022-03-16 21:34:28 +08:00
Nito Buendia
aba0c98eb9 Fix unit test to include testValue instead of a constant value 2022-03-16 21:31:40 +08:00
Nito Buendia
a7eff79db0 Simplify test for arguments passed 2022-03-16 21:26:59 +08:00
Nito Buendia
2a5673e6ab Change jasmine to jasmineUnderTest 2022-03-16 21:20:21 +08:00
Nito Buendia
c13dd26c4b Change set up to each of the formats
This goes against DRY principle, but it was recommended by Jasmine team to reduce coupling between tests.
2022-03-16 21:18:25 +08:00
Nito Buendia
2e8b477489 Change arrow functions with anonymous functions 2022-03-16 21:14:43 +08:00
Nito Buendia
b2c2e08641 Remove @since tag from JSDoc 2022-03-16 20:15:09 +08:00
Nito Buendia
d7d75abc42 Rename spec to include Spec to allow running 2022-03-16 20:14:06 +08:00
Nito Buendia
0b71d0a2a0 Merge branch 'jasmine:main' into main 2022-03-16 20:09:19 +08:00
Steve Gravrock
dfa5b6a53d Pretty-print [new String("")] as "[ '' ]" not "[]" 2022-03-14 18:47:23 -07:00
Steve Gravrock
7f75f23e5b Use new Circle CI images
The old images are deprecated:
<https://discuss.circleci.com/t/legacy-convenience-image-deprecation/41034>
2022-03-09 13:05:34 -08:00
Steve Gravrock
502cb24bb8 Merge branch '4.0.1' 2022-02-21 17:08:11 -08:00
Steve Gravrock
0ae234dc6e Bump version to 4.0.1 2022-02-21 16:58:32 -08:00
Steve Gravrock
38d102f1d1 Merge branch '3.99.1' into 4.0.1 2022-02-21 16:45:34 -08:00
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
Nito Buendia
7b01003d0b Add specs for the new toHaveSpyInteractions matcher 2022-02-16 21:11:42 +08:00
Nito Buendia
8e85f3df74 Create toHaveSpyInteractions matcher
This matcher checks all the properties of a given spy object and checks whether at least one of the spies has been called. It returns true if one or more of the spies of the spy object has been called and false otherwise.
2022-02-16 21:10:31 +08:00
Steve Gravrock
b0034797fe Merge branch 'fix-save-args-by-value' of https://github.com/coyoteecd/jasmine
* Fixes cloning of Date objects in saveArgumentsByValue()
* Merges #1955 from @coyoteecd
* Fixes #1885
2022-02-02 21:18:38 -08:00
Dan Cortel
83e9f88952 Make saveArgumentsByValue clone Date objects correctly
* Fixes #1885
2022-01-26 18:32:05 +02:00
Gwendolyn Van Hove
de13b47809 Update maintainers list 2022-01-20 15:57:48 -08:00
Steve Gravrock
9e10743a1c Include the name of the suite in the empty suite error message 2022-01-17 15:08:56 -08:00
Steve Gravrock
5327157832 Always run formerly flaky specs 2022-01-17 14:54:21 -08:00
Steve Gravrock
6e3128c792 Merge branch 'SymboltoEqual' of https://github.com/laeleoni/jasmine
* Merges #1879 from @laeleoni
* Fixes #1879
2022-01-15 11:44:53 -08:00
Steve Gravrock
bd2e877f4e Removed scheduled workflows from Circle CI config
Scheduled pipelines (configured via the Circle web UI) will be used instead.
2022-01-15 10:50:03 -08:00
Steve Gravrock
5b23ffe174 Merge pull request #1951 from ath0mas/patch-1
Update html example in README
2022-01-04 20:37:03 -08:00
Alexis THOMAS
384e0859c7 Update html example in README
Follow SpecRunner.html: Simplifies types (197cb13817) and Split boot.js in two (286524959b)
2022-01-04 23:51:30 +01:00
Steve Gravrock
616682e487 Stop cron builds on 3.99 and 4.0 2022-01-01 13:29:39 -08:00
Steve Gravrock
98c2f019c6 Bump version to 4.0.0 2022-01-01 12:43:29 -08:00
Steve Gravrock
507dad6d87 Set -npm and -browser-runner dev dependencies back to main 2022-01-01 12:10:24 -08:00
Steve Gravrock
6da7a32442 Merge branch '4.0' 2022-01-01 12:00:46 -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
ff14c03a40 Test against the latest Node 12 2022-01-01 08:44:28 -08:00
Steve Gravrock
ff848c812a Merge branch 'main' into 4.0 2021-12-31 15:07:03 -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
8444faab72 Use the clock from jasmineUnderTest in specs 2021-12-31 10:00:14 -08:00
Steve Gravrock
883f400074 Merge branch '4.0' of https://github.com/thw0rted/jasmine into 4.0
* Fixes handling of reentrant calls to `jasmine.clock().tick()`
* Merges #1948 from @thw0rted
* Fixes #1929
2021-12-31 09:50:09 -08:00
Steve Gravrock
3c16caa413 Link to the CONTRIBUTING guide from the PR template 2021-12-31 09:47:46 -08:00
Steve Gravrock
5d0be2e6cf Updated the contributing guide for 4.0
* Moved "Before Submitting a Pull Request" to the top
* Removed discussion of the standard Github PR workflow
  (Contributors who don't know how to create PRs on Github at all can find
  that information elsewhere. For the rest, it's just noise.)
* Misc copy edits
2021-12-31 09:43:46 -08:00
James Bromwell
c56631175f Fix time-travel in delayed function scheduler 2021-12-29 17:50:48 +01:00
Steve Gravrock
cef738966c Updated dev dependencies 2021-12-21 17:51:28 -08:00
Steve Gravrock
5fd0e49ccf Removed unused ejs dev dependency 2021-12-21 17:00:10 -08:00
Steve Gravrock
c431590d65 Fixed reporting of suites that are skipped due to a beforeAll failure 2021-12-20 13:39:24 -08:00
Steve Gravrock
656e6614da Built distribution 2021-12-15 20:36:44 -08:00
Steve Gravrock
24408a16ed Removed initialization of unused Promise config property 2021-12-15 20:34:00 -08:00
Steve Gravrock
ca90c76d12 Merge branch '3.99' into 4.0 2021-12-14 08:27:05 -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
e73eb18753 Test against jasmine-browser-runner 1.0.0-dev 2021-12-13 21:41:09 -08:00
Steve Gravrock
0411b0567d Added a mention of 4.0 migration to the README 2021-12-11 16:13:51 -08:00
Steve Gravrock
30b93ccdbb Updated jsdocs for Env#execute 2021-12-11 15:53:25 -08:00
Steve Gravrock
067b91b3ef Removed IE/PhantomJS support code 2021-12-11 14:57:41 -08:00
Steve Gravrock
0b1385c3d3 Report start and end events for specs/suites that are skipped due to a beforeAll error
This is noisier, but it maintains compatibility with reporters that assume
(quite reasonably) that all specs and suites are either filtered out or
reported.
2021-12-11 12:34:23 -08:00
Steve Gravrock
f1cf6ee419 Resolve the execute() promise to the entire JasmineDoneInfo
This matches jasmine-npm.
2021-12-09 18:18:36 -08:00
Steve Gravrock
b37d989f13 Removed past-EOL Firefox versions 2021-12-07 18:16:00 -08:00
Steve Gravrock
89151d6e64 Dropped Safari 13 from build matrix 2021-12-07 17:04:19 -08:00
Steve Gravrock
75e3e14861 Merge remote-tracking branch 'upstream/safari-15' into 4.0 2021-12-07 17:03:40 -08:00
Steve Gravrock
ce7460d8d4 Fixed stack trace filtering on Safari 15 2021-12-07 16:50:07 -08:00
Steve Gravrock
b8dabf96ff HTML: Include top suite failures in the reported failure count 2021-12-03 08:18:18 -08:00
Steve Gravrock
40fac8b6a2 Renamed the trace feature to debugLog[s]
"trace" was ambiguous and could easily be understood to have something
to do with stack traces.
2021-12-02 14:46:56 -08:00
Steve Gravrock
5eb42d67a7 Added a note about async testing style to contributing guide 2021-12-02 12:40:14 -08:00
Steve Gravrock
d739c23401 Resolve the promise returned by Env#execute to the overall status 2021-12-02 12:40:14 -08:00
Steve Gravrock
42e6c45efa Allow use without creating globals
* Fixes #1235
2021-11-29 20:37:07 -08:00
Steve Gravrock
5942654856 Merge branch '3.99' into 4.0 2021-11-26 13:27:57 -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
871ba99a30 Allow custom spy strategies to be inherited like other runnable resources 2021-11-17 12:50:16 -08:00
Steve Gravrock
7a685b16f6 Removed duplicate message from errors (incl. matcher failures) on V8 2021-11-16 12:52:07 -08:00
Steve Gravrock
2a049015b0 Use custom equality testers in Spy#withArgs
Fixes #1836.
2021-11-15 18:55:09 -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
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
8e74529631 Merge branch '3.99' into 4.0 2021-10-15 10:37:51 -07: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
c1db8f2f82 Clarified deprecation message for this in describes 2021-10-12 15:40:13 -07:00
Steve Gravrock
41f5c53959 Consistently identify clenaup fns by a type tag, not position
This was already done for everything except spec cleanup fns, since the
various skip policies need to know the difference between afterEach and
afterAll.
2021-10-11 18:05:57 -07:00
Steve Gravrock
25c3f06839 Run afterAll fns after failure even if stopOnSpecFailure is true
[#160905297]
2021-10-08 14:19:56 -07:00
Steve Gravrock
976928c7ae Set version to 4.0.0-pre.0 2021-10-08 08:48:22 -07:00
Steve Gravrock
36a4ddf433 Revert "Removed jsdoc entry for SpecResult#trace"
This reverts commit 4482355885.
2021-10-07 10:56:52 -07:00
Steve Gravrock
53b1cd37b6 Merge branch '3.99' into 4.0 2021-10-07 10:56:41 -07:00
Steve Gravrock
8cadfbd829 Fixed deprecation warning in spec 2021-10-07 10:51:06 -07:00
Steve Gravrock
86aeb5c88a Merge branch 'main' into 3.99 2021-10-07 10:38:35 -07:00
Steve Gravrock
d4c15b8df4 No longer test Node <12.17 2021-10-06 17:58:28 -07:00
Steve Gravrock
6f0c51260f Depend on the 4.0 branch of -npm 2021-10-06 17:54:54 -07:00
Steve Gravrock
15710937b8 Added a test that verifies skip to cleanup fns after pending()
Because pending() is implemented via the standard exception handling
path, we effectively got this feature for free as a result of the changes
for #1533, particularly 457a2727.

* [#178598493]
* Fixes #1579
2021-10-06 11:07:53 -07:00
Steve Gravrock
1a9d16715d Clarify which behaviors are specific to different stopSpecOnExpectationFailure values
* #1533
2021-10-06 08:55:01 -07:00
Steve Gravrock
b67a3043c7 Skip afterEach fns in nested suites when a beforeEach fn errors
This matches the behavior of beforeAll errors.

* #1533
2021-10-06 08:55:01 -07:00
Steve Gravrock
5f1ef5ac2b Skip everything except afterAll fns when a beforeAll fn errors
* Fixes #1533
2021-10-06 08:55:01 -07:00
Steve Gravrock
5eaeeb0b6c Moved fn skipping policy out of QueueRunner
This should allow us to more easily support complex skipping strategies
like skipping nested cleanup fns when the corresponding befores were
skipped, or skipping specs and suites when a beforeAll fails.

* #1533
2021-10-06 08:55:01 -07:00
Steve Gravrock
457a2727ba Skip to afterEach fns when a beforeEach fn errors
* #1533
2021-10-06 08:55:01 -07:00
Steve Gravrock
a1f14efac6 Improved specs for stopSpecOnExpectationFailure
* #1533
2021-10-06 08:55:01 -07:00
Steve Gravrock
b2067d9ce0 Fixed references to Env#trace in jsdocs 2021-10-02 09:58:47 -07:00
Steve Gravrock
47081258cd Revert "Revert "Added the ability to associate trace information with failing specs""
This reverts commit fdad8849df.
2021-10-02 09:56:25 -07:00
Steve Gravrock
9c03d4d3e9 Merge branch '3.99' into 4.0 2021-10-02 09:52:43 -07:00
Steve Gravrock
7f0087b805 Merge branch 'main' into 3.99 2021-10-02 09:47:30 -07:00
Steve Gravrock
35064cf60e Merge branch '3.99' into 4.0 2021-09-24 14:31:02 -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
3a77ae3dfe Throw if the argument to jasmine.clock().mockDate() is not a Date 2021-09-23 16:10:59 -07:00
Steve Gravrock
1332f01ca4 Merge branch '3.99' into 4.0 2021-09-23 16:08:44 -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
8d302d8dca Merge branch '3.99' into 4.0 2021-09-20 15:57:37 -07:00
Steve Gravrock
760f2d9003 Removed additional Ruby support files 2021-09-18 09:40:30 -07:00
Steve Gravrock
6e10f22403 Don't display late errors as AfterAll errors in the HTML reporter 2021-09-11 08:57:50 -07:00
Steve Gravrock
d092a59bd1 Treat multiple calls to done callbacks as errors 2021-09-10 18:07:35 -07:00
Steve Gravrock
af5984d5d6 Fixed flake list 2021-09-10 17:53:59 -07:00
Steve Gravrock
15f7013f85 Merge branch '3.99' into 4.0 2021-09-08 21:04:10 -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
bbcb5ff42f Fixed linter & formatter issues in boot files 2021-09-03 15:46:23 -07:00
Steve Gravrock
6603ed7ddc Don't distribute boot src files
[#179017951]
2021-09-03 15:42:06 -07:00
Steve Gravrock
d61800c5c8 Removed support for custom promise libraries
All supported platforms now provide promises, so there's no longer a need
for Jasmine to be able to create them via a user-provided library. Jasmine
can still consume non-native promises but will always use the built-in
Promise object to create promises.

[#179078103]
2021-08-30 19:07:26 -07:00
Steve Gravrock
37b9f8e420 Removed Ruby support
[#179247162]
2021-08-30 18:53:13 -07:00
Steve Gravrock
a63b0b0368 Merge branch '3.99' into 4.0 2021-08-30 18:44:32 -07:00
Steve Gravrock
de9815f436 Merge branch 'main' into 3.99 2021-08-30 18:41:02 -07:00
Steve Gravrock
2fd9d7b13f Merge branch 'main' into 3.99 2021-08-17 17:08:34 -07:00
Steve Gravrock
4e96514634 Deprecated the Promise config setting
4.0 will only support environments that have native promises, so there will
no longer be a need for a user-supplied promise library
2021-08-07 12:04:14 -07:00
Steve Gravrock
d8862aa583 Removed the failFast and oneFailurePerSpec config properties 2021-07-31 09:28:14 -07:00
Steve Gravrock
2480a0a93a Merge branch '3.99' into 4.0 2021-07-31 09:15:12 -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
13dfcacbb0 Remove access to non-public properties of suites and specs returned by describe, it, etc.
[#179064612]
2021-07-30 17:36:50 -07:00
Steve Gravrock
6d002d22af Merge branch '3.99' into 4.0 2021-07-29 21:46:48 -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
09d2ce9bc9 Removed more code that supported browsers we no longer run on 2021-07-27 17:53:09 -07:00
Steve Gravrock
e9bddc7a06 Removed obsolete timing function hacks from boot1.js 2021-07-26 19:04:43 -07:00
Steve Gravrock
310e4d5e6c Removed legacy boot.js file 2021-07-26 18:29:54 -07:00
Steve Gravrock
0424d4ae99 Removed Python support 2021-07-26 18:28:38 -07:00
Steve Gravrock
0720c88252 Merge branch '3.99' into 4.0 2021-07-26 18:20:24 -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
c73df57720 MatchersUtil#contains uses deep equality rather than === for set members
[#169001712]
2021-07-24 14:23:05 -07:00
Steve Gravrock
0170005015 Treat any argument to the done callback as an error
This reduces the risk of incorrectly passing a spec due to not correctly
detecting that an argument is an `Error` instance. Detecting Error instances
in a way that's reliable and portable across different browsers, TrustedTypes,
and frames is difficult.

[Finishes #178267587]
2021-07-24 09:30:39 -07:00
Steve Gravrock
6f04044417 Merge branch '3.99' into 4.0 2021-07-24 09:25:19 -07:00
Steve Gravrock
70d49e5b57 Deprecate non-Error arguments passed to done()
[Finishes #178267600]
2021-07-24 09:18:24 -07:00
Steve Gravrock
ed9363f477 Removed bower.json
Bower itself has been deprecated for four years, so we should drop support
for it in 4.0.

[Finishes #178512921]
2021-07-24 08:23:09 -07:00
Steve Gravrock
fe0a83ba87 Removed support for Internet Explorer 2021-07-23 21:46:15 -07:00
Steve Gravrock
623eecdcec Removed json2.js
Environments that don't provide a JSON parser are ancient history.
2021-07-22 21:37:57 -07:00
Steve Gravrock
a27280e9e7 Merge branch '3.99' into 4.0 2021-07-20 17:55:18 -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
e399953174 Removed obsolete timing function hacks from boot.js 2021-07-17 17:49:53 -07:00
Steve Gravrock
4edac7d3d1 Dropped Safari <13 from test matrix 2021-07-10 09:21:41 -07:00
Steve Gravrock
9b3d4a2bf2 Merge branch '3.99' into 4.0 2021-07-10 09:13:28 -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
a0f6b77c3e Remove access to non-public Suite and Spec members via Env#topSuite 2021-05-29 18:57:56 -07:00
Steve Gravrock
3f3fb38cf1 Merge branch '3.99' into 4.0 2021-05-29 18:42:31 -07:00
Steve Gravrock
00c1e3d608 Deprecate access to non-public Suite and Spec members via Env#topSuite
The deprecation warning relies on Proxy, and won't work in environments
that don't have it. Among Jasmine's supported environments, that's Safari 9,
Safari 8, and all versions of IE.
2021-05-29 15:45:10 -07:00
Steve Gravrock
6a2a30d540 Improved & unified deprecation handling
* De-duplication now happens in core, not in reporters. This ensures that
  the console doesn't get flooded.
* Stack traces are opt-out, not opt-in.
* The current runnable is not reported or logged for certain deprecations
  where it's irrelevant.
* HtmlReporter shows stack traces in expandable widgets.
* Env#deprecated and Env#deprecatedOnceWithStack are merged.
2021-05-29 15:39:28 -07:00
Steve Gravrock
e4e232864d Don't expose Suite objects as this of describe functions
This was a holdover from 1.x that should have been removed in 2.0,
but was missed. Suite is meant to be private, and almost none of
its methods can be safely called by user code.
2021-05-22 09:15:22 -07:00
Steve Gravrock
5acddcda4a Merge branch '3.99' into 4.0 2021-05-22 09:09:03 -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
752441a66f Merge branch '3.99' into 4.0 2021-05-18 17:12:29 -07:00
Steve Gravrock
3e2872a1df Merge branch 'main' into 3.99 2021-05-18 17:07:34 -07:00
Steve Gravrock
1b97795684 Merge branch '3.99' into 4.0 2021-04-23 08:41:12 -07:00
Steve Gravrock
5504965bea Merge branch 'main' into 3.99 2021-04-23 08:40:25 -07:00
Steve Gravrock
c2a714f168 Removed support for IE 10 and Safari 8 2021-04-23 08:14:19 -07:00
Steve Gravrock
c2b558a2da Fail specs that try to combine two forms of async 2021-04-22 22:44:37 -07:00
Steve Gravrock
235efe52f1 Fixed test failure in IE 2021-04-22 22:43:48 -07:00
Steve Gravrock
1e8619df88 Removed deprecated env methods 2021-04-22 22:38:08 -07:00
Steve Gravrock
4b2a14f1f3 Removed deprecated custom matcher, matchersUtil, pp, etc interfaces 2021-04-22 22:29:20 -07:00
Steve Gravrock
66189d742b Merge branch 'no-children' of https://github.com/johnjbarton/jasmine into 4.0
* Merges #1742 from @johnjbarton
2021-04-22 21:35:58 -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
leoni laetitia
3234d475cd expect...toEqual check for Symbols 2021-01-31 22:32:58 +01: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
johnjbarton
2369c8dba7 fix(env): Throw if nested describe has no children.
Users would like an error if it() is acciddently moved within a before/afterEach/All function.
The it() function calls ensureIsNotNested to report such an error. But if the user has no
other it() functions in the Suite, it() and thus ensureIsNotNested() is never called.

Here we check nested Suites for children; if none are found we throw.
2019-08-07 18:01:34 -07:00
287 changed files with 19745 additions and 14225 deletions

View File

@@ -3,25 +3,14 @@
version: 2.1
orbs:
node: circleci/node@3.0.0
executors:
node16:
node20:
docker:
- image: cimg/node:16.1.0-browsers
- image: cimg/node:20.0.0
working_directory: ~/workspace
node14:
node18:
docker:
- image: circleci/node:14
working_directory: ~/workspace
node12:
docker:
- image: circleci/node:12
working_directory: ~/workspace
node10:
docker:
- image: circleci/node:10
- image: cimg/node:18.0.0
working_directory: ~/workspace
jobs:
@@ -58,10 +47,20 @@ jobs:
name: Run tests
command: npm test
test_parallel: &test_parallel
parameters:
executor:
type: executor
executor: << parameters.executor >>
steps:
- attach_workspace:
at: .
- run:
name: Run tests in parallel
command: npx grunt execSpecsInParallel
test_browsers: &test_browsers
executor: node14
environment:
SKIP_JASMINE_BROWSER_FLAKES: "true"
executor: node18
steps:
- attach_workspace:
at: .
@@ -69,10 +68,10 @@ jobs:
name: Install Sauce Connect
command: |
cd /tmp
curl https://saucelabs.com/downloads/sc-4.6.4-linux.tar.gz | tar zxf -
chmod +x sc-4.6.4-linux/bin/sc
curl https://saucelabs.com/downloads/sc-4.7.1-linux.tar.gz | tar zxf -
chmod +x sc-4.7.1-linux/bin/sc
mkdir ~/workspace/bin
cp sc-4.6.4-linux/bin/sc ~/workspace/bin
cp sc-4.7.1-linux/bin/sc ~/workspace/bin
~/workspace/bin/sc --version
- run:
name: Run tests
@@ -81,7 +80,7 @@ jobs:
# cleanly if we kill it from a different step than it started in.
export PATH=$PATH:$HOME/workspace/bin
export SAUCE_TUNNEL_IDENTIFIER=$CIRCLE_BUILD_NUM
export SAUCE_TUNNEL_IDENTIFIER=$CIRCLE_WORKFLOW_JOB_ID
scripts/start-sauce-connect sauce-pidfile
set +o errexit
scripts/run-all-browsers
@@ -90,116 +89,40 @@ jobs:
scripts/stop-sauce-connect $(cat sauce-pidfile)
exit $exitcode
test_browser_flakes:
<<: *test_browsers
environment:
SKIP_JASMINE_BROWSER_FLAKES: "false"
workflows:
version: 2
cron:
triggers:
- schedule:
# Times are UTC.
cron: "0 11 * * *"
filters:
branches:
only:
- main
- "3.99"
- "4.0"
jobs:
- build:
executor: node16
name: build_node_16
- build:
executor: node14
name: build_node_14
- build:
executor: node12
name: build_node_12
- build:
executor: node10
name: build_node_10
- test_node:
executor: node16
name: test_node_16
requires:
- build_node_16
- test_node:
executor: node12
name: test_node_12
requires:
- build_node_12
- test_node:
executor: node10
name: test_node_10
requires:
- build_node_10
- test_browsers:
requires:
- build_node_14
filters:
branches:
ignore: /pull\/.*/ # Don't run on pull requests.
push:
jobs:
- build:
executor: node16
name: build_node_16
executor: node20
name: build_node_20
- build:
executor: node14
name: build_node_14
- build:
executor: node12
name: build_node_12
- build:
executor: node10
name: build_node_10
executor: node18
name: build_node_18
- test_node:
executor: node16
name: test_node_16
executor: node20
name: test_node_20
requires:
- build_node_16
- build_node_20
- test_node:
executor: node14
name: test_node_14
executor: node18
name: test_node_18
requires:
- build_node_14
- test_node:
executor: node12
name: test_node_12
- build_node_18
- test_parallel:
executor: node18
name: test_parallel_node_18
requires:
- build_node_12
- test_node:
executor: node10
name: test_node_10
- build_node_18
- test_parallel:
executor: node20
name: test_parallel_node_20
requires:
- build_node_10
- build_node_20
- test_browsers:
requires:
- build_node_14
- build_node_18
filters:
branches:
ignore: /pull\/.*/ # Don't run on pull requests.
browser-flakes:
triggers:
- schedule:
# Times are UTC.
cron: "0 10 * * *"
filters:
branches:
only:
- browser-flakes
jobs:
- build:
executor: node14
name: build_node_14
- test_browser_flakes:
requires:
- build_node_14
filters:
branches:
ignore: /pull\/.*/ # Don't run on pull requests.

View File

@@ -3,14 +3,6 @@ charset = utf-8
end_of_line = lf
insert_final_newline = true
[*.{js, json, sh, yml, gemspec}]
[*.{js, json, sh, yml}]
indent_style = space
indent_size = 2
[{Rakefile, .jshintrc}]
indent_style = space
indent_size = 2
[*.{py}]
indent_style = space
indent_size = 4

View File

@@ -1,35 +1,25 @@
# Developing for Jasmine Core
# Contributing to Jasmine
We welcome your contributions! Thanks for helping make Jasmine a better project
for everyone. Please review the backlog and discussion lists before starting
work. What you're looking for may already have been done. If it hasn't, the
community can help make your contribution better. If you want to contribute but
don't know what to work on,
[issues tagged help needed](https://github.com/jasmine/jasmine/labels/help%20needed)
for everyone. If you want to contribute but don't know what to work on,
[issues tagged help needed](https://github.com/issues?q=is%3Aopen+is%3Aissue+org%3Ajasmine+label%3A%22help+needed%22+)
should have enough detail to get started.
## Links
## Before Submitting a Pull Request
- [Jasmine Google Group](http://groups.google.com/group/jasmine-js)
- [Jasmine-dev Google Group](http://groups.google.com/group/jasmine-js-dev)
- [Jasmine on PivotalTracker](https://www.pivotaltracker.com/n/projects/10606)
1. Ensure all specs are green in browsers *and* node.
* Use `npm test` to test in Node.
* Use `npm run serve` to test in browsers.
2. Fix any eslint or prettier errors reported at the end of `npm test`. Prettier
errors can be automatically fixed by running `npm run cleanup`.
3. Build `jasmine.js` with `npm run build` and run all specs again. This
ensures that your changes self-test well.
5. Revert your changes to `jasmine.js` and `jasmine-html.js`. When we accept
your pull request, we will generate these files as a separate commit and
merge the entire branch into master.
## General Workflow
Please submit pull requests via feature branches using the semi-standard workflow of:
```bash
git clone git@github.com:yourUserName/jasmine.git # Clone your fork
cd jasmine # Change directory
git remote add upstream https://github.com/jasmine/jasmine.git # Assign original repository to a remote named 'upstream'
git fetch upstream # Fetch changes not present in your local repository
git merge upstream/main # Sync local main with upstream repository
git checkout -b my-new-feature # Create your feature branch
git commit -am 'Add some feature' # Commit your changes
git push origin my-new-feature # Push to the branch
```
Once you've pushed a feature branch to your forked repo, you're ready to open a pull request. We favor pull requests with very small, single commits with a single purpose.
We only accept green pull requests. If you see that the CI build failed, please
fix it. Feel free to ask for help if you're stuck.
## Background
@@ -38,15 +28,16 @@ Once you've pushed a feature branch to your forked repo, you're ready to open a
* `/src` contains all of the source files
* `/src/core` - generic source files
* `/src/html` - browser-specific files
* `/src/boot` - sources for boot files (see below)
* `/spec` contains all of the tests
* mirrors the source directory
* there are some additional files
* `/lib` contains the compiled copy of Jasmine. This is used to self-test and
distributed as the `jasmine-core` Node, Ruby, and Python packages.
distributed as the `jasmine-core` Node, and Ruby packages.
### Self-testing
Note that Jasmine tests itself. The files in `lib` are loaded first, defining the reference `jasmine`. Then the files in `src` are loaded, defining the reference `jasmineUnderTest`. So there are two copies of the code loaded under test.
Jasmine tests itself. The files in `lib` are loaded first, defining the reference `jasmine`. Then the files in `src` are loaded, defining the reference `jasmineUnderTest`. So there are two copies of the code loaded under test.
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.
@@ -60,9 +51,8 @@ is appropriate for browsers, projects may wish to customize this file.
### Compatibility
Jasmine runs in both Node and browsers, including some older browsers that do
not support the latest JavaScript features. See the README for the list of
currently supported environments.
Jasmine runs in both Node and a variety of browsers. See the README for the
list of currently supported environments.
## Development
@@ -88,51 +78,35 @@ Or, How to make a successful pull request
* _Do not change the public interface_. Lots of projects depend on Jasmine and
if you aren't careful you'll break them.
* _Be environment agnostic_ - server-side developers are just as important as
browser developers.
* _Be environment agnostic_. Some people run their specs in browsers, others in
Node. Jasmine should support them all as much as possible.
* _Be browser agnostic_ - if you must rely on browser-specific functionality,
please write it in a way that degrades gracefully.
* _Write specs_ - Jasmine's a testing framework. Don't add functionality
without test-driving it.
* _Write code in the style of the rest of the repo_ - Jasmine should look like
a cohesive whole.
a cohesive whole.
* _Ensure the *entire* test suite is green_ in all the big browsers, Node, and
ESLint. Your contribution shouldn't break Jasmine for other users.
ESLint/Prettier. Your contribution shouldn't break Jasmine for other users.
Follow these tips and your pull request, patch, or suggestion is much more likely to be integrated.
### Running Specs
Be sure to run the tests in at least one supported Node version and at least a
couple of supported browsers. It's also a good idea to run the tests in Internet
Explorer if you've touched code in `src/html`, if your change involves newer
JavaScript language/runtime features, or if you're unfamiliar with writing code
for older browsers. To run the tests in Node, simply use `npm test` as described
above. To run the tests in a browser, run `npm run serve` and then visit
`http://localhost:8888`.
couple of supported browsers. To run the tests in Node, simply use `npm test`
as described above. To run the tests in a browser, run `npm run serve` and then
visit `http://localhost:8888`.
If you have the necessary Selenium drivers installed, you can also use Jasmine's
CI tooling:
If you have the necessary Selenium drivers installed (e.g. geckodriver or
chromedriver), you can also use Jasmine's CI tooling:
$ JASMINE_BROWSER=<name of browser> node spec/support/ci.js
$ JASMINE_BROWSER=<name of browser> npm run ci
The easiest way to run the tests in **Internet Explorer** is to run a VM that has IE installed. It's easy to do this with VirtualBox.
1. Download and install [VirtualBox](https://www.virtualbox.org/wiki/Downloads).
1. Download a VM image [from Microsoft](https://developer.microsoft.com/en-us/microsoft-edge/tools/vms/). Select "VirtualBox" as the platform.
1. Unzip the downloaded archive. There should be an OVA file inside.
1. In VirtualBox, choose `File > Import Appliance` and select the OVA file. Accept the default settings in the dialog that appears. Now you have a Windows VM!
1. Run the VM and start IE.
1. With `npm run serve` running on your host machine, navigate to `http://<your IP address>:8888` in IE.
## Before Committing or Submitting a Pull Request
1. Ensure all specs are green in browser *and* node.
1. Ensure eslint and prettier are clean as part of your `npm test` command. You can run `npm run cleanup` to have prettier re-write the files.
1. Build `jasmine.js` with `npm run build` and run all specs again - this ensures that your changes self-test well.
1. Revert your changes to `jasmine.js` and `jasmine-html.js`
* We do this because `jasmine.js` and `jasmine-html.js` are auto-generated (as you've seen in the previous steps) and accepting multiple pull requests when this auto-generated file changes causes lots of headaches
* When we accept your pull request, we will generate these files as a separate commit and merge the entire branch into main
Note that we use Circle CI for Continuous Integration. We only accept green pull requests.
### Submitting a Pull Requeset
Once you've done the steps listed under "Before Submitting a Pull Request"
above, you can submit a pull request via the
[standard GitHub process](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request).
TL;DR: Fork the repository, push your work up to your fork, and create a PR from
there.

View File

@@ -1,47 +0,0 @@
## Are you creating an issue in the correct repository?
- When in doubt, create an issue here.
- If you have an issue with the Jasmine docs, file an issue in the docs repo
here: https://github.com/jasmine/jasmine.github.io
- If you have an issue with TypeScript typings, start a discussion at
[DefinitelyTpyed](https://github.com/DefinitelyTyped/DefinitelyTyped/discussions/new?category=issues-with-a-types-package)
- This repository is for the core Jasmine framework
- If you are using a test runner that wraps Jasmine, consider filing an issue with that library if appropriate:
- [Jasmine npm](https://github.com/jasmine/jasmine-npm/issues)
- [Jasmine browser runner](https://github.com/jasmine/jasmine-browser/issues)
- [Jasmine gem](https://github.com/jasmine/jasmine-gem/issues)
- [Jasmine py](https://github.com/jasmine/jasmine-py/issues)
- [Gulp Jasmine Browser](https://github.com/jasmine/gulp-jasmine-browser/issues)
- [Karma](https://github.com/karma-runner/karma/issues)
- [Grunt Contrib Jasmine](https://github.com/gruntjs/grunt-contrib-jasmine/issues)
<!--- Provide a general summary of the issue in the Title above -->
## Expected Behavior
<!--- If you're describing a bug, tell us what should happen -->
<!--- If you're suggesting a change/improvement, tell us how it should work -->
## Current Behavior
<!--- If describing a bug, tell us what happens instead of the expected behavior -->
<!--- If suggesting a change/improvement, explain the difference from current behavior -->
## Possible Solution
<!--- Not obligatory, but suggest a fix/reason for the bug, -->
<!--- or ideas how to implement the addition or change -->
## Suite that reproduces the behavior (for bugs)
<!--- Provide a sample suite that reproduces the bug. -->
```javascript
describe("sample", function() {
});
```
## Context
<!--- How has this issue affected you? What are you trying to accomplish? -->
<!--- Providing context helps us come up with a solution that is most useful in the real world -->
## Your Environment
<!--- Include as many relevant details about the environment you experienced the bug in -->
* Version used:
* Environment name and version (e.g. Chrome 39, node.js 5.4):
* Operating System and version (desktop or mobile):
* Link to your project:

98
.github/ISSUE_TEMPLATE/bug_report.yml vendored Normal file
View File

@@ -0,0 +1,98 @@
name: Bug Report
description: I think I've found a bug in Jasmine
labels: ["bug report"]
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to report a bug. Please follow these steps first.
## Troubleshooting
Please take the time to rule out issues with your code or third party libraries before filing a bug report. If you are reporting an error, try to determine whether the error is coming from Jasmine, another library, or your own code.
Check the [FAQ](https://jasmine.github.io/pages/faq.html) and any other relevant [documentation](https://jasmine.github.io/pages/docs_home.html) to see if your issue has already been addressed.
## Special troubleshooting steps for asynchronous scenarios
If the issue has to do with testing asynchronous code, please read the [async tutorial](https://jasmine.github.io/tutorials/async) and the async section of the FAQ. In particular, check for the following common errors:
* Are you trying to write a synchronous test for asynchronous code?
* Does the test signal completion before the code under test finishes?
* Do expectations run before the code that they're trying to verify?
## Try the latest version of Jasmine
If at all possible, upgrade to the latest versions of `jasmine-core` and any other relevant packages (e.g. `jasmine`, `jasmine-browser-runner`). If you can't do that, please check the [release notes](https://github.com/jasmine/jasmine/tree/main/release_notes) for all newer versions to make sure that the bug hasn't already been fixed.
## Put together a [minimal, reproducible example](https://stackoverflow.com/help/minimal-reproducible-example)
Please help us help you by creating a minimal but complete setup that demonstrates the problem. Remove any code and libraries that aren't absolutely necessary, but make sure it doesn't depend on any code you haven't included. In many cases a simple code snippet is enough. In cases involving external libraries, *especially* Karma or Angular, we're likely to need a runable Git repository or jsbin/stackblitz/etc.
**If we can't reproduce it, we can't fix it. Bug reports without a minimal, reproducible example are very likely to be closed.**
- type: textarea
id: steps-to-reproduce
attributes:
label: Steps to Reproduce
placeholder: |
Example steps:
1. Paste the example code below into `mySpec.js`.
2. Run `npx jasmine@<some version> mySpec.js`
validations:
required: true
- type: textarea
id: expected-behavior
attributes:
label: Expected Behavior
description: What do you think should have happened?
validations:
required: true
- type: textarea
id: actual-behavior
attributes:
label: Actual Behavior
description: What happened instead?
validations:
required: true
- type: textarea
id: code-sample
attributes:
label: Example code that reproduces the problem
description: Please include either a code snippet that reproduces the problem or a link to a repository or jsbin/stackblitz/etc containing a minimal, reproducible example as described above.
render: JavaScript
validations:
required: true
- type: textarea
id: possible-solution
attributes:
label: Possible Solution
description: This is optional, but if you have an idea for how to fix the bug we'd like to hear it.
- type: textarea
id: context
attributes:
label: Context
description: How has this issue affected you? What are you trying to accomplish? By providing context, you can help us come up with a solution that is most useful in the real world.
- type: input
id: jasmine-core-version
attributes:
label: jasmine-core version
validations:
required: true
- type: textarea
id: other-versions
attributes:
label: Versions of other relevant packages
placeholder: |
jasmine-browser-runner 1.2.0
fancy-reporter 132.4.8
- type: input
id: browser-or-node-version
attributes:
label: Node.js or browser version
placeholder: E.g. "node 16.2.0" or "Safari 15"
validations:
required: true
- type: input
id: os
attributes:
label: Operating System
placeholder: E.g. "Windows 10", "MacOS 12.5", "MCC Interim Linux 0.99.p8"
validations:
required: true

14
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@@ -0,0 +1,14 @@
blank_issues_enabled: false
contact_links:
- name: Issues with the `jasmine` CLI
url: https://github.com/jasmine/jasmine-npm/issues
about: Please create issues related to the `jasmine` package in its repository.
- name: Issues with jasmine-browser-runner
url: https://github.com/jasmine/jasmine-browser-runner/issues
about: Please create issues related to the `jasmine-browser-runner` package in its repository.
- name: Documentation issues
url: https://github.com/jasmine/jasmine.github.io/issues
about: Please create documentation issues in the docs repository.
- name: TypeScript issues
url: https://github.com/DefinitelyTyped/DefinitelyTyped/discussions
about: Please create issues related to TypeScript compilation errors or other problems with type definitions at DefinitelyTyped.

View File

@@ -0,0 +1,31 @@
name: Feature Proposal
description: I'd like to propose a new feature
labels: ["feature request"]
body:
- type: markdown
attributes:
value: Thanks for taking the time to propose a new feature. Although Jasmine is mostly feature complete, we're always open to hearing new ideas.
- type: textarea
id: description
attributes:
label: Feature Proposal
validations:
required: true
- type: textarea
id: context
attributes:
label: Context
description: How would this feature be useful to you? What are you trying to accomplish? By providing context, you can help us come up with a solution that is most useful in the real world.
validations:
required: true
- type: textarea
id: example
attributes:
label: Example
description: If you're proposing a new API or something similar, please show an example of how it would be used.
render: JavaScript
- type: textarea
id: other-info
attributes:
label: Other Information
description: Anything else that you think would be helpful.

View File

@@ -0,0 +1,73 @@
name: Question or Support Request
description: I need help using Jasmine
labels: ["question"]
body:
- type: markdown
attributes:
value: |
Jasmine is supported by volunteers working in their free time. Although we're generally willing to help, we're going to ask you to put in some effort first to help us help you.
## Troubleshooting
Please take the time to rule out problems with your code or third party libraries before opening an issue. If you're running into an error, try to determine whether the error is coming from Jasmine, another library, or your own code.
Check the [FAQ](https://jasmine.github.io/pages/faq.html) and any other relevant [documentation](https://jasmine.github.io/pages/docs_home.html) to see if your question has already been answered. Consider searching [Stack Overflow](https://stackoverflow.com/questions/tagged/jasmine) and past issues in this repository for related questions as well.
## Special troubleshooting steps for asynchronous scenarios
If the issue has to do with testing asynchronous code, please read the [async tutorial](https://jasmine.github.io/tutorials/async) and the async section of the FAQ. In particular, check for the following common errors:
* Are you trying to write a synchronous test for asynchronous code?
* Does the test signal completion before the code under test finishes?
* Do expectations run before the code that they're trying to verify?
## Consider asking Angular questions in an Angular forum
Questions like "how do I test this Angular service" are mostly about Angular, not Jasmine. You'll likely get better responses in an Angular forum. Here's a rule of thumb: If you can't demonstrate the problem without Angular, you probably have an Angular question.
## Try the latest version of Jasmine
If at all possible, upgrade to the latest versions of `jasmine-core` and any other relevant packages (e.g. `jasmine`, `jasmine-browser-runner`).
## Put together a [minimal, reproducible example](https://stackoverflow.com/help/minimal-reproducible-example)
Please help us help you by creating a minimal but complete setup that demonstrates the problem. Remove any code and libraries that aren't absolutely necessary, but make sure it doesn't depend on any code you haven't included. In many cases a simple code snippet is enough. In cases involving external libraries, *especially* Karma or Angular, we're likely to need a runable Git repository or jsbin/stackblitz/etc.
- type: textarea
id: question
attributes:
label: Your question
description: Clearly describe what you'd like help with.
validations:
required: true
- type: textarea
id: code-sample
attributes:
label: Example code that demonstrates the problem
description: Please include either a code snippet that demonstrates the problem or a link to a repository or jsbin/stackblitz/etc containing a minimal, reproducible example as described above.
render: JavaScript
validations:
required: true
- type: input
id: jasmine-core-version
attributes:
label: jasmine-core version
validations:
required: true
- type: textarea
id: other-versions
attributes:
label: Versions of other relevant packages
placeholder: |
jasmine-browser-runner 1.2.0
fancy-reporter 132.4.8
- type: input
id: browser-or-node-version
attributes:
label: Node.js or browser version
placeholder: E.g. "node 16.2.0" or "Safari 15"
validations:
required: true
- type: input
id: os
attributes:
label: Operating System
placeholder: E.g. "Windows 10", "MacOS 12.5", "MCC Interim Linux 0.99.p8"
validations:
required: true

View File

@@ -24,7 +24,7 @@
- [ ] My code follows the code style of this project.
- [ ] My change requires a change to the documentation.
- [ ] I have updated the documentation accordingly.
- [ ] I have read the **CONTRIBUTING** document.
- [ ] I have read the [**CONTRIBUTING**](https://github.com/jasmine/jasmine/blob/main/.github/CONTRIBUTING.md) guide.
- [ ] I have added tests to cover my changes.
- [ ] All new and existing tests passed.

2
.gitignore vendored
View File

@@ -17,11 +17,9 @@ pkg/*
.sass-cache/*
src/html/.sass-cache/*
node_modules/
*.pyc
sauce_connect.log
*.swp
build/
*.egg-info/
dist
nbproject/
*.iml

1
.rspec
View File

@@ -1 +0,0 @@
--color

View File

@@ -1,2 +0,0 @@
source 'https://rubygems.org'
gemspec

View File

@@ -16,12 +16,6 @@ module.exports = function(grunt) {
grunt.registerTask('default', ['sass:dist', "cssUrlEmbed"]);
var version = require('./grunt/tasks/version.js');
grunt.registerTask('build:copyVersionToGem',
"Propagates the version from package.json to version.rb",
version.copyToGem);
grunt.registerTask('buildDistribution',
'Builds and lints jasmine.js, jasmine-html.js, jasmine.css',
[
@@ -34,17 +28,59 @@ module.exports = function(grunt) {
grunt.registerTask("execSpecsInNode",
"Run Jasmine core specs in Node.js",
function() {
var done = this.async(),
Jasmine = require('jasmine'),
jasmineCore = require('./lib/jasmine-core.js'),
jasmine = new Jasmine({jasmineCore: jasmineCore});
verifyNoGlobals(() => require('./lib/jasmine-core.js').noGlobals());
const done = this.async(),
Jasmine = require('jasmine'),
jasmineCore = require('./lib/jasmine-core.js'),
jasmine = new Jasmine({jasmineCore: jasmineCore});
jasmine.loadConfigFile('./spec/support/jasmine.json');
jasmine.onComplete(function(passed) {
done(passed);
jasmine.exitOnCompletion = false;
jasmine.execute().then(
result => done(result.overallStatus === 'passed'),
err => {
console.error(err);
done(false);
}
);
}
);
grunt.registerTask("execSpecsInParallel",
"Run Jasmine core specs in parallel in Node.js",
function() {
// Need to require this here rather than at the top of the file
// so that we don't break verifyNoGlobals above by loading jasmine-core
// too early
const ParallelRunner = require('jasmine/parallel');
let numWorkers = require('os').cpus().length;
if (process.env['CIRCLECI']) {
// On Circle CI, the above gives the number of CPU cores on the host
// computer, which is unrelated to the resources actually available
// to the container. 2 workers gives peak performance with our current
// configuration, but 4 might increase the odds of discovering any
// parallel-specific bugs.
numWorkers = 4;
}
const done = this.async();
const runner = new ParallelRunner({
jasmineCore: require('./lib/jasmine-core.js'),
numWorkers
});
jasmine.execute();
runner.loadConfigFile('./spec/support/jasmine.json')
.then(() => {
runner.exitOnCompletion = false;
return runner.execute();
}).then(
jasmineDoneInfo => done(jasmineDoneInfo.overallStatus === 'passed'),
err => {
console.error(err);
done(false);
}
);
}
);
@@ -55,3 +91,14 @@ module.exports = function(grunt) {
}
);
};
function verifyNoGlobals(fn) {
const initialGlobals = Object.keys(global);
fn();
const extras = Object.keys(global).filter(k => !initialGlobals.includes(k));
if (extras.length !== 0) {
throw new Error('Globals were unexpectedly created: ' + extras.join(', '));
}
}

View File

@@ -1,6 +0,0 @@
recursive-include . *.py
prune node_modules
include lib/jasmine-core/*.js
include lib/jasmine-core/*.css
include images/*.png
include package.json

View File

@@ -2,14 +2,12 @@
[![Build Status](https://circleci.com/gh/jasmine/jasmine.svg?style=shield)](https://circleci.com/gh/jasmine/jasmine)
[![Open Source Helpers](https://www.codetriage.com/jasmine/jasmine/badges/users.svg)](https://www.codetriage.com/jasmine/jasmine)
[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fjasmine%2Fjasmine.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Fjasmine%2Fjasmine?ref=badge_shield)
# A JavaScript Testing Framework
Jasmine is a Behavior Driven Development testing framework for JavaScript. It does not rely on browsers, DOM, or any JavaScript framework. Thus it's suited for websites, [Node.js](http://nodejs.org) projects, or anywhere that JavaScript can run.
Documentation & guides live here: [http://jasmine.github.io](http://jasmine.github.io/)
For a quick start guide of Jasmine, see the beginning of [http://jasmine.github.io/edge/introduction.html](http://jasmine.github.io/edge/introduction.html).
Upgrading from Jasmine 3.x? Check out the [upgrade guide](https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0).
## Contributing
@@ -17,73 +15,47 @@ Please read the [contributors' guide](https://github.com/jasmine/jasmine/blob/ma
## Installation
For the Jasmine NPM module:<br>
[https://github.com/jasmine/jasmine-npm](https://github.com/jasmine/jasmine-npm).
There are several different ways to install Jasmine, depending on your
environment and how you'd like to use it. See the [Getting Started page](https://jasmine.github.io/pages/getting_started.html)
for details.
For the Jasmine browser runner:<br>
[https://github.com/jasmine/jasmine-browser](https://github.com/jasmine/jasmine-browser).
## Usage
For the Jasmine Ruby Gem:<br>
[https://github.com/jasmine/jasmine-gem](https://github.com/jasmine/jasmine-gem).
To install Jasmine standalone on your local box (where **_{#.#.#}_** below is substituted by the release number downloaded):
* Download the standalone distribution for your desired release from the [releases page](https://github.com/jasmine/jasmine/releases).
* Create a Jasmine directory in your project. - `mkdir my-project/jasmine`
* Move the dist to your project directory. - `mv jasmine/dist/jasmine-standalone-{#.#.#}.zip my-project/jasmine`
* Change directory. - `cd my-project/jasmine`
* Unzip the dist. - `unzip jasmine-standalone-{#.#.#}.zip`
Add the following to your HTML file:
```html
<link rel="shortcut icon" type="image/png" href="lib/jasmine-{#.#.#}/jasmine_favicon.png">
<link rel="stylesheet" type="text/css" href="lib/jasmine-{#.#.#}/jasmine.css">
<script type="text/javascript" src="lib/jasmine-{#.#.#}/jasmine.js"></script>
<script type="text/javascript" src="lib/jasmine-{#.#.#}/jasmine-html.js"></script>
<script type="text/javascript" src="lib/jasmine-{#.#.#}/boot.js"></script>
```
See the [documentation site](https://jasmine.github.io/pages/docs_home.html),
particularly the [Your First Suite tutorial](https://jasmine.github.io/tutorials/your_first_suite)
for information on writing specs, and [the FAQ](https://jasmine.github.io/pages/faq.html).
## Supported environments
Jasmine tests itself across many browsers (Safari, Chrome, Firefox, Microsoft Edge, and Internet Explorer) as well as nodejs.
Jasmine tests itself across popular browsers (Safari, Chrome, Firefox, and
Microsoft Edge) as well as Node.
| Environment | Supported versions |
|-------------------|--------------------|
| Node | 10, 12, 14, 16 |
| Safari | 8-14 |
| Chrome | Evergreen |
| Firefox | Evergreen, 68, 78 |
| Edge | Evergreen |
| Internet Explorer | 10, 11 |
| Environment | Supported versions |
|-------------------|---------------------|
| Node | 18, 20 |
| Safari | 15-16 |
| Chrome | Evergreen |
| Firefox | Evergreen, 102 |
| Edge | Evergreen |
For evergreen browsers, each version of Jasmine is tested against the version of the browser that is available to us
at the time of release. Other browsers, as well as older & newer versions of some supported browsers, are likely to work.
However, Jasmine isn't tested against them and they aren't actively supported.
## Support
* Search past discussions: [http://groups.google.com/group/jasmine-js](http://groups.google.com/group/jasmine-js).
* Send an email to the list: [jasmine-js@googlegroups.com](mailto:jasmine-js@googlegroups.com).
* View the project backlog at Pivotal Tracker: [http://www.pivotaltracker.com/projects/10606](http://www.pivotaltracker.com/projects/10606).
* Follow us on Twitter: [@JasmineBDD](http://twitter.com/JasmineBDD).
To find out what environments work with a particular Jasmine release, see the [release notes](https://github.com/jasmine/jasmine/tree/main/release_notes).
## Maintainers
* [Gregg Van Hove](mailto:gvanhove@pivotal.io), Pivotal Labs
* [Gwendolyn Van Hove](mailto:gwen@slackersoft.net)
* [Steve Gravrock](mailto:sdg@panix.com)
### Maintainers Emeritus
* [Davis W. Frank](mailto:dwfrank@pivotal.io), Pivotal Labs
* [Rajan Agaskar](mailto:rajan@pivotal.io), Pivotal Labs
* [Greg Cobb](mailto:gcobb@pivotal.io), Pivotal Labs
* [Chris Amavisca](mailto:camavisca@pivotal.io), Pivotal Labs
* [Christian Williams](mailto:antixian666@gmail.com), Cloud Foundry
* [Davis W. Frank](mailto:dwfrank@pivotal.io)
* [Rajan Agaskar](mailto:rajan@pivotal.io)
* [Greg Cobb](mailto:gcobb@pivotal.io)
* [Chris Amavisca](mailto:camavisca@pivotal.io)
* [Christian Williams](mailto:antixian666@gmail.com)
* Sheel Choksi
Copyright (c) 2008-2018 Pivotal Labs. This software is licensed under the MIT License.
## License
[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fjasmine%2Fjasmine.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2Fjasmine%2Fjasmine?ref=badge_large)
Copyright (c) 2008-2022 Jasmine Maintainers. This software is licensed under the [MIT License](https://github.com/jasmine/jasmine/blob/main/MIT.LICENSE).

View File

@@ -13,16 +13,16 @@ Please attempt to keep commits to `main` small, but cohesive. If a feature is co
We attempt to stick to [Semantic Versioning](http://semver.org/). Most of the time, development should be against a new minor version - fixing bugs and adding new features that are backwards compatible.
The current version lives in the file `/package.json`. This version will be the version number that is currently released. When releasing a new version, update `package.json` with the new version and `grunt build:copyVersionToGem` to update the gem version number.
The current version lives in the file `/package.json`. This version will be
copied to `jasmine.js` when the distribution is built. When releasing a new
version, update `package.json` with the new version and `npm run build` to
update the gem version number.
This version is used by both `jasmine.js` and the `jasmine-core` Ruby gem.
Note that Jasmine should only use the "patch" version number if the new release
contains only bug fixes.
Note that Jasmine should only use the "patch" version number in the following cases:
* Changes related to packaging for a specific platform (npm, gem, or pip).
* Fixes for regressions.
When jasmine-core revs its major or minor version, the binding libraries should also rev to that version.
When `jasmine-core` revs its major or minor version, the `jasmine` NPM package
should also rev to that version.
## Release
@@ -31,71 +31,42 @@ When ready to release - specs are all green and the stories are done:
1. Update the release notes in `release_notes` - use the Anchorman gem to generate the markdown file and edit accordingly. Include a list of supported environments.
1. Update the version in `package.json`
1. Run `npm run build`.
1. Copy version to the Ruby gem with `grunt build:copyVersionToGem`
### Commit and push core changes
1. Run the browser tests using `scripts/run-all-browsers`.
1. Commit release notes and version changes (jasmine.js, version.rb, package.json)
1. Push
1. Wait for Circle CI to go green
1. Commit release notes and version changes (jasmine.js, package.json)
2. Push
3. Tag the release and push the tag.
4. Wait for Circle CI to go green
### Build standalone distribution
1. Build the standalone distribution with `grunt buildStandaloneDist`
1. This will generate `dist/jasmine-standalone-<version>.zip`, which you will upload later (see "Finally" below).
### Release the core Ruby gem
1. __NOTE__: You will likely need to push a new jasmine gem with a dependent version right after this release. See below.
1. `rake release` - tags the repo with the version, builds the `jasmine-core` gem, pushes the gem to Rubygems.org. In order to release you will have to ensure you have rubygems creds locally.
### Release the core Python egg
Install [twine](https://github.com/pypa/twine)
1. `python setup.py sdist`
1. `twine upload dist/jasmine-core-<version>.tar.gz` You will need pypi credentials to upload the egg.
### Release the core NPM module
1. Run the tests on Windows. (CI only tests on Linux.)
1. `npm adduser` to save your credentials locally
1. `npm publish .` to publish what's in `package.json`
### Release the docs
Probably only need to do this when releasing a minor version, and not a patch version.
Probably only need to do this when releasing a minor version, and not a patch
version. See [the README file in the docs repo](https://github.com/jasmine/jasmine.github.io/blob/master/README.md)
for instructions.
1. `rake update_edge_jasmine`
1. `npm run jsdoc`
1. `rake release[${version}]` to copy the current edge docs to the new version
1. Commit and push.
### Release the binding libraries
### Release the `jasmine` NPM package
#### NPM
See <https://github.com/jasmine/jasmine-npm/blob/main/RELEASE.md>.
1. Create release notes using Anchorman as above
1. In `package.json`, update both the package version and the jasmine-core dependency version
1. Commit and push.
1. Wait for Circle CI to go green again.
1. Run the tests on Windows locally.
1. `grunt release `. (Note: This will publish the package by running `npm publish`.)
### Publish the GitHub release
#### Gem
1. Create release notes using Anchorman as above
1. Update the version number in `lib/jasmine/version.rb`.
1. Update the jasmine-core dependency version in `jasmine.gemspec`.
1. Commit and push.
1. Wait for Circle CI to go green again.
1. `rake release`
### Finally
For each of the above GitHub repos:
1. Visit the releases page and find the tag just published.
1. Paste in a link to the correct release notes for this release. The link should reference the blob and tag correctly, and the markdown file for the notes.
1. If it is a pre-release, mark it as such.
1. For core, attach the standalone zipfile.
2. Paste in a link to the correct release notes for this release.
3. If it is a pre-release, mark it as such.
4. Attach the standalone zipfile.

View File

@@ -1,2 +0,0 @@
require "bundler"
Bundler::GemHelper.install_tasks

View File

@@ -1,40 +0,0 @@
{
"name": "jasmine-core",
"homepage": "https://jasmine.github.io",
"authors": [
"slackersoft <gregg@slackersoft.net>"
],
"description": "Official packaging of Jasmine's core files",
"keywords": [
"test",
"jasmine",
"tdd",
"bdd"
],
"license": "MIT",
"moduleType": "globals",
"main": "lib/jasmine-core/jasmine.js",
"ignore": [
"**/.*",
"dist",
"grunt",
"node_modules",
"pkg",
"release_notes",
"spec",
"src",
"Gemfile",
"Gemfile.lock",
"Rakefile",
"jasmine-core.gemspec",
"*.sh",
"*.py",
"Gruntfile.js",
"lib/jasmine-core.rb",
"lib/jasmine-core/boot/",
"lib/jasmine-core/spec",
"lib/jasmine-core/version.rb",
"lib/jasmine-core/*.py",
"sauce_connect.log"
]
}

View File

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

View File

@@ -37,22 +37,14 @@ module.exports = {
],
dest: 'lib/jasmine-core/jasmine.js'
},
boot: {
src: ['lib/jasmine-core/boot/boot.js'],
dest: 'lib/jasmine-core/boot.js'
},
boot0: {
src: ['lib/jasmine-core/boot/boot0.js'],
src: ['src/boot/boot0.js'],
dest: 'lib/jasmine-core/boot0.js'
},
boot1: {
src: ['lib/jasmine-core/boot/boot1.js'],
src: ['src/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'
},
options: {
banner: license(),
process: {

View File

@@ -1,14 +0,0 @@
var grunt = require("grunt");
function gemLib(path) { return './lib/jasmine-core/' + path; }
function nodeToRuby(version) { return version.replace('-', '.'); }
module.exports = {
copyToGem: function() {
var versionRb = grunt.template.process(
grunt.file.read("grunt/templates/version.rb.jst"),
{ data: { jasmineVersion: nodeToRuby(global.jasmineVersion) }});
grunt.file.write(gemLib("version.rb"), versionRb);
}
};

View File

@@ -1,9 +0,0 @@
#
# DO NOT Edit this file. Canonical version of Jasmine lives in the repo's package.json. This file is generated
# by a grunt task when the standalone release is built.
#
module Jasmine
module Core
VERSION = "<%= jasmineVersion %>"
end
end

View File

View File

@@ -1,30 +0,0 @@
# -*- encoding: utf-8 -*-
$:.push File.expand_path("../lib", __FILE__)
require "jasmine-core/version"
Gem::Specification.new do |s|
s.name = "jasmine-core"
s.version = Jasmine::Core::VERSION
s.platform = Gem::Platform::RUBY
s.authors = ["Gregg Van Hove"]
s.summary = %q{JavaScript BDD framework}
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"
s.files = Dir.glob("./lib/**/*")
s.require_paths = ["lib"]
s.add_development_dependency "rake"
end

View File

@@ -1,16 +1,66 @@
module.exports = require("./jasmine-core/jasmine.js");
module.exports.boot = require('./jasmine-core/node_boot.js');
/**
* Note: Only available on Node.
* @module jasmine-core
*/
var path = require('path'),
fs = require('fs');
const jasmineRequire = require('./jasmine-core/jasmine.js');
module.exports = jasmineRequire;
var rootPath = path.join(__dirname, "jasmine-core"),
bootFiles = ['boot0.js', 'boot1.js'],
legacyBootFiles = ['boot.js'],
nodeBootFiles = ['node_boot.js'],
cssFiles = [],
jsFiles = [],
jsFilesToSkip = ['jasmine.js'].concat(bootFiles, legacyBootFiles, nodeBootFiles);
const boot = (function() {
let jasmine, jasmineInterface;
return function bootWithoutGlobals(reinitialize) {
if (!jasmineInterface || reinitialize === true) {
jasmine = jasmineRequire.core(jasmineRequire);
const env = jasmine.getEnv({ suppressLoadErrors: true });
jasmineInterface = jasmineRequire.interface(jasmine, env);
}
return {jasmine, jasmineInterface};
};
}());
/**
* Boots a copy of Jasmine and returns an object as described in {@link jasmine}.
* If boot is called multiple times, the same object is returned every time
* unless true is passed.
* @param {boolean} [reinitialize=false] Whether to create a new copy of Jasmine if one already exists
* @type {function}
* @return {jasmine}
*/
module.exports.boot = function(reinitialize) {
const {jasmine, jasmineInterface} = boot(reinitialize);
for (const k in jasmineInterface) {
global[k] = jasmineInterface[k];
}
return jasmine;
};
/**
* Boots a copy of Jasmine and returns an object containing the properties
* that would normally be added to the global object. If noGlobals is called
* multiple times, the same object is returned every time unless true is passed.
*
* @param {boolean} [reinitialize=false] Whether to create a new copy of Jasmine if one already exists
* @example
* const {describe, beforeEach, it, expect, jasmine} = require('jasmine-core').noGlobals();
*/
module.exports.noGlobals = function(reinitialize) {
const {jasmineInterface} = boot(reinitialize);
return jasmineInterface;
};
const path = require('path'),
fs = require('fs');
const rootPath = path.join(__dirname, 'jasmine-core'),
bootFiles = ['boot0.js', 'boot1.js'],
legacyBootFiles = ['boot.js'],
cssFiles = [],
jsFiles = [],
jsFilesToSkip = ['jasmine.js'].concat(bootFiles, legacyBootFiles);
fs.readdirSync(rootPath).forEach(function(file) {
if(fs.statSync(path.join(rootPath, file)).isFile()) {
@@ -20,18 +70,18 @@ fs.readdirSync(rootPath).forEach(function(file) {
break;
case '.js':
if (jsFilesToSkip.indexOf(file) < 0) {
jsFiles.push(file);
}
jsFiles.push(file);
}
break;
}
}
});
module.exports.files = {
self: __filename,
path: rootPath,
bootDir: rootPath,
bootFiles: bootFiles,
nodeBootFiles: nodeBootFiles,
cssFiles: cssFiles,
jsFiles: ['jasmine.js'].concat(jsFiles),
imagesDir: path.join(__dirname, '../images')

View File

@@ -1,78 +0,0 @@
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
def path
File.join(File.dirname(__FILE__), "jasmine-core")
end
def js_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"]
def core_spec_files
spec_files("core")
end
def html_spec_files
spec_files("html")
end
def node_spec_files
spec_files("node")
end
def boot_files
["boot.js"]
end
def node_boot_files
["node_boot.js"]
end
def boot_dir
path
end
def spec_files(type)
raise ArgumentError.new("Unrecognized spec type") unless SPEC_TYPES.include?(type)
(Dir.glob(File.join(path, "spec", type, "*.js"))).map { |f| File.join("spec", type, File.basename(f)) }.uniq
end
def css_files
Dir.glob(File.join(path, "*.css")).map { |f| File.basename(f) }
end
def images_dir
File.join(File.dirname(__FILE__), '../images')
end
end
end
end

View File

@@ -1 +0,0 @@
from .core import Core

View File

@@ -1,165 +0,0 @@
/*
Copyright (c) 2008-2021 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.
*/
/**
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.
The location of `boot.js` can be specified and/or overridden in `jasmine.yml`.
[jasmine-gem]: http://github.com/pivotal/jasmine-gem
*/
(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`.
*/
extend(global, jasmineInterface);
/**
* ## 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 = {
failFast: queryString.getParam("failFast"),
oneFailurePerSpec: 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(jasmineInterface.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

@@ -1,143 +0,0 @@
/**
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.
The location of `boot.js` can be specified and/or overridden in `jasmine.yml`.
[jasmine-gem]: http://github.com/pivotal/jasmine-gem
*/
(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`.
*/
extend(global, jasmineInterface);
/**
* ## 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 = {
failFast: queryString.getParam("failFast"),
oneFailurePerSpec: 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(jasmineInterface.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

@@ -1,16 +0,0 @@
module.exports = function(jasmineRequire) {
var jasmine = jasmineRequire.core(jasmineRequire);
var env = jasmine.getEnv({suppressLoadErrors: true});
var jasmineInterface = jasmineRequire.interface(jasmine, env);
extend(global, jasmineInterface);
function extend(destination, source) {
for (var property in source) destination[property] = source[property];
return destination;
}
return jasmine;
};

View File

@@ -1,5 +1,5 @@
/*
Copyright (c) 2008-2021 Pivotal Labs
Copyright (c) 2008-2023 Pivotal Labs
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@@ -27,14 +27,14 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
source files or spec files are loaded.
*/
(function() {
var jasmineRequire = window.jasmineRequire || require('./jasmine.js');
const 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),
const jasmine = jasmineRequire.core(jasmineRequire),
global = jasmine.getGlobal();
global.jasmine = jasmine;
@@ -46,19 +46,19 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
/**
* Create the Jasmine environment. This is used to run all specs in a project.
*/
var env = jasmine.getEnv();
const 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);
const 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) {
for (const property in jasmineInterface) {
global[property] = jasmineInterface[property];
}
}());
})();

View File

@@ -1,5 +1,5 @@
/*
Copyright (c) 2008-2021 Pivotal Labs
Copyright (c) 2008-2023 Pivotal Labs
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@@ -21,7 +21,7 @@ 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
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
@@ -34,7 +34,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
(function() {
var env = jasmine.getEnv();
const env = jasmine.getEnv();
/**
* ## Runner Parameters
@@ -42,25 +42,29 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
* 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; }
const queryString = new jasmine.QueryString({
getWindowLocation: function() {
return window.location;
}
});
var filterSpecs = !!queryString.getParam("spec");
const filterSpecs = !!queryString.getParam('spec');
var config = {
failFast: queryString.getParam("failFast"),
oneFailurePerSpec: queryString.getParam("oneFailurePerSpec"),
hideDisabled: queryString.getParam("hideDisabled")
const config = {
stopOnSpecFailure: queryString.getParam('stopOnSpecFailure'),
stopSpecOnExpectationFailure: queryString.getParam(
'stopSpecOnExpectationFailure'
),
hideDisabled: queryString.getParam('hideDisabled')
};
var random = queryString.getParam("random");
const random = queryString.getParam('random');
if (random !== undefined && random !== "") {
if (random !== undefined && random !== '') {
config.random = random;
}
var seed = queryString.getParam("seed");
const seed = queryString.getParam('seed');
if (seed) {
config.seed = seed;
}
@@ -69,13 +73,23 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
* ## 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({
const 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); },
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
});
@@ -89,8 +103,10 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
/**
* 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"); }
const specFilter = new jasmine.HtmlSpecFilter({
filterString: function() {
return queryString.getParam('spec');
}
});
config.specFilter = function(spec) {
@@ -99,20 +115,12 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
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;
const currentWindowOnload = window.onload;
window.onload = function() {
if (currentWindowOnload) {
@@ -121,13 +129,4 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
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

@@ -1,94 +0,0 @@
import pkg_resources
import os
if 'SUPPRESS_JASMINE_DEPRECATION' not in os.environ:
print('DEPRECATION WARNING:\n' +
'\n' +
'The Jasmine packages for Python are deprecated. There will be no further\n' +
'releases after the end of the Jasmine 3.x series. We recommend migrating to the\n' +
'following options:\n' +
'\n' +
'* jasmine-browser-runner (<https://github.com/jasmine/jasmine-browser>,\n' +
' `npm install jasmine-browser-runner`) to run specs in browsers, including\n' +
' headless Chrome and Saucelabs. This is the most direct replacement for the\n' +
' jasmine server` and `jasmine ci` commands provided by the `jasmine` Python\n' +
' package.\n' +
'* The jasmine npm package (<https://github.com/jasmine/jasmine-npm>,\n' +
' `npm install jasmine`) to run specs under Node.js.\n' +
'* The standalone distribution from the latest Jasmine release\n' +
' <https://github.com/jasmine/jasmine/releases> to run specs in browsers with\n' +
' no additional tools.\n' +
'* The jasmine-core npm package (`npm install jasmine-core`) if all you need is\n' +
' the Jasmine assets. This is the direct equivalent of the jasmine-core Python\n' +
' package.\n' +
'\n' +
'Except for the standalone distribution, all of the above are distributed through\n' +
'npm.\n' +
'\n' +
'To prevent this message from appearing, set the SUPPRESS_JASMINE_DEPRECATION\n' +
'environment variable.\n')
try:
from collections import OrderedDict
except ImportError:
from ordereddict import OrderedDict
class Core(object):
@classmethod
def js_package(cls):
return __package__
@classmethod
def css_package(cls):
return __package__
@classmethod
def image_package(cls):
return __package__ + ".images"
@classmethod
def js_files(cls):
js_files = sorted(list(filter(lambda x: '.js' in x, pkg_resources.resource_listdir(cls.js_package(), '.'))))
# jasmine.js needs to be first
js_files.insert(0, 'jasmine.js')
# boot needs to be last
js_files.remove('boot.js')
js_files.append('boot.js')
# Remove the new boot files. jasmine-py will continue to use the legacy
# boot.js.
js_files.remove('boot0.js')
js_files.remove('boot1.js')
return cls._uniq(js_files)
@classmethod
def css_files(cls):
return cls._uniq(sorted(filter(lambda x: '.css' in x, pkg_resources.resource_listdir(cls.css_package(), '.'))))
@classmethod
def favicon(cls):
return 'jasmine_favicon.png'
@classmethod
def _uniq(self, items, idfun=None):
# order preserving
if idfun is None:
def idfun(x): return x
seen = {}
result = []
for item in items:
marker = idfun(item)
# in old Python versions:
# if seen.has_key(marker)
# but in new ones:
if marker in seen:
continue
seen[marker] = 1
result.append(item)
return result

View File

@@ -1,24 +1,24 @@
function Player() {
}
Player.prototype.play = function(song) {
this.currentlyPlayingSong = song;
this.isPlaying = true;
};
Player.prototype.pause = function() {
this.isPlaying = false;
};
Player.prototype.resume = function() {
if (this.isPlaying) {
throw new Error("song is already playing");
class Player {
play(song) {
this.currentlyPlayingSong = song;
this.isPlaying = true;
}
this.isPlaying = true;
};
pause() {
this.isPlaying = false;
}
Player.prototype.makeFavorite = function() {
this.currentlyPlayingSong.persistFavoriteStatus(true);
};
resume() {
if (this.isPlaying) {
throw new Error('song is already playing');
}
this.isPlaying = true;
}
makeFavorite() {
this.currentlyPlayingSong.persistFavoriteStatus(true);
}
}
module.exports = Player;

View File

@@ -1,9 +1,8 @@
function Song() {
class Song {
persistFavoriteStatus(value) {
// something complicated
throw new Error('not yet implemented');
}
}
Song.prototype.persistFavoriteStatus = function(value) {
// something complicated
throw new Error("not yet implemented");
};
module.exports = Song;

View File

@@ -3,11 +3,11 @@ beforeEach(function () {
toBePlaying: function () {
return {
compare: function (actual, expected) {
var player = actual;
const player = actual;
return {
pass: player.currentlyPlayingSong === expected && player.isPlaying
}
};
}
};
}

View File

@@ -1,36 +1,37 @@
describe("Player", function() {
var Player = require('../../lib/jasmine_examples/Player');
var Song = require('../../lib/jasmine_examples/Song');
var player;
var song;
const Player = require('../../lib/jasmine_examples/Player');
const Song = require('../../lib/jasmine_examples/Song');
describe('Player', function() {
let player;
let song;
beforeEach(function() {
player = new Player();
song = new Song();
});
it("should be able to play a Song", function() {
it('should be able to play a Song', function() {
player.play(song);
expect(player.currentlyPlayingSong).toEqual(song);
//demonstrates use of custom matcher
// demonstrates use of custom matcher
expect(player).toBePlaying(song);
});
describe("when song has been paused", function() {
describe('when song has been paused', function() {
beforeEach(function() {
player.play(song);
player.pause();
});
it("should indicate that the song is currently paused", function() {
it('should indicate that the song is currently paused', function() {
expect(player.isPlaying).toBeFalsy();
// demonstrates use of 'not' with a custom matcher
expect(player).not.toBePlaying(song);
});
it("should be possible to resume", function() {
it('should be possible to resume', function() {
player.resume();
expect(player.isPlaying).toBeTruthy();
expect(player.currentlyPlayingSong).toEqual(song);
@@ -38,7 +39,7 @@ describe("Player", function() {
});
// demonstrates use of spies to intercept and test method calls
it("tells the current song if the user has made it a favorite", function() {
it('tells the current song if the user has made it a favorite', function() {
spyOn(song, 'persistFavoriteStatus');
player.play(song);
@@ -48,13 +49,13 @@ describe("Player", function() {
});
//demonstrates use of expected exceptions
describe("#resume", function() {
it("should throw an exception if song is already playing", function() {
describe('#resume', function() {
it('should throw an exception if song is already playing', function() {
player.play(song);
expect(function() {
player.resume();
}).toThrowError("song is already playing");
}).toThrowError('song is already playing');
});
});
});

View File

@@ -1,34 +1,34 @@
describe("Player", function() {
var player;
var song;
describe('Player', function() {
let player;
let song;
beforeEach(function() {
player = new Player();
song = new Song();
});
it("should be able to play a Song", function() {
it('should be able to play a Song', function() {
player.play(song);
expect(player.currentlyPlayingSong).toEqual(song);
//demonstrates use of custom matcher
// demonstrates use of custom matcher
expect(player).toBePlaying(song);
});
describe("when song has been paused", function() {
describe('when song has been paused', function() {
beforeEach(function() {
player.play(song);
player.pause();
});
it("should indicate that the song is currently paused", function() {
it('should indicate that the song is currently paused', function() {
expect(player.isPlaying).toBeFalsy();
// demonstrates use of 'not' with a custom matcher
expect(player).not.toBePlaying(song);
});
it("should be possible to resume", function() {
it('should be possible to resume', function() {
player.resume();
expect(player.isPlaying).toBeTruthy();
expect(player.currentlyPlayingSong).toEqual(song);
@@ -36,7 +36,7 @@ describe("Player", function() {
});
// demonstrates use of spies to intercept and test method calls
it("tells the current song if the user has made it a favorite", function() {
it('tells the current song if the user has made it a favorite', function() {
spyOn(song, 'persistFavoriteStatus');
player.play(song);
@@ -46,13 +46,13 @@ describe("Player", function() {
});
//demonstrates use of expected exceptions
describe("#resume", function() {
it("should throw an exception if song is already playing", function() {
describe('#resume', function() {
it('should throw an exception if song is already playing', function() {
player.play(song);
expect(function() {
player.resume();
}).toThrowError("song is already playing");
}).toThrowError('song is already playing');
});
});
});

View File

@@ -3,7 +3,7 @@ beforeEach(function () {
toBePlaying: function () {
return {
compare: function (actual, expected) {
var player = actual;
const player = actual;
return {
pass: player.currentlyPlayingSong === expected && player.isPlaying

View File

@@ -1,22 +1,22 @@
function Player() {
}
Player.prototype.play = function(song) {
this.currentlyPlayingSong = song;
this.isPlaying = true;
};
Player.prototype.pause = function() {
this.isPlaying = false;
};
Player.prototype.resume = function() {
if (this.isPlaying) {
throw new Error("song is already playing");
class Player {
play(song) {
this.currentlyPlayingSong = song;
this.isPlaying = true;
}
this.isPlaying = true;
};
pause() {
this.isPlaying = false;
}
Player.prototype.makeFavorite = function() {
this.currentlyPlayingSong.persistFavoriteStatus(true);
};
resume() {
if (this.isPlaying) {
throw new Error('song is already playing');
}
this.isPlaying = true;
}
makeFavorite() {
this.currentlyPlayingSong.persistFavoriteStatus(true);
}
}

View File

@@ -1,7 +1,6 @@
function Song() {
class Song {
persistFavoriteStatus(value) {
// something complicated
throw new Error('not yet implemented');
}
}
Song.prototype.persistFavoriteStatus = function(value) {
// something complicated
throw new Error("not yet implemented");
};

View File

@@ -1,5 +1,5 @@
/*
Copyright (c) 2008-2021 Pivotal Labs
Copyright (c) 2008-2023 Pivotal Labs
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@@ -20,6 +20,7 @@ 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.
*/
// eslint-disable-next-line no-var
var jasmineRequire = window.jasmineRequire || require('./jasmine.js');
jasmineRequire.html = function(j$) {
@@ -72,20 +73,28 @@ jasmineRequire.HtmlReporter = function(j$) {
}
};
ResultsStateBuilder.prototype.jasmineDone = function(result) {
if (result.failedExpectations) {
this.failureCount += result.failedExpectations.length;
}
};
function HtmlReporter(options) {
var config = function() {
return (options.env && options.env.configuration()) || {};
},
getContainer = options.getContainer,
createElement = options.createElement,
createTextNode = options.createTextNode,
navigateWithNewParam = options.navigateWithNewParam || function() {},
addToExistingQueryString =
options.addToExistingQueryString || defaultQueryString,
filterSpecs = options.filterSpecs,
htmlReporterMain,
symbols,
deprecationWarnings = [];
function config() {
return (options.env && options.env.configuration()) || {};
}
const getContainer = options.getContainer;
const createElement = options.createElement;
const createTextNode = options.createTextNode;
const navigateWithNewParam = options.navigateWithNewParam || function() {};
const addToExistingQueryString =
options.addToExistingQueryString || defaultQueryString;
const filterSpecs = options.filterSpecs;
let htmlReporterMain;
let symbols;
const deprecationWarnings = [];
const failures = [];
this.initialize = function() {
clearPrior();
@@ -113,14 +122,14 @@ jasmineRequire.HtmlReporter = function(j$) {
getContainer().appendChild(htmlReporterMain);
};
var totalSpecsDefined;
let totalSpecsDefined;
this.jasmineStarted = function(options) {
totalSpecsDefined = options.totalSpecsDefined || 0;
};
var summary = createDom('div', { className: 'jasmine-summary' });
const summary = createDom('div', { className: 'jasmine-summary' });
var stateBuilder = new ResultsStateBuilder();
const stateBuilder = new ResultsStateBuilder();
this.suiteStarted = function(result) {
stateBuilder.suiteStarted(result);
@@ -139,12 +148,11 @@ jasmineRequire.HtmlReporter = function(j$) {
stateBuilder.specStarted(result);
};
var failures = [];
this.specDone = function(result) {
stateBuilder.specDone(result);
if (noExpectations(result)) {
var noSpecMsg = "Spec '" + result.fullName + "' has no expectations.";
const noSpecMsg = "Spec '" + result.fullName + "' has no expectations.";
if (result.status === 'failed') {
console.error(noSpecMsg);
} else {
@@ -187,10 +195,11 @@ jasmineRequire.HtmlReporter = function(j$) {
};
this.jasmineDone = function(doneResult) {
var banner = find('.jasmine-banner');
var alert = find('.jasmine-alert');
var order = doneResult && doneResult.order;
var i;
stateBuilder.jasmineDone(doneResult);
const banner = find('.jasmine-banner');
const alert = find('.jasmine-alert');
const order = doneResult && doneResult.order;
alert.appendChild(
createDom(
'span',
@@ -202,14 +211,14 @@ jasmineRequire.HtmlReporter = function(j$) {
banner.appendChild(optionsMenu(config()));
if (stateBuilder.specsExecuted < totalSpecsDefined) {
var skippedMessage =
const skippedMessage =
'Ran ' +
stateBuilder.specsExecuted +
' of ' +
totalSpecsDefined +
' specs - run all';
// include window.location.pathname to fix issue with karma-jasmine-html-reporter in angular: see https://github.com/jasmine/jasmine/issues/1906
var skippedLink =
const skippedLink =
(window.location.pathname || '') +
addToExistingQueryString('spec', '');
alert.appendChild(
@@ -224,10 +233,11 @@ jasmineRequire.HtmlReporter = function(j$) {
)
);
}
var statusBarMessage = '';
var statusBarClassName = 'jasmine-overall-result jasmine-bar ';
var globalFailures = (doneResult && doneResult.failedExpectations) || [];
var failed = stateBuilder.failureCount + globalFailures.length > 0;
let statusBarMessage = '';
let statusBarClassName = 'jasmine-overall-result jasmine-bar ';
const globalFailures =
(doneResult && doneResult.failedExpectations) || [];
const failed = stateBuilder.failureCount + globalFailures.length > 0;
if (totalSpecsDefined > 0 || failed) {
statusBarMessage +=
@@ -253,7 +263,7 @@ jasmineRequire.HtmlReporter = function(j$) {
statusBarClassName += ' jasmine-failed ';
}
var seedBar;
let seedBar;
if (order && order.random) {
seedBar = createDom(
'span',
@@ -279,10 +289,10 @@ jasmineRequire.HtmlReporter = function(j$) {
)
);
var errorBarClassName = 'jasmine-bar jasmine-errored';
var afterAllMessagePrefix = 'AfterAll ';
const errorBarClassName = 'jasmine-bar jasmine-errored';
const afterAllMessagePrefix = 'AfterAll ';
for (i = 0; i < globalFailures.length; i++) {
for (let i = 0; i < globalFailures.length; i++) {
alert.appendChild(
createDom(
'span',
@@ -294,7 +304,7 @@ jasmineRequire.HtmlReporter = function(j$) {
function globalFailureMessage(failure) {
if (failure.globalErrorType === 'load') {
var prefix = 'Error during loading: ' + failure.message;
const prefix = 'Error during loading: ' + failure.message;
if (failure.filename) {
return (
@@ -303,15 +313,18 @@ jasmineRequire.HtmlReporter = function(j$) {
} else {
return prefix;
}
} else {
} else if (failure.globalErrorType === 'afterAll') {
return afterAllMessagePrefix + failure.message;
} else {
return failure.message;
}
}
addDeprecationWarnings(doneResult);
for (i = 0; i < deprecationWarnings.length; i++) {
var context;
for (let i = 0; i < deprecationWarnings.length; i++) {
const children = [];
let context;
switch (deprecationWarnings[i].runnableType) {
case 'spec':
@@ -324,18 +337,28 @@ 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
)
);
}
var results = find('.jasmine-results');
const results = find('.jasmine-results');
results.appendChild(summary);
summaryList(stateBuilder.topResults, summary);
@@ -377,8 +400,8 @@ jasmineRequire.HtmlReporter = function(j$) {
setMenuModeTo('jasmine-failure-list');
var failureNode = find('.jasmine-failures');
for (i = 0; i < failures.length; i++) {
const failureNode = find('.jasmine-failures');
for (let i = 0; i < failures.length; i++) {
failureNode.appendChild(failures[i]);
}
}
@@ -387,16 +410,16 @@ jasmineRequire.HtmlReporter = function(j$) {
return this;
function failureDom(result) {
var failure = createDom(
const failure = createDom(
'div',
{ className: 'jasmine-spec-detail jasmine-failed' },
failureDescription(result, stateBuilder.currentParent),
createDom('div', { className: 'jasmine-messages' })
);
var messages = failure.childNodes[1];
const messages = failure.childNodes[1];
for (var i = 0; i < result.failedExpectations.length; i++) {
var expectation = result.failedExpectations[i];
for (let i = 0; i < result.failedExpectations.length; i++) {
const expectation = result.failedExpectations[i];
messages.appendChild(
createDom(
'div',
@@ -423,18 +446,62 @@ jasmineRequire.HtmlReporter = function(j$) {
);
}
if (result.debugLogs) {
messages.appendChild(debugLogTable(result.debugLogs));
}
return failure;
}
function debugLogTable(debugLogs) {
const tbody = createDom('tbody');
debugLogs.forEach(function(entry) {
tbody.appendChild(
createDom(
'tr',
{},
createDom('td', {}, entry.timestamp.toString()),
createDom('td', {}, entry.message)
)
);
});
return createDom(
'div',
{ className: 'jasmine-debug-log' },
createDom(
'div',
{ className: 'jasmine-debug-log-header' },
'Debug logs'
),
createDom(
'table',
{},
createDom(
'thead',
{},
createDom(
'tr',
{},
createDom('th', {}, 'Time (ms)'),
createDom('th', {}, 'Message')
)
),
tbody
)
);
}
function summaryList(resultsTree, domParent) {
var specListNode;
for (var i = 0; i < resultsTree.children.length; i++) {
var resultNode = resultsTree.children[i];
let specListNode;
for (let i = 0; i < resultsTree.children.length; i++) {
const resultNode = resultsTree.children[i];
if (filterSpecs && !hasActiveSpec(resultNode)) {
continue;
}
if (resultNode.type === 'suite') {
var suiteListNode = createDom(
const suiteListNode = createDom(
'ul',
{ className: 'jasmine-suite', id: 'suite-' + resultNode.result.id },
createDom(
@@ -459,18 +526,17 @@ jasmineRequire.HtmlReporter = function(j$) {
specListNode = createDom('ul', { className: 'jasmine-specs' });
domParent.appendChild(specListNode);
}
var specDescription = resultNode.result.description;
let specDescription = resultNode.result.description;
if (noExpectations(resultNode.result)) {
specDescription = 'SPEC HAS NO EXPECTATIONS ' + specDescription;
}
if (
resultNode.result.status === 'pending' &&
resultNode.result.pendingReason !== ''
) {
specDescription =
specDescription +
' PENDING WITH MESSAGE: ' +
resultNode.result.pendingReason;
if (resultNode.result.status === 'pending') {
if (resultNode.result.pendingReason !== '') {
specDescription +=
' PENDING WITH MESSAGE: ' + resultNode.result.pendingReason;
} else {
specDescription += ' PENDING';
}
}
specListNode.appendChild(
createDom(
@@ -491,7 +557,7 @@ jasmineRequire.HtmlReporter = function(j$) {
}
function optionsMenu(config) {
var optionsMenuDom = createDom(
const optionsMenuDom = createDom(
'div',
{ className: 'jasmine-run-options' },
createDom('span', { className: 'jasmine-trigger' }, 'Options'),
@@ -557,24 +623,26 @@ jasmineRequire.HtmlReporter = function(j$) {
)
);
var failFastCheckbox = optionsMenuDom.querySelector('#jasmine-fail-fast');
const failFastCheckbox = optionsMenuDom.querySelector(
'#jasmine-fail-fast'
);
failFastCheckbox.checked = config.stopOnSpecFailure;
failFastCheckbox.onclick = function() {
navigateWithNewParam('failFast', !config.stopOnSpecFailure);
navigateWithNewParam('stopOnSpecFailure', !config.stopOnSpecFailure);
};
var throwCheckbox = optionsMenuDom.querySelector(
const throwCheckbox = optionsMenuDom.querySelector(
'#jasmine-throw-failures'
);
throwCheckbox.checked = config.stopSpecOnExpectationFailure;
throwCheckbox.onclick = function() {
navigateWithNewParam(
'oneFailurePerSpec',
'stopSpecOnExpectationFailure',
!config.stopSpecOnExpectationFailure
);
};
var randomCheckbox = optionsMenuDom.querySelector(
const randomCheckbox = optionsMenuDom.querySelector(
'#jasmine-random-order'
);
randomCheckbox.checked = config.random;
@@ -582,13 +650,15 @@ jasmineRequire.HtmlReporter = function(j$) {
navigateWithNewParam('random', !config.random);
};
var hideDisabled = optionsMenuDom.querySelector('#jasmine-hide-disabled');
const hideDisabled = optionsMenuDom.querySelector(
'#jasmine-hide-disabled'
);
hideDisabled.checked = config.hideDisabled;
hideDisabled.onclick = function() {
navigateWithNewParam('hideDisabled', !config.hideDisabled);
};
var optionsTrigger = optionsMenuDom.querySelector('.jasmine-trigger'),
const optionsTrigger = optionsMenuDom.querySelector('.jasmine-trigger'),
optionsPayload = optionsMenuDom.querySelector('.jasmine-payload'),
isOpen = /\bjasmine-open\b/;
@@ -607,7 +677,7 @@ jasmineRequire.HtmlReporter = function(j$) {
}
function failureDescription(result, suite) {
var wrapper = createDom(
const wrapper = createDom(
'div',
{ className: 'jasmine-description' },
createDom(
@@ -616,7 +686,7 @@ jasmineRequire.HtmlReporter = function(j$) {
result.description
)
);
var suiteLink;
let suiteLink;
while (suite && suite.parent) {
wrapper.insertBefore(createTextNode(' > '), wrapper.firstChild);
@@ -634,7 +704,7 @@ jasmineRequire.HtmlReporter = function(j$) {
}
function suiteHref(suite) {
var els = [];
const els = [];
while (suite && suite.parent) {
els.unshift(suite.result.description);
@@ -650,37 +720,74 @@ jasmineRequire.HtmlReporter = function(j$) {
function addDeprecationWarnings(result, runnableType) {
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
});
}
for (let i = 0; i < result.deprecationWarnings.length; i++) {
const warning = result.deprecationWarnings[i].message;
deprecationWarnings.push({
message: warning,
stack: result.deprecationWarnings[i].stack,
runnableName: result.fullName,
runnableType: runnableType
});
}
}
}
function createExpander(stackTrace) {
const expandLink = createDom('a', { href: '#' }, 'Show stack trace');
const 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);
}
function clearPrior() {
// return the reporter
var oldReporter = find('');
const oldReporter = find('');
if (oldReporter) {
getContainer().removeChild(oldReporter);
}
}
function createDom(type, attrs, childrenVarArgs) {
var el = createElement(type);
function createDom(type, attrs, childrenArrayOrVarArgs) {
const el = createElement(type);
let children;
for (var i = 2; i < arguments.length; i++) {
var child = arguments[i];
if (j$.isArray_(childrenArrayOrVarArgs)) {
children = childrenArrayOrVarArgs;
} else {
children = [];
for (let i = 2; i < arguments.length; i++) {
children.push(arguments[i]);
}
}
for (let i = 0; i < children.length; i++) {
const child = children[i];
if (typeof child === 'string') {
el.appendChild(createTextNode(child));
@@ -691,7 +798,7 @@ jasmineRequire.HtmlReporter = function(j$) {
}
}
for (var attr in attrs) {
for (const attr in attrs) {
if (attr == 'className') {
el[attr] = attrs[attr];
} else {
@@ -703,7 +810,7 @@ jasmineRequire.HtmlReporter = function(j$) {
}
function pluralize(singular, count) {
var word = count == 1 ? singular : singular + 's';
const word = count == 1 ? singular : singular + 's';
return '' + count + ' ' + word;
}
@@ -733,7 +840,7 @@ jasmineRequire.HtmlReporter = function(j$) {
}
function noExpectations(result) {
var allExpectations =
const allExpectations =
result.failedExpectations.length + result.passedExpectations.length;
return (
@@ -748,7 +855,7 @@ jasmineRequire.HtmlReporter = function(j$) {
}
if (resultNode.type == 'suite') {
for (var i = 0, j = resultNode.children.length; i < j; i++) {
for (let i = 0, j = resultNode.children.length; i < j; i++) {
if (hasActiveSpec(resultNode.children[i])) {
return true;
}
@@ -762,11 +869,11 @@ jasmineRequire.HtmlReporter = function(j$) {
jasmineRequire.HtmlSpecFilter = function() {
function HtmlSpecFilter(options) {
var filterString =
const filterString =
options &&
options.filterString() &&
options.filterString().replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
var filterPattern = new RegExp(filterString);
const filterPattern = new RegExp(filterString);
this.matches = function(specName) {
return filterPattern.test(specName);
@@ -810,7 +917,7 @@ jasmineRequire.QueryString = function() {
};
this.fullStringWithNewParam = function(key, value) {
var paramMap = queryStringToParamMap();
const paramMap = queryStringToParamMap();
paramMap[key] = value;
return toQueryString(paramMap);
};
@@ -822,8 +929,8 @@ jasmineRequire.QueryString = function() {
return this;
function toQueryString(paramMap) {
var qStrPairs = [];
for (var prop in paramMap) {
const qStrPairs = [];
for (const prop in paramMap) {
qStrPairs.push(
encodeURIComponent(prop) + '=' + encodeURIComponent(paramMap[prop])
);
@@ -832,15 +939,15 @@ jasmineRequire.QueryString = function() {
}
function queryStringToParamMap() {
var paramStr = options.getWindowLocation().search.substring(1),
params = [],
paramMap = {};
const paramStr = options.getWindowLocation().search.substring(1);
let params = [];
const paramMap = {};
if (paramStr.length > 0) {
params = paramStr.split('&');
for (var i = 0; i < params.length; i++) {
var p = params[i].split('=');
var value = decodeURIComponent(p[1]);
for (let i = 0; i < params.length; i++) {
const p = params[i].split('=');
let value = decodeURIComponent(p[1]);
if (value === 'true' || value === 'false') {
value = JSON.parse(value);
}

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@@ -1,489 +0,0 @@
/*
json2.js
2014-02-04
Public Domain.
NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
See http://www.JSON.org/js.html
This code should be minified before deployment.
See http://javascript.crockford.com/jsmin.html
USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
NOT CONTROL.
This file creates a global JSON object containing two methods: stringify
and parse.
JSON.stringify(value, replacer, space)
value any JavaScript value, usually an object or array.
replacer an optional parameter that determines how object
values are stringified for objects. It can be a
function or an array of strings.
space an optional parameter that specifies the indentation
of nested structures. If it is omitted, the text will
be packed without extra whitespace. If it is a number,
it will specify the number of spaces to indent at each
level. If it is a string (such as '\t' or '&nbsp;'),
it contains the characters used to indent at each level.
This method produces a JSON text from a JavaScript value.
When an object value is found, if the object contains a toJSON
method, its toJSON method will be called and the result will be
stringified. A toJSON method does not serialize: it returns the
value represented by the name/value pair that should be serialized,
or undefined if nothing should be serialized. The toJSON method
will be passed the key associated with the value, and this will be
bound to the value
For example, this would serialize Dates as ISO strings.
Date.prototype.toJSON = function (key) {
function f(n) {
// Format integers to have at least two digits.
return n < 10 ? '0' + n : n;
}
return this.getUTCFullYear() + '-' +
f(this.getUTCMonth() + 1) + '-' +
f(this.getUTCDate()) + 'T' +
f(this.getUTCHours()) + ':' +
f(this.getUTCMinutes()) + ':' +
f(this.getUTCSeconds()) + 'Z';
};
You can provide an optional replacer method. It will be passed the
key and value of each member, with this bound to the containing
object. The value that is returned from your method will be
serialized. If your method returns undefined, then the member will
be excluded from the serialization.
If the replacer parameter is an array of strings, then it will be
used to select the members to be serialized. It filters the results
such that only members with keys listed in the replacer array are
stringified.
Values that do not have JSON representations, such as undefined or
functions, will not be serialized. Such values in objects will be
dropped; in arrays they will be replaced with null. You can use
a replacer function to replace those with JSON values.
JSON.stringify(undefined) returns undefined.
The optional space parameter produces a stringification of the
value that is filled with line breaks and indentation to make it
easier to read.
If the space parameter is a non-empty string, then that string will
be used for indentation. If the space parameter is a number, then
the indentation will be that many spaces.
Example:
text = JSON.stringify(['e', {pluribus: 'unum'}]);
// text is '["e",{"pluribus":"unum"}]'
text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
// text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
text = JSON.stringify([new Date()], function (key, value) {
return this[key] instanceof Date ?
'Date(' + this[key] + ')' : value;
});
// text is '["Date(---current time---)"]'
JSON.parse(text, reviver)
This method parses a JSON text to produce an object or array.
It can throw a SyntaxError exception.
The optional reviver parameter is a function that can filter and
transform the results. It receives each of the keys and values,
and its return value is used instead of the original value.
If it returns what it received, then the structure is not modified.
If it returns undefined then the member is deleted.
Example:
// Parse the text. Values that look like ISO date strings will
// be converted to Date objects.
myData = JSON.parse(text, function (key, value) {
var a;
if (typeof value === 'string') {
a =
/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
if (a) {
return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
+a[5], +a[6]));
}
}
return value;
});
myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
var d;
if (typeof value === 'string' &&
value.slice(0, 5) === 'Date(' &&
value.slice(-1) === ')') {
d = new Date(value.slice(5, -1));
if (d) {
return d;
}
}
return value;
});
This is a reference implementation. You are free to copy, modify, or
redistribute.
*/
/*jslint evil: true, regexp: true */
/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
lastIndex, length, parse, prototype, push, replace, slice, stringify,
test, toJSON, toString, valueOf
*/
// Create a JSON object only if one does not already exist. We create the
// methods in a closure to avoid creating global variables.
if (typeof JSON !== 'object') {
JSON = {};
}
(function () {
'use strict';
function f(n) {
// Format integers to have at least two digits.
return n < 10 ? '0' + n : n;
}
if (typeof Date.prototype.toJSON !== 'function') {
Date.prototype.toJSON = function () {
return isFinite(this.valueOf())
? this.getUTCFullYear() + '-' +
f(this.getUTCMonth() + 1) + '-' +
f(this.getUTCDate()) + 'T' +
f(this.getUTCHours()) + ':' +
f(this.getUTCMinutes()) + ':' +
f(this.getUTCSeconds()) + 'Z'
: null;
};
String.prototype.toJSON =
Number.prototype.toJSON =
Boolean.prototype.toJSON = function () {
return this.valueOf();
};
}
var cx,
escapable,
gap,
indent,
meta,
rep;
function quote(string) {
// If the string contains no control characters, no quote characters, and no
// backslash characters, then we can safely slap some quotes around it.
// Otherwise we must also replace the offending characters with safe escape
// sequences.
escapable.lastIndex = 0;
return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
var c = meta[a];
return typeof c === 'string'
? c
: '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
}) + '"' : '"' + string + '"';
}
function str(key, holder) {
// Produce a string from holder[key].
var i, // The loop counter.
k, // The member key.
v, // The member value.
length,
mind = gap,
partial,
value = holder[key];
// If the value has a toJSON method, call it to obtain a replacement value.
if (value && typeof value === 'object' &&
typeof value.toJSON === 'function') {
value = value.toJSON(key);
}
// If we were called with a replacer function, then call the replacer to
// obtain a replacement value.
if (typeof rep === 'function') {
value = rep.call(holder, key, value);
}
// What happens next depends on the value's type.
switch (typeof value) {
case 'string':
return quote(value);
case 'number':
// JSON numbers must be finite. Encode non-finite numbers as null.
return isFinite(value) ? String(value) : 'null';
case 'boolean':
case 'null':
// If the value is a boolean or null, convert it to a string. Note:
// typeof null does not produce 'null'. The case is included here in
// the remote chance that this gets fixed someday.
return String(value);
// If the type is 'object', we might be dealing with an object or an array or
// null.
case 'object':
// Due to a specification blunder in ECMAScript, typeof null is 'object',
// so watch out for that case.
if (!value) {
return 'null';
}
// Make an array to hold the partial results of stringifying this object value.
gap += indent;
partial = [];
// Is the value an array?
if (Object.prototype.toString.apply(value) === '[object Array]') {
// The value is an array. Stringify every element. Use null as a placeholder
// for non-JSON values.
length = value.length;
for (i = 0; i < length; i += 1) {
partial[i] = str(i, value) || 'null';
}
// Join all of the elements together, separated with commas, and wrap them in
// brackets.
v = partial.length === 0
? '[]'
: gap
? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']'
: '[' + partial.join(',') + ']';
gap = mind;
return v;
}
// If the replacer is an array, use it to select the members to be stringified.
if (rep && typeof rep === 'object') {
length = rep.length;
for (i = 0; i < length; i += 1) {
if (typeof rep[i] === 'string') {
k = rep[i];
v = str(k, value);
if (v) {
partial.push(quote(k) + (gap ? ': ' : ':') + v);
}
}
}
} else {
// Otherwise, iterate through all of the keys in the object.
for (k in value) {
if (Object.prototype.hasOwnProperty.call(value, k)) {
v = str(k, value);
if (v) {
partial.push(quote(k) + (gap ? ': ' : ':') + v);
}
}
}
}
// Join all of the member texts together, separated with commas,
// and wrap them in braces.
v = partial.length === 0
? '{}'
: gap
? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}'
: '{' + partial.join(',') + '}';
gap = mind;
return v;
}
}
// If the JSON object does not yet have a stringify method, give it one.
if (typeof JSON.stringify !== 'function') {
escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
meta = { // table of character substitutions
'\b': '\\b',
'\t': '\\t',
'\n': '\\n',
'\f': '\\f',
'\r': '\\r',
'"' : '\\"',
'\\': '\\\\'
};
JSON.stringify = function (value, replacer, space) {
// The stringify method takes a value and an optional replacer, and an optional
// space parameter, and returns a JSON text. The replacer can be a function
// that can replace values, or an array of strings that will select the keys.
// A default replacer method can be provided. Use of the space parameter can
// produce text that is more easily readable.
var i;
gap = '';
indent = '';
// If the space parameter is a number, make an indent string containing that
// many spaces.
if (typeof space === 'number') {
for (i = 0; i < space; i += 1) {
indent += ' ';
}
// If the space parameter is a string, it will be used as the indent string.
} else if (typeof space === 'string') {
indent = space;
}
// If there is a replacer, it must be a function or an array.
// Otherwise, throw an error.
rep = replacer;
if (replacer && typeof replacer !== 'function' &&
(typeof replacer !== 'object' ||
typeof replacer.length !== 'number')) {
throw new Error('JSON.stringify');
}
// Make a fake root object containing our value under the key of ''.
// Return the result of stringifying the value.
return str('', {'': value});
};
}
// If the JSON object does not yet have a parse method, give it one.
if (typeof JSON.parse !== 'function') {
cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
JSON.parse = function (text, reviver) {
// The parse method takes a text and an optional reviver function, and returns
// a JavaScript value if the text is a valid JSON text.
var j;
function walk(holder, key) {
// The walk method is used to recursively walk the resulting structure so
// that modifications can be made.
var k, v, value = holder[key];
if (value && typeof value === 'object') {
for (k in value) {
if (Object.prototype.hasOwnProperty.call(value, k)) {
v = walk(value, k);
if (v !== undefined) {
value[k] = v;
} else {
delete value[k];
}
}
}
}
return reviver.call(holder, key, value);
}
// Parsing happens in four stages. In the first stage, we replace certain
// Unicode characters with escape sequences. JavaScript handles many characters
// incorrectly, either silently deleting them, or treating them as line endings.
text = String(text);
cx.lastIndex = 0;
if (cx.test(text)) {
text = text.replace(cx, function (a) {
return '\\u' +
('0000' + a.charCodeAt(0).toString(16)).slice(-4);
});
}
// In the second stage, we run the text against regular expressions that look
// for non-JSON patterns. We are especially concerned with '()' and 'new'
// because they can cause invocation, and '=' because it can cause mutation.
// But just to be safe, we want to reject all unexpected forms.
// We split the second stage into 4 regexp operations in order to work around
// crippling inefficiencies in IE's and Safari's regexp engines. First we
// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
// replace all simple value tokens with ']' characters. Third, we delete all
// open brackets that follow a colon or comma or that begin the text. Finally,
// we look to see that the remaining characters are only whitespace or ']' or
// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
if (/^[\],:{}\s]*$/
.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
.replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
// In the third stage we use the eval function to compile the text into a
// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
// in JavaScript: it can begin a block or an object literal. We wrap the text
// in parens to eliminate the ambiguity.
j = eval('(' + text + ')');
// In the optional fourth stage, we recursively walk the new structure, passing
// each name/value pair to a reviver function for possible transformation.
return typeof reviver === 'function'
? walk({'': j}, '')
: j;
}
// If the text is not JSON parseable, then a SyntaxError is thrown.
throw new SyntaxError('JSON.parse');
};
}
}());

View File

@@ -1,38 +0,0 @@
/*
Copyright (c) 2008-2021 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.
*/
module.exports = function(jasmineRequire) {
var jasmine = jasmineRequire.core(jasmineRequire);
var env = jasmine.getEnv({suppressLoadErrors: true});
var jasmineInterface = jasmineRequire.interface(jasmine, env);
extend(global, jasmineInterface);
function extend(destination, source) {
for (var property in source) destination[property] = source[property];
return destination;
}
return jasmine;
};

View File

@@ -1,9 +0,0 @@
#
# DO NOT Edit this file. Canonical version of Jasmine lives in the repo's package.json. This file is generated
# by a grunt task when the standalone release is built.
#
module Jasmine
module Core
VERSION = "3.10.1"
end
end

View File

@@ -1,7 +1,7 @@
{
"name": "jasmine-core",
"license": "MIT",
"version": "3.10.1",
"version": "5.1.0",
"repository": {
"type": "git",
"url": "https://github.com/jasmine/jasmine.git"
@@ -34,22 +34,21 @@
"package.json"
],
"devDependencies": {
"ejs": "^2.5.5",
"eslint": "^6.8.0",
"eslint-plugin-compat": "^3.8.0",
"fast-glob": "^2.2.6",
"eslint": "^8.36.0",
"eslint-plugin-compat": "^4.0.0",
"glob": "^10.2.3",
"grunt": "^1.0.4",
"grunt-cli": "^1.3.2",
"grunt-contrib-compress": "^1.3.0",
"grunt-contrib-concat": "^1.0.1",
"grunt-contrib-compress": "^2.0.0",
"grunt-contrib-concat": "^2.0.0",
"grunt-css-url-embed": "^1.11.1",
"grunt-sass": "^3.0.2",
"jasmine": "^3.4.0",
"jasmine-browser-runner": "github:jasmine/jasmine-browser#main",
"jsdom": "^15.0.0",
"load-grunt-tasks": "^4.0.0",
"jasmine": "^5.0.0",
"jasmine-browser-runner": "github:jasmine/jasmine-browser-runner",
"jsdom": "^22.0.0",
"load-grunt-tasks": "^5.1.0",
"prettier": "1.17.1",
"sass": "^1.32.12",
"sass": "^1.58.3",
"shelljs": "^0.8.3",
"temp": "^0.9.0"
},
@@ -60,8 +59,13 @@
"extends": [
"plugin:compat/recommended"
],
"env": {
"browser": true,
"node": true,
"es2017": true
},
"parserOptions": {
"ecmaVersion": 5
"ecmaVersion": 2018
},
"rules": {
"quotes": [
@@ -77,6 +81,7 @@
"args": "none"
}
],
"no-implicit-globals": "error",
"block-spacing": "error",
"func-call-spacing": [
"error",
@@ -90,15 +95,16 @@
"error",
"always"
],
"space-before-blocks": "error"
"space-before-blocks": "error",
"no-eval": "error",
"no-var": "error",
"no-debugger": "error"
}
},
"browserslist": [
"Safari >= 8",
"Safari >= 15",
"Firefox >= 102",
"last 2 Chrome versions",
"last 2 Firefox versions",
"Firefox 68",
"last 2 Edge versions",
"IE >= 10"
"last 2 Edge versions"
]
}

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)_

197
release_notes/4.0.0.md Normal file
View File

@@ -0,0 +1,197 @@
# Jasmine Core 4.0.0 Release Notes
## Summary
This is a major release. In addition to new features and bug fixes it contains
a number of breaking changes that are intended to diagnose common errors,
improve awkward or outdated APIs, and make Jasmine easier to maintain
and contribute to. If you're upgrading from Jasmine 3.x, we recommend installing
3.99 and fixing any deprecation warnings that it emits before updating to 4.0.
Please see the [migration guide](https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0)
for more information. If you use the `jasmine` or `jasmine-browser-runner` NPM
packages, please read the release notes for those packages as well.
## Highlights
* Obsolete environments, most notably Internet Explorer, are no longer
supported. Jasmine now expects to run in an environment that provides most
of ES2017 and, in the case of Node, good interoperability between CommonJS
modules and ES modules.
* The Jasmine packages for Ruby and Python have been discontinued.
* Errors in `beforeAll` and `beforeEach` functions are handled better.
* Jasmine can optionally be used without creating globals in Node.
* Certain common async testing bugs are now reported as errors.
* A new debug logging feature makes it easier to debug failing specs,
particularly intermittent failures.
See details below.
## Breaking changes
### Changes to supported environments
The following previously supported environments are no longer supported:
* Internet Explorer
* PhantomJS
* Safari 8-13
* Firefox 68 and 78
* Node 10 and 12.0-12.16
* Python
* Ruby
* Bower
Although Jasmine 4.0 may still work in some of those environments, we no longer
test against them and won't try to maintain compatibility with them in future
4.x releases.
The [`jasmine-browser-runner`](https://jasmine.github.io/setup/browser.html)
NPM package is the direct replacement for the `jasmine` Ruby and Python
packages.
### Changes that affect how specs are written
* When a `beforeAll` function fails in any way other than a failed expectation,
Jasmine will not run the contents of the suite or any child suites except
for any `afterAll` functions defined in the same suite as the failed
`beforeAll` function. All affected specs will still be reported as failed.
See [#1533](https://github.com/jasmine/jasmine/issues/1533).
* When a `beforeEach` function fails in any way other than a failed expectation,
Jasmine will skip any subsequent `beforeEach` functions, the corresponding
spec, and any `afterEach` functions defined in child suites. `afterEach`
functions defined at the same or higher levels will still run. The spec will
still be reported as failed. See [#1533](https://github.com/jasmine/jasmine/issues/1533).
* `MatchersUtil#contains` and the `toContain` matcher use deep equality rather
than `===` to compare set members. This matches how arrays are handled but
may cause some previously passing `.not.toContain()` expectations to fail.
* `jasmine.clock().mockDate()` throws if its argument is not a `Date`. Previous
versions ignored non-`Date` arguments.
* Multiple calls to an asynchronous function's `done` callback are treated as
errors.
* Any argument passed to a `done` callback (other than `undefined`) is treated
as an error. Previous versions ignored any argument that wasn't an `Error`
instance.
* Jasmine will report an error rather than a warning when a function tries to
combine two different forms of async (e.g. taking a callback and also
returning a promise).
* `this` in `describe` functions is no longer a `Suite` object.
* Empty suites are treated as errors.
* Merges [#1742](https://github.com/jasmine/jasmine/pull/1742) from @johnjbarton
* The current time value does not decrease when `jasmine.clock().tick()` is
called from a `setTimeout` or `setInterval` callback.
* Merges [#1948](https://github.com/jasmine/jasmine/pull/1948) from @thw0rted
* Fixes [#1929](https://github.com/jasmine/jasmine/issues/1929).
### Changes to how Jasmine is configured
* Individual configuration property getters and setters such as
`Env#randomTests` and `Env#randomizeTests` have been removed. Use
`Env#configuration` and `Env#configure` instead.
* The `failFast` and `oneFailurePerSpec` configuration properties have been
removed. Use `stopOnSpecFailure` and `stopSpecOnExpectationFailure` instead.
* The `Promise` configuration property has been removed. Jasmine can still
consume non-native promises but will always use the global `Promise` to
create promises.
### Changes that affect custom matchers
* The old style of using custom equality testers, where matchers received them
from Jasmine and had to pass them back to `matchersUtil` methods, is no longer
supported.
* `matchersUtil` and `pp` are no longer available globally. Instead, use the
instances that are passed to custom matcher factories and to `jasmineToString`.
See the [migration guide](https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0)
for more information about these changes and how to update custom matchers that
use the old APIs.
### Changes that affect custom reporters
* The [`Suite`](https://jasmine.github.io/api/4.0/Suite.html) and
[`Spec`](https://jasmine.github.io/api/4.0/Spec.html) objects returned from
`describe`, `it`, and `Env#topSuite` no longer expose private APIs.
### Other breaking changes
* `boot.js` is no longer included. Use `boot0.js` and `boot1.js` instead.
* Boot files in `lib/jasmine-core/boot` are no longer included in the NPM
package. Use the boot files in `lib/jasmine-core` instead.
* `json2.js` is no longer included, since all supported environments provide a
JSON parser.
## Other new features and bug fixes
* Jasmine can optionally be used without creating globals in Node.js.
* See https://jasmine.github.io/api/4.0/module-jasmine-core.html#.noGlobals
* If you're using the `jasmine` package, see
[its documentation](https://jasmine.github.io/api/npm/4.0/JasmineOptions.html#globals).
* Fixes [#1235](https://github.com/jasmine/jasmine/issues/1235)
* Custom spy strategies are inherited from parent suites like other runnable
resources.
* `pending()` can now be called from `beforeEach` functions.
* Fixes [#1579](https://github.com/jasmine/jasmine/issues/1579)
* Removed duplicate message from errors (including. matcher failures) in
V8-based environments.
* `Spy#withArgs` supports custom equality testers.
* Fixes [#1836](https://github.com/jasmine/jasmine/issues/1836)
* The promise returned by `Env#execute` is resolved to the
[jasmineDoneInfo](https://jasmine.github.io/api/4.0/global.html#JasmineDoneInfo).
* Fixed stack trace filtering on Safari 15.
* The HTML reporter includes top suite failures in the reported failure count.
* `afterAll` functions are run after a failure even if the `stopOnSpecFailure`
config property is set.
* Added a debug logging feature to make it easier to debug failing specs.
* Call `jasmine#debugLog` during spec execution to add a log entry.
* If the spec fails, log entries are reported as part of the
[specDone](https://jasmine.github.io/api/4.0/Reporter.html#specDone) reporter
event.
* The HTML reporter no longer says that expectations occurring after the spec
finishes are AfterAll errors.
## Documentation updates
* Added a [4.0 migration guide](https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0)
* Updated the README and contributing guide for 4.0
## Supported environments
jasmine-core 4.0.0 has been tested in the following environments.
| Environment | Supported versions |
|-------------------|--------------------|
| Node | 12.17+, 14, 16 |
| Safari | 14-15 |
| Chrome | 96 |
| Firefox | 91, 95 |
| Edge | 96 |
------
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_

21
release_notes/4.0.1.md Normal file
View File

@@ -0,0 +1,21 @@
# Jasmine Core 4.0.1 Release Notes
This release fixes a bug in 4.0.0, which incorrectly reported a failure
when a promise returned from a function passed to `it`, `beforeEach`,
etc was resolved to a value.
## Supported environments
jasmine-core 4.0.1 has been tested in the following environments.
| Environment | Supported versions |
|-------------------|--------------------|
| Node | 12.17+, 14, 16 |
| Safari | 14-15 |
| Chrome | 98 |
| Firefox | 91, 97 |
| Edge | 98 |
------
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_

50
release_notes/4.1.0.md Normal file
View File

@@ -0,0 +1,50 @@
# Jasmine 4.1.0 Release Notes
## New Features and Bug Fixes
* toBeCloseTo treats Infinity and -Infinity as close to themselves
* Fixes [#1957](https://github.com/jasmine/jasmine/issues/1957)
* Replaced uses of deprecated String.prototype.substr()
* Merges [#1962](https://github.com/jasmine/jasmine/pull/1962) from @CommanderRoot
* Removed obsolete vendor-specific background-size CSS rules
* Fixes [#1961](https://github.com/jasmine/jasmine/issues/1961)
* Added toHaveSpyInteractions matcher
* Merges [#1959](https://github.com/jasmine/jasmine/pull/1959) from @nitobuenida
* Fixes [#1568](https://github.com/jasmine/jasmine/issues/1568)
* Pretty-print [new String("")] as "[ '' ]", not "[]"
* Fixed cloning of Date objects in Spy#calls#saveArgumentsByValue
* Merges [#1955](https://github.com/jasmine/jasmine/pull/1955) from @coyoteecd
* Fixes [#1885](https://github.com/jasmine/jasmine/issues/1885)
* Include the name of the suite in the empty suite error message
* toEqual checks keys that are Symbols
* Merges [#1879](https://github.com/jasmine/jasmine/pull/1879) from @laeleoni
* Fixes [#1811](https://github.com/jasmine/jasmine/issues/1811)
## Documentation Updates
* Replaced redundant installation instructions in README with link to docs
* Added links to usage instructions to README
## Supported environments
jasmine-core 4.1.0 has been tested in the following environments.
| Environment | Supported versions |
|-------------------|--------------------|
| Node | 12.17+, 14, 16 |
| Safari | 14-15 |
| Chrome | 100 |
| Firefox | 91, 99 |
| Edge | 100 |
------
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_

35
release_notes/4.1.1.md Normal file
View File

@@ -0,0 +1,35 @@
# Jasmine 4.1.1 Release Notes
## Summary
This release fixes several bugs involving equality comparison of properties
with Symbol keys.
## Bug fixes
* Fixes for crash bugs and output problems when comparing objects with Symbol keys
* Include symbol properties in matcher diffs
* Fixed exception when comparing arrays with Symbol keys
* Include symbol properties in matcher diffs
* Include symbol keys when pretty-printing objects
* Fixes [#1966](https://github.com/jasmine/jasmine/issues/1966)
* Exclude non-enumerable symbol properties from equality comparison
* Merges [#1963](https://github.com/jasmine/jasmine/pull/1963) from @suke
## Supported environments
jasmine-core 4.1.1 has been tested in the following environments.
| Environment | Supported versions |
|-------------------|--------------------|
| Node | 12.17+, 14, 16, 18 |
| Safari | 14, 15 |
| Chrome | 101 |
| Firefox | 91, 100 |
| Edge | 101 |
------
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_

41
release_notes/4.2.0.md Normal file
View File

@@ -0,0 +1,41 @@
# Jasmine 4.2.0 Release Notes
## New Features
* Added a jasmine.is asymmetric equality tester
* Allows the use of === comparisons for specific fields of an object that
should otherwise be compared with the default deep value equality logic.
## Bug Fixes
* More reliably report errors that occur late in the suite/spec lifecycle
* Previously, an error that occurred after Jasmine started to report the
suiteDone or specDone event for the current runable would not be reliably
reported. Now such an error is reported on the nearest ancestor suite whose
suiteDone event has not yet been reported.
* Don't report a deprecation when a runnable uses two forms of async
* This was made into an error in 4.0, so the deprecation is redundant.
* Include property getter values in pretty-printed objects
## Documentation Updates
* Removed duplicate Suite and Spec jsdocs
## Supported environments
jasmine-core 4.2.0 has been tested in the following environments.
| Environment | Supported versions |
|-------------------|--------------------|
| Node | 12.17+, 14, 16, 18 |
| Safari | 14-15 |
| Chrome | 102 |
| Firefox | 91, 101 |
| Edge | 101 |
------
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_

40
release_notes/4.3.0.md Normal file
View File

@@ -0,0 +1,40 @@
# Jasmine 4.3.0 Release Notes
## New Features
* Added [`jasmine.spyOnGlobalErrorsAsync`](https://jasmine.github.io/api/4.3/jasmine.html#.spyOnGlobalErrorsAsync),
to better support testing code that's
expected to produce unhandled exceptions or unhandled promise rejections
* Fixes [#1843](https://github.com/jasmine/jasmine/issues/1843)
* Fixes [#1453](https://github.com/jasmine/jasmine/issues/1453)
## Documentation updates
* Updated the README to reduce redundancy and update support links
## Internal improvements
* Split `Env` into several smaller classes
* Replaced uses of `var` with `const`/`let`
* Replaced most uses of `self = this` with arrow fns
* Removed obsolete and unused utility fns
* Separated reporter- and runable-specific queue runner configuration
* Added more test coverage for default spy strategies
* Converted integration specs to `async`/`await`
## Supported environments
jasmine-core 4.3.0 has been tested in the following environments.
| Environment | Supported versions |
|-------------------|--------------------|
| Node | 12.17+, 14, 16, 18 |
| Safari | 14-15 |
| Chrome | 103 |
| Firefox | 91, 102 |
| Edge | 103 |
------
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_

28
release_notes/4.4.0.md Normal file
View File

@@ -0,0 +1,28 @@
# Jasmine 4.4.0 Release Notes
## Changes
* Optimized the process of transitioning between specs in Node, Safari, and
Edge. This change reduces the run time of jasmine-core's own test suite by
50-70% in Node, about 20% in Edge, and 75-90% in Safari. Your results may
vary. In general, suites with many fast specs will see the greatest
performance improvement.
* Removed old code to support browsers that don't provide
addEventListener/removeEventListener.
## Supported environments
jasmine-core 4.4.0 has been tested in the following environments.
| Environment | Supported versions |
|-------------------|--------------------|
| Node | 12.17+, 14, 16, 18 |
| Safari | 14-15 |
| Chrome | 105 |
| Firefox | 91, 102, 104 |
| Edge | 104 |
------
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_

40
release_notes/4.5.0.md Normal file
View File

@@ -0,0 +1,40 @@
# Jasmine 4.5.0 Release Notes
## New Features
* Added Safari 16 to supported browsers
* Include inner exceptions in stack traces
## Bug Fixes
* Report exceptions thrown by a describe before any it calls
* Coerce the random string to a seed before sending it to reporters
* This fixes an error in HTMLReporter when the configured seed is a
number rather than a string, which has been allowed since 3.8.0
## Documentation updates
* Fixed the jsdoc types of SuiteResult and SpecResult ids
* Replaced var with const in API doc examples
* Updated the style of the examples that are included in jasmine-core
## Internal improvements
* Converted TreeProcessor to async/await
* Converted ReportDispatcher to promises
## Supported environments
jasmine-core 4.5.0 has been tested in the following environments.
| Environment | Supported versions |
|-------------------|--------------------|
| Node | 12.17+, 14, 16, 18 |
| Safari | 14-16 |
| Chrome | 107 |
| Firefox | 91, 102, 106 |
| Edge | 106 |
------
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_

19
release_notes/4.6.0.md Normal file
View File

@@ -0,0 +1,19 @@
# Jasmine Core 4.6.0 Release Notes
## New Features
* Report the ID of each suite/spec's parent
* Report the path/url of the file that the spec/suite was defined in
* Fixes [#1884](https://github.com/jasmine/jasmine/issues/1884)
* Added Firefox 102 (current ESR) to supported browsers
## Internal improvements
* Pinned sass to 1.58.3 for compatibility with Node 12
* Pinned eslint-plugin-compat to <4.1.0 for compatibility with Node 12
* Pinned Grunt to <1.6.0 for compatibility with Node 12
------
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_

View File

@@ -0,0 +1,68 @@
# Jasmine Core 5.0.0-alpha.0 Release Notes
## Summary
This release primarily adds support for parallel execution via the `jasmine`
package. Please see its release notes and the
[parallel documentation](https://jasmine.github.io/tutorials/running_specs_in_parallel)
for more information. Additionally, this release cleans up a few outdated
interfaces.
This is a pre-release for a major version. It contains breaking changes, and
there may be further breaking changes between this release and the final 5.0.0
release.
## Breaking changes
* Use addEventListener in browsers rather than setting window.onerror
This simplifies error handling in browsers, makes Jasmine's own integration
tests easier to debug, and provides stack traces for more unhandled
exceptions. However, some browsers will provide less error information when
the error comes from a file:// URL. Additionally, Jasmine will no longer
override existing onerror handlers, and setting window.onerror will no longer
override Jasmine's global error handling. (Use `jasmine.spyOnGlobalErrors`
instead.)
* Made Env#execute async
* Env#execute no longer takes a callback
* The `boot` function exported by the core module returns the same object
every time it's called.
* Removed node_boot.js. Use the exported `boot` function instead.
### Changes to supported environments
The following previously supported environments are no longer supported:
* Node <16.14
* Safari 14
* Firefox 91
Although this release may still work in some of those environments, we no
longer test against them and won't try to maintain compatibility with them in
future releases.
## New features
* Support for parallel execution in Node.js using the `jasmine` package
## Bug fixes
* The global error handler is uninstalled at the end of env execution.
## Supported environments
jasmine-core 5.0.0-alpha.0 has been tested in the following environments.
| Environment | Supported versions |
|-------------------|--------------------|
| Node | 16.14+, 18 |
| Safari | 15-16 |
| Chrome | 111 |
| Firefox | 102, 111 |
| Edge | 111 |
------
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_

View File

@@ -0,0 +1,39 @@
# Jasmine Core 5.0.0-alpha.1 Release Notes
## Summary
This release provides improved support for parallel execution via the `jasmine`
package. Please see its release notes and the
[parallel documentation](https://jasmine.github.io/tutorials/running_specs_in_parallel)
for more information.
## New features and bug fixes
* Parallel: Cleaner interface for reporter dispatching
* When Env#config is called from spec and helper files in parallel mode, throw
an error rather than behaving unpredictably.
## Documentation improvements
* API reference docs for parallel support APIs that jasmine-npm uses
## Internal improvements
* Updated dev dependencies
## Supported environments
jasmine-core 5.0.0-alpha.1 has been tested in the following environments.
| Environment | Supported versions |
|-------------------|--------------------|
| Node | 16.14+, 18 |
| Safari | 15-16 |
| Chrome | 112 |
| Firefox | 102, 111 |
| Edge | 111 |
------
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_

View File

@@ -0,0 +1,28 @@
# Jasmine Core 5.0.0-beta.0 Release Notes
This release supports the 5.0.0-beta-0 release of the `jasmine` package.
## Breaking changes
* Dropped support for Node 16
## New features
* Added support for Node 20
## Supported environments
jasmine-core 5.0.0-beta.0 has been tested in the following environments.
| Environment | Supported versions |
|-------------------|--------------------|
| Node | 18, 20 |
| Safari | 15-16 |
| Chrome | 112 |
| Firefox | 102, 112 |
| Edge | 112 |
------
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_

55
release_notes/5.0.0.md Normal file
View File

@@ -0,0 +1,55 @@
# Jasmine Core 5.0.0 Release Notes
## Summary
This is a major release that includes breaking changes. It primarily adds
support for parallel execution in Node via the `jasmine` package. Most users
should be able to upgrade without changes, but please read the list of breaking
changes below and see the [migration guide](https://jasmine.github.io/tutorials/upgrading_to_Jasmine_5.0)
for more information.
## Breaking changes
* Dropped support for Node 12, 14, and 16
* Dropped support for Safari 14 and Firefox 91
* Made Env#execute async and removed the callback parameter
* Global errors are detected via addEventListener rather than setting window.onerror
* The `boot` function exported by the core module returns the same object
every time it's called.
* Removed node_boot.js. Use the exported `boot` function instead.
## New features
* Support for parallel execution in Node via the `jasmine` package
See the [parallel guide](https://jasmine.github.io/tutorials/running_specs_in_parallel)
for more information.
* Added Node 20 to supported environments
## Bug fixes
* Accessibility: Always provide a non-color indication that a spec is pending
* Accessibility: Improved contrast of version number and inactive tab links
* Uninstall the global error handler at the end of env execution
## Internal improvements
* Updated dev dependencies
* Dogfood parallel execution feature in CI
## Supported environments
jasmine-core 5.0.0 has been tested in the following environments.
| Environment | Supported versions |
|-------------------|--------------------|
| Node | 18, 20 |
| Safari | 15-16 |
| Chrome | 113 |
| Firefox | 102, 113 |
| Edge | 113 |
------
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_

25
release_notes/5.0.1.md Normal file
View File

@@ -0,0 +1,25 @@
# Jasmine Core 5.0.1 Release Notes
## Changes
* Optionally restore the pre-5.0 behavior of boot() always creating a new instance
This is needed by jasmine-npm (and likely other tools like it) that may
need to create and use multiple envs in sequence.
## Supported environments
jasmine-core 5.0.1 has been tested in the following environments.
| Environment | Supported versions |
|-------------------|--------------------|
| Node | 18, 20 |
| Safari | 15-16 |
| Chrome | 114 |
| Firefox | 102, 113 |
| Edge | 113 |
------
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_

39
release_notes/5.1.0.md Normal file
View File

@@ -0,0 +1,39 @@
# Jasmine Core 5.1.0 Release Notes
## Changes
* Exclude inherited Error properties from stack trace
* Fixed error when formatting Error object with non-Error cause property
Merges [#2013](https://github.com/jasmine/jasmine/pull/2013) from @angrycat9000.
Fixes [#2011](https://github.com/jasmine/jasmine/issues/2011).
* Added `throwUnless` and `throwUnlessAsync`
These are similar to `expect` and `expectAsync` except that they throw
exceptions rather than recording matcher failures as spec/suite failures.
They're intended to support using Jasmine matchers in [testing-library's](https://testing-library.com/)
`waitFor`, and also provide a way to integration-test custom matchers.
Fixes [#2003](https://github.com/jasmine/jasmine/issues/2003).
Fixes [#1980](https://github.com/jasmine/jasmine/issues/1980).
## Supported environments
jasmine-core 5.1.0 has been tested in the following environments.
| Environment | Supported versions |
|-------------------|--------------------|
| Node | 18, 20 |
| Safari | 15-16 |
| Chrome | 114 |
| Firefox | 102, 113 |
| Edge | 113 |
------
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_

View File

@@ -1 +0,0 @@
ordereddict==1.1

View File

@@ -23,17 +23,12 @@ run_browser() {
passfile=`mktemp -t jasmine-results.XXXXXX` || exit 1
failfile=`mktemp -t jasmine-results.XXXXXX` || exit 1
run_browser "internet explorer" 11
run_browser "internet explorer" 10
run_browser chrome latest
run_browser firefox latest
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
run_browser firefox 102
run_browser safari 16
run_browser safari 15
run_browser MicrosoftEdge latest
echo
cat "$passfile" "$failfile"

View File

@@ -1,70 +0,0 @@
from setuptools import setup, find_packages, os
import json
with open('package.json') as packageFile:
version = json.load(packageFile)['version']
short_description=('Jasmine is a Behavior Driven Development testing framework for JavaScript. It does not rely on '+
'browsers, DOM, or any JavaScript framework. Thus it\'s suited for websites, '+
'Node.js (http://nodejs.org) projects, or anywhere that JavaScript can run.')
deprecation=('The Jasmine packages for Python are deprecated. There will be no further\n' +
'releases after the end of the Jasmine 3.x series. We recommend migrating to the\n' +
'following options:\n' +
'\n' +
'* jasmine-browser-runner (<https://github.com/jasmine/jasmine-browser>,\n' +
' `npm install jasmine-browser-runner`) to run specs in browsers, including\n' +
' headless Chrome and Saucelabs. This is the most direct replacement for the\n' +
' jasmine server` and `jasmine ci` commands provided by the `jasmine` Python\n' +
' package.\n' +
'* The jasmine npm package (<https://github.com/jasmine/jasmine-npm>,\n' +
' `npm install jasmine`) to run specs under Node.js.\n' +
'* The standalone distribution from the latest Jasmine release\n' +
' <https://github.com/jasmine/jasmine/releases> to run specs in browsers with\n' +
' no additional tools.\n' +
'* The jasmine-core npm package (`npm install jasmine-core`) if all you need is\n' +
' the Jasmine assets. This is the direct equivalent of the jasmine-core Python\n' +
' package.\n' +
'\n' +
'Except for the standalone distribution, all of the above are distributed through\n'
'npm.\n')
long_description = short_description + '\n\n' + deprecation
setup(
name="jasmine-core",
version=version,
url="http://jasmine.github.io",
author="Pivotal Labs",
author_email="jasmine-js@googlegroups.com",
description=short_description,
long_description=long_description,
long_description_content_type='text/plain',
license='MIT',
classifiers=[
'Development Status :: 5 - Production/Stable',
'Environment :: Console',
'Environment :: Web Environment',
'Framework :: Django',
'Intended Audience :: Developers',
'License :: OSI Approved :: MIT License',
'Operating System :: OS Independent',
'Programming Language :: Python',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.2',
'Programming Language :: Python :: 3.3',
'Programming Language :: Python :: Implementation :: PyPy',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Software Development :: Libraries :: Python Modules',
'Topic :: Software Development :: Build Tools',
'Topic :: Software Development :: Quality Assurance',
'Topic :: Software Development :: Testing',
],
packages=['jasmine_core', 'jasmine_core.images'],
package_dir={'jasmine_core': 'lib/jasmine-core', 'jasmine_core.images': 'images'},
package_data={'jasmine_core': ['*.js', '*.css'], 'jasmine_core.images': ['*.png']},
include_package_data=True,
install_requires=['glob2>=0.4.1', 'ordereddict==1.1']
)

View File

@@ -7,10 +7,13 @@ module.exports = {
semi: 'off',
'key-spacing': 'off',
'space-before-blocks': 'off',
'no-unused-vars': 'off',
'no-trailing-spaces': 'off',
'block-spacing': 'off',
// Additionally, check for unused fn args
// TODO: consider doing this in src files as well as specs
'no-unused-vars': ['error', { args: 'after-used' }],
// Since linting is done at the end of the process and doesn't stop us
// from running tests, it makes sense to fail if debugger statements
// or console references are present.

View File

@@ -1,4 +1,3 @@
/* eslint-disable compat/compat */
describe('AsyncExpectation', function() {
beforeEach(function() {
jasmineUnderTest.Expectation.addAsyncCoreMatchers(
@@ -6,24 +5,9 @@ describe('AsyncExpectation', function() {
);
});
describe('Factory', function() {
it('throws an Error if promises are not available', function() {
var thenable = { then: function() {} },
options = { global: {}, actual: thenable };
function f() {
jasmineUnderTest.Expectation.asyncFactory(options);
}
expect(f).toThrowError(
'expectAsync is unavailable because the environment does not support promises.'
);
});
});
describe('#not', function() {
it('converts a pass to a fail', function() {
jasmine.getEnv().requirePromises();
var addExpectationResult = jasmine.createSpy('addExpectationResult'),
const addExpectationResult = jasmine.createSpy('addExpectationResult'),
actual = Promise.resolve(),
pp = jasmineUnderTest.makePrettyPrinter(),
expectation = jasmineUnderTest.Expectation.asyncFactory({
@@ -44,10 +28,8 @@ describe('AsyncExpectation', function() {
});
it('converts a fail to a pass', function() {
jasmine.getEnv().requirePromises();
var addExpectationResult = jasmine.createSpy('addExpectationResult'),
actual = Promise.reject(),
const addExpectationResult = jasmine.createSpy('addExpectationResult'),
actual = Promise.reject(new Error('nope')),
expectation = jasmineUnderTest.Expectation.asyncFactory({
matchersUtil: new jasmineUnderTest.MatchersUtil({
pp: function() {}
@@ -69,10 +51,9 @@ describe('AsyncExpectation', function() {
});
it('propagates rejections from the comparison function', function() {
jasmine.getEnv().requirePromises();
var error = new Error('ExpectationSpec failure');
const error = new Error('ExpectationSpec failure');
var addExpectationResult = jasmine.createSpy('addExpectationResult'),
const addExpectationResult = jasmine.createSpy('addExpectationResult'),
actual = dummyPromise(),
expectation = jasmineUnderTest.Expectation.asyncFactory({
actual: actual,
@@ -93,9 +74,7 @@ describe('AsyncExpectation', function() {
describe('#withContext', function() {
it('prepends the context to the generated failure message', function() {
jasmine.getEnv().requirePromises();
var matchersUtil = {
const matchersUtil = {
pp: function(val) {
return val.toString();
}
@@ -122,9 +101,7 @@ describe('AsyncExpectation', function() {
});
it('prepends the context to a custom failure message', function() {
jasmine.getEnv().requirePromises();
var matchersUtil = {
const matchersUtil = {
buildFailureMessage: function() {
return 'failure message';
},
@@ -154,15 +131,14 @@ describe('AsyncExpectation', function() {
it('prepends the context to a custom failure message from a function', function() {
pending('should actually work, but no custom matchers for async yet');
jasmine.getEnv().requirePromises();
var matchersUtil = {
const matchersUtil = {
buildFailureMessage: function() {
return 'failure message';
}
},
addExpectationResult = jasmine.createSpy('addExpectationResult'),
actual = Promise.reject(),
actual = Promise.reject(new Error('nope')),
expectation = jasmineUnderTest.Expectation.asyncFactory({
actual: actual,
addExpectationResult: addExpectationResult,
@@ -183,9 +159,7 @@ describe('AsyncExpectation', function() {
});
it('works with #not', function() {
jasmine.getEnv().requirePromises();
var addExpectationResult = jasmine.createSpy('addExpectationResult'),
const addExpectationResult = jasmine.createSpy('addExpectationResult'),
actual = Promise.resolve(),
pp = jasmineUnderTest.makePrettyPrinter(),
expectation = jasmineUnderTest.Expectation.asyncFactory({
@@ -209,9 +183,7 @@ describe('AsyncExpectation', function() {
});
it('works with #not and a custom message', function() {
jasmine.getEnv().requirePromises();
var addExpectationResult = jasmine.createSpy('addExpectationResult'),
const addExpectationResult = jasmine.createSpy('addExpectationResult'),
actual = Promise.resolve('a'),
expectation = jasmineUnderTest.Expectation.asyncFactory({
actual: actual,
@@ -238,26 +210,20 @@ describe('AsyncExpectation', function() {
describe('async matchers', function() {
it('makes custom matchers available to this expectation', function() {
jasmine.getEnv().requirePromises();
var asyncMatchers = {
const asyncMatchers = {
toFoo: function() {},
toBar: function() {}
},
expectation;
expectation = jasmineUnderTest.Expectation.asyncFactory({
customAsyncMatchers: asyncMatchers
});
expectation = jasmineUnderTest.Expectation.asyncFactory({
customAsyncMatchers: asyncMatchers
});
expect(expectation.toFoo).toBeDefined();
expect(expectation.toBar).toBeDefined();
});
it("wraps matchers's compare functions, passing in matcher dependencies", function() {
jasmine.getEnv().requirePromises();
var fakeCompare = function() {
const fakeCompare = function() {
return Promise.resolve({ pass: true });
},
matcherFactory = jasmine
@@ -269,30 +235,21 @@ 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
});
expectation = jasmineUnderTest.Expectation.asyncFactory({
matchersUtil: matchersUtil,
customAsyncMatchers: matchers,
actual: 'an actual',
addExpectationResult: addExpectationResult
});
return expectation.toFoo('hello').then(function() {
expect(matcherFactory).toHaveBeenCalledWith(
matchersUtil,
customEqualityTesters
);
expect(matcherFactory).toHaveBeenCalledWith(matchersUtil);
});
});
it("wraps matchers's compare functions, passing the actual and expected", function() {
jasmine.getEnv().requirePromises();
var fakeCompare = jasmine
const fakeCompare = jasmine
.createSpy('fake-compare')
.and.returnValue(Promise.resolve({ pass: true })),
matchers = {
@@ -306,14 +263,12 @@ describe('AsyncExpectation', function() {
buildFailureMessage: jasmine.createSpy('buildFailureMessage')
},
addExpectationResult = jasmine.createSpy('addExpectationResult'),
expectation;
expectation = jasmineUnderTest.Expectation.asyncFactory({
matchersUtil: matchersUtil,
customAsyncMatchers: matchers,
actual: 'an actual',
addExpectationResult: addExpectationResult
});
expectation = jasmineUnderTest.Expectation.asyncFactory({
matchersUtil: matchersUtil,
customAsyncMatchers: matchers,
actual: 'an actual',
addExpectationResult: addExpectationResult
});
return expectation.toFoo('hello').then(function() {
expect(fakeCompare).toHaveBeenCalledWith('an actual', 'hello');
@@ -321,9 +276,7 @@ describe('AsyncExpectation', function() {
});
it('reports a passing result to the spec when the comparison passes', function() {
jasmine.getEnv().requirePromises();
var matchers = {
const matchers = {
toFoo: function() {
return {
compare: function() {
@@ -336,14 +289,13 @@ describe('AsyncExpectation', function() {
buildFailureMessage: jasmine.createSpy('buildFailureMessage')
},
addExpectationResult = jasmine.createSpy('addExpectationResult'),
errorWithStack = new Error('errorWithStack'),
expectation;
errorWithStack = new Error('errorWithStack');
spyOn(jasmineUnderTest.util, 'errorWithStack').and.returnValue(
errorWithStack
);
expectation = jasmineUnderTest.Expectation.asyncFactory({
const expectation = jasmineUnderTest.Expectation.asyncFactory({
customAsyncMatchers: matchers,
matchersUtil: matchersUtil,
actual: 'an actual',
@@ -364,9 +316,7 @@ describe('AsyncExpectation', function() {
});
it('reports a failing result to the spec when the comparison fails', function() {
jasmine.getEnv().requirePromises();
var matchers = {
const matchers = {
toFoo: function() {
return {
compare: function() {
@@ -381,14 +331,13 @@ describe('AsyncExpectation', function() {
}
},
addExpectationResult = jasmine.createSpy('addExpectationResult'),
errorWithStack = new Error('errorWithStack'),
expectation;
errorWithStack = new Error('errorWithStack');
spyOn(jasmineUnderTest.util, 'errorWithStack').and.returnValue(
errorWithStack
);
expectation = jasmineUnderTest.Expectation.asyncFactory({
const expectation = jasmineUnderTest.Expectation.asyncFactory({
customAsyncMatchers: matchers,
matchersUtil: matchersUtil,
actual: 'an actual',
@@ -409,9 +358,7 @@ describe('AsyncExpectation', function() {
});
it('reports a failing result and a custom fail message to the spec when the comparison fails', function() {
jasmine.getEnv().requirePromises();
var matchers = {
const matchers = {
toFoo: function() {
return {
compare: function() {
@@ -424,14 +371,13 @@ describe('AsyncExpectation', function() {
}
},
addExpectationResult = jasmine.createSpy('addExpectationResult'),
errorWithStack = new Error('errorWithStack'),
expectation;
errorWithStack = new Error('errorWithStack');
spyOn(jasmineUnderTest.util, 'errorWithStack').and.returnValue(
errorWithStack
);
expectation = jasmineUnderTest.Expectation.asyncFactory({
const expectation = jasmineUnderTest.Expectation.asyncFactory({
actual: 'an actual',
customAsyncMatchers: matchers,
addExpectationResult: addExpectationResult
@@ -451,9 +397,7 @@ describe('AsyncExpectation', function() {
});
it('reports a failing result with a custom fail message function to the spec when the comparison fails', function() {
jasmine.getEnv().requirePromises();
var matchers = {
const matchers = {
toFoo: function() {
return {
compare: function() {
@@ -468,14 +412,13 @@ describe('AsyncExpectation', function() {
}
},
addExpectationResult = jasmine.createSpy('addExpectationResult'),
errorWithStack = new Error('errorWithStack'),
expectation;
errorWithStack = new Error('errorWithStack');
spyOn(jasmineUnderTest.util, 'errorWithStack').and.returnValue(
errorWithStack
);
expectation = jasmineUnderTest.Expectation.asyncFactory({
const expectation = jasmineUnderTest.Expectation.asyncFactory({
customAsyncMatchers: matchers,
actual: 'an actual',
addExpectationResult: addExpectationResult
@@ -495,9 +438,7 @@ describe('AsyncExpectation', function() {
});
it('reports a passing result to the spec when the comparison fails for a negative expectation', function() {
jasmine.getEnv().requirePromises();
var matchers = {
const matchers = {
toFoo: function() {
return {
compare: function() {
@@ -508,14 +449,13 @@ describe('AsyncExpectation', function() {
},
addExpectationResult = jasmine.createSpy('addExpectationResult'),
actual = 'an actual',
errorWithStack = new Error('errorWithStack'),
expectation;
errorWithStack = new Error('errorWithStack');
spyOn(jasmineUnderTest.util, 'errorWithStack').and.returnValue(
errorWithStack
);
expectation = jasmineUnderTest.Expectation.asyncFactory({
const expectation = jasmineUnderTest.Expectation.asyncFactory({
customAsyncMatchers: matchers,
actual: 'an actual',
addExpectationResult: addExpectationResult
@@ -535,9 +475,7 @@ describe('AsyncExpectation', function() {
});
it('reports a failing result to the spec when the comparison passes for a negative expectation', function() {
jasmine.getEnv().requirePromises();
var matchers = {
const matchers = {
toFoo: function() {
return {
compare: function() {
@@ -553,14 +491,13 @@ describe('AsyncExpectation', function() {
},
addExpectationResult = jasmine.createSpy('addExpectationResult'),
actual = 'an actual',
errorWithStack = new Error('errorWithStack'),
expectation;
errorWithStack = new Error('errorWithStack');
spyOn(jasmineUnderTest.util, 'errorWithStack').and.returnValue(
errorWithStack
);
expectation = jasmineUnderTest.Expectation.asyncFactory({
const expectation = jasmineUnderTest.Expectation.asyncFactory({
customAsyncMatchers: matchers,
actual: 'an actual',
matchersUtil: matchersUtil,
@@ -581,9 +518,7 @@ describe('AsyncExpectation', function() {
});
it('reports a failing result and a custom fail message to the spec when the comparison passes for a negative expectation', function() {
jasmine.getEnv().requirePromises();
var matchers = {
const matchers = {
toFoo: function() {
return {
compare: function() {
@@ -597,14 +532,13 @@ describe('AsyncExpectation', function() {
},
addExpectationResult = jasmine.createSpy('addExpectationResult'),
actual = 'an actual',
errorWithStack = new Error('errorWithStack'),
expectation;
errorWithStack = new Error('errorWithStack');
spyOn(jasmineUnderTest.util, 'errorWithStack').and.returnValue(
errorWithStack
);
expectation = jasmineUnderTest.Expectation.asyncFactory({
const expectation = jasmineUnderTest.Expectation.asyncFactory({
customAsyncMatchers: matchers,
actual: 'an actual',
addExpectationResult: addExpectationResult
@@ -624,9 +558,7 @@ describe('AsyncExpectation', function() {
});
it("reports a passing result to the spec when the 'not' comparison passes, given a negativeCompare", function() {
jasmine.getEnv().requirePromises();
var matchers = {
const matchers = {
toFoo: function() {
return {
compare: function() {
@@ -640,14 +572,13 @@ describe('AsyncExpectation', function() {
},
addExpectationResult = jasmine.createSpy('addExpectationResult'),
actual = 'an actual',
errorWithStack = new Error('errorWithStack'),
expectation;
errorWithStack = new Error('errorWithStack');
spyOn(jasmineUnderTest.util, 'errorWithStack').and.returnValue(
errorWithStack
);
expectation = jasmineUnderTest.Expectation.asyncFactory({
const expectation = jasmineUnderTest.Expectation.asyncFactory({
customAsyncMatchers: matchers,
actual: 'an actual',
addExpectationResult: addExpectationResult
@@ -667,9 +598,7 @@ describe('AsyncExpectation', function() {
});
it("reports a failing result and a custom fail message to the spec when the 'not' comparison fails, given a negativeCompare", function() {
jasmine.getEnv().requirePromises();
var matchers = {
const matchers = {
toFoo: function() {
return {
compare: function() {
@@ -686,14 +615,13 @@ describe('AsyncExpectation', function() {
},
addExpectationResult = jasmine.createSpy('addExpectationResult'),
actual = 'an actual',
errorWithStack = new Error('errorWithStack'),
expectation;
errorWithStack = new Error('errorWithStack');
spyOn(jasmineUnderTest.util, 'errorWithStack').and.returnValue(
errorWithStack
);
expectation = jasmineUnderTest.Expectation.asyncFactory({
const expectation = jasmineUnderTest.Expectation.asyncFactory({
customAsyncMatchers: matchers,
actual: 'an actual',
addExpectationResult: addExpectationResult
@@ -713,10 +641,8 @@ describe('AsyncExpectation', function() {
});
it('reports errorWithStack when a custom error message is returned', function() {
jasmine.getEnv().requirePromises();
var customError = new Error('I am a custom error');
var matchers = {
const customError = new Error('I am a custom error');
const matchers = {
toFoo: function() {
return {
compare: function() {
@@ -730,14 +656,13 @@ describe('AsyncExpectation', function() {
}
},
addExpectationResult = jasmine.createSpy('addExpectationResult'),
errorWithStack = new Error('errorWithStack'),
expectation;
errorWithStack = new Error('errorWithStack');
spyOn(jasmineUnderTest.util, 'errorWithStack').and.returnValue(
errorWithStack
);
expectation = jasmineUnderTest.Expectation.asyncFactory({
const expectation = jasmineUnderTest.Expectation.asyncFactory({
actual: 'an actual',
customAsyncMatchers: matchers,
addExpectationResult: addExpectationResult
@@ -757,9 +682,7 @@ describe('AsyncExpectation', function() {
});
it("reports a custom message to the spec when a 'not' comparison fails", function() {
jasmine.getEnv().requirePromises();
var matchers = {
const matchers = {
toFoo: function() {
return {
compare: function() {
@@ -772,14 +695,13 @@ describe('AsyncExpectation', function() {
}
},
addExpectationResult = jasmine.createSpy('addExpectationResult'),
errorWithStack = new Error('errorWithStack'),
expectation;
errorWithStack = new Error('errorWithStack');
spyOn(jasmineUnderTest.util, 'errorWithStack').and.returnValue(
errorWithStack
);
expectation = jasmineUnderTest.Expectation.asyncFactory({
const expectation = jasmineUnderTest.Expectation.asyncFactory({
actual: 'an actual',
customAsyncMatchers: matchers,
addExpectationResult: addExpectationResult
@@ -799,9 +721,7 @@ describe('AsyncExpectation', function() {
});
it("reports a custom message func to the spec when a 'not' comparison fails", function() {
jasmine.getEnv().requirePromises();
var matchers = {
const matchers = {
toFoo: function() {
return {
compare: function() {
@@ -816,14 +736,13 @@ describe('AsyncExpectation', function() {
}
},
addExpectationResult = jasmine.createSpy('addExpectationResult'),
errorWithStack = new Error('errorWithStack'),
expectation;
errorWithStack = new Error('errorWithStack');
spyOn(jasmineUnderTest.util, 'errorWithStack').and.returnValue(
errorWithStack
);
expectation = jasmineUnderTest.Expectation.asyncFactory({
let expectation = jasmineUnderTest.Expectation.asyncFactory({
actual: 'an actual',
customAsyncMatchers: matchers,
addExpectationResult: addExpectationResult
@@ -844,6 +763,6 @@ describe('AsyncExpectation', function() {
});
function dummyPromise() {
return new Promise(function(resolve, reject) {});
return new Promise(function() {});
}
});

View File

@@ -1,6 +1,6 @@
describe('CallTracker', function() {
it('tracks that it was called when executed', function() {
var callTracker = new jasmineUnderTest.CallTracker();
const callTracker = new jasmineUnderTest.CallTracker();
expect(callTracker.any()).toBe(false);
@@ -10,7 +10,7 @@ describe('CallTracker', function() {
});
it('tracks that number of times that it is executed', function() {
var callTracker = new jasmineUnderTest.CallTracker();
const callTracker = new jasmineUnderTest.CallTracker();
expect(callTracker.count()).toEqual(0);
@@ -20,7 +20,7 @@ describe('CallTracker', function() {
});
it('tracks the params from each execution', function() {
var callTracker = new jasmineUnderTest.CallTracker();
const callTracker = new jasmineUnderTest.CallTracker();
callTracker.track({ object: void 0, args: [] });
callTracker.track({ object: {}, args: [0, 'foo'] });
@@ -31,9 +31,9 @@ describe('CallTracker', function() {
});
it("tracks the 'this' object from each execution", function() {
var callTracker = new jasmineUnderTest.CallTracker();
const callTracker = new jasmineUnderTest.CallTracker();
var this0 = {},
const this0 = {},
this1 = {};
callTracker.track({ object: this0, args: [] });
callTracker.track({ object: this1, args: [] });
@@ -45,13 +45,13 @@ describe('CallTracker', function() {
});
it('returns any empty array when there was no call', function() {
var callTracker = new jasmineUnderTest.CallTracker();
const callTracker = new jasmineUnderTest.CallTracker();
expect(callTracker.argsFor(0)).toEqual([]);
});
it('allows access for the arguments for all calls', function() {
var callTracker = new jasmineUnderTest.CallTracker();
const callTracker = new jasmineUnderTest.CallTracker();
callTracker.track({ object: {}, args: [] });
callTracker.track({ object: {}, args: [0, 'foo'] });
@@ -60,7 +60,7 @@ describe('CallTracker', function() {
});
it('tracks the context and arguments for each call', function() {
var callTracker = new jasmineUnderTest.CallTracker();
const callTracker = new jasmineUnderTest.CallTracker();
callTracker.track({ object: {}, args: [] });
callTracker.track({ object: {}, args: [0, 'foo'] });
@@ -71,7 +71,7 @@ describe('CallTracker', function() {
});
it('simplifies access to the arguments for the last (most recent) call', function() {
var callTracker = new jasmineUnderTest.CallTracker();
const callTracker = new jasmineUnderTest.CallTracker();
callTracker.track();
callTracker.track({ object: {}, args: [0, 'foo'] });
@@ -83,13 +83,13 @@ describe('CallTracker', function() {
});
it("returns a useful falsy value when there isn't a last (most recent) call", function() {
var callTracker = new jasmineUnderTest.CallTracker();
const callTracker = new jasmineUnderTest.CallTracker();
expect(callTracker.mostRecent()).toBeFalsy();
});
it('simplifies access to the arguments for the first (oldest) call', function() {
var callTracker = new jasmineUnderTest.CallTracker();
const callTracker = new jasmineUnderTest.CallTracker();
callTracker.track({ object: {}, args: [0, 'foo'] });
@@ -97,13 +97,13 @@ describe('CallTracker', function() {
});
it("returns a useful falsy value when there isn't a first (oldest) call", function() {
var callTracker = new jasmineUnderTest.CallTracker();
const callTracker = new jasmineUnderTest.CallTracker();
expect(callTracker.first()).toBeFalsy();
});
it('allows the tracking to be reset', function() {
var callTracker = new jasmineUnderTest.CallTracker();
const callTracker = new jasmineUnderTest.CallTracker();
callTracker.track();
callTracker.track({ object: {}, args: [0, 'foo'] });
@@ -117,10 +117,10 @@ describe('CallTracker', function() {
});
it('allows object arguments to be shallow cloned', function() {
var callTracker = new jasmineUnderTest.CallTracker();
const callTracker = new jasmineUnderTest.CallTracker();
callTracker.saveArgumentsByValue();
var objectArg = { foo: 'bar' },
const objectArg = { foo: 'bar' },
arrayArg = ['foo', 'bar'];
callTracker.track({
@@ -135,7 +135,7 @@ describe('CallTracker', function() {
});
it('saves primitive arguments by value', function() {
var callTracker = new jasmineUnderTest.CallTracker(),
const callTracker = new jasmineUnderTest.CallTracker(),
args = [undefined, null, false, '', /\s/, 0, 1.2, NaN];
callTracker.saveArgumentsByValue();

View File

@@ -1,6 +1,6 @@
describe('ClearStack', function() {
it('works in an integrationy way', function(done) {
var clearStack = jasmineUnderTest.getClearStack(
const clearStack = jasmineUnderTest.getClearStack(
jasmineUnderTest.getGlobal()
);
@@ -9,158 +9,216 @@ describe('ClearStack', function() {
});
});
it('uses setImmediate when available', function() {
var setImmediate = jasmine
.createSpy('setImmediate')
.and.callFake(function(fn) {
describe('in Safari', function() {
usesQueueMicrotaskWithSetTimeout(function() {
return {
navigator: {
userAgent:
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/605.0.8 (KHTML, like Gecko) Version/15.1 Safari/605.0.8'
},
// queueMicrotask should be used even though MessageChannel is present
MessageChannel: fakeMessageChannel
};
});
});
describe('in browsers other than Safari', function() {
usesMessageChannel(function() {
return {
navigator: {
// Chrome's user agent string contains "Safari" so it's a good test case
userAgent:
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36'
}
};
});
describe('when MessageChannel is unavailable', function() {
usesQueueMicrotaskWithSetTimeout(function() {
return {
navigator: {
userAgent: 'CERN-LineMode/2.15 libwww/2.17b3',
MessageChannel: undefined
}
};
});
});
});
describe('in Node', function() {
usesQueueMicrotaskWithoutSetTimeout(function() {
return {
process: {
versions: {
node: '3.1415927'
}
}
};
});
});
function usesMessageChannel(makeGlobal) {
it('uses MessageChannel', function() {
const global = {
...makeGlobal(),
MessageChannel: fakeMessageChannel
};
const clearStack = jasmineUnderTest.getClearStack(global);
let called = false;
clearStack(function() {
called = true;
});
expect(called).toBe(true);
});
it('uses setTimeout instead of MessageChannel every 10 calls to make sure we release the CPU', function() {
const fakeChannel = fakeMessageChannel();
spyOn(fakeChannel.port2, 'postMessage');
const setTimeout = jasmine.createSpy('setTimeout');
const global = {
...makeGlobal(),
setTimeout,
MessageChannel: function() {
return fakeChannel;
}
};
const clearStack = jasmineUnderTest.getClearStack(global);
for (let i = 0; i < 9; i++) {
clearStack(function() {});
}
expect(fakeChannel.port2.postMessage).toHaveBeenCalled();
expect(setTimeout).not.toHaveBeenCalled();
clearStack(function() {});
expect(fakeChannel.port2.postMessage).toHaveBeenCalledTimes(9);
expect(setTimeout).toHaveBeenCalledTimes(1);
clearStack(function() {});
expect(fakeChannel.port2.postMessage).toHaveBeenCalledTimes(10);
expect(setTimeout).toHaveBeenCalledTimes(1);
});
it('calls setTimeout when onmessage is called recursively', function() {
const setTimeout = jasmine.createSpy('setTimeout');
const global = {
...makeGlobal(),
setTimeout,
MessageChannel: fakeMessageChannel
};
const clearStack = jasmineUnderTest.getClearStack(global);
const fn = jasmine.createSpy('second clearStack function');
clearStack(function() {
clearStack(fn);
});
expect(fn).not.toHaveBeenCalled();
expect(setTimeout).toHaveBeenCalledWith(fn, 0);
});
}
function usesQueueMicrotaskWithSetTimeout(makeGlobal) {
it('uses queueMicrotask', function() {
const global = {
...makeGlobal(),
queueMicrotask: function(fn) {
fn();
}),
global = { setImmediate: setImmediate },
clearStack = jasmineUnderTest.getClearStack(global),
called = false;
}
};
const clearStack = jasmineUnderTest.getClearStack(global);
let called = false;
clearStack(function() {
called = true;
clearStack(function() {
called = true;
});
expect(called).toBe(true);
});
expect(called).toBe(true);
expect(setImmediate).toHaveBeenCalled();
});
it('uses setTimeout instead of queueMicrotask every 10 calls to make sure we release the CPU', function() {
const queueMicrotask = jasmine.createSpy('queueMicrotask');
const setTimeout = jasmine.createSpy('setTimeout');
const global = {
...makeGlobal(),
queueMicrotask,
setTimeout
};
const clearStack = jasmineUnderTest.getClearStack(global);
it('uses setTimeout instead of setImmediate every 10 calls to make sure we release the CPU', function() {
var setImmediate = jasmine.createSpy('setImmediate'),
setTimeout = jasmine.createSpy('setTimeout'),
global = { setImmediate: setImmediate, setTimeout: setTimeout },
clearStack = jasmineUnderTest.getClearStack(global);
for (let i = 0; i < 9; i++) {
clearStack(function() {});
}
clearStack(function() {});
clearStack(function() {});
clearStack(function() {});
clearStack(function() {});
clearStack(function() {});
clearStack(function() {});
clearStack(function() {});
clearStack(function() {});
clearStack(function() {});
expect(queueMicrotask).toHaveBeenCalled();
expect(setTimeout).not.toHaveBeenCalled();
expect(setImmediate).toHaveBeenCalled();
expect(setTimeout).not.toHaveBeenCalled();
clearStack(function() {});
expect(queueMicrotask).toHaveBeenCalledTimes(9);
expect(setTimeout).toHaveBeenCalledTimes(1);
clearStack(function() {});
expect(setImmediate.calls.count()).toEqual(9);
expect(setTimeout.calls.count()).toEqual(1);
clearStack(function() {});
expect(queueMicrotask).toHaveBeenCalledTimes(10);
expect(setTimeout).toHaveBeenCalledTimes(1);
});
}
clearStack(function() {});
expect(setImmediate.calls.count()).toEqual(10);
expect(setTimeout.calls.count()).toEqual(1);
});
it('uses MessageChannels when available', function() {
var fakeChannel = {
port1: {},
port2: {
postMessage: function() {
fakeChannel.port1.onmessage();
}
function usesQueueMicrotaskWithoutSetTimeout(makeGlobal) {
it('uses queueMicrotask', function() {
const global = {
...makeGlobal(),
queueMicrotask: function(fn) {
fn();
}
},
global = {
MessageChannel: function() {
return fakeChannel;
}
},
clearStack = jasmineUnderTest.getClearStack(global),
called = false;
};
const clearStack = jasmineUnderTest.getClearStack(global);
let called = false;
clearStack(function() {
called = true;
clearStack(function() {
called = true;
});
expect(called).toBe(true);
});
expect(called).toBe(true);
});
it('does not use setTimeout', function() {
const queueMicrotask = jasmine.createSpy('queueMicrotask');
const setTimeout = jasmine.createSpy('setTimeout');
const global = {
...makeGlobal(),
queueMicrotask,
setTimeout
};
const clearStack = jasmineUnderTest.getClearStack(global);
it('uses setTimeout instead of MessageChannel every 10 calls to make sure we release the CPU', function() {
var fakeChannel = {
port1: {},
port2: {
postMessage: jasmine
.createSpy('postMessage')
.and.callFake(function() {
fakeChannel.port1.onmessage();
})
}
},
setTimeout = jasmine.createSpy('setTimeout'),
global = {
MessageChannel: function() {
return fakeChannel;
},
setTimeout: setTimeout
},
clearStack = jasmineUnderTest.getClearStack(global);
clearStack(function() {});
clearStack(function() {});
clearStack(function() {});
clearStack(function() {});
clearStack(function() {});
clearStack(function() {});
clearStack(function() {});
clearStack(function() {});
clearStack(function() {});
clearStack(function() {});
clearStack(function() {});
clearStack(function() {});
clearStack(function() {});
clearStack(function() {});
clearStack(function() {});
clearStack(function() {});
clearStack(function() {});
clearStack(function() {});
clearStack(function() {});
expect(fakeChannel.port2.postMessage).toHaveBeenCalled();
expect(setTimeout).not.toHaveBeenCalled();
clearStack(function() {});
expect(fakeChannel.port2.postMessage.calls.count()).toEqual(9);
expect(setTimeout.calls.count()).toEqual(1);
clearStack(function() {});
expect(fakeChannel.port2.postMessage.calls.count()).toEqual(10);
expect(setTimeout.calls.count()).toEqual(1);
});
it('calls setTimeout when onmessage is called recursively', function() {
var fakeChannel = {
port1: {},
port2: {
postMessage: function() {
fakeChannel.port1.onmessage();
}
}
},
setTimeout = jasmine.createSpy('setTimeout'),
global = {
MessageChannel: function() {
return fakeChannel;
},
setTimeout: setTimeout
},
clearStack = jasmineUnderTest.getClearStack(global),
fn = jasmine.createSpy('second clearStack function');
clearStack(function() {
clearStack(fn);
expect(queueMicrotask).toHaveBeenCalledTimes(10);
expect(setTimeout).not.toHaveBeenCalled();
});
}
expect(fn).not.toHaveBeenCalled();
expect(setTimeout).toHaveBeenCalledWith(fn, 0);
});
it('falls back to setTimeout', function() {
var setTimeout = jasmine.createSpy('setTimeout').and.callFake(function(fn) {
fn();
}),
global = { setTimeout: setTimeout },
clearStack = jasmineUnderTest.getClearStack(global),
called = false;
clearStack(function() {
called = true;
});
expect(called).toBe(true);
expect(setTimeout).toHaveBeenCalledWith(jasmine.any(Function), 0);
});
function fakeMessageChannel() {
const channel = {
port1: {},
port2: {
postMessage: function() {
channel.port1.onmessage();
}
}
};
return channel;
}
});

View File

@@ -1,11 +1,11 @@
describe('Clock', function() {
var NODE_JS =
const NODE_JS =
typeof process !== 'undefined' &&
process.versions &&
typeof process.versions.node === 'string';
it('does not replace setTimeout until it is installed', function() {
var fakeSetTimeout = jasmine.createSpy('global setTimeout'),
const fakeSetTimeout = jasmine.createSpy('global setTimeout'),
fakeGlobal = { setTimeout: fakeSetTimeout },
delayedFunctionScheduler = jasmine.createSpyObj(
'delayedFunctionScheduler',
@@ -40,7 +40,7 @@ describe('Clock', function() {
});
it('does not replace clearTimeout until it is installed', function() {
var fakeClearTimeout = jasmine.createSpy('global cleartimeout'),
const fakeClearTimeout = jasmine.createSpy('global cleartimeout'),
fakeGlobal = { clearTimeout: fakeClearTimeout },
delayedFunctionScheduler = jasmine.createSpyObj(
'delayedFunctionScheduler',
@@ -76,7 +76,7 @@ describe('Clock', function() {
});
it('does not replace setInterval until it is installed', function() {
var fakeSetInterval = jasmine.createSpy('global setInterval'),
const fakeSetInterval = jasmine.createSpy('global setInterval'),
fakeGlobal = { setInterval: fakeSetInterval },
delayedFunctionScheduler = jasmine.createSpyObj(
'delayedFunctionScheduler',
@@ -111,7 +111,7 @@ describe('Clock', function() {
});
it('does not replace clearInterval until it is installed', function() {
var fakeClearInterval = jasmine.createSpy('global clearinterval'),
const fakeClearInterval = jasmine.createSpy('global clearinterval'),
fakeGlobal = { clearInterval: fakeClearInterval },
delayedFunctionScheduler = jasmine.createSpyObj(
'delayedFunctionScheduler',
@@ -147,7 +147,7 @@ describe('Clock', function() {
});
it('does not install if the current setTimeout is not the original function on the global', function() {
var originalFakeSetTimeout = function() {},
const originalFakeSetTimeout = function() {},
replacedSetTimeout = function() {},
fakeGlobal = { setTimeout: originalFakeSetTimeout },
delayedFunctionSchedulerFactory = jasmine.createSpy(
@@ -171,7 +171,7 @@ describe('Clock', function() {
});
it('does not install if the current clearTimeout is not the original function on the global', function() {
var originalFakeClearTimeout = function() {},
const originalFakeClearTimeout = function() {},
replacedClearTimeout = function() {},
fakeGlobal = { clearTimeout: originalFakeClearTimeout },
delayedFunctionSchedulerFactory = jasmine.createSpy(
@@ -195,7 +195,7 @@ describe('Clock', function() {
});
it('does not install if the current setInterval is not the original function on the global', function() {
var originalFakeSetInterval = function() {},
const originalFakeSetInterval = function() {},
replacedSetInterval = function() {},
fakeGlobal = { setInterval: originalFakeSetInterval },
delayedFunctionSchedulerFactory = jasmine.createSpy(
@@ -219,7 +219,7 @@ describe('Clock', function() {
});
it('does not install if the current clearInterval is not the original function on the global', function() {
var originalFakeClearInterval = function() {},
const originalFakeClearInterval = function() {},
replacedClearInterval = function() {},
fakeGlobal = { clearInterval: originalFakeClearInterval },
delayedFunctionSchedulerFactory = jasmine.createSpy(
@@ -243,7 +243,7 @@ describe('Clock', function() {
});
it('replaces the global timer functions on uninstall', function() {
var fakeSetTimeout = jasmine.createSpy('global setTimeout'),
const fakeSetTimeout = jasmine.createSpy('global setTimeout'),
fakeClearTimeout = jasmine.createSpy('global clearTimeout'),
fakeSetInterval = jasmine.createSpy('global setInterval'),
fakeClearInterval = jasmine.createSpy('global clearInterval'),
@@ -286,7 +286,7 @@ describe('Clock', function() {
});
it('can be installed for the duration of a passed in function and uninstalled when done', function() {
var fakeSetTimeout = jasmine.createSpy('global setTimeout'),
const fakeSetTimeout = jasmine.createSpy('global setTimeout'),
fakeClearTimeout = jasmine.createSpy('global clearTimeout'),
fakeSetInterval = jasmine.createSpy('global setInterval'),
fakeClearInterval = jasmine.createSpy('global clearInterval'),
@@ -312,8 +312,8 @@ describe('Clock', function() {
return delayedFunctionScheduler;
},
mockDate
),
passedFunctionCalled = false;
);
let passedFunctionCalled = false;
clock.withMock(function() {
fakeGlobal.setTimeout(delayedFn, 0);
@@ -346,7 +346,7 @@ describe('Clock', function() {
});
it('can be installed for the duration of a passed in function and uninstalled if an error is thrown', function() {
var fakeSetTimeout = jasmine.createSpy('global setTimeout'),
const fakeSetTimeout = jasmine.createSpy('global setTimeout'),
fakeClearTimeout = jasmine.createSpy('global clearTimeout'),
fakeSetInterval = jasmine.createSpy('global setInterval'),
fakeClearInterval = jasmine.createSpy('global clearInterval'),
@@ -372,8 +372,8 @@ describe('Clock', function() {
return delayedFunctionScheduler;
},
mockDate
),
passedFunctionCalled = false;
);
let passedFunctionCalled = false;
expect(function() {
clock.withMock(function() {
@@ -409,7 +409,7 @@ describe('Clock', function() {
});
it('schedules the delayed function (via setTimeout) with the fake timer', function() {
var fakeSetTimeout = jasmine.createSpy('setTimeout'),
const fakeSetTimeout = jasmine.createSpy('setTimeout'),
scheduleFunction = jasmine.createSpy('scheduleFunction'),
delayedFunctionScheduler = { scheduleFunction: scheduleFunction },
fakeGlobal = { setTimeout: fakeSetTimeout },
@@ -451,7 +451,7 @@ describe('Clock', function() {
});
it('returns an id for the delayed function', function() {
var fakeSetTimeout = jasmine.createSpy('setTimeout'),
const fakeSetTimeout = jasmine.createSpy('setTimeout'),
scheduleId = 123,
scheduleFunction = jasmine
.createSpy('scheduleFunction')
@@ -470,11 +470,10 @@ describe('Clock', function() {
return delayedFunctionScheduler;
},
mockDate
),
timeout;
);
clock.install();
timeout = clock.setTimeout(delayedFn, 0);
const timeout = clock.setTimeout(delayedFn, 0);
if (!NODE_JS) {
expect(timeout).toEqual(123);
@@ -484,7 +483,7 @@ describe('Clock', function() {
});
it('clears the scheduled function with the scheduler', function() {
var fakeClearTimeout = jasmine.createSpy('clearTimeout'),
const fakeClearTimeout = jasmine.createSpy('clearTimeout'),
delayedFunctionScheduler = jasmine.createSpyObj(
'delayedFunctionScheduler',
['removeFunctionWithId']
@@ -513,7 +512,7 @@ describe('Clock', function() {
});
it('schedules the delayed function with the fake timer', function() {
var fakeSetInterval = jasmine.createSpy('setInterval'),
const fakeSetInterval = jasmine.createSpy('setInterval'),
scheduleFunction = jasmine.createSpy('scheduleFunction'),
delayedFunctionScheduler = { scheduleFunction: scheduleFunction },
fakeGlobal = { setInterval: fakeSetInterval },
@@ -556,7 +555,7 @@ describe('Clock', function() {
});
it('returns an id for the delayed function', function() {
var fakeSetInterval = jasmine.createSpy('setInterval'),
const fakeSetInterval = jasmine.createSpy('setInterval'),
scheduleId = 123,
scheduleFunction = jasmine
.createSpy('scheduleFunction')
@@ -575,11 +574,10 @@ describe('Clock', function() {
return delayedFunctionScheduler;
},
mockDate
),
interval;
);
clock.install();
interval = clock.setInterval(delayedFn, 0);
const interval = clock.setInterval(delayedFn, 0);
if (!NODE_JS) {
expect(interval).toEqual(123);
@@ -589,7 +587,7 @@ describe('Clock', function() {
});
it('clears the scheduled function with the scheduler', function() {
var clearInterval = jasmine.createSpy('clearInterval'),
const clearInterval = jasmine.createSpy('clearInterval'),
delayedFunctionScheduler = jasmine.createSpyObj(
'delayedFunctionScheduler',
['removeFunctionWithId']
@@ -618,7 +616,7 @@ describe('Clock', function() {
});
it('gives you a friendly reminder if the Clock is not installed and you tick', function() {
var clock = new jasmineUnderTest.Clock(
const clock = new jasmineUnderTest.Clock(
{},
jasmine.createSpyObj('delayedFunctionScheduler', ['tick'])
);
@@ -630,7 +628,7 @@ describe('Clock', function() {
describe('Clock (acceptance)', function() {
it('can run setTimeouts/setIntervals synchronously', function() {
var delayedFn1 = jasmine.createSpy('delayedFn1'),
const delayedFn1 = jasmine.createSpy('delayedFn1'),
delayedFn2 = jasmine.createSpy('delayedFn2'),
delayedFn3 = jasmine.createSpy('delayedFn3'),
recurring1 = jasmine.createSpy('recurring1'),
@@ -651,7 +649,7 @@ describe('Clock (acceptance)', function() {
clock.install();
clock.setTimeout(delayedFn1, 0);
var intervalId = clock.setInterval(recurring1, 50);
const intervalId = clock.setInterval(recurring1, 50);
clock.setTimeout(delayedFn2, 100);
clock.setTimeout(delayedFn3, 200);
@@ -690,7 +688,7 @@ describe('Clock (acceptance)', function() {
});
it('can clear a previously set timeout', function() {
var clearedFn = jasmine.createSpy('clearedFn'),
const clearedFn = jasmine.createSpy('clearedFn'),
delayedFunctionScheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
mockDate = {
install: function() {},
@@ -703,12 +701,11 @@ describe('Clock (acceptance)', function() {
return delayedFunctionScheduler;
},
mockDate
),
timeoutId;
);
clock.install();
timeoutId = clock.setTimeout(clearedFn, 100);
const timeoutId = clock.setTimeout(clearedFn, 100);
expect(clearedFn).not.toHaveBeenCalled();
clock.clearTimeout(timeoutId);
@@ -718,7 +715,7 @@ describe('Clock (acceptance)', function() {
});
it("can clear a previously set interval using that interval's handler", function() {
var spy = jasmine.createSpy('spy'),
const spy = jasmine.createSpy('spy'),
delayedFunctionScheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
mockDate = {
install: function() {},
@@ -731,12 +728,11 @@ describe('Clock (acceptance)', function() {
return delayedFunctionScheduler;
},
mockDate
),
intervalId;
);
clock.install();
intervalId = clock.setInterval(function() {
const intervalId = clock.setInterval(function() {
spy();
clock.clearInterval(intervalId);
}, 100);
@@ -746,7 +742,7 @@ describe('Clock (acceptance)', function() {
});
it('correctly schedules functions after the Clock has advanced', function() {
var delayedFn1 = jasmine.createSpy('delayedFn1'),
const delayedFn1 = jasmine.createSpy('delayedFn1'),
delayedFunctionScheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
mockDate = {
install: function() {},
@@ -772,7 +768,7 @@ describe('Clock (acceptance)', function() {
});
it('correctly schedules functions while the Clock is advancing', function() {
var delayedFn1 = jasmine.createSpy('delayedFn1'),
const delayedFn1 = jasmine.createSpy('delayedFn1'),
delayedFn2 = jasmine.createSpy('delayedFn2'),
delayedFunctionScheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
mockDate = {
@@ -803,7 +799,7 @@ describe('Clock (acceptance)', function() {
});
it('correctly calls functions scheduled while the Clock is advancing', function() {
var delayedFn1 = jasmine.createSpy('delayedFn1'),
const delayedFn1 = jasmine.createSpy('delayedFn1'),
delayedFn2 = jasmine.createSpy('delayedFn2'),
delayedFunctionScheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
mockDate = {
@@ -831,7 +827,7 @@ describe('Clock (acceptance)', function() {
});
it('correctly schedules functions scheduled while the Clock is advancing but after the Clock is uninstalled', function() {
var delayedFn1 = jasmine.createSpy('delayedFn1'),
const delayedFn1 = jasmine.createSpy('delayedFn1'),
delayedFn2 = jasmine.createSpy('delayedFn2'),
delayedFunctionScheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
mockDate = {
@@ -865,7 +861,7 @@ describe('Clock (acceptance)', function() {
});
it('does not mock the Date object by default', function() {
var delayedFunctionScheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
const delayedFunctionScheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
global = { Date: Date },
mockDate = new jasmineUnderTest.MockDate(global),
clock = new jasmineUnderTest.Clock(
@@ -880,7 +876,7 @@ describe('Clock (acceptance)', function() {
expect(global.Date).toEqual(Date);
var now = new global.Date().getTime();
const now = new global.Date().getTime();
clock.tick(50);
@@ -888,7 +884,7 @@ describe('Clock (acceptance)', function() {
});
it('mocks the Date object and sets it to current time', function() {
var delayedFunctionScheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
const delayedFunctionScheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
global = { Date: Date },
mockDate = new jasmineUnderTest.MockDate(global),
clock = new jasmineUnderTest.Clock(
@@ -901,13 +897,13 @@ describe('Clock (acceptance)', function() {
clock.install().mockDate();
var now = new global.Date().getTime();
const now = new global.Date().getTime();
clock.tick(50);
expect(new global.Date().getTime() - now).toEqual(50);
var timeoutDate = 0;
let timeoutDate = 0;
clock.setTimeout(function() {
timeoutDate = new global.Date().getTime();
}, 100);
@@ -918,7 +914,7 @@ describe('Clock (acceptance)', function() {
});
it('mocks the Date object and sets it to a given time', function() {
var delayedFunctionScheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
const delayedFunctionScheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
global = { Date: Date },
mockDate = new jasmineUnderTest.MockDate(global),
clock = new jasmineUnderTest.Clock(
@@ -932,7 +928,7 @@ describe('Clock (acceptance)', function() {
clock.install().mockDate(baseTime);
var now = new global.Date().getTime();
const now = new global.Date().getTime();
expect(now).toEqual(baseTime.getTime());
@@ -940,7 +936,7 @@ describe('Clock (acceptance)', function() {
expect(new global.Date().getTime()).toEqual(baseTime.getTime() + 50);
var timeoutDate = 0;
let timeoutDate = 0;
clock.setTimeout(function() {
timeoutDate = new global.Date().getTime();
}, 100);
@@ -950,8 +946,26 @@ describe('Clock (acceptance)', function() {
expect(timeoutDate).toEqual(baseTime.getTime() + 150);
});
it('throws mockDate is called with a non-Date', function() {
const delayedFunctionScheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
global = { Date: Date },
mockDate = new jasmineUnderTest.MockDate(global),
clock = new jasmineUnderTest.Clock(
{ setTimeout: setTimeout },
function() {
return delayedFunctionScheduler;
},
mockDate
);
expect(() => clock.mockDate(12345)).toThrowError(
'The argument to jasmine.clock().mockDate(), if specified, should be ' +
'a Date instance.'
);
});
it('mocks the Date object and updates the date per delayed function', function() {
var delayedFunctionScheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
const delayedFunctionScheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
global = { Date: Date },
mockDate = new jasmineUnderTest.MockDate(global),
clock = new jasmineUnderTest.Clock(
@@ -965,8 +979,8 @@ describe('Clock (acceptance)', function() {
clock.install().mockDate(baseTime);
var actualTimes = [];
var pushCurrentTime = function() {
const actualTimes = [];
const pushCurrentTime = function() {
actualTimes.push(global.Date().getTime());
};
delayedFunctionScheduler.scheduleFunction(pushCurrentTime);
@@ -990,7 +1004,7 @@ describe('Clock (acceptance)', function() {
});
it('correctly clears a scheduled timeout while the Clock is advancing', function() {
var delayedFunctionScheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
const delayedFunctionScheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
global = { Date: Date, setTimeout: undefined },
mockDate = new jasmineUnderTest.MockDate(global),
clock = new jasmineUnderTest.Clock(
@@ -1003,7 +1017,7 @@ describe('Clock (acceptance)', function() {
clock.install();
var timerId2;
let timerId2;
global.setTimeout(function() {
global.clearTimeout(timerId2);
@@ -1015,7 +1029,7 @@ describe('Clock (acceptance)', function() {
});
it('correctly clears a scheduled interval while the Clock is advancing', function() {
var delayedFunctionScheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
const delayedFunctionScheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
global = { Date: Date, setTimeout: undefined },
mockDate = new jasmineUnderTest.MockDate(global),
clock = new jasmineUnderTest.Clock(
@@ -1028,7 +1042,7 @@ describe('Clock (acceptance)', function() {
clock.install();
var timerId2;
let timerId2;
global.setInterval(function() {
global.clearInterval(timerId2);
}, 100);

View File

@@ -0,0 +1,131 @@
describe('CompleteOnFirstErrorSkipPolicy', function() {
describe('#skipTo', function() {
describe('Before anything has errored', function() {
it('returns the next index', function() {
const policy = new jasmineUnderTest.CompleteOnFirstErrorSkipPolicy(
arrayOfArbitraryFns(4),
4
);
expect(policy.skipTo(1)).toEqual(2);
});
});
describe('After something has errored', function() {
it('skips non cleanup fns', function() {
const fns = arrayOfArbitraryFns(4);
fns[2].type = arbitraryCleanupType();
fns[3].type = arbitraryCleanupType();
const policy = new jasmineUnderTest.CompleteOnFirstErrorSkipPolicy(fns);
policy.fnErrored(0);
expect(policy.skipTo(0)).toEqual(2);
expect(policy.skipTo(2)).toEqual(3);
expect(policy.skipTo(3)).toEqual(4);
});
for (const type of ['afterEach', 'specCleanup', 'afterAll']) {
it(`does not skip ${type} fns`, function() {
const fns = arrayOfArbitraryFns(2);
fns[1].type = type;
const policy = new jasmineUnderTest.CompleteOnFirstErrorSkipPolicy(
fns
);
policy.fnErrored(0);
expect(policy.skipTo(0)).toEqual(1);
});
}
describe('When the error was in a beforeEach fn', function() {
it('runs cleanup fns defined by the current and containing suites', function() {
const parentSuite = { description: 'parentSuite' };
const suite = { description: 'suite', parentSuite };
const fns = [
{
suite: suite
},
{
fn: () => {}
},
{
fn: () => {},
suite: suite,
type: arbitraryCleanupType()
},
{
fn: () => {},
suite: parentSuite,
type: arbitraryCleanupType()
}
];
const policy = new jasmineUnderTest.CompleteOnFirstErrorSkipPolicy(
fns
);
policy.fnErrored(0);
expect(policy.skipTo(0)).toEqual(2);
expect(policy.skipTo(2)).toEqual(3);
});
it('skips cleanup fns defined by nested suites', function() {
const parentSuite = { description: 'parentSuite' };
const suite = { description: 'suite', parentSuite };
const fns = [
{
fn: () => {},
type: 'beforeEach',
suite: parentSuite
},
{
fn: () => {}
},
{
fn: () => {},
suite: suite,
type: arbitraryCleanupType()
},
{
fn: () => {},
suite: parentSuite,
type: arbitraryCleanupType()
}
];
const policy = new jasmineUnderTest.CompleteOnFirstErrorSkipPolicy(
fns
);
policy.fnErrored(0);
expect(policy.skipTo(0)).toEqual(3);
});
});
it('does not skip cleanup fns that have no suite, such as the spec complete fn', function() {
const fns = [
{ fn: () => {} },
{
fn: () => {},
type: arbitraryCleanupType()
}
];
const policy = new jasmineUnderTest.CompleteOnFirstErrorSkipPolicy(fns);
policy.fnErrored(0);
expect(policy.skipTo(0)).toEqual(1);
});
});
});
function arrayOfArbitraryFns(n) {
const result = [];
for (let i = 0; i < n; i++) {
result.push({ fn: () => {} });
}
return result;
}
function arbitraryCleanupType() {
return 'specCleanup';
}
});

View File

@@ -1,6 +1,6 @@
describe('DelayedFunctionScheduler', function() {
it('schedules a function for later execution', function() {
var scheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
const scheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
fn = jasmine.createSpy('fn');
scheduler.scheduleFunction(fn, 0);
@@ -13,7 +13,7 @@ describe('DelayedFunctionScheduler', function() {
});
it('schedules a string for later execution', function() {
var scheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
const scheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
strfn = 'horrible = true;';
scheduler.scheduleFunction(strfn, 0);
@@ -24,7 +24,7 @@ describe('DelayedFunctionScheduler', function() {
});
it('#tick defaults to 0', function() {
var scheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
const scheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
fn = jasmine.createSpy('fn');
scheduler.scheduleFunction(fn, 0);
@@ -37,7 +37,7 @@ describe('DelayedFunctionScheduler', function() {
});
it('defaults delay to 0', function() {
var scheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
const scheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
fn = jasmine.createSpy('fn');
scheduler.scheduleFunction(fn);
@@ -50,7 +50,7 @@ describe('DelayedFunctionScheduler', function() {
});
it('optionally passes params to scheduled functions', function() {
var scheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
const scheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
fn = jasmine.createSpy('fn');
scheduler.scheduleFunction(fn, 0, ['foo', 'bar']);
@@ -63,7 +63,7 @@ describe('DelayedFunctionScheduler', function() {
});
it('scheduled fns can optionally reoccur', function() {
var scheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
const scheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
fn = jasmine.createSpy('fn');
scheduler.scheduleFunction(fn, 20, [], true);
@@ -84,7 +84,7 @@ describe('DelayedFunctionScheduler', function() {
});
it('increments scheduled fns ids unless one is passed', function() {
var scheduler = new jasmineUnderTest.DelayedFunctionScheduler();
const scheduler = new jasmineUnderTest.DelayedFunctionScheduler();
expect(scheduler.scheduleFunction(function() {}, 0)).toBe(1);
expect(scheduler.scheduleFunction(function() {}, 0)).toBe(2);
@@ -95,11 +95,9 @@ describe('DelayedFunctionScheduler', function() {
});
it('#removeFunctionWithId removes a previously scheduled function with a given id', function() {
var scheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
const scheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
fn = jasmine.createSpy('fn'),
timeoutKey;
timeoutKey = scheduler.scheduleFunction(fn, 0);
timeoutKey = scheduler.scheduleFunction(fn, 0);
expect(fn).not.toHaveBeenCalled();
@@ -111,15 +109,15 @@ describe('DelayedFunctionScheduler', function() {
});
it('executes recurring functions interleaved with regular functions in the correct order', function() {
var scheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
fn = jasmine.createSpy('fn'),
recurringCallCount = 0,
recurring = jasmine.createSpy('recurring').and.callFake(function() {
recurringCallCount++;
if (recurringCallCount < 5) {
expect(fn).not.toHaveBeenCalled();
}
});
const scheduler = new jasmineUnderTest.DelayedFunctionScheduler();
const fn = jasmine.createSpy('fn');
let recurringCallCount = 0;
const recurring = jasmine.createSpy('recurring').and.callFake(function() {
recurringCallCount++;
if (recurringCallCount < 5) {
expect(fn).not.toHaveBeenCalled();
}
});
scheduler.scheduleFunction(recurring, 10, [], true);
scheduler.scheduleFunction(fn, 50);
@@ -132,7 +130,7 @@ describe('DelayedFunctionScheduler', function() {
});
it('schedules a function for later execution during a tick', function() {
var scheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
const scheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
fn = jasmine.createSpy('fn'),
fnDelay = 10;
@@ -148,10 +146,10 @@ describe('DelayedFunctionScheduler', function() {
});
it('#removeFunctionWithId removes a previously scheduled function with a given id during a tick', function() {
var scheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
const scheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
fn = jasmine.createSpy('fn'),
fnDelay = 10,
timeoutKey;
fnDelay = 10;
let timeoutKey;
scheduler.scheduleFunction(function() {
scheduler.removeFunctionWithId(timeoutKey);
@@ -166,24 +164,24 @@ describe('DelayedFunctionScheduler', function() {
});
it('executes recurring functions interleaved with regular functions and functions scheduled during a tick in the correct order', function() {
var scheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
fn = jasmine.createSpy('fn'),
recurringCallCount = 0,
recurring = jasmine.createSpy('recurring').and.callFake(function() {
recurringCallCount++;
if (recurringCallCount < 5) {
expect(fn).not.toHaveBeenCalled();
}
}),
innerFn = jasmine.createSpy('innerFn').and.callFake(function() {
expect(recurring.calls.count()).toBe(4);
const scheduler = new jasmineUnderTest.DelayedFunctionScheduler();
const fn = jasmine.createSpy('fn');
let recurringCallCount = 0;
const recurring = jasmine.createSpy('recurring').and.callFake(function() {
recurringCallCount++;
if (recurringCallCount < 5) {
expect(fn).not.toHaveBeenCalled();
}),
scheduling = jasmine.createSpy('scheduling').and.callFake(function() {
expect(recurring.calls.count()).toBe(3);
expect(fn).not.toHaveBeenCalled();
scheduler.scheduleFunction(innerFn, 10); // 41ms absolute
});
}
});
const innerFn = jasmine.createSpy('innerFn').and.callFake(function() {
expect(recurring.calls.count()).toBe(4);
expect(fn).not.toHaveBeenCalled();
});
const scheduling = jasmine.createSpy('scheduling').and.callFake(function() {
expect(recurring.calls.count()).toBe(3);
expect(fn).not.toHaveBeenCalled();
scheduler.scheduleFunction(innerFn, 10); // 41ms absolute
});
scheduler.scheduleFunction(recurring, 10, [], true);
scheduler.scheduleFunction(fn, 50);
@@ -199,7 +197,7 @@ describe('DelayedFunctionScheduler', function() {
});
it('executes recurring functions after rescheduling them', function() {
var scheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
const scheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
recurring = function() {
expect(scheduler.scheduleFunction).toHaveBeenCalled();
};
@@ -212,11 +210,11 @@ describe('DelayedFunctionScheduler', function() {
});
it('removes functions during a tick that runs the function', function() {
var scheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
const scheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
spy = jasmine.createSpy('fn'),
spyAndRemove = jasmine.createSpy('fn'),
fnDelay = 10,
timeoutKey;
fnDelay = 10;
let timeoutKey;
spyAndRemove.and.callFake(function() {
scheduler.removeFunctionWithId(timeoutKey);
@@ -233,10 +231,10 @@ describe('DelayedFunctionScheduler', function() {
});
it('removes functions during the first tick that runs the function', function() {
var scheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
const scheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
fn = jasmine.createSpy('fn'),
fnDelay = 10,
timeoutKey;
fnDelay = 10;
let timeoutKey;
timeoutKey = scheduler.scheduleFunction(fn, fnDelay, [], true);
scheduler.scheduleFunction(function() {
@@ -252,7 +250,7 @@ describe('DelayedFunctionScheduler', function() {
});
it("does not remove a function that hasn't been added yet", function() {
var scheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
const scheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
fn = jasmine.createSpy('fn'),
fnDelay = 10;
@@ -267,7 +265,7 @@ describe('DelayedFunctionScheduler', function() {
});
it('updates the mockDate per scheduled time', function() {
var scheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
const scheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
tickDate = jasmine.createSpy('tickDate');
scheduler.scheduleFunction(function() {});
@@ -278,4 +276,58 @@ describe('DelayedFunctionScheduler', function() {
expect(tickDate).toHaveBeenCalledWith(0);
expect(tickDate).toHaveBeenCalledWith(1);
});
describe('ticking inside a scheduled function', function() {
let clock;
// Runner function calls the callback until it returns false
function runWork(workCallback) {
while (workCallback()) {}
}
// Make a worker that takes a little time and tracks when it finished
function mockWork(times) {
return () => {
clock.tick(1);
const now = new Date().getTime();
expect(lastWork)
.withContext('Previous function calls should always be in the past')
.toBeLessThan(now);
lastWork = now;
times--;
return times > 0;
};
}
let lastWork = 0;
beforeEach(() => {
clock = jasmineUnderTest.getEnv().clock;
clock.install();
clock.mockDate(new Date(1));
});
afterEach(function() {
jasmineUnderTest.getEnv().clock.uninstall();
});
it('preserves monotonically-increasing current time', () => {
const work1 = mockWork(3);
setTimeout(() => {
runWork(work1);
}, 1);
clock.tick(1);
expect(lastWork)
.withContext('tick should advance past last-scheduled function')
.toBeLessThanOrEqual(new Date().getTime());
const work2 = mockWork(3);
setTimeout(() => {
runWork(work2);
}, 1);
clock.tick(1);
expect(lastWork)
.withContext('tick should advance past last-scheduled function')
.toBeLessThanOrEqual(new Date().getTime());
});
});
});

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

@@ -0,0 +1,328 @@
/* 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() {
const runnable = { addDeprecationWarning: function() {} };
const 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() {
const runnable = {
addDeprecationWarning: function() {},
getFullName: function() {
return 'the suite';
},
children: []
};
const 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() {
const runnable = {
addDeprecationWarning: function() {},
getFullName: function() {
return 'the spec';
}
};
const 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() {
const topSuite = jasmine.createSpyObj('topSuite', [
'addDeprecationWarning',
'getFullName'
]);
const deprecator = new jasmineUnderTest.Deprecator(topSuite);
const 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() {
const deprecator = new jasmineUnderTest.Deprecator({});
const runnable1 = jasmine.createSpyObj('runnable1', [
'addDeprecationWarning',
'getFullName'
]);
const 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() {
const deprecator = new jasmineUnderTest.Deprecator({});
const runnable1 = jasmine.createSpyObj('runnable1', [
'addDeprecationWarning',
'getFullName'
]);
const 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() {
const deprecator = new jasmineUnderTest.Deprecator({});
const runnable1 = jasmine.createSpyObj('runnable1', [
'addDeprecationWarning',
'getFullName'
]);
const 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() {
const deprecator = new jasmineUnderTest.Deprecator({});
const 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() {
const deprecator = new jasmineUnderTest.Deprecator({});
const 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() {
const deprecator = new jasmineUnderTest.Deprecator({});
const runnable = jasmine.createSpyObj('runnable', [
'addDeprecationWarning',
'getFullName'
]);
let 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() {
const deprecator = new jasmineUnderTest.Deprecator({});
const runnable = jasmine.createSpyObj('runnable', [
'addDeprecationWarning',
'getFullName'
]);
let 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() {
const deprecator = new jasmineUnderTest.Deprecator({});
const runnable = jasmine.createSpyObj('runnable', [
'addDeprecationWarning',
'getFullName'
]);
let 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) {
const deprecator = new jasmineUnderTest.Deprecator({});
const 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) {
const deprecator = new jasmineUnderTest.Deprecator({});
const 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

@@ -1,6 +1,6 @@
// TODO: Fix these unit tests!
describe('Env', function() {
var env;
let env;
beforeEach(function() {
env = new jasmineUnderTest.Env();
});
@@ -26,9 +26,72 @@ 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() {
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');
});
});
const suite = env.topSuite();
expect(suite).not.toBeInstanceOf(jasmineUnderTest.Suite);
expect(suite.description).toEqual('Jasmine__TopLevel__Suite');
expect(suite.getFullName()).toEqual('');
expect(suite.children.length).toEqual(2);
expect(suite.children[0]).not.toBeInstanceOf(jasmineUnderTest.Spec);
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]).not.toBeInstanceOf(jasmineUnderTest.Suite);
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]).not.toBeInstanceOf(
jasmineUnderTest.Spec
);
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('throws if called in parallel mode', function() {
env.setParallelLoadingState('helpers');
check();
env.setParallelLoadingState('specs');
check();
function check() {
expect(function() {
env.topSuite();
}).toThrowError("'topSuite' is not available in parallel mode");
}
});
});
@@ -37,9 +100,9 @@ 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');
spyOn(jasmineUnderTest, 'Spec').and.callThrough();
env.it('foo', function() {});
expect(jasmineUnderTest.Spec).toHaveBeenCalledWith(
jasmine.objectContaining({
@@ -49,7 +112,7 @@ describe('Env', function() {
});
it('can configure suites to throw errors on expectation failures', function() {
env.configure({ oneFailurePerSpec: true });
env.configure({ stopSpecOnExpectationFailure: true });
spyOn(jasmineUnderTest, 'Suite');
env.describe('foo', function() {});
@@ -61,12 +124,11 @@ describe('Env', function() {
});
it('ignores configuration properties that are present but undefined', function() {
var initialConfig = {
spyOn(env, 'deprecated');
const initialConfig = {
random: true,
seed: '123',
failFast: true,
failSpecWithNoExpectations: true,
oneFailurePerSpec: true,
stopSpecOnExpectationFailure: true,
stopOnSpecFailure: true,
hideDisabled: true
@@ -76,9 +138,7 @@ describe('Env', function() {
env.configure({
random: undefined,
seed: undefined,
failFast: undefined,
failSpecWithNoExpectations: undefined,
oneFailurePerSpec: undefined,
stopSpecOnExpectationFailure: undefined,
stopOnSpecFailure: undefined,
hideDisabled: undefined
@@ -89,91 +149,8 @@ describe('Env', function() {
);
});
it('sets stopOnSpecFailure when failFast is set, and vice versa', function() {
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() {
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('sets stopSpecOnExpectationFailure when oneFailurePerSpec is set, and vice versa', function() {
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() {
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.'
);
});
describe('promise library', function() {
it('can be configured without a custom library', function() {
env.configure({});
env.configure({ Promise: undefined });
});
it('can be configured with a custom library', function() {
var myLibrary = {
resolve: jasmine.createSpy(),
reject: jasmine.createSpy()
};
env.configure({ Promise: myLibrary });
});
it('cannot be configured with an invalid promise library', function() {
var myLibrary = {};
expect(function() {
env.configure({ Promise: myLibrary });
}).toThrowError(
'Custom promise library missing `resolve`/`reject` functions'
);
});
});
it('defaults to multiple failures for specs', function() {
spyOn(jasmineUnderTest, 'Spec');
spyOn(jasmineUnderTest, 'Spec').and.callThrough();
env.it('bar', function() {});
expect(jasmineUnderTest.Spec).toHaveBeenCalledWith(
jasmine.objectContaining({
@@ -192,9 +169,43 @@ describe('Env', function() {
);
});
function behavesLikeDescribe(methodName) {
it('returns a suite metadata object', function() {
let innerSuite;
let spec;
const suite = env[methodName]('outer suite', function() {
innerSuite = env[methodName]('inner suite', function() {
spec = env.it('a spec');
});
});
expect(suite.parentSuite).toEqual(
jasmine.objectContaining({
description: 'Jasmine__TopLevel__Suite'
})
);
expect(suite.parentSuite.pend).toBeUndefined();
expect(suite.pend).toBeUndefined();
expect(suite.description).toEqual('outer suite');
expect(suite.getFullName()).toEqual('outer suite');
expect(suite.id).toBeInstanceOf(String);
expect(suite.id).not.toEqual('');
expect(suite.children.length).toEqual(1);
expect(suite.children[0]).toBe(innerSuite);
expect(innerSuite.children.length).toEqual(1);
expect(innerSuite.children[0]).toBe(spec);
expect(innerSuite.getFullName()).toEqual('outer suite inner suite');
expect(innerSuite.parentSuite).toBe(suite);
expect(spec.getFullName()).toEqual('outer suite inner suite a spec');
});
}
describe('#describe', function() {
behavesLikeDescribe('describe');
it('throws an error when given arguments', function() {
expect(function() {
// eslint-disable-next-line no-unused-vars
env.describe('done method', function(done) {});
}).toThrowError('describe does not expect any arguments');
});
@@ -228,14 +239,73 @@ 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('throws an error when it has no children', function() {
let ran = false;
env.describe('parent suite', function() {
expect(function() {
env.describe('child suite', function() {});
}).toThrowError(
'describe with no children (describe() or it()): parent suite child suite'
);
ran = true;
});
expect(ran).toBeTrue();
});
});
describe('#fdescribe', function() {
behavesLikeDescribe('fdescribe');
it('throws an error in parallel mode', function() {
env.setParallelLoadingState('specs');
expect(function() {
env.fdescribe('a suite', function() {
env.it('a spec');
});
}).toThrowError("'fdescribe' is not available in parallel mode");
});
});
describe('xdescribe', function() {
behavesLikeDescribe('xdescribe');
});
function behavesLikeIt(methodName) {
it('returns a spec metadata object', function() {
let spec;
env.describe('a suite', function() {
spec = env[methodName]('a spec', function() {});
});
expect(spec.description)
.withContext('description')
.toEqual('a spec');
expect(spec.getFullName())
.withContext('getFullName')
.toEqual('a suite a spec');
expect(spec.id)
.withContext('id')
.toBeInstanceOf(String);
expect(spec.id)
.withContext('id')
.not.toEqual('');
expect(spec.pend).toBeFalsy();
});
}
describe('#it', function() {
behavesLikeIt('it');
it('throws an error when it receives a non-fn argument', function() {
expect(function() {
env.it('undefined arg', null);
@@ -251,9 +321,8 @@ describe('Env', function() {
});
it('accepts an async function', function() {
jasmine.getEnv().requireAsyncAwait();
expect(function() {
env.it('async', jasmine.getEnv().makeAsyncAwaitFunction());
env.it('async', async function() {});
}).not.toThrow();
});
@@ -265,9 +334,11 @@ describe('Env', function() {
});
describe('#xit', function() {
behavesLikeIt('xit');
it('calls spec.exclude with "Temporarily disabled with xit"', function() {
var excludeSpy = jasmine.createSpy();
spyOn(env, 'it').and.returnValue({
const excludeSpy = jasmine.createSpy();
spyOn(jasmineUnderTest.SuiteBuilder.prototype, 'it_').and.returnValue({
exclude: excludeSpy
});
env.xit('foo', function() {});
@@ -275,10 +346,10 @@ describe('Env', function() {
});
it('calls spec.pend with "Temporarily disabled with xit"', function() {
var pendSpy = jasmine.createSpy();
var realExclude = jasmineUnderTest.Spec.prototype.exclude;
const pendSpy = jasmine.createSpy();
const realExclude = jasmineUnderTest.Spec.prototype.exclude;
spyOn(env, 'it').and.returnValue({
spyOn(jasmineUnderTest.SuiteBuilder.prototype, 'it_').and.returnValue({
exclude: realExclude,
pend: pendSpy
});
@@ -301,14 +372,15 @@ describe('Env', function() {
});
it('accepts an async function', function() {
jasmine.getEnv().requireAsyncAwait();
expect(function() {
env.xit('async', jasmine.getEnv().makeAsyncAwaitFunction());
env.xit('async', async function() {});
}).not.toThrow();
});
});
describe('#fit', function() {
behavesLikeIt('fit');
it('throws an error when it receives a non-fn argument', function() {
expect(function() {
env.fit('undefined arg', undefined);
@@ -322,6 +394,13 @@ describe('Env', function() {
env.fit('huge timeout', function() {}, 2147483648);
}).toThrowError('Timeout value cannot be greater than 2147483647');
});
it('throws an error in parallel mode', function() {
env.setParallelLoadingState('specs');
expect(function() {
env.fit('a spec', function() {});
}).toThrowError("'fit' is not available in parallel mode");
});
});
describe('#beforeEach', function() {
@@ -334,9 +413,8 @@ describe('Env', function() {
});
it('accepts an async function', function() {
jasmine.getEnv().requireAsyncAwait();
expect(function() {
env.beforeEach(jasmine.getEnv().makeAsyncAwaitFunction());
env.beforeEach(async function() {});
}).not.toThrow();
});
@@ -345,6 +423,28 @@ describe('Env', function() {
env.beforeEach(function() {}, 2147483648);
}).toThrowError('Timeout value cannot be greater than 2147483647');
});
it('throws when called at the top level in a spec file in parallel mode', function() {
env.setParallelLoadingState('specs');
expect(function() {
env.beforeEach(function() {});
}).toThrowError(
'In parallel mode, beforeEach must be in a describe block or in a helper file'
);
});
it('does not throw when called at the top level in a helper file in parallel mode', function() {
env.setParallelLoadingState('helpers');
env.beforeEach(function() {});
});
it('does not throw when called in a describe in a spec file in parallel mode', function() {
env.setParallelLoadingState('specs');
env.describe('a suite', function() {
env.beforeEach(function() {});
env.it('a spec');
});
});
});
describe('#beforeAll', function() {
@@ -357,9 +457,8 @@ describe('Env', function() {
});
it('accepts an async function', function() {
jasmine.getEnv().requireAsyncAwait();
expect(function() {
env.beforeAll(jasmine.getEnv().makeAsyncAwaitFunction());
env.beforeAll(async function() {});
}).not.toThrow();
});
@@ -368,6 +467,47 @@ describe('Env', function() {
env.beforeAll(function() {}, 2147483648);
}).toThrowError('Timeout value cannot be greater than 2147483647');
});
describe('in parallel mode', function() {
it('throws an error when called at the top level', function() {
env.setParallelLoadingState('helpers');
check();
env.setParallelLoadingState('specs');
check();
function check() {
expect(function() {
env.beforeAll(function() {});
}).toThrowError(
"In parallel mode, 'beforeAll' must be in a describe block. " +
'Use the globalSetup config property for exactly-once setup in' +
' parallel mode.'
);
}
});
it('does not throw an error when called in a describe', function() {
env.setParallelLoadingState('helpers');
check();
env.setParallelLoadingState('specs');
check();
function check() {
let done = false;
env.describe('a suite', function() {
expect(function() {
env.it('a spec');
env.beforeAll(function() {});
}).not.toThrow();
done = true;
});
expect(done).toBeTrue();
}
});
});
});
describe('#afterEach', function() {
@@ -380,9 +520,8 @@ describe('Env', function() {
});
it('accepts an async function', function() {
jasmine.getEnv().requireAsyncAwait();
expect(function() {
env.afterEach(jasmine.getEnv().makeAsyncAwaitFunction());
env.afterEach(async function() {});
}).not.toThrow();
});
@@ -391,6 +530,28 @@ describe('Env', function() {
env.afterEach(function() {}, 2147483648);
}).toThrowError('Timeout value cannot be greater than 2147483647');
});
it('throws when called at the top level in a spec file in parallel mode', function() {
env.setParallelLoadingState('specs');
expect(function() {
env.afterEach(function() {});
}).toThrowError(
'In parallel mode, afterEach must be in a describe block or in a helper file'
);
});
it('does not throw when called at the top level in a helper file in parallel mode', function() {
env.setParallelLoadingState('helpers');
env.afterEach(function() {});
});
it('does not throw when called in a describe in a spec file in parallel mode', function() {
env.setParallelLoadingState('specs');
env.describe('a suite', function() {
env.afterEach(function() {});
env.it('a spec');
});
});
});
describe('#afterAll', function() {
@@ -403,9 +564,8 @@ describe('Env', function() {
});
it('accepts an async function', function() {
jasmine.getEnv().requireAsyncAwait();
expect(function() {
env.afterAll(jasmine.getEnv().makeAsyncAwaitFunction());
env.afterAll(async function() {});
}).not.toThrow();
});
@@ -414,15 +574,57 @@ describe('Env', function() {
env.afterAll(function() {}, 2147483648);
}).toThrowError('Timeout value cannot be greater than 2147483647');
});
describe('in parallel mode', function() {
it('throws an error when called at the top level', function() {
env.setParallelLoadingState('helpers');
check();
env.setParallelLoadingState('specs');
check();
function check() {
expect(function() {
env.afterAll(function() {});
}).toThrowError(
"In parallel mode, 'afterAll' must be in a describe block. " +
'Use the globalTeardown config property for exactly-once ' +
'teardown in parallel mode.'
);
}
});
it('does not throw an error when called in a describe', function() {
env.setParallelLoadingState('helpers');
check();
env.setParallelLoadingState('specs');
check();
function check() {
let done = false;
env.describe('a suite', function() {
expect(function() {
env.it('a spec');
env.afterAll(function() {});
}).not.toThrow();
done = true;
});
expect(done).toBeTrue();
}
});
});
});
describe('when not constructed with suppressLoadErrors: true', function() {
it('installs a global error handler on construction', function() {
var globalErrors = jasmine.createSpyObj('globalErrors', [
const globalErrors = jasmine.createSpyObj('globalErrors', [
'install',
'uninstall',
'pushListener',
'popListener'
'popListener',
'removeOverrideListener'
]);
spyOn(jasmineUnderTest, 'GlobalErrors').and.returnValue(globalErrors);
env.cleanup_();
@@ -433,11 +635,12 @@ describe('Env', function() {
describe('when constructed with suppressLoadErrors: true', function() {
it('does not install a global error handler until execute is called', function() {
var globalErrors = jasmine.createSpyObj('globalErrors', [
const globalErrors = jasmine.createSpyObj('globalErrors', [
'install',
'uninstall',
'pushListener',
'popListener'
'popListener',
'removeOverrideListener'
]);
spyOn(jasmineUnderTest, 'GlobalErrors').and.returnValue(globalErrors);
env.cleanup_();
@@ -448,13 +651,13 @@ describe('Env', function() {
});
});
it('creates an expectationFactory that uses the current custom equality testers and object formatters', function(done) {
it('creates an expectationFactory that uses the current custom equality testers and object formatters', async function() {
function customEqualityTester() {}
function customObjectFormatter() {}
function prettyPrinter() {}
var RealSpec = jasmineUnderTest.Spec,
specInstance,
expectationFactory;
const RealSpec = jasmineUnderTest.Spec;
let specInstance;
let expectationFactory;
spyOn(jasmineUnderTest, 'MatchersUtil');
spyOn(jasmineUnderTest, 'makePrettyPrinter').and.returnValue(prettyPrinter);
spyOn(jasmineUnderTest, 'Spec').and.callFake(function(options) {
@@ -469,25 +672,23 @@ describe('Env', function() {
expectationFactory('actual', specInstance);
});
env.execute(null, function() {
expect(jasmineUnderTest.makePrettyPrinter).toHaveBeenCalledWith([
customObjectFormatter
]);
expect(jasmineUnderTest.MatchersUtil).toHaveBeenCalledWith({
customTesters: [customEqualityTester],
pp: prettyPrinter
});
done();
await env.execute();
expect(jasmineUnderTest.makePrettyPrinter).toHaveBeenCalledWith([
customObjectFormatter
]);
expect(jasmineUnderTest.MatchersUtil).toHaveBeenCalledWith({
customTesters: [customEqualityTester],
pp: prettyPrinter
});
});
it('creates an asyncExpectationFactory that uses the current custom equality testers and object formatters', function(done) {
it('creates an asyncExpectationFactory that uses the current custom equality testers and object formatters', async function() {
function customEqualityTester() {}
function customObjectFormatter() {}
function prettyPrinter() {}
var RealSpec = jasmineUnderTest.Spec,
specInstance,
asyncExpectationFactory;
const RealSpec = jasmineUnderTest.Spec;
let specInstance;
let asyncExpectationFactory;
spyOn(jasmineUnderTest, 'MatchersUtil');
spyOn(jasmineUnderTest, 'makePrettyPrinter').and.returnValue(prettyPrinter);
spyOn(jasmineUnderTest, 'Spec').and.callFake(function(options) {
@@ -502,49 +703,132 @@ describe('Env', function() {
asyncExpectationFactory('actual', specInstance);
});
env.execute(null, function() {
expect(jasmineUnderTest.makePrettyPrinter).toHaveBeenCalledWith([
customObjectFormatter
]);
expect(jasmineUnderTest.MatchersUtil).toHaveBeenCalledWith({
customTesters: [customEqualityTester],
pp: prettyPrinter
});
done();
await env.execute();
expect(jasmineUnderTest.makePrettyPrinter).toHaveBeenCalledWith([
customObjectFormatter
]);
expect(jasmineUnderTest.MatchersUtil).toHaveBeenCalledWith({
customTesters: [customEqualityTester],
pp: prettyPrinter
});
});
it("does not expose the suite as 'this'", function() {
let suiteThis;
spyOn(env, 'deprecated');
env.describe('a suite', function() {
suiteThis = this;
env.it('has a spec');
});
expect(suiteThis).not.toBeInstanceOf(jasmineUnderTest.Suite);
});
describe('#execute', function() {
it('returns a promise when the environment supports promises', function() {
jasmine.getEnv().requirePromises();
it('returns a promise', function() {
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() {};
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(env.topSuite(), 'reset');
spyOn(jasmineUnderTest.Suite.prototype, 'reset');
return env
.execute() // 1
.then(function() {
return env.execute(); // 2
})
.then(function() {
expect(env.topSuite().reset).toHaveBeenCalledOnceWith();
expect(
jasmineUnderTest.Suite.prototype.reset
).toHaveBeenCalledOnceWith();
const id = jasmineUnderTest.Suite.prototype.reset.calls.thisFor(0).id;
expect(id).toBeTruthy();
expect(id).toEqual(env.topSuite().id);
});
});
it('should not reset the topSuite if parallelReset was called since the last run', async function() {
await env.execute();
env.parallelReset();
spyOn(jasmineUnderTest.Suite.prototype, 'reset');
await env.execute();
expect(jasmineUnderTest.Suite.prototype.reset).not.toHaveBeenCalled();
});
describe('In parallel mode', function() {
it('rejects if random is set to false', async function() {
env.configure({ random: false });
env.setParallelLoadingState('specs');
await expectAsync(env.execute()).toBeRejectedWithError(
'Randomization cannot be disabled in parallel mode'
);
});
it('rejects if seed is set', async function() {
env.configure({ seed: 1234 });
env.setParallelLoadingState('specs');
await expectAsync(env.execute()).toBeRejectedWithError(
'Random seed cannot be set in parallel mode'
);
});
});
});
describe('#spyOnGlobalErrorsAsync', function() {
it('throws if the callback does not return a promise', async function() {
const msg =
'The callback to spyOnGlobalErrorsAsync must be an async or ' +
'promise-returning function';
await expectAsync(
env.spyOnGlobalErrorsAsync(() => undefined)
).toBeRejectedWithError(msg);
await expectAsync(
env.spyOnGlobalErrorsAsync(() => 'not a promise')
).toBeRejectedWithError(msg);
});
});
describe('#addReporter', function() {
it('throws when called in parallel mode', function() {
env.setParallelLoadingState('helpers');
expect(function() {
env.addReporter({});
}).toThrowError('Reporters cannot be added via Env in parallel mode');
env.setParallelLoadingState('specs');
expect(function() {
env.addReporter({});
}).toThrowError('Reporters cannot be added via Env in parallel mode');
});
});
describe('#clearReporters', function() {
it('throws when called in parallel mode', function() {
env.setParallelLoadingState('helpers');
expect(function() {
env.clearReporters();
}).toThrowError('Reporters cannot be removed via Env in parallel mode');
env.setParallelLoadingState('specs');
expect(function() {
env.clearReporters();
}).toThrowError('Reporters cannot be removed via Env in parallel mode');
});
});
describe('#configure', function() {
it('throws when called in parallel mode', function() {
env.setParallelLoadingState('helpers');
expect(function() {
env.configure({});
}).toThrowError('Jasmine cannot be configured via Env in parallel mode');
env.setParallelLoadingState('specs');
expect(function() {
env.configure({});
}).toThrowError('Jasmine cannot be configured via Env in parallel mode');
});
});
});

View File

@@ -1,7 +1,7 @@
describe('ExceptionFormatter', function() {
describe('#message', function() {
it('formats Firefox exception messages', function() {
var sampleFirefoxException = {
const sampleFirefoxException = {
fileName: 'foo.js',
lineNumber: '1978',
message: 'you got your foo in my bar',
@@ -16,7 +16,7 @@ describe('ExceptionFormatter', function() {
});
it('formats Webkit exception messages', function() {
var sampleWebkitException = {
const sampleWebkitException = {
sourceURL: 'foo.js',
line: '1978',
message: 'you got your foo in my bar',
@@ -31,7 +31,7 @@ describe('ExceptionFormatter', function() {
});
it('formats V8 exception messages', function() {
var sampleV8 = {
const sampleV8 = {
message: 'you got your foo in my bar',
name: 'A Classic Mistake'
},
@@ -42,29 +42,29 @@ describe('ExceptionFormatter', function() {
});
it('formats unnamed exceptions with message', function() {
var unnamedError = { message: 'This is an unnamed error message.' };
const unnamedError = { message: 'This is an unnamed error message.' };
var exceptionFormatter = new jasmineUnderTest.ExceptionFormatter(),
const exceptionFormatter = new jasmineUnderTest.ExceptionFormatter(),
message = exceptionFormatter.message(unnamedError);
expect(message).toEqual('This is an unnamed error message.');
});
it('formats empty exceptions with toString format', function() {
var EmptyError = function() {};
const EmptyError = function() {};
EmptyError.prototype.toString = function() {
return '[EmptyError]';
};
var emptyError = new EmptyError();
const emptyError = new EmptyError();
var exceptionFormatter = new jasmineUnderTest.ExceptionFormatter(),
const exceptionFormatter = new jasmineUnderTest.ExceptionFormatter(),
message = exceptionFormatter.message(emptyError);
expect(message).toEqual('[EmptyError] thrown');
});
it("formats thrown exceptions that aren't errors", function() {
var thrown = 'crazy error',
const thrown = 'crazy error',
exceptionFormatter = new jasmineUnderTest.ExceptionFormatter(),
message = exceptionFormatter.message(thrown);
@@ -74,12 +74,7 @@ describe('ExceptionFormatter', function() {
describe('#stack', function() {
it('formats stack traces', function() {
var error;
try {
throw new Error('an error');
} catch (e) {
error = e;
}
const error = new Error('an error');
expect(new jasmineUnderTest.ExceptionFormatter().stack(error)).toMatch(
/ExceptionFormatterSpec\.js.*\d+/
@@ -87,7 +82,7 @@ describe('ExceptionFormatter', function() {
});
it('filters Jasmine stack frames from V8-style traces but leaves unmatched lines intact', function() {
var error = {
const error = {
message: 'nope',
stack:
'C:\\__spec__\\core\\UtilSpec.ts:120\n' +
@@ -101,10 +96,10 @@ describe('ExceptionFormatter', function() {
' at fn3 (C:\\__jasmine__\\lib\\jasmine-core\\jasmine.js:7575:25)\n' +
' at fn4 (node:internal/timers:462:21)\n'
};
var subject = new jasmineUnderTest.ExceptionFormatter({
const subject = new jasmineUnderTest.ExceptionFormatter({
jasmineFile: 'C:\\__jasmine__\\lib\\jasmine-core\\jasmine.js'
});
var result = subject.stack(error);
const result = subject.stack(error);
expect(result).toEqual(
'C:\\__spec__\\core\\UtilSpec.ts:120\n' +
" new Error('nope');\n" +
@@ -118,7 +113,7 @@ describe('ExceptionFormatter', function() {
});
it('filters Jasmine stack frames from V8 style traces', function() {
var error = {
const error = {
message: 'nope',
stack:
'Error: nope\n' +
@@ -127,10 +122,10 @@ describe('ExceptionFormatter', function() {
' at fn3 (http://localhost:8888/__jasmine__/jasmine.js:4320:20)\n' +
' at fn4 (http://localhost:8888/__spec__/core/UtilSpec.js:110:19)\n'
};
var subject = new jasmineUnderTest.ExceptionFormatter({
const subject = new jasmineUnderTest.ExceptionFormatter({
jasmineFile: 'http://localhost:8888/__jasmine__/jasmine.js'
});
var result = subject.stack(error);
const result = subject.stack(error);
expect(result).toEqual(
'Error: nope\n' +
' at fn1 (http://localhost:8888/__spec__/core/UtilSpec.js:115:19)\n' +
@@ -140,17 +135,17 @@ describe('ExceptionFormatter', function() {
});
it('filters Jasmine stack frames from Webkit style traces', function() {
var error = {
const error = {
stack:
'http://localhost:8888/__spec__/core/UtilSpec.js:115:28\n' +
'fn1@http://localhost:8888/__jasmine__/jasmine.js:4320:27\n' +
'fn2@http://localhost:8888/__jasmine__/jasmine.js:4320:27\n' +
'http://localhost:8888/__spec__/core/UtilSpec.js:115:28'
};
var subject = new jasmineUnderTest.ExceptionFormatter({
const subject = new jasmineUnderTest.ExceptionFormatter({
jasmineFile: 'http://localhost:8888/__jasmine__/jasmine.js'
});
var result = subject.stack(error);
const result = subject.stack(error);
expect(result).toEqual(
'http://localhost:8888/__spec__/core/UtilSpec.js:115:28\n' +
'<Jasmine>\n' +
@@ -159,17 +154,12 @@ describe('ExceptionFormatter', function() {
});
it('filters Jasmine stack frames in this environment', function() {
var error, i;
try {
throw new Error('an error');
} catch (e) {
error = e;
}
var subject = new jasmineUnderTest.ExceptionFormatter({
const error = new Error('an error');
const subject = new jasmineUnderTest.ExceptionFormatter({
jasmineFile: jasmine.util.jasmineFile()
});
var result = subject.stack(error);
var lines = result.split('\n');
const result = subject.stack(error);
const lines = result.split('\n');
if (lines[0].match(/an error/)) {
lines.shift();
@@ -179,28 +169,23 @@ describe('ExceptionFormatter', function() {
expect(lines[1]).toMatch(/<Jasmine>/);
// Node has some number of additional frames below Jasmine.
for (i = 2; i < lines.length; i++) {
for (let i = 2; i < lines.length; i++) {
expect(lines[i]).not.toMatch(/jasmine.js/);
}
});
it('handles multiline error messages in this environment', function() {
var error,
msg = 'an error\nwith two lines';
try {
throw new Error(msg);
} catch (e) {
error = e;
}
const msg = 'an error\nwith two lines';
const error = new Error(msg);
if (error.stack.indexOf(msg) === -1) {
pending("Stack traces don't have messages in this environment");
}
var subject = new jasmineUnderTest.ExceptionFormatter({
const subject = new jasmineUnderTest.ExceptionFormatter({
jasmineFile: jasmine.util.jasmineFile()
});
var result = subject.stack(error);
var lines = result.split('\n');
const result = subject.stack(error);
const lines = result.split('\n');
expect(lines[0]).toMatch(/an error/);
expect(lines[1]).toMatch(/with two lines/);
@@ -212,18 +197,133 @@ describe('ExceptionFormatter', function() {
expect(new jasmineUnderTest.ExceptionFormatter().stack()).toBeNull();
});
it('includes error properties in stack', function() {
var error;
try {
throw new Error('an error');
} catch (e) {
error = e;
}
it("includes the error's own properties in stack", function() {
const error = new Error('an error');
error.someProperty = 'hello there';
var result = new jasmineUnderTest.ExceptionFormatter().stack(error);
const result = new jasmineUnderTest.ExceptionFormatter().stack(error);
expect(result).toMatch(/error properties:.*someProperty.*hello there/);
});
it('does not include inherited error properties', function() {
function CustomError(msg) {
Error.call(this, msg);
}
CustomError.prototype = new Error();
CustomError.prototype.anInheritedProp = 'something';
const error = new CustomError('nope');
const result = new jasmineUnderTest.ExceptionFormatter().stack(error);
expect(result).not.toContain('anInheritedProp');
});
describe('When omitMessage is true', function() {
it('filters the message from V8-style stack traces', function() {
const error = {
message: 'nope',
stack:
'Error: nope\n' +
' at fn1 (http://localhost:8888/__spec__/core/UtilSpec.js:115:19)\n' +
' at fn2 (http://localhost:8888/__jasmine__/jasmine.js:4320:20)\n' +
' at fn3 (http://localhost:8888/__jasmine__/jasmine.js:4320:20)\n' +
' at fn4 (http://localhost:8888/__spec__/core/UtilSpec.js:110:19)\n'
};
const subject = new jasmineUnderTest.ExceptionFormatter({
jasmineFile: 'http://localhost:8888/__jasmine__/jasmine.js'
});
const result = subject.stack(error, { omitMessage: true });
expect(result).toEqual(
' at fn1 (http://localhost:8888/__spec__/core/UtilSpec.js:115:19)\n' +
' at <Jasmine>\n' +
' at fn4 (http://localhost:8888/__spec__/core/UtilSpec.js:110:19)'
);
});
it('handles Webkit style traces that do not include a message', function() {
const error = {
stack:
'http://localhost:8888/__spec__/core/UtilSpec.js:115:28\n' +
'fn1@http://localhost:8888/__jasmine__/jasmine.js:4320:27\n' +
'fn2@http://localhost:8888/__jasmine__/jasmine.js:4320:27\n' +
'http://localhost:8888/__spec__/core/UtilSpec.js:115:28'
};
const subject = new jasmineUnderTest.ExceptionFormatter({
jasmineFile: 'http://localhost:8888/__jasmine__/jasmine.js'
});
const result = subject.stack(error, { omitMessage: true });
expect(result).toEqual(
'http://localhost:8888/__spec__/core/UtilSpec.js:115:28\n' +
'<Jasmine>\n' +
'http://localhost:8888/__spec__/core/UtilSpec.js:115:28'
);
});
it('ensures that stack traces do not include the message in this environment', function() {
const error = new Error('an error');
const subject = new jasmineUnderTest.ExceptionFormatter({
jasmineFile: jasmine.util.jasmineFile()
});
const result = subject.stack(error, { omitMessage: true });
expect(result).not.toContain('an error');
});
});
describe('when the error has a cause property', function() {
it('recursively includes the cause in the stack trace in this environment', function() {
const subject = new jasmineUnderTest.ExceptionFormatter();
const rootCause = new Error('root cause');
const proximateCause = new Error('proximate cause', {
cause: rootCause
});
const symptom = new Error('symptom', { cause: proximateCause });
const lines = subject.stack(symptom).split('\n');
// Not all environments include the message in the stack trace.
const hasRootMessage = lines[0].indexOf('symptom') !== -1;
const firstSymptomStackIx = hasRootMessage ? 1 : 0;
expect(lines[firstSymptomStackIx])
.withContext('first symptom stack frame')
.toContain('ExceptionFormatterSpec.js');
const proximateCauseMsgIx = lines.indexOf(
'Caused by: Error: proximate cause'
);
expect(proximateCauseMsgIx)
.withContext('index of proximate cause message')
.toBeGreaterThan(firstSymptomStackIx);
expect(lines[proximateCauseMsgIx + 1])
.withContext('first proximate cause stack frame')
.toContain('ExceptionFormatterSpec.js');
const rootCauseMsgIx = lines.indexOf('Caused by: Error: root cause');
expect(rootCauseMsgIx)
.withContext('index of root cause message')
.toBeGreaterThan(proximateCauseMsgIx + 1);
expect(lines[rootCauseMsgIx + 1])
.withContext('first root cause stack frame')
.toContain('ExceptionFormatterSpec.js');
});
it('does not throw if cause is a non Error', function() {
const formatter = new jasmineUnderTest.ExceptionFormatter();
expect(function() {
formatter.stack(
new Error('error', {
cause: function() {}
})
);
}).not.toThrowError();
expect(function() {
formatter.stack(
new Error('error', {
cause: 'another error'
})
);
}).not.toThrowError();
});
});
});
});

View File

@@ -1,5 +1,5 @@
describe('Exceptions:', function() {
var env;
let env;
beforeEach(function() {
env = new jasmineUnderTest.Env();
@@ -9,8 +9,8 @@ describe('Exceptions:', function() {
env.cleanup_();
});
it('should handle exceptions thrown, but continue', function(done) {
var secondTest = jasmine.createSpy('second test');
it('should handle exceptions thrown, but continue', async function() {
const secondTest = jasmine.createSpy('second test');
env.describe('Suite for handles exceptions', function() {
env.it(
'should be a test that fails because it throws an exception',
@@ -24,16 +24,17 @@ describe('Exceptions:', function() {
);
});
var expectations = function() {
expect(secondTest).toHaveBeenCalled();
done();
};
await env.execute();
env.execute(null, expectations);
expect(secondTest).toHaveBeenCalled();
});
it('should handle exceptions thrown directly in top-level describe blocks and continue', function(done) {
var secondDescribe = jasmine.createSpy('second describe');
it('should handle exceptions thrown directly in top-level describe blocks and continue', async function() {
const 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);
@@ -43,11 +44,8 @@ describe('Exceptions:', function() {
});
env.describe("a suite that doesn't throw an exception", secondDescribe);
var expectations = function() {
expect(secondDescribe).toHaveBeenCalled();
done();
};
await env.execute();
env.execute(null, expectations);
expect(secondDescribe).toHaveBeenCalled();
});
});

View File

@@ -1,7 +1,7 @@
describe('ExpectationFilterChain', function() {
describe('#addFilter', function() {
it('returns a new filter chain with the added filter', function() {
var first = jasmine.createSpy('first'),
const first = jasmine.createSpy('first'),
second = jasmine.createSpy('second'),
orig = new jasmineUnderTest.ExpectationFilterChain({
modifyFailureMessage: first
@@ -15,7 +15,7 @@ describe('ExpectationFilterChain', function() {
});
it('does not modify the original filter chain', function() {
var orig = new jasmineUnderTest.ExpectationFilterChain({}),
const orig = new jasmineUnderTest.ExpectationFilterChain({}),
f = jasmine.createSpy('f');
orig.addFilter({ selectComparisonFunc: f });
@@ -28,7 +28,7 @@ describe('ExpectationFilterChain', function() {
describe('#selectComparisonFunc', function() {
describe('When no filters have #selectComparisonFunc', function() {
it('returns undefined', function() {
var chain = new jasmineUnderTest.ExpectationFilterChain();
const chain = new jasmineUnderTest.ExpectationFilterChain();
chain.addFilter({});
expect(chain.selectComparisonFunc()).toBeUndefined();
});
@@ -36,15 +36,13 @@ describe('ExpectationFilterChain', function() {
describe('When some filters have #selectComparisonFunc', function() {
it('calls the first filter that has #selectComparisonFunc', function() {
var first = jasmine.createSpy('first').and.returnValue('first'),
const first = jasmine.createSpy('first').and.returnValue('first'),
second = jasmine.createSpy('second').and.returnValue('second'),
chain = new jasmineUnderTest.ExpectationFilterChain()
.addFilter({ selectComparisonFunc: first })
.addFilter({ selectComparisonFunc: second }),
matcher = {},
result;
result = chain.selectComparisonFunc(matcher);
result = chain.selectComparisonFunc(matcher);
expect(first).toHaveBeenCalledWith(matcher);
expect(second).not.toHaveBeenCalled();
@@ -56,7 +54,7 @@ describe('ExpectationFilterChain', function() {
describe('#buildFailureMessage', function() {
describe('When no filters have #buildFailureMessage', function() {
it('returns undefined', function() {
var chain = new jasmineUnderTest.ExpectationFilterChain();
const chain = new jasmineUnderTest.ExpectationFilterChain();
chain.addFilter({});
expect(chain.buildFailureMessage()).toBeUndefined();
});
@@ -64,7 +62,7 @@ describe('ExpectationFilterChain', function() {
describe('When some filters have #buildFailureMessage', function() {
it('calls the first filter that has #buildFailureMessage', function() {
var first = jasmine.createSpy('first').and.returnValue('first'),
const first = jasmine.createSpy('first').and.returnValue('first'),
second = jasmine.createSpy('second').and.returnValue('second'),
chain = new jasmineUnderTest.ExpectationFilterChain()
.addFilter({ buildFailureMessage: first })
@@ -72,10 +70,9 @@ describe('ExpectationFilterChain', function() {
matcherResult = { pass: false },
matcherName = 'foo',
args = [],
matchersUtil = {},
result;
matchersUtil = {};
result = chain.buildFailureMessage(
const result = chain.buildFailureMessage(
matcherResult,
matcherName,
args,
@@ -97,7 +94,7 @@ describe('ExpectationFilterChain', function() {
describe('#modifyFailureMessage', function() {
describe('When no filters have #modifyFailureMessage', function() {
it('returns the original message', function() {
var chain = new jasmineUnderTest.ExpectationFilterChain();
const chain = new jasmineUnderTest.ExpectationFilterChain();
chain.addFilter({});
expect(chain.modifyFailureMessage('msg')).toEqual('msg');
});
@@ -105,14 +102,12 @@ describe('ExpectationFilterChain', function() {
describe('When some filters have #modifyFailureMessage', function() {
it('calls the first filter that has #modifyFailureMessage', function() {
var first = jasmine.createSpy('first').and.returnValue('first'),
const first = jasmine.createSpy('first').and.returnValue('first'),
second = jasmine.createSpy('second').and.returnValue('second'),
chain = new jasmineUnderTest.ExpectationFilterChain()
.addFilter({ modifyFailureMessage: first })
.addFilter({ modifyFailureMessage: second }),
result;
result = chain.modifyFailureMessage('original');
result = chain.modifyFailureMessage('original');
expect(first).toHaveBeenCalledWith('original');
expect(second).not.toHaveBeenCalled();

View File

@@ -1,126 +0,0 @@
describe('buildExpectationResult', function() {
it('defaults to passed', function() {
var result = jasmineUnderTest.buildExpectationResult({
passed: 'some-value'
});
expect(result.passed).toBe('some-value');
});
it('message defaults to Passed for passing specs', function() {
var result = jasmineUnderTest.buildExpectationResult({
passed: true,
message: 'some-value'
});
expect(result.message).toBe('Passed.');
});
it('message returns the message for failing expectations', function() {
var result = jasmineUnderTest.buildExpectationResult({
passed: false,
message: 'some-value'
});
expect(result.message).toBe('some-value');
});
it('delegates message formatting to the provided formatter if there was an Error', function() {
var fakeError = { message: 'foo' },
messageFormatter = jasmine
.createSpy('exception message formatter')
.and.returnValue(fakeError.message);
var result = jasmineUnderTest.buildExpectationResult({
passed: false,
error: fakeError,
messageFormatter: messageFormatter
});
expect(messageFormatter).toHaveBeenCalledWith(fakeError);
expect(result.message).toEqual('foo');
});
it('delegates stack formatting to the provided formatter if there was an Error', function() {
var fakeError = { stack: 'foo' },
stackFormatter = jasmine
.createSpy('stack formatter')
.and.returnValue(fakeError.stack);
var result = jasmineUnderTest.buildExpectationResult({
passed: false,
error: fakeError,
stackFormatter: stackFormatter
});
expect(stackFormatter).toHaveBeenCalledWith(fakeError);
expect(result.stack).toEqual('foo');
});
it('delegates stack formatting to the provided formatter if there was a provided errorForStack', function() {
var fakeError = { stack: 'foo' },
stackFormatter = jasmine
.createSpy('stack formatter')
.and.returnValue(fakeError.stack);
var result = jasmineUnderTest.buildExpectationResult({
passed: false,
errorForStack: fakeError,
stackFormatter: stackFormatter
});
expect(stackFormatter).toHaveBeenCalledWith(fakeError);
expect(result.stack).toEqual('foo');
});
it('matcherName returns passed matcherName', function() {
var result = jasmineUnderTest.buildExpectationResult({
matcherName: 'some-value'
});
expect(result.matcherName).toBe('some-value');
});
it('expected returns passed expected', function() {
var result = jasmineUnderTest.buildExpectationResult({
expected: 'some-value'
});
expect(result.expected).toBe('some-value');
});
it('actual returns passed actual', function() {
var result = jasmineUnderTest.buildExpectationResult({
actual: 'some-value'
});
expect(result.actual).toBe('some-value');
});
it('handles nodejs assertions', function() {
if (typeof require === 'undefined') {
return;
}
var assert = require('assert');
var error;
var value = 8421;
var expectedValue = 'JasmineExpectationTestValue';
try {
assert.equal(value, expectedValue);
} catch (e) {
error = e;
}
expect(error.code).toEqual('ERR_ASSERTION');
expect(error.actual).toEqual(value);
expect(error.expected).toEqual(expectedValue);
expect(error.operator).toEqual('==');
var result = jasmineUnderTest.buildExpectationResult({
passed: false,
matcherName: '',
expected: '',
actual: '',
error: error
});
expect(result.code).toEqual('ERR_ASSERTION');
expect(result.actual).toEqual(value);
expect(result.expected).toEqual(expectedValue);
expect(result.matcherName).toEqual('assert ==');
});
});

View File

@@ -1,34 +1,31 @@
describe('Expectation', function() {
it('makes custom matchers available to this expectation', function() {
var matchers = {
const matchers = {
toFoo: function() {},
toBar: function() {}
},
expectation;
expectation = jasmineUnderTest.Expectation.factory({
customMatchers: matchers
});
expectation = jasmineUnderTest.Expectation.factory({
customMatchers: matchers
});
expect(expectation.toFoo).toBeDefined();
expect(expectation.toBar).toBeDefined();
});
it('.addCoreMatchers makes matchers available to any expectation', function() {
var coreMatchers = {
toQuux: function() {}
},
expectation;
const coreMatchers = {
toQuux: function() {}
};
jasmineUnderTest.Expectation.addCoreMatchers(coreMatchers);
expectation = jasmineUnderTest.Expectation.factory({});
const expectation = jasmineUnderTest.Expectation.factory({});
expect(expectation.toQuux).toBeDefined();
});
it("wraps matchers's compare functions, passing in matcher dependencies", function() {
var fakeCompare = function() {
const fakeCompare = function() {
return { pass: true };
},
matcherFactory = jasmine
@@ -40,28 +37,22 @@ describe('Expectation', function() {
matchersUtil = {
buildFailureMessage: jasmine.createSpy('buildFailureMessage')
},
customEqualityTesters = ['a'],
addExpectationResult = jasmine.createSpy('addExpectationResult'),
expectation;
addExpectationResult = jasmine.createSpy('addExpectationResult');
expectation = jasmineUnderTest.Expectation.factory({
const expectation = jasmineUnderTest.Expectation.factory({
matchersUtil: matchersUtil,
customMatchers: matchers,
customEqualityTesters: customEqualityTesters,
actual: 'an actual',
addExpectationResult: addExpectationResult
});
expectation.toFoo('hello');
expect(matcherFactory).toHaveBeenCalledWith(
matchersUtil,
customEqualityTesters
);
expect(matcherFactory).toHaveBeenCalledWith(matchersUtil);
});
it("wraps matchers's compare functions, passing the actual and expected", function() {
var fakeCompare = jasmine
const fakeCompare = jasmine
.createSpy('fake-compare')
.and.returnValue({ pass: true }),
matchers = {
@@ -74,10 +65,9 @@ describe('Expectation', function() {
matchersUtil = {
buildFailureMessage: jasmine.createSpy('buildFailureMessage')
},
addExpectationResult = jasmine.createSpy('addExpectationResult'),
expectation;
addExpectationResult = jasmine.createSpy('addExpectationResult');
expectation = jasmineUnderTest.Expectation.factory({
const expectation = jasmineUnderTest.Expectation.factory({
matchersUtil: matchersUtil,
customMatchers: matchers,
actual: 'an actual',
@@ -90,7 +80,7 @@ describe('Expectation', function() {
});
it('reports a passing result to the spec when the comparison passes', function() {
var matchers = {
const matchers = {
toFoo: function() {
return {
compare: function() {
@@ -102,10 +92,9 @@ describe('Expectation', function() {
matchersUtil = {
buildFailureMessage: jasmine.createSpy('buildFailureMessage')
},
addExpectationResult = jasmine.createSpy('addExpectationResult'),
expectation;
addExpectationResult = jasmine.createSpy('addExpectationResult');
expectation = jasmineUnderTest.Expectation.factory({
const expectation = jasmineUnderTest.Expectation.factory({
customMatchers: matchers,
matchersUtil: matchersUtil,
actual: 'an actual',
@@ -126,7 +115,7 @@ describe('Expectation', function() {
});
it('reports a failing result to the spec when the comparison fails', function() {
var matchers = {
const matchers = {
toFoo: function() {
return {
compare: function() {
@@ -140,10 +129,9 @@ describe('Expectation', function() {
return '';
}
},
addExpectationResult = jasmine.createSpy('addExpectationResult'),
expectation;
addExpectationResult = jasmine.createSpy('addExpectationResult');
expectation = jasmineUnderTest.Expectation.factory({
const expectation = jasmineUnderTest.Expectation.factory({
customMatchers: matchers,
matchersUtil: matchersUtil,
actual: 'an actual',
@@ -164,7 +152,7 @@ describe('Expectation', function() {
});
it('reports a failing result and a custom fail message to the spec when the comparison fails', function() {
var matchers = {
const matchers = {
toFoo: function() {
return {
compare: function() {
@@ -176,10 +164,9 @@ describe('Expectation', function() {
};
}
},
addExpectationResult = jasmine.createSpy('addExpectationResult'),
expectation;
addExpectationResult = jasmine.createSpy('addExpectationResult');
expectation = jasmineUnderTest.Expectation.factory({
const expectation = jasmineUnderTest.Expectation.factory({
actual: 'an actual',
customMatchers: matchers,
addExpectationResult: addExpectationResult
@@ -199,7 +186,7 @@ describe('Expectation', function() {
});
it('reports a failing result with a custom fail message function to the spec when the comparison fails', function() {
var matchers = {
const matchers = {
toFoo: function() {
return {
compare: function() {
@@ -213,10 +200,9 @@ describe('Expectation', function() {
};
}
},
addExpectationResult = jasmine.createSpy('addExpectationResult'),
expectation;
addExpectationResult = jasmine.createSpy('addExpectationResult');
expectation = jasmineUnderTest.Expectation.factory({
const expectation = jasmineUnderTest.Expectation.factory({
customMatchers: matchers,
actual: 'an actual',
addExpectationResult: addExpectationResult
@@ -236,7 +222,7 @@ describe('Expectation', function() {
});
it('reports a passing result to the spec when the comparison fails for a negative expectation', function() {
var matchers = {
const matchers = {
toFoo: function() {
return {
compare: function() {
@@ -246,10 +232,9 @@ describe('Expectation', function() {
}
},
addExpectationResult = jasmine.createSpy('addExpectationResult'),
actual = 'an actual',
expectation;
actual = 'an actual';
expectation = jasmineUnderTest.Expectation.factory({
const expectation = jasmineUnderTest.Expectation.factory({
customMatchers: matchers,
actual: 'an actual',
addExpectationResult: addExpectationResult
@@ -269,7 +254,7 @@ describe('Expectation', function() {
});
it('reports a failing result to the spec when the comparison passes for a negative expectation', function() {
var matchers = {
const matchers = {
toFoo: function() {
return {
compare: function() {
@@ -284,10 +269,9 @@ describe('Expectation', function() {
}
},
addExpectationResult = jasmine.createSpy('addExpectationResult'),
actual = 'an actual',
expectation;
actual = 'an actual';
expectation = jasmineUnderTest.Expectation.factory({
const expectation = jasmineUnderTest.Expectation.factory({
customMatchers: matchers,
actual: 'an actual',
matchersUtil: matchersUtil,
@@ -308,7 +292,7 @@ describe('Expectation', function() {
});
it('reports a failing result and a custom fail message to the spec when the comparison passes for a negative expectation', function() {
var matchers = {
const matchers = {
toFoo: function() {
return {
compare: function() {
@@ -321,10 +305,9 @@ describe('Expectation', function() {
}
},
addExpectationResult = jasmine.createSpy('addExpectationResult'),
actual = 'an actual',
expectation;
actual = 'an actual';
expectation = jasmineUnderTest.Expectation.factory({
const expectation = jasmineUnderTest.Expectation.factory({
customMatchers: matchers,
actual: 'an actual',
addExpectationResult: addExpectationResult
@@ -344,7 +327,7 @@ describe('Expectation', function() {
});
it("reports a passing result to the spec when the 'not' comparison passes, given a negativeCompare", function() {
var matchers = {
const matchers = {
toFoo: function() {
return {
compare: function() {
@@ -357,10 +340,9 @@ describe('Expectation', function() {
}
},
addExpectationResult = jasmine.createSpy('addExpectationResult'),
actual = 'an actual',
expectation;
actual = 'an actual';
expectation = jasmineUnderTest.Expectation.factory({
const expectation = jasmineUnderTest.Expectation.factory({
customMatchers: matchers,
actual: 'an actual',
addExpectationResult: addExpectationResult
@@ -380,7 +362,7 @@ describe('Expectation', function() {
});
it("reports a failing result and a custom fail message to the spec when the 'not' comparison fails, given a negativeCompare", function() {
var matchers = {
const matchers = {
toFoo: function() {
return {
compare: function() {
@@ -396,10 +378,9 @@ describe('Expectation', function() {
}
},
addExpectationResult = jasmine.createSpy('addExpectationResult'),
actual = 'an actual',
expectation;
actual = 'an actual';
expectation = jasmineUnderTest.Expectation.factory({
const expectation = jasmineUnderTest.Expectation.factory({
customMatchers: matchers,
actual: 'an actual',
addExpectationResult: addExpectationResult
@@ -419,8 +400,8 @@ describe('Expectation', function() {
});
it('reports a custom error message to the spec', function() {
var customError = new Error('I am a custom error');
var matchers = {
const customError = new Error('I am a custom error');
const matchers = {
toFoo: function() {
return {
compare: function() {
@@ -433,10 +414,9 @@ describe('Expectation', function() {
};
}
},
addExpectationResult = jasmine.createSpy('addExpectationResult'),
expectation;
addExpectationResult = jasmine.createSpy('addExpectationResult');
expectation = jasmineUnderTest.Expectation.factory({
const expectation = jasmineUnderTest.Expectation.factory({
actual: 'an actual',
customMatchers: matchers,
addExpectationResult: addExpectationResult
@@ -456,8 +436,8 @@ describe('Expectation', function() {
});
it("reports a custom message to the spec when a 'not' comparison fails", function() {
var customError = new Error('I am a custom error');
var matchers = {
const customError = new Error('I am a custom error');
const matchers = {
toFoo: function() {
return {
compare: function() {
@@ -470,10 +450,9 @@ describe('Expectation', function() {
};
}
},
addExpectationResult = jasmine.createSpy('addExpectationResult'),
expectation;
addExpectationResult = jasmine.createSpy('addExpectationResult');
expectation = jasmineUnderTest.Expectation.factory({
const expectation = jasmineUnderTest.Expectation.factory({
actual: 'an actual',
customMatchers: matchers,
addExpectationResult: addExpectationResult
@@ -493,8 +472,8 @@ describe('Expectation', function() {
});
it("reports a custom message func to the spec when a 'not' comparison fails", function() {
var customError = new Error('I am a custom error');
var matchers = {
const customError = new Error('I am a custom error');
const matchers = {
toFoo: function() {
return {
compare: function() {
@@ -509,10 +488,9 @@ describe('Expectation', function() {
};
}
},
addExpectationResult = jasmine.createSpy('addExpectationResult'),
expectation;
addExpectationResult = jasmine.createSpy('addExpectationResult');
expectation = jasmineUnderTest.Expectation.factory({
const expectation = jasmineUnderTest.Expectation.factory({
actual: 'an actual',
customMatchers: matchers,
addExpectationResult: addExpectationResult
@@ -533,7 +511,7 @@ describe('Expectation', function() {
describe('#withContext', function() {
it('prepends the context to the generated failure message', function() {
var matchers = {
const matchers = {
toFoo: function() {
return {
compare: function() {
@@ -566,7 +544,7 @@ describe('Expectation', function() {
});
it('prepends the context to a custom failure message', function() {
var matchers = {
const matchers = {
toFoo: function() {
return {
compare: function() {
@@ -593,7 +571,7 @@ describe('Expectation', function() {
});
it('indents a multiline failure message', function() {
var matchers = {
const matchers = {
toFoo: function() {
return {
compare: function() {
@@ -607,19 +585,18 @@ describe('Expectation', function() {
customMatchers: matchers,
actual: 'an actual',
addExpectationResult: addExpectationResult
}),
actualMessage;
});
expectation.withContext('Some context').toFoo('hello');
actualMessage = addExpectationResult.calls.argsFor(0)[1].message;
const actualMessage = addExpectationResult.calls.argsFor(0)[1].message;
expect(actualMessage).toEqual(
'Some context:\n a\n multiline\n message'
);
});
it('prepends the context to a custom failure message from a function', function() {
var matchers = {
const matchers = {
toFoo: function() {
return {
compare: function() {
@@ -651,7 +628,7 @@ describe('Expectation', function() {
});
it('works with #not', function() {
var matchers = {
const matchers = {
toFoo: function() {
return {
compare: function() {
@@ -680,8 +657,8 @@ describe('Expectation', function() {
});
it('works with #not and a custom message', function() {
var customError = new Error('I am a custom error');
var matchers = {
const customError = new Error('I am a custom error');
const matchers = {
toFoo: function() {
return {
compare: function() {

View File

@@ -1,75 +1,65 @@
describe('GlobalErrors', function() {
it('calls the added handler on error', function() {
var fakeGlobal = { onerror: null },
handler = jasmine.createSpy('errorHandler'),
errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
const fakeGlobal = browserGlobal();
const handler = jasmine.createSpy('errorHandler');
const errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
errors.install();
errors.pushListener(handler);
fakeGlobal.onerror('foo');
expect(handler).toHaveBeenCalledWith('foo');
});
it('enables external interception of error by overriding global.onerror', function() {
var fakeGlobal = { onerror: null },
handler = jasmine.createSpy('errorHandler'),
hijackHandler = jasmine.createSpy('hijackErrorHandler'),
errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
errors.install();
errors.pushListener(handler);
fakeGlobal.onerror = hijackHandler;
fakeGlobal.onerror('foo');
expect(hijackHandler).toHaveBeenCalledWith('foo');
expect(handler).not.toHaveBeenCalled();
});
it('calls the global error handler with all parameters', function() {
var fakeGlobal = { onerror: null },
handler = jasmine.createSpy('errorHandler'),
errors = new jasmineUnderTest.GlobalErrors(fakeGlobal),
fooError = new Error('foo');
errors.install();
errors.pushListener(handler);
fakeGlobal.onerror(fooError.message, 'foo.js', 1, 1, fooError);
const error = new Error('nope');
dispatchErrorEvent(fakeGlobal, { error });
expect(handler).toHaveBeenCalledWith(
fooError.message,
'foo.js',
1,
1,
fooError
jasmine.is(error),
jasmine.objectContaining({ error: jasmine.is(error) })
);
});
it('is not affected by overriding global.onerror', function() {
const fakeGlobal = browserGlobal();
const handler = jasmine.createSpy('errorHandler');
const errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
errors.install();
errors.pushListener(handler);
fakeGlobal.onerror = () => {};
const error = new Error('nope');
dispatchErrorEvent(fakeGlobal, { error });
expect(handler).toHaveBeenCalledWith(
jasmine.is(error),
jasmine.objectContaining({ error: jasmine.is(error) })
);
});
it('only calls the most recent handler', function() {
var fakeGlobal = { onerror: null },
handler1 = jasmine.createSpy('errorHandler1'),
handler2 = jasmine.createSpy('errorHandler2'),
errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
const fakeGlobal = browserGlobal();
const handler1 = jasmine.createSpy('errorHandler1');
const handler2 = jasmine.createSpy('errorHandler2');
const errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
errors.install();
errors.pushListener(handler1);
errors.pushListener(handler2);
fakeGlobal.onerror('foo');
const error = new Error('nope');
dispatchErrorEvent(fakeGlobal, { error });
expect(handler1).not.toHaveBeenCalled();
expect(handler2).toHaveBeenCalledWith('foo');
expect(handler2).toHaveBeenCalledWith(
jasmine.is(error),
jasmine.objectContaining({ error: jasmine.is(error) })
);
});
it('calls previous handlers when one is removed', function() {
var fakeGlobal = { onerror: null },
handler1 = jasmine.createSpy('errorHandler1'),
handler2 = jasmine.createSpy('errorHandler2'),
errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
const fakeGlobal = browserGlobal();
const handler1 = jasmine.createSpy('errorHandler1');
const handler2 = jasmine.createSpy('errorHandler2');
const errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
errors.install();
errors.pushListener(handler1);
@@ -77,44 +67,44 @@ describe('GlobalErrors', function() {
errors.popListener(handler2);
fakeGlobal.onerror('foo');
const error = new Error('nope');
dispatchErrorEvent(fakeGlobal, { error });
expect(handler1).toHaveBeenCalledWith('foo');
expect(handler1).toHaveBeenCalledWith(
jasmine.is(error),
jasmine.objectContaining({ error: jasmine.is(error) })
);
expect(handler2).not.toHaveBeenCalled();
});
it('throws when no listener is passed to #popListener', function() {
var errors = new jasmineUnderTest.GlobalErrors({});
const errors = new jasmineUnderTest.GlobalErrors({});
expect(function() {
errors.popListener();
}).toThrowError('popListener expects a listener');
});
it('uninstalls itself, putting back a previous callback', function() {
var originalCallback = jasmine.createSpy('error'),
fakeGlobal = { onerror: originalCallback },
errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
expect(fakeGlobal.onerror).toBe(originalCallback);
it('uninstalls itself', function() {
const fakeGlobal = browserGlobal();
const errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
function unrelatedListener() {}
errors.install();
expect(fakeGlobal.onerror).not.toBe(originalCallback);
fakeGlobal.addEventListener('error', unrelatedListener);
errors.uninstall();
expect(fakeGlobal.onerror).toBe(originalCallback);
expect(fakeGlobal.listeners_.error).toEqual([unrelatedListener]);
});
it('rethrows the original error when there is no handler', function() {
var fakeGlobal = {},
errors = new jasmineUnderTest.GlobalErrors(fakeGlobal),
originalError = new Error('nope');
const fakeGlobal = browserGlobal();
const errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
const originalError = new Error('nope');
errors.install();
try {
fakeGlobal.onerror(originalError);
dispatchErrorEvent(fakeGlobal, { error: originalError });
} catch (e) {
expect(e).toBe(originalError);
}
@@ -123,7 +113,7 @@ describe('GlobalErrors', function() {
});
it('reports uncaught exceptions in node.js', function() {
var fakeGlobal = {
const fakeGlobal = {
process: {
on: jasmine.createSpy('process.on'),
removeListener: jasmine.createSpy('process.removeListener'),
@@ -150,7 +140,7 @@ describe('GlobalErrors', function() {
errors.pushListener(handler);
var addedListener = fakeGlobal.process.on.calls.argsFor(0)[1];
const addedListener = fakeGlobal.process.on.calls.argsFor(0)[1];
addedListener(new Error('bar'));
expect(handler).toHaveBeenCalledWith(new Error('bar'));
@@ -172,7 +162,7 @@ describe('GlobalErrors', function() {
describe('Reporting unhandled promise rejections in node.js', function() {
it('reports rejections with `Error` reasons', function() {
var fakeGlobal = {
const fakeGlobal = {
process: {
on: jasmine.createSpy('process.on'),
removeListener: jasmine.createSpy('process.removeListener'),
@@ -199,7 +189,7 @@ describe('GlobalErrors', function() {
errors.pushListener(handler);
var addedListener = fakeGlobal.process.on.calls.argsFor(1)[1];
const addedListener = fakeGlobal.process.on.calls.argsFor(1)[1];
addedListener(new Error('bar'));
expect(handler).toHaveBeenCalledWith(new Error('bar'));
@@ -220,7 +210,7 @@ describe('GlobalErrors', function() {
});
it('reports rejections with non-`Error` reasons', function() {
var fakeGlobal = {
const fakeGlobal = {
process: {
on: jasmine.createSpy('process.on'),
removeListener: function() {},
@@ -239,7 +229,7 @@ describe('GlobalErrors', function() {
expect(fakeGlobal.process.on.calls.argsFor(1)[0]).toEqual(
'unhandledRejection'
);
var addedListener = fakeGlobal.process.on.calls.argsFor(1)[1];
const addedListener = fakeGlobal.process.on.calls.argsFor(1)[1];
addedListener(17);
expect(handler).toHaveBeenCalledWith(
@@ -252,7 +242,7 @@ describe('GlobalErrors', function() {
});
it('reports rejections with no reason provided', function() {
var fakeGlobal = {
const fakeGlobal = {
process: {
on: jasmine.createSpy('process.on'),
removeListener: function() {},
@@ -271,7 +261,7 @@ describe('GlobalErrors', function() {
expect(fakeGlobal.process.on.calls.argsFor(1)[0]).toEqual(
'unhandledRejection'
);
var addedListener = fakeGlobal.process.on.calls.argsFor(1)[1];
const addedListener = fakeGlobal.process.on.calls.argsFor(1)[1];
addedListener(undefined);
expect(handler).toHaveBeenCalledWith(
@@ -286,136 +276,239 @@ describe('GlobalErrors', function() {
describe('Reporting unhandled promise rejections in the browser', function() {
it('subscribes and unsubscribes from the unhandledrejection event', function() {
var fakeGlobal = jasmine.createSpyObj('globalErrors', [
'addEventListener',
'removeEventListener',
'onerror'
]),
errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
const fakeGlobal = browserGlobal();
const errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
errors.install();
expect(fakeGlobal.addEventListener).toHaveBeenCalledWith(
'unhandledrejection',
expect(fakeGlobal.listeners_.unhandledrejection).toEqual([
jasmine.any(Function)
);
]);
var addedListener = fakeGlobal.addEventListener.calls.argsFor(0)[1];
errors.uninstall();
expect(fakeGlobal.removeEventListener).toHaveBeenCalledWith(
'unhandledrejection',
addedListener
);
expect(fakeGlobal.listeners_.unhandledrejection).toEqual([]);
});
it('reports rejections whose reason is a string', function() {
var fakeGlobal = jasmine.createSpyObj('globalErrors', [
'addEventListener',
'removeEventListener',
'onerror'
]),
handler = jasmine.createSpy('errorHandler'),
errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
const fakeGlobal = browserGlobal();
const handler = jasmine.createSpy('errorHandler');
const errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
errors.install();
errors.pushListener(handler);
var addedListener = fakeGlobal.addEventListener.calls.argsFor(0)[1];
addedListener({ reason: 'nope' });
const event = { reason: 'nope' };
dispatchUnhandledRejectionEvent(fakeGlobal, event);
expect(handler).toHaveBeenCalledWith('Unhandled promise rejection: nope');
expect(handler).toHaveBeenCalledWith(
'Unhandled promise rejection: nope',
event
);
});
it('reports rejections whose reason is an Error', function() {
var fakeGlobal = jasmine.createSpyObj('globalErrors', [
'addEventListener',
'removeEventListener',
'onerror'
]),
handler = jasmine.createSpy('errorHandler'),
errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
const fakeGlobal = browserGlobal();
const handler = jasmine.createSpy('errorHandler');
const errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
errors.install();
errors.pushListener(handler);
var addedListener = fakeGlobal.addEventListener.calls.argsFor(0)[1];
var reason;
try {
// Throwing ensures that we get a stack property in all browsers
throw new Error('bar');
} catch (e) {
reason = e;
}
addedListener({ reason: reason });
const reason = new Error('bar');
const event = { reason };
dispatchUnhandledRejectionEvent(fakeGlobal, event);
expect(handler).toHaveBeenCalledWith(
jasmine.objectContaining({
jasmineMessage: 'Unhandled promise rejection: Error: bar',
message: reason.message,
stack: reason.stack
})
}),
event
);
});
});
describe('Enabling external interception of reported rejections by overriding global.onerror', function() {
it('overriding global.onerror intercepts rejections whose reason is a string', function() {
var fakeGlobal = jasmine.createSpyObj('globalErrors', [
'addEventListener'
]),
handler = jasmine.createSpy('errorHandler'),
hijackHandler = jasmine.createSpy('hijackErrorHandler'),
errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
describe('#setOverrideListener', function() {
it('overrides the existing handlers in browsers until removed', function() {
const fakeGlobal = browserGlobal();
const handler0 = jasmine.createSpy('handler0');
const handler1 = jasmine.createSpy('handler1');
const overrideHandler = jasmine.createSpy('overrideHandler');
const errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
errors.install();
errors.pushListener(handler);
errors.install();
errors.pushListener(handler0);
errors.setOverrideListener(overrideHandler, () => {});
errors.pushListener(handler1);
dispatchErrorEvent(fakeGlobal, { error: 'foo' });
fakeGlobal.onerror = hijackHandler;
expect(overrideHandler).toHaveBeenCalledWith('foo');
expect(handler0).not.toHaveBeenCalled();
expect(handler1).not.toHaveBeenCalled();
var addedListener = fakeGlobal.addEventListener.calls.argsFor(0)[1];
addedListener({ reason: 'nope' });
errors.removeOverrideListener();
expect(hijackHandler).toHaveBeenCalledWith(
'Unhandled promise rejection: nope'
);
expect(handler).not.toHaveBeenCalled();
});
const event = { error: 'baz' };
dispatchErrorEvent(fakeGlobal, event);
expect(overrideHandler).not.toHaveBeenCalledWith('baz');
expect(handler1).toHaveBeenCalledWith('baz', event);
});
it('overriding global.onerror intercepts rejections whose reason is an Error', function() {
var fakeGlobal = jasmine.createSpyObj('globalErrors', [
'addEventListener'
]),
handler = jasmine.createSpy('errorHandler'),
hijackHandler = jasmine.createSpy('hijackErrorHandler'),
errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
errors.install();
errors.pushListener(handler);
fakeGlobal.onerror = hijackHandler;
var addedListener = fakeGlobal.addEventListener.calls.argsFor(0)[1];
var reason;
try {
// Throwing ensures that we get a stack property in all browsers
throw new Error('bar');
} catch (e) {
reason = e;
it('overrides the existing handlers in Node until removed', function() {
const globalEventListeners = {};
const fakeGlobal = {
process: {
on: (name, listener) => (globalEventListeners[name] = listener),
removeListener: () => {},
listeners: name => globalEventListeners[name],
removeAllListeners: name => (globalEventListeners[name] = [])
}
};
const handler0 = jasmine.createSpy('handler0');
const handler1 = jasmine.createSpy('handler1');
const overrideHandler = jasmine.createSpy('overrideHandler');
const errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
addedListener({ reason: reason });
errors.install();
errors.pushListener(handler0);
errors.setOverrideListener(overrideHandler);
errors.pushListener(handler1);
expect(hijackHandler).toHaveBeenCalledWith(
jasmine.objectContaining({
jasmineMessage: 'Unhandled promise rejection: Error: bar',
message: reason.message,
stack: reason.stack
})
);
expect(handler).not.toHaveBeenCalled();
});
globalEventListeners['uncaughtException'](new Error('foo'));
expect(overrideHandler).toHaveBeenCalledWith(new Error('foo'));
expect(handler0).not.toHaveBeenCalled();
expect(handler1).not.toHaveBeenCalled();
errors.removeOverrideListener();
globalEventListeners['uncaughtException'](new Error('bar'));
expect(overrideHandler).not.toHaveBeenCalledWith(new Error('bar'));
expect(handler1).toHaveBeenCalledWith(new Error('bar'));
});
it('handles unhandled promise rejections in browsers', function() {
const globalEventListeners = {};
const fakeGlobal = {
addEventListener(name, listener) {
globalEventListeners[name] = listener;
},
removeEventListener() {}
};
const handler = jasmine.createSpy('handler');
const overrideHandler = jasmine.createSpy('overrideHandler');
const errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
errors.install();
errors.pushListener(handler);
errors.setOverrideListener(overrideHandler, () => {});
const reason = new Error('bar');
globalEventListeners['unhandledrejection']({ reason: reason });
expect(overrideHandler).toHaveBeenCalledWith(
jasmine.objectContaining({
jasmineMessage: 'Unhandled promise rejection: Error: bar',
message: reason.message,
stack: reason.stack
})
);
expect(handler).not.toHaveBeenCalled();
});
it('handles unhandled promise rejections in Node', function() {
const globalEventListeners = {};
const fakeGlobal = {
process: {
on(name, listener) {
globalEventListeners[name] = listener;
},
removeListener() {},
listeners(name) {
return globalEventListeners[name];
},
removeAllListeners(name) {
globalEventListeners[name] = null;
}
}
};
const handler0 = jasmine.createSpy('handler0');
const handler1 = jasmine.createSpy('handler1');
const overrideHandler = jasmine.createSpy('overrideHandler');
const errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
errors.install();
errors.pushListener(handler0);
errors.setOverrideListener(overrideHandler, () => {});
errors.pushListener(handler1);
globalEventListeners['unhandledRejection'](new Error('nope'));
expect(overrideHandler).toHaveBeenCalledWith(new Error('nope'));
expect(handler0).not.toHaveBeenCalled();
expect(handler1).not.toHaveBeenCalled();
});
it('throws if there is already an override handler', function() {
const errors = new jasmineUnderTest.GlobalErrors(browserGlobal());
errors.setOverrideListener(() => {}, () => {});
expect(function() {
errors.setOverrideListener(() => {}, () => {});
}).toThrowError("Can't set more than one override listener at a time");
});
});
describe('#removeOverrideListener', function() {
it("calls the handler's onRemove callback", function() {
const onRemove = jasmine.createSpy('onRemove');
const errors = new jasmineUnderTest.GlobalErrors(browserGlobal());
errors.setOverrideListener(() => {}, onRemove);
errors.removeOverrideListener();
expect(onRemove).toHaveBeenCalledWith();
});
it('does not throw if there is no handler', function() {
const errors = new jasmineUnderTest.GlobalErrors(browserGlobal());
expect(() => errors.removeOverrideListener()).not.toThrow();
});
});
function browserGlobal() {
return {
listeners_: { error: [], unhandledrejection: [] },
addEventListener(eventName, listener) {
this.listeners_[eventName].push(listener);
},
removeEventListener(eventName, listener) {
this.listeners_[eventName] = this.listeners_[eventName].filter(
l => l !== listener
);
}
};
}
function dispatchErrorEvent(global, event) {
expect(global.listeners_.error.length)
.withContext('number of error listeners')
.toBeGreaterThan(0);
for (const l of global.listeners_.error) {
l(event);
}
}
function dispatchUnhandledRejectionEvent(global, event) {
expect(global.listeners_.unhandledrejection.length)
.withContext('number of unhandledrejection listeners')
.toBeGreaterThan(0);
for (const l of global.listeners_.unhandledrejection) {
l(event);
}
}
});

View File

@@ -1,6 +1,6 @@
describe('JsApiReporter', function() {
it('knows when a full environment is started', function() {
var reporter = new jasmineUnderTest.JsApiReporter({});
const reporter = new jasmineUnderTest.JsApiReporter({});
expect(reporter.started).toBe(false);
expect(reporter.finished).toBe(false);
@@ -12,7 +12,7 @@ describe('JsApiReporter', function() {
});
it('knows when a full environment is done', function() {
var reporter = new jasmineUnderTest.JsApiReporter({});
const reporter = new jasmineUnderTest.JsApiReporter({});
expect(reporter.started).toBe(false);
expect(reporter.finished).toBe(false);
@@ -24,13 +24,13 @@ describe('JsApiReporter', function() {
});
it("defaults to 'loaded' status", function() {
var reporter = new jasmineUnderTest.JsApiReporter({});
const reporter = new jasmineUnderTest.JsApiReporter({});
expect(reporter.status()).toEqual('loaded');
});
it("reports 'started' when Jasmine has started", function() {
var reporter = new jasmineUnderTest.JsApiReporter({});
const reporter = new jasmineUnderTest.JsApiReporter({});
reporter.jasmineStarted();
@@ -38,7 +38,7 @@ describe('JsApiReporter', function() {
});
it("reports 'done' when Jasmine is done", function() {
var reporter = new jasmineUnderTest.JsApiReporter({});
const reporter = new jasmineUnderTest.JsApiReporter({});
reporter.jasmineDone({});
@@ -46,14 +46,14 @@ describe('JsApiReporter', function() {
});
it('tracks a suite', function() {
var reporter = new jasmineUnderTest.JsApiReporter({});
const reporter = new jasmineUnderTest.JsApiReporter({});
reporter.suiteStarted({
id: 123,
description: 'A suite'
});
var suites = reporter.suites();
const suites = reporter.suites();
expect(suites).toEqual({ 123: { id: 123, description: 'A suite' } });
@@ -69,7 +69,7 @@ describe('JsApiReporter', function() {
});
describe('#specResults', function() {
var reporter, specResult1, specResult2;
let reporter, specResult1, specResult2;
beforeEach(function() {
reporter = new jasmineUnderTest.JsApiReporter({});
specResult1 = {
@@ -99,7 +99,7 @@ describe('JsApiReporter', function() {
});
describe('#suiteResults', function() {
var reporter, suiteResult1, suiteResult2;
let reporter, suiteStarted1, suiteResult1, suiteResult2;
beforeEach(function() {
reporter = new jasmineUnderTest.JsApiReporter({});
suiteStarted1 = {
@@ -137,7 +137,7 @@ describe('JsApiReporter', function() {
describe('#executionTime', function() {
it('should start the timer when jasmine starts', function() {
var timerSpy = jasmine.createSpyObj('timer', ['start', 'elapsed']),
const timerSpy = jasmine.createSpyObj('timer', ['start', 'elapsed']),
reporter = new jasmineUnderTest.JsApiReporter({
timer: timerSpy
});
@@ -147,7 +147,7 @@ describe('JsApiReporter', function() {
});
it('should return the time it took the specs to run, in ms', function() {
var timerSpy = jasmine.createSpyObj('timer', ['start', 'elapsed']),
const timerSpy = jasmine.createSpyObj('timer', ['start', 'elapsed']),
reporter = new jasmineUnderTest.JsApiReporter({
timer: timerSpy
});
@@ -159,7 +159,7 @@ describe('JsApiReporter', function() {
describe("when the specs haven't finished being run", function() {
it('should return undefined', function() {
var timerSpy = jasmine.createSpyObj('timer', ['start', 'elapsed']),
const timerSpy = jasmine.createSpyObj('timer', ['start', 'elapsed']),
reporter = new jasmineUnderTest.JsApiReporter({
timer: timerSpy
});
@@ -171,7 +171,7 @@ describe('JsApiReporter', function() {
describe('#runDetails', function() {
it('should have details about the run', function() {
var reporter = new jasmineUnderTest.JsApiReporter({});
const reporter = new jasmineUnderTest.JsApiReporter({});
reporter.jasmineDone({ some: { run: 'details' } });
expect(reporter.runDetails).toEqual({ some: { run: 'details' } });
});

View File

@@ -1,6 +1,6 @@
describe('FakeDate', function() {
it('does not fail if no global date is found', function() {
var fakeGlobal = {},
const fakeGlobal = {},
mockDate = new jasmineUnderTest.MockDate(fakeGlobal);
expect(function() {
@@ -11,11 +11,13 @@ describe('FakeDate', function() {
});
it('replaces the global Date when it is installed', function() {
var globalDate = jasmine.createSpy('global Date').and.callFake(function() {
return {
getTime: function() {}
};
}),
const globalDate = jasmine
.createSpy('global Date')
.and.callFake(function() {
return {
getTime: function() {}
};
}),
fakeGlobal = { Date: globalDate },
mockDate = new jasmineUnderTest.MockDate(fakeGlobal);
@@ -26,11 +28,13 @@ describe('FakeDate', function() {
});
it('replaces the global Date on uninstall', function() {
var globalDate = jasmine.createSpy('global Date').and.callFake(function() {
return {
getTime: function() {}
};
}),
const globalDate = jasmine
.createSpy('global Date')
.and.callFake(function() {
return {
getTime: function() {}
};
}),
fakeGlobal = { Date: globalDate },
mockDate = new jasmineUnderTest.MockDate(fakeGlobal);
@@ -41,13 +45,15 @@ describe('FakeDate', function() {
});
it('takes the current time as the base when installing without parameters', function() {
var globalDate = jasmine.createSpy('global Date').and.callFake(function() {
return {
getTime: function() {
return 1000;
}
};
}),
const globalDate = jasmine
.createSpy('global Date')
.and.callFake(function() {
return {
getTime: function() {
return 1000;
}
};
}),
fakeGlobal = { Date: globalDate },
mockDate = new jasmineUnderTest.MockDate(fakeGlobal);
@@ -59,7 +65,7 @@ describe('FakeDate', function() {
});
it('can accept a date as time base when installing', function() {
var fakeGlobal = { Date: Date },
const fakeGlobal = { Date: Date },
mockDate = new jasmineUnderTest.MockDate(fakeGlobal),
baseDate = new Date();
@@ -70,7 +76,7 @@ describe('FakeDate', function() {
});
it('makes real dates', function() {
var fakeGlobal = { Date: Date },
const fakeGlobal = { Date: Date },
mockDate = new jasmineUnderTest.MockDate(fakeGlobal);
mockDate.install();
@@ -79,53 +85,39 @@ describe('FakeDate', function() {
});
it('fakes current time when using Date.now()', function() {
var globalDate = jasmine.createSpy('global Date').and.callFake(function() {
return {
getTime: function() {
return 1000;
}
};
}),
const globalDate = jasmine
.createSpy('global Date')
.and.callFake(function() {
return {
getTime: function() {
return 1000;
}
};
}),
fakeGlobal = { Date: globalDate };
globalDate.now = function() {};
var mockDate = new jasmineUnderTest.MockDate(fakeGlobal);
const mockDate = new jasmineUnderTest.MockDate(fakeGlobal);
mockDate.install();
expect(fakeGlobal.Date.now()).toEqual(1000);
});
it("does not stub Date.now() if it doesn't already exist", function() {
var globalDate = jasmine.createSpy('global Date').and.callFake(function() {
return {
getTime: function() {
return 1000;
}
};
}),
fakeGlobal = { Date: globalDate },
mockDate = new jasmineUnderTest.MockDate(fakeGlobal);
mockDate.install();
expect(fakeGlobal.Date.now).toThrowError(
'Browser does not support Date.now()'
);
});
it('makes time passes using tick', function() {
var globalDate = jasmine.createSpy('global Date').and.callFake(function() {
return {
getTime: function() {
return 1000;
}
};
}),
const globalDate = jasmine
.createSpy('global Date')
.and.callFake(function() {
return {
getTime: function() {
return 1000;
}
};
}),
fakeGlobal = { Date: globalDate };
globalDate.now = function() {};
var mockDate = new jasmineUnderTest.MockDate(fakeGlobal);
const mockDate = new jasmineUnderTest.MockDate(fakeGlobal);
mockDate.install();
@@ -139,17 +131,19 @@ describe('FakeDate', function() {
});
it('allows to increase 0 milliseconds using tick', function() {
var globalDate = jasmine.createSpy('global Date').and.callFake(function() {
return {
getTime: function() {
return 1000;
}
};
}),
const globalDate = jasmine
.createSpy('global Date')
.and.callFake(function() {
return {
getTime: function() {
return 1000;
}
};
}),
fakeGlobal = { Date: globalDate };
globalDate.now = function() {};
var mockDate = new jasmineUnderTest.MockDate(fakeGlobal);
const mockDate = new jasmineUnderTest.MockDate(fakeGlobal);
mockDate.install();
@@ -161,40 +155,40 @@ describe('FakeDate', function() {
});
it('allows creation of a Date in a different time than the mocked time', function() {
var fakeGlobal = { Date: Date },
const fakeGlobal = { Date: Date },
mockDate = new jasmineUnderTest.MockDate(fakeGlobal);
mockDate.install();
var otherDate = new fakeGlobal.Date(2013, 9, 23, 0, 0, 1, 0);
const otherDate = new fakeGlobal.Date(2013, 9, 23, 0, 0, 1, 0);
expect(otherDate.getTime()).toEqual(
new Date(2013, 9, 23, 0, 0, 1, 0).getTime()
);
});
it("allows creation of a Date that isn't fully specified", function() {
var fakeGlobal = { Date: Date },
const fakeGlobal = { Date: Date },
mockDate = new jasmineUnderTest.MockDate(fakeGlobal);
mockDate.install();
var otherDate = new fakeGlobal.Date(2013, 9, 23);
const otherDate = new fakeGlobal.Date(2013, 9, 23);
expect(otherDate.getTime()).toEqual(new Date(2013, 9, 23).getTime());
});
it('allows creation of a Date with millis', function() {
var fakeGlobal = { Date: Date },
const fakeGlobal = { Date: Date },
mockDate = new jasmineUnderTest.MockDate(fakeGlobal),
now = new Date(2014, 3, 15).getTime();
mockDate.install();
var otherDate = new fakeGlobal.Date(now);
const otherDate = new fakeGlobal.Date(now);
expect(otherDate.getTime()).toEqual(now);
});
it('copies all Date properties to the mocked date', function() {
var fakeGlobal = { Date: Date },
const fakeGlobal = { Date: Date },
mockDate = new jasmineUnderTest.MockDate(fakeGlobal);
mockDate.install();

View File

@@ -0,0 +1,176 @@
describe('ParallelReportDispatcher', function() {
it('dispatches the standard reporter events', async function() {
const subject = new jasmineUnderTest.ParallelReportDispatcher(() => {}, {
globalErrors: mockGlobalErrors()
});
const events = [
'jasmineStarted',
'jasmineDone',
'suiteStarted',
'suiteDone',
'specStarted',
'specDone'
];
const reporter = jasmine.createSpyObj('reporter', events);
subject.addReporter(reporter);
for (const eventName of events) {
const payload = { payloadFor: eventName };
await subject[eventName](payload);
expect(reporter[eventName]).toHaveBeenCalledWith(payload);
}
});
it('installs and uninstalls the global error handler', function() {
const globalErrors = mockGlobalErrors();
const subject = new jasmineUnderTest.ParallelReportDispatcher(() => {}, {
globalErrors
});
subject.installGlobalErrors();
expect(globalErrors.install).toHaveBeenCalled();
subject.uninstallGlobalErrors();
expect(globalErrors.uninstall).toHaveBeenCalled();
});
it('handles global errors from async reporters', async function() {
const globalErrors = mockGlobalErrors();
const onError = jasmine.createSpy('onError');
const subject = new jasmineUnderTest.ParallelReportDispatcher(onError, {
globalErrors
});
const reporter = jasmine.createSpyObj('reporter', [
'jasmineStarted',
'jasmineDone'
]);
let resolveStarted;
reporter.jasmineStarted.and.callFake(function() {
return new Promise(function(res) {
resolveStarted = res;
});
});
subject.addReporter(reporter);
const promise = subject.jasmineStarted({});
expect(globalErrors.pushListener).toHaveBeenCalled();
expect(globalErrors.popListener).not.toHaveBeenCalled();
const error = new Error('nope');
globalErrors.pushListener.calls.argsFor(0)[0](error);
expect(onError).toHaveBeenCalledWith(error);
resolveStarted();
await promise;
expect(globalErrors.popListener).toHaveBeenCalled();
});
it('handles done(error) from callback-style async reporters', function() {
const globalErrors = mockGlobalErrors();
const onError = jasmine.createSpy('onError');
const subject = new jasmineUnderTest.ParallelReportDispatcher(onError, {
globalErrors
});
const reporter = jasmine.createSpyObj('reporter', [
'jasmineStarted',
'jasmineDone'
]);
let callback;
reporter.jasmineStarted = function(event, cb) {
callback = cb;
};
subject.addReporter(reporter);
subject.jasmineStarted({});
expect(callback).toBeInstanceOf(Function);
const error = new Error('nope');
callback(error);
expect(onError).toHaveBeenCalledWith(error);
});
it('handles done.fail() from callback-style async reporters', function() {
const globalErrors = mockGlobalErrors();
const onError = jasmine.createSpy('onError');
const subject = new jasmineUnderTest.ParallelReportDispatcher(onError, {
globalErrors
});
const reporter = jasmine.createSpyObj('reporter', [
'jasmineStarted',
'jasmineDone'
]);
let callback;
reporter.jasmineStarted = function(event, cb) {
callback = cb;
};
subject.addReporter(reporter);
subject.jasmineStarted({});
expect(callback).toBeInstanceOf(Function);
const error = new Error('nope');
callback.fail(error);
expect(onError).toHaveBeenCalledWith(error);
onError.calls.reset();
callback.fail();
expect(onError).toHaveBeenCalledWith(
new Error('A reporter called done.fail()')
);
});
it('handles errors due to mixed async style in reporters', async function() {
const globalErrors = mockGlobalErrors();
const onError = jasmine.createSpy('onError');
const subject = new jasmineUnderTest.ParallelReportDispatcher(onError, {
globalErrors
});
subject.addReporter({
async jasmineStarted(event, done) {
done();
}
});
await subject.jasmineStarted({});
expect(onError).toHaveBeenCalledWith(
new Error(
'An asynchronous before/it/after function took a done callback but also returned a promise. Either remove the done callback (recommended) or change the function to not return a promise.'
)
);
});
it('handles errors due to multiple done calls in reporters', async function() {
const globalErrors = mockGlobalErrors();
const onError = jasmine.createSpy('onError');
const subject = new jasmineUnderTest.ParallelReportDispatcher(onError, {
globalErrors
});
subject.addReporter({
jasmineStarted(event, done) {
done();
done();
}
});
await subject.jasmineStarted({});
expect(onError).toHaveBeenCalledWith(
new Error(
"An asynchronous reporter callback called its 'done' callback more than once."
)
);
});
function mockGlobalErrors() {
const globalErrors = jasmine.createSpyObj('globalErrors', [
'install',
'pushListener',
'popListener'
]);
globalErrors.install.and.callFake(function() {
globalErrors.uninstall = jasmine.createSpy('globalErrors.uninstall');
});
return globalErrors;
}
});

View File

@@ -1,12 +1,20 @@
describe('PrettyPrinter', function() {
it('should wrap strings in single quotes', function() {
var pp = jasmineUnderTest.makePrettyPrinter();
const pp = jasmineUnderTest.makePrettyPrinter();
expect(pp('some string')).toEqual("'some string'");
expect(pp("som' string")).toEqual("'som' string'");
});
it('stringifies empty string primitives and objects recognizably', function() {
const pp = jasmineUnderTest.makePrettyPrinter();
expect(pp(new String(''))).toEqual(pp(''));
expect(pp(new String(''))).toEqual("''");
expect(pp([new String('')])).toEqual(pp(['']));
expect(pp([new String('')])).toEqual("[ '' ]");
});
it('should stringify primitives properly', function() {
var pp = jasmineUnderTest.makePrettyPrinter();
const pp = jasmineUnderTest.makePrettyPrinter();
expect(pp(true)).toEqual('true');
expect(pp(false)).toEqual('false');
expect(pp(null)).toEqual('null');
@@ -18,25 +26,23 @@ describe('PrettyPrinter', function() {
describe('stringify sets', function() {
it('should stringify sets properly', function() {
jasmine.getEnv().requireFunctioningSets();
var set = new Set(); // eslint-disable-line compat/compat
const set = new Set();
set.add(1);
set.add(2);
var pp = jasmineUnderTest.makePrettyPrinter();
const pp = jasmineUnderTest.makePrettyPrinter();
expect(pp(set)).toEqual('Set( 1, 2 )');
});
it('should truncate sets with more elements than jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH', function() {
jasmine.getEnv().requireFunctioningSets();
var originalMaxSize = jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH;
const originalMaxSize = jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH;
try {
jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH = 2;
var set = new Set(); // eslint-disable-line compat/compat
const set = new Set();
set.add('a');
set.add('b');
set.add('c');
var pp = jasmineUnderTest.makePrettyPrinter();
const pp = jasmineUnderTest.makePrettyPrinter();
expect(pp(set)).toEqual("Set( 'a', 'b', ... )");
} finally {
jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH = originalMaxSize;
@@ -46,24 +52,22 @@ describe('PrettyPrinter', function() {
describe('stringify maps', function() {
it('should stringify maps properly', function() {
jasmine.getEnv().requireFunctioningMaps();
var map = new Map(); // eslint-disable-line compat/compat
const map = new Map();
map.set(1, 2);
var pp = jasmineUnderTest.makePrettyPrinter();
const pp = jasmineUnderTest.makePrettyPrinter();
expect(pp(map)).toEqual('Map( [ 1, 2 ] )');
});
it('should truncate maps with more elements than jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH', function() {
jasmine.getEnv().requireFunctioningMaps();
var originalMaxSize = jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH;
const originalMaxSize = jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH;
try {
jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH = 2;
var map = new Map(); // eslint-disable-line compat/compat
const map = new Map();
map.set('a', 1);
map.set('b', 2);
map.set('c', 3);
var pp = jasmineUnderTest.makePrettyPrinter();
const pp = jasmineUnderTest.makePrettyPrinter();
expect(pp(map)).toEqual("Map( [ 'a', 1 ], [ 'b', 2 ], ... )");
} finally {
jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH = originalMaxSize;
@@ -73,17 +77,22 @@ describe('PrettyPrinter', function() {
describe('stringify arrays', function() {
it('should stringify arrays properly', function() {
var pp = jasmineUnderTest.makePrettyPrinter();
const pp = jasmineUnderTest.makePrettyPrinter();
expect(pp([1, 2])).toEqual('[ 1, 2 ]');
expect(pp([1, 'foo', {}, jasmine.undefined, null])).toEqual(
"[ 1, 'foo', Object({ }), undefined, null ]"
);
});
it('includes symbols', function() {
const pp = jasmineUnderTest.makePrettyPrinter();
expect(pp([1, Symbol('foo'), 2])).toEqual('[ 1, Symbol(foo), 2 ]');
});
it('should truncate arrays that are longer than jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH', function() {
var originalMaxLength = jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH;
var array = [1, 2, 3];
var pp = jasmineUnderTest.makePrettyPrinter();
const originalMaxLength = jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH;
const array = [1, 2, 3];
const pp = jasmineUnderTest.makePrettyPrinter();
try {
jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH = 2;
@@ -94,25 +103,25 @@ describe('PrettyPrinter', function() {
});
it('should stringify arrays with properties properly', function() {
var pp = jasmineUnderTest.makePrettyPrinter();
var arr = [1, 2];
const pp = jasmineUnderTest.makePrettyPrinter();
const arr = [1, 2];
arr.foo = 'bar';
arr.baz = {};
expect(pp(arr)).toEqual("[ 1, 2, foo: 'bar', baz: Object({ }) ]");
});
it('should stringify empty arrays with properties properly', function() {
var pp = jasmineUnderTest.makePrettyPrinter();
var empty = [];
const pp = jasmineUnderTest.makePrettyPrinter();
const empty = [];
empty.foo = 'bar';
empty.baz = {};
expect(pp(empty)).toEqual("[ foo: 'bar', baz: Object({ }) ]");
});
it('should stringify long arrays with properties properly', function() {
var pp = jasmineUnderTest.makePrettyPrinter();
var originalMaxLength = jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH;
var long = [1, 2, 3];
const pp = jasmineUnderTest.makePrettyPrinter();
const originalMaxLength = jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH;
const long = [1, 2, 3];
long.foo = 'bar';
long.baz = {};
@@ -127,22 +136,22 @@ describe('PrettyPrinter', function() {
});
it('should indicate circular array references', function() {
var pp = jasmineUnderTest.makePrettyPrinter();
var array1 = [1, 2];
var array2 = [array1];
const pp = jasmineUnderTest.makePrettyPrinter();
const array1 = [1, 2];
const array2 = [array1];
array1.push(array2);
expect(pp(array1)).toEqual('[ 1, 2, [ <circular reference: Array> ] ]');
});
it('should not indicate circular references incorrectly', function() {
var pp = jasmineUnderTest.makePrettyPrinter();
var array = [[1]];
const pp = jasmineUnderTest.makePrettyPrinter();
const array = [[1]];
expect(pp(array)).toEqual('[ [ 1 ] ]');
});
});
it('should stringify objects properly', function() {
var pp = jasmineUnderTest.makePrettyPrinter();
const pp = jasmineUnderTest.makePrettyPrinter();
expect(pp({ foo: 'bar' })).toEqual("Object({ foo: 'bar' })");
expect(
pp({
@@ -159,15 +168,34 @@ describe('PrettyPrinter', function() {
);
});
it('includes symbol keys in objects', function() {
const pp = jasmineUnderTest.makePrettyPrinter();
const obj = {};
obj[Symbol('foo')] = 'bar';
expect(pp(obj)).toEqual("Object({ Symbol(foo): 'bar' })");
});
it('stringifies string and symbol keys differently', function() {
const pp = jasmineUnderTest.makePrettyPrinter();
const symObj = {};
const strObj = {};
const k = 'foo';
const v = 'bar';
symObj[Symbol(k)] = v;
strObj[k] = v;
expect(pp(symObj)).not.toEqual(pp(strObj));
});
it('should stringify objects that almost look like DOM nodes', function() {
var pp = jasmineUnderTest.makePrettyPrinter();
const pp = jasmineUnderTest.makePrettyPrinter();
expect(pp({ nodeType: 1 })).toEqual('Object({ nodeType: 1 })');
});
it('should truncate objects with too many keys', function() {
var pp = jasmineUnderTest.makePrettyPrinter();
var originalMaxLength = jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH;
var long = { a: 1, b: 2, c: 3 };
const pp = jasmineUnderTest.makePrettyPrinter();
const originalMaxLength = jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH;
const long = { a: 1, b: 2, c: 3 };
try {
jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH = 2;
@@ -178,7 +206,7 @@ describe('PrettyPrinter', function() {
});
function withMaxChars(maxChars, fn) {
var originalMaxChars = jasmineUnderTest.MAX_PRETTY_PRINT_CHARS;
const originalMaxChars = jasmineUnderTest.MAX_PRETTY_PRINT_CHARS;
try {
jasmineUnderTest.MAX_PRETTY_PRINT_CHARS = maxChars;
@@ -189,8 +217,8 @@ describe('PrettyPrinter', function() {
}
it('should truncate outputs that are too long', function() {
var pp = jasmineUnderTest.makePrettyPrinter();
var big = [{ a: 1, b: 'a long string' }, {}];
const pp = jasmineUnderTest.makePrettyPrinter();
const big = [{ a: 1, b: 'a long string' }, {}];
withMaxChars(34, function() {
expect(pp(big)).toEqual("[ Object({ a: 1, b: 'a long st ...");
@@ -198,7 +226,7 @@ describe('PrettyPrinter', function() {
});
it('should not serialize more objects after hitting MAX_PRETTY_PRINT_CHARS', function() {
var a = {
const a = {
jasmineToString: function() {
return 'object a';
}
@@ -228,25 +256,25 @@ describe('PrettyPrinter', function() {
});
it("should print 'null' as the constructor of an object with its own constructor property", function() {
var pp = jasmineUnderTest.makePrettyPrinter();
const pp = jasmineUnderTest.makePrettyPrinter();
expect(pp({ constructor: function() {} })).toContain('null({');
expect(pp({ constructor: 'foo' })).toContain('null({');
});
it('should not include inherited properties when stringifying an object', function() {
var pp = jasmineUnderTest.makePrettyPrinter();
var SomeClass = function SomeClass() {};
const pp = jasmineUnderTest.makePrettyPrinter();
const SomeClass = function SomeClass() {};
SomeClass.prototype.foo = 'inherited foo';
var instance = new SomeClass();
const instance = new SomeClass();
instance.bar = 'my own bar';
expect(pp(instance)).toEqual("SomeClass({ bar: 'my own bar' })");
});
it('should not recurse objects and arrays more deeply than jasmineUnderTest.MAX_PRETTY_PRINT_DEPTH', function() {
var pp = jasmineUnderTest.makePrettyPrinter();
var originalMaxDepth = jasmineUnderTest.MAX_PRETTY_PRINT_DEPTH;
var nestedObject = { level1: { level2: { level3: { level4: 'leaf' } } } };
var nestedArray = [1, [2, [3, [4, 'leaf']]]];
const pp = jasmineUnderTest.makePrettyPrinter();
const originalMaxDepth = jasmineUnderTest.MAX_PRETTY_PRINT_DEPTH;
const nestedObject = { level1: { level2: { level3: { level4: 'leaf' } } } };
const nestedArray = [1, [2, [3, [4, 'leaf']]]];
try {
jasmineUnderTest.MAX_PRETTY_PRINT_DEPTH = 2;
@@ -272,69 +300,62 @@ describe('PrettyPrinter', function() {
});
it('should stringify immutable circular objects', function() {
if (Object.freeze) {
var pp = jasmineUnderTest.makePrettyPrinter();
var frozenObject = { foo: { bar: 'baz' } };
frozenObject.circular = frozenObject;
frozenObject = Object.freeze(frozenObject);
expect(pp(frozenObject)).toEqual(
"Object({ foo: Object({ bar: 'baz' }), circular: <circular reference: Object> })"
);
}
const pp = jasmineUnderTest.makePrettyPrinter();
let frozenObject = { foo: { bar: 'baz' } };
frozenObject.circular = frozenObject;
frozenObject = Object.freeze(frozenObject);
expect(pp(frozenObject)).toEqual(
"Object({ foo: Object({ bar: 'baz' }), circular: <circular reference: Object> })"
);
});
it('should stringify RegExp objects properly', function() {
var pp = jasmineUnderTest.makePrettyPrinter();
const pp = jasmineUnderTest.makePrettyPrinter();
expect(pp(/x|y|z/)).toEqual('/x|y|z/');
});
it('should indicate circular object references', function() {
var pp = jasmineUnderTest.makePrettyPrinter();
var sampleValue = { foo: 'hello' };
const pp = jasmineUnderTest.makePrettyPrinter();
const sampleValue = { foo: 'hello' };
sampleValue.nested = sampleValue;
expect(pp(sampleValue)).toEqual(
"Object({ foo: 'hello', nested: <circular reference: Object> })"
);
});
it('should indicate getters on objects as such', function() {
var pp = jasmineUnderTest.makePrettyPrinter();
var sampleValue = { id: 1 };
if (sampleValue.__defineGetter__) {
//not supported in IE!
sampleValue.__defineGetter__('calculatedValue', function() {
throw new Error("don't call me!");
});
}
if (sampleValue.__defineGetter__) {
expect(pp(sampleValue)).toEqual(
'Object({ id: 1, calculatedValue: <getter> })'
);
} else {
expect(pp(sampleValue)).toEqual('Object({ id: 1 })');
}
it('should use the return value of getters', function() {
const pp = jasmineUnderTest.makePrettyPrinter();
const sampleValue = {
id: 1,
get calculatedValue() {
return 'the getter return value';
}
};
expect(pp(sampleValue)).toEqual(
"Object({ id: 1, calculatedValue: 'the getter return value' })"
);
});
it('should not do HTML escaping of strings', function() {
var pp = jasmineUnderTest.makePrettyPrinter();
const pp = jasmineUnderTest.makePrettyPrinter();
expect(pp('some <b>html string</b> &', false)).toEqual(
"'some <b>html string</b> &'"
);
});
it('should abbreviate the global (usually window) object', function() {
var pp = jasmineUnderTest.makePrettyPrinter();
const pp = jasmineUnderTest.makePrettyPrinter();
expect(pp(jasmine.getGlobal())).toEqual('<global>');
});
it('should stringify Date objects properly', function() {
var pp = jasmineUnderTest.makePrettyPrinter();
var now = new Date();
const pp = jasmineUnderTest.makePrettyPrinter();
const now = new Date();
expect(pp(now)).toEqual('Date(' + now.toString() + ')');
});
describe('with a spy object', function() {
var env, pp;
let env, pp;
beforeEach(function() {
env = new jasmineUnderTest.Env();
@@ -346,11 +367,11 @@ describe('PrettyPrinter', function() {
});
it('should stringify spy objects properly', function() {
var TestObject = {
const TestObject = {
someFunction: function() {}
};
var spyRegistry = new jasmineUnderTest.SpyRegistry({
const spyRegistry = new jasmineUnderTest.SpyRegistry({
currentSpies: function() {
return [];
},
@@ -366,13 +387,13 @@ describe('PrettyPrinter', function() {
});
it('should stringify spyOn toString properly', function() {
var TestObject = {
const TestObject = {
someFunction: function() {}
},
env = new jasmineUnderTest.Env(),
pp = jasmineUnderTest.makePrettyPrinter();
var spyRegistry = new jasmineUnderTest.SpyRegistry({
const spyRegistry = new jasmineUnderTest.SpyRegistry({
currentSpies: function() {
return [];
},
@@ -382,15 +403,15 @@ describe('PrettyPrinter', function() {
});
spyRegistry.spyOn(TestObject, 'toString');
var testSpyObj = env.createSpyObj('TheClassName', ['toString']);
const testSpyObj = env.createSpyObj('TheClassName', ['toString']);
expect(pp(testSpyObj)).toEqual('spy on TheClassName.toString');
});
});
it('should stringify objects that implement jasmineToString', function() {
var pp = jasmineUnderTest.makePrettyPrinter();
var obj = {
const pp = jasmineUnderTest.makePrettyPrinter();
const obj = {
jasmineToString: function() {
return 'strung';
}
@@ -400,8 +421,8 @@ describe('PrettyPrinter', function() {
});
it('should pass itself to jasmineToString', function() {
var pp = jasmineUnderTest.makePrettyPrinter([]);
var obj = {
const pp = jasmineUnderTest.makePrettyPrinter([]);
const obj = {
jasmineToString: jasmine.createSpy('jasmineToString').and.returnValue('')
};
@@ -410,8 +431,8 @@ describe('PrettyPrinter', function() {
});
it('should stringify objects that implement custom toString', function() {
var pp = jasmineUnderTest.makePrettyPrinter();
var obj = {
const pp = jasmineUnderTest.makePrettyPrinter();
const obj = {
toString: function() {
return 'my toString';
}
@@ -421,7 +442,7 @@ describe('PrettyPrinter', function() {
// Simulate object from another global context (e.g. an iframe or Web Worker) that does not actually have a custom
// toString despite obj.toString !== Object.prototype.toString
var objFromOtherContext = {
const objFromOtherContext = {
foo: 'bar',
toString: function() {
return Object.prototype.toString.call(this);
@@ -434,8 +455,8 @@ describe('PrettyPrinter', function() {
});
it("should stringify objects have have a toString that isn't a function", function() {
var pp = jasmineUnderTest.makePrettyPrinter();
var obj = {
const pp = jasmineUnderTest.makePrettyPrinter();
const obj = {
toString: 'foo'
};
@@ -443,30 +464,30 @@ describe('PrettyPrinter', function() {
});
it('should stringify objects from anonymous constructors with custom toString', function() {
var pp = jasmineUnderTest.makePrettyPrinter();
var MyAnonymousConstructor = (function() {
const pp = jasmineUnderTest.makePrettyPrinter();
const MyAnonymousConstructor = (function() {
return function() {};
})();
MyAnonymousConstructor.toString = function() {
return '';
};
var a = new MyAnonymousConstructor();
const a = new MyAnonymousConstructor();
expect(pp(a)).toEqual('<anonymous>({ })');
});
it('should handle objects with null prototype', function() {
var pp = jasmineUnderTest.makePrettyPrinter();
var obj = Object.create(null);
const pp = jasmineUnderTest.makePrettyPrinter();
const obj = Object.create(null);
obj.foo = 'bar';
expect(pp(obj)).toEqual("null({ foo: 'bar' })");
});
it('should gracefully handle objects with invalid toString implementations', function() {
var pp = jasmineUnderTest.makePrettyPrinter();
var obj = {
const pp = jasmineUnderTest.makePrettyPrinter();
const obj = {
foo: {
toString: function() {
// Invalid: toString returning a number
@@ -502,8 +523,8 @@ describe('PrettyPrinter', function() {
describe('Custom object formatters', function() {
it('should use the first custom object formatter that does not return undefined', function() {
var customObjectFormatters = [
function(obj) {
const customObjectFormatters = [
function() {
return undefined;
},
function(obj) {
@@ -520,8 +541,8 @@ describe('PrettyPrinter', function() {
});
it('should fall back to built in logic if all custom object formatters return undefined', function() {
var customObjectFormatters = [
function(obj) {
const customObjectFormatters = [
function() {
return undefined;
}
],
@@ -534,8 +555,8 @@ describe('PrettyPrinter', function() {
describe('#customFormat_', function() {
it('should use the first custom object formatter that does not return undefined', function() {
var customObjectFormatters = [
function(obj) {
const customObjectFormatters = [
function() {
return undefined;
},
function(obj) {
@@ -552,8 +573,8 @@ describe('PrettyPrinter', function() {
});
it('should return undefined if all custom object formatters return undefined', function() {
var customObjectFormatters = [
function(obj) {
const customObjectFormatters = [
function() {
return undefined;
}
],

View File

@@ -1,6 +1,6 @@
describe('QueueRunner', function() {
it("runs all the functions it's passed", function() {
var calls = [],
const calls = [],
queueableFn1 = { fn: jasmine.createSpy('fn1') },
queueableFn2 = { fn: jasmine.createSpy('fn2') },
queueRunner = new jasmineUnderTest.QueueRunner({
@@ -18,30 +18,11 @@ describe('QueueRunner', function() {
expect(calls).toEqual(['fn1', 'fn2']);
});
it('runs cleanup functions after the others', function() {
var calls = [],
queueableFn1 = { fn: jasmine.createSpy('fn1') },
queueableFn2 = { fn: jasmine.createSpy('fn2') },
queueRunner = new jasmineUnderTest.QueueRunner({
queueableFns: [queueableFn1],
cleanupFns: [queueableFn2]
});
queueableFn1.fn.and.callFake(function() {
calls.push('fn1');
});
queueableFn2.fn.and.callFake(function() {
calls.push('fn2');
});
queueRunner.execute();
expect(calls).toEqual(['fn1', 'fn2']);
});
it("calls each function with a consistent 'this'-- an empty object", function() {
var queueableFn1 = { fn: jasmine.createSpy('fn1') },
queueableFn2 = { fn: jasmine.createSpy('fn2') },
queueableFn3 = {
const queueableFn1 = { fn: jasmine.createSpy('fn1') };
const queueableFn2 = { fn: jasmine.createSpy('fn2') };
let asyncContext;
const queueableFn3 = {
fn: function(done) {
asyncContext = this;
done();
@@ -49,12 +30,11 @@ describe('QueueRunner', function() {
},
queueRunner = new jasmineUnderTest.QueueRunner({
queueableFns: [queueableFn1, queueableFn2, queueableFn3]
}),
asyncContext;
});
queueRunner.execute();
var context = queueableFn1.fn.calls.first().object;
const context = queueableFn1.fn.calls.first().object;
expect(context).toEqual(new jasmineUnderTest.UserContext());
expect(queueableFn2.fn.calls.first().object).toBe(context);
expect(asyncContext).toBe(context);
@@ -73,7 +53,7 @@ describe('QueueRunner', function() {
//TODO: it would be nice if spy arity could match the fake, so we could do something like:
//createSpy('asyncfn').and.callFake(function(done) {});
var onComplete = jasmine.createSpy('onComplete'),
const onComplete = jasmine.createSpy('onComplete'),
beforeCallback = jasmine.createSpy('beforeCallback'),
fnCallback = jasmine.createSpy('fnCallback'),
afterCallback = jasmine.createSpy('afterCallback'),
@@ -124,7 +104,7 @@ describe('QueueRunner', function() {
});
it('explicitly fails an async function with a provided fail function and moves to the next function', function() {
var queueableFn1 = {
const queueableFn1 = {
fn: function(done) {
setTimeout(function() {
done.fail('foo');
@@ -149,35 +129,89 @@ 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() {
it('explicitly fails and moves to the next function', function() {
const err = 'anything except undefined',
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();
});
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) {
const err = new Error('foo'),
queueableFn1 = {
fn: function() {
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();
});
});
queueRunner.execute();
describe('and the argument is not an Error', function() {
it('does not report a failure', function(done) {
const queueableFn1 = {
fn: function() {
return Promise.resolve('not an error');
}
},
failFn = jasmine.createSpy('fail'),
queueRunner = new jasmineUnderTest.QueueRunner({
queueableFns: [queueableFn1],
fail: failFn,
onComplete: function() {
expect(failFn).not.toHaveBeenCalled();
done();
}
});
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 cause an explicit fail if execution is being stopped', function() {
var err = new jasmineUnderTest.StopExecutionError('foo'),
const err = new jasmineUnderTest.StopExecutionError('foo'),
queueableFn1 = {
fn: function(done) {
setTimeout(function() {
@@ -204,7 +238,8 @@ describe('QueueRunner', function() {
});
it("sets a timeout if requested for asynchronous functions so they don't go on forever", function() {
var timeout = 3,
const timeout = 3,
// eslint-disable-next-line no-unused-vars
beforeFn = { fn: function(done) {}, type: 'before', timeout: timeout },
queueableFn = { fn: jasmine.createSpy('fn'), type: 'queueable' },
onComplete = jasmine.createSpy('onComplete'),
@@ -225,8 +260,35 @@ describe('QueueRunner', function() {
expect(onComplete).toHaveBeenCalled();
});
it('does not call onMultipleDone if an asynchrnous function completes after timing out', function() {
const timeout = 3;
let queueableFnDone;
const queueableFn = {
fn: function(done) {
queueableFnDone = done;
},
type: 'queueable',
timeout: timeout
};
const onComplete = jasmine.createSpy('onComplete');
const onMultipleDone = jasmine.createSpy('onMultipleDone');
const queueRunner = new jasmineUnderTest.QueueRunner({
queueableFns: [queueableFn],
onComplete: onComplete,
onMultipleDone: onMultipleDone
});
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) {} },
// eslint-disable-next-line no-unused-vars
const beforeFn = { fn: function(done) {} },
queueableFn = { fn: jasmine.createSpy('fn') },
onComplete = jasmine.createSpy('onComplete'),
onException = jasmine.createSpy('onException'),
@@ -247,7 +309,8 @@ describe('QueueRunner', function() {
});
it('clears the timeout when an async function throws an exception, to prevent additional exception reporting', function() {
var queueableFn = {
const queueableFn = {
// eslint-disable-next-line no-unused-vars
fn: function(done) {
throw new Error('error!');
}
@@ -270,7 +333,7 @@ describe('QueueRunner', function() {
});
it('clears the timeout when the done callback is called', function() {
var queueableFn = {
const queueableFn = {
fn: function(done) {
done();
}
@@ -293,24 +356,27 @@ describe('QueueRunner', function() {
});
it('only moves to the next spec the first time you call done', function() {
var queueableFn = {
const queueableFn = {
fn: function(done) {
done();
done();
}
},
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() {
var queueableFn = {
const queueableFn = {
fn: function(done) {
setTimeout(done, 1);
throw new Error('error!');
@@ -320,7 +386,6 @@ describe('QueueRunner', function() {
queueRunner = new jasmineUnderTest.QueueRunner({
queueableFns: [queueableFn, nextQueueableFn]
});
queueRunner.execute();
jasmine.clock().tick(1);
expect(nextQueueableFn.fn.calls.count()).toEqual(1);
@@ -328,22 +393,23 @@ describe('QueueRunner', function() {
it('should return a null when you call done', function() {
// Some promises want handlers to return anything but undefined to help catch "forgotten returns".
var doneReturn,
queueableFn = {
fn: function(done) {
doneReturn = done();
}
},
queueRunner = new jasmineUnderTest.QueueRunner({
queueableFns: [queueableFn]
});
let doneReturn;
const queueableFn = {
fn: function(done) {
doneReturn = done();
}
};
const queueRunner = new jasmineUnderTest.QueueRunner({
queueableFns: [queueableFn]
});
queueRunner.execute();
expect(doneReturn).toBe(null);
});
it('continues running functions when an exception is thrown in async code without timing out', function() {
var queueableFn = {
const queueableFn = {
// eslint-disable-next-line no-unused-vars
fn: function(done) {
throwAsync();
},
@@ -394,7 +460,7 @@ describe('QueueRunner', function() {
});
it('handles exceptions thrown while waiting for the stack to clear', function() {
var queueableFn = {
const queueableFn = {
fn: function(done) {
done();
}
@@ -445,7 +511,7 @@ describe('QueueRunner', function() {
});
it('runs the function asynchronously, advancing once the promise is settled', function() {
var onComplete = jasmine.createSpy('onComplete'),
const onComplete = jasmine.createSpy('onComplete'),
fnCallback = jasmine.createSpy('fnCallback'),
p1 = new StubPromise(),
p2 = new StubPromise(),
@@ -456,20 +522,20 @@ describe('QueueRunner', function() {
}, 100);
return p1;
}
};
(queueableFn2 = {
fn: function() {
fnCallback();
setTimeout(function() {
p2.resolveHandler();
}, 100);
return p2;
}
}),
(queueRunner = new jasmineUnderTest.QueueRunner({
},
queueableFn2 = {
fn: function() {
fnCallback();
setTimeout(function() {
p2.resolveHandler();
}, 100);
return p2;
}
},
queueRunner = new jasmineUnderTest.QueueRunner({
queueableFns: [queueableFn1, queueableFn2],
onComplete: onComplete
}));
});
queueRunner.execute();
expect(fnCallback).not.toHaveBeenCalled();
@@ -486,7 +552,7 @@ describe('QueueRunner', function() {
});
it('handles a rejected promise like an unhandled exception', function() {
var promise = new StubPromise(),
const promise = new StubPromise(),
queueableFn1 = {
fn: function() {
setTimeout(function() {
@@ -513,79 +579,69 @@ describe('QueueRunner', function() {
expect(queueableFn2.fn).toHaveBeenCalled();
});
it('issues a deprecation if the function also takes a parameter', function() {
var queueableFn = {
it('issues an error if the function also takes a parameter', function() {
const queueableFn = {
// eslint-disable-next-line no-unused-vars
fn: function(done) {
return new StubPromise();
}
},
deprecated = jasmine.createSpy('deprecated'),
onException = jasmine.createSpy('onException'),
queueRunner = new jasmineUnderTest.QueueRunner({
queueableFns: [queueableFn],
deprecated: deprecated
}),
env = jasmineUnderTest.getEnv();
queueRunner.execute();
expect(deprecated).toHaveBeenCalledWith(
'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.'
);
});
it('issues a more specific deprecation if the function is `async`', function() {
jasmine.getEnv().requireAsyncAwait();
eval('var fn = async function(done){};');
var deprecated = jasmine.createSpy('deprecated'),
queueRunner = new jasmineUnderTest.QueueRunner({
queueableFns: [{ fn: fn }],
deprecated: deprecated
onException: onException
});
queueRunner.execute();
expect(deprecated).toHaveBeenCalledWith(
'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.'
expect(onException).toHaveBeenCalledWith(
new Error(
'An asynchronous ' +
'before/it/after function took a done callback but also returned a ' +
'promise. ' +
'Either remove the done callback (recommended) or change the function ' +
'to not return a promise.'
)
);
});
it('issues a more specific error if the function is `async`', function() {
// eslint-disable-next-line no-unused-vars
async function fn(done) {}
const onException = jasmine.createSpy('onException'),
queueRunner = new jasmineUnderTest.QueueRunner({
queueableFns: [{ fn: fn }],
onException: onException
});
queueRunner.execute();
expect(onException).toHaveBeenCalledWith(
new Error(
'An asynchronous ' +
'before/it/after function was defined with the async keyword but ' +
'also took a done callback. Either remove the done callback ' +
'(recommended) or remove the async keyword.'
)
);
});
});
it('passes the error instance to exception handlers in HTML browsers', function() {
var error = new Error('fake error'),
it('passes final errors to exception handlers', function() {
const error = new Error('fake error'),
onExceptionCallback = jasmine.createSpy('on exception callback'),
queueRunner = new jasmineUnderTest.QueueRunner({
onException: onExceptionCallback
});
queueRunner.execute();
queueRunner.handleFinalError(error.message, 'fake.js', 1, 1, error);
queueRunner.handleFinalError(error);
expect(onExceptionCallback).toHaveBeenCalledWith(error);
});
it('passes the first argument to exception handlers for compatibility', function() {
var error = new Error('fake error'),
onExceptionCallback = jasmine.createSpy('on exception callback'),
queueRunner = new jasmineUnderTest.QueueRunner({
onException: onExceptionCallback
});
queueRunner.execute();
queueRunner.handleFinalError(error.message);
expect(onExceptionCallback).toHaveBeenCalledWith(error.message);
});
it('calls exception handlers when an exception is thrown in a fn', function() {
var queueableFn = {
const queueableFn = {
type: 'queueable',
fn: function() {
throw new Error('fake error');
@@ -603,7 +659,8 @@ describe('QueueRunner', function() {
});
it('continues running the functions even after an exception is thrown in an async spec', function() {
var queueableFn = {
const queueableFn = {
// eslint-disable-next-line no-unused-vars
fn: function(done) {
throw new Error('error');
}
@@ -617,21 +674,84 @@ describe('QueueRunner', function() {
expect(nextQueueableFn.fn).toHaveBeenCalled();
});
describe('When configured with a skip policy', function() {
it('instantiates the skip policy', function() {
const SkipPolicy = jasmine.createSpy('SkipPolicy ctor');
const queueableFns = [{ fn: () => {} }, { fn: () => {} }];
new jasmineUnderTest.QueueRunner({
queueableFns,
SkipPolicy
});
expect(SkipPolicy).toHaveBeenCalledWith(queueableFns);
});
it('uses the skip policy to determine which fn to run next', function() {
const queueableFns = [
{ fn: jasmine.createSpy('fn0') },
{ fn: jasmine.createSpy('fn1') },
{ fn: jasmine.createSpy('fn2').and.throwError(new Error('nope')) },
{ fn: jasmine.createSpy('fn3') }
];
const skipPolicy = jasmine.createSpyObj('skipPolicy', [
'skipTo',
'fnErrored'
]);
skipPolicy.skipTo.and.callFake(function(lastRanIx) {
return lastRanIx === 0 ? 2 : lastRanIx + 1;
});
const queueRunner = new jasmineUnderTest.QueueRunner({
queueableFns,
SkipPolicy: function() {
return skipPolicy;
}
});
queueRunner.execute();
expect(skipPolicy.skipTo).toHaveBeenCalledWith(0);
expect(skipPolicy.skipTo).toHaveBeenCalledWith(2);
expect(skipPolicy.fnErrored).toHaveBeenCalledWith(2);
expect(queueableFns[0].fn).toHaveBeenCalled();
expect(queueableFns[1].fn).not.toHaveBeenCalled();
expect(queueableFns[2].fn).toHaveBeenCalled();
expect(queueableFns[3].fn).toHaveBeenCalled();
});
it('throws if the skip policy returns the current fn', function() {
const skipPolicy = { skipTo: i => i };
const queueableFns = [{ fn: () => {} }];
const queueRunner = new jasmineUnderTest.QueueRunner({
queueableFns,
SkipPolicy: function() {
return skipPolicy;
}
});
expect(function() {
queueRunner.execute();
}).toThrowError("Can't skip to the same queueable fn that just finished");
});
});
describe('When configured to complete on first error', function() {
it('skips to cleanup functions on the first exception', function() {
var queueableFn = {
const queueableFn = {
fn: function() {
throw new Error('error');
}
},
nextQueueableFn = { fn: jasmine.createSpy('nextFunction') },
cleanupFn = { fn: jasmine.createSpy('cleanup') },
cleanupFn = {
fn: jasmine.createSpy('cleanup'),
type: 'specCleanup'
},
onComplete = jasmine.createSpy('onComplete'),
queueRunner = new jasmineUnderTest.QueueRunner({
queueableFns: [queueableFn, nextQueueableFn],
cleanupFns: [cleanupFn],
queueableFns: [queueableFn, nextQueueableFn, cleanupFn],
onComplete: onComplete,
completeOnFirstError: true
SkipPolicy: jasmineUnderTest.CompleteOnFirstErrorSkipPolicy
});
queueRunner.execute();
@@ -643,17 +763,20 @@ describe('QueueRunner', function() {
});
it('does not skip when a cleanup function throws', function() {
var queueableFn = { fn: function() {} },
const queueableFn = { fn: function() {} },
cleanupFn1 = {
fn: function() {
throw new Error('error');
}
},
type: 'afterEach'
},
cleanupFn2 = {
fn: jasmine.createSpy('cleanupFn2'),
type: 'afterEach'
},
cleanupFn2 = { fn: jasmine.createSpy('cleanupFn2') },
queueRunner = new jasmineUnderTest.QueueRunner({
queueableFns: [queueableFn],
cleanupFns: [cleanupFn1, cleanupFn2],
completeOnFirstError: true
queueableFns: [queueableFn, cleanupFn1, cleanupFn2],
SkipPolicy: jasmineUnderTest.CompleteOnFirstErrorSkipPolicy
});
queueRunner.execute();
@@ -670,28 +793,30 @@ describe('QueueRunner', function() {
});
it('skips to cleanup functions once the fn completes after an unhandled exception', function() {
var errorListeners = [],
queueableFn = {
fn: function(done) {
queueableFnDone = done;
const errorListeners = [];
let queueableFnDone;
const queueableFn = {
fn: function(done) {
queueableFnDone = done;
}
};
const nextQueueableFn = { fn: jasmine.createSpy('nextFunction') };
const cleanupFn = {
fn: jasmine.createSpy('cleanup'),
type: 'specCleanup'
};
const queueRunner = new jasmineUnderTest.QueueRunner({
globalErrors: {
pushListener: function(f) {
errorListeners.push(f);
},
popListener: function() {
errorListeners.pop();
}
},
nextQueueableFn = { fn: jasmine.createSpy('nextFunction') },
cleanupFn = { fn: jasmine.createSpy('cleanup') },
queueRunner = new jasmineUnderTest.QueueRunner({
globalErrors: {
pushListener: function(f) {
errorListeners.push(f);
},
popListener: function() {
errorListeners.pop();
}
},
queueableFns: [queueableFn, nextQueueableFn],
cleanupFns: [cleanupFn],
completeOnFirstError: true
}),
queueableFnDone;
queueableFns: [queueableFn, nextQueueableFn, cleanupFn],
SkipPolicy: jasmineUnderTest.CompleteOnFirstErrorSkipPolicy
});
queueRunner.execute();
errorListeners[errorListeners.length - 1](new Error('error'));
@@ -702,17 +827,16 @@ describe('QueueRunner', function() {
});
it('skips to cleanup functions when next.fail is called', function() {
var queueableFn = {
const queueableFn = {
fn: function(done) {
done.fail('nope');
}
},
nextQueueableFn = { fn: jasmine.createSpy('nextFunction') },
cleanupFn = { fn: jasmine.createSpy('cleanup') },
cleanupFn = { fn: jasmine.createSpy('cleanup'), type: 'specCleanup' },
queueRunner = new jasmineUnderTest.QueueRunner({
queueableFns: [queueableFn, nextQueueableFn],
cleanupFns: [cleanupFn],
completeOnFirstError: true
queueableFns: [queueableFn, nextQueueableFn, cleanupFn],
SkipPolicy: jasmineUnderTest.CompleteOnFirstErrorSkipPolicy
});
queueRunner.execute();
@@ -722,17 +846,19 @@ describe('QueueRunner', function() {
});
it('skips to cleanup functions when next is called with an Error', function() {
var queueableFn = {
const queueableFn = {
fn: function(done) {
done(new Error('nope'));
}
},
nextQueueableFn = { fn: jasmine.createSpy('nextFunction') },
cleanupFn = { fn: jasmine.createSpy('cleanup') },
cleanupFn = {
fn: jasmine.createSpy('cleanup'),
type: 'specCleanup'
},
queueRunner = new jasmineUnderTest.QueueRunner({
queueableFns: [queueableFn, nextQueueableFn],
cleanupFns: [cleanupFn],
completeOnFirstError: true
queueableFns: [queueableFn, nextQueueableFn, cleanupFn],
SkipPolicy: jasmineUnderTest.CompleteOnFirstErrorSkipPolicy
});
queueRunner.execute();
@@ -744,7 +870,7 @@ describe('QueueRunner', function() {
});
it('calls a provided complete callback when done', function() {
var queueableFn = { fn: jasmine.createSpy('fn') },
const queueableFn = { fn: jasmine.createSpy('fn') },
completeCallback = jasmine.createSpy('completeCallback'),
queueRunner = new jasmineUnderTest.QueueRunner({
queueableFns: [queueableFn],
@@ -766,7 +892,7 @@ describe('QueueRunner', function() {
});
it('calls a provided stack clearing function when done', function() {
var asyncFn = {
const asyncFn = {
fn: function(done) {
done();
}
@@ -795,16 +921,16 @@ describe('QueueRunner', function() {
describe('when user context has not been defined', function() {
beforeEach(function() {
var fn;
const fn = jasmine.createSpy('fn1');
this.fn = fn = jasmine.createSpy('fn1');
this.fn = fn;
this.queueRunner = new jasmineUnderTest.QueueRunner({
queueableFns: [{ fn: fn }]
});
});
it('runs the functions on the scope of a UserContext', function() {
var context;
let context;
this.fn.and.callFake(function() {
context = this;
});
@@ -817,9 +943,10 @@ describe('QueueRunner', function() {
describe('when user context has been defined', function() {
beforeEach(function() {
var fn, context;
const fn = jasmine.createSpy('fn1');
let context;
this.fn = fn = jasmine.createSpy('fn1');
this.fn = fn;
this.context = context = new jasmineUnderTest.UserContext();
this.queueRunner = new jasmineUnderTest.QueueRunner({
queueableFns: [{ fn: fn }],
@@ -828,7 +955,7 @@ describe('QueueRunner', function() {
});
it('runs the functions on the scope of a UserContext', function() {
var context;
let context;
this.fn.and.callFake(function() {
context = this;
});

View File

@@ -1,6 +1,6 @@
describe('ReportDispatcher', function() {
it('builds an interface of requested methods', function() {
var dispatcher = new jasmineUnderTest.ReportDispatcher([
const dispatcher = new jasmineUnderTest.ReportDispatcher([
'foo',
'bar',
'baz'
@@ -12,19 +12,18 @@ describe('ReportDispatcher', function() {
});
it('dispatches requested methods to added reporters', function() {
var queueRunnerFactory = jasmine.createSpy('queueRunner'),
const queueRunnerFactory = jasmine.createSpy('queueRunner'),
dispatcher = new jasmineUnderTest.ReportDispatcher(
['foo', 'bar'],
queueRunnerFactory
),
reporter = jasmine.createSpyObj('reporter', ['foo', 'bar']),
anotherReporter = jasmine.createSpyObj('reporter', ['foo', 'bar']),
completeCallback = jasmine.createSpy('complete');
anotherReporter = jasmine.createSpyObj('reporter', ['foo', 'bar']);
dispatcher.addReporter(reporter);
dispatcher.addReporter(anotherReporter);
dispatcher.foo(123, 456, completeCallback);
dispatcher.foo(123, 456);
expect(queueRunnerFactory).toHaveBeenCalledWith(
jasmine.objectContaining({
@@ -36,7 +35,7 @@ describe('ReportDispatcher', function() {
})
);
var fns = queueRunnerFactory.calls.mostRecent().args[0].queueableFns;
let fns = queueRunnerFactory.calls.mostRecent().args[0].queueableFns;
fns[0].fn();
expect(reporter.foo).toHaveBeenCalledWith(123, 456);
expect(reporter.foo.calls.mostRecent().object).toBe(reporter);
@@ -47,7 +46,7 @@ describe('ReportDispatcher', function() {
queueRunnerFactory.calls.reset();
dispatcher.bar('a', 'b', completeCallback);
dispatcher.bar('a', 'b');
expect(queueRunnerFactory).toHaveBeenCalledWith(
jasmine.objectContaining({
@@ -68,7 +67,7 @@ describe('ReportDispatcher', function() {
});
it("does not dispatch to a reporter if the reporter doesn't accept the method", function() {
var queueRunnerFactory = jasmine.createSpy('queueRunner'),
const queueRunnerFactory = jasmine.createSpy('queueRunner'),
dispatcher = new jasmineUnderTest.ReportDispatcher(
['foo'],
queueRunnerFactory
@@ -86,16 +85,15 @@ describe('ReportDispatcher', function() {
});
it("allows providing a fallback reporter in case there's no other reporter", function() {
var queueRunnerFactory = jasmine.createSpy('queueRunner'),
const queueRunnerFactory = jasmine.createSpy('queueRunner'),
dispatcher = new jasmineUnderTest.ReportDispatcher(
['foo', 'bar'],
queueRunnerFactory
),
reporter = jasmine.createSpyObj('reporter', ['foo', 'bar']),
completeCallback = jasmine.createSpy('complete');
reporter = jasmine.createSpyObj('reporter', ['foo', 'bar']);
dispatcher.provideFallbackReporter(reporter);
dispatcher.foo(123, 456, completeCallback);
dispatcher.foo(123, 456);
expect(queueRunnerFactory).toHaveBeenCalledWith(
jasmine.objectContaining({
@@ -104,24 +102,23 @@ describe('ReportDispatcher', function() {
})
);
var fns = queueRunnerFactory.calls.mostRecent().args[0].queueableFns;
const fns = queueRunnerFactory.calls.mostRecent().args[0].queueableFns;
fns[0].fn();
expect(reporter.foo).toHaveBeenCalledWith(123, 456);
});
it('does not call fallback reporting methods when another reporter is provided', function() {
var queueRunnerFactory = jasmine.createSpy('queueRunner'),
const queueRunnerFactory = jasmine.createSpy('queueRunner'),
dispatcher = new jasmineUnderTest.ReportDispatcher(
['foo', 'bar'],
queueRunnerFactory
),
reporter = jasmine.createSpyObj('reporter', ['foo', 'bar']),
fallbackReporter = jasmine.createSpyObj('otherReporter', ['foo', 'bar']),
completeCallback = jasmine.createSpy('complete');
fallbackReporter = jasmine.createSpyObj('otherReporter', ['foo', 'bar']);
dispatcher.provideFallbackReporter(fallbackReporter);
dispatcher.addReporter(reporter);
dispatcher.foo(123, 456, completeCallback);
dispatcher.foo(123, 456);
expect(queueRunnerFactory).toHaveBeenCalledWith(
jasmine.objectContaining({
@@ -130,24 +127,23 @@ describe('ReportDispatcher', function() {
})
);
var fns = queueRunnerFactory.calls.mostRecent().args[0].queueableFns;
const fns = queueRunnerFactory.calls.mostRecent().args[0].queueableFns;
fns[0].fn();
expect(reporter.foo).toHaveBeenCalledWith(123, 456);
expect(fallbackReporter.foo).not.toHaveBeenCalledWith(123, 456);
});
it('allows registered reporters to be cleared', function() {
var queueRunnerFactory = jasmine.createSpy('queueRunner'),
const queueRunnerFactory = jasmine.createSpy('queueRunner'),
dispatcher = new jasmineUnderTest.ReportDispatcher(
['foo', 'bar'],
queueRunnerFactory
),
reporter1 = jasmine.createSpyObj('reporter1', ['foo', 'bar']),
reporter2 = jasmine.createSpyObj('reporter2', ['foo', 'bar']),
completeCallback = jasmine.createSpy('complete');
reporter2 = jasmine.createSpyObj('reporter2', ['foo', 'bar']);
dispatcher.addReporter(reporter1);
dispatcher.foo(123, completeCallback);
dispatcher.foo(123);
expect(queueRunnerFactory).toHaveBeenCalledWith(
jasmine.objectContaining({
queueableFns: [{ fn: jasmine.any(Function) }],
@@ -155,13 +151,13 @@ describe('ReportDispatcher', function() {
})
);
var fns = queueRunnerFactory.calls.mostRecent().args[0].queueableFns;
let fns = queueRunnerFactory.calls.mostRecent().args[0].queueableFns;
fns[0].fn();
expect(reporter1.foo).toHaveBeenCalledWith(123);
dispatcher.clearReporters();
dispatcher.addReporter(reporter2);
dispatcher.bar(456, completeCallback);
dispatcher.bar(456);
expect(queueRunnerFactory).toHaveBeenCalledWith(
jasmine.objectContaining({

View File

@@ -0,0 +1,557 @@
describe('RunableResources', function() {
describe('#spies', function() {
behavesLikeAPerRunableMutableArray(
'spies',
'Spies must be created in a before function or a spec',
false
);
});
describe('#customSpyStrategies', function() {
behavesLikeAPerRunableMutableObject(
'customSpyStrategies',
'Custom spy strategies must be added in a before function or a spec'
);
});
describe('#customEqualityTesters', function() {
behavesLikeAPerRunableMutableArray(
'customEqualityTesters',
'Custom Equalities must be added in a before function or a spec'
);
});
describe('#customObjectFormatters', function() {
behavesLikeAPerRunableMutableArray(
'customObjectFormatters',
'Custom object formatters must be added in a before function or a spec'
);
});
describe('#customMatchers', function() {
behavesLikeAPerRunableMutableObject(
'customMatchers',
'Matchers must be added in a before function or a spec'
);
});
describe('#addCustomMatchers', function() {
it("adds all properties to the current runable's matchers", function() {
const currentRunableId = 1;
const runableResources = new jasmineUnderTest.RunableResources({
globalErrors: stubGlobalErrors(),
getCurrentRunableId: () => currentRunableId
});
runableResources.initForRunable(1);
function toBeFoo() {}
function toBeBar() {}
function toBeBaz() {}
runableResources.addCustomMatchers({ toBeFoo });
expect(runableResources.customMatchers()).toEqual({ toBeFoo });
runableResources.addCustomMatchers({ toBeBar, toBeBaz });
expect(runableResources.customMatchers()).toEqual({
toBeFoo,
toBeBar,
toBeBaz
});
});
});
describe('#customAsyncMatchers', function() {
behavesLikeAPerRunableMutableObject(
'customAsyncMatchers',
'Async Matchers must be added in a before function or a spec'
);
});
describe('#addCustomAsyncMatchers', function() {
it("adds all properties to the current runable's matchers", function() {
const currentRunableId = 1;
const runableResources = new jasmineUnderTest.RunableResources({
globalErrors: stubGlobalErrors(),
getCurrentRunableId: () => currentRunableId
});
runableResources.initForRunable(1);
function toBeFoo() {}
function toBeBar() {}
function toBeBaz() {}
runableResources.addCustomAsyncMatchers({ toBeFoo });
expect(runableResources.customAsyncMatchers()).toEqual({ toBeFoo });
runableResources.addCustomAsyncMatchers({ toBeBar, toBeBaz });
expect(runableResources.customAsyncMatchers()).toEqual({
toBeFoo,
toBeBar,
toBeBaz
});
});
});
describe('#defaultSpyStrategy', function() {
it('returns undefined for a newly initialized resource', function() {
let currentRunableId = 1;
const runableResources = new jasmineUnderTest.RunableResources({
globalErrors: stubGlobalErrors(),
getCurrentRunableId: () => currentRunableId
});
runableResources.initForRunable(1);
expect(runableResources.defaultSpyStrategy()).toBeUndefined();
});
it('returns the value previously set by #setDefaultSpyStrategy', function() {
let currentRunableId = 1;
const runableResources = new jasmineUnderTest.RunableResources({
globalErrors: stubGlobalErrors(),
getCurrentRunableId: () => currentRunableId
});
runableResources.initForRunable(1);
const fn = () => {};
runableResources.setDefaultSpyStrategy(fn);
expect(runableResources.defaultSpyStrategy()).toBe(fn);
});
it('is per-runable', function() {
let currentRunableId = 1;
const runableResources = new jasmineUnderTest.RunableResources({
globalErrors: stubGlobalErrors(),
getCurrentRunableId: () => currentRunableId
});
runableResources.initForRunable(1);
runableResources.setDefaultSpyStrategy(() => {});
currentRunableId = 2;
runableResources.initForRunable(2);
expect(runableResources.defaultSpyStrategy()).toBeUndefined();
});
it('does not require a current runable', function() {
const runableResources = new jasmineUnderTest.RunableResources({
globalErrors: stubGlobalErrors(),
getCurrentRunableId: () => null
});
expect(runableResources.defaultSpyStrategy()).toBeUndefined();
});
it("inherits the parent runable's value", function() {
let currentRunableId = 1;
const runableResources = new jasmineUnderTest.RunableResources({
globalErrors: stubGlobalErrors(),
getCurrentRunableId: () => currentRunableId
});
runableResources.initForRunable(1);
const fn = () => {};
runableResources.setDefaultSpyStrategy(fn);
currentRunableId = 2;
runableResources.initForRunable(2, 1);
expect(runableResources.defaultSpyStrategy()).toBe(fn);
});
});
describe('#setDefaultSpyStrategy', function() {
it('throws a user-facing error when there is no current runable', function() {
const runableResources = new jasmineUnderTest.RunableResources({
globalErrors: stubGlobalErrors(),
getCurrentRunableId: () => null
});
expect(function() {
runableResources.setDefaultSpyStrategy();
}).toThrowError(
'Default spy strategy must be set in a before function or a spec'
);
});
});
describe('#makePrettyPrinter', function() {
it('returns a pretty printer configured with the current customObjectFormatters', function() {
const runableResources = new jasmineUnderTest.RunableResources({
globalErrors: stubGlobalErrors(),
getCurrentRunableId: () => 1
});
runableResources.initForRunable(1);
function cof() {}
runableResources.customObjectFormatters().push(cof);
spyOn(jasmineUnderTest, 'makePrettyPrinter').and.callThrough();
const pp = runableResources.makePrettyPrinter();
expect(jasmineUnderTest.makePrettyPrinter).toHaveBeenCalledOnceWith([
cof
]);
expect(pp).toBe(
jasmineUnderTest.makePrettyPrinter.calls.first().returnValue
);
});
});
describe('#makeMatchersUtil', function() {
describe('When there is a current runable', function() {
it('returns a MatchersUtil configured with the current resources', function() {
const runableResources = new jasmineUnderTest.RunableResources({
globalErrors: stubGlobalErrors(),
getCurrentRunableId: () => 1
});
runableResources.initForRunable(1);
function cof() {}
runableResources.customObjectFormatters().push(cof);
function ceq() {}
runableResources.customEqualityTesters().push(ceq);
const expectedPP = {};
const expectedMatchersUtil = {};
spyOn(jasmineUnderTest, 'makePrettyPrinter').and.returnValue(
expectedPP
);
spyOn(jasmineUnderTest, 'MatchersUtil').and.returnValue(
expectedMatchersUtil
);
const matchersUtil = runableResources.makeMatchersUtil();
expect(matchersUtil).toBe(expectedMatchersUtil);
expect(jasmineUnderTest.makePrettyPrinter).toHaveBeenCalledOnceWith([
cof
]);
// We need === equality on the pp passed to MatchersUtil
expect(jasmineUnderTest.MatchersUtil).toHaveBeenCalledOnceWith(
jasmine.objectContaining({
customTesters: [ceq]
})
);
expect(jasmineUnderTest.MatchersUtil.calls.argsFor(0)[0].pp).toBe(
expectedPP
);
});
});
describe('When there is no current runable', function() {
it('returns a MatchersUtil configured with defaults', function() {
const runableResources = new jasmineUnderTest.RunableResources({
globalErrors: stubGlobalErrors(),
getCurrentRunableId: () => null
});
const expectedMatchersUtil = {};
spyOn(jasmineUnderTest, 'MatchersUtil').and.returnValue(
expectedMatchersUtil
);
const matchersUtil = runableResources.makeMatchersUtil();
expect(matchersUtil).toBe(expectedMatchersUtil);
// We need === equality on the pp passed to MatchersUtil
expect(jasmineUnderTest.MatchersUtil).toHaveBeenCalledTimes(1);
expect(jasmineUnderTest.MatchersUtil.calls.argsFor(0)[0].pp).toBe(
jasmineUnderTest.basicPrettyPrinter_
);
expect(
jasmineUnderTest.MatchersUtil.calls.argsFor(0)[0].customTesters
).toBeUndefined();
});
});
});
describe('.spyFactory', function() {
describe('When there is no current runable', function() {
it('is configured with default strategies and matchersUtil', function() {
const runableResources = new jasmineUnderTest.RunableResources({
globalErrors: stubGlobalErrors(),
getCurrentRunableId: () => null
});
spyOn(jasmineUnderTest, 'Spy');
const matchersUtil = {};
spyOn(runableResources, 'makeMatchersUtil').and.returnValue(
matchersUtil
);
runableResources.spyFactory.createSpy('foo');
expect(jasmineUnderTest.Spy).toHaveBeenCalledWith(
'foo',
is(matchersUtil),
jasmine.objectContaining({
customStrategies: {},
defaultStrategyFn: undefined
})
);
});
});
describe('When there is a current runable', function() {
it("is configured with the current runable's strategies and matchersUtil", function() {
const runableResources = new jasmineUnderTest.RunableResources({
globalErrors: stubGlobalErrors(),
getCurrentRunableId: () => 1
});
runableResources.initForRunable(1);
function customStrategy() {}
function defaultStrategy() {}
runableResources.customSpyStrategies().foo = customStrategy;
runableResources.setDefaultSpyStrategy(defaultStrategy);
spyOn(jasmineUnderTest, 'Spy');
const matchersUtil = {};
spyOn(runableResources, 'makeMatchersUtil').and.returnValue(
matchersUtil
);
runableResources.spyFactory.createSpy('foo');
expect(jasmineUnderTest.Spy).toHaveBeenCalledWith(
'foo',
is(matchersUtil),
jasmine.objectContaining({
customStrategies: { foo: customStrategy },
defaultStrategyFn: defaultStrategy
})
);
});
});
function is(expected) {
return {
asymmetricMatch: function(actual) {
return actual === expected;
},
jasmineToString: function(pp) {
return '<same instance as ' + pp(expected) + '>';
}
};
}
});
describe('.spyRegistry', function() {
it("writes to the current runable's spies", function() {
const runableResources = new jasmineUnderTest.RunableResources({
globalErrors: stubGlobalErrors(),
getCurrentRunableId: () => 1
});
runableResources.initForRunable(1);
function foo() {}
const spyObj = { foo };
runableResources.spyRegistry.spyOn(spyObj, 'foo');
expect(runableResources.spies()).toEqual([
jasmine.objectContaining({
restoreObjectToOriginalState: jasmine.any(Function)
})
]);
expect(jasmineUnderTest.isSpy(spyObj.foo)).toBeTrue();
runableResources.spyRegistry.clearSpies();
expect(spyObj.foo).toBe(foo);
});
});
describe('#clearForRunable', function() {
it('removes resources for the specified runable', function() {
const runableResources = new jasmineUnderTest.RunableResources({
globalErrors: stubGlobalErrors(),
getCurrentRunableId: () => 1
});
runableResources.initForRunable(1);
expect(function() {
runableResources.spies();
}).not.toThrow();
runableResources.clearForRunable(1);
expect(function() {
runableResources.spies();
}).toThrowError('Spies must be created in a before function or a spec');
});
it('clears spies', function() {
const runableResources = new jasmineUnderTest.RunableResources({
globalErrors: stubGlobalErrors(),
getCurrentRunableId: () => 1
});
runableResources.initForRunable(1);
function foo() {}
const spyObj = { foo };
runableResources.spyRegistry.spyOn(spyObj, 'foo');
expect(spyObj.foo).not.toBe(foo);
runableResources.clearForRunable(1);
expect(spyObj.foo).toBe(foo);
});
it('clears the global error spy', function() {
const globalErrors = jasmine.createSpyObj('globalErrors', [
'removeOverrideListener'
]);
const runableResources = new jasmineUnderTest.RunableResources({
getCurrentRunableId: () => 1,
globalErrors
});
runableResources.initForRunable(1);
runableResources.clearForRunable(1);
expect(globalErrors.removeOverrideListener).toHaveBeenCalled();
});
it('does not remove resources for other runables', function() {
const runableResources = new jasmineUnderTest.RunableResources({
globalErrors: stubGlobalErrors(),
getCurrentRunableId: () => 1
});
runableResources.initForRunable(1);
function cof() {}
runableResources.customObjectFormatters().push(cof);
runableResources.clearForRunable(2);
expect(runableResources.customObjectFormatters()).toEqual([cof]);
});
});
function behavesLikeAPerRunableMutableArray(
methodName,
errorMsg,
inherits = true
) {
it('is initially empty', function() {
const currentRunableId = 1;
const runableResources = new jasmineUnderTest.RunableResources({
globalErrors: stubGlobalErrors(),
getCurrentRunableId: () => currentRunableId
});
runableResources.initForRunable(1);
expect(runableResources[methodName]()).toEqual([]);
});
it('is mutable', function() {
const currentRunableId = 1;
const runableResources = new jasmineUnderTest.RunableResources({
globalErrors: stubGlobalErrors(),
getCurrentRunableId: () => currentRunableId
});
runableResources.initForRunable(1);
function newItem() {}
runableResources[methodName]().push(newItem);
expect(runableResources[methodName]()).toEqual([newItem]);
});
it('is per-runable', function() {
let currentRunableId = 1;
const runableResources = new jasmineUnderTest.RunableResources({
globalErrors: stubGlobalErrors(),
getCurrentRunableId: () => currentRunableId
});
runableResources.initForRunable(1);
runableResources[methodName]().push(() => {});
runableResources.initForRunable(2);
currentRunableId = 2;
expect(runableResources[methodName]()).toEqual([]);
});
it('throws a user-facing error when there is no current runable', function() {
const runableResources = new jasmineUnderTest.RunableResources({
globalErrors: stubGlobalErrors(),
getCurrentRunableId: () => null
});
expect(function() {
runableResources[methodName]();
}).toThrowError(errorMsg);
});
if (inherits) {
it('inherits from the parent runable', function() {
let currentRunableId = 1;
const runableResources = new jasmineUnderTest.RunableResources({
globalErrors: stubGlobalErrors(),
getCurrentRunableId: () => currentRunableId
});
runableResources.initForRunable(1);
function parentItem() {}
runableResources[methodName]().push(parentItem);
runableResources.initForRunable(2, 1);
currentRunableId = 2;
function childItem() {}
runableResources[methodName]().push(childItem);
expect(runableResources[methodName]()).toEqual([parentItem, childItem]);
currentRunableId = 1;
expect(runableResources[methodName]()).toEqual([parentItem]);
});
}
}
function behavesLikeAPerRunableMutableObject(methodName, errorMsg) {
it('is initially empty', function() {
const currentRunableId = 1;
const runableResources = new jasmineUnderTest.RunableResources({
globalErrors: stubGlobalErrors(),
getCurrentRunableId: () => currentRunableId
});
runableResources.initForRunable(1);
expect(runableResources[methodName]()).toEqual({});
});
it('is mutable', function() {
const currentRunableId = 1;
const runableResources = new jasmineUnderTest.RunableResources({
globalErrors: stubGlobalErrors(),
getCurrentRunableId: () => currentRunableId
});
runableResources.initForRunable(1);
function newItem() {}
runableResources[methodName]().foo = newItem;
expect(runableResources[methodName]()).toEqual({ foo: newItem });
});
it('is per-runable', function() {
let currentRunableId = 1;
const runableResources = new jasmineUnderTest.RunableResources({
globalErrors: stubGlobalErrors(),
getCurrentRunableId: () => currentRunableId
});
runableResources.initForRunable(1);
runableResources[methodName]().foo = function() {};
runableResources.initForRunable(2);
currentRunableId = 2;
expect(runableResources[methodName]()).toEqual({});
});
it('throws a user-facing error when there is no current runable', function() {
const runableResources = new jasmineUnderTest.RunableResources({
globalErrors: stubGlobalErrors(),
getCurrentRunableId: () => null
});
expect(function() {
runableResources[methodName]();
}).toThrowError(errorMsg);
});
it('inherits from the parent runable', function() {
let currentRunableId = 1;
const runableResources = new jasmineUnderTest.RunableResources({
globalErrors: stubGlobalErrors(),
getCurrentRunableId: () => currentRunableId
});
runableResources.initForRunable(1);
function parentItem() {}
runableResources[methodName]().parentName = parentItem;
runableResources.initForRunable(2, 1);
currentRunableId = 2;
function childItem() {}
runableResources[methodName]().childName = childItem;
expect(runableResources[methodName]()).toEqual({
parentName: parentItem,
childName: childItem
});
currentRunableId = 1;
expect(runableResources[methodName]()).toEqual({
parentName: parentItem
});
});
}
function stubGlobalErrors() {
return {
removeOverrideListener() {}
};
}
});

View File

@@ -0,0 +1,84 @@
describe('SkipAfterBeforeAllErrorPolicy', function() {
describe('#skipTo', function() {
describe('When nothing has errored', function() {
it('does not skip anything', function() {
const policy = new jasmineUnderTest.SkipAfterBeforeAllErrorPolicy(
arrayOfArbitraryFns(4)
);
expect(policy.skipTo(0)).toEqual(1);
expect(policy.skipTo(1)).toEqual(2);
expect(policy.skipTo(2)).toEqual(3);
expect(policy.skipTo(3)).toEqual(4);
});
});
describe('When anything but a beforeAll has errored', function() {
it('does not skip anything', function() {
const policy = new jasmineUnderTest.SkipAfterBeforeAllErrorPolicy(
arrayOfArbitraryFns(4)
);
policy.fnErrored(0);
expect(policy.skipTo(0)).toEqual(1);
policy.fnErrored(1);
expect(policy.skipTo(1)).toEqual(2);
policy.fnErrored(2);
expect(policy.skipTo(2)).toEqual(3);
policy.fnErrored(3);
expect(policy.skipTo(3)).toEqual(4);
});
});
describe('When a beforeAll has errored', function() {
it('skips subsequent functions other than afterAll', function() {
const suite = {};
const fns = [
{ type: 'beforeAll', fn: () => {}, suite },
{ fn: () => {} },
{ fn: () => {} },
{ type: 'afterAll', fn: () => {} },
{ type: 'afterAll', fn: () => {} }
];
const policy = new jasmineUnderTest.SkipAfterBeforeAllErrorPolicy(fns);
policy.fnErrored(0);
expect(policy.skipTo(0)).toEqual(3);
expect(policy.skipTo(3)).toEqual(4);
});
});
});
describe('#fnErrored', function() {
describe('When the fn is a beforeAll', function() {
it("sets the suite's hadBeforeAllFailure property to true", function() {
const suite = {};
const fns = [{ type: 'beforeAll', fn: () => {}, suite }];
const policy = new jasmineUnderTest.SkipAfterBeforeAllErrorPolicy(fns);
policy.fnErrored(0);
expect(suite.hadBeforeAllFailure).toBeTrue();
});
});
describe('When the fn is not a beforeAll', function() {
it('does not try to access the suite, which is probably not there', function() {
const fns = [{ fn: () => {} /* no suite */ }];
const policy = new jasmineUnderTest.SkipAfterBeforeAllErrorPolicy(fns);
expect(() => policy.fnErrored(0)).not.toThrow();
});
});
});
});
function arrayOfArbitraryFns(n) {
const result = [];
for (let i = 0; i < n; i++) {
result.push({ fn: () => {} });
}
return result;
}

View File

@@ -1,12 +1,12 @@
describe('Spec', function() {
it('#isPendingSpecException returns true for a pending spec exception', function() {
var e = new Error(jasmineUnderTest.Spec.pendingSpecExceptionMessage);
const e = new Error(jasmineUnderTest.Spec.pendingSpecExceptionMessage);
expect(jasmineUnderTest.Spec.isPendingSpecException(e)).toBe(true);
});
it('#isPendingSpecException returns true for a pending spec exception (even when FF bug is present)', function() {
var fakeError = {
const fakeError = {
toString: function() {
return 'Error: ' + jasmineUnderTest.Spec.pendingSpecExceptionMessage;
}
@@ -24,7 +24,7 @@ describe('Spec', function() {
});
it('#isPendingSpecException returns false for not a pending spec exception', function() {
var e = new Error('foo');
const e = new Error('foo');
expect(jasmineUnderTest.Spec.isPendingSpecException(e)).toBe(false);
});
@@ -34,70 +34,63 @@ describe('Spec', function() {
});
it('delegates execution to a QueueRunner', function() {
var fakeQueueRunner = jasmine.createSpy('fakeQueueRunner'),
const fakeQueueRunner = jasmine.createSpy('fakeQueueRunner'),
spec = new jasmineUnderTest.Spec({
description: 'my test',
id: 'some-id',
queueableFn: { fn: function() {} },
queueRunnerFactory: fakeQueueRunner
queueableFn: { fn: function() {} }
});
spec.execute();
spec.execute(fakeQueueRunner);
expect(fakeQueueRunner).toHaveBeenCalled();
});
it('should call the start callback on execution', function() {
var fakeQueueRunner = jasmine.createSpy('fakeQueueRunner'),
const fakeQueueRunner = jasmine.createSpy('fakeQueueRunner'),
startCallback = jasmine.createSpy('startCallback'),
spec = new jasmineUnderTest.Spec({
id: 123,
description: 'foo bar',
queueableFn: { fn: function() {} },
onStart: startCallback,
queueRunnerFactory: fakeQueueRunner
onStart: startCallback
});
spec.execute();
spec.execute(fakeQueueRunner);
fakeQueueRunner.calls.mostRecent().args[0].queueableFns[0].fn();
// TODO: due to some issue with the Pretty Printer, this line fails, but the other two pass.
// This means toHaveBeenCalledWith on IE8 will always be broken.
// expect(startCallback).toHaveBeenCalledWith(spec);
expect(startCallback).toHaveBeenCalled();
expect(startCallback.calls.first().object).toEqual(spec);
});
it('should call the start callback on execution but before any befores are called', function() {
var fakeQueueRunner = jasmine.createSpy('fakeQueueRunner'),
beforesWereCalled = false,
startCallback = jasmine
.createSpy('start-callback')
.and.callFake(function() {
expect(beforesWereCalled).toBe(false);
}),
spec = new jasmineUnderTest.Spec({
queueableFn: { fn: function() {} },
beforeFns: function() {
return [
function() {
beforesWereCalled = true;
}
];
},
onStart: startCallback,
queueRunnerFactory: fakeQueueRunner
const fakeQueueRunner = jasmine.createSpy('fakeQueueRunner');
let beforesWereCalled = false;
const startCallback = jasmine
.createSpy('start-callback')
.and.callFake(function() {
expect(beforesWereCalled).toBe(false);
});
const spec = new jasmineUnderTest.Spec({
queueableFn: { fn: function() {} },
beforeFns: function() {
return [
function() {
beforesWereCalled = true;
}
];
},
onStart: startCallback
});
spec.execute();
spec.execute(fakeQueueRunner);
fakeQueueRunner.calls.mostRecent().args[0].queueableFns[0].fn();
expect(startCallback).toHaveBeenCalled();
});
it('provides all before fns and after fns to be run', function() {
var fakeQueueRunner = jasmine.createSpy('fakeQueueRunner'),
const fakeQueueRunner = jasmine.createSpy('fakeQueueRunner'),
before = jasmine.createSpy('before'),
after = jasmine.createSpy('after'),
queueableFn = {
@@ -110,32 +103,34 @@ describe('Spec', function() {
queueableFn: queueableFn,
beforeAndAfterFns: function() {
return { befores: [before], afters: [after] };
},
queueRunnerFactory: fakeQueueRunner
}
});
spec.execute();
spec.execute(fakeQueueRunner);
var options = fakeQueueRunner.calls.mostRecent().args[0];
const options = fakeQueueRunner.calls.mostRecent().args[0];
expect(options.queueableFns).toEqual([
{ fn: jasmine.any(Function) },
before,
queueableFn
queueableFn,
after,
{
fn: jasmine.any(Function),
type: 'specCleanup'
}
]);
expect(options.cleanupFns).toEqual([after, { fn: jasmine.any(Function) }]);
});
it("tells the queue runner that it's a leaf node", function() {
var fakeQueueRunner = jasmine.createSpy('fakeQueueRunner'),
const fakeQueueRunner = jasmine.createSpy('fakeQueueRunner'),
spec = new jasmineUnderTest.Spec({
queueableFn: { fn: function() {} },
beforeAndAfterFns: function() {
return { befores: [], afters: [] };
},
queueRunnerFactory: fakeQueueRunner
}
});
spec.execute();
spec.execute(fakeQueueRunner);
expect(fakeQueueRunner).toHaveBeenCalledWith(
jasmine.objectContaining({
@@ -145,63 +140,66 @@ describe('Spec', function() {
});
it('is marked pending if created without a function body', function() {
var fakeQueueRunner = jasmine.createSpy('fakeQueueRunner'),
startCallback = jasmine.createSpy('startCallback'),
const startCallback = jasmine.createSpy('startCallback'),
resultCallback = jasmine.createSpy('resultCallback'),
spec = new jasmineUnderTest.Spec({
onStart: startCallback,
queueableFn: { fn: null },
resultCallback: resultCallback,
queueRunnerFactory: fakeQueueRunner
resultCallback: resultCallback
});
expect(spec.status()).toBe('pending');
});
it('can be excluded at execution time by a parent', function() {
var fakeQueueRunner = jasmine.createSpy('fakeQueueRunner'),
const fakeQueueRunner = jasmine.createSpy('fakeQueueRunner'),
startCallback = jasmine.createSpy('startCallback'),
specBody = jasmine.createSpy('specBody'),
resultCallback = jasmine.createSpy('resultCallback'),
spec = new jasmineUnderTest.Spec({
onStart: startCallback,
queueableFn: { fn: specBody },
resultCallback: resultCallback,
queueRunnerFactory: fakeQueueRunner
resultCallback: resultCallback
});
spec.execute('cally-back', true);
spec.execute(fakeQueueRunner, 'cally-back', true);
expect(fakeQueueRunner).toHaveBeenCalledWith(
jasmine.objectContaining({
onComplete: jasmine.any(Function),
queueableFns: [{ fn: jasmine.any(Function) }],
cleanupFns: [{ fn: jasmine.any(Function) }]
queueableFns: [
{ fn: jasmine.any(Function) },
{
fn: jasmine.any(Function),
type: 'specCleanup'
}
]
})
);
expect(specBody).not.toHaveBeenCalled();
var args = fakeQueueRunner.calls.mostRecent().args[0];
const args = fakeQueueRunner.calls.mostRecent().args[0];
args.queueableFns[0].fn();
expect(startCallback).toHaveBeenCalled();
args.cleanupFns[0].fn();
args.queueableFns[args.queueableFns.length - 1].fn();
expect(resultCallback).toHaveBeenCalled();
expect(spec.result.status).toBe('excluded');
});
it('can be marked pending, but still calls callbacks when executed', function() {
var fakeQueueRunner = jasmine.createSpy('fakeQueueRunner'),
const fakeQueueRunner = jasmine.createSpy('fakeQueueRunner'),
startCallback = jasmine.createSpy('startCallback'),
resultCallback = jasmine.createSpy('resultCallback'),
spec = new jasmineUnderTest.Spec({
onStart: startCallback,
resultCallback: resultCallback,
description: 'with a spec',
parentSuiteId: 'suite1',
filename: 'someSpecFile.js',
getSpecName: function() {
return 'a suite with a spec';
},
queueRunnerFactory: fakeQueueRunner,
queueableFn: { fn: null }
});
@@ -209,64 +207,64 @@ describe('Spec', function() {
expect(spec.status()).toBe('pending');
spec.execute();
spec.execute(fakeQueueRunner);
expect(fakeQueueRunner).toHaveBeenCalled();
var args = fakeQueueRunner.calls.mostRecent().args[0];
const args = fakeQueueRunner.calls.mostRecent().args[0];
args.queueableFns[0].fn();
expect(startCallback).toHaveBeenCalled();
args.cleanupFns[0].fn('things');
args.queueableFns[1].fn('things');
expect(resultCallback).toHaveBeenCalledWith(
{
id: spec.id,
status: 'pending',
description: 'with a spec',
fullName: 'a suite with a spec',
parentSuiteId: 'suite1',
filename: 'someSpecFile.js',
failedExpectations: [],
passedExpectations: [],
deprecationWarnings: [],
pendingReason: '',
duration: jasmine.any(Number),
properties: null
properties: null,
debugLogs: null
},
'things'
);
});
it('should call the done callback on execution complete', function() {
var done = jasmine.createSpy('done callback'),
const done = jasmine.createSpy('done callback'),
spec = new jasmineUnderTest.Spec({
queueableFn: { fn: function() {} },
catchExceptions: function() {
return false;
},
resultCallback: function() {},
queueRunnerFactory: function(attrs) {
attrs.onComplete();
}
resultCallback: function() {}
});
spec.execute(done);
spec.execute(attrs => attrs.onComplete(), done);
expect(done).toHaveBeenCalled();
});
it('should call the done callback with an error if the spec is failed', function() {
var done = jasmine.createSpy('done callback'),
const done = jasmine.createSpy('done callback'),
spec = new jasmineUnderTest.Spec({
queueableFn: { fn: function() {} },
catchExceptions: function() {
return false;
},
resultCallback: function() {},
queueRunnerFactory: function(attrs) {
spec.result.status = 'failed';
attrs.onComplete();
}
resultCallback: function() {}
});
spec.execute(done);
function queueRunnerFactory(attrs) {
spec.result.status = 'failed';
attrs.onComplete();
}
spec.execute(queueRunnerFactory, done);
expect(done).toHaveBeenCalledWith(
jasmine.any(jasmineUnderTest.StopExecutionError)
@@ -274,150 +272,224 @@ describe('Spec', function() {
});
it('should report the duration of the test', function() {
var timer = jasmine.createSpyObj('timer', { start: null, elapsed: 77000 }),
spec = new jasmineUnderTest.Spec({
queueableFn: { fn: jasmine.createSpy('spec body') },
catchExceptions: function() {
return false;
},
resultCallback: function(result) {
duration = result.duration;
},
queueRunnerFactory: function(config) {
config.queueableFns.forEach(function(qf) {
qf.fn();
});
config.cleanupFns.forEach(function(qf) {
qf.fn();
});
config.onComplete();
},
timer: timer
}),
duration = undefined;
const timer = jasmine.createSpyObj('timer', {
start: null,
elapsed: 77000
});
let duration = undefined;
const spec = new jasmineUnderTest.Spec({
queueableFn: { fn: jasmine.createSpy('spec body') },
catchExceptions: function() {
return false;
},
resultCallback: function(result) {
duration = result.duration;
},
timer: timer
});
spec.execute(function() {});
function queueRunnerFactory(config) {
config.queueableFns.forEach(function(qf) {
qf.fn();
});
config.onComplete();
}
spec.execute(queueRunnerFactory, function() {});
expect(duration).toBe(77000);
});
it('should report properties set during the test', function() {
var done = jasmine.createSpy('done callback'),
const done = jasmine.createSpy('done callback'),
spec = new jasmineUnderTest.Spec({
queueableFn: { fn: jasmine.createSpy('spec body') },
catchExceptions: function() {
return false;
},
resultCallback: function() {},
queueRunnerFactory: function(attrs) {
attrs.onComplete();
}
resultCallback: function() {}
});
spec.setSpecProperty('a', 4);
spec.execute(done);
spec.execute(attrs => attrs.onComplete(), done);
expect(spec.result.properties).toEqual({ a: 4 });
});
it('#status returns passing by default', function() {
var spec = new jasmineUnderTest.Spec({
const spec = new jasmineUnderTest.Spec({
queueableFn: { fn: jasmine.createSpy('spec body') }
});
expect(spec.status()).toBe('passed');
});
it('#status returns passed if all expectations in the spec have passed', function() {
var spec = new jasmineUnderTest.Spec({
const spec = new jasmineUnderTest.Spec({
queueableFn: { fn: jasmine.createSpy('spec body') }
});
spec.addExpectationResult(true);
spec.addExpectationResult(true, {});
expect(spec.status()).toBe('passed');
});
it('#status returns failed if any expectations in the spec have failed', function() {
var spec = new jasmineUnderTest.Spec({
const spec = new jasmineUnderTest.Spec({
queueableFn: { fn: jasmine.createSpy('spec body') }
});
spec.addExpectationResult(true);
spec.addExpectationResult(false);
spec.addExpectationResult(true, {});
spec.addExpectationResult(false, {});
expect(spec.status()).toBe('failed');
});
it('keeps track of passed and failed expectations', function() {
var fakeQueueRunner = jasmine.createSpy('queueRunner'),
const fakeQueueRunner = jasmine.createSpy('queueRunner'),
resultCallback = jasmine.createSpy('resultCallback'),
spec = new jasmineUnderTest.Spec({
queueableFn: { fn: jasmine.createSpy('spec body') },
expectationResultFactory: function(data) {
return data;
},
queueRunnerFactory: fakeQueueRunner,
resultCallback: resultCallback
});
spec.addExpectationResult(true, 'expectation1');
spec.addExpectationResult(false, 'expectation2');
spec.addExpectationResult(true, { message: 'expectation1' });
spec.addExpectationResult(false, { message: 'expectation2' });
spec.execute();
spec.execute(fakeQueueRunner);
const fns = fakeQueueRunner.calls.mostRecent().args[0].queueableFns;
fns[fns.length - 1].fn();
fakeQueueRunner.calls.mostRecent().args[0].cleanupFns[0].fn();
expect(resultCallback.calls.first().args[0].passedExpectations).toEqual([
'expectation1'
jasmine.objectContaining({ message: 'expectation1' })
]);
expect(resultCallback.calls.first().args[0].failedExpectations).toEqual([
'expectation2'
jasmine.objectContaining({ message: 'expectation2' })
]);
});
it("throws an ExpectationFailed error upon receiving a failed expectation when 'throwOnExpectationFailure' is set", function() {
var fakeQueueRunner = jasmine.createSpy('queueRunner'),
const fakeQueueRunner = jasmine.createSpy('queueRunner'),
resultCallback = jasmine.createSpy('resultCallback'),
spec = new jasmineUnderTest.Spec({
queueableFn: { fn: function() {} },
expectationResultFactory: function(data) {
return data;
},
queueRunnerFactory: fakeQueueRunner,
resultCallback: resultCallback,
throwOnExpectationFailure: true
});
spec.addExpectationResult(true, 'passed');
spec.addExpectationResult(true, { message: 'passed' });
expect(function() {
spec.addExpectationResult(false, 'failed');
spec.addExpectationResult(false, { message: 'failed' });
}).toThrowError(jasmineUnderTest.errors.ExpectationFailed);
spec.execute();
spec.execute(fakeQueueRunner);
fakeQueueRunner.calls.mostRecent().args[0].cleanupFns[0].fn();
const fns = fakeQueueRunner.calls.mostRecent().args[0].queueableFns;
fns[fns.length - 1].fn();
expect(resultCallback.calls.first().args[0].passedExpectations).toEqual([
'passed'
jasmine.objectContaining({ message: 'passed' })
]);
expect(resultCallback.calls.first().args[0].failedExpectations).toEqual([
'failed'
jasmine.objectContaining({ message: 'failed' })
]);
});
it('forwards late expectation failures to onLateError', function() {
const onLateError = jasmine.createSpy('onLateError');
const spec = new jasmineUnderTest.Spec({
onLateError,
queueableFn: { fn: function() {} }
});
const data = {
matcherName: '',
passed: false,
expected: '',
actual: '',
error: new Error('nope')
};
spec.reportedDone = true;
spec.addExpectationResult(false, data, true);
expect(onLateError).toHaveBeenCalledWith(
jasmine.objectContaining({
message: jasmine.stringMatching(/^Error: nope/)
})
);
expect(spec.result.failedExpectations).toEqual([]);
});
it('does not forward non-late expectation failures to onLateError', function() {
const onLateError = jasmine.createSpy('onLateError');
const spec = new jasmineUnderTest.Spec({
onLateError,
queueableFn: { fn: function() {} }
});
const data = {
matcherName: '',
passed: false,
expected: '',
actual: '',
error: new Error('nope')
};
spec.addExpectationResult(false, data, true);
expect(onLateError).not.toHaveBeenCalled();
});
it('forwards late handleException calls to onLateError', function() {
const onLateError = jasmine.createSpy('onLateError');
const spec = new jasmineUnderTest.Spec({
onLateError,
queueableFn: { fn: function() {} }
});
spec.reportedDone = true;
spec.handleException(new Error('oops'));
expect(onLateError).toHaveBeenCalledWith(
jasmine.objectContaining({
message: jasmine.stringMatching(/^Error: oops/)
})
);
expect(spec.result.failedExpectations).toEqual([]);
});
it('does not forward non-late handleException calls to onLateError', function() {
const onLateError = jasmine.createSpy('onLateError');
const spec = new jasmineUnderTest.Spec({
onLateError,
queueableFn: { fn: function() {} }
});
const error = new Error('oops');
spec.handleException(error);
expect(onLateError).not.toHaveBeenCalled();
expect(spec.result.failedExpectations.length).toEqual(1);
});
it('clears the reportedDone flag when reset', function() {
const spec = new jasmineUnderTest.Spec({
queueableFn: { fn: function() {} }
});
spec.reportedDone = true;
spec.reset();
expect(spec.reportedDone).toBeFalse();
});
it('does not throw an ExpectationFailed error when handling an error', function() {
var resultCallback = jasmine.createSpy('resultCallback'),
const resultCallback = jasmine.createSpy('resultCallback'),
spec = new jasmineUnderTest.Spec({
queueableFn: { fn: function() {} },
expectationResultFactory: function(data) {
return data;
},
queueRunnerFactory: function(attrs) {
attrs.onComplete();
},
resultCallback: resultCallback,
throwOnExpectationFailure: true
});
spec.onException('failing exception');
spec.handleException('failing exception');
});
it('can return its full name', function() {
var specNameSpy = jasmine
const specNameSpy = jasmine
.createSpy('specNameSpy')
.and.returnValue('expected val');
var spec = new jasmineUnderTest.Spec({
const spec = new jasmineUnderTest.Spec({
getSpecName: specNameSpy,
queueableFn: { fn: null }
});
@@ -428,7 +500,7 @@ describe('Spec', function() {
describe('when a spec is marked pending during execution', function() {
it('should mark the spec as pending', function() {
var fakeQueueRunner = function(opts) {
const fakeQueueRunner = function(opts) {
opts.onException(
new Error(jasmineUnderTest.Spec.pendingSpecExceptionMessage)
);
@@ -436,18 +508,17 @@ describe('Spec', function() {
spec = new jasmineUnderTest.Spec({
description: 'my test',
id: 'some-id',
queueableFn: { fn: function() {} },
queueRunnerFactory: fakeQueueRunner
queueableFn: { fn: function() {} }
});
spec.execute();
spec.execute(fakeQueueRunner);
expect(spec.status()).toEqual('pending');
expect(spec.result.pendingReason).toEqual('');
});
it('should set the pendingReason', function() {
var fakeQueueRunner = function(opts) {
const fakeQueueRunner = function(opts) {
opts.onException(
new Error(
jasmineUnderTest.Spec.pendingSpecExceptionMessage +
@@ -458,11 +529,10 @@ describe('Spec', function() {
spec = new jasmineUnderTest.Spec({
description: 'my test',
id: 'some-id',
queueableFn: { fn: function() {} },
queueRunnerFactory: fakeQueueRunner
queueableFn: { fn: function() {} }
});
spec.execute();
spec.execute(fakeQueueRunner);
expect(spec.status()).toEqual('pending');
expect(spec.result.pendingReason).toEqual('custom message');
@@ -470,50 +540,177 @@ describe('Spec', function() {
});
it('should log a failure when handling an exception', function() {
var fakeQueueRunner = jasmine.createSpy('queueRunner'),
const fakeQueueRunner = jasmine.createSpy('queueRunner'),
resultCallback = jasmine.createSpy('resultCallback'),
spec = new jasmineUnderTest.Spec({
queueableFn: { fn: function() {} },
expectationResultFactory: function(data) {
return data;
},
queueRunnerFactory: fakeQueueRunner,
resultCallback: resultCallback
});
spec.onException('foo');
spec.execute();
spec.handleException('foo');
spec.execute(fakeQueueRunner);
var args = fakeQueueRunner.calls.mostRecent().args[0];
args.cleanupFns[0].fn();
const args = fakeQueueRunner.calls.mostRecent().args[0];
args.queueableFns[args.queueableFns.length - 1].fn();
expect(resultCallback.calls.first().args[0].failedExpectations).toEqual([
{
error: 'foo',
message: 'foo thrown',
matcherName: '',
passed: false,
expected: '',
actual: ''
actual: '',
stack: null
}
]);
});
it('should not log an additional failure when handling an ExpectationFailed error', function() {
var fakeQueueRunner = jasmine.createSpy('queueRunner'),
const fakeQueueRunner = jasmine.createSpy('queueRunner'),
resultCallback = jasmine.createSpy('resultCallback'),
spec = new jasmineUnderTest.Spec({
queueableFn: { fn: function() {} },
expectationResultFactory: function(data) {
return data;
},
queueRunnerFactory: fakeQueueRunner,
resultCallback: resultCallback
});
spec.onException(new jasmineUnderTest.errors.ExpectationFailed());
spec.execute();
spec.handleException(new jasmineUnderTest.errors.ExpectationFailed());
spec.execute(fakeQueueRunner);
var args = fakeQueueRunner.calls.mostRecent().args[0];
args.cleanupFns[0].fn();
const args = fakeQueueRunner.calls.mostRecent().args[0];
args.queueableFns[args.queueableFns.length - 1].fn();
expect(resultCallback.calls.first().args[0].failedExpectations).toEqual([]);
});
it('treats multiple done calls as late errors', function() {
const queueRunnerFactory = jasmine.createSpy('queueRunnerFactory'),
onLateError = jasmine.createSpy('onLateError'),
spec = new jasmineUnderTest.Spec({
onLateError: onLateError,
queueableFn: { fn: function() {} },
getSpecName: function() {
return 'a spec';
}
});
spec.execute(queueRunnerFactory);
expect(queueRunnerFactory).toHaveBeenCalled();
queueRunnerFactory.calls.argsFor(0)[0].onMultipleDone();
expect(onLateError).toHaveBeenCalledTimes(1);
expect(onLateError.calls.argsFor(0)[0]).toBeInstanceOf(Error);
expect(onLateError.calls.argsFor(0)[0].message).toEqual(
'An asynchronous spec, beforeEach, or afterEach function called its ' +
"'done' callback more than once.\n(in spec: a spec)"
);
});
describe('#trace', function() {
it('adds the messages to the result', function() {
const timer = jasmine.createSpyObj('timer', ['start', 'elapsed']),
spec = new jasmineUnderTest.Spec({
queueableFn: {
fn: function() {}
},
timer: timer
}),
t1 = 123,
t2 = 456;
spec.execute(() => {});
expect(spec.result.debugLogs).toBeNull();
timer.elapsed.and.returnValue(t1);
spec.debugLog('msg 1');
expect(spec.result.debugLogs).toEqual([
{ message: 'msg 1', timestamp: t1 }
]);
timer.elapsed.and.returnValue(t2);
spec.debugLog('msg 2');
expect(spec.result.debugLogs).toEqual([
{ message: 'msg 1', timestamp: t1 },
{ message: 'msg 2', timestamp: t2 }
]);
});
describe('When the spec passes', function() {
it('omits the messages from the reported result', function() {
const resultCallback = jasmine.createSpy('resultCallback'),
spec = new jasmineUnderTest.Spec({
queueableFn: {
fn: function() {}
},
resultCallback: resultCallback
});
function queueRunnerFactory(config) {
spec.debugLog('msg');
for (const fn of config.queueableFns) {
fn.fn();
}
config.onComplete(false);
}
spec.execute(queueRunnerFactory, function() {});
expect(resultCallback).toHaveBeenCalledWith(
jasmine.objectContaining({ debugLogs: null }),
undefined
);
});
it('removes the messages to save memory', function() {
const resultCallback = jasmine.createSpy('resultCallback'),
spec = new jasmineUnderTest.Spec({
queueableFn: {
fn: function() {}
},
resultCallback: resultCallback
});
function queueRunnerFactory(config) {
spec.debugLog('msg');
for (const fn of config.queueableFns) {
fn.fn();
}
config.onComplete(false);
}
spec.execute(queueRunnerFactory, function() {});
expect(resultCallback).toHaveBeenCalled();
expect(spec.result.debugLogs).toBeNull();
});
});
describe('When the spec fails', function() {
it('includes the messages in the reported result', function() {
const resultCallback = jasmine.createSpy('resultCallback'),
timer = jasmine.createSpyObj('timer', ['start', 'elapsed']),
spec = new jasmineUnderTest.Spec({
queueableFn: {
fn: function() {}
},
resultCallback: resultCallback,
timer: timer
}),
timestamp = 12345;
timer.elapsed.and.returnValue(timestamp);
function queueRunnerFactory(config) {
spec.debugLog('msg');
spec.handleException(new Error('nope'));
for (const fn of config.queueableFns) {
fn.fn();
}
config.onComplete(true);
}
spec.execute(queueRunnerFactory, function() {});
expect(resultCallback).toHaveBeenCalledWith(
jasmine.objectContaining({
debugLogs: [{ message: 'msg', timestamp: timestamp }]
}),
undefined
);
});
});
});
});

View File

@@ -5,7 +5,7 @@ describe('SpyRegistry', function() {
describe('#spyOn', function() {
it('checks for the existence of the object', function() {
var spyRegistry = new jasmineUnderTest.SpyRegistry({
const spyRegistry = new jasmineUnderTest.SpyRegistry({
createSpy: createSpy
});
expect(function() {
@@ -14,7 +14,7 @@ describe('SpyRegistry', function() {
});
it('checks that a method name was passed', function() {
var spyRegistry = new jasmineUnderTest.SpyRegistry(),
const spyRegistry = new jasmineUnderTest.SpyRegistry(),
subject = {};
expect(function() {
@@ -23,14 +23,14 @@ describe('SpyRegistry', function() {
});
it('checks that the object is not `null`', function() {
var spyRegistry = new jasmineUnderTest.SpyRegistry();
const spyRegistry = new jasmineUnderTest.SpyRegistry();
expect(function() {
spyRegistry.spyOn(null, 'pants');
}).toThrowError(/could not find an object/);
});
it('checks that the method name is not `null`', function() {
var spyRegistry = new jasmineUnderTest.SpyRegistry(),
const spyRegistry = new jasmineUnderTest.SpyRegistry(),
subject = {};
expect(function() {
@@ -39,7 +39,7 @@ describe('SpyRegistry', function() {
});
it('checks for the existence of the method', function() {
var spyRegistry = new jasmineUnderTest.SpyRegistry(),
const spyRegistry = new jasmineUnderTest.SpyRegistry(),
subject = {};
expect(function() {
@@ -48,7 +48,7 @@ describe('SpyRegistry', function() {
});
it('checks if it has already been spied upon', function() {
var spies = [],
const spies = [],
spyRegistry = new jasmineUnderTest.SpyRegistry({
currentSpies: function() {
return spies;
@@ -65,7 +65,7 @@ describe('SpyRegistry', function() {
});
it('checks if it can be spied upon', function() {
var scope = {};
const scope = {};
function myFunc() {
return 1;
@@ -77,7 +77,7 @@ describe('SpyRegistry', function() {
}
});
var spies = [],
const spies = [],
spyRegistry = new jasmineUnderTest.SpyRegistry({
currentSpies: function() {
return spies;
@@ -95,7 +95,7 @@ describe('SpyRegistry', function() {
});
it('overrides the method on the object and returns the spy', function() {
var originalFunctionWasCalled = false,
const originalFunctionWasCalled = false,
spyRegistry = new jasmineUnderTest.SpyRegistry({
createSpy: createSpy
}),
@@ -105,7 +105,7 @@ describe('SpyRegistry', function() {
}
};
var spy = spyRegistry.spyOn(subject, 'spiedFunc');
const spy = spyRegistry.spyOn(subject, 'spiedFunc');
expect(subject.spiedFunc).toEqual(spy);
subject.spiedFunc();
@@ -115,14 +115,14 @@ describe('SpyRegistry', function() {
describe('#spyOnProperty', function() {
it('checks for the existence of the object', function() {
var spyRegistry = new jasmineUnderTest.SpyRegistry();
const spyRegistry = new jasmineUnderTest.SpyRegistry();
expect(function() {
spyRegistry.spyOnProperty(void 0, 'pants');
}).toThrowError(/could not find an object/);
});
it('checks that a property name was passed', function() {
var spyRegistry = new jasmineUnderTest.SpyRegistry(),
const spyRegistry = new jasmineUnderTest.SpyRegistry(),
subject = {};
expect(function() {
@@ -131,7 +131,7 @@ describe('SpyRegistry', function() {
});
it('checks for the existence of the method', function() {
var spyRegistry = new jasmineUnderTest.SpyRegistry(),
const spyRegistry = new jasmineUnderTest.SpyRegistry(),
subject = {};
expect(function() {
@@ -140,7 +140,7 @@ describe('SpyRegistry', function() {
});
it('checks for the existence of access type', function() {
var spyRegistry = new jasmineUnderTest.SpyRegistry(),
const spyRegistry = new jasmineUnderTest.SpyRegistry(),
subject = {};
Object.defineProperty(subject, 'pants', {
@@ -156,7 +156,7 @@ describe('SpyRegistry', function() {
});
it('checks if it can be spied upon', function() {
var subject = {};
const subject = {};
Object.defineProperty(subject, 'myProp', {
get: function() {}
@@ -167,7 +167,7 @@ describe('SpyRegistry', function() {
configurable: true
});
var spyRegistry = new jasmineUnderTest.SpyRegistry();
const spyRegistry = new jasmineUnderTest.SpyRegistry();
expect(function() {
spyRegistry.spyOnProperty(subject, 'myProp');
@@ -179,7 +179,7 @@ describe('SpyRegistry', function() {
});
it('overrides the property getter on the object and returns the spy', function() {
var spyRegistry = new jasmineUnderTest.SpyRegistry({
const spyRegistry = new jasmineUnderTest.SpyRegistry({
createSpy: createSpy
}),
subject = {},
@@ -194,8 +194,8 @@ describe('SpyRegistry', function() {
expect(subject.spiedProperty).toEqual(returnValue);
var spy = spyRegistry.spyOnProperty(subject, 'spiedProperty');
var getter = Object.getOwnPropertyDescriptor(subject, 'spiedProperty')
const spy = spyRegistry.spyOnProperty(subject, 'spiedProperty');
const getter = Object.getOwnPropertyDescriptor(subject, 'spiedProperty')
.get;
expect(getter).toEqual(spy);
@@ -203,7 +203,7 @@ describe('SpyRegistry', function() {
});
it('overrides the property setter on the object and returns the spy', function() {
var spyRegistry = new jasmineUnderTest.SpyRegistry({
const spyRegistry = new jasmineUnderTest.SpyRegistry({
createSpy: createSpy
}),
subject = {},
@@ -217,8 +217,8 @@ describe('SpyRegistry', function() {
configurable: true
});
var spy = spyRegistry.spyOnProperty(subject, 'spiedProperty', 'set');
var setter = Object.getOwnPropertyDescriptor(subject, 'spiedProperty')
const spy = spyRegistry.spyOnProperty(subject, 'spiedProperty', 'set');
const setter = Object.getOwnPropertyDescriptor(subject, 'spiedProperty')
.set;
expect(subject.spiedProperty).toEqual(returnValue);
@@ -227,7 +227,7 @@ describe('SpyRegistry', function() {
describe('when the property is already spied upon', function() {
it('throws an error if respy is not allowed', function() {
var spyRegistry = new jasmineUnderTest.SpyRegistry({
const spyRegistry = new jasmineUnderTest.SpyRegistry({
createSpy: createSpy
}),
subject = {};
@@ -247,7 +247,7 @@ describe('SpyRegistry', function() {
});
it('returns the original spy if respy is allowed', function() {
var spyRegistry = new jasmineUnderTest.SpyRegistry({
const spyRegistry = new jasmineUnderTest.SpyRegistry({
createSpy: createSpy
}),
subject = {};
@@ -261,7 +261,7 @@ describe('SpyRegistry', function() {
configurable: true
});
var originalSpy = spyRegistry.spyOnProperty(subject, 'spiedProp');
const originalSpy = spyRegistry.spyOnProperty(subject, 'spiedProp');
expect(spyRegistry.spyOnProperty(subject, 'spiedProp')).toBe(
originalSpy
@@ -272,33 +272,33 @@ describe('SpyRegistry', function() {
describe('#spyOnAllFunctions', function() {
it('checks for the existence of the object', function() {
var spyRegistry = new jasmineUnderTest.SpyRegistry();
const spyRegistry = new jasmineUnderTest.SpyRegistry();
expect(function() {
spyRegistry.spyOnAllFunctions(void 0);
}).toThrowError(/spyOnAllFunctions could not find an object to spy upon/);
});
it('overrides all writable and configurable functions of the object and its parents', function() {
var spyRegistry = new jasmineUnderTest.SpyRegistry({
const spyRegistry = new jasmineUnderTest.SpyRegistry({
createSpy: function() {
return 'I am a spy';
}
});
var createNoop = function() {
const createNoop = function() {
return function() {
/**/
};
};
var noop1 = createNoop();
var noop2 = createNoop();
var noop3 = createNoop();
var noop4 = createNoop();
var noop5 = createNoop();
const noop1 = createNoop();
const noop2 = createNoop();
const noop3 = createNoop();
const noop4 = createNoop();
const noop5 = createNoop();
var parent = {
const parent = {
parentSpied1: noop1
};
var subject = Object.create(parent);
const subject = Object.create(parent);
Object.defineProperty(subject, 'spied1', {
value: noop1,
writable: true,
@@ -311,7 +311,7 @@ describe('SpyRegistry', function() {
configurable: true,
enumerable: true
});
var _spied3 = noop3;
let _spied3 = noop3;
Object.defineProperty(subject, 'spied3', {
configurable: true,
set: function(val) {
@@ -337,7 +337,7 @@ describe('SpyRegistry', function() {
});
Object.defineProperty(subject, 'notSpied4', {
configurable: false,
set: function(val) {
set: function() {
/**/
},
get: function() {
@@ -353,7 +353,7 @@ describe('SpyRegistry', function() {
});
subject.notSpied6 = 6;
var spiedObject = spyRegistry.spyOnAllFunctions(subject);
const spiedObject = spyRegistry.spyOnAllFunctions(subject);
expect(subject.parentSpied1).toBe('I am a spy');
expect(subject.notSpied2).toBe(noop2);
@@ -369,21 +369,21 @@ describe('SpyRegistry', function() {
});
it('overrides prototype methods on the object', function() {
var spyRegistry = new jasmineUnderTest.SpyRegistry({
const spyRegistry = new jasmineUnderTest.SpyRegistry({
createSpy: function() {
return 'I am a spy';
}
});
var noop1 = function() {};
var noop2 = function() {};
const noop1 = function() {};
const noop2 = function() {};
var MyClass = function() {
const MyClass = function() {
this.spied1 = noop1;
};
MyClass.prototype.spied2 = noop2;
var subject = new MyClass();
const subject = new MyClass();
spyRegistry.spyOnAllFunctions(subject);
expect(subject.spied1).toBe('I am a spy');
@@ -392,12 +392,12 @@ describe('SpyRegistry', function() {
});
it('does not override non-enumerable properties (like Object.prototype methods)', function() {
var spyRegistry = new jasmineUnderTest.SpyRegistry({
const spyRegistry = new jasmineUnderTest.SpyRegistry({
createSpy: function() {
return 'I am a spy';
}
});
var subject = {
const subject = {
spied1: function() {}
};
@@ -409,12 +409,12 @@ describe('SpyRegistry', function() {
});
describe('when includeNonEnumerable is true', function() {
it('does not override Object.prototype methods', function() {
var spyRegistry = new jasmineUnderTest.SpyRegistry({
const spyRegistry = new jasmineUnderTest.SpyRegistry({
createSpy: function() {
return 'I am a spy';
}
});
var subject = {
const subject = {
spied1: function() {}
};
@@ -426,12 +426,12 @@ describe('SpyRegistry', function() {
});
it('overrides non-enumerable properties', function() {
var spyRegistry = new jasmineUnderTest.SpyRegistry({
const spyRegistry = new jasmineUnderTest.SpyRegistry({
createSpy: function() {
return 'I am a spy';
}
});
var subject = {
const subject = {
spied1: function() {},
spied2: function() {}
};
@@ -449,12 +449,12 @@ describe('SpyRegistry', function() {
});
it('should not spy on non-enumerable functions named constructor', function() {
var spyRegistry = new jasmineUnderTest.SpyRegistry({
const spyRegistry = new jasmineUnderTest.SpyRegistry({
createSpy: function() {
return 'I am a spy';
}
});
var subject = {
const subject = {
constructor: function() {}
};
@@ -470,12 +470,12 @@ describe('SpyRegistry', function() {
});
it('should spy on enumerable functions named constructor', function() {
var spyRegistry = new jasmineUnderTest.SpyRegistry({
const spyRegistry = new jasmineUnderTest.SpyRegistry({
createSpy: function() {
return 'I am a spy';
}
});
var subject = {
const subject = {
constructor: function() {}
};
@@ -485,13 +485,13 @@ describe('SpyRegistry', function() {
});
it('should not throw an exception if we try and access strict mode restricted properties', function() {
var spyRegistry = new jasmineUnderTest.SpyRegistry({
const spyRegistry = new jasmineUnderTest.SpyRegistry({
createSpy: function() {
return 'I am a spy';
}
});
var subject = function() {};
var fn = function() {
const subject = function() {};
const fn = function() {
spyRegistry.spyOnAllFunctions(subject, true);
};
@@ -499,24 +499,24 @@ describe('SpyRegistry', function() {
});
it('should not spy on properties which are more permissable further up the prototype chain', function() {
var spyRegistry = new jasmineUnderTest.SpyRegistry({
const spyRegistry = new jasmineUnderTest.SpyRegistry({
createSpy: function() {
return 'I am a spy';
}
});
var subjectParent = Object.defineProperty({}, 'sharedProp', {
const subjectParent = Object.defineProperty({}, 'sharedProp', {
value: function() {},
writable: true,
configurable: true
});
var subject = Object.create(subjectParent);
const subject = Object.create(subjectParent);
Object.defineProperty(subject, 'sharedProp', {
value: function() {}
});
var fn = function() {
const fn = function() {
spyRegistry.spyOnAllFunctions(subject, true);
};
@@ -528,7 +528,7 @@ describe('SpyRegistry', function() {
describe('#clearSpies', function() {
it('restores the original functions on the spied-upon objects', function() {
var spies = [],
const spies = [],
spyRegistry = new jasmineUnderTest.SpyRegistry({
currentSpies: function() {
return spies;
@@ -545,7 +545,7 @@ describe('SpyRegistry', function() {
});
it('restores the original functions, even when that spy has been replace and re-spied upon', function() {
var spies = [],
const spies = [],
spyRegistry = new jasmineUnderTest.SpyRegistry({
currentSpies: function() {
return spies;
@@ -569,7 +569,7 @@ describe('SpyRegistry', function() {
});
it("does not add a property that the spied-upon object didn't originally have", function() {
var spies = [],
const spies = [],
spyRegistry = new jasmineUnderTest.SpyRegistry({
currentSpies: function() {
return spies;
@@ -579,7 +579,7 @@ describe('SpyRegistry', function() {
originalFunction = function() {},
subjectParent = { spiedFunc: originalFunction };
var subject = Object.create(subjectParent);
const subject = Object.create(subjectParent);
expect(subject.hasOwnProperty('spiedFunc')).toBe(false);
@@ -591,7 +591,7 @@ describe('SpyRegistry', function() {
});
it("restores the original function when it's inherited and cannot be deleted", function() {
var spies = [],
const spies = [],
spyRegistry = new jasmineUnderTest.SpyRegistry({
currentSpies: function() {
return spies;
@@ -601,7 +601,7 @@ describe('SpyRegistry', function() {
originalFunction = function() {},
subjectParent = { spiedFunc: originalFunction };
var subject = Object.create(subjectParent);
const subject = Object.create(subjectParent);
spyRegistry.spyOn(subject, 'spiedFunc');
@@ -619,7 +619,7 @@ describe('SpyRegistry', function() {
function FakeWindow() {}
FakeWindow.prototype.onerror = function() {};
var spies = [],
const spies = [],
global = new FakeWindow(),
spyRegistry = new jasmineUnderTest.SpyRegistry({
currentSpies: function() {
@@ -638,7 +638,7 @@ describe('SpyRegistry', function() {
describe('spying on properties', function() {
it('restores the original properties on the spied-upon objects', function() {
var spies = [],
const spies = [],
spyRegistry = new jasmineUnderTest.SpyRegistry({
currentSpies: function() {
return spies;
@@ -662,7 +662,7 @@ describe('SpyRegistry', function() {
});
it("does not add a property that the spied-upon object didn't originally have", function() {
var spies = [],
const spies = [],
spyRegistry = new jasmineUnderTest.SpyRegistry({
currentSpies: function() {
return spies;
@@ -679,7 +679,7 @@ describe('SpyRegistry', function() {
configurable: true
});
var subject = Object.create(subjectParent);
const subject = Object.create(subjectParent);
expect(subject.hasOwnProperty('spiedProp')).toBe(false);

View File

@@ -1,5 +1,5 @@
describe('Spies', function() {
var env;
let env;
beforeEach(function() {
env = new jasmineUnderTest.Env();
@@ -10,7 +10,7 @@ describe('Spies', function() {
});
describe('createSpy', function() {
var TestClass;
let TestClass;
beforeEach(function() {
TestClass = function() {};
@@ -19,7 +19,7 @@ describe('Spies', function() {
});
it('preserves the properties of the spied function', function() {
var spy = env.createSpy(
const spy = env.createSpy(
TestClass.prototype,
TestClass.prototype.someFunction
);
@@ -28,15 +28,10 @@ describe('Spies', function() {
});
it('should allow you to omit the name argument and only pass the originalFn argument', function() {
var fn = function test() {};
var spy = env.createSpy(fn);
const fn = function test() {};
const spy = env.createSpy(fn);
// IE doesn't do `.name`
if (fn.name === 'test') {
expect(spy.and.identity).toEqual('test');
} else {
expect(spy.and.identity).toEqual('unknown');
}
expect(spy.and.identity).toEqual('test');
});
it('warns the user that we intend to overwrite an existing property', function() {
@@ -50,7 +45,7 @@ describe('Spies', function() {
});
it('adds a spyStrategy and callTracker to the spy', function() {
var spy = env.createSpy(
const spy = env.createSpy(
TestClass.prototype,
TestClass.prototype.someFunction
);
@@ -60,11 +55,11 @@ describe('Spies', function() {
});
it('tracks the argument of calls', function() {
var spy = env.createSpy(
const spy = env.createSpy(
TestClass.prototype,
TestClass.prototype.someFunction
);
var trackSpy = spyOn(spy.calls, 'track');
const trackSpy = spyOn(spy.calls, 'track');
spy('arg');
@@ -72,24 +67,24 @@ describe('Spies', function() {
});
it('tracks the context of calls', function() {
var spy = env.createSpy(
const spy = env.createSpy(
TestClass.prototype,
TestClass.prototype.someFunction
);
var trackSpy = spyOn(spy.calls, 'track');
const trackSpy = spyOn(spy.calls, 'track');
var contextObject = { spyMethod: spy };
const contextObject = { spyMethod: spy };
contextObject.spyMethod();
expect(trackSpy.calls.mostRecent().args[0].object).toEqual(contextObject);
});
it('tracks the return value of calls', function() {
var spy = env.createSpy(
const spy = env.createSpy(
TestClass.prototype,
TestClass.prototype.someFunction
);
var trackSpy = spyOn(spy.calls, 'track');
const trackSpy = spyOn(spy.calls, 'track');
spy.and.returnValue('return value');
spy();
@@ -100,18 +95,24 @@ describe('Spies', function() {
});
it('preserves arity of original function', function() {
var functions = [
const functions = [
function nullary() {},
// eslint-disable-next-line no-unused-vars
function unary(arg) {},
// eslint-disable-next-line no-unused-vars
function binary(arg1, arg2) {},
// eslint-disable-next-line no-unused-vars
function ternary(arg1, arg2, arg3) {},
// eslint-disable-next-line no-unused-vars
function quaternary(arg1, arg2, arg3, arg4) {},
// eslint-disable-next-line no-unused-vars
function quinary(arg1, arg2, arg3, arg4, arg5) {},
// eslint-disable-next-line no-unused-vars
function senary(arg1, arg2, arg3, arg4, arg5, arg6) {}
];
for (var arity = 0; arity < functions.length; arity++) {
var someFunction = functions[arity],
for (let arity = 0; arity < functions.length; arity++) {
const someFunction = functions[arity],
spy = env.createSpy(someFunction.name, someFunction);
expect(spy.length).toEqual(arity);
@@ -121,7 +122,7 @@ describe('Spies', function() {
describe('createSpyObj', function() {
it('should create an object with spy methods and corresponding return values when you call jasmine.createSpyObj() with an object', function() {
var spyObj = env.createSpyObj('BaseName', {
const spyObj = env.createSpyObj('BaseName', {
method1: 42,
method2: 'special sauce'
});
@@ -134,7 +135,7 @@ describe('Spies', function() {
});
it('should create an object with a bunch of spy methods when you call jasmine.createSpyObj()', function() {
var spyObj = env.createSpyObj('BaseName', ['method1', 'method2']);
const spyObj = env.createSpyObj('BaseName', ['method1', 'method2']);
expect(spyObj).toEqual({
method1: jasmine.any(Function),
@@ -145,7 +146,7 @@ describe('Spies', function() {
});
it('should allow you to omit the baseName', function() {
var spyObj = env.createSpyObj(['method1', 'method2']);
const spyObj = env.createSpyObj(['method1', 'method2']);
expect(spyObj).toEqual({
method1: jasmine.any(Function),
@@ -180,20 +181,20 @@ describe('Spies', function() {
});
it('creates an object with spy properties if a second list is passed', function() {
var spyObj = env.createSpyObj('base', ['method1'], ['prop1']);
const spyObj = env.createSpyObj('base', ['method1'], ['prop1']);
expect(spyObj).toEqual({
method1: jasmine.any(Function),
prop1: undefined
});
var descriptor = Object.getOwnPropertyDescriptor(spyObj, 'prop1');
const descriptor = Object.getOwnPropertyDescriptor(spyObj, 'prop1');
expect(descriptor.get.and.identity).toEqual('base.prop1.get');
expect(descriptor.set.and.identity).toEqual('base.prop1.set');
});
it('creates an object with property names and return values if second object is passed', function() {
var spyObj = env.createSpyObj('base', ['method1'], {
const spyObj = env.createSpyObj('base', ['method1'], {
prop1: 'foo',
prop2: 37
});
@@ -214,7 +215,7 @@ describe('Spies', function() {
});
it('allows base name to be omitted when assigning methods and properties', function() {
var spyObj = env.createSpyObj({ m: 3 }, { p: 4 });
const spyObj = env.createSpyObj({ m: 3 }, { p: 4 });
expect(spyObj.m()).toEqual(3);
expect(spyObj.p).toEqual(4);
@@ -225,7 +226,7 @@ describe('Spies', function() {
});
it('can use different strategies for different arguments', function() {
var spy = env.createSpy('foo');
const spy = env.createSpy('foo');
spy.and.returnValue(42);
spy.withArgs('baz', 'grault').and.returnValue(-1);
spy.withArgs('thud').and.returnValue('bob');
@@ -236,8 +237,8 @@ describe('Spies', function() {
expect(spy('baz', 'grault', 'waldo')).toEqual(42);
});
it('uses custom equality testers when selecting a strategy', function() {
var spy = env.createSpy('foo');
it('uses asymmetric equality testers when selecting a strategy', function() {
const spy = env.createSpy('foo');
spy.and.returnValue(42);
spy.withArgs(jasmineUnderTest.any(String)).and.returnValue(-1);
@@ -245,18 +246,33 @@ describe('Spies', function() {
expect(spy({})).toEqual(42);
});
it('uses the provided matchersUtil selecting a strategy', function() {
const matchersUtil = new jasmineUnderTest.MatchersUtil({
customTesters: [
function(a, b) {
if ((a === 'bar' && b === 'baz') || (a === 'baz' && b === 'bar')) {
return true;
}
}
]
});
const spy = new jasmineUnderTest.Spy('aSpy', matchersUtil);
spy.and.returnValue('default strategy return value');
spy.withArgs('bar').and.returnValue('custom strategy return value');
expect(spy('foo')).toEqual('default strategy return value');
expect(spy('baz')).toEqual('custom strategy return value');
});
it('can reconfigure an argument-specific strategy', function() {
var spy = env.createSpy('foo');
const spy = env.createSpy('foo');
spy.withArgs('foo').and.returnValue(42);
spy.withArgs('foo').and.returnValue(17);
expect(spy('foo')).toEqual(17);
});
describe('any promise-based strategy', function() {
it('works with global Promise library when available', function(done) {
jasmine.getEnv().requirePromises();
var spy = env.createSpy('foo').and.resolveTo(42);
it('works with global Promise library', function(done) {
const spy = env.createSpy('foo').and.resolveTo(42);
spy()
.then(function(result) {
expect(result).toEqual(42);
@@ -264,31 +280,18 @@ describe('Spies', function() {
})
.catch(done.fail);
});
it('works with a custom Promise library', function() {
var customPromise = {
resolve: jasmine.createSpy(),
reject: jasmine.createSpy()
};
customPromise.resolve.and.returnValue('resolved');
env.configure({ Promise: customPromise });
var spy = env.createSpy('foo').and.resolveTo(42);
expect(spy()).toEqual('resolved');
expect(customPromise.resolve).toHaveBeenCalledWith(42);
});
});
describe('when withArgs is used without a base strategy', function() {
it('uses the matching strategy', function() {
var spy = env.createSpy('foo');
const spy = env.createSpy('foo');
spy.withArgs('baz').and.returnValue(-1);
expect(spy('baz')).toEqual(-1);
});
it("throws if the args don't match", function() {
var spy = env.createSpy('foo');
const spy = env.createSpy('foo');
spy.withArgs('bar').and.returnValue(-1);
expect(function() {

View File

@@ -1,18 +1,18 @@
describe('SpyStrategy', function() {
it('defaults its name to unknown', function() {
var spyStrategy = new jasmineUnderTest.SpyStrategy();
const spyStrategy = new jasmineUnderTest.SpyStrategy();
expect(spyStrategy.identity).toEqual('unknown');
});
it('takes a name', function() {
var spyStrategy = new jasmineUnderTest.SpyStrategy({ name: 'foo' });
const spyStrategy = new jasmineUnderTest.SpyStrategy({ name: 'foo' });
expect(spyStrategy.identity).toEqual('foo');
});
it('stubs an original function, if provided', function() {
var originalFn = jasmine.createSpy('original'),
const originalFn = jasmine.createSpy('original'),
spyStrategy = new jasmineUnderTest.SpyStrategy({ fn: originalFn });
spyStrategy.exec();
@@ -21,12 +21,11 @@ describe('SpyStrategy', function() {
});
it("allows an original function to be called, passed through the params and returns it's value", function() {
var originalFn = jasmine.createSpy('original').and.returnValue(42),
spyStrategy = new jasmineUnderTest.SpyStrategy({ fn: originalFn }),
returnValue;
const originalFn = jasmine.createSpy('original').and.returnValue(42),
spyStrategy = new jasmineUnderTest.SpyStrategy({ fn: originalFn });
spyStrategy.callThrough();
returnValue = spyStrategy.exec(null, ['foo']);
const returnValue = spyStrategy.exec(null, ['foo']);
expect(originalFn).toHaveBeenCalled();
expect(originalFn.calls.mostRecent().args).toEqual(['foo']);
@@ -34,19 +33,18 @@ describe('SpyStrategy', function() {
});
it('can return a specified value when executed', function() {
var originalFn = jasmine.createSpy('original'),
spyStrategy = new jasmineUnderTest.SpyStrategy({ fn: originalFn }),
returnValue;
const originalFn = jasmine.createSpy('original'),
spyStrategy = new jasmineUnderTest.SpyStrategy({ fn: originalFn });
spyStrategy.returnValue(17);
returnValue = spyStrategy.exec();
const returnValue = spyStrategy.exec();
expect(originalFn).not.toHaveBeenCalled();
expect(returnValue).toEqual(17);
});
it('can return specified values in order specified when executed', function() {
var originalFn = jasmine.createSpy('original'),
const originalFn = jasmine.createSpy('original'),
spyStrategy = new jasmineUnderTest.SpyStrategy({ fn: originalFn });
spyStrategy.returnValues('value1', 'value2', 'value3');
@@ -59,7 +57,7 @@ describe('SpyStrategy', function() {
});
it('allows an exception to be thrown when executed', function() {
var originalFn = jasmine.createSpy('original'),
const originalFn = jasmine.createSpy('original'),
spyStrategy = new jasmineUnderTest.SpyStrategy({ fn: originalFn });
spyStrategy.throwError(new TypeError('bar'));
@@ -71,7 +69,7 @@ describe('SpyStrategy', function() {
});
it('allows a string to be thrown, wrapping it into an exception when executed', function() {
var originalFn = jasmine.createSpy('original'),
const originalFn = jasmine.createSpy('original'),
spyStrategy = new jasmineUnderTest.SpyStrategy({ fn: originalFn });
spyStrategy.throwError('bar');
@@ -83,7 +81,7 @@ describe('SpyStrategy', function() {
});
it('allows a non-Error to be thrown when executed', function() {
var originalFn = jasmine.createSpy('original'),
const originalFn = jasmine.createSpy('original'),
spyStrategy = new jasmineUnderTest.SpyStrategy({ fn: originalFn });
spyStrategy.throwError({ code: 'ESRCH' });
@@ -95,24 +93,22 @@ describe('SpyStrategy', function() {
});
it('allows a fake function to be called instead', function() {
var originalFn = jasmine.createSpy('original'),
const originalFn = jasmine.createSpy('original'),
fakeFn = jasmine.createSpy('fake').and.returnValue(67),
spyStrategy = new jasmineUnderTest.SpyStrategy({ fn: originalFn }),
returnValue;
spyStrategy = new jasmineUnderTest.SpyStrategy({ fn: originalFn });
spyStrategy.callFake(fakeFn);
returnValue = spyStrategy.exec();
const returnValue = spyStrategy.exec();
expect(originalFn).not.toHaveBeenCalled();
expect(returnValue).toEqual(67);
});
it('allows a fake async function to be called instead', function(done) {
jasmine.getEnv().requireAsyncAwait();
var originalFn = jasmine.createSpy('original'),
fakeFn = jasmine
.createSpy('fake')
.and.callFake(eval('async () => { return 67; }')),
const originalFn = jasmine.createSpy('original'),
fakeFn = jasmine.createSpy('fake').and.callFake(async () => {
return 67;
}),
spyStrategy = new jasmineUnderTest.SpyStrategy({ fn: originalFn });
spyStrategy.callFake(fakeFn);
@@ -131,15 +127,9 @@ describe('SpyStrategy', function() {
describe('#resolveTo', function() {
it('allows a resolved promise to be returned', function(done) {
jasmine.getEnv().requirePromises();
var originalFn = jasmine.createSpy('original'),
getPromise = function() {
return Promise;
},
const originalFn = jasmine.createSpy('original'),
spyStrategy = new jasmineUnderTest.SpyStrategy({
fn: originalFn,
getPromise: getPromise
fn: originalFn
});
spyStrategy.resolveTo(37);
@@ -153,15 +143,9 @@ describe('SpyStrategy', function() {
});
it('allows an empty resolved promise to be returned', function(done) {
jasmine.getEnv().requirePromises();
var originalFn = jasmine.createSpy('original'),
getPromise = function() {
return Promise;
},
const originalFn = jasmine.createSpy('original'),
spyStrategy = new jasmineUnderTest.SpyStrategy({
fn: originalFn,
getPromise: getPromise
fn: originalFn
});
spyStrategy.resolveTo();
@@ -173,30 +157,13 @@ describe('SpyStrategy', function() {
})
.catch(done.fail);
});
it('fails if promises are not available', function() {
var originalFn = jasmine.createSpy('original'),
spyStrategy = new jasmineUnderTest.SpyStrategy({ fn: originalFn });
expect(function() {
spyStrategy.resolveTo(37);
}).toThrowError(
'resolveTo requires global Promise, or `Promise` configured with `jasmine.getEnv().configure()`'
);
});
});
describe('#rejectWith', function() {
it('allows a rejected promise to be returned', function(done) {
jasmine.getEnv().requirePromises();
var originalFn = jasmine.createSpy('original'),
getPromise = function() {
return Promise;
},
const originalFn = jasmine.createSpy('original'),
spyStrategy = new jasmineUnderTest.SpyStrategy({
fn: originalFn,
getPromise: getPromise
fn: originalFn
});
spyStrategy.rejectWith(new Error('oops'));
@@ -211,15 +178,9 @@ describe('SpyStrategy', function() {
});
it('allows an empty rejected promise to be returned', function(done) {
jasmine.getEnv().requirePromises();
var originalFn = jasmine.createSpy('original'),
getPromise = function() {
return Promise;
},
const originalFn = jasmine.createSpy('original'),
spyStrategy = new jasmineUnderTest.SpyStrategy({
fn: originalFn,
getPromise: getPromise
fn: originalFn
});
spyStrategy.rejectWith();
@@ -234,15 +195,9 @@ describe('SpyStrategy', function() {
});
it('allows a non-Error to be rejected', function(done) {
jasmine.getEnv().requirePromises();
var originalFn = jasmine.createSpy('original'),
getPromise = function() {
return Promise;
},
const originalFn = jasmine.createSpy('original'),
spyStrategy = new jasmineUnderTest.SpyStrategy({
fn: originalFn,
getPromise: getPromise
fn: originalFn
});
spyStrategy.rejectWith('oops');
@@ -255,21 +210,10 @@ describe('SpyStrategy', function() {
})
.catch(done.fail);
});
it('fails if promises are not available', function() {
var originalFn = jasmine.createSpy('original'),
spyStrategy = new jasmineUnderTest.SpyStrategy({ fn: originalFn });
expect(function() {
spyStrategy.rejectWith(new Error('oops'));
}).toThrowError(
'rejectWith requires global Promise, or `Promise` configured with `jasmine.getEnv().configure()`'
);
});
});
it('allows a custom strategy to be used', function() {
var plan = jasmine
const plan = jasmine
.createSpy('custom strategy')
.and.returnValue('custom strategy result'),
customStrategy = jasmine
@@ -292,7 +236,7 @@ describe('SpyStrategy', function() {
});
it("throws an error if a custom strategy doesn't return a function", function() {
var originalFn = jasmine.createSpy('original'),
const originalFn = jasmine.createSpy('original'),
spyStrategy = new jasmineUnderTest.SpyStrategy({
fn: originalFn,
customStrategies: {
@@ -308,7 +252,7 @@ describe('SpyStrategy', function() {
});
it('does not allow custom strategies to overwrite existing methods', function() {
var spyStrategy = new jasmineUnderTest.SpyStrategy({
const spyStrategy = new jasmineUnderTest.SpyStrategy({
fn: function() {},
customStrategies: {
exec: function() {}
@@ -319,7 +263,7 @@ describe('SpyStrategy', function() {
});
it('throws an error when a non-function is passed to callFake strategy', function() {
var originalFn = jasmine.createSpy('original'),
const originalFn = jasmine.createSpy('original'),
spyStrategy = new jasmineUnderTest.SpyStrategy({ fn: originalFn });
spyOn(jasmineUnderTest, 'isFunction_').and.returnValue(false);
@@ -335,9 +279,9 @@ describe('SpyStrategy', function() {
});
it('allows generator functions to be passed to callFake strategy', function() {
jasmine.getEnv().requireGeneratorFunctions();
var generator = jasmine.getEnv().makeGeneratorFunction('yield "ok";'),
const generator = function*() {
yield 'ok';
},
spyStrategy = new jasmineUnderTest.SpyStrategy({ fn: function() {} });
spyStrategy.callFake(generator);
@@ -346,13 +290,12 @@ describe('SpyStrategy', function() {
});
it('allows a return to plan stubbing after another strategy', function() {
var originalFn = jasmine.createSpy('original'),
const originalFn = jasmine.createSpy('original'),
fakeFn = jasmine.createSpy('fake').and.returnValue(67),
spyStrategy = new jasmineUnderTest.SpyStrategy({ fn: originalFn }),
returnValue;
spyStrategy = new jasmineUnderTest.SpyStrategy({ fn: originalFn });
spyStrategy.callFake(fakeFn);
returnValue = spyStrategy.exec();
let returnValue = spyStrategy.exec();
expect(originalFn).not.toHaveBeenCalled();
expect(returnValue).toEqual(67);
@@ -364,7 +307,7 @@ describe('SpyStrategy', function() {
});
it('returns the spy after changing the strategy', function() {
var spy = {},
const spy = {},
spyFn = jasmine.createSpy('spyFn').and.returnValue(spy),
spyStrategy = new jasmineUnderTest.SpyStrategy({ getSpy: spyFn });

View File

@@ -1,6 +1,6 @@
describe('StackTrace', function() {
it('understands Chrome/IE/Edge style traces', function() {
var error = {
it('understands Chrome/Edge style traces', function() {
const error = {
message: 'nope',
stack:
'Error: nope\n' +
@@ -8,7 +8,7 @@ describe('StackTrace', function() {
' at QueueRunner.run (http://localhost:8888/__jasmine__/jasmine.js:4320:20)'
};
var result = new jasmineUnderTest.StackTrace(error);
const result = new jasmineUnderTest.StackTrace(error);
expect(result.message).toEqual('Error: nope');
expect(result.style).toEqual('v8');
@@ -30,8 +30,8 @@ describe('StackTrace', function() {
]);
});
it('understands Chrome/IE/Edge style traces with multiline messages', function() {
var error = {
it('understands Chrome/Edge style traces with multiline messages', function() {
const error = {
message: 'line 1\nline 2',
stack:
'Error: line 1\nline 2\n' +
@@ -39,10 +39,10 @@ describe('StackTrace', function() {
' at QueueRunner.run (http://localhost:8888/__jasmine__/jasmine.js:4320:20)'
};
var result = new jasmineUnderTest.StackTrace(error);
const result = new jasmineUnderTest.StackTrace(error);
expect(result.message).toEqual('Error: line 1\nline 2');
var rawFrames = result.frames.map(function(f) {
const rawFrames = result.frames.map(function(f) {
return f.raw;
});
expect(rawFrames).toEqual([
@@ -52,7 +52,7 @@ describe('StackTrace', function() {
});
it('understands Node style traces', function() {
var error = {
const error = {
message: 'nope',
stack:
'Error\n' +
@@ -61,7 +61,7 @@ describe('StackTrace', function() {
' at Immediate.<anonymous> (/somewhere/jasmine/lib/jasmine-core/jasmine.js:4314:12)\n' +
' at runCallback (timers.js:672:20)'
};
var result = new jasmineUnderTest.StackTrace(error);
const result = new jasmineUnderTest.StackTrace(error);
expect(result.message).toEqual('Error');
expect(result.style).toEqual('v8');
@@ -95,14 +95,14 @@ describe('StackTrace', function() {
]);
});
it('understands Safari/Firefox/Phantom-OS X style traces', function() {
var error = {
it('understands Safari <=14/Firefox/Phantom-OS X style traces', function() {
const error = {
message: 'nope',
stack:
'http://localhost:8888/__spec__/core/UtilSpec.js:115:28\n' +
'run@http://localhost:8888/__jasmine__/jasmine.js:4320:27'
};
var result = new jasmineUnderTest.StackTrace(error);
const result = new jasmineUnderTest.StackTrace(error);
expect(result.message).toBeFalsy();
expect(result.style).toEqual('webkit');
@@ -122,25 +122,52 @@ describe('StackTrace', function() {
]);
});
it('understands Safari 15 style traces', function() {
const error = {
message: 'nope',
stack:
'@http://localhost:8888/__spec__/core/FooSpec.js:164:24\n' +
'attempt@http://localhost:8888/__jasmine__/jasmine.js:8074:44\n'
};
const result = new jasmineUnderTest.StackTrace(error);
expect(result.message).toBeFalsy();
expect(result.style).toEqual('webkit');
expect(result.frames).toEqual([
{
raw: '@http://localhost:8888/__spec__/core/FooSpec.js:164:24',
func: undefined,
file: 'http://localhost:8888/__spec__/core/FooSpec.js',
line: 164
},
{
raw: 'attempt@http://localhost:8888/__jasmine__/jasmine.js:8074:44',
func: 'attempt',
file: 'http://localhost:8888/__jasmine__/jasmine.js',
line: 8074
}
]);
});
it('does not mistake gibberish for Safari/Firefox/Phantom-OS X style traces', function() {
var error = {
const error = {
message: 'nope',
stack: 'randomcharsnotincludingwhitespace'
};
var result = new jasmineUnderTest.StackTrace(error);
const result = new jasmineUnderTest.StackTrace(error);
expect(result.style).toBeNull();
expect(result.frames).toEqual([{ raw: error.stack }]);
});
it('understands Phantom-Linux style traces', function() {
var error = {
const error = {
message: 'nope',
stack:
' at UserContext.<anonymous> (http://localhost:8888/__spec__/core/UtilSpec.js:115:19)\n' +
' at QueueRunner.run (http://localhost:8888/__jasmine__/jasmine.js:4320:20)'
};
var result = new jasmineUnderTest.StackTrace(error);
const result = new jasmineUnderTest.StackTrace(error);
expect(result.message).toBeFalsy();
expect(result.style).toEqual('v8');
@@ -163,13 +190,13 @@ describe('StackTrace', function() {
});
it('ignores blank lines', function() {
var error = {
const error = {
message: 'nope',
stack:
' at UserContext.<anonymous> (http://localhost:8888/__spec__/core/UtilSpec.js:115:19)\n'
};
var result = new jasmineUnderTest.StackTrace(error);
const result = new jasmineUnderTest.StackTrace(error);
expect(result.frames).toEqual([
{
@@ -183,7 +210,7 @@ describe('StackTrace', function() {
});
it("omits properties except 'raw' for frames that are not understood", function() {
var error = {
const error = {
message: 'nope',
stack:
' at UserContext.<anonymous> (http://localhost:8888/__spec__/core/UtilSpec.js:115:19)\n' +
@@ -191,7 +218,7 @@ describe('StackTrace', function() {
' at QueueRunner.run (http://localhost:8888/__jasmine__/jasmine.js:4320:20)'
};
var result = new jasmineUnderTest.StackTrace(error);
const result = new jasmineUnderTest.StackTrace(error);
expect(result.style).toEqual('v8');
expect(result.frames).toEqual([
{
@@ -215,7 +242,7 @@ describe('StackTrace', function() {
});
it('consideres different types of errors', function() {
var error = {
const error = {
message: 'nope',
stack:
'TypeError: nope\n' +
@@ -223,7 +250,7 @@ describe('StackTrace', function() {
' at QueueRunner.run (http://localhost:8888/__jasmine__/jasmine.js:4320:20)'
};
var result = new jasmineUnderTest.StackTrace(error);
const result = new jasmineUnderTest.StackTrace(error);
expect(result.message).toEqual('TypeError: nope');
expect(result.frames).toEqual([
@@ -243,7 +270,7 @@ describe('StackTrace', function() {
}
]);
var no_error = {
const no_error = {
message: 'nope',
stack:
'Type Error: nope\n' +
@@ -251,7 +278,7 @@ describe('StackTrace', function() {
' at QueueRunner.run (http://localhost:8888/__jasmine__/jasmine.js:4320:20)'
};
var result_no_error = new jasmineUnderTest.StackTrace(no_error);
const result_no_error = new jasmineUnderTest.StackTrace(no_error);
expect(result_no_error.message).not.toEqual(jasmine.anything());
});

View File

@@ -0,0 +1,265 @@
describe('SuiteBuilder', function() {
beforeEach(function() {
// Rethrow exceptions to ease debugging
spyOn(jasmineUnderTest.Suite.prototype, 'handleException').and.callFake(
function(e) {
throw e;
}
);
spyOn(jasmineUnderTest.Spec.prototype, 'handleException').and.callFake(
function(e) {
throw e;
}
);
});
it('creates the top suite', function() {
const env = { configuration: () => ({}) };
const suiteBuilder = new jasmineUnderTest.SuiteBuilder({ env });
expect(suiteBuilder.topSuite).toBeInstanceOf(jasmineUnderTest.Suite);
expect(suiteBuilder.topSuite.description).toEqual(
'Jasmine__TopLevel__Suite'
);
expect(suiteBuilder.topSuite.parentSuite).toBeUndefined();
});
describe('#describe', function() {
definesSuites('describe');
});
describe('#fdescribe', function() {
definesSuites('fdescribe');
it('focuses the suite', function() {
const env = { configuration: () => ({}) };
const suiteBuilder = new jasmineUnderTest.SuiteBuilder({ env });
const suite = suiteBuilder.fdescribe('a suite', function() {
suiteBuilder.it('a spec');
});
expect(suite.isFocused).toBeTrue();
expect(suiteBuilder.focusedRunables).toEqual([suite.id]);
});
it('unfocuses any focused ancestor suite', function() {
const env = { configuration: () => ({}) };
const suiteBuilder = new jasmineUnderTest.SuiteBuilder({ env });
const grandparent = suiteBuilder.fdescribe('a suite', function() {
suiteBuilder.describe('another suite', function() {
suiteBuilder.fdescribe('the focused suite', function() {
suiteBuilder.it('a spec');
});
});
});
expect(suiteBuilder.focusedRunables).not.toContain(grandparent.id);
});
});
describe('#xdescribe', function() {
definesSuites('xdescribe');
it('excludes the suite', function() {
const env = { configuration: () => ({}) };
const suiteBuilder = new jasmineUnderTest.SuiteBuilder({ env });
const suite = suiteBuilder.xdescribe('a suite', function() {
suiteBuilder.it('a spec');
});
expect(suite.markedExcluding).toBeTrue();
});
it('causes child suites to be marked excluded', function() {
const env = { configuration: () => ({}) };
const suiteBuilder = new jasmineUnderTest.SuiteBuilder({ env });
let suite;
suiteBuilder.xdescribe('a suite', function() {
suite = suiteBuilder.describe('another suite', function() {
suiteBuilder.it('a spec');
});
});
expect(suite.markedExcluding).toBeTrue();
});
});
describe('#it', function() {
definesSpecs('it');
});
describe('#fit', function() {
definesSpecs('fit');
});
describe('#xit', function() {
definesSpecs('xit');
});
function definesSuites(fnName) {
it('links suites to their parents and children', function() {
const env = { configuration: () => ({}) };
const suiteBuilder = new jasmineUnderTest.SuiteBuilder({ env });
let child;
const parent = suiteBuilder[fnName]('parent', function() {
child = suiteBuilder[fnName]('child', function() {
suiteBuilder.it('a spec');
});
});
expect(suiteBuilder.topSuite.children).toEqual([sameInstanceAs(parent)]);
expect(parent.children).toEqual([sameInstanceAs(child)]);
expect(child.parentSuite).toBe(parent);
expect(parent.parentSuite).toBe(suiteBuilder.topSuite);
});
it('gives each suite a unique ID', function() {
const env = { configuration: () => ({}) };
const suiteBuilder = new jasmineUnderTest.SuiteBuilder({ env });
let child;
const parent = suiteBuilder[fnName]('parent', function() {
child = suiteBuilder[fnName]('child', function() {
suiteBuilder.it('a spec');
});
});
const ids = [suiteBuilder.topSuite.id, parent.id, child.id];
for (const id of ids) {
expect(id).toMatch(/^suite[0-9]$/);
}
expect(new Set(ids).size).toEqual(3);
});
}
function definesSpecs(fnName) {
it('adds the spec to its suite', function() {
const env = { configuration: () => ({}) };
const suiteBuilder = new jasmineUnderTest.SuiteBuilder({ env });
let spec;
const suite = suiteBuilder.describe('a suite', function() {
spec = suiteBuilder[fnName]('a spec', function() {});
});
expect(suite.children).toEqual([sameInstanceAs(spec)]);
});
it('gives each spec a unique ID', function() {
const env = { configuration: () => ({}) };
const suiteBuilder = new jasmineUnderTest.SuiteBuilder({ env });
const spec1 = suiteBuilder[fnName]('a spec', function() {});
const spec2 = suiteBuilder[fnName]('another spec', function() {});
expect(spec1.id).toMatch(/^spec[0-9]+$/);
expect(spec2.id).toMatch(/^spec[0-9]+$/);
expect(spec1.id).not.toEqual(spec2.id);
});
}
function sameInstanceAs(expected) {
return {
asymmetricMatch: function(actual) {
return actual === expected;
},
jasmineToString: function(pp) {
return '<same instance as ' + pp(expected) + '>';
}
};
}
describe('#parallelReset', function() {
it('resets the top suite result', function() {
jasmineUnderTest.Suite.prototype.handleException.and.callThrough();
const env = { configuration: () => ({}) };
const suiteBuilder = new jasmineUnderTest.SuiteBuilder({ env });
suiteBuilder.topSuite.handleException(new Error('nope'));
suiteBuilder.parallelReset();
expect(suiteBuilder.topSuite.result).toEqual({
id: suiteBuilder.topSuite.id,
description: 'Jasmine__TopLevel__Suite',
fullName: '',
failedExpectations: [],
deprecationWarnings: [],
duration: null,
properties: null,
parentSuiteId: null,
filename: undefined
});
});
it('removes children of the top suite', function() {
const env = { configuration: () => ({}) };
const suiteBuilder = new jasmineUnderTest.SuiteBuilder({ env });
suiteBuilder.describe('a suite', function() {
suiteBuilder.it('a nested spec');
});
suiteBuilder.it('a spec');
suiteBuilder.parallelReset();
expect(suiteBuilder.topSuite.children).toEqual([]);
});
it('preserves top suite befores and afters', function() {
const env = { configuration: () => ({}) };
const suiteBuilder = new jasmineUnderTest.SuiteBuilder({ env });
function beforeAll() {}
function beforeEach() {}
function afterEach() {}
function afterAll() {}
suiteBuilder.beforeAll(beforeAll);
suiteBuilder.beforeEach(beforeEach);
suiteBuilder.afterEach(afterEach);
suiteBuilder.afterAll(afterAll);
suiteBuilder.parallelReset();
expect(suiteBuilder.topSuite.beforeAllFns).toEqual([
jasmine.objectContaining({ fn: beforeAll })
]);
expect(suiteBuilder.topSuite.beforeFns).toEqual([
jasmine.objectContaining({ fn: beforeEach })
]);
expect(suiteBuilder.topSuite.afterFns).toEqual([
jasmine.objectContaining({ fn: afterEach })
]);
expect(suiteBuilder.topSuite.afterAllFns).toEqual([
jasmine.objectContaining({ fn: afterAll })
]);
});
it('resets totalSpecsDefined', function() {
const env = { configuration: () => ({}) };
const suiteBuilder = new jasmineUnderTest.SuiteBuilder({ env });
suiteBuilder.it('a spec');
suiteBuilder.parallelReset();
expect(suiteBuilder.totalSpecsDefined).toEqual(0);
});
it('resets focusedRunables', function() {
const env = { configuration: () => ({}) };
const suiteBuilder = new jasmineUnderTest.SuiteBuilder({ env });
suiteBuilder.fit('a spec', function() {});
suiteBuilder.parallelReset();
expect(suiteBuilder.focusedRunables).toEqual([]);
});
});
});

View File

@@ -1,5 +1,5 @@
describe('Suite', function() {
var env;
let env;
beforeEach(function() {
env = new jasmineUnderTest.Env();
@@ -10,7 +10,7 @@ describe('Suite', function() {
});
it('keeps its id', function() {
var suite = new jasmineUnderTest.Suite({
const suite = new jasmineUnderTest.Suite({
env: env,
id: 456,
description: 'I am a suite'
@@ -20,7 +20,7 @@ describe('Suite', function() {
});
it('returns blank full name for top level suite', function() {
var suite = new jasmineUnderTest.Suite({
const suite = new jasmineUnderTest.Suite({
env: env,
description: 'I am a suite'
});
@@ -29,7 +29,7 @@ describe('Suite', function() {
});
it('returns its full name when it has parent suites', function() {
var parentSuite = new jasmineUnderTest.Suite({
const parentSuite = new jasmineUnderTest.Suite({
env: env,
description: 'I am a parent suite',
parentSuite: jasmine.createSpy('pretend top level suite')
@@ -43,84 +43,202 @@ describe('Suite', function() {
expect(suite.getFullName()).toEqual('I am a parent suite I am a suite');
});
it('adds before functions in order of needed execution', function() {
var suite = new jasmineUnderTest.Suite({
it('adds beforeEach functions in order of needed execution', function() {
const suite = new jasmineUnderTest.Suite({
env: env,
description: 'I am a suite'
}),
outerBefore = jasmine.createSpy('outerBeforeEach'),
innerBefore = jasmine.createSpy('insideBeforeEach');
outerBefore = { fn: 'outerBeforeEach' },
innerBefore = { fn: 'insideBeforeEach' };
suite.beforeEach(outerBefore);
suite.beforeEach(innerBefore);
expect(suite.beforeFns).toEqual([innerBefore, outerBefore]);
expect(suite.beforeFns).toEqual([
{ fn: innerBefore.fn, suite },
{ fn: outerBefore.fn, suite }
]);
});
it('adds after functions in order of needed execution', function() {
var suite = new jasmineUnderTest.Suite({
it('adds beforeAll functions in order of needed execution', function() {
const suite = new jasmineUnderTest.Suite({
env: env,
description: 'I am a suite'
}),
outerAfter = jasmine.createSpy('outerAfterEach'),
innerAfter = jasmine.createSpy('insideAfterEach');
outerBefore = { fn: 'outerBeforeAll' },
innerBefore = { fn: 'insideBeforeAll' };
suite.beforeAll(outerBefore);
suite.beforeAll(innerBefore);
expect(suite.beforeAllFns).toEqual([
{ fn: outerBefore.fn, type: 'beforeAll', suite: jasmine.is(suite) },
{ fn: innerBefore.fn, type: 'beforeAll', suite: jasmine.is(suite) }
]);
});
it('adds afterEach functions in order of needed execution', function() {
const suite = new jasmineUnderTest.Suite({
env: env,
description: 'I am a suite'
}),
outerAfter = { fn: 'outerAfterEach' },
innerAfter = { fn: 'insideAfterEach' };
suite.afterEach(outerAfter);
suite.afterEach(innerAfter);
expect(suite.afterFns).toEqual([innerAfter, outerAfter]);
expect(suite.afterFns).toEqual([
{ fn: innerAfter.fn, suite, type: 'afterEach' },
{ fn: outerAfter.fn, suite, type: 'afterEach' }
]);
});
it('adds afterAll functions in order of needed execution', function() {
const suite = new jasmineUnderTest.Suite({
env: env,
description: 'I am a suite'
}),
outerAfter = { fn: 'outerAfterAll' },
innerAfter = { fn: 'insideAfterAl' };
suite.afterAll(outerAfter);
suite.afterAll(innerAfter);
expect(suite.afterAllFns).toEqual([
{ fn: innerAfter.fn, type: 'afterAll' },
{ fn: outerAfter.fn, type: 'afterAll' }
]);
});
it('has a status of failed if any expectations have failed', function() {
var suite = new jasmineUnderTest.Suite({
expectationResultFactory: function() {
return 'hi';
}
});
const suite = new jasmineUnderTest.Suite({});
suite.addExpectationResult(false);
suite.addExpectationResult(false, {});
expect(suite.status()).toBe('failed');
});
it('retrieves a result with updated status', function() {
var suite = new jasmineUnderTest.Suite({});
const suite = new jasmineUnderTest.Suite({});
expect(suite.getResult().status).toBe('passed');
});
it('retrieves a result with pending status', function() {
var suite = new jasmineUnderTest.Suite({});
const suite = new jasmineUnderTest.Suite({});
suite.pend();
expect(suite.getResult().status).toBe('pending');
});
it('throws an ExpectationFailed when receiving a failed expectation when throwOnExpectationFailure is set', function() {
var suite = new jasmineUnderTest.Suite({
expectationResultFactory: function(data) {
return data;
},
const suite = new jasmineUnderTest.Suite({
throwOnExpectationFailure: true
});
expect(function() {
suite.addExpectationResult(false, 'failed');
suite.addExpectationResult(false, { message: 'failed' });
}).toThrowError(jasmineUnderTest.errors.ExpectationFailed);
expect(suite.status()).toBe('failed');
expect(suite.result.failedExpectations).toEqual(['failed']);
expect(suite.result.failedExpectations).toEqual([
jasmine.objectContaining({ message: 'failed' })
]);
});
it('does not add an additional failure when an expectation fails', function() {
var suite = new jasmineUnderTest.Suite({});
const suite = new jasmineUnderTest.Suite({});
suite.onException(new jasmineUnderTest.errors.ExpectationFailed());
suite.handleException(new jasmineUnderTest.errors.ExpectationFailed());
expect(suite.getResult().failedExpectations).toEqual([]);
});
it('forwards late expectation failures to onLateError', function() {
const onLateError = jasmine.createSpy('onLateError');
const suite = new jasmineUnderTest.Suite({ onLateError });
const data = {
matcherName: '',
passed: false,
expected: '',
actual: '',
error: new Error('nope')
};
suite.reportedDone = true;
suite.addExpectationResult(false, data, true);
expect(onLateError).toHaveBeenCalledWith(
jasmine.objectContaining({
message: jasmine.stringMatching(/^Error: nope/)
})
);
expect(suite.result.failedExpectations).toEqual([]);
});
it('does not forward non-late expectation failures to onLateError', function() {
const onLateError = jasmine.createSpy('onLateError');
const suite = new jasmineUnderTest.Suite({
onLateError
});
const data = {
matcherName: '',
passed: false,
expected: '',
actual: '',
error: new Error('nope')
};
suite.addExpectationResult(false, data, true);
expect(onLateError).not.toHaveBeenCalled();
expect(suite.result.failedExpectations.length).toEqual(1);
});
it('forwards late handleException calls to onLateError', function() {
const onLateError = jasmine.createSpy('onLateError');
const suite = new jasmineUnderTest.Suite({
onLateError
});
const error = new Error('oops');
suite.reportedDone = true;
suite.handleException(error);
expect(onLateError).toHaveBeenCalledWith(
jasmine.objectContaining({
message: jasmine.stringMatching(/^Error: oops/)
})
);
expect(suite.result.failedExpectations).toEqual([]);
});
it('does not forward non-late handleException calls to onLateError', function() {
const onLateError = jasmine.createSpy('onLateError');
const suite = new jasmineUnderTest.Suite({
onLateError
});
const error = new Error('oops');
suite.handleException(error);
expect(onLateError).not.toHaveBeenCalled();
expect(suite.result.failedExpectations.length).toEqual(1);
});
it('clears the reportedDone flag when reset', function() {
const suite = new jasmineUnderTest.Suite({
queueableFn: { fn: function() {} }
});
suite.reportedDone = true;
suite.reset();
expect(suite.reportedDone).toBeFalse();
});
it('calls timer to compute duration', function() {
var suite = new jasmineUnderTest.Suite({
const suite = new jasmineUnderTest.Suite({
env: env,
id: 456,
description: 'I am a suite',
@@ -145,7 +263,7 @@ describe('Suite', function() {
describe('attr.autoCleanClosures', function() {
function arrangeSuite(attrs) {
var suite = new jasmineUnderTest.Suite(attrs);
const suite = new jasmineUnderTest.Suite(attrs);
suite.beforeAll(function() {});
suite.beforeEach(function() {});
suite.afterEach(function() {});
@@ -154,7 +272,7 @@ describe('Suite', function() {
}
it('should clean closures when "attr.autoCleanClosures" is missing', function() {
var suite = arrangeSuite({});
const suite = arrangeSuite({});
suite.cleanupBeforeAfter();
expect(suite.beforeAllFns[0].fn).toBe(null);
expect(suite.beforeFns[0].fn).toBe(null);
@@ -163,7 +281,7 @@ describe('Suite', function() {
});
it('should clean closures when "attr.autoCleanClosures" is true', function() {
var suite = arrangeSuite({ autoCleanClosures: true });
const suite = arrangeSuite({ autoCleanClosures: true });
suite.cleanupBeforeAfter();
expect(suite.beforeAllFns[0].fn).toBe(null);
expect(suite.beforeFns[0].fn).toBe(null);
@@ -172,7 +290,7 @@ describe('Suite', function() {
});
it('should NOT clean closures when "attr.autoCleanClosures" is false', function() {
var suite = arrangeSuite({ autoCleanClosures: false });
const suite = arrangeSuite({ autoCleanClosures: false });
suite.cleanupBeforeAfter();
expect(suite.beforeAllFns[0].fn).not.toBe(null);
expect(suite.beforeFns[0].fn).not.toBe(null);
@@ -183,23 +301,23 @@ describe('Suite', function() {
describe('#reset', function() {
it('should reset the "pending" status', function() {
var suite = new jasmineUnderTest.Suite({});
const 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({});
const 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']);
const suite = new jasmineUnderTest.Suite({});
const child1 = jasmine.createSpyObj(['reset']);
const child2 = jasmine.createSpyObj(['reset']);
suite.addChild(child1);
suite.addChild(child2);
@@ -210,18 +328,54 @@ describe('Suite', function() {
});
it('should reset the failedExpectations', function() {
var suite = new jasmineUnderTest.Suite({
expectationResultFactory: function(error) {
return error;
}
});
suite.onException(new Error());
const suite = new jasmineUnderTest.Suite({});
suite.handleException(new Error());
suite.reset();
var result = suite.getResult();
const result = suite.getResult();
expect(result.status).toBe('passed');
expect(result.failedExpectations).toHaveSize(0);
});
});
describe('#onMultipleDone', function() {
it('reports a special error when it is the top suite', function() {
const onLateError = jasmine.createSpy('onLateError');
const suite = new jasmineUnderTest.Suite({
onLateError,
parentSuite: null
});
suite.onMultipleDone();
expect(onLateError).toHaveBeenCalledTimes(1);
expect(onLateError.calls.argsFor(0)[0]).toBeInstanceOf(Error);
expect(onLateError.calls.argsFor(0)[0].message).toEqual(
'A top-level beforeAll or afterAll function called its ' +
"'done' callback more than once."
);
});
it('reports an error including the suite name when it is a normal suite', function() {
const onLateError = jasmine.createSpy('onLateError');
const suite = new jasmineUnderTest.Suite({
onLateError,
description: 'the suite',
parentSuite: {
description: 'the parent suite',
parentSuite: {}
}
});
suite.onMultipleDone();
expect(onLateError).toHaveBeenCalledTimes(1);
expect(onLateError.calls.argsFor(0)[0]).toBeInstanceOf(Error);
expect(onLateError.calls.argsFor(0)[0].message).toEqual(
"An asynchronous beforeAll or afterAll function called its 'done' " +
'callback more than once.\n(in suite: the parent suite the suite)'
);
});
});
});

View File

@@ -1,6 +1,6 @@
describe('Timer', function() {
it('reports the time elapsed', function() {
var fakeNow = jasmine.createSpy('fake Date.now'),
const fakeNow = jasmine.createSpy('fake Date.now'),
timer = new jasmineUnderTest.Timer({ now: fakeNow });
fakeNow.and.returnValue(100);
@@ -12,17 +12,19 @@ describe('Timer', function() {
});
describe('when date is stubbed, perhaps by other testing helpers', function() {
var origDate = Date;
const origDate = Date;
beforeEach(function() {
// eslint-disable-next-line no-implicit-globals
Date = jasmine.createSpy('date spy');
});
afterEach(function() {
// eslint-disable-next-line no-implicit-globals
Date = origDate;
});
it('does not throw even though Date was taken away', function() {
var timer = new jasmineUnderTest.Timer();
const timer = new jasmineUnderTest.Timer();
expect(timer.start).not.toThrow();
expect(timer.elapsed()).toEqual(jasmine.any(Number));

View File

@@ -1,5 +1,5 @@
describe('TreeProcessor', function() {
var nodeNumber = 0,
let nodeNumber = 0,
leafNumber = 0;
function Node(attrs) {
@@ -27,7 +27,7 @@ describe('TreeProcessor', function() {
}
it('processes a single leaf', function() {
var leaf = new Leaf(),
const leaf = new Leaf(),
processor = new jasmineUnderTest.TreeProcessor({
tree: leaf,
runnableIds: [leaf.id]
@@ -44,7 +44,7 @@ describe('TreeProcessor', function() {
});
it('processes a single pending leaf', function() {
var leaf = new Leaf({ markedPending: true }),
const leaf = new Leaf({ markedPending: true }),
processor = new jasmineUnderTest.TreeProcessor({
tree: leaf,
runnableIds: [leaf.id]
@@ -61,7 +61,7 @@ describe('TreeProcessor', function() {
});
it('processes a single non-specified leaf', function() {
var leaf = new Leaf(),
const leaf = new Leaf(),
processor = new jasmineUnderTest.TreeProcessor({
tree: leaf,
runnableIds: []
@@ -78,11 +78,11 @@ describe('TreeProcessor', function() {
});
it('processes a single excluded leaf', function() {
var leaf = new Leaf(),
const leaf = new Leaf(),
processor = new jasmineUnderTest.TreeProcessor({
tree: leaf,
runnableIds: [leaf.id],
excludeNode: function(node) {
excludeNode: function() {
return true;
}
}),
@@ -98,7 +98,7 @@ describe('TreeProcessor', function() {
});
it('processes a tree with a single leaf with the root specified', function() {
var leaf = new Leaf(),
const leaf = new Leaf(),
parent = new Node({ children: [leaf] }),
processor = new jasmineUnderTest.TreeProcessor({
tree: parent,
@@ -122,7 +122,7 @@ describe('TreeProcessor', function() {
});
it('processes a tree with a single pending leaf, with the root specified', function() {
var leaf = new Leaf({ markedPending: true }),
const leaf = new Leaf({ markedPending: true }),
parent = new Node({ children: [leaf] }),
processor = new jasmineUnderTest.TreeProcessor({
tree: parent,
@@ -146,7 +146,7 @@ describe('TreeProcessor', function() {
});
it('processes a complicated tree with the root specified', function() {
var pendingLeaf = new Leaf({ markedPending: true }),
const pendingLeaf = new Leaf({ markedPending: true }),
executableLeaf = new Leaf({ markedPending: false }),
parent = new Node({ children: [pendingLeaf, executableLeaf] }),
childless = new Node(),
@@ -218,7 +218,7 @@ describe('TreeProcessor', function() {
});
it('marks the run order invalid if it would re-enter a node that does not allow re-entry', function() {
var leaf1 = new Leaf(),
const leaf1 = new Leaf(),
leaf2 = new Leaf(),
leaf3 = new Leaf(),
reentered = new Node({ noReenter: true, children: [leaf1, leaf2] }),
@@ -233,7 +233,7 @@ describe('TreeProcessor', function() {
});
it('marks the run order valid if a node being re-entered allows re-entry', function() {
var leaf1 = new Leaf(),
const leaf1 = new Leaf(),
leaf2 = new Leaf(),
leaf3 = new Leaf(),
reentered = new Node({ children: [leaf1, leaf2] }),
@@ -248,7 +248,7 @@ describe('TreeProcessor', function() {
});
it("marks the run order valid if a node which can't be re-entered is only entered once", function() {
var leaf1 = new Leaf(),
const leaf1 = new Leaf(),
leaf2 = new Leaf(),
leaf3 = new Leaf(),
noReentry = new Node({ noReenter: true }),
@@ -263,7 +263,7 @@ describe('TreeProcessor', function() {
});
it("marks the run order valid if a node which can't be re-entered is run directly", function() {
var noReentry = new Node({ noReenter: true }),
const noReentry = new Node({ noReenter: true }),
root = new Node({ children: [noReentry] }),
processor = new jasmineUnderTest.TreeProcessor({
tree: root,
@@ -274,33 +274,36 @@ describe('TreeProcessor', function() {
expect(result.valid).toBe(true);
});
it('runs a single leaf', function() {
var leaf = new Leaf(),
it('runs a single leaf', async function() {
const leaf = new Leaf(),
node = new Node({ children: [leaf], userContext: { root: 'context' } }),
queueRunner = jasmine.createSpy('queueRunner'),
processor = new jasmineUnderTest.TreeProcessor({
tree: node,
runnableIds: [leaf.id],
queueRunnerFactory: queueRunner
}),
treeComplete = jasmine.createSpy('treeComplete');
});
processor.execute(treeComplete);
const promise = processor.execute();
expect(queueRunner).toHaveBeenCalledWith({
onComplete: treeComplete,
onComplete: jasmine.any(Function),
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');
const queueRunnerArgs = queueRunner.calls.mostRecent().args[0];
queueRunnerArgs.queueableFns[0].fn('foo');
expect(leaf.execute).toHaveBeenCalledWith(queueRunner, 'foo', false, false);
expect(leaf.execute).toHaveBeenCalledWith('foo', false, false);
queueRunnerArgs.onComplete();
await expectAsync(promise).toBeResolvedTo(undefined);
});
it('runs a node with no children', function() {
var node = new Node({ userContext: { node: 'context' } }),
it('runs a node with no children', async function() {
const node = new Node({ userContext: { node: 'context' } }),
root = new Node({ children: [node], userContext: { root: 'context' } }),
nodeStart = jasmine.createSpy('nodeStart'),
nodeComplete = jasmine.createSpy('nodeComplete'),
@@ -312,25 +315,27 @@ describe('TreeProcessor', function() {
nodeComplete: nodeComplete,
queueRunnerFactory: queueRunner
}),
treeComplete = jasmine.createSpy('treeComplete'),
nodeDone = jasmine.createSpy('nodeDone');
processor.execute(treeComplete);
expect(queueRunner).toHaveBeenCalledWith({
onComplete: treeComplete,
onException: jasmine.any(Function),
userContext: { root: 'context' },
queueableFns: [{ fn: jasmine.any(Function) }]
});
queueRunner.calls.mostRecent().args[0].queueableFns[0].fn(nodeDone);
const promise = processor.execute();
expect(queueRunner).toHaveBeenCalledWith({
onComplete: jasmine.any(Function),
onException: jasmine.any(Function),
userContext: { root: 'context' },
queueableFns: [{ fn: jasmine.any(Function) }],
onMultipleDone: null
});
const queueRunnerArgs = queueRunner.calls.mostRecent().args[0];
queueRunnerArgs.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');
@@ -344,10 +349,13 @@ describe('TreeProcessor', function() {
{ my: 'result' },
jasmine.any(Function)
);
queueRunnerArgs.onComplete();
await expectAsync(promise).toBeResolvedTo(undefined);
});
it('runs a node with children', function() {
var leaf1 = new Leaf(),
const leaf1 = new Leaf(),
leaf2 = new Leaf(),
node = new Node({ children: [leaf1, leaf2] }),
root = new Node({ children: [node] }),
@@ -361,21 +369,31 @@ describe('TreeProcessor', function() {
nodeDone = jasmine.createSpy('nodeDone');
processor.execute(treeComplete);
var queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns;
let queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns;
queueableFns[0].fn(nodeDone);
queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns;
expect(queueableFns.length).toBe(3);
queueableFns[1].fn('foo');
expect(leaf1.execute).toHaveBeenCalledWith('foo', false, false);
expect(leaf1.execute).toHaveBeenCalledWith(
queueRunner,
'foo',
false,
false
);
queueableFns[2].fn('bar');
expect(leaf2.execute).toHaveBeenCalledWith('bar', false, false);
expect(leaf2.execute).toHaveBeenCalledWith(
queueRunner,
'bar',
false,
false
);
});
it('cascades errors up the tree', function() {
var leaf = new Leaf(),
const leaf = new Leaf(),
node = new Node({ children: [leaf] }),
root = new Node({ children: [node] }),
queueRunner = jasmine.createSpy('queueRunner'),
@@ -390,14 +408,14 @@ describe('TreeProcessor', function() {
nodeDone = jasmine.createSpy('nodeDone');
processor.execute(treeComplete);
var queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns;
let queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns;
queueableFns[0].fn(nodeDone);
queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns;
expect(queueableFns.length).toBe(2);
queueableFns[1].fn('foo');
expect(leaf.execute).toHaveBeenCalledWith('foo', false, false);
expect(leaf.execute).toHaveBeenCalledWith(queueRunner, 'foo', false, false);
queueRunner.calls.mostRecent().args[0].onComplete('things');
expect(nodeComplete).toHaveBeenCalled();
@@ -406,7 +424,7 @@ describe('TreeProcessor', function() {
});
it('runs an excluded node with leaf', function() {
var leaf1 = new Leaf(),
const leaf1 = new Leaf(),
node = new Node({ children: [leaf1] }),
root = new Node({ children: [node] }),
queueRunner = jasmine.createSpy('queueRunner'),
@@ -423,7 +441,7 @@ describe('TreeProcessor', function() {
nodeDone = jasmine.createSpy('nodeDone');
processor.execute(treeComplete);
var queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns;
let queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns;
queueableFns[0].fn(nodeDone);
queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns;
@@ -433,7 +451,7 @@ describe('TreeProcessor', function() {
expect(nodeStart).toHaveBeenCalledWith(node, 'bar');
queueableFns[1].fn('foo');
expect(leaf1.execute).toHaveBeenCalledWith('foo', true, false);
expect(leaf1.execute).toHaveBeenCalledWith(queueRunner, 'foo', true, false);
node.getResult.and.returnValue({ im: 'disabled' });
@@ -446,7 +464,7 @@ describe('TreeProcessor', function() {
});
it('should execute node with correct arguments when failSpecWithNoExpectations option is set', function() {
var leaf = new Leaf(),
const leaf = new Leaf(),
node = new Node({ children: [leaf] }),
root = new Node({ children: [node] }),
queueRunner = jasmine.createSpy('queueRunner'),
@@ -464,21 +482,24 @@ describe('TreeProcessor', function() {
nodeDone = jasmine.createSpy('nodeDone');
processor.execute(treeComplete);
var queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns;
let queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns;
queueableFns[0].fn(nodeDone);
queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns;
expect(queueableFns.length).toBe(2);
queueableFns[1].fn('foo');
expect(leaf.execute).toHaveBeenCalledWith('foo', true, true);
expect(leaf.execute).toHaveBeenCalledWith(queueRunner, 'foo', true, true);
});
it('runs beforeAlls for a node with children', function() {
var leaf = new Leaf(),
const leaf = new Leaf(),
node = new Node({
children: [leaf],
beforeAllFns: ['beforeAll1', 'beforeAll2']
beforeAllFns: [
{ fn: 'beforeAll1', timeout: 1 },
{ fn: 'beforeAll2', timeout: 2 }
]
}),
root = new Node({ children: [node] }),
queueRunner = jasmine.createSpy('queueRunner'),
@@ -491,24 +512,25 @@ describe('TreeProcessor', function() {
nodeDone = jasmine.createSpy('nodeDone');
processor.execute(treeComplete);
var queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns;
let queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns;
queueableFns[0].fn(nodeDone);
queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns;
expect(queueableFns).toEqual([
{ fn: jasmine.any(Function) },
'beforeAll1',
'beforeAll2',
{ fn: 'beforeAll1', timeout: 1 },
{ fn: 'beforeAll2', timeout: 2 },
{ fn: jasmine.any(Function) }
]);
});
it('runs afterAlls for a node with children', function() {
var leaf = new Leaf(),
const leaf = new Leaf(),
afterAllFns = [{ fn: 'afterAll1' }, { fn: 'afterAll2' }],
node = new Node({
children: [leaf],
afterAllFns: ['afterAll1', 'afterAll2']
afterAllFns
}),
root = new Node({ children: [node] }),
queueRunner = jasmine.createSpy('queueRunner'),
@@ -521,7 +543,7 @@ describe('TreeProcessor', function() {
nodeDone = jasmine.createSpy('nodeDone');
processor.execute(treeComplete);
var queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns;
let queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns;
queueableFns[0].fn(nodeDone);
queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns;
@@ -529,15 +551,15 @@ describe('TreeProcessor', function() {
expect(queueableFns).toEqual([
{ fn: jasmine.any(Function) },
{ fn: jasmine.any(Function) },
'afterAll1',
'afterAll2'
afterAllFns[0],
afterAllFns[1]
]);
});
it('does not run beforeAlls or afterAlls for a node with no children', function() {
var node = new Node({
beforeAllFns: ['before'],
afterAllFns: ['after']
const node = new Node({
beforeAllFns: [{ fn: 'before' }],
afterAllFns: [{ fn: 'after' }]
}),
root = new Node({ children: [node] }),
queueRunner = jasmine.createSpy('queueRunner'),
@@ -550,7 +572,7 @@ describe('TreeProcessor', function() {
nodeDone = jasmine.createSpy('nodeDone');
processor.execute(treeComplete);
var queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns;
let queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns;
queueableFns[0].fn(nodeDone);
queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns;
@@ -559,11 +581,11 @@ describe('TreeProcessor', function() {
});
it('does not run beforeAlls or afterAlls for a node with only pending children', function() {
var leaf = new Leaf({ markedPending: true }),
const leaf = new Leaf({ markedPending: true }),
node = new Node({
children: [leaf],
beforeAllFns: ['before'],
afterAllFns: ['after'],
beforeAllFns: [{ fn: 'before' }],
afterAllFns: [{ fn: 'after' }],
markedPending: false
}),
root = new Node({ children: [node] }),
@@ -577,7 +599,7 @@ describe('TreeProcessor', function() {
nodeDone = jasmine.createSpy('nodeDone');
processor.execute(treeComplete);
var queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns;
let queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns;
queueableFns[0].fn(nodeDone);
queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns;
@@ -589,7 +611,7 @@ describe('TreeProcessor', function() {
});
it('runs leaves in the order specified', function() {
var leaf1 = new Leaf(),
const leaf1 = new Leaf(),
leaf2 = new Leaf(),
root = new Node({ children: [leaf1, leaf2] }),
queueRunner = jasmine.createSpy('queueRunner'),
@@ -601,7 +623,7 @@ describe('TreeProcessor', function() {
treeComplete = jasmine.createSpy('treeComplete');
processor.execute(treeComplete);
var queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns;
const queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns;
queueableFns[0].fn();
expect(leaf1.execute).not.toHaveBeenCalled();
@@ -613,7 +635,7 @@ describe('TreeProcessor', function() {
});
it('runs specified leaves before non-specified leaves within a parent node', function() {
var specified = new Leaf(),
const specified = new Leaf(),
nonSpecified = new Leaf(),
root = new Node({ children: [nonSpecified, specified] }),
queueRunner = jasmine.createSpy('queueRunner'),
@@ -625,19 +647,29 @@ describe('TreeProcessor', function() {
treeComplete = jasmine.createSpy('treeComplete');
processor.execute(treeComplete);
var queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns;
const queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns;
queueableFns[0].fn();
expect(nonSpecified.execute).not.toHaveBeenCalled();
expect(specified.execute).toHaveBeenCalledWith(undefined, false, false);
expect(specified.execute).toHaveBeenCalledWith(
queueRunner,
undefined,
false,
false
);
queueableFns[1].fn();
expect(nonSpecified.execute).toHaveBeenCalledWith(undefined, true, false);
expect(nonSpecified.execute).toHaveBeenCalledWith(
queueRunner,
undefined,
true,
false
);
});
it('runs nodes and leaves with a specified order', function() {
var specifiedLeaf = new Leaf(),
const specifiedLeaf = new Leaf(),
childLeaf = new Leaf(),
specifiedNode = new Node({ children: [childLeaf] }),
root = new Node({ children: [specifiedLeaf, specifiedNode] }),
@@ -649,11 +681,12 @@ describe('TreeProcessor', function() {
});
processor.execute();
var queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns;
const queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns;
queueableFns[0].fn();
expect(specifiedLeaf.execute).not.toHaveBeenCalled();
var nodeQueueableFns = queueRunner.calls.mostRecent().args[0].queueableFns;
const nodeQueueableFns = queueRunner.calls.mostRecent().args[0]
.queueableFns;
nodeQueueableFns[1].fn();
expect(childLeaf.execute).toHaveBeenCalled();
@@ -664,7 +697,7 @@ describe('TreeProcessor', function() {
});
it('runs a node multiple times if the order specified leaves and re-enters it', function() {
var leaf1 = new Leaf(),
const leaf1 = new Leaf(),
leaf2 = new Leaf(),
leaf3 = new Leaf(),
leaf4 = new Leaf(),
@@ -679,7 +712,7 @@ describe('TreeProcessor', function() {
});
processor.execute();
var queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns;
const queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns;
expect(queueableFns.length).toBe(5);
queueableFns[0].fn();
@@ -707,7 +740,7 @@ describe('TreeProcessor', function() {
});
it('runs a parent of a node with segments correctly', function() {
var leaf1 = new Leaf(),
const leaf1 = new Leaf(),
leaf2 = new Leaf(),
leaf3 = new Leaf(),
leaf4 = new Leaf(),
@@ -723,7 +756,7 @@ describe('TreeProcessor', function() {
});
processor.execute();
var queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns;
const queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns;
expect(queueableFns.length).toBe(5);
queueableFns[0].fn();
@@ -764,7 +797,7 @@ describe('TreeProcessor', function() {
});
it('runs nodes in the order they were declared', function() {
var leaf1 = new Leaf(),
const leaf1 = new Leaf(),
leaf2 = new Leaf(),
leaf3 = new Leaf(),
parent = new Node({ children: [leaf2, leaf3] }),
@@ -777,7 +810,7 @@ describe('TreeProcessor', function() {
});
processor.execute();
var queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns;
const queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns;
expect(queueableFns.length).toBe(2);
queueableFns[0].fn();
@@ -785,7 +818,7 @@ describe('TreeProcessor', function() {
queueableFns[1].fn();
var childFns = queueRunner.calls.mostRecent().args[0].queueableFns;
const childFns = queueRunner.calls.mostRecent().args[0].queueableFns;
expect(childFns.length).toBe(3);
childFns[1].fn();
expect(leaf2.execute).toHaveBeenCalled();
@@ -795,7 +828,7 @@ describe('TreeProcessor', function() {
});
it('runs large segments of nodes in the order they were declared', function() {
var leaf1 = new Leaf(),
const leaf1 = new Leaf(),
leaf2 = new Leaf(),
leaf3 = new Leaf(),
leaf4 = new Leaf(),
@@ -829,7 +862,7 @@ describe('TreeProcessor', function() {
});
processor.execute();
var queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns;
const queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns;
expect(queueableFns.length).toBe(11);
queueableFns[0].fn();
@@ -867,7 +900,7 @@ describe('TreeProcessor', function() {
});
it('runs nodes in a custom order when orderChildren is overridden', function() {
var leaf1 = new Leaf(),
const leaf1 = new Leaf(),
leaf2 = new Leaf(),
leaf3 = new Leaf(),
leaf4 = new Leaf(),
@@ -899,13 +932,13 @@ describe('TreeProcessor', function() {
runnableIds: [root.id],
queueRunnerFactory: queueRunner,
orderChildren: function(node) {
var children = node.children.slice();
const children = node.children.slice();
return children.reverse();
}
});
processor.execute();
var queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns;
const queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns;
expect(queueableFns.length).toBe(11);
queueableFns[0].fn();

Some files were not shown because too many files have changed in this diff Show More