Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

kinvey-business-logic-testing-library

Package Overview
Dependencies
Maintainers
2
Versions
5
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

kinvey-business-logic-testing-library

Kinvey's Business Logic Testing Library

  • 0.1.4
  • latest
  • npm
  • Socket score

Version published
Maintainers
2
Created
Source

Helper module for testing Kinvey Business Logic

This module provides an easy way to connect to a Kinvey Business Logic (BL) instance running on docker. It is up to the user to download, configure and start the docker image itself before running code using this module. Two utility functions are provided to automate setting up the docker image.

The module serves two purposes:

  1. Integrate with the Kinvey BL CLI tool to support offline testing of BL code.
  2. Allow a developer to run a custom BL function in order to test its validity and behavior.

In order to use the module, you will first need to create and configure a client instance, and then call one of its API methods. These steps are explained in more detail below.

Table of contents

Usage

The module exposes the following API:

createMockRequest(fromJSON)

Create an instance of the request builder, which can be used to construct a request object to pass to the run... function described above. For more details, take a look at the request builder documentation below.

createMockResponse(fromJSON)

Create an instance of the response builder, which can be used to construct a response object to pass to the run... function described above. For more details, take a look at the response builder documentation below.

createClient(jsonConfiguration, callback)

Create a client instance, which will be able to communicate with the Business Logic docker container. The jsonConfiguration parameter allows you to optionally specify configuration options as a JSON object. The structure of the JSON object supports the following properties:

property nametypedescriptiondefault value
blRootPathstringthe path to the root of the business-logic folder created by using the BL CLI toolN/A
environmentIDstringthe ID of the environment to simulate'BusinessLogicTest'
appSecretstringthe app secret of the simulated environment'environmentID-app-secret'
masterSecretstringthe master secret of the simulated environment'environmentID-master-secret'
containerHostOrIPstringthe hostname or IP address of the docker container running the BL instance$DOCKER_HOST or 'localhost'
runnerPortnumberthe port exposed by the instance of the Kinvey BL running in the docker container7000
proxyPortnumberthe port exposed by the instance of the Kinvey proxy running in the docker container2845

Note that you do not need to specify all values. Generally, you will want to configure the testing module with the blRootPath parameter. The environment-specific configuration parameters are provided as an option in case your BL code relies on this information. The other parameters, which are related to the docker container, will normally be obtained automatically (containerHostOrIP will default to the DOCKER_HOST environment variable, if defined, and to localhost otherwise; runnerPort and proxyPort will be obtained by inspecting the running docker container), and are only provided here as optional overrides.

The callback function should accept two arguments: an error (which will be set to null if no error has occurred), and an instance of the client.

The client instance created using this method exposes the following methods, which are described in detail below:

Example

var tester = require('business-logic-testing-library');

var options = {
  blRootPath: '/Users/JohnDoe/Documents/kinvey/business-logic',
  environmentID: 'MyAwesomeEnvironment'
}

tester.createClient(options, function(err, client) {
  if (err) {
    // handle error
  }

  client.runFunction( ... );
});
runCollectionHook(collectionName, blFunctionName, requestObject, responseObject, callback)

Run the code contained within a collection hook. This method relies on the existence of the collection hook .js file within the BL CLI folder structure. For example, if your collection is called MyCollection, and you are running an post-fetch hook, the tester will look for the code at _blRootPath_/collections/MyCollection/onPostFetch.js (where _blRootPath_ is the path to the root of the BL folder structure, as specified in the options to the createClient method).

Arguments
nametypedescription
collectionNamestringthe name of the collection associated with the hook
blFunctionNamestringthe hook function to call. One of: onPreSave, onPostSave, onPreFetch, onPostFetch, onPreDelete, onPostDelete
requestObjectJSON or mock-request-builder instancethe object made available to the BL code through the request variable
responseObjectJSON or mock-response-builder instancethe object made available to the BL code through the response variable
callbackfunctionthe function that will be called when the BL code has finished executing. This function should accept two parameters: error and blResult. The response will be a JSON object containing metadata, request and response properties.
Example
var requestObject = {
  body: {
    _id: 'abcd'
  },
  headers: {
    'x-kinvey-api-version': 3
  },
  username: 'foobar'
};

