I m trying to write unit test cases to handle error codes that are defined below. not sure how to achieve it.
module.exports = {
Error: Err,
BadRequest: function () {
return new Err(400, 'Bad Request');
},
NotAcceptable: function () {
return new Err(406, 'Not Acceptable');
},
NotAuthorized: function () {
return new Err(401, 'Not Authorized');
}
};
function Err(code, message) {
assert(code, 'code');
Error.call(this);
Error.captureStackTrace(this, this.constructor);
Object.defineProperty(this, 'code', {
enumerable: true,
value: code
});
this.reason = message;
}
You should have a better base error layer by extending the Error class which already provide most of the functions you would need (capturing the stack trace automatically):
class Err extends Error {
constructor(code, message) {
super(message);
this.code = code;
this.reason = message;
}
}
You can then performa your assertion using the throw expectation:
const errorFn = () => { throw new Err(401, 'Unauthorized') };
expect(errorFn).to.throw(Err).to.haveOwnProperty('code', 401).to.haveOwnProperty('reason', 'Unauthorized');
You should obviously update your sub-error accordingly to extend your generic error.
Related
I am testing some express middlewares with jest.
it("should throw 400 error if request.body.id is null", () => {
const req = { body: { id: null } } as any;
const res = {} as any;
const next = jest.fn();
myMiddleware(req, res, next);
expect(next).toBeCalledWith(expect.any(ErrorResponse));
expect(next).toBeCalledWith(
expect.objectContaining({
statusCode: 400,
errCode: "error-0123-2342",
message: "Field id is missing",
})
);
});
my ErrorResponse:
export class ErrorResponse extends Error {
public statusCode: number;
public errCode: string;
constructor(
statusCode: number = 500,
errCode: string = "error-123-1993",
message: string = "Internal Server Error"
) {
super(message);
this.statusCode = statusCode;
this.errCode = errCode;
}
}
I manage to check if the ErrorResponse with specific property is called in the next function, but it doesn't guarantee the ErrorResponse Object contains only 3 properties (statusCode, errCode, message) if someone change the ErrorResponse to add One more property, such as details.
I would like to do something below and guarantee the ErrorResponse Object contains only 3 properties (statusCode, errCode, message).
it("should throw 400 error if request.body.id is null", () => {
const req = { body: { id: null } } as any;
const res = {} as any;
const next = jest.fn();
myMiddleware(req, res, next);
expect(next).toBeCalledWith(
new ErrorResponse(
400,
"error-3123-2332",
"Field id is missing"
)
);
});
May I know if there is an way to do it in jest?
After a cursory look at the jest documentation, it seems that expect.extend might do what you want:
expect.extend({
toBeErrorResponse(received) {
if (received instanceof ErrorResponse &&
Object.keys(received).length === 2)
return {
message: () => "expected no ErrorResponse",
pass: true,
};
else
return {
message: () => "expected an ErrorResponse",
pass: false,
};
}
});
test("my ErrorResponse", () => {
const next = jest.fn();
next(new ErrorResponse(400, "E", "M"));
expect(next).toBeCalledWith(expect.toBeErrorResponse());
});
For example, I can't access to this module, why ?
let nodeCacheClient;
module.exports = {
initNodeCache: () => {
const NodeCache = require("node-cache");
nodeCacheClient = new NodeCache();
return nodeCacheClient;
},
insertToCacheWithTtl: (key, obj, ttl) => {
return nodeCacheClient.set(key, obj, ttl);
},
getCache: (key) => {
return nodeCacheClient.get(key);
},
deleteKey: (key) => {
return nodeCacheClient.del(key);
},
};
when I run this test I get this : TypeError: Cannot read property 'get' of undefined Error
test("login a user", async () => {
try {
const response = await axiosInstance.post("users/login", {
email: "test#gmail.com",
password: "144847120",
otpCode: getCacheClient.getCache("test#gmail.com")
});
console.log(response.data);
expect(response.data.status).toBe("success");
} catch (error) {
console.log(error + " Error");
expect(error);
}
});
It’s totally normal!
Actually you got access to your module, and the error is coming into your module where the “nodeCacheClient” is undefined since it was not defined!
Your error is coming from your “getCache()” function, in this syntax:
return nodeCacheClient.get(key);
Where in your test you didnt call for the “initNodeCache()” method which will do
nodeCacheClient = new NodeCache();
So, for your test scope, the nodeCacheClient is undefined, and that’s why
nodeCacheClient.get(key);
Will return the
typeError: Cannot read property 'get' of undefined Error
How can I use this inside a callback? Using callback, I got undefined on this.callback() (this is undefined):
constructor(collection, journey, callback, environment=null) {
this.collection = collection;
this.journey = journey;
this.callback = callback;
console.log(this.callback)
this.environment = environment;
}
run() {
newman.run({
collection: this.collection,
environment: this.environment,
insecure: true
}, this.internalCallback).on('console', function (err, args) {
console.log(args.messages.join(' '));
})
}
internalCallback(error, summary) {
if(error || summary.error) throw (error || summary.error)
console.log(this)
this.callback(this.journey, summary) // here throws an error because this is undefined
}
I assume that newman.run creates a new "this" context in your code. Have you tried binding the function: this.internalCallback.bind(this) to this of your class when passing it to newman.run?
Try this code:
run() {
newman.run({
collection: this.collection,
environment: this.environment,
insecure: true
}, this.internalCallback.bind(this)).on('console', function (err, args) {
console.log(args.messages.join(' '));
})
}
Can you try something like this:
that = this;
constructor(){
}
internalCallback(error, summary) {
if(error || summary.error) throw (error || summary.error)
console.log(this)
that.callback(that.journey, summary) // here throws an error because this is undefined
}
In my mocha testframework, I have an it-block that might throw an error. How do I obtain this error in the afterEach-hook that is called afterwards? Is there any workaround if it is not directly passed?
...
afterEach(async function () {
var testObject = {
title: this.currentTest.title,
state: this.currentTest.state,
duration: this.currentTest.duration,
timedOut: this.currentTest.timedOut,
error: this.currentTest.err // I want the error object here
}
});
it('my title', () => {
try {
doSomethingThatMightThrowError();
} catch (err) {
throw new Error(err)
}
});
....
How to build an Error object instead of give its a string? https://codesandbox.io/s/pwr973487x
async function getUrl() {
try {
const res = await axios.get('https://httpstat.us/500')
} catch(e) {
const errorObj = {
status: 500,
message: 'Internal server error, something is not defined etc'
}
throw new Error('err') //how to build object?
}
}
I want throw Error() to return errorObj. Do I have to do my own class to do that or I can modify the existing Error class for that? I need that so it standardize my error message of my different set of Apis.
You can use the error object returned from catch
try {
const res = await axios.get('https://httpstat.us/500')
} catch(e) {
e.message = 'Internal server error, something is not defined etc';
throw e;
}
You can just add a field to the Error object, e.g.
var err = new Error('Internal Server error');
err.customField = { someProperty: 'some value'};
console.log(err);
And then you can throw it as normal:
throw err;
When you catch the error (higher up in the call stack) you can pull out the custom field:
try
{
throw err;
}
catch (e)
{
console.error(e);
console.log(e.customField);
}
With ES6 onwards you can also create your own error class:
class MyError extends Error {
constructor(message, customValue) {
super(message);
this.field = customValue;
}
get customField() {
return this.field;
}
set customField(obj) {
this.field = obj;
}
};
var ex = new MyError('Error message', {someProperty: 'some value'});
console.dir(ex);
console.log('My custom error details: ', ex.customField);
you could try with the cause propoty of :
TS has inaccurate value type about it at present, this is being discussed on the official to revolve it.
try {
throw new Error('Failed in some way', {
cause: {status: 400}
});
} catch(e) {
console.log(e); // Error('Failed in some way')
console.log(e.cause) // {status: 400}
}
or throw the Error instance with the custom property
try {
const error = new Error('Failed in some way');
error.status = 400;
throw error;
} catch(e) {
console.log(e); // Error('Failed in some way')
console.log(e.status) // 400
}