Autofac/Automapper - Custom value resolvers Error - automapper

Autofac Registration:
builder.RegisterType<RelatedTransportMangerResolver>().AsSelf();
builder.Register(context => new MapperConfiguration(cfg =>
{
cfg.AddProfile<AssetMapperProfile>();
})).AsSelf().SingleInstance();
builder.Register(c => c.Resolve<MapperConfiguration>().CreateMapper(c.Resolve))
.As<IMapper>()
.InstancePerLifetimeScope();
Map that uses the custom value resolver:
CreateMap<TrafficArea, TrafficAreaViewModel>()
.ForMember(ta => ta.TransportManagers,
opt => opt.MapFrom(ta =>
ta.TrafficAreaKeyContacts
.Where(kc => kc.KeyContactGroup.HasFlag(KeyContactGroup.TransportManager))
.Select(atr => atr.KeyContact)))
.ForMember(ta => ta.RelatedTransportManagers,
opt => opt.MapFrom<RelatedTransportMangerResolver>());
Error being returned is:
This resolve operation has already ended. When registering components using lambdas, the IComponentContext 'c' parameter to the lambda cannot be stored. Instead, either resolve IComponentContext again from 'c', or resolve a Func<> based factory to create subsequent components from.
Any ideas on how to fix this error?

Should of done a bit more digging myself first...
Fix here if anybody has this same issue:
builder.Register(c =>
{
//This resolves a new context that can be used later.
var context = c.Resolve<IComponentContext>();
var config = context.Resolve<MapperConfiguration>();
return config.CreateMapper(context.Resolve);
})
.As<IMapper>()
.InstancePerLifetimeScope();

Related

Knex.js return transactionScope in promise

I've got a function setClaims which is simply setting claims for current transaction. I need to create a helper function which will check if uuid was provided, set claims and return the transaction object. Something like this:
export const useAuthTransaction = async (
kx: Knex,
setClaims: (tx: Knex.Transaction, uuid?: string) => Promise<any>,
uuid?: string,
): Promise<Knex.Transaction> => {
if (!uuid) {
throw { errorCodes: [RemoveQuestionErrorCode.Unauthorized] };
}
return kx.transaction(async tx => {
await setClaims(tx);
return tx;
});
};
But when I try to use it in my resolver:
useAuthTransaction(kx, setClaims, claims?.uid).then(async tx =>
dataSources.questionAPI.update(tx, input));
it says:
Transaction query already complete
How do I resolve transaction context without closing it?
Returning promise from transaction handler automatically commits / rejects it.
So you are using async tx => {...} type of handler which implicitly always returns a promise.
What you want to do is to use the knex.transactionProvider() feature (check examples from docuementation) and then you can pass that transaction around and tell explicitly when it should be committed / rolled back.

Parameterize Jest's expect

I can't pass a function that throws into expect() as due to operator precedence that will throw before Jest can try-catch it.
So instead of this:
expect(thisThrows())
We must do this:
expect(() => thisThrows())
But say I want to parameterize it:
test("foo", () => {
const sut = (arg) => { if (!arg) throw new Error(); };
expect(sut(undefined)).toThrow();
expect(sut(null)).toThrow();
expect(sut(0)).toThrow();
expect(sut("")).toThrow();
expect(sut(10)).not.toThrow();
});
This still has the original problem.
How can I do something like this neatly, so I can keep my tests DRY?
Since sut() throws an error, it cannot be called directly as expect(sut(undefined) because the error is thrown immediately and it cannot be asserted.
It should be treated the same way as with expect(() => thisThrows()):
expect(() => sut(undefined)).toThrow();

Are there reasonable exemptions for eslint promise/no-nesting rule?

An eslint promise/no-nesting rule violation will occur for the following example:
return foo()
.catch(handleErrorAndReject('foo'))
.then(() => bar().catch(handleErrorAndReject('bar')))
.then(() => baz().catch(handleErrorAndReject('baz')))
Note that handleErrorAndReject is a curried function like this:
const handleErrorAndReject = action => error => {
console.warn(`${action} fails with error`, error)
res.status(400).send(error.message).end()
return Promise.reject(error)
}
But the nested catches seem necessary in this case, because they vary by stage. Is this a case where I should just eslint-disable, or is there a better way to structure this code?

How do you detect UniqueConstraintError in Sequelize?

I want to retry creating record in case unique attribute is already there, so how do I check if failure to create new record is due to UniqueConstraintError.
I'm trying to find an example code but haven't been able to find anything.
import {UniqueConstraintError} from 'sequelize'
Model
.create({...})
.then(obj => {})
.catch(err => {
if(err instanceof UniqueConstraintError){
throw new Error('duplicate error')
}
else{
throw err
}
})
If you also need the field name (which caused this error) this might help
err.errors[0].path
Model.create(objectToCreate)
.catch(sequelize.UniqueConstraintError, () => { // TODO });
If you use bulkCreate you can use boolean property in option ignoreDuplicates (not supported by Postgres) or updateOnDuplicate (only supported by MySQL)

Testing Promises with multiple thens using testdoublejs

I am using testdouble for stubbing calls within my node.js project. This particular function is wrapping a promise and has multiple then calls within the function itself.
function getUser (rethink, username) {
return new Promise((resolve, reject) => {
let r = database.connect();
r.then(conn => database.table(tablename).filter({username}))
.then(data => resolve(data))
.error(err => reject(err));
});
}
So I am wanting to determine if the resolve and reject are handled correctly based on error conditions. Assume there is some custom logic in there that I need to validate.
For my test
import getUser from './user';
import td from 'testdouble';
test(t => {
const db = td.object();
const connect = td.function();
td.when(connect('options')).thenResolve();
const result = getUser(db, 'testuser');
t.verify(result);
}
The issue is that the result of connect needs to be a promise, so I use then resolve with a value which needs to be another promise that resolves or rejects.
The line it is relating to is the result of database.connect() is not a promise.
TypeError: Cannot read property 'then' of undefined
Anyone have success with stubbing this type of call with Test Double?
So figured out the resolution. There are a few things to note in the solution and that we encountered. In short the resolution ended up being this...
td.when(database.connect()).thenResolve({then: (resolve) => resolve('ok')});
This resolves a thenable that is returned when test double sees database connect. Then subsequent calls can also be added.
There is also a part to note if you send in an object to database.connect() you have to be aware that it is doing === equality checking and you will need to have a reference to that object for it to correctly use td.when.
Test double provides stubs for unit testing. And in your case 'db' is the object we need to mock. Creating the mocking db through
td.object(Database) // Database is the class or constructor of your db
will be the right choice, but to simply mock those methods you need in this case, I wouldn't pick that way.
Here's the tested module, 'some.js':
function getUser (database, username) {
return new Promise((resolve, reject) => {
let r = database.connect();
r.then(conn => database.table('table').filter({username:username}))
.then(data => resolve(data))
.catch(err => reject(err));
});
}
module.exports = getUser;
And the test file, using mocha and chai.expect, which is could also be any other unit test module here:
let td = require('testdouble');
let expect = require('chai').expect;
const getUser = require('./some');
describe('some.js',()=>{
it('getUser',()=>{
const db = {};
const name = 'name';
db.connect = td.function();
db.table = td.function('table');
db.filter = td.function('filter');
td.when(db.connect()).thenResolve(db);
td.when(db.table('table')).thenReturn(db);
td.when(db.filter({username: name})).thenResolve('some user data');
return getUser(db, name)
.then(user=>{
expect(user).to.equal('some user data')
})
.catch(e=>assert(e))
})
})
So please let me know if any of these confuse you.

Resources