How to check test case response using jasemine? - javascript

I am writing test case for API where I have passed params and main file method is calling http request to get the data, So core() is basically calling the API and getting the response. This is just backend code that we have to test using jasemine.
First how to see response in test case if that's matched with success that is defined in test.
What is a correct way to write test in below scenario.
balance.spec.ts
import { GetAccountBalance } from './GetAccountBalance.node'
import { Promise } from 'es6-promise'
import { HttpRequest } from '../../../core/http/HttpRequest.node'
import * as sinon from 'sinon'
import { getValidationError } from '../../../common/ValidationErrorFactory'
// for easy mocking and cleanup
const sandbox = sinon.createSandbox()
afterAll(function afterTests () {
sandbox.restore()
})
describe('getAccountBalance', function () {
// the module under test
const module = new GetAccountBalance()
const testURL = 'https://essdd.max.com:4535'
const urlPath = '/webServices/instrument/accountBalance'
const fullURL = testURL + urlPath
const options = { isJSON: true }
let result
const stubbedEC = sandbox.spy(getValidationError)
const stubbedHttp = sandbox.createStubInstance(HttpRequest)
const success = {
header: {
serviceName: 'accountBalance',
statusCode: '0000',
statusDesc: 'SUCCESS',
},
response: {
balanceAccount: '6346.44',
},
}
const params = { Id: '21544', appName: 'instrucn', channelName: 'Web' }
describe('core() is called with correct params', function () {
beforeEach(function () {
result = module.core(params, stubbedHttp)
})
it('it should return the response from server', function () {
// Invoke the unit being tested as necessary
result.then((data) => {
expect(data).toBe(success)
})
})
})
})
getaccountBalnce.ts
public core(args: IAccountBalanceParam, httpRequest: HttpRequestBase): Promise<any> {
console.log('enter core');
const DBPLurl: string = this.constructDBPLurl(args);
const DBPLrequest: IAccountBalanceDBPLParam = this.constructDBPLrequest(args);
return Promise.resolve(httpRequest.makeRequest(DBPLurl, DBPLrequest, {isJSON: true}));
}

Related

In Jest, how do I cause a function called within the function to return a specific value

