Stub an Object's instance whose methods are nested under properties

353 Views Asked by At

I'm trying to test out a class method, where the method ultimately calls a dependency like so:

class Repo {

    api;

    constructor(host) {
        const api = new repoClient({
            host: host
        });

        this.api = api;
    }

    async getLatestProjectPipeline(projectId) {
        // sorted in descending order by default.
        const projectPipelines = await this.api.Pipelines.all(projectId)
        if (projectPipelines.length == 0) {
            // TODO: Error out
            return null;
        }
    
        return projectPipelines[0];
    };
}

The caveat here is that repoClient only has properties and no immediate methods. (e.g. this.api.Pipelines is a property, then you call said property's methods.

How do I correctly stub the this.api.Pipelines.all method?

Currently, if I use sinon.createStubInstance(repoClient);, sinon complains:

Error: Found no methods on object to which we could apply mutations

However, if I don't it will actually try to call the actual constructor for repoClient, which I do not want.

1

There are 1 best solutions below

0
Lin Du On

You can create a stub repoClient class and pass it to the Repo class's constructor.

E.g.

repoClient.js:

export class RepoClient {
    constructor() {
        this.Pipelines = {
            all(projectId) {
                return [1, 2, 3];
            },
        };
    }
}

repo.js:

class Repo {
    api;
    constructor(host, RepoClient) {
        const api = new RepoClient({
            host: host,
        });

        this.api = api;
    }

    async getLatestProjectPipeline(projectId) {
        const projectPipelines = await this.api.Pipelines.all(projectId);
        if (projectPipelines.length == 0) {
            return null;
        }
        return projectPipelines[0];
    }
}

export { Repo };

repo.test.js:

import sinon from 'sinon';
import { Repo } from './repo';

describe('76734307', () => {
    it('should pass', async () => {
        const PipelinesStub = {
            all: sinon.stub().resolves(['a', 'b', 'c']),
        };
        const repoClientInstanceStub = {
            Pipelines: PipelinesStub,
        };

        const RepoClientClassStub = sinon.stub().returns(repoClientInstanceStub);
        const repo = new Repo('127.0.0.1', RepoClientClassStub);
        const actual = await repo.getLatestProjectPipeline();
        sinon.assert.match(actual, 'a');
    });
});