Is it possible to access the ctx context in #beforeSave Adonis 5? - adonis.js

How could I do something like that?
#beforeSave()
public static async audit(model: Model) {
console.log(ctx.auth.user)
await Audit.create({
model,
ctx.auth.user
})
}

Related

NestJS: How can I mock ExecutionContext in canActivate

I am having trouble in mocking ExecutionContext in Guard middleware.
Here's my RoleGuard extends JwtGuard
#Injectable()
export class RoleGuard extends JwtAuthGuard {
...
async canActivate(context: ExecutionContext): Promise<boolean> {
const request = context.switchToHttp().getRequest();
const params = request.params;
...
}
}
This is what I am trying on my unit test.
let context: ExecutionContext = jest.genMockFromModule('#nestjs/common');
context.switchToHttp = jest.fn().mockResolvedValue({
getRequest: () => ({
originalUrl: '/',
method: 'GET',
params: undefined,
query: undefined,
body: undefined,
}),
getResponse: () => ({
statusCode: 200,
}),
});
jest.spyOn(context.switchToHttp(), 'getRequest').mockImplementation(() => {
return Promise.resolve(null);
});
And I am getting this kind of error.
Cannot spy the getRequest property because it is not a function; undefined given instead
I would like you to suggest any other way to mock context. Thank you.
Please check this library https://www.npmjs.com/package/#golevelup/ts-jest
Then you could mock ExecutionContext as following.
import { createMock } from '#golevelup/ts-jest';
import { ExecutionContext } from '#nestjs/common';
describe('Mocked Execution Context', () => {
it('should have a fully mocked Execution Context', () => {
const mockExecutionContext = createMock<ExecutionContext>();
expect(mockExecutionContext.switchToHttp()).toBeDefined();
...
});
});
Hope it helps
When it comes to the ExecutionContext, depending on what I'm tetsting, I just supply a simple object instead, something like
const ctxMock = {
switchToHttp: () => ({
getRequest: () => ({
params: paramsToAdd,
url: 'some url path',
...
}),
}),
}
And use that as I need. If I need access to jest functions I save those to a variable before hand and assign the context's function to the variable, then I can use expect(variable).toHaveBeenCalledTimes(x) without a problem.
Another option is to use #golevelup/ts-jest to create type safe mock objects for you. I've made extensive use of this library as well for other libraries I've made.

How to enter transaction callback in typeorm?

I'm kind of new in unit testing and trying to make some test with typeorm.
The code I've is this:
public executeTransaction(querys: IQueryTransaction[]) {
return getManager().transaction(async transactionalManager => {
for (const query of querys) {
await transactionalManager.query(query[0], query[1]);
}
});
}
I need to enter the transaction callBack but can't figured out how to do it. I tried to mock getManager and transaction playing with it, but with no results.
I'm using jest, typeorm and nest.
Someone knows how to do this?.
EDIT: Connecting to the database is not an option
I think you should try something like this...
return await getManager().transaction(async transactionalManager => {
for (const query of querys) {
await transactionalManager.query(query[0], query[1]);
}
});
OR
import {getManager} from "typeorm";
await getManager().transaction(async transactionalManager => {
await transactionalManager.save(users);
await transactionalManager.save(photos);
});
OR
#Controller("/user")
export class UserController {
constructor(
private userService: UserService,
) {}
#Post("/")
#Transaction()
async createNewUser(#Body() body: UserDTO) {
return await this.userService.createNewUser(body);
}
}
you can use Istambul to simplify your life.
/* istanbul ignore next */

Doing a mocha and chai unit testing for node js that need to query from dynamodb

