Writings by Tom de Bruin (@deadlyhifi), a software engineer who cares about all the things. more…

JS Testing and Stubbing Methods Wrapped by a 'Store'

Maybe it's obvious and that's why I didn't find much about it in my searches, or my search criteria were off, or whatever, but it took me a while to figure it out. Then I keep forgetting and scratch my head for half an hour everytime, so I'm writing it down.

Here’s a simple class, MyStore, that needs to do stuff when the document.readyState is complete. The default export is wrapped in AltJs createStore.

export MyStore {
    construct() {
        if (this.getDocumentReadyState() !== 'complete') {
            return;
        }

        this.userAgent = this.getUserAgent();
        // do all the things 🦋
    }

    getDocumentReadyState() {
        return document.readyState;
    }

    ...
}

export default alt.createStore(MyStore, 'MyStore');

Testing

The first test here is to make sure nothing happens if the document isn't ready, so we need to stub getDocumentReadyState(). But because the default export is wrapped in AltJs we can’t get to the actual MyStore to stub the method.

Make sure MyStore is exported as well as the default export, then in your test import MyStore (this is the wrapped one), and also import the unwrapped class.

import MyStore, {MyStore as UnwrappedMyStore} from '../../../src/stores/MyStore';

You can then stub getDocumentReadyState from the unwrapped class before firing the event that this store listens to; and make your assertion(s) as appropriate. I'm using Sinon to stub the method.

Don’t forget to use UnwrappedMyStore.prototype to reference the class. JS classes are just syntactic sugar and add the methods to the prototype.

documentReadyState = sinon.stub(
    UnwrappedMyStore.prototype,
    'getDocumentReadyState'
).returns('interactive');

// dispatch action

chai.expect(MyStore.getState().userAgent).to.be.undefined;

stackoverflow - stubbing-a-class-method-with-sinon-js helped me figure it out.