Close
Glad You're Ready. Let's Get Started!

Let us know how we can contact you.

Thank you!

We'll respond shortly.

LABS
NYC Standup Round-up for Mar 8th – Mar 12th

Spring is in the air here in sunny NYC! Well, it was sunny for a bit. Now it’s turned into that classic film-noir drizzle. That’s authentic New York weather outside our window as we do the Round Up!

Ask for Help

  • I asked, “In Jasmine, how do you spy on a constructor?” Suppose you have a constructor called Widget. Saying spyOn(window, "Widget") swaps out the real Widget function with a spy. The real Widget implementation takes its prototype with it, which means that Widgets created while the constructor is spied on don’t get the methods a Widget would get. That’s true even when you spy with spyOn(window, "Widget").andCallThrough().

    Also, there doesn’t seem to be a way to stub out object construction and return an object of your choosing. In Rspec in Ruby you can say,

    Widget.should_receive(:new).and_return(my_fake_widget)

    because .new is a class method. But in Javascript, new is a keyword which always creates a new object. I’m guessing there’s no good way around this, but if there is one, we could really use it.

    Update: This is, as it turns out, entirely incorrect. Jasmine’s .andReturn() does let you stub constructors properly. I still have no idea how this works. See the comments for more discussion.

Interesting Stuff

  • Todd notifies us that in ActiveRecord, dynamic finders with too-few arguments fail silently. That is, if you say,

    Person.find_by_first_name_and_last_name_and_email(”Todd”, “Persen”)

    and fail to specify a value for email, the value is taken to be nil. That means that the finder will look for someone named “Todd Persen” with a nil email address. You might have meant that. More likely, you made a mistake. AR should probably check the number of arguments it’s given against the number of columns in the finder name.

  • You already know that Pivotal does real Extreme Programming. But did you know that we have…Extreme Breakfast?

Comments
  1. Adam Milligan says:

    Regarding Jasmine and stubbing constructors, you can do this:

    var fakeWidget = new FakeWidget();
    spyOn(window, 'Widget').andReturn(fakeWidget);
    

    Since the Widget ctor is just a function, new calls the function and gets your fake widget, and then it does its extra magic with the prototype and such on your fake widget. Should work for most things you’d want to do, I believe.

  2. Peter Jaros says:

    The problem is that constructors don’t return their new objects; they just do stuff to them. So even if I do that, `new Widget()` won’t return `fakeWidget`, it’ll return `{}` (since we’ve stubbed out the constructor implementation, and so no properties are added to the new object).

    Just saying `Widget()` *will* return `fakeWidget`, but that’s not how `Widget` is used.

  3. Adam Milligan says:

    Aaah, I see the problem you’re having with stubbing the constructor. It’s not that the function is stubbed, it’s that the function’s prototype is not on the stub. Calling new will return the object in the andReturn parameter, but it won’t attach the prototype (or, really, it attaches the prototype associated with the stub to the new object).

    Hm. What happens if you do this:

    var proto = Widget.prototype;
    spyOn(window, 'Widget');
    Widget.prototype = proto;
    
  4. Peter Jaros says:

    That was the workaround we went with for the prototype problem that doesn’t solve the fact that `andReturn` doesn’t work on constructors…

    …which turns out to be a complete lie. I really thought we saw that fail, but an isolated test case shows that it works.

    Which is curious to me: how is that possible? My understanding is that `spyOn` replaces the spied function with a spy. That spy can be told what to return with `.andReturn`. But the return value of a constructor is discarded! Saying `new Foo()` *always* creates and returns a new object, doesn’t it? So how does this pass?

    var namespace = {};
    namespace.Constructor = function() {
    this.wasMadeWithRealConstructor = true;
    };
    var myFakeObject = { wasMadeWithRealConstructor: false };
    spyOn(namespace, “Constructor”).andReturn(myFakeObject);
    expect(new namespace.Constructor()).toEqual(myFakeObject);

  5. Chad Woolley says:

    OK, who let their pair stick a knife in the toaster? Bad pair…

  6. Rajan Agaskar says:

    fwiw, I believe the following will generally get you the behavior you need, but it requires a fixed set of arguments. We’ll look at supporting functions with properties better in jasmine; hopefully in the future this sort of thing will be transparent.

    >>> function Foo(myVal) { console.log("Passed '" + myVal + "' to Foo Constructor"); this.bar = myVal; }
    >>> Foo.prototype.quux = function() { console.log("Called quux"); return this.bar; }
    function()
    >>> FooClone = Foo
    >>> spyOn(window, "Foo").andCallFake(function(myVal) { console.log("passed '"+ myVal + "' to Fake"); return new FooClone(myVal); });
    function()
    >>> var f = new Foo("test");
    passed 'test' to Fake
    Passed 'test' to Foo Constructor
    >>> f.quux();
    Called quux
    "test"
    >>> expect(window.Foo).wasCalledWith("test")
    true
    
Post a Comment

Your Information (Name required. Email address will not be displayed with comment.)

* Copy This Password *

* Type Or Paste Password Here *