Hi I am new to AWS dynamdoDB and mocha chai unit testing.
I wanted to create a node js unit testing with mocha and chai.
In my test.js i need to get expected outcome from AWS dynamoDB. However i not sure how to do it.
in my test.js
var assert = require('chai').assert;
describle('querying items from dynamodb', function(){
it('find date in Month collection', function(){
//not sure how should i put my inputs in here.
});
})
Do you have any articles or resources that I should read on?
If you want to make actual calls to AWS DynamoDB, a simple way to do it would be the following (based on documentation found for DynamoDB and DynamoDB.DocumentClient):
const assert = require('chai').assert;
const AWS = require('aws-sdk');
describe('querying items from dynamodb', function(){
it('find date in Month collection', function(done){
var params = {
TableName : <TEST_TABLE_NAME>,
Key: {
<PRIMARY_KEY>: <TEST_KEY_VALUE>
}
};
var expectedDate = <EXPECTED_VALUE>;
var documentClient = new AWS.DynamoDB.DocumentClient({apiVersion: '2012-08-10'});
documentClient.get(params, function(err, data) {
assert.strictEqual(data.Item.Date, expectedDate);
done();
});
});
});
BUT BUYER BEWARE! This will make calls to your actual DynamoDB and AWS may charge you money! To avoid this, mocking is highly recommended. Mocking calls to your DynamoDB can be done with the following code (based on documentation found on github, npmjs.com, and npmdoc.github.io):
const assert = require('chai').assert;
const AWS = require('aws-sdk');
const MOCK = require('aws-sdk-mock');
describe('querying items from dynamodb', function(){
before(() => {
// set up a mock call to DynamoDB
MOCK.mock('DynamoDB.DocumentClient', 'get', (params, callback) => {
console.log('Let us not call AWS DynamoDB and say we did.');
// return fake data
let fakeData = {
Item: {
Date: <FAKE_DATE>
}
};
return callback(null, fakeData);
});
});
after(() => {
// restore normal function
MOCK.restore('DynamoDB.DocumentClient');
});
it('find date in Month collection', function(done){
// set up the call like it's real
var params = {
TableName : <TEST_TABLE_NAME>,
Key: {
<PRIMARY_KEY>: <TEST_KEY_VALUE>
}
};
var expectedDate = <EXPECTED_VALUE>;
var documentClient = new AWS.DynamoDB.DocumentClient({apiVersion: '2012-08-10'});
documentClient.get(params, function(err, data) {
// data should be the fake object that should match
assert.strictEqual(data.Item.Date, expectedDate);
done();
});
});
});

Stubbing vuex getters with sinonjs

On my application, inside a navigation guard used by my router, I have a vuex namespaced getter to check authentication state. The getter do the magic underlaying check if the user is authenticated.
I want to write a simple unit test which check that the redirection is done according to the authenticated state. I'm stucked on stubbing the getter.
My getter is the following :
isAuthenticated (state) {
return state.token !== null
}
My authentication module is the following :
export default {
namespaced: true,
state,
getters
}
And my store is the following :
export default new Vuex.Store({
modules: {
authentication
}
})
My naviguation guard is :
import store from '#/store'
export default (to, from, next) => {
if (store.getters['authentication/isAuthenticated']) {
next()
return
}
next({name: 'login'})
}
I've wrote that unit test :
describe('authenticated-guard.spec.js', () => {
let authenticatedStub
beforeEach(() => {
authenticatedStub = sandbox.stub(store.getters, 'authentication/isAuthenticated')
})
afterEach(() => {
sandbox.restore()
})
it('should redirect to login route when the user is not authenticated', () => {
// Given
const to = {}
const from = {}
const next = spy()
authenticatedStub.value(false)
// When
authenticatedGuard(to, from, next)
// Then
assert.ok(next.calledWith({name: 'login'}), 'should have redirected to login route')
})
})
The unit test trigger the following error : TypeError: Cannot redefine property: authentication/isAuthenticated.
I've tried as an alternative to stub using authenticatedStub.value(false) but the error is the same.
I'm unable to stub the getter to avoid to have store logics on guard tests.
Does someone beeing able to stub any getter outside of components ?
Regards
The problem is that vuex sets the getters as non-configurable properties, so they can't be changed.
A way to stub them is to stub the getters object itself so your test could work like this:
describe('authenticated-guard.spec.js', () => {
it('should redirect to', () => {
const authenticatedStub = sandbox.stub(store, 'getters')
// Given
const to = {}
const from = {}
const next = spy()
authenticatedStub.value({
'authentication/isAuthenticated': false
})
// When
authenticatedGuard(to, from, next)
// Then
expect(next.lastCall.args).to.deep.equal([{name: 'login'}], 'login route when the user is not authenticated')
authenticatedStub.value({
'authentication/isAuthenticated': true
})
authenticatedGuard(to, from, next)
expect(next.lastCall.args).to.deep.equal([], 'next route when the user is authenticated')
})
})

Stubbing the mongoose save method on a model

