From 81e39156ee7300e66a7c3babef635cbbdbcb2a57 Mon Sep 17 00:00:00 2001 From: wtgtybhertgeghgtwtg Date: Thu, 16 Mar 2017 08:18:29 -0700 Subject: [PATCH 1/8] [jest-jasmine2] Split `jasmine-light` over multiple files. --- packages/jest-jasmine2/src/CallTracker.js | 74 + packages/jest-jasmine2/src/Env.js | 527 +++++ .../jest-jasmine2/src/ExceptionFormatter.js | 54 + .../jest-jasmine2/src/ExpectationFailed.js | 14 + packages/jest-jasmine2/src/JsApiReporter.js | 105 + packages/jest-jasmine2/src/QueueRunner.js | 151 ++ .../jest-jasmine2/src/ReportDispatcher.js | 70 + packages/jest-jasmine2/src/Spec.js | 199 ++ packages/jest-jasmine2/src/SpyRegistry.js | 132 ++ packages/jest-jasmine2/src/SpyStrategy.js | 90 + packages/jest-jasmine2/src/Suite.js | 187 ++ packages/jest-jasmine2/src/Timer.js | 49 + packages/jest-jasmine2/src/TreeProcessor.js | 256 +++ .../src/buildExpectationResult.js | 76 + packages/jest-jasmine2/src/jasmine-light.js | 1790 +---------------- 15 files changed, 2056 insertions(+), 1718 deletions(-) create mode 100644 packages/jest-jasmine2/src/CallTracker.js create mode 100644 packages/jest-jasmine2/src/Env.js create mode 100644 packages/jest-jasmine2/src/ExceptionFormatter.js create mode 100644 packages/jest-jasmine2/src/ExpectationFailed.js create mode 100644 packages/jest-jasmine2/src/JsApiReporter.js create mode 100644 packages/jest-jasmine2/src/QueueRunner.js create mode 100644 packages/jest-jasmine2/src/ReportDispatcher.js create mode 100644 packages/jest-jasmine2/src/Spec.js create mode 100644 packages/jest-jasmine2/src/SpyRegistry.js create mode 100644 packages/jest-jasmine2/src/SpyStrategy.js create mode 100644 packages/jest-jasmine2/src/Suite.js create mode 100644 packages/jest-jasmine2/src/Timer.js create mode 100644 packages/jest-jasmine2/src/TreeProcessor.js create mode 100644 packages/jest-jasmine2/src/buildExpectationResult.js diff --git a/packages/jest-jasmine2/src/CallTracker.js b/packages/jest-jasmine2/src/CallTracker.js new file mode 100644 index 000000000000..3af6ba401239 --- /dev/null +++ b/packages/jest-jasmine2/src/CallTracker.js @@ -0,0 +1,74 @@ +/* +Copyright (c) 2008-2016 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. +*/ +/* eslint-disable sort-keys */ +'use strict'; + +module.exports = function(j$) { + function CallTracker() { + let calls = []; + + this.track = function(context) { + calls.push(context); + }; + + this.any = function() { + return !!calls.length; + }; + + this.count = function() { + return calls.length; + }; + + this.argsFor = function(index) { + const call = calls[index]; + return call ? call.args : []; + }; + + this.all = function() { + return calls; + }; + + this.allArgs = function() { + const callArgs = []; + for (let i = 0; i < calls.length; i++) { + callArgs.push(calls[i].args); + } + + return callArgs; + }; + + this.first = function() { + return calls[0]; + }; + + this.mostRecent = function() { + return calls[calls.length - 1]; + }; + + this.reset = function() { + calls = []; + }; + } + + return CallTracker; +}; diff --git a/packages/jest-jasmine2/src/Env.js b/packages/jest-jasmine2/src/Env.js new file mode 100644 index 000000000000..b611c97fc168 --- /dev/null +++ b/packages/jest-jasmine2/src/Env.js @@ -0,0 +1,527 @@ +/* +Copyright (c) 2008-2016 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. +*/ +/* eslint-disable sort-keys */ +'use strict'; + +module.exports = function(j$) { + function Env(options) { + options = options || {}; + + const self = this; + + let totalSpecsDefined = 0; + + let catchExceptions = true; + + const realSetTimeout = global.setTimeout; + const realClearTimeout = global.clearTimeout; + + const runnableResources = {}; + + let currentSpec = null; + const currentlyExecutingSuites = []; + let currentDeclarationSuite = null; + let throwOnExpectationFailure = false; + let random = false; + let seed = null; + + const currentSuite = function() { + return currentlyExecutingSuites[currentlyExecutingSuites.length - 1]; + }; + + const currentRunnable = function() { + return currentSpec || currentSuite(); + }; + + const reporter = new j$.ReportDispatcher([ + 'jasmineStarted', + 'jasmineDone', + 'suiteStarted', + 'suiteDone', + 'specStarted', + 'specDone', + ]); + + this.specFilter = function() { + return true; + }; + + let nextSpecId = 0; + const getNextSpecId = function() { + return 'spec' + nextSpecId++; + }; + + let nextSuiteId = 0; + const getNextSuiteId = function() { + return 'suite' + nextSuiteId++; + }; + + const expectationFactory = function(actual, spec) { + return j$.Expectation.Factory({ + actual, + addExpectationResult, + }); + + function addExpectationResult(passed, result) { + return spec.addExpectationResult(passed, result); + } + }; + + const defaultResourcesForRunnable = function(id, parentRunnableId) { + const resources = {spies: []}; + + runnableResources[id] = resources; + }; + + const clearResourcesForRunnable = function(id) { + spyRegistry.clearSpies(); + delete runnableResources[id]; + }; + + const beforeAndAfterFns = function(suite) { + return function() { + let afters = []; + let befores = []; + + while (suite) { + befores = befores.concat(suite.beforeFns); + afters = afters.concat(suite.afterFns); + + suite = suite.parentSuite; + } + + return { + befores: befores.reverse(), + afters, + }; + }; + }; + + const getSpecName = function(spec, suite) { + const fullName = [spec.description]; + const suiteFullName = suite.getFullName(); + + if (suiteFullName !== '') { + fullName.unshift(suiteFullName); + } + + return fullName.join(' '); + }; + + const buildExpectationResult = j$.buildExpectationResult; + const exceptionFormatter = new j$.ExceptionFormatter(); + const expectationResultFactory = function(attrs) { + attrs.messageFormatter = exceptionFormatter.message; + attrs.stackFormatter = exceptionFormatter.stack; + + return buildExpectationResult(attrs); + }; + + this.catchExceptions = function(value) { + catchExceptions = !!value; + return catchExceptions; + }; + + this.catchingExceptions = function() { + return catchExceptions; + }; + + const maximumSpecCallbackDepth = 20; + let currentSpecCallbackDepth = 0; + + function clearStack(fn) { + currentSpecCallbackDepth++; + if (currentSpecCallbackDepth >= maximumSpecCallbackDepth) { + currentSpecCallbackDepth = 0; + realSetTimeout(fn, 0); + } else { + fn(); + } + } + + const catchException = function(e) { + return j$.Spec.isPendingSpecException(e) || catchExceptions; + }; + + this.throwOnExpectationFailure = function(value) { + throwOnExpectationFailure = !!value; + }; + + this.throwingExpectationFailures = function() { + return throwOnExpectationFailure; + }; + + this.randomizeTests = function(value) { + random = !!value; + }; + + this.randomTests = function() { + return random; + }; + + this.seed = function(value) { + if (value) { + seed = value; + } + return seed; + }; + + const queueRunnerFactory = function(options) { + options.catchException = catchException; + options.clearStack = options.clearStack || clearStack; + options.timeout = { + setTimeout: realSetTimeout, + clearTimeout: realClearTimeout, + }; + options.fail = self.fail; + + new j$.QueueRunner(options).execute(); + }; + + const topSuite = new j$.Suite({ + env: this, + id: getNextSuiteId(), + description: 'test', + expectationFactory, + expectationResultFactory, + }); + defaultResourcesForRunnable(topSuite.id); + currentDeclarationSuite = topSuite; + + this.topSuite = function() { + return topSuite; + }; + + this.execute = function(runnablesToRun) { + if (!runnablesToRun) { + if (focusedRunnables.length) { + runnablesToRun = focusedRunnables; + } else { + runnablesToRun = [topSuite.id]; + } + } + + const processor = new j$.TreeProcessor({ + tree: topSuite, + runnableIds: runnablesToRun, + queueRunnerFactory, + nodeStart(suite) { + currentlyExecutingSuites.push(suite); + defaultResourcesForRunnable(suite.id, suite.parentSuite.id); + reporter.suiteStarted(suite.result); + }, + nodeComplete(suite, result) { + if (!suite.disabled) { + clearResourcesForRunnable(suite.id); + } + currentlyExecutingSuites.pop(); + reporter.suiteDone(result); + }, + }); + + if (!processor.processTree().valid) { + throw new Error( + 'Invalid order: would cause a beforeAll or afterAll to be ' + + 'run multiple times', + ); + } + + reporter.jasmineStarted({ + totalSpecsDefined, + }); + + currentlyExecutingSuites.push(topSuite); + + processor.execute(() => { + clearResourcesForRunnable(topSuite.id); + currentlyExecutingSuites.pop(); + + reporter.jasmineDone({ + failedExpectations: topSuite.result.failedExpectations, + }); + }); + }; + + this.addReporter = function(reporterToAdd) { + reporter.addReporter(reporterToAdd); + }; + + this.provideFallbackReporter = function(reporterToAdd) { + reporter.provideFallbackReporter(reporterToAdd); + }; + + this.clearReporters = function() { + reporter.clearReporters(); + }; + + const spyRegistry = new j$.SpyRegistry({ + currentSpies() { + if (!currentRunnable()) { + throw new Error( + 'Spies must be created in a before function or a spec', + ); + } + return runnableResources[currentRunnable().id].spies; + }, + }); + + this.allowRespy = function(allow) { + spyRegistry.allowRespy(allow); + }; + + this.spyOn = function() { + return spyRegistry.spyOn.apply(spyRegistry, arguments); + }; + + const suiteFactory = function(description) { + const suite = new j$.Suite({ + env: self, + id: getNextSuiteId(), + description, + parentSuite: currentDeclarationSuite, + expectationFactory, + expectationResultFactory, + throwOnExpectationFailure, + }); + + return suite; + }; + + this.describe = function(description, specDefinitions) { + const suite = suiteFactory(description); + if (specDefinitions.length > 0) { + throw new Error('describe does not expect any arguments'); + } + if (currentDeclarationSuite.markedPending) { + suite.pend(); + } + addSpecsToSuite(suite, specDefinitions); + return suite; + }; + + this.xdescribe = function(description, specDefinitions) { + const suite = suiteFactory(description); + suite.pend(); + addSpecsToSuite(suite, specDefinitions); + return suite; + }; + + const focusedRunnables = []; + + this.fdescribe = function(description, specDefinitions) { + const suite = suiteFactory(description); + suite.isFocused = true; + + focusedRunnables.push(suite.id); + unfocusAncestor(); + addSpecsToSuite(suite, specDefinitions); + + return suite; + }; + + function addSpecsToSuite(suite, specDefinitions) { + const parentSuite = currentDeclarationSuite; + parentSuite.addChild(suite); + currentDeclarationSuite = suite; + + let declarationError = null; + try { + specDefinitions.call(suite); + } catch (e) { + declarationError = e; + } + + if (declarationError) { + self.it('encountered a declaration exception', () => { + throw declarationError; + }); + } + + currentDeclarationSuite = parentSuite; + } + + function findFocusedAncestor(suite) { + while (suite) { + if (suite.isFocused) { + return suite.id; + } + suite = suite.parentSuite; + } + + return null; + } + + function unfocusAncestor() { + const focusedAncestor = findFocusedAncestor(currentDeclarationSuite); + if (focusedAncestor) { + for (let i = 0; i < focusedRunnables.length; i++) { + if (focusedRunnables[i] === focusedAncestor) { + focusedRunnables.splice(i, 1); + break; + } + } + } + } + + const specFactory = function(description, fn, suite, timeout) { + totalSpecsDefined++; + const spec = new j$.Spec({ + id: getNextSpecId(), + beforeAndAfterFns: beforeAndAfterFns(suite), + expectationFactory, + resultCallback: specResultCallback, + getSpecName(spec) { + return getSpecName(spec, suite); + }, + onStart: specStarted, + description, + expectationResultFactory, + queueRunnerFactory, + userContext() { + return suite.clonedSharedUserContext(); + }, + queueableFn: { + fn, + timeout() { + return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; + }, + }, + throwOnExpectationFailure, + }); + + if (!self.specFilter(spec)) { + spec.disable(); + } + + return spec; + + function specResultCallback(result) { + clearResourcesForRunnable(spec.id); + currentSpec = null; + reporter.specDone(result); + } + + function specStarted(spec) { + currentSpec = spec; + defaultResourcesForRunnable(spec.id, suite.id); + reporter.specStarted(spec.result); + } + }; + + this.it = function(description, fn, timeout) { + const spec = specFactory( + description, + fn, + currentDeclarationSuite, + timeout, + ); + if (currentDeclarationSuite.markedPending) { + spec.pend(); + } + currentDeclarationSuite.addChild(spec); + return spec; + }; + + this.xit = function() { + const spec = this.it.apply(this, arguments); + spec.pend('Temporarily disabled with xit'); + return spec; + }; + + this.fit = function(description, fn, timeout) { + const spec = specFactory( + description, + fn, + currentDeclarationSuite, + timeout, + ); + currentDeclarationSuite.addChild(spec); + focusedRunnables.push(spec.id); + unfocusAncestor(); + return spec; + }; + + this.beforeEach = function(beforeEachFunction, timeout) { + currentDeclarationSuite.beforeEach({ + fn: beforeEachFunction, + timeout() { + return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; + }, + }); + }; + + this.beforeAll = function(beforeAllFunction, timeout) { + currentDeclarationSuite.beforeAll({ + fn: beforeAllFunction, + timeout() { + return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; + }, + }); + }; + + this.afterEach = function(afterEachFunction, timeout) { + currentDeclarationSuite.afterEach({ + fn: afterEachFunction, + timeout() { + return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; + }, + }); + }; + + this.afterAll = function(afterAllFunction, timeout) { + currentDeclarationSuite.afterAll({ + fn: afterAllFunction, + timeout() { + return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; + }, + }); + }; + + this.pending = function(message) { + let fullMessage = j$.Spec.pendingSpecExceptionMessage; + if (message) { + fullMessage += message; + } + throw fullMessage; + }; + + this.fail = function(error) { + let message = 'Failed'; + if (error) { + message += ': '; + message += error.message || error; + } + + currentRunnable().addExpectationResult(false, { + matcherName: '', + passed: false, + expected: '', + actual: '', + message, + error: error && error.message ? error : null, + }); + }; + } + + return Env; +}; diff --git a/packages/jest-jasmine2/src/ExceptionFormatter.js b/packages/jest-jasmine2/src/ExceptionFormatter.js new file mode 100644 index 000000000000..bff92755db4f --- /dev/null +++ b/packages/jest-jasmine2/src/ExceptionFormatter.js @@ -0,0 +1,54 @@ +/* +Copyright (c) 2008-2016 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. +*/ +/* eslint-disable sort-keys */ +'use strict'; + +module.exports = function() { + function ExceptionFormatter() { + this.message = function(error) { + let message = ''; + + if (error.name && error.message) { + message += error.name + ': ' + error.message; + } else { + message += error.toString() + ' thrown'; + } + + if (error.fileName || error.sourceURL) { + message += ' in ' + (error.fileName || error.sourceURL); + } + + if (error.line || error.lineNumber) { + message += ' (line ' + (error.line || error.lineNumber) + ')'; + } + + return message; + }; + + this.stack = function(error) { + return error ? error.stack : null; + }; + } + + return ExceptionFormatter; +}; diff --git a/packages/jest-jasmine2/src/ExpectationFailed.js b/packages/jest-jasmine2/src/ExpectationFailed.js new file mode 100644 index 000000000000..34b22549bce6 --- /dev/null +++ b/packages/jest-jasmine2/src/ExpectationFailed.js @@ -0,0 +1,14 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @flow + */ +'use strict'; + +class ExpectationFailed extends Error {} + +module.exports = ExpectationFailed; diff --git a/packages/jest-jasmine2/src/JsApiReporter.js b/packages/jest-jasmine2/src/JsApiReporter.js new file mode 100644 index 000000000000..ebb1240e859e --- /dev/null +++ b/packages/jest-jasmine2/src/JsApiReporter.js @@ -0,0 +1,105 @@ +/* +Copyright (c) 2008-2016 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. +*/ +/* eslint-disable sort-keys */ +'use strict'; + +module.exports = function() { + const noopTimer = { + start() {}, + elapsed() { + return 0; + }, + }; + + function JsApiReporter(options) { + const timer = options.timer || noopTimer; + let status = 'loaded'; + + this.started = false; + this.finished = false; + this.runDetails = {}; + + this.jasmineStarted = function() { + this.started = true; + status = 'started'; + timer.start(); + }; + + let executionTime; + + this.jasmineDone = function(runDetails) { + this.finished = true; + this.runDetails = runDetails; + executionTime = timer.elapsed(); + status = 'done'; + }; + + this.status = function() { + return status; + }; + + const suites = []; + const suites_hash = {}; + + this.suiteStarted = function(result) { + suites_hash[result.id] = result; + }; + + this.suiteDone = function(result) { + storeSuite(result); + }; + + this.suiteResults = function(index, length) { + return suites.slice(index, index + length); + }; + + function storeSuite(result) { + suites.push(result); + suites_hash[result.id] = result; + } + + this.suites = function() { + return suites_hash; + }; + + const specs = []; + + this.specDone = function(result) { + specs.push(result); + }; + + this.specResults = function(index, length) { + return specs.slice(index, index + length); + }; + + this.specs = function() { + return specs; + }; + + this.executionTime = function() { + return executionTime; + }; + } + + return JsApiReporter; +}; diff --git a/packages/jest-jasmine2/src/QueueRunner.js b/packages/jest-jasmine2/src/QueueRunner.js new file mode 100644 index 000000000000..409a9e59402e --- /dev/null +++ b/packages/jest-jasmine2/src/QueueRunner.js @@ -0,0 +1,151 @@ +/* +Copyright (c) 2008-2016 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. +*/ +/* eslint-disable sort-keys */ +'use strict'; + +module.exports = function(j$) { + function once(fn) { + let called = false; + return function() { + if (!called) { + called = true; + fn(); + } + return null; + }; + } + + function QueueRunner(attrs) { + this.queueableFns = attrs.queueableFns || []; + this.onComplete = attrs.onComplete || function() {}; + this.clearStack = attrs.clearStack || + function(fn) { + fn(); + }; + this.onException = attrs.onException || function() {}; + this.catchException = attrs.catchException || + function() { + return true; + }; + this.userContext = attrs.userContext || {}; + this.timeout = attrs.timeout || { + setTimeout, + clearTimeout, + }; + this.fail = attrs.fail || function() {}; + } + + QueueRunner.prototype.execute = function() { + this.run(this.queueableFns, 0); + }; + + QueueRunner.prototype.run = function(queueableFns, recursiveIndex) { + const length = queueableFns.length; + const self = this; + let iterativeIndex; + + for ( + iterativeIndex = recursiveIndex; + iterativeIndex < length; + iterativeIndex++ + ) { + const queueableFn = queueableFns[iterativeIndex]; + if (queueableFn.fn.length > 0) { + attemptAsync(queueableFn); + return; + } else { + attemptSync(queueableFn); + } + } + + const runnerDone = iterativeIndex >= length; + + if (runnerDone) { + this.clearStack(this.onComplete); + } + + function attemptSync(queueableFn) { + try { + queueableFn.fn.call(self.userContext); + } catch (e) { + handleException(e, queueableFn); + } + } + + function attemptAsync(queueableFn) { + const clearTimeout = function() { + Function.prototype.apply.apply(self.timeout.clearTimeout, [ + global, + [timeoutId], + ]); + }; + const next = once(() => { + clearTimeout(timeoutId); + self.run(queueableFns, iterativeIndex + 1); + }); + let timeoutId; + + next.fail = function() { + self.fail.apply(null, arguments); + next(); + }; + + if (queueableFn.timeout) { + timeoutId = Function.prototype.apply.apply(self.timeout.setTimeout, [ + global, + [ + function() { + const error = new Error( + 'Timeout - Async callback was not invoked within ' + + 'timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.', + ); + onException(error); + next(); + }, + queueableFn.timeout(), + ], + ]); + } + + try { + queueableFn.fn.call(self.userContext, next); + } catch (e) { + handleException(e, queueableFn); + next(); + } + } + + function onException(e) { + self.onException(e); + } + + function handleException(e, queueableFn) { + onException(e); + if (!self.catchException(e)) { + throw e; + } + } + }; + + return QueueRunner; +}; diff --git a/packages/jest-jasmine2/src/ReportDispatcher.js b/packages/jest-jasmine2/src/ReportDispatcher.js new file mode 100644 index 000000000000..8f71dd76ee81 --- /dev/null +++ b/packages/jest-jasmine2/src/ReportDispatcher.js @@ -0,0 +1,70 @@ +/* +Copyright (c) 2008-2016 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. +*/ +/* eslint-disable sort-keys */ +'use strict'; + +module.exports = function() { + function ReportDispatcher(methods) { + const dispatchedMethods = methods || []; + + for (let i = 0; i < dispatchedMethods.length; i++) { + const method = dispatchedMethods[i]; + this[method] = (function(m) { + return function() { + dispatch(m, arguments); + }; + })(method); + } + + let reporters = []; + let fallbackReporter = null; + + this.addReporter = function(reporter) { + reporters.push(reporter); + }; + + this.provideFallbackReporter = function(reporter) { + fallbackReporter = reporter; + }; + + this.clearReporters = function() { + reporters = []; + }; + + return this; + + function dispatch(method, args) { + if (reporters.length === 0 && fallbackReporter !== null) { + reporters.push(fallbackReporter); + } + for (let i = 0; i < reporters.length; i++) { + const reporter = reporters[i]; + if (reporter[method]) { + reporter[method].apply(reporter, args); + } + } + } + } + + return ReportDispatcher; +}; diff --git a/packages/jest-jasmine2/src/Spec.js b/packages/jest-jasmine2/src/Spec.js new file mode 100644 index 000000000000..c7f110a1f47f --- /dev/null +++ b/packages/jest-jasmine2/src/Spec.js @@ -0,0 +1,199 @@ +/* +Copyright (c) 2008-2016 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. +*/ +/* eslint-disable sort-keys */ +'use strict'; + +const ExpectationFailed = require('./ExpectationFailed'); + +module.exports = function(j$) { + function Spec(attrs) { + this.expectationFactory = attrs.expectationFactory; + this.resultCallback = attrs.resultCallback || function() {}; + this.id = attrs.id; + this.description = attrs.description || ''; + this.queueableFn = attrs.queueableFn; + this.beforeAndAfterFns = attrs.beforeAndAfterFns || + function() { + return {befores: [], afters: []}; + }; + this.userContext = attrs.userContext || + function() { + return {}; + }; + this.onStart = attrs.onStart || function() {}; + this.getSpecName = attrs.getSpecName || + function() { + return ''; + }; + this.expectationResultFactory = attrs.expectationResultFactory || + function() {}; + this.queueRunnerFactory = attrs.queueRunnerFactory || function() {}; + this.catchingExceptions = attrs.catchingExceptions || + function() { + return true; + }; + this.throwOnExpectationFailure = !!attrs.throwOnExpectationFailure; + + if (!this.queueableFn.fn) { + this.pend(); + } + + this.result = { + id: this.id, + description: this.description, + fullName: this.getFullName(), + failedExpectations: [], + passedExpectations: [], + pendingReason: '', + }; + } + + Spec.prototype.addExpectationResult = function(passed, data, isError) { + const expectationResult = this.expectationResultFactory(data); + if (passed) { + this.result.passedExpectations.push(expectationResult); + } else { + this.result.failedExpectations.push(expectationResult); + + if (this.throwOnExpectationFailure && !isError) { + throw new ExpectationFailed(); + } + } + }; + + Spec.prototype.execute = function(onComplete, enabled) { + const self = this; + + this.onStart(this); + + if (!this.isExecutable() || this.markedPending || enabled === false) { + complete(enabled); + return; + } + + const fns = this.beforeAndAfterFns(); + const allFns = fns.befores.concat(this.queueableFn).concat(fns.afters); + + this.queueRunnerFactory({ + queueableFns: allFns, + onException() { + self.onException.apply(self, arguments); + }, + onComplete: complete, + userContext: this.userContext(), + }); + + function complete(enabledAgain) { + self.result.status = self.status(enabledAgain); + self.resultCallback(self.result); + + if (onComplete) { + onComplete(); + } + } + }; + + Spec.prototype.onException = function onException(e) { + if (Spec.isPendingSpecException(e)) { + this.pend(extractCustomPendingMessage(e)); + return; + } + + if (e instanceof ExpectationFailed) { + return; + } + + this.addExpectationResult( + false, + { + matcherName: '', + passed: false, + expected: '', + actual: '', + error: e, + }, + true, + ); + }; + + Spec.prototype.disable = function() { + this.disabled = true; + }; + + Spec.prototype.pend = function(message) { + this.markedPending = true; + if (message) { + this.result.pendingReason = message; + } + }; + + Spec.prototype.getResult = function() { + this.result.status = this.status(); + return this.result; + }; + + Spec.prototype.status = function(enabled) { + if (this.disabled || enabled === false) { + return 'disabled'; + } + + if (this.markedPending) { + return 'pending'; + } + + if (this.result.failedExpectations.length > 0) { + return 'failed'; + } else { + return 'passed'; + } + }; + + Spec.prototype.isExecutable = function() { + return !this.disabled; + }; + + Spec.prototype.getFullName = function() { + return this.getSpecName(this); + }; + + const extractCustomPendingMessage = function(e) { + const fullMessage = e.toString(); + const boilerplateStart = fullMessage.indexOf( + Spec.pendingSpecExceptionMessage, + ); + const boilerplateEnd = boilerplateStart + + Spec.pendingSpecExceptionMessage.length; + + return fullMessage.substr(boilerplateEnd); + }; + + Spec.pendingSpecExceptionMessage = '=> marked Pending'; + + Spec.isPendingSpecException = function(e) { + return !!(e && + e.toString && + e.toString().indexOf(Spec.pendingSpecExceptionMessage) !== -1); + }; + + return Spec; +}; diff --git a/packages/jest-jasmine2/src/SpyRegistry.js b/packages/jest-jasmine2/src/SpyRegistry.js new file mode 100644 index 000000000000..dab0f626e456 --- /dev/null +++ b/packages/jest-jasmine2/src/SpyRegistry.js @@ -0,0 +1,132 @@ +/* +Copyright (c) 2008-2016 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. +*/ +/* eslint-disable sort-keys */ +'use strict'; + +const formatErrorMsg = function() { + function generateErrorMsg(domain, usage) { + const usageDefinition = usage ? '\nUsage: ' + usage : ''; + + return function errorMsg(msg) { + return domain + ' : ' + msg + usageDefinition; + }; + } + + return generateErrorMsg; +}; + +module.exports = function(j$) { + const getErrorMsg = formatErrorMsg( + '', + 'spyOn(, )', + ); + + function SpyRegistry(options) { + options = options || {}; + const currentSpies = options.currentSpies || + function() { + return []; + }; + + this.allowRespy = function(allow) { + this.respy = allow; + }; + + this.spyOn = function(obj, methodName) { + if (obj === void 0) { + throw new Error( + getErrorMsg( + 'could not find an object to spy upon for ' + methodName + '()', + ), + ); + } + + if (methodName === void 0) { + throw new Error(getErrorMsg('No method name supplied')); + } + + if (obj[methodName] === void 0) { + throw new Error(getErrorMsg(methodName + '() method does not exist')); + } + + if (obj[methodName] && j$.isSpy(obj[methodName])) { + if (this.respy) { + return obj[methodName]; + } else { + throw new Error( + getErrorMsg(methodName + ' has already been spied upon'), + ); + } + } + + let descriptor; + try { + descriptor = Object.getOwnPropertyDescriptor(obj, methodName); + } catch (e) { + // IE 8 doesn't support `definePropery` on non-DOM nodes + } + + if (descriptor && !(descriptor.writable || descriptor.set)) { + throw new Error( + getErrorMsg( + methodName + ' is not declared writable or has no setter', + ), + ); + } + + const originalMethod = obj[methodName]; + const spiedMethod = j$.createSpy(methodName, originalMethod); + let restoreStrategy; + + if (Object.prototype.hasOwnProperty.call(obj, methodName)) { + restoreStrategy = function() { + obj[methodName] = originalMethod; + }; + } else { + restoreStrategy = function() { + if (!delete obj[methodName]) { + obj[methodName] = originalMethod; + } + }; + } + + currentSpies().push({ + restoreObjectToOriginalState: restoreStrategy, + }); + + obj[methodName] = spiedMethod; + + return spiedMethod; + }; + + this.clearSpies = function() { + const spies = currentSpies(); + for (let i = spies.length - 1; i >= 0; i--) { + const spyEntry = spies[i]; + spyEntry.restoreObjectToOriginalState(); + } + }; + } + + return SpyRegistry; +}; diff --git a/packages/jest-jasmine2/src/SpyStrategy.js b/packages/jest-jasmine2/src/SpyStrategy.js new file mode 100644 index 000000000000..5922d74a3458 --- /dev/null +++ b/packages/jest-jasmine2/src/SpyStrategy.js @@ -0,0 +1,90 @@ +/* +Copyright (c) 2008-2016 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. +*/ +/* eslint-disable sort-keys */ +'use strict'; + +module.exports = function(j$) { + function SpyStrategy(options) { + options = options || {}; + + const identity = options.name || 'unknown'; + const originalFn = options.fn || function() {}; + const getSpy = options.getSpy || function() {}; + let plan = function() {}; + + this.identity = function() { + return identity; + }; + + this.exec = function() { + return plan.apply(this, arguments); + }; + + this.callThrough = function() { + plan = originalFn; + return getSpy(); + }; + + this.returnValue = function(value) { + plan = function() { + return value; + }; + return getSpy(); + }; + + this.returnValues = function() { + const values = Array.prototype.slice.call(arguments); + plan = function() { + return values.shift(); + }; + return getSpy(); + }; + + this.throwError = function(something) { + const error = something instanceof Error + ? something + : new Error(something); + plan = function() { + throw error; + }; + return getSpy(); + }; + + this.callFake = function(fn) { + if (typeof fn !== 'function') { + throw new Error( + 'Argument passed to callFake should be a function, got ' + fn, + ); + } + plan = fn; + return getSpy(); + }; + + this.stub = function(fn) { + plan = function() {}; + return getSpy(); + }; + } + + return SpyStrategy; +}; diff --git a/packages/jest-jasmine2/src/Suite.js b/packages/jest-jasmine2/src/Suite.js new file mode 100644 index 000000000000..a5dde5b2d7bf --- /dev/null +++ b/packages/jest-jasmine2/src/Suite.js @@ -0,0 +1,187 @@ +/* +Copyright (c) 2008-2016 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. +*/ +/* eslint-disable sort-keys */ +'use strict'; + +const ExpectationFailed = require('./ExpectationFailed'); + +module.exports = function(j$) { + function Suite(attrs) { + this.env = attrs.env; + this.id = attrs.id; + this.parentSuite = attrs.parentSuite; + this.description = attrs.description; + this.expectationFactory = attrs.expectationFactory; + this.expectationResultFactory = attrs.expectationResultFactory; + this.throwOnExpectationFailure = !!attrs.throwOnExpectationFailure; + + this.beforeFns = []; + this.afterFns = []; + this.beforeAllFns = []; + this.afterAllFns = []; + this.disabled = false; + + this.children = []; + + this.result = { + id: this.id, + description: this.description, + fullName: this.getFullName(), + failedExpectations: [], + }; + } + + Suite.prototype.getFullName = function() { + const fullName = []; + for ( + let parentSuite = this; + parentSuite; + parentSuite = parentSuite.parentSuite + ) { + if (parentSuite.parentSuite) { + fullName.unshift(parentSuite.description); + } + } + return fullName.join(' '); + }; + + Suite.prototype.disable = function() { + this.disabled = true; + }; + + Suite.prototype.pend = function(message) { + this.markedPending = true; + }; + + Suite.prototype.beforeEach = function(fn) { + this.beforeFns.unshift(fn); + }; + + Suite.prototype.beforeAll = function(fn) { + this.beforeAllFns.push(fn); + }; + + Suite.prototype.afterEach = function(fn) { + this.afterFns.unshift(fn); + }; + + Suite.prototype.afterAll = function(fn) { + this.afterAllFns.push(fn); + }; + + Suite.prototype.addChild = function(child) { + this.children.push(child); + }; + + Suite.prototype.status = function() { + if (this.disabled) { + return 'disabled'; + } + + if (this.markedPending) { + return 'pending'; + } + + if (this.result.failedExpectations.length > 0) { + return 'failed'; + } else { + return 'finished'; + } + }; + + Suite.prototype.isExecutable = function() { + return !this.disabled; + }; + + Suite.prototype.canBeReentered = function() { + return this.beforeAllFns.length === 0 && this.afterAllFns.length === 0; + }; + + Suite.prototype.getResult = function() { + this.result.status = this.status(); + return this.result; + }; + + Suite.prototype.sharedUserContext = function() { + if (!this.sharedContext) { + this.sharedContext = {}; + } + + return this.sharedContext; + }; + + Suite.prototype.clonedSharedUserContext = function() { + return this.sharedUserContext(); + }; + + Suite.prototype.onException = function() { + if (arguments[0] instanceof ExpectationFailed) { + return; + } + + if (isAfterAll(this.children)) { + const data = { + matcherName: '', + passed: false, + expected: '', + actual: '', + error: arguments[0], + }; + this.result.failedExpectations.push(this.expectationResultFactory(data)); + } else { + for (let i = 0; i < this.children.length; i++) { + const child = this.children[i]; + child.onException.apply(child, arguments); + } + } + }; + + Suite.prototype.addExpectationResult = function() { + if (isAfterAll(this.children) && isFailure(arguments)) { + const data = arguments[1]; + this.result.failedExpectations.push(this.expectationResultFactory(data)); + if (this.throwOnExpectationFailure) { + throw new ExpectationFailed(); + } + } else { + for (let i = 0; i < this.children.length; i++) { + const child = this.children[i]; + try { + child.addExpectationResult.apply(child, arguments); + } catch (e) { + // keep going + } + } + } + }; + + function isAfterAll(children) { + return children && children[0].result.status; + } + + function isFailure(args) { + return !args[0]; + } + + return Suite; +}; diff --git a/packages/jest-jasmine2/src/Timer.js b/packages/jest-jasmine2/src/Timer.js new file mode 100644 index 000000000000..88fb6934cefa --- /dev/null +++ b/packages/jest-jasmine2/src/Timer.js @@ -0,0 +1,49 @@ +/* +Copyright (c) 2008-2016 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. +*/ +/* eslint-disable sort-keys */ +'use strict'; + +module.exports = function() { + const defaultNow = (function(Date) { + return function() { + return new Date().getTime(); + }; + })(Date); + + function Timer(options) { + options = options || {}; + + const now = options.now || defaultNow; + let startTime; + + this.start = function() { + startTime = now(); + }; + + this.elapsed = function() { + return now() - startTime; + }; + } + + return Timer; +}; diff --git a/packages/jest-jasmine2/src/TreeProcessor.js b/packages/jest-jasmine2/src/TreeProcessor.js new file mode 100644 index 000000000000..04e5b4431d1d --- /dev/null +++ b/packages/jest-jasmine2/src/TreeProcessor.js @@ -0,0 +1,256 @@ +/* +Copyright (c) 2008-2016 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. +*/ +/* eslint-disable sort-keys */ +'use strict'; + +module.exports = function() { + function TreeProcessor(attrs) { + const tree = attrs.tree; + const runnableIds = attrs.runnableIds; + const queueRunnerFactory = attrs.queueRunnerFactory; + const nodeStart = attrs.nodeStart || function() {}; + const nodeComplete = attrs.nodeComplete || function() {}; + const defaultMin = Infinity; + const defaultMax = 1 - Infinity; + let processed = false; + let stats = {valid: true}; + + this.processTree = function() { + processNode(tree, false); + processed = true; + return stats; + }; + + this.execute = function(done) { + if (!processed) { + this.processTree(); + } + + if (!stats.valid) { + throw new Error('invalid order'); + } + + const childFns = wrapChildren(tree, 0); + + queueRunnerFactory({ + queueableFns: childFns, + userContext: tree.sharedUserContext(), + onException() { + tree.onException.apply(tree, arguments); + }, + onComplete: done, + }); + }; + + function runnableIndex(id) { + for (let i = 0; i < runnableIds.length; i++) { + if (runnableIds[i] === id) { + return i; + } + } + return void 0; + } + + function processNode(node, parentEnabled) { + const executableIndex = runnableIndex(node.id); + + if (executableIndex !== undefined) { + parentEnabled = true; + } + + parentEnabled = parentEnabled && node.isExecutable(); + + if (!node.children) { + stats[node.id] = { + executable: parentEnabled && node.isExecutable(), + segments: [ + { + index: 0, + owner: node, + nodes: [node], + min: startingMin(executableIndex), + max: startingMax(executableIndex), + }, + ], + }; + } else { + let hasExecutableChild = false; + + const children = node.children; + + for (let i = 0; i < children.length; i++) { + const child = children[i]; + + processNode(child, parentEnabled); + + if (!stats.valid) { + return; + } + + const childStats = stats[child.id]; + + hasExecutableChild = hasExecutableChild || childStats.executable; + } + + stats[node.id] = { + executable: hasExecutableChild, + }; + + segmentChildren(node, children, stats[node.id], executableIndex); + + if (!node.canBeReentered() && stats[node.id].segments.length > 1) { + stats = {valid: false}; + } + } + } + + function startingMin(executableIndex) { + return executableIndex === undefined ? defaultMin : executableIndex; + } + + function startingMax(executableIndex) { + return executableIndex === undefined ? defaultMax : executableIndex; + } + + function segmentChildren( + node, + children, + nodeStats, + executableIndex, + ) { + let currentSegment = { + index: 0, + owner: node, + nodes: [], + min: startingMin(executableIndex), + max: startingMax(executableIndex), + }; + const result = [currentSegment]; + const orderedChildSegments = orderChildSegments(children); + let lastMax = defaultMax; + + function isSegmentBoundary(minIndex) { + return lastMax !== defaultMax && + minIndex !== defaultMin && + lastMax < minIndex - 1; + } + + for (let i = 0; i < orderedChildSegments.length; i++) { + const childSegment = orderedChildSegments[i]; + const maxIndex = childSegment.max; + const minIndex = childSegment.min; + + if (isSegmentBoundary(minIndex)) { + currentSegment = { + index: result.length, + owner: node, + nodes: [], + min: defaultMin, + max: defaultMax, + }; + result.push(currentSegment); + } + + currentSegment.nodes.push(childSegment); + currentSegment.min = Math.min(currentSegment.min, minIndex); + currentSegment.max = Math.max(currentSegment.max, maxIndex); + lastMax = maxIndex; + } + + nodeStats.segments = result; + } + + function orderChildSegments(children) { + const specifiedOrder = []; + const unspecifiedOrder = []; + + for (let i = 0; i < children.length; i++) { + const child = children[i]; + const segments = stats[child.id].segments; + + for (let j = 0; j < segments.length; j++) { + const seg = segments[j]; + + if (seg.min === defaultMin) { + unspecifiedOrder.push(seg); + } else { + specifiedOrder.push(seg); + } + } + } + + specifiedOrder.sort((a, b) => { + return a.min - b.min; + }); + + return specifiedOrder.concat(unspecifiedOrder); + } + + function executeNode(node, segmentNumber) { + if (node.children) { + return { + fn(done) { + nodeStart(node); + + queueRunnerFactory({ + onComplete() { + nodeComplete(node, node.getResult()); + done(); + }, + queueableFns: wrapChildren(node, segmentNumber), + userContext: node.sharedUserContext(), + onException() { + node.onException.apply(node, arguments); + }, + }); + }, + }; + } else { + return { + fn(done) { + node.execute(done, stats[node.id].executable); + }, + }; + } + } + + function wrapChildren(node, segmentNumber) { + const result = []; + const segmentChildren = stats[node.id].segments[segmentNumber].nodes; + + for (let i = 0; i < segmentChildren.length; i++) { + result.push( + executeNode(segmentChildren[i].owner, segmentChildren[i].index), + ); + } + + if (!stats[node.id].executable) { + return result; + } + + return node.beforeAllFns.concat(result).concat(node.afterAllFns); + } + } + + return TreeProcessor; +}; diff --git a/packages/jest-jasmine2/src/buildExpectationResult.js b/packages/jest-jasmine2/src/buildExpectationResult.js new file mode 100644 index 000000000000..f4d2a7e392bd --- /dev/null +++ b/packages/jest-jasmine2/src/buildExpectationResult.js @@ -0,0 +1,76 @@ +/* +Copyright (c) 2008-2016 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. +*/ +/* eslint-disable sort-keys */ +'use strict'; + +module.exports = function() { + function buildExpectationResult(options) { + const messageFormatter = options.messageFormatter || function() {}; + const stackFormatter = options.stackFormatter || function() {}; + + const result = { + matcherName: options.matcherName, + message: message(), + stack: stack(), + passed: options.passed, + // CUSTOM JEST CHANGE: we pass error message to the result. + error: options.error, + }; + + if (!result.passed) { + result.expected = options.expected; + result.actual = options.actual; + } + + return result; + + function message() { + if (options.passed) { + return 'Passed.'; + } else if (options.message) { + return options.message; + } else if (options.error) { + return messageFormatter(options.error); + } + return ''; + } + + function stack() { + if (options.passed) { + return ''; + } + + let error = options.error; + if (!error) { + try { + throw new Error(message()); + } catch (e) { + error = e; + } + } + return stackFormatter(error); + } + } + + return buildExpectationResult; +}; diff --git a/packages/jest-jasmine2/src/jasmine-light.js b/packages/jest-jasmine2/src/jasmine-light.js index fcd7797811ac..e9d203c02b77 100644 --- a/packages/jest-jasmine2/src/jasmine-light.js +++ b/packages/jest-jasmine2/src/jasmine-light.js @@ -23,38 +23,38 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. /* eslint-disable sort-keys */ 'use strict'; -const formatErrorMsg = function() { - function generateErrorMsg(domain, usage) { - const usageDefinition = usage ? '\nUsage: ' + usage : ''; - - return function errorMsg(msg) { - return domain + ' : ' + msg + usageDefinition; - }; - } - - return generateErrorMsg; -}; - -class ExpectationFailed extends Error {} +const buildExpectationResult = require('./buildExpectationResult'); +const CallTracker = require('./CallTracker'); +const Env = require('./Env'); +const ExceptionFormatter = require('./ExceptionFormatter'); +const JsApiReporter = require('./JsApiReporter'); +const QueueRunner = require('./QueueRunner'); +const ReportDispatcher = require('./ReportDispatcher'); +const Spec = require('./Spec'); +const SpyRegistry = require('./SpyRegistry'); +const SpyStrategy = require('./SpyStrategy'); +const Suite = require('./Suite'); +const Timer = require('./Timer'); +const TreeProcessor = require('./TreeProcessor'); exports.create = function() { const j$ = {}; exports.base(j$); - j$.CallTracker = exports.CallTracker(j$); - j$.Env = exports.Env(j$); - j$.ExceptionFormatter = exports.ExceptionFormatter(); - j$.buildExpectationResult = exports.buildExpectationResult(); - j$.JsApiReporter = exports.JsApiReporter(); - j$.QueueRunner = exports.QueueRunner(j$); - j$.ReportDispatcher = exports.ReportDispatcher(); - j$.Spec = exports.Spec(j$); - j$.SpyRegistry = exports.SpyRegistry(j$); - j$.SpyStrategy = exports.SpyStrategy(j$); - j$.Suite = exports.Suite(j$); - j$.Timer = exports.Timer(); - j$.TreeProcessor = exports.TreeProcessor(); - j$.version = exports.version(); + j$.buildExpectationResult = buildExpectationResult(); + j$.CallTracker = CallTracker(j$); + j$.Env = Env(j$); + j$.ExceptionFormatter = ExceptionFormatter(); + j$.JsApiReporter = JsApiReporter(); + j$.QueueRunner = QueueRunner(j$); + j$.ReportDispatcher = ReportDispatcher(); + j$.Spec = Spec(j$); + j$.SpyRegistry = SpyRegistry(j$); + j$.SpyStrategy = SpyStrategy(j$); + j$.Suite = Suite(j$); + j$.Timer = Timer(); + j$.TreeProcessor = TreeProcessor(); + j$.version = '2.5.2-light'; return j$; }; @@ -135,1712 +135,66 @@ exports.base = function(j$) { }; }; -exports.Spec = function(j$) { - function Spec(attrs) { - this.expectationFactory = attrs.expectationFactory; - this.resultCallback = attrs.resultCallback || function() {}; - this.id = attrs.id; - this.description = attrs.description || ''; - this.queueableFn = attrs.queueableFn; - this.beforeAndAfterFns = attrs.beforeAndAfterFns || - function() { - return {befores: [], afters: []}; - }; - this.userContext = attrs.userContext || - function() { - return {}; - }; - this.onStart = attrs.onStart || function() {}; - this.getSpecName = attrs.getSpecName || - function() { - return ''; - }; - this.expectationResultFactory = attrs.expectationResultFactory || - function() {}; - this.queueRunnerFactory = attrs.queueRunnerFactory || function() {}; - this.catchingExceptions = attrs.catchingExceptions || - function() { - return true; - }; - this.throwOnExpectationFailure = !!attrs.throwOnExpectationFailure; - - if (!this.queueableFn.fn) { - this.pend(); - } - - this.result = { - id: this.id, - description: this.description, - fullName: this.getFullName(), - failedExpectations: [], - passedExpectations: [], - pendingReason: '', - }; - } - - Spec.prototype.addExpectationResult = function(passed, data, isError) { - const expectationResult = this.expectationResultFactory(data); - if (passed) { - this.result.passedExpectations.push(expectationResult); - } else { - this.result.failedExpectations.push(expectationResult); - - if (this.throwOnExpectationFailure && !isError) { - throw new ExpectationFailed(); - } - } - }; - - Spec.prototype.execute = function(onComplete, enabled) { - const self = this; - - this.onStart(this); - - if (!this.isExecutable() || this.markedPending || enabled === false) { - complete(enabled); - return; - } - - const fns = this.beforeAndAfterFns(); - const allFns = fns.befores.concat(this.queueableFn).concat(fns.afters); - - this.queueRunnerFactory({ - queueableFns: allFns, - onException() { - self.onException.apply(self, arguments); - }, - onComplete: complete, - userContext: this.userContext(), - }); - - function complete(enabledAgain) { - self.result.status = self.status(enabledAgain); - self.resultCallback(self.result); - - if (onComplete) { - onComplete(); - } - } - }; - - Spec.prototype.onException = function onException(e) { - if (Spec.isPendingSpecException(e)) { - this.pend(extractCustomPendingMessage(e)); - return; - } - - if (e instanceof ExpectationFailed) { - return; - } - - this.addExpectationResult( - false, - { - matcherName: '', - passed: false, - expected: '', - actual: '', - error: e, - }, - true, - ); - }; - - Spec.prototype.disable = function() { - this.disabled = true; - }; - - Spec.prototype.pend = function(message) { - this.markedPending = true; - if (message) { - this.result.pendingReason = message; - } - }; - - Spec.prototype.getResult = function() { - this.result.status = this.status(); - return this.result; - }; - - Spec.prototype.status = function(enabled) { - if (this.disabled || enabled === false) { - return 'disabled'; - } - - if (this.markedPending) { - return 'pending'; - } - - if (this.result.failedExpectations.length > 0) { - return 'failed'; - } else { - return 'passed'; - } - }; - - Spec.prototype.isExecutable = function() { - return !this.disabled; - }; - - Spec.prototype.getFullName = function() { - return this.getSpecName(this); - }; - - const extractCustomPendingMessage = function(e) { - const fullMessage = e.toString(); - const boilerplateStart = fullMessage.indexOf( - Spec.pendingSpecExceptionMessage, - ); - const boilerplateEnd = boilerplateStart + - Spec.pendingSpecExceptionMessage.length; - - return fullMessage.substr(boilerplateEnd); - }; - - Spec.pendingSpecExceptionMessage = '=> marked Pending'; - - Spec.isPendingSpecException = function(e) { - return !!(e && - e.toString && - e.toString().indexOf(Spec.pendingSpecExceptionMessage) !== -1); - }; - - return Spec; -}; - -exports.Env = function(j$) { - function Env(options) { - options = options || {}; - - const self = this; - - let totalSpecsDefined = 0; - - let catchExceptions = true; - - const realSetTimeout = global.setTimeout; - const realClearTimeout = global.clearTimeout; - - const runnableResources = {}; - - let currentSpec = null; - const currentlyExecutingSuites = []; - let currentDeclarationSuite = null; - let throwOnExpectationFailure = false; - let random = false; - let seed = null; - - const currentSuite = function() { - return currentlyExecutingSuites[currentlyExecutingSuites.length - 1]; - }; - - const currentRunnable = function() { - return currentSpec || currentSuite(); - }; - - const reporter = new j$.ReportDispatcher([ - 'jasmineStarted', - 'jasmineDone', - 'suiteStarted', - 'suiteDone', - 'specStarted', - 'specDone', - ]); - - this.specFilter = function() { - return true; - }; - - let nextSpecId = 0; - const getNextSpecId = function() { - return 'spec' + nextSpecId++; - }; - - let nextSuiteId = 0; - const getNextSuiteId = function() { - return 'suite' + nextSuiteId++; - }; - - const expectationFactory = function(actual, spec) { - return j$.Expectation.Factory({ - actual, - addExpectationResult, - }); - - function addExpectationResult(passed, result) { - return spec.addExpectationResult(passed, result); - } - }; - - const defaultResourcesForRunnable = function(id, parentRunnableId) { - const resources = {spies: []}; - - runnableResources[id] = resources; - }; - - const clearResourcesForRunnable = function(id) { - spyRegistry.clearSpies(); - delete runnableResources[id]; - }; - - const beforeAndAfterFns = function(suite) { - return function() { - let afters = []; - let befores = []; - - while (suite) { - befores = befores.concat(suite.beforeFns); - afters = afters.concat(suite.afterFns); - - suite = suite.parentSuite; - } - - return { - befores: befores.reverse(), - afters, - }; - }; - }; - - const getSpecName = function(spec, suite) { - const fullName = [spec.description]; - const suiteFullName = suite.getFullName(); - - if (suiteFullName !== '') { - fullName.unshift(suiteFullName); - } - - return fullName.join(' '); - }; - - const buildExpectationResult = j$.buildExpectationResult; - const exceptionFormatter = new j$.ExceptionFormatter(); - const expectationResultFactory = function(attrs) { - attrs.messageFormatter = exceptionFormatter.message; - attrs.stackFormatter = exceptionFormatter.stack; - - return buildExpectationResult(attrs); - }; - - this.catchExceptions = function(value) { - catchExceptions = !!value; - return catchExceptions; - }; - - this.catchingExceptions = function() { - return catchExceptions; - }; - - const maximumSpecCallbackDepth = 20; - let currentSpecCallbackDepth = 0; - - function clearStack(fn) { - currentSpecCallbackDepth++; - if (currentSpecCallbackDepth >= maximumSpecCallbackDepth) { - currentSpecCallbackDepth = 0; - realSetTimeout(fn, 0); - } else { - fn(); - } - } - - const catchException = function(e) { - return j$.Spec.isPendingSpecException(e) || catchExceptions; - }; - - this.throwOnExpectationFailure = function(value) { - throwOnExpectationFailure = !!value; - }; - - this.throwingExpectationFailures = function() { - return throwOnExpectationFailure; - }; - - this.randomizeTests = function(value) { - random = !!value; - }; - - this.randomTests = function() { - return random; - }; - - this.seed = function(value) { - if (value) { - seed = value; - } - return seed; - }; - - const queueRunnerFactory = function(options) { - options.catchException = catchException; - options.clearStack = options.clearStack || clearStack; - options.timeout = { - setTimeout: realSetTimeout, - clearTimeout: realClearTimeout, - }; - options.fail = self.fail; - - new j$.QueueRunner(options).execute(); - }; - - const topSuite = new j$.Suite({ - env: this, - id: getNextSuiteId(), - description: 'test', - expectationFactory, - expectationResultFactory, - }); - defaultResourcesForRunnable(topSuite.id); - currentDeclarationSuite = topSuite; - - this.topSuite = function() { - return topSuite; - }; - - this.execute = function(runnablesToRun) { - if (!runnablesToRun) { - if (focusedRunnables.length) { - runnablesToRun = focusedRunnables; - } else { - runnablesToRun = [topSuite.id]; - } - } - - const processor = new j$.TreeProcessor({ - tree: topSuite, - runnableIds: runnablesToRun, - queueRunnerFactory, - nodeStart(suite) { - currentlyExecutingSuites.push(suite); - defaultResourcesForRunnable(suite.id, suite.parentSuite.id); - reporter.suiteStarted(suite.result); - }, - nodeComplete(suite, result) { - if (!suite.disabled) { - clearResourcesForRunnable(suite.id); - } - currentlyExecutingSuites.pop(); - reporter.suiteDone(result); - }, - }); - - if (!processor.processTree().valid) { - throw new Error( - 'Invalid order: would cause a beforeAll or afterAll to be ' + - 'run multiple times', - ); - } - - reporter.jasmineStarted({ - totalSpecsDefined, - }); - - currentlyExecutingSuites.push(topSuite); - - processor.execute(() => { - clearResourcesForRunnable(topSuite.id); - currentlyExecutingSuites.pop(); - - reporter.jasmineDone({ - failedExpectations: topSuite.result.failedExpectations, - }); - }); - }; - - this.addReporter = function(reporterToAdd) { - reporter.addReporter(reporterToAdd); - }; - - this.provideFallbackReporter = function(reporterToAdd) { - reporter.provideFallbackReporter(reporterToAdd); - }; - - this.clearReporters = function() { - reporter.clearReporters(); - }; - - const spyRegistry = new j$.SpyRegistry({ - currentSpies() { - if (!currentRunnable()) { - throw new Error( - 'Spies must be created in a before function or a spec', - ); - } - return runnableResources[currentRunnable().id].spies; - }, - }); - - this.allowRespy = function(allow) { - spyRegistry.allowRespy(allow); - }; - - this.spyOn = function() { - return spyRegistry.spyOn.apply(spyRegistry, arguments); - }; - - const suiteFactory = function(description) { - const suite = new j$.Suite({ - env: self, - id: getNextSuiteId(), - description, - parentSuite: currentDeclarationSuite, - expectationFactory, - expectationResultFactory, - throwOnExpectationFailure, - }); - - return suite; - }; - - this.describe = function(description, specDefinitions) { - const suite = suiteFactory(description); - if (specDefinitions.length > 0) { - throw new Error('describe does not expect any arguments'); - } - if (currentDeclarationSuite.markedPending) { - suite.pend(); - } - addSpecsToSuite(suite, specDefinitions); - return suite; - }; - - this.xdescribe = function(description, specDefinitions) { - const suite = suiteFactory(description); - suite.pend(); - addSpecsToSuite(suite, specDefinitions); - return suite; - }; - - const focusedRunnables = []; - - this.fdescribe = function(description, specDefinitions) { - const suite = suiteFactory(description); - suite.isFocused = true; - - focusedRunnables.push(suite.id); - unfocusAncestor(); - addSpecsToSuite(suite, specDefinitions); - - return suite; - }; - - function addSpecsToSuite(suite, specDefinitions) { - const parentSuite = currentDeclarationSuite; - parentSuite.addChild(suite); - currentDeclarationSuite = suite; - - let declarationError = null; - try { - specDefinitions.call(suite); - } catch (e) { - declarationError = e; - } - - if (declarationError) { - self.it('encountered a declaration exception', () => { - throw declarationError; - }); - } - - currentDeclarationSuite = parentSuite; - } - - function findFocusedAncestor(suite) { - while (suite) { - if (suite.isFocused) { - return suite.id; - } - suite = suite.parentSuite; - } - - return null; - } - - function unfocusAncestor() { - const focusedAncestor = findFocusedAncestor(currentDeclarationSuite); - if (focusedAncestor) { - for (let i = 0; i < focusedRunnables.length; i++) { - if (focusedRunnables[i] === focusedAncestor) { - focusedRunnables.splice(i, 1); - break; - } - } - } - } - - const specFactory = function(description, fn, suite, timeout) { - totalSpecsDefined++; - const spec = new j$.Spec({ - id: getNextSpecId(), - beforeAndAfterFns: beforeAndAfterFns(suite), - expectationFactory, - resultCallback: specResultCallback, - getSpecName(spec) { - return getSpecName(spec, suite); - }, - onStart: specStarted, - description, - expectationResultFactory, - queueRunnerFactory, - userContext() { - return suite.clonedSharedUserContext(); - }, - queueableFn: { - fn, - timeout() { - return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; - }, - }, - throwOnExpectationFailure, - }); - - if (!self.specFilter(spec)) { - spec.disable(); - } - - return spec; +exports.interface = function(jasmine, env) { + const jasmineInterface = { + describe(description, specDefinitions) { + return env.describe(description, specDefinitions); + }, - function specResultCallback(result) { - clearResourcesForRunnable(spec.id); - currentSpec = null; - reporter.specDone(result); - } + xdescribe(description, specDefinitions) { + return env.xdescribe(description, specDefinitions); + }, - function specStarted(spec) { - currentSpec = spec; - defaultResourcesForRunnable(spec.id, suite.id); - reporter.specStarted(spec.result); - } - }; + fdescribe(description, specDefinitions) { + return env.fdescribe(description, specDefinitions); + }, - this.it = function(description, fn, timeout) { - const spec = specFactory( - description, - fn, - currentDeclarationSuite, - timeout, - ); - if (currentDeclarationSuite.markedPending) { - spec.pend(); - } - currentDeclarationSuite.addChild(spec); - return spec; - }; + it() { + return env.it.apply(env, arguments); + }, - this.xit = function() { - const spec = this.it.apply(this, arguments); - spec.pend('Temporarily disabled with xit'); - return spec; - }; + xit() { + return env.xit.apply(env, arguments); + }, - this.fit = function(description, fn, timeout) { - const spec = specFactory( - description, - fn, - currentDeclarationSuite, - timeout, - ); - currentDeclarationSuite.addChild(spec); - focusedRunnables.push(spec.id); - unfocusAncestor(); - return spec; - }; + fit() { + return env.fit.apply(env, arguments); + }, - this.beforeEach = function(beforeEachFunction, timeout) { - currentDeclarationSuite.beforeEach({ - fn: beforeEachFunction, - timeout() { - return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; - }, - }); - }; + beforeEach() { + return env.beforeEach.apply(env, arguments); + }, - this.beforeAll = function(beforeAllFunction, timeout) { - currentDeclarationSuite.beforeAll({ - fn: beforeAllFunction, - timeout() { - return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; - }, - }); - }; + afterEach() { + return env.afterEach.apply(env, arguments); + }, - this.afterEach = function(afterEachFunction, timeout) { - currentDeclarationSuite.afterEach({ - fn: afterEachFunction, - timeout() { - return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; - }, - }); - }; + beforeAll() { + return env.beforeAll.apply(env, arguments); + }, - this.afterAll = function(afterAllFunction, timeout) { - currentDeclarationSuite.afterAll({ - fn: afterAllFunction, - timeout() { - return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; - }, - }); - }; + afterAll() { + return env.afterAll.apply(env, arguments); + }, - this.pending = function(message) { - let fullMessage = j$.Spec.pendingSpecExceptionMessage; - if (message) { - fullMessage += message; - } - throw fullMessage; - }; + pending() { + return env.pending.apply(env, arguments); + }, - this.fail = function(error) { - let message = 'Failed'; - if (error) { - message += ': '; - message += error.message || error; - } + fail() { + return env.fail.apply(env, arguments); + }, - currentRunnable().addExpectationResult(false, { - matcherName: '', - passed: false, - expected: '', - actual: '', - message, - error: error && error.message ? error : null, - }); - }; - } + spyOn(obj, methodName) { + return env.spyOn(obj, methodName); + }, - return Env; -}; + jsApiReporter: new jasmine.JsApiReporter({ + timer: new jasmine.Timer(), + }), -exports.JsApiReporter = function() { - const noopTimer = { - start() {}, - elapsed() { - return 0; - }, - }; - - function JsApiReporter(options) { - const timer = options.timer || noopTimer; - let status = 'loaded'; - - this.started = false; - this.finished = false; - this.runDetails = {}; - - this.jasmineStarted = function() { - this.started = true; - status = 'started'; - timer.start(); - }; - - let executionTime; - - this.jasmineDone = function(runDetails) { - this.finished = true; - this.runDetails = runDetails; - executionTime = timer.elapsed(); - status = 'done'; - }; - - this.status = function() { - return status; - }; - - const suites = []; - const suites_hash = {}; - - this.suiteStarted = function(result) { - suites_hash[result.id] = result; - }; - - this.suiteDone = function(result) { - storeSuite(result); - }; - - this.suiteResults = function(index, length) { - return suites.slice(index, index + length); - }; - - function storeSuite(result) { - suites.push(result); - suites_hash[result.id] = result; - } - - this.suites = function() { - return suites_hash; - }; - - const specs = []; - - this.specDone = function(result) { - specs.push(result); - }; - - this.specResults = function(index, length) { - return specs.slice(index, index + length); - }; - - this.specs = function() { - return specs; - }; - - this.executionTime = function() { - return executionTime; - }; - } - - return JsApiReporter; -}; - -exports.CallTracker = function(j$) { - function CallTracker() { - let calls = []; - - this.track = function(context) { - calls.push(context); - }; - - this.any = function() { - return !!calls.length; - }; - - this.count = function() { - return calls.length; - }; - - this.argsFor = function(index) { - const call = calls[index]; - return call ? call.args : []; - }; - - this.all = function() { - return calls; - }; - - this.allArgs = function() { - const callArgs = []; - for (let i = 0; i < calls.length; i++) { - callArgs.push(calls[i].args); - } - - return callArgs; - }; - - this.first = function() { - return calls[0]; - }; - - this.mostRecent = function() { - return calls[calls.length - 1]; - }; - - this.reset = function() { - calls = []; - }; - } - - return CallTracker; -}; - -exports.ExceptionFormatter = function() { - function ExceptionFormatter() { - this.message = function(error) { - let message = ''; - - if (error.name && error.message) { - message += error.name + ': ' + error.message; - } else { - message += error.toString() + ' thrown'; - } - - if (error.fileName || error.sourceURL) { - message += ' in ' + (error.fileName || error.sourceURL); - } - - if (error.line || error.lineNumber) { - message += ' (line ' + (error.line || error.lineNumber) + ')'; - } - - return message; - }; - - this.stack = function(error) { - return error ? error.stack : null; - }; - } - - return ExceptionFormatter; -}; - -exports.buildExpectationResult = function() { - function buildExpectationResult(options) { - const messageFormatter = options.messageFormatter || function() {}; - const stackFormatter = options.stackFormatter || function() {}; - - const result = { - matcherName: options.matcherName, - message: message(), - stack: stack(), - passed: options.passed, - // CUSTOM JEST CHANGE: we pass error message to the result. - error: options.error, - }; - - if (!result.passed) { - result.expected = options.expected; - result.actual = options.actual; - } - - return result; - - function message() { - if (options.passed) { - return 'Passed.'; - } else if (options.message) { - return options.message; - } else if (options.error) { - return messageFormatter(options.error); - } - return ''; - } - - function stack() { - if (options.passed) { - return ''; - } - - let error = options.error; - if (!error) { - try { - throw new Error(message()); - } catch (e) { - error = e; - } - } - return stackFormatter(error); - } - } - - return buildExpectationResult; -}; - -exports.QueueRunner = function(j$) { - function once(fn) { - let called = false; - return function() { - if (!called) { - called = true; - fn(); - } - return null; - }; - } - - function QueueRunner(attrs) { - this.queueableFns = attrs.queueableFns || []; - this.onComplete = attrs.onComplete || function() {}; - this.clearStack = attrs.clearStack || - function(fn) { - fn(); - }; - this.onException = attrs.onException || function() {}; - this.catchException = attrs.catchException || - function() { - return true; - }; - this.userContext = attrs.userContext || {}; - this.timeout = attrs.timeout || { - setTimeout, - clearTimeout, - }; - this.fail = attrs.fail || function() {}; - } - - QueueRunner.prototype.execute = function() { - this.run(this.queueableFns, 0); - }; - - QueueRunner.prototype.run = function(queueableFns, recursiveIndex) { - const length = queueableFns.length; - const self = this; - let iterativeIndex; - - for ( - iterativeIndex = recursiveIndex; - iterativeIndex < length; - iterativeIndex++ - ) { - const queueableFn = queueableFns[iterativeIndex]; - if (queueableFn.fn.length > 0) { - attemptAsync(queueableFn); - return; - } else { - attemptSync(queueableFn); - } - } - - const runnerDone = iterativeIndex >= length; - - if (runnerDone) { - this.clearStack(this.onComplete); - } - - function attemptSync(queueableFn) { - try { - queueableFn.fn.call(self.userContext); - } catch (e) { - handleException(e, queueableFn); - } - } - - function attemptAsync(queueableFn) { - const clearTimeout = function() { - Function.prototype.apply.apply(self.timeout.clearTimeout, [ - global, - [timeoutId], - ]); - }; - const next = once(() => { - clearTimeout(timeoutId); - self.run(queueableFns, iterativeIndex + 1); - }); - let timeoutId; - - next.fail = function() { - self.fail.apply(null, arguments); - next(); - }; - - if (queueableFn.timeout) { - timeoutId = Function.prototype.apply.apply(self.timeout.setTimeout, [ - global, - [ - function() { - const error = new Error( - 'Timeout - Async callback was not invoked within ' + - 'timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.', - ); - onException(error); - next(); - }, - queueableFn.timeout(), - ], - ]); - } - - try { - queueableFn.fn.call(self.userContext, next); - } catch (e) { - handleException(e, queueableFn); - next(); - } - } - - function onException(e) { - self.onException(e); - } - - function handleException(e, queueableFn) { - onException(e); - if (!self.catchException(e)) { - throw e; - } - } - }; - - return QueueRunner; -}; - -exports.ReportDispatcher = function() { - function ReportDispatcher(methods) { - const dispatchedMethods = methods || []; - - for (let i = 0; i < dispatchedMethods.length; i++) { - const method = dispatchedMethods[i]; - this[method] = (function(m) { - return function() { - dispatch(m, arguments); - }; - })(method); - } - - let reporters = []; - let fallbackReporter = null; - - this.addReporter = function(reporter) { - reporters.push(reporter); - }; - - this.provideFallbackReporter = function(reporter) { - fallbackReporter = reporter; - }; - - this.clearReporters = function() { - reporters = []; - }; - - return this; - - function dispatch(method, args) { - if (reporters.length === 0 && fallbackReporter !== null) { - reporters.push(fallbackReporter); - } - for (let i = 0; i < reporters.length; i++) { - const reporter = reporters[i]; - if (reporter[method]) { - reporter[method].apply(reporter, args); - } - } - } - } - - return ReportDispatcher; -}; - -exports.SpyRegistry = function(j$) { - const getErrorMsg = formatErrorMsg( - '', - 'spyOn(, )', - ); - - function SpyRegistry(options) { - options = options || {}; - const currentSpies = options.currentSpies || - function() { - return []; - }; - - this.allowRespy = function(allow) { - this.respy = allow; - }; - - this.spyOn = function(obj, methodName) { - if (obj === void 0) { - throw new Error( - getErrorMsg( - 'could not find an object to spy upon for ' + methodName + '()', - ), - ); - } - - if (methodName === void 0) { - throw new Error(getErrorMsg('No method name supplied')); - } - - if (obj[methodName] === void 0) { - throw new Error(getErrorMsg(methodName + '() method does not exist')); - } - - if (obj[methodName] && j$.isSpy(obj[methodName])) { - if (this.respy) { - return obj[methodName]; - } else { - throw new Error( - getErrorMsg(methodName + ' has already been spied upon'), - ); - } - } - - let descriptor; - try { - descriptor = Object.getOwnPropertyDescriptor(obj, methodName); - } catch (e) { - // IE 8 doesn't support `definePropery` on non-DOM nodes - } - - if (descriptor && !(descriptor.writable || descriptor.set)) { - throw new Error( - getErrorMsg( - methodName + ' is not declared writable or has no setter', - ), - ); - } - - const originalMethod = obj[methodName]; - const spiedMethod = j$.createSpy(methodName, originalMethod); - let restoreStrategy; - - if (Object.prototype.hasOwnProperty.call(obj, methodName)) { - restoreStrategy = function() { - obj[methodName] = originalMethod; - }; - } else { - restoreStrategy = function() { - if (!delete obj[methodName]) { - obj[methodName] = originalMethod; - } - }; - } - - currentSpies().push({ - restoreObjectToOriginalState: restoreStrategy, - }); - - obj[methodName] = spiedMethod; - - return spiedMethod; - }; - - this.clearSpies = function() { - const spies = currentSpies(); - for (let i = spies.length - 1; i >= 0; i--) { - const spyEntry = spies[i]; - spyEntry.restoreObjectToOriginalState(); - } - }; - } - - return SpyRegistry; -}; - -exports.SpyStrategy = function(j$) { - function SpyStrategy(options) { - options = options || {}; - - const identity = options.name || 'unknown'; - const originalFn = options.fn || function() {}; - const getSpy = options.getSpy || function() {}; - let plan = function() {}; - - this.identity = function() { - return identity; - }; - - this.exec = function() { - return plan.apply(this, arguments); - }; - - this.callThrough = function() { - plan = originalFn; - return getSpy(); - }; - - this.returnValue = function(value) { - plan = function() { - return value; - }; - return getSpy(); - }; - - this.returnValues = function() { - const values = Array.prototype.slice.call(arguments); - plan = function() { - return values.shift(); - }; - return getSpy(); - }; - - this.throwError = function(something) { - const error = something instanceof Error - ? something - : new Error(something); - plan = function() { - throw error; - }; - return getSpy(); - }; - - this.callFake = function(fn) { - if (typeof fn !== 'function') { - throw new Error( - 'Argument passed to callFake should be a function, got ' + fn, - ); - } - plan = fn; - return getSpy(); - }; - - this.stub = function(fn) { - plan = function() {}; - return getSpy(); - }; - } - - return SpyStrategy; -}; - -exports.Suite = function(j$) { - function Suite(attrs) { - this.env = attrs.env; - this.id = attrs.id; - this.parentSuite = attrs.parentSuite; - this.description = attrs.description; - this.expectationFactory = attrs.expectationFactory; - this.expectationResultFactory = attrs.expectationResultFactory; - this.throwOnExpectationFailure = !!attrs.throwOnExpectationFailure; - - this.beforeFns = []; - this.afterFns = []; - this.beforeAllFns = []; - this.afterAllFns = []; - this.disabled = false; - - this.children = []; - - this.result = { - id: this.id, - description: this.description, - fullName: this.getFullName(), - failedExpectations: [], - }; - } - - Suite.prototype.getFullName = function() { - const fullName = []; - for ( - let parentSuite = this; - parentSuite; - parentSuite = parentSuite.parentSuite - ) { - if (parentSuite.parentSuite) { - fullName.unshift(parentSuite.description); - } - } - return fullName.join(' '); - }; - - Suite.prototype.disable = function() { - this.disabled = true; - }; - - Suite.prototype.pend = function(message) { - this.markedPending = true; - }; - - Suite.prototype.beforeEach = function(fn) { - this.beforeFns.unshift(fn); - }; - - Suite.prototype.beforeAll = function(fn) { - this.beforeAllFns.push(fn); - }; - - Suite.prototype.afterEach = function(fn) { - this.afterFns.unshift(fn); - }; - - Suite.prototype.afterAll = function(fn) { - this.afterAllFns.push(fn); - }; - - Suite.prototype.addChild = function(child) { - this.children.push(child); - }; - - Suite.prototype.status = function() { - if (this.disabled) { - return 'disabled'; - } - - if (this.markedPending) { - return 'pending'; - } - - if (this.result.failedExpectations.length > 0) { - return 'failed'; - } else { - return 'finished'; - } - }; - - Suite.prototype.isExecutable = function() { - return !this.disabled; - }; - - Suite.prototype.canBeReentered = function() { - return this.beforeAllFns.length === 0 && this.afterAllFns.length === 0; - }; - - Suite.prototype.getResult = function() { - this.result.status = this.status(); - return this.result; - }; - - Suite.prototype.sharedUserContext = function() { - if (!this.sharedContext) { - this.sharedContext = {}; - } - - return this.sharedContext; - }; - - Suite.prototype.clonedSharedUserContext = function() { - return this.sharedUserContext(); - }; - - Suite.prototype.onException = function() { - if (arguments[0] instanceof ExpectationFailed) { - return; - } - - if (isAfterAll(this.children)) { - const data = { - matcherName: '', - passed: false, - expected: '', - actual: '', - error: arguments[0], - }; - this.result.failedExpectations.push(this.expectationResultFactory(data)); - } else { - for (let i = 0; i < this.children.length; i++) { - const child = this.children[i]; - child.onException.apply(child, arguments); - } - } - }; - - Suite.prototype.addExpectationResult = function() { - if (isAfterAll(this.children) && isFailure(arguments)) { - const data = arguments[1]; - this.result.failedExpectations.push(this.expectationResultFactory(data)); - if (this.throwOnExpectationFailure) { - throw new ExpectationFailed(); - } - } else { - for (let i = 0; i < this.children.length; i++) { - const child = this.children[i]; - try { - child.addExpectationResult.apply(child, arguments); - } catch (e) { - // keep going - } - } - } - }; - - function isAfterAll(children) { - return children && children[0].result.status; - } - - function isFailure(args) { - return !args[0]; - } - - return Suite; -}; - -exports.Timer = function() { - const defaultNow = (function(Date) { - return function() { - return new Date().getTime(); - }; - })(Date); - - function Timer(options) { - options = options || {}; - - const now = options.now || defaultNow; - let startTime; - - this.start = function() { - startTime = now(); - }; - - this.elapsed = function() { - return now() - startTime; - }; - } - - return Timer; -}; - -exports.TreeProcessor = function() { - function TreeProcessor(attrs) { - const tree = attrs.tree; - const runnableIds = attrs.runnableIds; - const queueRunnerFactory = attrs.queueRunnerFactory; - const nodeStart = attrs.nodeStart || function() {}; - const nodeComplete = attrs.nodeComplete || function() {}; - const defaultMin = Infinity; - const defaultMax = 1 - Infinity; - let processed = false; - let stats = {valid: true}; - - this.processTree = function() { - processNode(tree, false); - processed = true; - return stats; - }; - - this.execute = function(done) { - if (!processed) { - this.processTree(); - } - - if (!stats.valid) { - throw new Error('invalid order'); - } - - const childFns = wrapChildren(tree, 0); - - queueRunnerFactory({ - queueableFns: childFns, - userContext: tree.sharedUserContext(), - onException() { - tree.onException.apply(tree, arguments); - }, - onComplete: done, - }); - }; - - function runnableIndex(id) { - for (let i = 0; i < runnableIds.length; i++) { - if (runnableIds[i] === id) { - return i; - } - } - return void 0; - } - - function processNode(node, parentEnabled) { - const executableIndex = runnableIndex(node.id); - - if (executableIndex !== undefined) { - parentEnabled = true; - } - - parentEnabled = parentEnabled && node.isExecutable(); - - if (!node.children) { - stats[node.id] = { - executable: parentEnabled && node.isExecutable(), - segments: [ - { - index: 0, - owner: node, - nodes: [node], - min: startingMin(executableIndex), - max: startingMax(executableIndex), - }, - ], - }; - } else { - let hasExecutableChild = false; - - const children = node.children; - - for (let i = 0; i < children.length; i++) { - const child = children[i]; - - processNode(child, parentEnabled); - - if (!stats.valid) { - return; - } - - const childStats = stats[child.id]; - - hasExecutableChild = hasExecutableChild || childStats.executable; - } - - stats[node.id] = { - executable: hasExecutableChild, - }; - - segmentChildren(node, children, stats[node.id], executableIndex); - - if (!node.canBeReentered() && stats[node.id].segments.length > 1) { - stats = {valid: false}; - } - } - } - - function startingMin(executableIndex) { - return executableIndex === undefined ? defaultMin : executableIndex; - } - - function startingMax(executableIndex) { - return executableIndex === undefined ? defaultMax : executableIndex; - } - - function segmentChildren( - node, - children, - nodeStats, - executableIndex, - ) { - let currentSegment = { - index: 0, - owner: node, - nodes: [], - min: startingMin(executableIndex), - max: startingMax(executableIndex), - }; - const result = [currentSegment]; - const orderedChildSegments = orderChildSegments(children); - let lastMax = defaultMax; - - function isSegmentBoundary(minIndex) { - return lastMax !== defaultMax && - minIndex !== defaultMin && - lastMax < minIndex - 1; - } - - for (let i = 0; i < orderedChildSegments.length; i++) { - const childSegment = orderedChildSegments[i]; - const maxIndex = childSegment.max; - const minIndex = childSegment.min; - - if (isSegmentBoundary(minIndex)) { - currentSegment = { - index: result.length, - owner: node, - nodes: [], - min: defaultMin, - max: defaultMax, - }; - result.push(currentSegment); - } - - currentSegment.nodes.push(childSegment); - currentSegment.min = Math.min(currentSegment.min, minIndex); - currentSegment.max = Math.max(currentSegment.max, maxIndex); - lastMax = maxIndex; - } - - nodeStats.segments = result; - } - - function orderChildSegments(children) { - const specifiedOrder = []; - const unspecifiedOrder = []; - - for (let i = 0; i < children.length; i++) { - const child = children[i]; - const segments = stats[child.id].segments; - - for (let j = 0; j < segments.length; j++) { - const seg = segments[j]; - - if (seg.min === defaultMin) { - unspecifiedOrder.push(seg); - } else { - specifiedOrder.push(seg); - } - } - } - - specifiedOrder.sort((a, b) => { - return a.min - b.min; - }); - - return specifiedOrder.concat(unspecifiedOrder); - } - - function executeNode(node, segmentNumber) { - if (node.children) { - return { - fn(done) { - nodeStart(node); - - queueRunnerFactory({ - onComplete() { - nodeComplete(node, node.getResult()); - done(); - }, - queueableFns: wrapChildren(node, segmentNumber), - userContext: node.sharedUserContext(), - onException() { - node.onException.apply(node, arguments); - }, - }); - }, - }; - } else { - return { - fn(done) { - node.execute(done, stats[node.id].executable); - }, - }; - } - } - - function wrapChildren(node, segmentNumber) { - const result = []; - const segmentChildren = stats[node.id].segments[segmentNumber].nodes; - - for (let i = 0; i < segmentChildren.length; i++) { - result.push( - executeNode(segmentChildren[i].owner, segmentChildren[i].index), - ); - } - - if (!stats[node.id].executable) { - return result; - } - - return node.beforeAllFns.concat(result).concat(node.afterAllFns); - } - } - - return TreeProcessor; -}; - -exports.interface = function(jasmine, env) { - const jasmineInterface = { - describe(description, specDefinitions) { - return env.describe(description, specDefinitions); - }, - - xdescribe(description, specDefinitions) { - return env.xdescribe(description, specDefinitions); - }, - - fdescribe(description, specDefinitions) { - return env.fdescribe(description, specDefinitions); - }, - - it() { - return env.it.apply(env, arguments); - }, - - xit() { - return env.xit.apply(env, arguments); - }, - - fit() { - return env.fit.apply(env, arguments); - }, - - beforeEach() { - return env.beforeEach.apply(env, arguments); - }, - - afterEach() { - return env.afterEach.apply(env, arguments); - }, - - beforeAll() { - return env.beforeAll.apply(env, arguments); - }, - - afterAll() { - return env.afterAll.apply(env, arguments); - }, - - pending() { - return env.pending.apply(env, arguments); - }, - - fail() { - return env.fail.apply(env, arguments); - }, - - spyOn(obj, methodName) { - return env.spyOn(obj, methodName); - }, - - jsApiReporter: new jasmine.JsApiReporter({ - timer: new jasmine.Timer(), - }), - - jasmine, + jasmine, }; return jasmineInterface; }; - -exports.version = function() { - return '2.5.2-light'; -}; From 40a2066c59e903714aa95096d75e543d027ad750 Mon Sep 17 00:00:00 2001 From: wtgtybhertgeghgtwtg Date: Thu, 16 Mar 2017 08:46:00 -0700 Subject: [PATCH 2/8] Don't wrap things that don't need to be wrapped. --- .../jest-jasmine2/src/ExceptionFormatter.js | 6 +- packages/jest-jasmine2/src/JsApiReporter.js | 122 +++++++++--------- .../jest-jasmine2/src/ReportDispatcher.js | 6 +- packages/jest-jasmine2/src/Timer.js | 46 ++++--- packages/jest-jasmine2/src/TreeProcessor.js | 6 +- .../src/buildExpectationResult.js | 78 ++++++----- packages/jest-jasmine2/src/jasmine-light.js | 12 +- 7 files changed, 132 insertions(+), 144 deletions(-) diff --git a/packages/jest-jasmine2/src/ExceptionFormatter.js b/packages/jest-jasmine2/src/ExceptionFormatter.js index bff92755db4f..24ffb26d885f 100644 --- a/packages/jest-jasmine2/src/ExceptionFormatter.js +++ b/packages/jest-jasmine2/src/ExceptionFormatter.js @@ -23,8 +23,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. /* eslint-disable sort-keys */ 'use strict'; -module.exports = function() { - function ExceptionFormatter() { +function ExceptionFormatter() { this.message = function(error) { let message = ''; @@ -50,5 +49,4 @@ module.exports = function() { }; } - return ExceptionFormatter; -}; +module.exports = ExceptionFormatter; diff --git a/packages/jest-jasmine2/src/JsApiReporter.js b/packages/jest-jasmine2/src/JsApiReporter.js index ebb1240e859e..c29bcdf28cd2 100644 --- a/packages/jest-jasmine2/src/JsApiReporter.js +++ b/packages/jest-jasmine2/src/JsApiReporter.js @@ -23,83 +23,81 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. /* eslint-disable sort-keys */ 'use strict'; -module.exports = function() { - const noopTimer = { - start() {}, - elapsed() { - return 0; - }, - }; +const noopTimer = { + start() {}, + elapsed() { + return 0; + }, +}; - function JsApiReporter(options) { - const timer = options.timer || noopTimer; - let status = 'loaded'; +function JsApiReporter(options) { + const timer = options.timer || noopTimer; + let status = 'loaded'; - this.started = false; - this.finished = false; - this.runDetails = {}; + this.started = false; + this.finished = false; + this.runDetails = {}; - this.jasmineStarted = function() { - this.started = true; - status = 'started'; - timer.start(); - }; + this.jasmineStarted = function() { + this.started = true; + status = 'started'; + timer.start(); + }; - let executionTime; + let executionTime; - this.jasmineDone = function(runDetails) { - this.finished = true; - this.runDetails = runDetails; - executionTime = timer.elapsed(); - status = 'done'; - }; + this.jasmineDone = function(runDetails) { + this.finished = true; + this.runDetails = runDetails; + executionTime = timer.elapsed(); + status = 'done'; + }; - this.status = function() { - return status; - }; + this.status = function() { + return status; + }; - const suites = []; - const suites_hash = {}; + const suites = []; + const suites_hash = {}; - this.suiteStarted = function(result) { - suites_hash[result.id] = result; - }; + this.suiteStarted = function(result) { + suites_hash[result.id] = result; + }; - this.suiteDone = function(result) { - storeSuite(result); - }; + this.suiteDone = function(result) { + storeSuite(result); + }; - this.suiteResults = function(index, length) { - return suites.slice(index, index + length); - }; + this.suiteResults = function(index, length) { + return suites.slice(index, index + length); + }; - function storeSuite(result) { - suites.push(result); - suites_hash[result.id] = result; - } + function storeSuite(result) { + suites.push(result); + suites_hash[result.id] = result; + } - this.suites = function() { - return suites_hash; - }; + this.suites = function() { + return suites_hash; + }; - const specs = []; + const specs = []; - this.specDone = function(result) { - specs.push(result); - }; + this.specDone = function(result) { + specs.push(result); + }; - this.specResults = function(index, length) { - return specs.slice(index, index + length); - }; + this.specResults = function(index, length) { + return specs.slice(index, index + length); + }; - this.specs = function() { - return specs; - }; + this.specs = function() { + return specs; + }; - this.executionTime = function() { - return executionTime; - }; - } + this.executionTime = function() { + return executionTime; + }; +} - return JsApiReporter; -}; +module.exports = JsApiReporter; diff --git a/packages/jest-jasmine2/src/ReportDispatcher.js b/packages/jest-jasmine2/src/ReportDispatcher.js index 8f71dd76ee81..1357be765b3e 100644 --- a/packages/jest-jasmine2/src/ReportDispatcher.js +++ b/packages/jest-jasmine2/src/ReportDispatcher.js @@ -23,8 +23,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. /* eslint-disable sort-keys */ 'use strict'; -module.exports = function() { - function ReportDispatcher(methods) { +function ReportDispatcher(methods) { const dispatchedMethods = methods || []; for (let i = 0; i < dispatchedMethods.length; i++) { @@ -66,5 +65,4 @@ module.exports = function() { } } - return ReportDispatcher; -}; +module.exports = ReportDispatcher; diff --git a/packages/jest-jasmine2/src/Timer.js b/packages/jest-jasmine2/src/Timer.js index 88fb6934cefa..93fa55da10d9 100644 --- a/packages/jest-jasmine2/src/Timer.js +++ b/packages/jest-jasmine2/src/Timer.js @@ -23,27 +23,25 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. /* eslint-disable sort-keys */ 'use strict'; -module.exports = function() { - const defaultNow = (function(Date) { - return function() { - return new Date().getTime(); - }; - })(Date); - - function Timer(options) { - options = options || {}; - - const now = options.now || defaultNow; - let startTime; - - this.start = function() { - startTime = now(); - }; - - this.elapsed = function() { - return now() - startTime; - }; - } - - return Timer; -}; +const defaultNow = (function(Date) { + return function() { + return new Date().getTime(); + }; +})(Date); + +function Timer(options) { + options = options || {}; + + const now = options.now || defaultNow; + let startTime; + + this.start = function() { + startTime = now(); + }; + + this.elapsed = function() { + return now() - startTime; + }; +} + +module.exports = Timer; diff --git a/packages/jest-jasmine2/src/TreeProcessor.js b/packages/jest-jasmine2/src/TreeProcessor.js index 04e5b4431d1d..9367b40f119b 100644 --- a/packages/jest-jasmine2/src/TreeProcessor.js +++ b/packages/jest-jasmine2/src/TreeProcessor.js @@ -23,8 +23,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. /* eslint-disable sort-keys */ 'use strict'; -module.exports = function() { - function TreeProcessor(attrs) { +function TreeProcessor(attrs) { const tree = attrs.tree; const runnableIds = attrs.runnableIds; const queueRunnerFactory = attrs.queueRunnerFactory; @@ -252,5 +251,4 @@ module.exports = function() { } } - return TreeProcessor; -}; +module.exports = TreeProcessor; diff --git a/packages/jest-jasmine2/src/buildExpectationResult.js b/packages/jest-jasmine2/src/buildExpectationResult.js index f4d2a7e392bd..6ad6e104b75b 100644 --- a/packages/jest-jasmine2/src/buildExpectationResult.js +++ b/packages/jest-jasmine2/src/buildExpectationResult.js @@ -23,54 +23,52 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. /* eslint-disable sort-keys */ 'use strict'; -module.exports = function() { - function buildExpectationResult(options) { - const messageFormatter = options.messageFormatter || function() {}; - const stackFormatter = options.stackFormatter || function() {}; +function buildExpectationResult(options) { + const messageFormatter = options.messageFormatter || function() {}; + const stackFormatter = options.stackFormatter || function() {}; - const result = { - matcherName: options.matcherName, - message: message(), - stack: stack(), - passed: options.passed, - // CUSTOM JEST CHANGE: we pass error message to the result. - error: options.error, - }; + const result = { + matcherName: options.matcherName, + message: message(), + stack: stack(), + passed: options.passed, + // CUSTOM JEST CHANGE: we pass error message to the result. + error: options.error, + }; - if (!result.passed) { - result.expected = options.expected; - result.actual = options.actual; - } + if (!result.passed) { + result.expected = options.expected; + result.actual = options.actual; + } - return result; + return result; - function message() { - if (options.passed) { - return 'Passed.'; - } else if (options.message) { - return options.message; - } else if (options.error) { - return messageFormatter(options.error); - } - return ''; + function message() { + if (options.passed) { + return 'Passed.'; + } else if (options.message) { + return options.message; + } else if (options.error) { + return messageFormatter(options.error); } + return ''; + } - function stack() { - if (options.passed) { - return ''; - } + function stack() { + if (options.passed) { + return ''; + } - let error = options.error; - if (!error) { - try { - throw new Error(message()); - } catch (e) { - error = e; - } + let error = options.error; + if (!error) { + try { + throw new Error(message()); + } catch (e) { + error = e; } - return stackFormatter(error); } + return stackFormatter(error); } +} - return buildExpectationResult; -}; +module.exports = buildExpectationResult; diff --git a/packages/jest-jasmine2/src/jasmine-light.js b/packages/jest-jasmine2/src/jasmine-light.js index e9d203c02b77..5161d5da71bd 100644 --- a/packages/jest-jasmine2/src/jasmine-light.js +++ b/packages/jest-jasmine2/src/jasmine-light.js @@ -41,19 +41,19 @@ exports.create = function() { const j$ = {}; exports.base(j$); - j$.buildExpectationResult = buildExpectationResult(); + j$.buildExpectationResult = buildExpectationResult; j$.CallTracker = CallTracker(j$); j$.Env = Env(j$); - j$.ExceptionFormatter = ExceptionFormatter(); - j$.JsApiReporter = JsApiReporter(); + j$.ExceptionFormatter = ExceptionFormatter; + j$.JsApiReporter = JsApiReporter; j$.QueueRunner = QueueRunner(j$); - j$.ReportDispatcher = ReportDispatcher(); + j$.ReportDispatcher = ReportDispatcher; j$.Spec = Spec(j$); j$.SpyRegistry = SpyRegistry(j$); j$.SpyStrategy = SpyStrategy(j$); j$.Suite = Suite(j$); - j$.Timer = Timer(); - j$.TreeProcessor = TreeProcessor(); + j$.Timer = Timer; + j$.TreeProcessor = TreeProcessor; j$.version = '2.5.2-light'; return j$; From c7d557242faf1f93dad84a1b3e05bec1a548085a Mon Sep 17 00:00:00 2001 From: wtgtybhertgeghgtwtg Date: Thu, 16 Mar 2017 09:00:54 -0700 Subject: [PATCH 3/8] Don't wrap things that don't need to be wrapped (again). --- packages/jest-jasmine2/src/CallTracker.js | 74 +++-- packages/jest-jasmine2/src/QueueRunner.js | 218 ++++++++------- packages/jest-jasmine2/src/Spec.js | 288 ++++++++++---------- packages/jest-jasmine2/src/SpyStrategy.js | 6 +- packages/jest-jasmine2/src/Suite.js | 264 +++++++++--------- packages/jest-jasmine2/src/jasmine-light.js | 10 +- 6 files changed, 425 insertions(+), 435 deletions(-) diff --git a/packages/jest-jasmine2/src/CallTracker.js b/packages/jest-jasmine2/src/CallTracker.js index 3af6ba401239..7195f5f395a4 100644 --- a/packages/jest-jasmine2/src/CallTracker.js +++ b/packages/jest-jasmine2/src/CallTracker.js @@ -23,52 +23,50 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. /* eslint-disable sort-keys */ 'use strict'; -module.exports = function(j$) { - function CallTracker() { - let calls = []; +function CallTracker() { + let calls = []; - this.track = function(context) { - calls.push(context); - }; + this.track = function(context) { + calls.push(context); + }; - this.any = function() { - return !!calls.length; - }; + this.any = function() { + return !!calls.length; + }; - this.count = function() { - return calls.length; - }; + this.count = function() { + return calls.length; + }; - this.argsFor = function(index) { - const call = calls[index]; - return call ? call.args : []; - }; + this.argsFor = function(index) { + const call = calls[index]; + return call ? call.args : []; + }; - this.all = function() { - return calls; - }; + this.all = function() { + return calls; + }; - this.allArgs = function() { - const callArgs = []; - for (let i = 0; i < calls.length; i++) { - callArgs.push(calls[i].args); - } + this.allArgs = function() { + const callArgs = []; + for (let i = 0; i < calls.length; i++) { + callArgs.push(calls[i].args); + } - return callArgs; - }; + return callArgs; + }; - this.first = function() { - return calls[0]; - }; + this.first = function() { + return calls[0]; + }; - this.mostRecent = function() { - return calls[calls.length - 1]; - }; + this.mostRecent = function() { + return calls[calls.length - 1]; + }; - this.reset = function() { - calls = []; - }; - } + this.reset = function() { + calls = []; + }; +} - return CallTracker; -}; +module.exports = CallTracker; diff --git a/packages/jest-jasmine2/src/QueueRunner.js b/packages/jest-jasmine2/src/QueueRunner.js index 409a9e59402e..2d69f1961468 100644 --- a/packages/jest-jasmine2/src/QueueRunner.js +++ b/packages/jest-jasmine2/src/QueueRunner.js @@ -23,129 +23,127 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. /* eslint-disable sort-keys */ 'use strict'; -module.exports = function(j$) { - function once(fn) { - let called = false; - return function() { - if (!called) { - called = true; - fn(); - } - return null; +function once(fn) { + let called = false; + return function() { + if (!called) { + called = true; + fn(); + } + return null; + }; +} + +function QueueRunner(attrs) { + this.queueableFns = attrs.queueableFns || []; + this.onComplete = attrs.onComplete || function() {}; + this.clearStack = attrs.clearStack || + function(fn) { + fn(); }; - } - - function QueueRunner(attrs) { - this.queueableFns = attrs.queueableFns || []; - this.onComplete = attrs.onComplete || function() {}; - this.clearStack = attrs.clearStack || - function(fn) { - fn(); - }; - this.onException = attrs.onException || function() {}; - this.catchException = attrs.catchException || - function() { - return true; - }; - this.userContext = attrs.userContext || {}; - this.timeout = attrs.timeout || { - setTimeout, - clearTimeout, + this.onException = attrs.onException || function() {}; + this.catchException = attrs.catchException || + function() { + return true; }; - this.fail = attrs.fail || function() {}; - } - - QueueRunner.prototype.execute = function() { - this.run(this.queueableFns, 0); + this.userContext = attrs.userContext || {}; + this.timeout = attrs.timeout || { + setTimeout, + clearTimeout, }; + this.fail = attrs.fail || function() {}; +} - QueueRunner.prototype.run = function(queueableFns, recursiveIndex) { - const length = queueableFns.length; - const self = this; - let iterativeIndex; - - for ( - iterativeIndex = recursiveIndex; - iterativeIndex < length; - iterativeIndex++ - ) { - const queueableFn = queueableFns[iterativeIndex]; - if (queueableFn.fn.length > 0) { - attemptAsync(queueableFn); - return; - } else { - attemptSync(queueableFn); - } +QueueRunner.prototype.execute = function() { + this.run(this.queueableFns, 0); +}; + +QueueRunner.prototype.run = function(queueableFns, recursiveIndex) { + const length = queueableFns.length; + const self = this; + let iterativeIndex; + + for ( + iterativeIndex = recursiveIndex; + iterativeIndex < length; + iterativeIndex++ + ) { + const queueableFn = queueableFns[iterativeIndex]; + if (queueableFn.fn.length > 0) { + attemptAsync(queueableFn); + return; + } else { + attemptSync(queueableFn); } + } - const runnerDone = iterativeIndex >= length; + const runnerDone = iterativeIndex >= length; - if (runnerDone) { - this.clearStack(this.onComplete); - } + if (runnerDone) { + this.clearStack(this.onComplete); + } - function attemptSync(queueableFn) { - try { - queueableFn.fn.call(self.userContext); - } catch (e) { - handleException(e, queueableFn); - } + function attemptSync(queueableFn) { + try { + queueableFn.fn.call(self.userContext); + } catch (e) { + handleException(e, queueableFn); } + } - function attemptAsync(queueableFn) { - const clearTimeout = function() { - Function.prototype.apply.apply(self.timeout.clearTimeout, [ - global, - [timeoutId], - ]); - }; - const next = once(() => { - clearTimeout(timeoutId); - self.run(queueableFns, iterativeIndex + 1); - }); - let timeoutId; - - next.fail = function() { - self.fail.apply(null, arguments); - next(); - }; - - if (queueableFn.timeout) { - timeoutId = Function.prototype.apply.apply(self.timeout.setTimeout, [ - global, - [ - function() { - const error = new Error( - 'Timeout - Async callback was not invoked within ' + - 'timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.', - ); - onException(error); - next(); - }, - queueableFn.timeout(), - ], - ]); - } - - try { - queueableFn.fn.call(self.userContext, next); - } catch (e) { - handleException(e, queueableFn); - next(); - } - } + function attemptAsync(queueableFn) { + const clearTimeout = function() { + Function.prototype.apply.apply(self.timeout.clearTimeout, [ + global, + [timeoutId], + ]); + }; + const next = once(() => { + clearTimeout(timeoutId); + self.run(queueableFns, iterativeIndex + 1); + }); + let timeoutId; + + next.fail = function() { + self.fail.apply(null, arguments); + next(); + }; - function onException(e) { - self.onException(e); + if (queueableFn.timeout) { + timeoutId = Function.prototype.apply.apply(self.timeout.setTimeout, [ + global, + [ + function() { + const error = new Error( + 'Timeout - Async callback was not invoked within ' + + 'timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.', + ); + onException(error); + next(); + }, + queueableFn.timeout(), + ], + ]); } - function handleException(e, queueableFn) { - onException(e); - if (!self.catchException(e)) { - throw e; - } + try { + queueableFn.fn.call(self.userContext, next); + } catch (e) { + handleException(e, queueableFn); + next(); } - }; + } - return QueueRunner; + function onException(e) { + self.onException(e); + } + + function handleException(e, queueableFn) { + onException(e); + if (!self.catchException(e)) { + throw e; + } + } }; + +module.exports = QueueRunner diff --git a/packages/jest-jasmine2/src/Spec.js b/packages/jest-jasmine2/src/Spec.js index c7f110a1f47f..09ccc70deb38 100644 --- a/packages/jest-jasmine2/src/Spec.js +++ b/packages/jest-jasmine2/src/Spec.js @@ -25,175 +25,173 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. const ExpectationFailed = require('./ExpectationFailed'); -module.exports = function(j$) { - function Spec(attrs) { - this.expectationFactory = attrs.expectationFactory; - this.resultCallback = attrs.resultCallback || function() {}; - this.id = attrs.id; - this.description = attrs.description || ''; - this.queueableFn = attrs.queueableFn; - this.beforeAndAfterFns = attrs.beforeAndAfterFns || - function() { - return {befores: [], afters: []}; - }; - this.userContext = attrs.userContext || - function() { - return {}; - }; - this.onStart = attrs.onStart || function() {}; - this.getSpecName = attrs.getSpecName || - function() { - return ''; - }; - this.expectationResultFactory = attrs.expectationResultFactory || - function() {}; - this.queueRunnerFactory = attrs.queueRunnerFactory || function() {}; - this.catchingExceptions = attrs.catchingExceptions || - function() { - return true; - }; - this.throwOnExpectationFailure = !!attrs.throwOnExpectationFailure; - - if (!this.queueableFn.fn) { - this.pend(); - } - - this.result = { - id: this.id, - description: this.description, - fullName: this.getFullName(), - failedExpectations: [], - passedExpectations: [], - pendingReason: '', +function Spec(attrs) { + this.expectationFactory = attrs.expectationFactory; + this.resultCallback = attrs.resultCallback || function() {}; + this.id = attrs.id; + this.description = attrs.description || ''; + this.queueableFn = attrs.queueableFn; + this.beforeAndAfterFns = attrs.beforeAndAfterFns || + function() { + return {befores: [], afters: []}; + }; + this.userContext = attrs.userContext || + function() { + return {}; }; + this.onStart = attrs.onStart || function() {}; + this.getSpecName = attrs.getSpecName || + function() { + return ''; + }; + this.expectationResultFactory = attrs.expectationResultFactory || + function() {}; + this.queueRunnerFactory = attrs.queueRunnerFactory || function() {}; + this.catchingExceptions = attrs.catchingExceptions || + function() { + return true; + }; + this.throwOnExpectationFailure = !!attrs.throwOnExpectationFailure; + + if (!this.queueableFn.fn) { + this.pend(); } - Spec.prototype.addExpectationResult = function(passed, data, isError) { - const expectationResult = this.expectationResultFactory(data); - if (passed) { - this.result.passedExpectations.push(expectationResult); - } else { - this.result.failedExpectations.push(expectationResult); + this.result = { + id: this.id, + description: this.description, + fullName: this.getFullName(), + failedExpectations: [], + passedExpectations: [], + pendingReason: '', + }; +} + +Spec.prototype.addExpectationResult = function(passed, data, isError) { + const expectationResult = this.expectationResultFactory(data); + if (passed) { + this.result.passedExpectations.push(expectationResult); + } else { + this.result.failedExpectations.push(expectationResult); - if (this.throwOnExpectationFailure && !isError) { - throw new ExpectationFailed(); - } + if (this.throwOnExpectationFailure && !isError) { + throw new ExpectationFailed(); } - }; + } +}; - Spec.prototype.execute = function(onComplete, enabled) { - const self = this; +Spec.prototype.execute = function(onComplete, enabled) { + const self = this; - this.onStart(this); + this.onStart(this); - if (!this.isExecutable() || this.markedPending || enabled === false) { - complete(enabled); - return; - } + if (!this.isExecutable() || this.markedPending || enabled === false) { + complete(enabled); + return; + } - const fns = this.beforeAndAfterFns(); - const allFns = fns.befores.concat(this.queueableFn).concat(fns.afters); - - this.queueRunnerFactory({ - queueableFns: allFns, - onException() { - self.onException.apply(self, arguments); - }, - onComplete: complete, - userContext: this.userContext(), - }); - - function complete(enabledAgain) { - self.result.status = self.status(enabledAgain); - self.resultCallback(self.result); - - if (onComplete) { - onComplete(); - } - } - }; + const fns = this.beforeAndAfterFns(); + const allFns = fns.befores.concat(this.queueableFn).concat(fns.afters); - Spec.prototype.onException = function onException(e) { - if (Spec.isPendingSpecException(e)) { - this.pend(extractCustomPendingMessage(e)); - return; - } + this.queueRunnerFactory({ + queueableFns: allFns, + onException() { + self.onException.apply(self, arguments); + }, + onComplete: complete, + userContext: this.userContext(), + }); + + function complete(enabledAgain) { + self.result.status = self.status(enabledAgain); + self.resultCallback(self.result); - if (e instanceof ExpectationFailed) { - return; + if (onComplete) { + onComplete(); } + } +}; - this.addExpectationResult( - false, - { - matcherName: '', - passed: false, - expected: '', - actual: '', - error: e, - }, - true, - ); - }; +Spec.prototype.onException = function onException(e) { + if (Spec.isPendingSpecException(e)) { + this.pend(extractCustomPendingMessage(e)); + return; + } - Spec.prototype.disable = function() { - this.disabled = true; - }; + if (e instanceof ExpectationFailed) { + return; + } - Spec.prototype.pend = function(message) { - this.markedPending = true; - if (message) { - this.result.pendingReason = message; - } - }; + this.addExpectationResult( + false, + { + matcherName: '', + passed: false, + expected: '', + actual: '', + error: e, + }, + true, + ); +}; - Spec.prototype.getResult = function() { - this.result.status = this.status(); - return this.result; - }; +Spec.prototype.disable = function() { + this.disabled = true; +}; - Spec.prototype.status = function(enabled) { - if (this.disabled || enabled === false) { - return 'disabled'; - } +Spec.prototype.pend = function(message) { + this.markedPending = true; + if (message) { + this.result.pendingReason = message; + } +}; - if (this.markedPending) { - return 'pending'; - } +Spec.prototype.getResult = function() { + this.result.status = this.status(); + return this.result; +}; - if (this.result.failedExpectations.length > 0) { - return 'failed'; - } else { - return 'passed'; - } - }; +Spec.prototype.status = function(enabled) { + if (this.disabled || enabled === false) { + return 'disabled'; + } - Spec.prototype.isExecutable = function() { - return !this.disabled; - }; + if (this.markedPending) { + return 'pending'; + } - Spec.prototype.getFullName = function() { - return this.getSpecName(this); - }; + if (this.result.failedExpectations.length > 0) { + return 'failed'; + } else { + return 'passed'; + } +}; + +Spec.prototype.isExecutable = function() { + return !this.disabled; +}; - const extractCustomPendingMessage = function(e) { - const fullMessage = e.toString(); - const boilerplateStart = fullMessage.indexOf( - Spec.pendingSpecExceptionMessage, - ); - const boilerplateEnd = boilerplateStart + - Spec.pendingSpecExceptionMessage.length; +Spec.prototype.getFullName = function() { + return this.getSpecName(this); +}; - return fullMessage.substr(boilerplateEnd); - }; +const extractCustomPendingMessage = function(e) { + const fullMessage = e.toString(); + const boilerplateStart = fullMessage.indexOf( + Spec.pendingSpecExceptionMessage, + ); + const boilerplateEnd = boilerplateStart + + Spec.pendingSpecExceptionMessage.length; - Spec.pendingSpecExceptionMessage = '=> marked Pending'; + return fullMessage.substr(boilerplateEnd); +}; - Spec.isPendingSpecException = function(e) { - return !!(e && - e.toString && - e.toString().indexOf(Spec.pendingSpecExceptionMessage) !== -1); - }; +Spec.pendingSpecExceptionMessage = '=> marked Pending'; - return Spec; +Spec.isPendingSpecException = function(e) { + return !!(e && + e.toString && + e.toString().indexOf(Spec.pendingSpecExceptionMessage) !== -1); }; + +module.exports = Spec; diff --git a/packages/jest-jasmine2/src/SpyStrategy.js b/packages/jest-jasmine2/src/SpyStrategy.js index 5922d74a3458..a99b7119e7cd 100644 --- a/packages/jest-jasmine2/src/SpyStrategy.js +++ b/packages/jest-jasmine2/src/SpyStrategy.js @@ -23,8 +23,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. /* eslint-disable sort-keys */ 'use strict'; -module.exports = function(j$) { - function SpyStrategy(options) { +function SpyStrategy(options) { options = options || {}; const identity = options.name || 'unknown'; @@ -86,5 +85,4 @@ module.exports = function(j$) { }; } - return SpyStrategy; -}; +module.exports = SpyStrategy; diff --git a/packages/jest-jasmine2/src/Suite.js b/packages/jest-jasmine2/src/Suite.js index a5dde5b2d7bf..ee9920a7665a 100644 --- a/packages/jest-jasmine2/src/Suite.js +++ b/packages/jest-jasmine2/src/Suite.js @@ -25,163 +25,161 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. const ExpectationFailed = require('./ExpectationFailed'); -module.exports = function(j$) { - function Suite(attrs) { - this.env = attrs.env; - this.id = attrs.id; - this.parentSuite = attrs.parentSuite; - this.description = attrs.description; - this.expectationFactory = attrs.expectationFactory; - this.expectationResultFactory = attrs.expectationResultFactory; - this.throwOnExpectationFailure = !!attrs.throwOnExpectationFailure; - - this.beforeFns = []; - this.afterFns = []; - this.beforeAllFns = []; - this.afterAllFns = []; - this.disabled = false; - - this.children = []; - - this.result = { - id: this.id, - description: this.description, - fullName: this.getFullName(), - failedExpectations: [], - }; +function Suite(attrs) { + this.env = attrs.env; + this.id = attrs.id; + this.parentSuite = attrs.parentSuite; + this.description = attrs.description; + this.expectationFactory = attrs.expectationFactory; + this.expectationResultFactory = attrs.expectationResultFactory; + this.throwOnExpectationFailure = !!attrs.throwOnExpectationFailure; + + this.beforeFns = []; + this.afterFns = []; + this.beforeAllFns = []; + this.afterAllFns = []; + this.disabled = false; + + this.children = []; + + this.result = { + id: this.id, + description: this.description, + fullName: this.getFullName(), + failedExpectations: [], + }; +} + +Suite.prototype.getFullName = function() { + const fullName = []; + for ( + let parentSuite = this; + parentSuite; + parentSuite = parentSuite.parentSuite + ) { + if (parentSuite.parentSuite) { + fullName.unshift(parentSuite.description); + } } + return fullName.join(' '); +}; - Suite.prototype.getFullName = function() { - const fullName = []; - for ( - let parentSuite = this; - parentSuite; - parentSuite = parentSuite.parentSuite - ) { - if (parentSuite.parentSuite) { - fullName.unshift(parentSuite.description); - } - } - return fullName.join(' '); - }; +Suite.prototype.disable = function() { + this.disabled = true; +}; - Suite.prototype.disable = function() { - this.disabled = true; - }; +Suite.prototype.pend = function(message) { + this.markedPending = true; +}; - Suite.prototype.pend = function(message) { - this.markedPending = true; - }; +Suite.prototype.beforeEach = function(fn) { + this.beforeFns.unshift(fn); +}; - Suite.prototype.beforeEach = function(fn) { - this.beforeFns.unshift(fn); - }; +Suite.prototype.beforeAll = function(fn) { + this.beforeAllFns.push(fn); +}; - Suite.prototype.beforeAll = function(fn) { - this.beforeAllFns.push(fn); - }; +Suite.prototype.afterEach = function(fn) { + this.afterFns.unshift(fn); +}; - Suite.prototype.afterEach = function(fn) { - this.afterFns.unshift(fn); - }; +Suite.prototype.afterAll = function(fn) { + this.afterAllFns.push(fn); +}; - Suite.prototype.afterAll = function(fn) { - this.afterAllFns.push(fn); - }; +Suite.prototype.addChild = function(child) { + this.children.push(child); +}; - Suite.prototype.addChild = function(child) { - this.children.push(child); - }; +Suite.prototype.status = function() { + if (this.disabled) { + return 'disabled'; + } - Suite.prototype.status = function() { - if (this.disabled) { - return 'disabled'; - } + if (this.markedPending) { + return 'pending'; + } - if (this.markedPending) { - return 'pending'; - } + if (this.result.failedExpectations.length > 0) { + return 'failed'; + } else { + return 'finished'; + } +}; - if (this.result.failedExpectations.length > 0) { - return 'failed'; - } else { - return 'finished'; - } - }; +Suite.prototype.isExecutable = function() { + return !this.disabled; +}; - Suite.prototype.isExecutable = function() { - return !this.disabled; - }; +Suite.prototype.canBeReentered = function() { + return this.beforeAllFns.length === 0 && this.afterAllFns.length === 0; +}; - Suite.prototype.canBeReentered = function() { - return this.beforeAllFns.length === 0 && this.afterAllFns.length === 0; - }; +Suite.prototype.getResult = function() { + this.result.status = this.status(); + return this.result; +}; - Suite.prototype.getResult = function() { - this.result.status = this.status(); - return this.result; - }; +Suite.prototype.sharedUserContext = function() { + if (!this.sharedContext) { + this.sharedContext = {}; + } - Suite.prototype.sharedUserContext = function() { - if (!this.sharedContext) { - this.sharedContext = {}; - } + return this.sharedContext; +}; - return this.sharedContext; - }; +Suite.prototype.clonedSharedUserContext = function() { + return this.sharedUserContext(); +}; - Suite.prototype.clonedSharedUserContext = function() { - return this.sharedUserContext(); - }; +Suite.prototype.onException = function() { + if (arguments[0] instanceof ExpectationFailed) { + return; + } - Suite.prototype.onException = function() { - if (arguments[0] instanceof ExpectationFailed) { - return; + if (isAfterAll(this.children)) { + const data = { + matcherName: '', + passed: false, + expected: '', + actual: '', + error: arguments[0], + }; + this.result.failedExpectations.push(this.expectationResultFactory(data)); + } else { + for (let i = 0; i < this.children.length; i++) { + const child = this.children[i]; + child.onException.apply(child, arguments); } + } +}; - if (isAfterAll(this.children)) { - const data = { - matcherName: '', - passed: false, - expected: '', - actual: '', - error: arguments[0], - }; - this.result.failedExpectations.push(this.expectationResultFactory(data)); - } else { - for (let i = 0; i < this.children.length; i++) { - const child = this.children[i]; - child.onException.apply(child, arguments); - } +Suite.prototype.addExpectationResult = function() { + if (isAfterAll(this.children) && isFailure(arguments)) { + const data = arguments[1]; + this.result.failedExpectations.push(this.expectationResultFactory(data)); + if (this.throwOnExpectationFailure) { + throw new ExpectationFailed(); } - }; - - Suite.prototype.addExpectationResult = function() { - if (isAfterAll(this.children) && isFailure(arguments)) { - const data = arguments[1]; - this.result.failedExpectations.push(this.expectationResultFactory(data)); - if (this.throwOnExpectationFailure) { - throw new ExpectationFailed(); - } - } else { - for (let i = 0; i < this.children.length; i++) { - const child = this.children[i]; - try { - child.addExpectationResult.apply(child, arguments); - } catch (e) { - // keep going - } + } else { + for (let i = 0; i < this.children.length; i++) { + const child = this.children[i]; + try { + child.addExpectationResult.apply(child, arguments); + } catch (e) { + // keep going } } - }; - - function isAfterAll(children) { - return children && children[0].result.status; } +}; - function isFailure(args) { - return !args[0]; - } +function isAfterAll(children) { + return children && children[0].result.status; +} - return Suite; -}; +function isFailure(args) { + return !args[0]; +} + +module.exports = Suite; diff --git a/packages/jest-jasmine2/src/jasmine-light.js b/packages/jest-jasmine2/src/jasmine-light.js index 5161d5da71bd..d6c6833c8f83 100644 --- a/packages/jest-jasmine2/src/jasmine-light.js +++ b/packages/jest-jasmine2/src/jasmine-light.js @@ -42,16 +42,16 @@ exports.create = function() { exports.base(j$); j$.buildExpectationResult = buildExpectationResult; - j$.CallTracker = CallTracker(j$); + j$.CallTracker = CallTracker; j$.Env = Env(j$); j$.ExceptionFormatter = ExceptionFormatter; j$.JsApiReporter = JsApiReporter; - j$.QueueRunner = QueueRunner(j$); + j$.QueueRunner = QueueRunner; j$.ReportDispatcher = ReportDispatcher; - j$.Spec = Spec(j$); + j$.Spec = Spec; j$.SpyRegistry = SpyRegistry(j$); - j$.SpyStrategy = SpyStrategy(j$); - j$.Suite = Suite(j$); + j$.SpyStrategy = SpyStrategy; + j$.Suite = Suite; j$.Timer = Timer; j$.TreeProcessor = TreeProcessor; j$.version = '2.5.2-light'; From e8f1c3c848162bb86409e829addc01bc64b264e7 Mon Sep 17 00:00:00 2001 From: wtgtybhertgeghgtwtg Date: Thu, 16 Mar 2017 13:11:29 -0700 Subject: [PATCH 4/8] Lint. --- packages/jest-jasmine2/src/QueueRunner.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/jest-jasmine2/src/QueueRunner.js b/packages/jest-jasmine2/src/QueueRunner.js index 2d69f1961468..df7ecfe40146 100644 --- a/packages/jest-jasmine2/src/QueueRunner.js +++ b/packages/jest-jasmine2/src/QueueRunner.js @@ -146,4 +146,4 @@ QueueRunner.prototype.run = function(queueableFns, recursiveIndex) { } }; -module.exports = QueueRunner +module.exports = QueueRunner; From 92f3aa28ce142bd342448777affb01a6495aeb73 Mon Sep 17 00:00:00 2001 From: Michael Sharer Date: Thu, 16 Mar 2017 19:39:43 -0400 Subject: [PATCH 5/8] Adding NHL to companies that use Jest (#3163) --- website/siteConfig.js | 5 +++++ website/src/jest/img/logos/nhl.png | Bin 0 -> 46497 bytes 2 files changed, 5 insertions(+) create mode 100755 website/src/jest/img/logos/nhl.png diff --git a/website/siteConfig.js b/website/siteConfig.js index ba3845851d0f..e4eeaa2c10c9 100644 --- a/website/siteConfig.js +++ b/website/siteConfig.js @@ -173,6 +173,11 @@ const users = [ image: '/jest/img/logos/klm.png', infoLink: 'https://www.klm.com/', }, + { + caption: 'NHL', + image: '/jest/img/logos/nhl.png', + infoLink: 'https://www.nhl.com/', + }, { caption: 'Quiqup', image: '/jest/img/logos/quiqup.png', diff --git a/website/src/jest/img/logos/nhl.png b/website/src/jest/img/logos/nhl.png new file mode 100755 index 0000000000000000000000000000000000000000..44f7e4e4e23164e62ccc0a5e38f6c413eba16a4d GIT binary patch literal 46497 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 literal 0 HcmV?d00001 From 0de1642c3dcdefe3feb7046a9d8e53ca16608b1a Mon Sep 17 00:00:00 2001 From: wtgtybhertgeghgtwtg Date: Thu, 16 Mar 2017 17:22:23 -0700 Subject: [PATCH 6/8] [jest-jasmine2] Trim `jasmine` singleton. --- packages/jest-jasmine2/src/Env.js | 16 -- packages/jest-jasmine2/src/Spec.js | 5 - packages/jest-jasmine2/src/SpyRegistry.js | 176 +++++++++++--------- packages/jest-jasmine2/src/Suite.js | 2 - packages/jest-jasmine2/src/createSpy.js | 68 ++++++++ packages/jest-jasmine2/src/jasmine-light.js | 91 ++-------- 6 files changed, 171 insertions(+), 187 deletions(-) create mode 100644 packages/jest-jasmine2/src/createSpy.js diff --git a/packages/jest-jasmine2/src/Env.js b/packages/jest-jasmine2/src/Env.js index b611c97fc168..70f5ebf4f1d5 100644 --- a/packages/jest-jasmine2/src/Env.js +++ b/packages/jest-jasmine2/src/Env.js @@ -76,17 +76,6 @@ module.exports = function(j$) { return 'suite' + nextSuiteId++; }; - const expectationFactory = function(actual, spec) { - return j$.Expectation.Factory({ - actual, - addExpectationResult, - }); - - function addExpectationResult(passed, result) { - return spec.addExpectationResult(passed, result); - } - }; - const defaultResourcesForRunnable = function(id, parentRunnableId) { const resources = {spies: []}; @@ -199,10 +188,8 @@ module.exports = function(j$) { }; const topSuite = new j$.Suite({ - env: this, id: getNextSuiteId(), description: 'test', - expectationFactory, expectationResultFactory, }); defaultResourcesForRunnable(topSuite.id); @@ -295,11 +282,9 @@ module.exports = function(j$) { const suiteFactory = function(description) { const suite = new j$.Suite({ - env: self, id: getNextSuiteId(), description, parentSuite: currentDeclarationSuite, - expectationFactory, expectationResultFactory, throwOnExpectationFailure, }); @@ -388,7 +373,6 @@ module.exports = function(j$) { const spec = new j$.Spec({ id: getNextSpecId(), beforeAndAfterFns: beforeAndAfterFns(suite), - expectationFactory, resultCallback: specResultCallback, getSpecName(spec) { return getSpecName(spec, suite); diff --git a/packages/jest-jasmine2/src/Spec.js b/packages/jest-jasmine2/src/Spec.js index 09ccc70deb38..6614d6bba2cd 100644 --- a/packages/jest-jasmine2/src/Spec.js +++ b/packages/jest-jasmine2/src/Spec.js @@ -26,7 +26,6 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. const ExpectationFailed = require('./ExpectationFailed'); function Spec(attrs) { - this.expectationFactory = attrs.expectationFactory; this.resultCallback = attrs.resultCallback || function() {}; this.id = attrs.id; this.description = attrs.description || ''; @@ -47,10 +46,6 @@ function Spec(attrs) { this.expectationResultFactory = attrs.expectationResultFactory || function() {}; this.queueRunnerFactory = attrs.queueRunnerFactory || function() {}; - this.catchingExceptions = attrs.catchingExceptions || - function() { - return true; - }; this.throwOnExpectationFailure = !!attrs.throwOnExpectationFailure; if (!this.queueableFn.fn) { diff --git a/packages/jest-jasmine2/src/SpyRegistry.js b/packages/jest-jasmine2/src/SpyRegistry.js index dab0f626e456..1727e13d8d1e 100644 --- a/packages/jest-jasmine2/src/SpyRegistry.js +++ b/packages/jest-jasmine2/src/SpyRegistry.js @@ -23,6 +23,10 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. /* eslint-disable sort-keys */ 'use strict'; +const CallTracker = require('./CallTracker'); +const createSpy = require('./createSpy'); +const SpyStrategy = require('./SpyStrategy'); + const formatErrorMsg = function() { function generateErrorMsg(domain, usage) { const usageDefinition = usage ? '\nUsage: ' + usage : ''; @@ -35,98 +39,104 @@ const formatErrorMsg = function() { return generateErrorMsg; }; -module.exports = function(j$) { - const getErrorMsg = formatErrorMsg( - '', - 'spyOn(, )', - ); - - function SpyRegistry(options) { - options = options || {}; - const currentSpies = options.currentSpies || - function() { - return []; - }; - - this.allowRespy = function(allow) { - this.respy = allow; - }; - - this.spyOn = function(obj, methodName) { - if (obj === void 0) { - throw new Error( - getErrorMsg( - 'could not find an object to spy upon for ' + methodName + '()', - ), - ); - } - - if (methodName === void 0) { - throw new Error(getErrorMsg('No method name supplied')); - } - - if (obj[methodName] === void 0) { - throw new Error(getErrorMsg(methodName + '() method does not exist')); - } +function isSpy(putativeSpy) { + if (!putativeSpy) { + return false; + } + return putativeSpy.and instanceof SpyStrategy && + putativeSpy.calls instanceof CallTracker; +}; - if (obj[methodName] && j$.isSpy(obj[methodName])) { - if (this.respy) { - return obj[methodName]; - } else { - throw new Error( - getErrorMsg(methodName + ' has already been spied upon'), - ); - } - } +const getErrorMsg = formatErrorMsg( + '', + 'spyOn(, )', +); - let descriptor; - try { - descriptor = Object.getOwnPropertyDescriptor(obj, methodName); - } catch (e) { - // IE 8 doesn't support `definePropery` on non-DOM nodes - } +function SpyRegistry(options) { + options = options || {}; + const currentSpies = options.currentSpies || + function() { + return []; + }; - if (descriptor && !(descriptor.writable || descriptor.set)) { + this.allowRespy = function(allow) { + this.respy = allow; + }; + + this.spyOn = function(obj, methodName) { + if (obj === void 0) { + throw new Error( + getErrorMsg( + 'could not find an object to spy upon for ' + methodName + '()', + ), + ); + } + + if (methodName === void 0) { + throw new Error(getErrorMsg('No method name supplied')); + } + + if (obj[methodName] === void 0) { + throw new Error(getErrorMsg(methodName + '() method does not exist')); + } + + if (obj[methodName] && isSpy(obj[methodName])) { + if (this.respy) { + return obj[methodName]; + } else { throw new Error( - getErrorMsg( - methodName + ' is not declared writable or has no setter', - ), + getErrorMsg(methodName + ' has already been spied upon'), ); } - - const originalMethod = obj[methodName]; - const spiedMethod = j$.createSpy(methodName, originalMethod); - let restoreStrategy; - - if (Object.prototype.hasOwnProperty.call(obj, methodName)) { - restoreStrategy = function() { + } + + let descriptor; + try { + descriptor = Object.getOwnPropertyDescriptor(obj, methodName); + } catch (e) { + // IE 8 doesn't support `definePropery` on non-DOM nodes + } + + if (descriptor && !(descriptor.writable || descriptor.set)) { + throw new Error( + getErrorMsg( + methodName + ' is not declared writable or has no setter', + ), + ); + } + + const originalMethod = obj[methodName]; + const spiedMethod = createSpy(methodName, originalMethod); + let restoreStrategy; + + if (Object.prototype.hasOwnProperty.call(obj, methodName)) { + restoreStrategy = function() { + obj[methodName] = originalMethod; + }; + } else { + restoreStrategy = function() { + if (!delete obj[methodName]) { obj[methodName] = originalMethod; - }; - } else { - restoreStrategy = function() { - if (!delete obj[methodName]) { - obj[methodName] = originalMethod; - } - }; - } + } + }; + } - currentSpies().push({ - restoreObjectToOriginalState: restoreStrategy, - }); + currentSpies().push({ + restoreObjectToOriginalState: restoreStrategy, + }); - obj[methodName] = spiedMethod; + obj[methodName] = spiedMethod; - return spiedMethod; - }; + return spiedMethod; + }; - this.clearSpies = function() { - const spies = currentSpies(); - for (let i = spies.length - 1; i >= 0; i--) { - const spyEntry = spies[i]; - spyEntry.restoreObjectToOriginalState(); - } - }; - } + this.clearSpies = function() { + const spies = currentSpies(); + for (let i = spies.length - 1; i >= 0; i--) { + const spyEntry = spies[i]; + spyEntry.restoreObjectToOriginalState(); + } + }; +} - return SpyRegistry; -}; +module.exports = SpyRegistry; diff --git a/packages/jest-jasmine2/src/Suite.js b/packages/jest-jasmine2/src/Suite.js index ee9920a7665a..3cc17c0ab11b 100644 --- a/packages/jest-jasmine2/src/Suite.js +++ b/packages/jest-jasmine2/src/Suite.js @@ -26,11 +26,9 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. const ExpectationFailed = require('./ExpectationFailed'); function Suite(attrs) { - this.env = attrs.env; this.id = attrs.id; this.parentSuite = attrs.parentSuite; this.description = attrs.description; - this.expectationFactory = attrs.expectationFactory; this.expectationResultFactory = attrs.expectationResultFactory; this.throwOnExpectationFailure = !!attrs.throwOnExpectationFailure; diff --git a/packages/jest-jasmine2/src/createSpy.js b/packages/jest-jasmine2/src/createSpy.js new file mode 100644 index 000000000000..7377dcc0329c --- /dev/null +++ b/packages/jest-jasmine2/src/createSpy.js @@ -0,0 +1,68 @@ +/* +Copyright (c) 2008-2016 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. +*/ +/* eslint-disable sort-keys */ +'use strict'; + +const CallTracker = require('./CallTracker'); +const SpyStrategy = require('./SpyStrategy'); + +function createSpy(name, originalFn) { + const spyStrategy = new SpyStrategy({ + name, + fn: originalFn, + getSpy() { + return spy; + }, + }); + const callTracker = new CallTracker(); + const spy = function() { + const callData = { + object: this, + args: Array.prototype.slice.apply(arguments), + }; + + callTracker.track(callData); + const returnValue = spyStrategy.exec.apply(this, arguments); + callData.returnValue = returnValue; + + return returnValue; + }; + + for (const prop in originalFn) { + if (prop === 'and' || prop === 'calls') { + throw new Error( + "Jasmine spies would overwrite the 'and' and 'calls' properties " + + 'on the object being spied upon', + ); + } + + spy[prop] = originalFn[prop]; + } + + spy.and = spyStrategy; + spy.calls = callTracker; + + return spy; +}; + +module.exports = createSpy; diff --git a/packages/jest-jasmine2/src/jasmine-light.js b/packages/jest-jasmine2/src/jasmine-light.js index d6c6833c8f83..d0186a539603 100644 --- a/packages/jest-jasmine2/src/jasmine-light.js +++ b/packages/jest-jasmine2/src/jasmine-light.js @@ -24,7 +24,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 'use strict'; const buildExpectationResult = require('./buildExpectationResult'); -const CallTracker = require('./CallTracker'); +const createSpy = require('./createSpy'); const Env = require('./Env'); const ExceptionFormatter = require('./ExceptionFormatter'); const JsApiReporter = require('./JsApiReporter'); @@ -40,17 +40,22 @@ const TreeProcessor = require('./TreeProcessor'); exports.create = function() { const j$ = {}; - exports.base(j$); + j$.DEFAULT_TIMEOUT_INTERVAL = 5000; + + j$.getEnv = function(options) { + const env = (j$.currentEnv_ = j$.currentEnv_ || new j$.Env(options)); + //jasmine. singletons in here (setTimeout blah blah). + return env; + }; j$.buildExpectationResult = buildExpectationResult; - j$.CallTracker = CallTracker; + j$.createSpy = createSpy; j$.Env = Env(j$); j$.ExceptionFormatter = ExceptionFormatter; j$.JsApiReporter = JsApiReporter; j$.QueueRunner = QueueRunner; j$.ReportDispatcher = ReportDispatcher; j$.Spec = Spec; - j$.SpyRegistry = SpyRegistry(j$); - j$.SpyStrategy = SpyStrategy; + j$.SpyRegistry = SpyRegistry; j$.Suite = Suite; j$.Timer = Timer; j$.TreeProcessor = TreeProcessor; @@ -59,82 +64,6 @@ exports.create = function() { return j$; }; -exports.base = function(j$) { - j$.DEFAULT_TIMEOUT_INTERVAL = 5000; - - j$.getEnv = function(options) { - const env = (j$.currentEnv_ = j$.currentEnv_ || new j$.Env(options)); - //jasmine. singletons in here (setTimeout blah blah). - return env; - }; - - j$.createSpy = function(name, originalFn) { - const spyStrategy = new j$.SpyStrategy({ - name, - fn: originalFn, - getSpy() { - return spy; - }, - }); - const callTracker = new j$.CallTracker(); - const spy = function() { - const callData = { - object: this, - args: Array.prototype.slice.apply(arguments), - }; - - callTracker.track(callData); - const returnValue = spyStrategy.exec.apply(this, arguments); - callData.returnValue = returnValue; - - return returnValue; - }; - - for (const prop in originalFn) { - if (prop === 'and' || prop === 'calls') { - throw new Error( - "Jasmine spies would overwrite the 'and' and 'calls' properties " + - 'on the object being spied upon', - ); - } - - spy[prop] = originalFn[prop]; - } - - spy.and = spyStrategy; - spy.calls = callTracker; - - return spy; - }; - - j$.isSpy = function(putativeSpy) { - if (!putativeSpy) { - return false; - } - return putativeSpy.and instanceof j$.SpyStrategy && - putativeSpy.calls instanceof j$.CallTracker; - }; - - j$.createSpyObj = function(baseName, methodNames) { - if (Array.isArray(baseName) && methodNames === void 0) { - methodNames = baseName; - baseName = 'unknown'; - } - - if (!Array.isArray(methodNames) || methodNames.length === 0) { - throw new Error( - 'createSpyObj requires a non-empty array of method names to ' + - 'create spies for', - ); - } - const obj = {}; - for (let i = 0; i < methodNames.length; i++) { - obj[methodNames[i]] = j$.createSpy(baseName + '.' + methodNames[i]); - } - return obj; - }; -}; - exports.interface = function(jasmine, env) { const jasmineInterface = { describe(description, specDefinitions) { From 5b1bb61702075ce64091b99031e713efba131671 Mon Sep 17 00:00:00 2001 From: Andrew Imm Date: Thu, 16 Mar 2017 17:25:07 -0700 Subject: [PATCH 7/8] Support custom platforms on jest-haste-map (#3162) * Support custom platforms on jest-haste-map * Run prettier --- packages/jest-haste-map/src/index.js | 6 ++++-- packages/jest-haste-map/src/lib/getPlatformExtension.js | 9 ++++++++- packages/jest-matchers/src/asymmetric-matchers.js | 6 ++++-- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/packages/jest-haste-map/src/index.js b/packages/jest-haste-map/src/index.js index da7015cb170d..6d5f510dc8e8 100644 --- a/packages/jest-haste-map/src/index.js +++ b/packages/jest-haste-map/src/index.js @@ -305,8 +305,10 @@ class HasteMap extends EventEmitter { map[id] = Object.create(null); } const moduleMap = map[id]; - const platform = getPlatformExtension(module[H.PATH]) || - H.GENERIC_PLATFORM; + const platform = getPlatformExtension( + module[H.PATH], + this._options.platforms, + ) || H.GENERIC_PLATFORM; const existingModule = moduleMap[platform]; if (existingModule && existingModule[H.PATH] !== module[H.PATH]) { const message = `jest-haste-map: @providesModule naming collision:\n` + diff --git a/packages/jest-haste-map/src/lib/getPlatformExtension.js b/packages/jest-haste-map/src/lib/getPlatformExtension.js index fa211d075c64..f1b82e92abbb 100644 --- a/packages/jest-haste-map/src/lib/getPlatformExtension.js +++ b/packages/jest-haste-map/src/lib/getPlatformExtension.js @@ -17,13 +17,20 @@ const SUPPORTED_PLATFORM_EXTS = { }; // Extract platform extension: index.ios.js -> ios -function getPlatformExtension(file: string): ?string { +function getPlatformExtension( + file: string, + platforms?: Array, +): ?string { const last = file.lastIndexOf('.'); const secondToLast = file.lastIndexOf('.', last - 1); if (secondToLast === -1) { return null; } const platform = file.substring(secondToLast + 1, last); + // If an overriding platform array is passed, check that first + if (platforms && platforms.includes(platform)) { + return platform; + } return SUPPORTED_PLATFORM_EXTS[platform] ? platform : null; } diff --git a/packages/jest-matchers/src/asymmetric-matchers.js b/packages/jest-matchers/src/asymmetric-matchers.js index ac0ccbaa5303..b3ad1f32b895 100644 --- a/packages/jest-matchers/src/asymmetric-matchers.js +++ b/packages/jest-matchers/src/asymmetric-matchers.js @@ -130,8 +130,10 @@ class ArrayContaining extends AsymmetricMatcher { ); } - return this.sample.length === 0 || Array.isArray(other) && - this.sample.every(item => other.some(another => equals(item, another))); + return this.sample.length === 0 || + (Array.isArray(other) && + this.sample.every(item => + other.some(another => equals(item, another)))); } toString() { From b34ed149618d449c1c1e29f069d7d8578801cf6b Mon Sep 17 00:00:00 2001 From: wtgtybhertgeghgtwtg Date: Thu, 16 Mar 2017 20:02:12 -0700 Subject: [PATCH 8/8] Rebase. --- .../jest-jasmine2/src/{ => jasmine}/CallTracker.js | 10 ++++++++++ packages/jest-jasmine2/src/{ => jasmine}/Env.js | 10 ++++++++++ .../src/{ => jasmine}/ExceptionFormatter.js | 10 ++++++++++ .../src/{ => jasmine}/ExpectationFailed.js | 10 ++++++++++ .../jest-jasmine2/src/{ => jasmine}/JsApiReporter.js | 10 ++++++++++ .../jest-jasmine2/src/{ => jasmine}/QueueRunner.js | 10 ++++++++++ .../src/{ => jasmine}/ReportDispatcher.js | 10 ++++++++++ packages/jest-jasmine2/src/{ => jasmine}/Spec.js | 10 ++++++++++ .../jest-jasmine2/src/{ => jasmine}/SpyRegistry.js | 10 ++++++++++ .../jest-jasmine2/src/{ => jasmine}/SpyStrategy.js | 10 ++++++++++ packages/jest-jasmine2/src/{ => jasmine}/Suite.js | 10 ++++++++++ packages/jest-jasmine2/src/{ => jasmine}/Timer.js | 10 ++++++++++ .../jest-jasmine2/src/{ => jasmine}/TreeProcessor.js | 10 ++++++++++ .../src/{ => jasmine}/buildExpectationResult.js | 10 ++++++++++ packages/jest-jasmine2/src/{ => jasmine}/createSpy.js | 10 ++++++++++ .../jest-jasmine2/src/{ => jasmine}/jasmine-light.js | 10 ++++++++++ 16 files changed, 160 insertions(+) rename packages/jest-jasmine2/src/{ => jasmine}/CallTracker.js (82%) rename packages/jest-jasmine2/src/{ => jasmine}/Env.js (97%) rename packages/jest-jasmine2/src/{ => jasmine}/ExceptionFormatter.js (81%) rename packages/jest-jasmine2/src/{ => jasmine}/ExpectationFailed.js (50%) rename packages/jest-jasmine2/src/{ => jasmine}/JsApiReporter.js (86%) rename packages/jest-jasmine2/src/{ => jasmine}/QueueRunner.js (90%) rename packages/jest-jasmine2/src/{ => jasmine}/ReportDispatcher.js (84%) rename packages/jest-jasmine2/src/{ => jasmine}/Spec.js (92%) rename packages/jest-jasmine2/src/{ => jasmine}/SpyRegistry.js (90%) rename packages/jest-jasmine2/src/{ => jasmine}/SpyStrategy.js (86%) rename packages/jest-jasmine2/src/{ => jasmine}/Suite.js (91%) rename packages/jest-jasmine2/src/{ => jasmine}/Timer.js (78%) rename packages/jest-jasmine2/src/{ => jasmine}/TreeProcessor.js (94%) rename packages/jest-jasmine2/src/{ => jasmine}/buildExpectationResult.js (84%) rename packages/jest-jasmine2/src/{ => jasmine}/createSpy.js (83%) rename packages/jest-jasmine2/src/{ => jasmine}/jasmine-light.js (90%) diff --git a/packages/jest-jasmine2/src/CallTracker.js b/packages/jest-jasmine2/src/jasmine/CallTracker.js similarity index 82% rename from packages/jest-jasmine2/src/CallTracker.js rename to packages/jest-jasmine2/src/jasmine/CallTracker.js index 7195f5f395a4..8a16d12f072b 100644 --- a/packages/jest-jasmine2/src/CallTracker.js +++ b/packages/jest-jasmine2/src/jasmine/CallTracker.js @@ -1,3 +1,13 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @flow + */ +// This file is a heavily modified fork of Jasmine. The original license of the code: /* Copyright (c) 2008-2016 Pivotal Labs diff --git a/packages/jest-jasmine2/src/Env.js b/packages/jest-jasmine2/src/jasmine/Env.js similarity index 97% rename from packages/jest-jasmine2/src/Env.js rename to packages/jest-jasmine2/src/jasmine/Env.js index 70f5ebf4f1d5..b00aee618f65 100644 --- a/packages/jest-jasmine2/src/Env.js +++ b/packages/jest-jasmine2/src/jasmine/Env.js @@ -1,3 +1,13 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @flow + */ +// This file is a heavily modified fork of Jasmine. The original license of the code: /* Copyright (c) 2008-2016 Pivotal Labs diff --git a/packages/jest-jasmine2/src/ExceptionFormatter.js b/packages/jest-jasmine2/src/jasmine/ExceptionFormatter.js similarity index 81% rename from packages/jest-jasmine2/src/ExceptionFormatter.js rename to packages/jest-jasmine2/src/jasmine/ExceptionFormatter.js index 24ffb26d885f..c604536332b2 100644 --- a/packages/jest-jasmine2/src/ExceptionFormatter.js +++ b/packages/jest-jasmine2/src/jasmine/ExceptionFormatter.js @@ -1,3 +1,13 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @flow + */ +// This file is a heavily modified fork of Jasmine. The original license of the code: /* Copyright (c) 2008-2016 Pivotal Labs diff --git a/packages/jest-jasmine2/src/ExpectationFailed.js b/packages/jest-jasmine2/src/jasmine/ExpectationFailed.js similarity index 50% rename from packages/jest-jasmine2/src/ExpectationFailed.js rename to packages/jest-jasmine2/src/jasmine/ExpectationFailed.js index 34b22549bce6..245876d89b01 100644 --- a/packages/jest-jasmine2/src/ExpectationFailed.js +++ b/packages/jest-jasmine2/src/jasmine/ExpectationFailed.js @@ -1,3 +1,13 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @flow + */ +// This file is a heavily modified fork of Jasmine. The original license of the code: /** * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. * diff --git a/packages/jest-jasmine2/src/JsApiReporter.js b/packages/jest-jasmine2/src/jasmine/JsApiReporter.js similarity index 86% rename from packages/jest-jasmine2/src/JsApiReporter.js rename to packages/jest-jasmine2/src/jasmine/JsApiReporter.js index c29bcdf28cd2..6254180e01ef 100644 --- a/packages/jest-jasmine2/src/JsApiReporter.js +++ b/packages/jest-jasmine2/src/jasmine/JsApiReporter.js @@ -1,3 +1,13 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @flow + */ +// This file is a heavily modified fork of Jasmine. The original license of the code: /* Copyright (c) 2008-2016 Pivotal Labs diff --git a/packages/jest-jasmine2/src/QueueRunner.js b/packages/jest-jasmine2/src/jasmine/QueueRunner.js similarity index 90% rename from packages/jest-jasmine2/src/QueueRunner.js rename to packages/jest-jasmine2/src/jasmine/QueueRunner.js index df7ecfe40146..9959cc852259 100644 --- a/packages/jest-jasmine2/src/QueueRunner.js +++ b/packages/jest-jasmine2/src/jasmine/QueueRunner.js @@ -1,3 +1,13 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @flow + */ +// This file is a heavily modified fork of Jasmine. The original license of the code: /* Copyright (c) 2008-2016 Pivotal Labs diff --git a/packages/jest-jasmine2/src/ReportDispatcher.js b/packages/jest-jasmine2/src/jasmine/ReportDispatcher.js similarity index 84% rename from packages/jest-jasmine2/src/ReportDispatcher.js rename to packages/jest-jasmine2/src/jasmine/ReportDispatcher.js index 1357be765b3e..ca24f9277a8c 100644 --- a/packages/jest-jasmine2/src/ReportDispatcher.js +++ b/packages/jest-jasmine2/src/jasmine/ReportDispatcher.js @@ -1,3 +1,13 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @flow + */ +// This file is a heavily modified fork of Jasmine. The original license of the code: /* Copyright (c) 2008-2016 Pivotal Labs diff --git a/packages/jest-jasmine2/src/Spec.js b/packages/jest-jasmine2/src/jasmine/Spec.js similarity index 92% rename from packages/jest-jasmine2/src/Spec.js rename to packages/jest-jasmine2/src/jasmine/Spec.js index 6614d6bba2cd..c096b42449aa 100644 --- a/packages/jest-jasmine2/src/Spec.js +++ b/packages/jest-jasmine2/src/jasmine/Spec.js @@ -1,3 +1,13 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @flow + */ +// This file is a heavily modified fork of Jasmine. The original license of the code: /* Copyright (c) 2008-2016 Pivotal Labs diff --git a/packages/jest-jasmine2/src/SpyRegistry.js b/packages/jest-jasmine2/src/jasmine/SpyRegistry.js similarity index 90% rename from packages/jest-jasmine2/src/SpyRegistry.js rename to packages/jest-jasmine2/src/jasmine/SpyRegistry.js index 1727e13d8d1e..9b0e725290bf 100644 --- a/packages/jest-jasmine2/src/SpyRegistry.js +++ b/packages/jest-jasmine2/src/jasmine/SpyRegistry.js @@ -1,3 +1,13 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @flow + */ +// This file is a heavily modified fork of Jasmine. The original license of the code: /* Copyright (c) 2008-2016 Pivotal Labs diff --git a/packages/jest-jasmine2/src/SpyStrategy.js b/packages/jest-jasmine2/src/jasmine/SpyStrategy.js similarity index 86% rename from packages/jest-jasmine2/src/SpyStrategy.js rename to packages/jest-jasmine2/src/jasmine/SpyStrategy.js index a99b7119e7cd..4d238a729524 100644 --- a/packages/jest-jasmine2/src/SpyStrategy.js +++ b/packages/jest-jasmine2/src/jasmine/SpyStrategy.js @@ -1,3 +1,13 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @flow + */ +// This file is a heavily modified fork of Jasmine. The original license of the code: /* Copyright (c) 2008-2016 Pivotal Labs diff --git a/packages/jest-jasmine2/src/Suite.js b/packages/jest-jasmine2/src/jasmine/Suite.js similarity index 91% rename from packages/jest-jasmine2/src/Suite.js rename to packages/jest-jasmine2/src/jasmine/Suite.js index 3cc17c0ab11b..ead151d8baeb 100644 --- a/packages/jest-jasmine2/src/Suite.js +++ b/packages/jest-jasmine2/src/jasmine/Suite.js @@ -1,3 +1,13 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @flow + */ +// This file is a heavily modified fork of Jasmine. The original license of the code: /* Copyright (c) 2008-2016 Pivotal Labs diff --git a/packages/jest-jasmine2/src/Timer.js b/packages/jest-jasmine2/src/jasmine/Timer.js similarity index 78% rename from packages/jest-jasmine2/src/Timer.js rename to packages/jest-jasmine2/src/jasmine/Timer.js index 93fa55da10d9..f1acb529b6a8 100644 --- a/packages/jest-jasmine2/src/Timer.js +++ b/packages/jest-jasmine2/src/jasmine/Timer.js @@ -1,3 +1,13 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @flow + */ +// This file is a heavily modified fork of Jasmine. The original license of the code: /* Copyright (c) 2008-2016 Pivotal Labs diff --git a/packages/jest-jasmine2/src/TreeProcessor.js b/packages/jest-jasmine2/src/jasmine/TreeProcessor.js similarity index 94% rename from packages/jest-jasmine2/src/TreeProcessor.js rename to packages/jest-jasmine2/src/jasmine/TreeProcessor.js index 9367b40f119b..663d7f703edb 100644 --- a/packages/jest-jasmine2/src/TreeProcessor.js +++ b/packages/jest-jasmine2/src/jasmine/TreeProcessor.js @@ -1,3 +1,13 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @flow + */ +// This file is a heavily modified fork of Jasmine. The original license of the code: /* Copyright (c) 2008-2016 Pivotal Labs diff --git a/packages/jest-jasmine2/src/buildExpectationResult.js b/packages/jest-jasmine2/src/jasmine/buildExpectationResult.js similarity index 84% rename from packages/jest-jasmine2/src/buildExpectationResult.js rename to packages/jest-jasmine2/src/jasmine/buildExpectationResult.js index 6ad6e104b75b..f099207ec9b8 100644 --- a/packages/jest-jasmine2/src/buildExpectationResult.js +++ b/packages/jest-jasmine2/src/jasmine/buildExpectationResult.js @@ -1,3 +1,13 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @flow + */ +// This file is a heavily modified fork of Jasmine. The original license of the code: /* Copyright (c) 2008-2016 Pivotal Labs diff --git a/packages/jest-jasmine2/src/createSpy.js b/packages/jest-jasmine2/src/jasmine/createSpy.js similarity index 83% rename from packages/jest-jasmine2/src/createSpy.js rename to packages/jest-jasmine2/src/jasmine/createSpy.js index 7377dcc0329c..4fba94d86c3f 100644 --- a/packages/jest-jasmine2/src/createSpy.js +++ b/packages/jest-jasmine2/src/jasmine/createSpy.js @@ -1,3 +1,13 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @flow + */ +// This file is a heavily modified fork of Jasmine. The original license of the code: /* Copyright (c) 2008-2016 Pivotal Labs diff --git a/packages/jest-jasmine2/src/jasmine-light.js b/packages/jest-jasmine2/src/jasmine/jasmine-light.js similarity index 90% rename from packages/jest-jasmine2/src/jasmine-light.js rename to packages/jest-jasmine2/src/jasmine/jasmine-light.js index d0186a539603..e23fbd3a3813 100644 --- a/packages/jest-jasmine2/src/jasmine-light.js +++ b/packages/jest-jasmine2/src/jasmine/jasmine-light.js @@ -1,3 +1,13 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @flow + */ +// This file is a heavily modified fork of Jasmine. The original license of the code: /* Copyright (c) 2008-2016 Pivotal Labs