From 9672689d40ce77329fc604de83eb94e88bbc3237 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Fri, 12 May 2017 14:42:14 -0700 Subject: [PATCH] Added support for ES2017 async functions --- spec/core/EnvSpec.js | 42 ++++++++++++++++++++++++++++++++++++++ spec/helpers/asyncAwait.js | 27 ++++++++++++++++++++++++ spec/support/jasmine.json | 1 + spec/support/jasmine.yml | 1 + src/core/Env.js | 20 +++++++++++------- src/core/base.js | 4 ++++ 6 files changed, 88 insertions(+), 7 deletions(-) create mode 100644 spec/helpers/asyncAwait.js diff --git a/spec/core/EnvSpec.js b/spec/core/EnvSpec.js index 61c52511..bf239707 100644 --- a/spec/core/EnvSpec.js +++ b/spec/core/EnvSpec.js @@ -91,6 +91,13 @@ describe("Env", function() { env.it('pending spec'); }).not.toThrow(); }); + + it('accepts an async function', function() { + jasmine.getEnv().requireAsyncAwait(); + expect(function() { + env.it('async', jasmine.getEnv().makeAsyncAwaitFunction()); + }).not.toThrow(); + }); }); describe('#xit', function() { @@ -114,6 +121,13 @@ describe("Env", function() { env.xit('pending spec'); }).not.toThrow(); }); + + it('accepts an async function', function() { + jasmine.getEnv().requireAsyncAwait(); + expect(function() { + env.xit('async', jasmine.getEnv().makeAsyncAwaitFunction()); + }).not.toThrow(); + }); }); describe('#fit', function () { @@ -130,6 +144,13 @@ describe("Env", function() { env.beforeEach(undefined); }).toThrowError(/beforeEach expects a function argument; received \[object (Undefined|DOMWindow|Object)\]/); }); + + it('accepts an async function', function() { + jasmine.getEnv().requireAsyncAwait(); + expect(function() { + env.beforeEach(jasmine.getEnv().makeAsyncAwaitFunction()); + }).not.toThrow(); + }); }); describe('#beforeAll', function () { @@ -138,6 +159,13 @@ describe("Env", function() { env.beforeAll(undefined); }).toThrowError(/beforeAll expects a function argument; received \[object (Undefined|DOMWindow|Object)\]/); }); + + it('accepts an async function', function() { + jasmine.getEnv().requireAsyncAwait(); + expect(function() { + env.beforeAll(jasmine.getEnv().makeAsyncAwaitFunction()); + }).not.toThrow(); + }); }); describe('#afterEach', function () { @@ -146,6 +174,13 @@ describe("Env", function() { env.afterEach(undefined); }).toThrowError(/afterEach expects a function argument; received \[object (Undefined|DOMWindow|Object)\]/); }); + + it('accepts an async function', function() { + jasmine.getEnv().requireAsyncAwait(); + expect(function() { + env.afterEach(jasmine.getEnv().makeAsyncAwaitFunction()); + }).not.toThrow(); + }); }); describe('#afterAll', function () { @@ -154,5 +189,12 @@ describe("Env", function() { env.afterAll(undefined); }).toThrowError(/afterAll expects a function argument; received \[object (Undefined|DOMWindow|Object)\]/); }); + + it('accepts an async function', function() { + jasmine.getEnv().requireAsyncAwait(); + expect(function() { + env.afterAll(jasmine.getEnv().makeAsyncAwaitFunction()); + }).not.toThrow(); + }); }); }); diff --git a/spec/helpers/asyncAwait.js b/spec/helpers/asyncAwait.js new file mode 100644 index 00000000..866d9526 --- /dev/null +++ b/spec/helpers/asyncAwait.js @@ -0,0 +1,27 @@ +(function(env) { + function getAsyncCtor() { + try { + eval("var func = async function(){};"); + } catch (e) { + return null; + } + + return Object.getPrototypeOf(func).constructor; + } + + function hasAsyncAwaitSupport() { + return getAsyncCtor() !== null; + } + + env.makeAsyncAwaitFunction = function() { + var AsyncFunction = getAsyncCtor(); + return new AsyncFunction(""); + }; + + env.requireAsyncAwait = function() { + if (!hasAsyncAwaitSupport()) { + env.pending("Environment does not support async/await functions"); + } + }; +})(jasmine.getEnv()); + diff --git a/spec/support/jasmine.json b/spec/support/jasmine.json index 83b19dbb..01f1d828 100644 --- a/spec/support/jasmine.json +++ b/spec/support/jasmine.json @@ -6,6 +6,7 @@ "npmPackage/**/*.js" ], "helpers": [ + "helpers/asyncAwait.js", "helpers/checkForSet.js", "helpers/nodeDefineJasmineUnderTest.js" ], diff --git a/spec/support/jasmine.yml b/spec/support/jasmine.yml index da959031..053f67e8 100644 --- a/spec/support/jasmine.yml +++ b/spec/support/jasmine.yml @@ -16,6 +16,7 @@ src_files: - '**/*.js' stylesheets: helpers: + - 'helpers/asyncAwait.js' - 'helpers/BrowserFlags.js' - 'helpers/checkForSet.js' - 'helpers/defineJasmineUnderTest.js' diff --git a/src/core/Env.js b/src/core/Env.js index 81927ed9..6d7ae755 100644 --- a/src/core/Env.js +++ b/src/core/Env.js @@ -319,6 +319,12 @@ getJasmineRequireObj().Env = function(j$) { } }; + var ensureIsFunctionOrAsync = function(fn, caller) { + if (!j$.isFunction_(fn) && !j$.isAsyncFunction_(fn)) { + throw new Error(caller + ' expects a function argument; received ' + j$.getType_(fn)); + } + }; + var suiteFactory = function(description) { var suite = new j$.Suite({ env: self, @@ -457,7 +463,7 @@ getJasmineRequireObj().Env = function(j$) { // it() sometimes doesn't have a fn argument, so only check the type if // it's given. if (arguments.length > 1 && typeof fn !== 'undefined') { - ensureIsFunction(fn, 'it'); + ensureIsFunctionOrAsync(fn, 'it'); } var spec = specFactory(description, fn, currentDeclarationSuite, timeout); if (currentDeclarationSuite.markedPending) { @@ -471,7 +477,7 @@ getJasmineRequireObj().Env = function(j$) { // xit(), like it(), doesn't always have a fn argument, so only check the // type when needed. if (arguments.length > 1 && typeof fn !== 'undefined') { - ensureIsFunction(fn, 'xit'); + ensureIsFunctionOrAsync(fn, 'xit'); } var spec = this.it.apply(this, arguments); spec.pend('Temporarily disabled with xit'); @@ -479,7 +485,7 @@ getJasmineRequireObj().Env = function(j$) { }; this.fit = function(description, fn, timeout){ - ensureIsFunction(fn, 'fit'); + ensureIsFunctionOrAsync(fn, 'fit'); var spec = specFactory(description, fn, currentDeclarationSuite, timeout); currentDeclarationSuite.addChild(spec); focusedRunnables.push(spec.id); @@ -496,7 +502,7 @@ getJasmineRequireObj().Env = function(j$) { }; this.beforeEach = function(beforeEachFunction, timeout) { - ensureIsFunction(beforeEachFunction, 'beforeEach'); + ensureIsFunctionOrAsync(beforeEachFunction, 'beforeEach'); currentDeclarationSuite.beforeEach({ fn: beforeEachFunction, timeout: function() { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; } @@ -504,7 +510,7 @@ getJasmineRequireObj().Env = function(j$) { }; this.beforeAll = function(beforeAllFunction, timeout) { - ensureIsFunction(beforeAllFunction, 'beforeAll'); + ensureIsFunctionOrAsync(beforeAllFunction, 'beforeAll'); currentDeclarationSuite.beforeAll({ fn: beforeAllFunction, timeout: function() { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; } @@ -512,7 +518,7 @@ getJasmineRequireObj().Env = function(j$) { }; this.afterEach = function(afterEachFunction, timeout) { - ensureIsFunction(afterEachFunction, 'afterEach'); + ensureIsFunctionOrAsync(afterEachFunction, 'afterEach'); currentDeclarationSuite.afterEach({ fn: afterEachFunction, timeout: function() { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; } @@ -520,7 +526,7 @@ getJasmineRequireObj().Env = function(j$) { }; this.afterAll = function(afterAllFunction, timeout) { - ensureIsFunction(afterAllFunction, 'afterAll'); + ensureIsFunctionOrAsync(afterAllFunction, 'afterAll'); currentDeclarationSuite.afterAll({ fn: afterAllFunction, timeout: function() { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; } diff --git a/src/core/base.js b/src/core/base.js index 89b94555..bbd81170 100644 --- a/src/core/base.js +++ b/src/core/base.js @@ -58,6 +58,10 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) { return j$.isA_('Function', value); }; + j$.isAsyncFunction_ = function(value) { + return j$.isA_('AsyncFunction', value); + }; + j$.isA_ = function(typeName, value) { return j$.getType_(value) === '[object ' + typeName + ']'; };