var responseObject = {};

client.runCollectionHook('MyCollection', 'onPreSave', requestObject, responseObject, function(error, blResult) {
  if (error) {
    // handle the error
  }
  else {
    console.log("Received response with body:", blResult.response.body);
  }
});
runCustomEndpoint(endpointName, requestObject, responseObject, callback)

Run the code contained within a custom endpoint. This method relies on the existence of the endpoint .js file within the BL CLI folder structure. For example, if your endpoint is called myEndpoint, the tester will look for the code at _blRootPath_/endpoints/myEndpoint.js (where _blRootPath_ is the path to the root of the BL folder structure, as specified in the options to the createClient method).

Arguments
nametypedescription
endpointNamestringthe name of the endpoint you wish to run
requestObjectJSON or mock-request-builder instancethe object made available to the BL code through the request variable
responseObjectJSON or mock-response-builder instancethe object made available to the BL code through the response variable
callbackfunctionthe function that will be called when the BL code has finished executing. This function should accept two parameters: error and blResult. The response will be a JSON object containing metadata, request and response properties.
Example
var requestObject = {
  body: {
    _id: 'abcd'
  },
  headers: {
    'x-kinvey-api-version': 3
  },
  username: 'foobar'
};

var responseObject = {};

client.runCustomEndpoint('myEndpoint', requestObject, responseObject, function(error, blResult) {
  if (error) {
    // handle the error
  }
  else {
    console.log("Received response with body:", blResult.response.body);
  }
});
runFunction(codeToRun, requestObject, responseObject, callback)

Run code from a function or a function string. The function must match the custom endpoint signature: function onRequest(request, response, modules){ ... }.

Arguments
nametypedescription
codeToRunfunction or stringcode you wish to run
requestObjectJSON or mock-request-builder instancethe object made available to the BL code through the request variable
responseObjectJSON or mock-response-builder instancethe object made available to the BL code through the response variable
callbackfunctionthe function that will be called when the BL code has finished executing. This function should accept two parameters: error and blResult. The response will be a JSON object containing metadata, request and response properties.
Example
var requestObject = {
  body: {
    _id: 'abcd'
  },
  headers: {
    'x-kinvey-api-version': 3
  },
  username: 'foobar'
};

var responseObject = {};

var helloWorld = function onRequest(request, response, modules) {
  response.body = { 'hello': 'world' };
  response.complete();
};

client.runFunction(helloWorld, requestObject, responseObject, function(error, blResult) {
  if (error) {
    // handle the error
  }
  else {
    console.log("Received response with body:", blResult.response.body);
  }
});
dataStore

The testing container uses TingoDB to create a simulated data store and allow your Business Logic code to interact with data through the collectionAccess module, much like it normally would. While there are some differences between the API exposed by TingoDB and the one exposed by production instances of Kinvey (which use MongoDB), these are minor, and should allow you to simulate almost everything you wish. If you were to encounter a corner case which is handled differently by TingoDB and MongoDB, please first check the TingoDB documentation before contacting Kinvey support.

Please note that this data store exists entirely offline, within the docker container running on your local machine, and is not connected to Kinvey's production data store.

The data store exposes several methods, which can be accessed through the client's dataStore object. Detailed information on these methods and examples of their use can be found below.

importCollectionData(collectionName, jsonData, clearBeforeInsert, callback)

Allows you to import JSON data into a named collection.

The jsonData parameter can contain a JSON object or an array of JSON objects.

The clearBeforeInsert parameter, which defaults to false, will remove the contents of the collection before importing the data. This may be useful if you wish to be sure that your test environment starts with the same data every time.

The callback function should accept a single error argument, which will be set to null if no error has occurred.

Example

var tester = require('business-logic-testing-library');
var options = { ... };

