Search code examples
javascriptmockingsinon

With Sinon, how can I mocked http.foo.get when http is a property?


I have a file I wish to test, with an http-client that should be mocked:

schema.js:

const { http } = require('@foo/http-client');
.......
const result = await http.foo('another-service').get('graphql', {
                query: `
    {
        SomeResolver(clientId: "${args.clientId}") {
            id
            start
            end
        }
    }
    `,
});

I need to mock the result.

schema.test.js:

const sinon = require('sinon');
const mockHttp = sinon.mock(require('@foo/http-client'));
.........
mockHttp.expects('foo').returns({
    get: (x,y) => {
        // mock the response here
    },
});

TypeError: Attempted to wrap undefined property foo as function is the error with the above which makes sense because http is destructured.

However, if I change the expects line to:

mockHttp.expects('http').returns

I get the error TypeError: Attempted to wrap object property http as function which also makes sense because http is a property.

As you can see I'm quite new to Sinon but my question is how can I mocked http.foo.get when http is a property?


Solution

  • To my understanding, mocks are for objects, and expectations are for functions - one per each.

    In your context, it seems you could do:

    const { http } = require('@foo/http-client');
    const mockHttp = sinon.mock(require('@foo/http-client').http); // mind .http
    mockHttp.expects('foo').returns({
        get: (x,y) => {
            // mock the response here
        },
    });
    http.foo().get();
    mockHttp.verify();
    

    If you need to set expectations on other http functions, you can reuse mockHttp. If you need expectations on functions somewhere else in the module, you'll need to create another mock for the object they're declared in, and verify() that other mock as well. (That's how I understand it anyway, someone please correct if you know better!)

    In any case, using destructuring assignments won't change the fact that your http variable references the module's http property. In other words:

    const { http } = require('@foo/http-client');
    console.log( http === require('@foo/http-client').http ); // true