Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sinon stub- cannot stub arrow function in a class #1136

Closed
repspark-trh opened this issue Sep 2, 2016 · 1 comment
Closed

sinon stub- cannot stub arrow function in a class #1136

repspark-trh opened this issue Sep 2, 2016 · 1 comment
Labels
Documentation ES2015+ ES2015 and later revision

Comments

@repspark-trh
Copy link

  • Sinon version : v2.0.0-pre.2
  • Environment : Windows 10
  • Other libraries you are using: Typescript, babel, mocha, chai

What did you expect to happen?
I expected to be able to stub an arrow function in a class.

What actually happens
I can't stub an arrow function, however, I can stub the class prototype function.

FAILED TESTS:
  ExampleClass tests
    × should stub thisDoesntWork arrow function
      Chrome 52.0.2743 (Windows 10 0.0.0)
    TypeError: Attempted to wrap undefined property thisDoesntWork as function
        at wrapMethod (webpack:///~/sinon/pkg/sinon.js:3138:0 <- test-bundler.js:7377:21)
        at Object.stub (webpack:///~/sinon/pkg/sinon.js:2472:0 <- test-bundler.js:6711:12)
        at Context.<anonymous> (webpack:///src/stores/sinon.test.ts:22:51 <- test-bundler.js:96197:72)

How to reproduce

export class ExampleClass {
    thisWorks() {
        return 0;
    }

    thisDoesntWork = () => {
        return 0;
    }
}

describe("ExampleClass tests", () => {
    it("should stub thisWorks function", () => {
        let stubFunctionA = sinon.stub(ExampleClass.prototype, "thisWorks");
    });
    it("should stub thisDoesntWork arrow function", () => {
        let stubFunctionB = sinon.stub(ExampleClass, "thisDoesntWork");
    });
});
@fatso83
Copy link
Contributor

fatso83 commented Sep 4, 2016

This is food for the upcoming new documentation site where we hope to publish some more tutorial oriented articles on stubbing, spying, etc in the context of ES2015.

Generally when you come across issues like this it is very helpful in remembering one simple fact: ES2015 is often just syntactic sugar on top of simple ES5 constructs. Meaning, when you don't understand why something happens (or doesn't happen), try deconstructing the code into its ES5 equivalent. The simplest way (which is what I just did) is to just paste the example code into the Babel playground and see what the ES2015/ES6 code compiles into:

The transpiled code from Babel

"use strict";

Object.defineProperty(exports, "__esModule", {
    value: true
});

var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

var ExampleClass = exports.ExampleClass = function () {
    function ExampleClass() {
        _classCallCheck(this, ExampleClass);

        this.thisDoesntWork = function () {
            return 0;
        };
    }

    _createClass(ExampleClass, [{
        key: "thisWorks",
        value: function thisWorks() {
            return 0;
        }
    }]);

    return ExampleClass;
}();

The first thing I spot is that arrow functions are simply instance methods. That means a few things:

  1. they do not exist until object creation.
  2. they cannot be stubbed by modifying the prototype, since they do not exist on the prototype
  3. they cannot be stubbed by modifying the constructor object, since their definition is hidden within the closure.

Knowing all of this, it is simply to change your failing test to this:

    it("should stub thisDoesntWork arrow function", () => {
        var example = new ExampleClass();
        let stubFunctionB = sinon.stub(example, "thisDoesntWork", () => "actually it does work" );
    });

Good luck.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Documentation ES2015+ ES2015 and later revision
Projects
None yet
Development

No branches or pull requests

2 participants