This is the function I am testing (stripped down for simplicity's sake):
populate.js->
const { createSessionID } = require('./populate-template-utilities');
const createFile = async () => {
const responseHeader = {};
responseHeader.SessionID = createSessionID();
return responseHeader;
};
module.exports = {
createFile,
};
The function this function calls:
populate-template-utilities ->
const createSessionID = () => {
const digits = (Math.floor(Math.random() * 9000000000) + 1000000000).toString();
return `PAX${digits}`;
};
module.exports = {
createSessionID,
};
And my unit test (again stripped down):
const { createSessionID } = require('../app/lib/populate-template-utilities');
describe('create XML for output files', () => {
const mockID = jest
.spyOn(createSessionID)
.mockImplementation(() => 'PAX123456');
it('should create a PAX File', async () => {
const result = await createFile();
expect(result).toEqual(getFile);
});
});
I want createSessionID to return 'PAX123456' and think mockID should do it, but it's erroring with:
Cannot spy the undefined property because it is not a function; undefined given instead
The spyOn method needs at least two parameters: object and methodName.
Try sth like this:
import * as populateTemplateUtils from "../sessionStuff";
import { createFile } from "../createFile";
describe('create XML for output files', () => {
it('should create a PAX File', async () => {
jest
.spyOn(populateTemplateUtils, 'createSessionID')
.mockReturnValue('PAX123456');
const result = await createFile();
expect(result).toEqual({"SessionID": "PAX123456"});
});
});
It all started to work when I changed the:
module.exports = {
createSessionID,
};
to:
export const createSessionID = () => {

Stub out node-vault import

How can the 'node-vault' module be stubbed out using Sinon.JS?
Here is the sample code to be tested:
const NodeVault = require('node-vault');
class BearerAuth {
getVaultConfig (token) {
return {
apiVersion: 'v1',
endpoint: app.get('vault'),
token: token
};
}
verify (token) {
const vault = NodeVault(this.getVaultConfig(token));
const resp = vault.tokenLookupSelf().then((result) => {
console.log(`Vault token: ${token}, successfully authenticated.`);
return Promise.resolve({
'name': result.data.meta.username
});
}).catch((err) => {
console.error(err.message);
return Promise.reject(new this.ApplicationError.Authentication('Bearer token is incorrect.'));
});
return resp;
}
}
module.exports = BearerAuth;
}
The test code which attempts to stub out the module using sinon.stub:
const assert = require('assert');
const sinon = require('sinon');
const nodeVault = require('node-vault');
const BearerAuth = require('bearer');
describe('Bearer AuthConfig', () => {
beforeEach(async () => {
class TestBearerAuth extends BearerAuth {
// override some other methods
}
testAuth = new TestBearerAuth();
const vaultConfig = {
endpoint: 'http://localhost:8200',
token: '123'
};
testAuth.getVaultConfig = sinon.stub.returns(vaultConfig);
});
it('returns user when valid token', async () => {
const user = await testAuth.verify(null, 'mytoken');
assert.deepEqual(user, {name: 'sre'});
})
}
This fails when run with this error:
1) Bearer Auth
returns user when valid token:
TypeError: Attempted to wrap undefined property undefined as function
at wrapMethod (node_modules/sinon/lib/sinon/util/core/wrap-method.js:70:21)
at TestBearerAuth.stub [as getVaultConfig] (node_modules/sinon/lib/sinon/stub.js:65:44)
at TestBearerAuthConfig.verify (src/modules/auth/bearer.js:34:34)
at Context.<anonymous> (test/unit/modules/auth/test-bearer.js:57:39)
at processTicksAndRejections (internal/process/task_queues.js:97:5)
The node-vault library has the following export in index.d.ts:
declare function NodeVault(options?: NodeVault.VaultOptions): NodeVault.client;
export = NodeVault;
The unit test code from the node-vault library provided the solution:
Test code:
const assert = require('assert');
const sinon = require('sinon');
const nodeVault = require('node-vault');
const BearerAuth = require('bearer');
describe('Bearer AuthConfig', () => {
beforeEach(async () => {
request = sinon.stub();
response = sinon.stub();
response.statusCode = 200;
response.body = {
data: {
meta: {
username: 'jack'
}
}
};
request.returns({
then (fn) {
return fn(response);
},
catch (fn) {
return fn();
}
});
class TestBearerAuth extends BearerAuth {
getVaultConfig (token) {
return {
endpoint: 'http://localhost:8200',
token: '123',
namespace: 'test',
'request-promise': {
defaults: () => request // dependency injection of stub
}
};
}
}
testAuth = new TestBearerAuth();
});
it('returns user when valid token', async () => {
const user = await testAuth.verify(null, 'mytoken');
assert.deepEqual(user, {name: 'sre'});
})
}
Adding this here in case someone else runs into a similar issue.

How to access a mock method returned from a mocked library

I'm mocking the #elastic/elasticsearch library and I want to test that the search method is called with the right arguments but I'm having issues accessing search from my tests.
In my ES mock I just export an object that includes a Client prop that returns another object that has the search prop. This is the way search is accessed from the library
const { Client } = require('#elastic/elasticsearch')
const client = new Client(...)
client.search(...)
__mocks__/#elastic/elasticsearch
module.exports = {
Client: jest.fn().mockImplementation(() => {
return {
search: (obj, cb) => {
return cb(
'',
{
statusCode: 200,
body: {
hits: {
hits: [
{
_source: esIndexes[obj.index]
}
]
}
}
}
)
}
}
})
}
__tests__/getAddresses.test.js
const { getAddresses } = require('../src/multiAddressLookup/utils/getAddresses')
const { Client } = require('#elastic/elasticsearch')
beforeEach(() => {
process.env.ES_CLUSTER_INDEX = 'foo'
process.env.ui = '*'
})
describe('multiAddressLookup', () => {
test('Should return the correct premises data with only the relevant "forecasted_outages"', async () => {
const event = {
foo: 'bar'
}
const esQueryResponse = {
"body": "\"foo\":\"bar\"",
"headers": {"Access-Control-Allow-Origin": '*'},
"statusCode": 200
}
await expect(getAddresses(event)).resolves.toEqual(esQueryResponse)
expect(Client().search).toHaveBeenCalled() // This fails with 0 calls registered
})
})
I'm not sure of any exact documentation for this scenario but I got the idea while looking through the Jest: The 4 ways to create an ES6 Mock Class - Automatic mock portion of the Jest documentation.
First, the search method in the ES mock, __mocks__/#elastic/elasticsearch, needs to be converted into a jest mock function, jest.fn(). Doing this gives us access to properties and values that jest mocks provide.
__mocks__/#elastic/elasticsearch.js converted
module.exports = {
Client: jest.fn().mockImplementation(() => {
return {
search: jest.fn((obj, cb) => {
return cb(
'',
{
statusCode: 200,
body: {
hits: {
hits: [
{
_source: esIndexes[obj.index]
}
]
}
}
}
)
})
}
})
}
Second, in our tests we need to follow the path from the Client mock class until we find out methods. The syntax is MockClass.mock.results[0].value.mockFunction.
Example Test
const { Client } = require('#elastic/elasticsearch') // This is located in the "__mocks__" folder in the root of your project
const { getAddresses } = require('../../src/getAddresses') // This is the file we wrote and what we are unit testing
describe('getAddresses', () => {
it('Should call the ES Search method', async () => {
const event = { ... }
const expected = { ... }
await expect(getAddresses(event)).resolves.toEqual(expected) // pass
expect(Client.mock.results[0].value.search).toHaveBeenCalled() // pass
})
})

Mock call in Typescript in unit test using only Mocha

I have the following method:
import { ObjectDal } from "./ObjectDal";
export class ObjectBL {
async getObject(id) {
try {
let dal = new ObjectDal();
let result = await dal.get(id);
return result;
} catch (err) {
// log the error
}
}
where the ObjectDal class is:
export class ObjectDal {
async get(id) {
// open connection to db
// make a query based on id
// put the result in a `result` variable
return result;
}
}
I have to write an unit test for the getObject() method using only Mocha...
This is the begining of the UT:
const assert = require('assert');
const ObjectBL = require("../ObjectBL");
describe('Something', () => {
describe('...', () => {
it('getObject_GetsObjectUsingID_True', async () => {
// arange
let id = "123456789101";
let expected = {
"name": "ana",
"hasApples": true
};
let test = new ObjectBL.ObjectBL();
let result = await test.getObject(id);
assert.deepStrictEqual(result, expected);
});
});
});
But in this case I would have to call the method from the ObjectDal class...
How can I mock the call to the get() method using only Mocha?
I found answers with Sinon, or Mocha with Sinon and/or Chai... but nothing with only Mocha...
Proxies might be the way to go for you.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy
You could mok methods by using a Proxy like so:
const assert = require('assert');
const ObjectBL = require("../ObjectBL");
describe('Something', () => {
describe('...', () => {
it('getObject_GetsObjectUsingID_True', async () => {
// arange
let id = "123456789101";
let expected = {
"name": "ana",
"hasApples": true
};
let test = new ObjectBL.ObjectBL();
const handler = {
get: function(obj, prop) {
// mok the getObject method
if(prop === 'getObject'){
return () => {
return Promise.resolve({
"name": "ana",
"hasApples": true
});
}
} else {
return obj[prop];
}
}
};
const p = new Proxy(test, handler);
let result = await p.getObject(id);
assert.deepStrictEqual(result, expected);
});
});
});
If you ONLY want to mok the ObjectDal.get method, you might want to override the prototype and recover it afterwards:
const assert = require('assert');
const ObjectBL = require("../ObjectBL");
const ObjectDal = require("../ObjectDal");
describe('Something', () => {
describe('...', () => {
it('getObject_GetsObjectUsingID_True', async () => {
// arange
let id = "123456789101";
let expected = {
"name": "ana",
"hasApples": true,
};
const proto = Object.getOwnPropertyDescriptor(ObjectDal, 'prototype').value;
const backup = proto.get;
proto.get = () => {
return Promise.resolve({
"name": "ana",
"hasApples": true,
});
}
let test = new ObjectBL.ObjectBL();
let result = await test.getObject(id);
ObjectDal.prototype.get = backup;
assert.deepStrictEqual(result, expected);
});
});
});
You could also override the ObjectDal with a Proxy and implement the construct handler to return a dummy ObjectDal, but this might be more tricky, since you are working with modules.
Testing is feedback, not just on whether or not your code works as advertised but even more crucially on the quality of your design.
The fact that you are having trouble writing the tests is your first sign you did something sub-optimal in the implementation. What you want is this:
export class ObjectBL {
constructor (dal) {
this.dal = dal;
}
async getObject(id) {
try {
let result = await this.dal.get(id);
return result;
} catch (err) {
// log the error
}
}
...and now the dependency is clear rather than implicit and will show up in editor tooltips, is more amenable to static analysis, etc. And it solves your problem: now you can mock it easily for testing, no further libraries needed.

stampit.js beginner needs some guidance

I'm implementing service between a view and a Rest API.
Beside, i'm completly new to stamp programming and i'm in search of some advices about this sort of code:
import {compose, methods} from '#stamp/it'
import ArgOverProp from '#stamp/arg-over-prop'
import {template} from 'lodash'
const createLogger = name => (...args) => console.log('['+ name + ']', ...args)
const HasHttpClient = ArgOverProp.argOverProp('httpClient')
const HasApiVersion = ArgOverProp.argOverProp('apiVersion')
const HasUrl = ArgOverProp.argOverProp('url')
const UseRestApi = compose(HasHttpClient, HasApiVersion, HasUrl).init([
function () {
this.getUrl = template(this.url)
this.useRestApiLog = createLogger('UseRestApi')
}
]).methods({
query: function query(method, {params, headers, body}) {
const {apiVersion} = this
const q = {
baseURL: this.getUrl({apiVersion}),
method,
...params != null && {params},
...headers != null && {headers},
...body != null && {body}
}
this.useRestApiLog('request config:', q)
return q
}
})
const WithGetOperation = compose(UseRestApi).init([
function () {
this.withGetOperationLog = createLogger('WithGetOperation')
}
]).methods({
'get': function get ({params}) {
const q = this.query('get', {headers: {'Accept': 'application/json'}, params})
this.withGetOperationLog('getting data')
return this.httpClient(q)
}
})
const CustomerRestApi = compose(WithGetOperation).init([
function () {
this.customerRestApiLog = createLogger('CustomerRestApi')
}
]).methods({
all: function all() {
this.customerRestApiLog('get all customers')
return this.get({params: {page: 1, limit: 15}})
}
})
const customerProvider = CustomerRestApi({
url: 'http://sample.com/<%=apiVersion%>/customers',
apiVersion: 'v1',
httpClient: function(config) {
return Promise.resolve({
status: 200,
config
})
}
})
const appLog = createLogger('APP')
customerProvider.all()
.then(r => appLog('HTTP response code:', r.status))
Am i in the right directions?
Especially, the createLogger thing seems ugly!
How to inject a prefixed logger into each stamp ?
How to extend that to warn, error, ... methods ?
Your logger looks just fine. 👍 It is not necessary to create every bit as a stamp. However, if you want to make the logger as a reusable stamp then you can do the same way as ArgOverProp is implemented.
Ruffly ArgOverProp is done this way:
const ArgOverProp = stampit.statics({
argOverProp(...args) {
return this.deepConf({ArgOverProp: [...args]});
}
})
.init(function (options, {stamp}) {
const {ArgOverProp} = stamp.compose.deepConfiguration;
for (let assignableArgName of ArgOverProp) {
this[assignableArgName] = options[assignableArgName];
}
});
Your logger could look like this (not necessary exactly like this):
import {argOverProp} from '#stamp/arg-over-prop';
const Logger = stampit(
argOverProp('prefix'),
{
methods: {
log(...args){ console.log(this.prefix, ...args); },
error(...args){ console.error(this.prefix, ...args); },
warn(...args){ console.warn(this.prefix, ...args); }
}
}
);
const HasLogger = stampit.statics({
hasLogger(name) {
return this.conf({HasLogger: {name}});
}
})
.init(_, {stamp}) {
const {HasLogger} = stamp.compose.configuration;
if (HasLogger) {
this.logger = Logger({prefix: HasLogger.name});
}
});
And usage:
const CustomerRestApi = stampit(
WithGetOperation,
HasLogger.hasLogger('CustomerRestApi'),
{
methods: {
all() {
this.logger.log('get all customers');
return this.get({params: {page: 1, limit: 15}});
}
}
);
I always prefer readability. So, the code above, I hope, is readable to you and any stampit newbie.
PS: a tip. The stampit and the stampit.compose you imported above are the same exact function. :) See source code.

Categories

Resources