Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to mock an instance of elasticsearch in Node.js?

I am using elasticsearch and would like to write a unit test for the following code:

import * as elasticsearch from "elasticsearch";
import config from "../config";

const client = new elasticsearch.Client({
  host: config.elasticsearch.host,
  log: "trace"
});

export function index(data) {
    return new Promise((resolve, reject) => {
        client.create({
            index: "myindex",
            type: "mytype",
            id: booking.urn,
            body: data
        }).then(resolve, reject);
    });
}

I am familiar with mocha and sinon, however I don't know of a good pattern to use to stub\mock client.create in this case.

Can anyone suggest an approach that I could use?

like image 387
Daryn Avatar asked Feb 09 '17 11:02

Daryn


People also ask

How do you mock in Elasticsearch?

The best way to mock Elasticsearch with the official clients is to replace the Connection component since it has very few responsibilities and it does not interact with other internal components other than getting requests and returning responses.

How do you mock in node JS?

In Jest, Node. js modules are automatically mocked in your tests when you place the mock files in a __mocks__ folder that's next to the node_modules folder. For example, if you a file called __mock__/fs. js , then every time the fs module is called in your test, Jest will automatically use the mocks.

Can we use Elasticsearch with node js?

Elasticsearch lets you search through vast amounts of data, whether you're implementing real-time search experiences or doing in-depth data analysis. In this tutorial, you'll learn how to integrate Elasticsearch into your Node. js app.

How do I test Elasticsearch connection?

Once you have Elasticsearch installed and running on your local machine, you can test to see that it's up and running with a tool like curl. By default, Elasticsearch will be running on port 9200. Typically the machine will have a name like localhost .


2 Answers

One possible option is to use proxyquire + sinon combo

Sinon will fake Client:

const FakeClient = sinon.stub();
FakeClient.prototype.create = sinon.stub().returns("your data");
var fakeClient = new FakeClient();
console.log(fakeClient.create()); // -> "your data"

Such fake client can be passed into module under test by injection via proxyquire:

import proxyquire from 'proxyquire';
const index = proxyquire('./your/index/module', {
  'elasticsearch': { Client: FakeClient }
});
like image 123
luboskrnac Avatar answered Sep 23 '22 20:09

luboskrnac


The answer of luboskrnac will works if you are trying to proxiquire module that doesn't wrap elasticsearch client, otherwise you need to proxiquire nested elasticsearch client.

// controller.spec.js

const FakeClient = {};    
FakeClient.search = () => {};
sinon.stub(FakeClient, 'search').callsFake((params, cb) => cb(null, {
    hits: {
        hits: [{
            _source: {
                id: '95254ea9-a0bd-4c26-b5e2-3e9ef819571d',
            },
        }],
    },
}));

controller = proxyquire('./controller', {
    '../components/es.wrapper': FakeClient,
    '@global': true,
});

wrapper

// components/es.wrapper.js

const elasticsearch = require('elasticsearch');

const client = new elasticsearch.Client({
    host: process.env.ELASTICSEARCH_HOST,
});

const wrapper = (method, params, callback) => {
    if (process.env.NODE_ENV === 'development') {
        params.index = `dev_${params.index}`;
    }
    return client[method](params, callback);
};

// Wrap ES client methods with dev env prefix
module.exports = {
    search: (params, callback) => {
        return wrapper('search', params, callback);
    },
}

controller

// controller.js
const es = require('../components/es.wrapper');

module.exports = {
    search: (req, res, next) => {
         ....
         es.search(...)
         ....
    }
}
like image 24
1nstinct Avatar answered Sep 20 '22 20:09

1nstinct