I would like to stub the save method available to Mongoose models. Here's a sample model:
/* model.js */
var mongoose = require('mongoose');
var userSchema = mongoose.Schema({
username: {
type: String,
required: true
}
});
var User = mongoose.model('User', userSchema);
module.exports = User;
I have some helper function that will call the save method.
/* utils.js */
var User = require('./model');
module.exports = function(req, res) {
var username = req.body.username;
var user = new User({ username: username });
user.save(function(err) {
if (err) return res.end();
return res.sendStatus(201);
});
};
I would like to check that user.save is called inside my helper function using a unit test.
/* test.js */
var mongoose = require('mongoose');
var createUser = require('./utils');
var userModel = require('./model');
it('should do what...', function(done) {
var req = { username: 'Andrew' };
var res = { sendStatus: sinon.stub() };
var saveStub = sinon.stub(mongoose.Model.prototype, 'save');
saveStub.yields(null);
createUser(req, res);
// because `save` is asynchronous, it has proven necessary to place the
// expectations inside a setTimeout to run in the next turn of the event loop
setTimeout(function() {
expect(saveStub.called).to.equal(true);
expect(res.sendStatus.called).to.equal(true);
done();
}, 0)
});
I discovered var saveStub = sinon.stub(mongoose.Model.prototype, 'save') from here.
All is fine unless I try to add something to my saveStub, e.g. with saveStub.yields(null). If I wanted to simulate an error being passed to the save callback with saveStub.yields('mock error'), I get this error:
TypeError: Attempted to wrap undefined property undefined as function
The stack trace is totally unhelpful.
The research I've done
I attempted to refactor my model to gain access to the underlying user model, as recommended here. That yielded the same error for me. Here was my code for that attempt:
/* in model.js... */
var UserSchema = mongoose.model('User');
User._model = new UserSchema();
/* in test.js... */
var saveStub = sinon.stub(userModel._model, 'save');
I found that this solution didn't work for me at all. Maybe this is because I'm setting up my user model in a different way?
I've also tried Mockery following this guide and this one, but that was way more setup than I thought should be necessary, and made me question the value of spending the time to isolate the db.
My impression is that it all has to do with the mysterious way mongoose implements save. I've read something about it using npm hooks, which makes the save method a slippery thing to stub.
I've also heard of mockgoose, though I haven't attempted that solution yet. Anyone had success with that strategy? [EDIT: turns out mockgoose provides an in-memory database for ease of setup/teardown, but it does not solve the issue of stubbing.]
Any insight on how to resolve this issue would be very appreciated.
Here's the final configuration I developed, which uses a combination of sinon and mockery:
// Dependencies
var expect = require('chai').expect;
var sinon = require('sinon');
var mockery = require('mockery');
var reloadStub = require('../../../spec/utils/reloadStub');
describe('UNIT: userController.js', function() {
var reportErrorStub;
var controller;
var userModel;
before(function() {
// mock the error reporter
mockery.enable({
warnOnReplace: false,
warnOnUnregistered: false,
useCleanCache: true
});
// load controller and model
controller = require('./userController');
userModel = require('./userModel');
});
after(function() {
// disable mock after tests complete
mockery.disable();
});
describe('#createUser', function() {
var req;
var res;
var status;
var end;
var json;
// Stub `#save` for all these tests
before(function() {
sinon.stub(userModel.prototype, 'save');
});
// Stub out req and res
beforeEach(function() {
req = {
body: {
username: 'Andrew',
userID: 1
}
};
status = sinon.stub();
end = sinon.stub();
json = sinon.stub();
res = { status: status.returns({ end: end, json: json }) };
});
// Reset call count after each test
afterEach(function() {
userModel.prototype.save.reset();
});
// Restore after all tests finish
after(function() {
userModel.prototype.save.restore();
});
it('should call `User.save`', function(done) {
controller.createUser(req, res);
/**
* Since Mongoose's `new` is asynchronous, run our expectations on the
* next cycle of the event loop.
*/
setTimeout(function() {
expect(userModel.prototype.save.callCount).to.equal(1);
done();
}, 0);
});
}
}
Have you tried:
sinon.stub(userModel.prototype, 'save')
Also, where is the helper function getting called in the test? It looks like you define the function as the utils module, but call it as a method of a controller object. I'm assuming this has nothing to do with that error message, but it did make it harder to figure out when and where the stub was getting called.