tester.createClient(options, function(err, client) {
  if (err) {
    // handle error
  }

  var data = [{
      'first_name': 'John',
      'last_name': 'Doe'
    },
    {
      'first_name': 'Chuck',
      'last_name': 'Norris'
    }];

  client.dataStore.importCollectionData('customers', data, true, function(err) {
    if (err) {
      // handle error
    }

    ...
  });
});
removeCollectionData(collectionName, query, callback)

Allows you to remove entities from a named collection.

The query parameter should contain a MongoDB-style JSON query (for more details on constructing these types of queries, please check MongoDB's site).

The callback function should accept a single error argument, which will be set to null if no error has occurred.

Example

var tester = require('business-logic-testing-library');
var options = { ... };

tester.createClient(options, function(err, client) {
  if (err) {
    // handle error
  }

  client.dataStore.removeCollectionData('customers', { 'first_name': { '$in': ['John', 'Chuck'] } }, function(err) {
    if (err) {
      // handle error
    }

    ...
  });
});
getCollectionData(collectionName, query, callback)

Allows you to retrieve entities from a named collection.

The query parameter should contain a MongoDB-style JSON query (for more details on constructing these types of queries, please check MongoDB's site).

The callback function should accept an error argument, which will be set to null if no error has occurred, and a second argument which will contain the retrieved JSON data.

Example

var tester = require('business-logic-testing-library');
var options = { ... };

tester.createClient(options, function(err, client) {
  if (err) {
    // handle error
  }

  client.dataStore.getCollectionData('customers', { 'first_name': { '$in': ['John', 'Chuck'] } }, function(err, entities) {
    if (err) {
      // handle error
    }

    // at this point, the entities variable contains the results of execuring the query against the testing container's data store
  });
});

BL Modules

When testing, the email, logger, and push modules do not send out "real" e-mails or push notifications. Instead, the details of an e-mail, log, or push message are stored inside the following collections.

  • emails: _outgoingEmailMessages,
  • logs: _outgoingPushMessages,
  • push: _blLogs.

Retrieve these details as follows:

var tester = require('business-logic-testing-library');
var options = { ... };

tester.createClient(options, function(err, client) {
  if (err) {
    // handle error
  }

  client.runCustomEndpoint('myEndpoint', { }, { }, function(error, blResult) {
    if (err) {
      // handle error
    }

    client.dataStore.getCollectionData('_blLogs', { }, function(err, logs) {
      if (err) {
        // handle error
      }

      // at this point, the logs variable contains the logs recorded while executing the custom endpoint.
    });
  });
});

Common code

All methods support common code defined within the BL CLI folder structure. When any of the run... methods described above are called, the testing module will read the contents of any common code files contained within the _blRootPath_/common/ directory (where _blRootPath_ is the path to the root of the BL folder structure, as specified in the options to the createClient method). Any common code will be executed before running your collection hook/custom endpoint/function code.

Example
/**** contents of _blRootPath/common/helperFunctions.js ***/
var timesTwo = function(number) {
  return (number * 2);
}
/**** end of helperFunctions.js ****/


/**** contents of _blRootPath/custom/myEndpoint.js ***/
function onRequest(request, response, modules) {
  response.body = {
    multipliedNumber: timesTwo(parseInt(request.body.number))
  };
  response.complete();
};
/**** end of myEndpoint.js ***/


// testing code
var requestObject = {
  body: {
    number: 4
  }
};

client.runCustomEndpoint('myEndpoint', requestObject, {}, function(error, blResult) {
  if (error) {
    console.log("Error encountered! details:", error);
  }
  else {
    console.log("4 * 2 is", blResult.response.body.multipliedNumber);
  }
});

Helpers

Mock request builder

In order to run business logic using any of the run... methods listed on this page, you must pass in a request object. This object contains data and metadata about the (simulated) incoming HTTP request (FROM the client TO Kinvey), and is used to pass necessary information to the testing framework. In order to simplify the use of this object, you can use the mock-request-builder helper module, which exposes an API to create a request object.

Usage and constructor

To use the request builder, require the testing module, and then call its createMockRequest method. The constructor optionally accepts a JSON object containing initial values.

Example
var tester = require('business-logic-testing-library');
var options = { ... };

var requestObject = tester.createMockRequest({ body: { testing: true }});

tester.createClient(options, function(err, client) {
  if (err) {
    // handle error
  }

  client.runCustomEndpoint('myEndpoint', requestObject, {}, function(error, blResult) {});
});
Chaining

With the exception of toJSON, all methods of the request builder return the instance of the builder, allowing for chained method calls. For example:

var tester = require('business-logic-testing-library');
var requestObject = tester.createMockRequest();
requestObject.setBody({ testing: true }).addHeader('x-kinvey-api-version', 3);
setBody(jsonObject)

Set the body property of the request object, which corresponds to the body of the incoming HTTP request. Accepts a JSON object.

Example
var tester = require('business-logic-testing-library');
var requestObject = tester.createMockRequest();

requestObject.setBody({ testing: true });

client.runCustomEndpoint('myEndpoint', requestObject, {}, function(error, blResult) {});
setHeaders(jsonObject)

Set the headers property of the request object, which corresponds to the headers of the incoming HTTP request. Accepts a JSON object in which keys are header names and values are header contents.

Example
var requestObject = tester.createMockRequest();

requestObject.setHeaders({ 'x-kinvey-api-version': 3 });

client.runCustomEndpoint('myEndpoint', requestObject, {}, function(error, blResult) {});
addHeader(name, contents)

Add a header to the headers property of the request object, which corresponds to the headers of the incoming HTTP request. Accepts the name of a header, and its contents. If a header by that name already exists, this method will replace its contents.

Example
var requestObject = tester.createMockRequest();

requestObject.addHeader('x-kinvey-api-version', 3);

client.runCustomEndpoint('myEndpoint', requestObject, {}, function(error, blResult) {});
setParams(jsonObject)

Set the params property of the request object, which corresponds to the parameters of the incoming HTTP request. Accepts a JSON object in which keys are parameter names and values are their contents. For GET, PUT, and DELETE requests, you can use id (not: _id) as parameter name to specify an entity id. For POST, specify an _id in the request body.

Example
var requestObject = tester.createMockRequest();

requestObject.setParams({ 'query': { myField: 'myValue' }});

client.runCustomEndpoint('myEndpoint', requestObject, {}, function(error, blResult) {});
addParam(name, contents)

Add a parameter to the params property of the request object, which corresponds to the parameters of the incoming HTTP request. Accepts the name of a parameter, and its contents. If a parameter by that name already exists, this method will replace its contents.

Example
var requestObject = tester.createMockRequest();

requestObject.addParam('query', { myField: 'myValue' });

client.runCustomEndpoint('myEndpoint', requestObject, {}, function(error, blResult) {});
setAuthenticatedUsername(username)

Set the username of the authenticated Kinvey user making the simulated request. This is the username accessible to your business logic code by the modules.backendContext.getAuthenticatedUsername() method (for more details, please check our business logic reference).

Example
var requestObject = tester.createMockRequest();

requestObject.setAuthenticatedUsername('myUsername');

client.runCustomEndpoint('myEndpoint', requestObject, {}, function(error, blResult) {});
setTempObjectStore(jsonObject)

Set the value of the temporary object store available to your business logic code through modules.utils.tempObjectStore. For more details, please check our business logic reference.

Example
var requestObject = tester.createMockRequest();

var objectStore = {
  myProperty: 'myValue'
};

requestObject.setTempObjectStore(objectStore);

client.runCustomEndpoint('myEndpoint', requestObject, {}, function(error, blResult) {});
toJSON()

Returns the JSON object representing the request built by this helper.

Example
var tester = require('business-logic-testing-library');

var requestObject = tester.createMockRequest({ body: { testing: true }});

requestObject.setAuthenticatedUsername('myUser');

console.log(requestObject.toJSON());

/* outputs:
{
  body: {
    testing: true
  },
  username: 'myUser'
}
*/

Mock response builder

In order to run business logic using any of the run... methods listed on this page, you must pass in a response object. This object contains data and metadata about the (simulated) outgoing HTTP response (FROM Kinvey TO the client). In order to simplify the use of this object, you can use the mock-response-builder helper module, which exposes an API to create a response object.

Usage and constructor

To use the response builder, require the testing module, and then call its createMockResponse method. The constructor optionally accepts a JSON object containing initial values.

Example
var tester = require('business-logic-testing-library');
var options = { ... };

var responseObject = tester.createMockResponse({ body: { testing: true }});

tester.createClient(options, function(err, client) {
  if (err) {
    // handle error
  }

  client.runCustomEndpoint('myEndpoint', {}, responseObject, function(error, blResult) {});
});
Chaining

With the exception of toJSON, all methods of the response builder return the instance of the builder, allowing for chained method calls. For example:

var tester = require('business-logic-testing-library');
var responseObject = tester.createMockResponse();
responseObject.setBody({ testing: true }).setStatusCode(200);
setBody(jsonObject)

Set the body property of the response object, which corresponds to the body of the outgoing HTTP response. Accepts a JSON object.

Example
var responseObject = tester.createMockResponse();

responseObject.setBody({ testing: true });

client.runCustomEndpoint('myEndpoint', {}, responseObject, function(error, blResult) {});
setHeaders(jsonObject)

Set the headers property of the response object, which corresponds to the headers of the outgoing HTTP response. Accepts a JSON object in which keys are header names and values are header contents.

Example
var responseObject = tester.createMockResponse();

responseObject.setHeaders({ 'x-kinvey-api-version': 3 });

client.runCustomEndpoint('myEndpoint', {}, responseObject, function(error, blResult) {});
addHeader(name, contents)

Add a header to the headers property of the response object, which corresponds to the headers of the outgoing HTTP response. Accepts the name of a header, and its contents. If a header by that name already exists, this method will replace its contents.

Example
var responseObject = tester.createMockResponse();

responseObject.addHeader('x-kinvey-api-version', 3);

client.runCustomEndpoint('myEndpoint', {}, responseObject, function(error, blResult) {});
setStatusCode(code)

Set the status code of the response object, which corresponds to the HTTP status code of the outgoing HTTP response.

Example
var responseObject = tester.createMockResponse();

responseObject.setStatusCode(200);

client.runCustomEndpoint('myEndpoint', {}, responseObject, function(error, blResult) {});
toJSON()

Returns the JSON object representing the response built by this helper.

Example
var tester = require('business-logic-testing-library');

var responseObject = tester.createMockResponse({ body: { testing: true }});

responseObject.setStatusCode(200);

console.log(responseObject.toJSON());

/* outputs:
{
  body: {
    testing: true
  },
  status: 200
}
*/

Utilities

Setup

Start the required Docker images and return a tester instance. Prior to running this method, make sure Docker is installed properly. The set-up method expects a jsonConfiguration object as first parameter. The set-up method is best used in a before-hook of your test suite.

Example
// Assuming Mocha.
var tester = require('business-logic-testing-library');

var options = {
  blRootPath: '/Users/JohnDoe/Documents/kinvey/business-logic',
  environmentID: 'MyAwesomeEnvironment'
}

before(function(done) {
  tester.util.setup(options, function(err, client) {
    if(err) {
      // handle error
    }

    // client...
  });
});

Teardown

Currently, the teardown method is an empty method. This might change in the future.

Example
// Assuming Mocha.
var tester = require('business-logic-testing-library');

var options = {
  blRootPath: '/Users/JohnDoe/Documents/kinvey/business-logic',
  environmentID: 'MyAwesomeEnvironment'
}

before(...);

after(function(done) {
  tester.util.teardown(options, done);
});

License

Copyright 2016 Kinvey, Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

FAQs

Package last updated on 17 Oct 2016

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc