diff --git a/lib/sinon/spy.js b/lib/sinon/spy.js index d898bcf4f..d6963c431 100644 --- a/lib/sinon/spy.js +++ b/lib/sinon/spy.js @@ -8,6 +8,7 @@ var functionToString = require("./util/core/function-to-string"); var getPropertyDescriptor = require("./util/core/get-property-descriptor"); var sinonMatch = require("./match"); var deepEqual = require("./util/core/deep-equal").use(sinonMatch); +var isEsModule = require("./util/core/is-es-module"); var spyCall = require("./call"); var wrapMethod = require("./util/core/wrap-method"); var sinonFormat = require("./util/core/format"); @@ -25,12 +26,16 @@ var callId = 0; function spy(object, property, types) { var descriptor, methodDesc; + if (isEsModule(object)) { + throw new TypeError("ES Modules cannot be spied"); + } + if (!property && typeof object === "function") { return spy.create(object); } if (!object && !property) { - return spy.create(function () { }); + return spy.create(function () {}); } if (!types) { diff --git a/test/es2015/a-function-module.mjs b/test/es2015/a-function-module.mjs new file mode 100644 index 000000000..57072ba8c --- /dev/null +++ b/test/es2015/a-function-module.mjs @@ -0,0 +1 @@ +export default function (){ return 42; } diff --git a/test/es2015/a-module-with-default.mjs b/test/es2015/a-module-with-default.mjs new file mode 100644 index 000000000..65ac3455c --- /dev/null +++ b/test/es2015/a-module-with-default.mjs @@ -0,0 +1,3 @@ +export default { + anExport(){ return 42; } +} diff --git a/test/es2015/module-support-assessment-test.mjs b/test/es2015/module-support-assessment-test.mjs index d4c5a220d..eb9a830e9 100644 --- a/test/es2015/module-support-assessment-test.mjs +++ b/test/es2015/module-support-assessment-test.mjs @@ -2,13 +2,54 @@ import referee from "referee"; import sinon from "../../lib/sinon"; import * as aModule from "./a-module"; -const {assert} = referee; - -describe("Explicit lack of support for stubbing Modules", function() { - it("should give a proper error message for modules without default export", function() { - assert.exception(function() { - sinon.stub(aModule, "anExport").returns(400); - }, - /TypeError: No support for stubbing ES Modules/); +import aModuleWithDefaultExport from "./a-module-with-default"; +import functionModule, * as functionModuleAlternative from "./a-function-module"; +const {assert, refute} = referee; + +function createTestSuite(action){ + var stub; + var errorRegEx = /TypeError: ES Modules cannot be (stubbed|spied)/; + + afterEach(function() { + stub && stub.restore && stub.restore(); }); -}); + + describe("sinon." + action + "()", function(){ + describe("Modules with objects as their default export", function() { + afterEach(function() { + stub && stub.restore && stub.restore(); + }); + it("should NOT result in error", function() { + refute.exception(function() { + stub = sinon[action](aModuleWithDefaultExport, "anExport"); + }); + }); + + it("should spy/stub an exported function", function() { + stub = sinon[action](aModuleWithDefaultExport, "anExport"); + aModuleWithDefaultExport.anExport(); + aModuleWithDefaultExport.anExport(); + assert(stub.callCount === 2); + }); + }); + + describe("Modules without default export", function() { + it("should give a proper error message", function() { + assert.exception(function() { + sinon[action](aModule, "anExport"); + }, errorRegEx); + }); + }); + + describe("Modules that exports a function as their default export", function() { + it("should not be possible to spy/stub the default export using a wrapper for the exports", function() { + assert.exception(function() { + stub = sinon[action](functionModuleAlternative, "anExport"); + }, errorRegEx); + }); + }); + }); +} + +createTestSuite('stub'); +createTestSuite('spy');