I have a Angular service that looks something like this:
import {environment} from '../environment'
....
public something() {
if(environment.production)
{
// do stuf
} else {
// do something else
}
}
Now i want to test both cases (dev and prod environemnt). How do I "mock" when the environment is imported ?
So i came up with a solution where I didn't have to check for the environment in my service:
I used the useFactory:
NgModule({
declarations: [],
imports: [],
providers: [
{
provide: Service,
useFactory: (httpClient: HttpClient) => {
if (environment.production) {
return new MyCustomService(httpClient);
} else {
return new Service();
}
},
deps: [HttpClient],
}
],
bootstrap: [AppComponent]
})
This way i manage which service is provided when the application is started up
Related
I have the following error :
Nest can't resolve dependencies of the ParametrageRepository (?). Please make sure that the argument DataSource at index [0] is available in the TypeOrmModule context.
My test code :
describe("ParametrageController (e2e)", () => {
let parametrage: INestApplication;
beforeEach(async () => {
const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [ParametrageModule],
}).compile();
parametrage = moduleFixture.createNestApplication();
await parametrage.init();
});
it("/ (POST)", () =>
request(parametrage.getHttpServer())
.post("/parametrage")
.send({
libelle: "GROUPE_TYPE",
liste: ["TEAM", "SERVICE", "ORGANISATION"],
})
.expect(201));
});
My module code:
#Module({
imports: [TypeOrmModule.forFeature([Parametrage])],
exports: [TypeOrmModule],
controllers: [ParametrageController],
providers: [ParametrageService, ParametrageRepository, ParametrageActions, Logger],
})
export class ParametrageModule {}
I cannot tel why I have this error since I followed the Nestjs documentation. Maybe I skipped a part I don't know. Maybe it's because of my providers that has parameters in their constructors :
My ParametrageRepository provider :
#Injectable()
export class ParametrageRepository
extends RepositoryStarter<Parametrage, IParametrageListFilter>
implements IParametrageRepository
{
constructor(#InjectDataSource() datasource: DataSource) {
super(datasource.getRepository(Parametrage));
}
I tried to add providers injection :
const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [ParametrageModule],
** providers: [
{ provide: ParametrageActions, useValue: ParametrageActions },
{ provide: ParametrageRepository, useValue: ParametrageRepository },
{ provide: Logger, useValue: Logger ,
],**
}).compile();
But stil the same error, it didn't solved anything
Thanks in advance
I am developing a module that suppport forRoot and forChild. Whenever this module is imported with forRoot, forChild some methods of a custom service should be called. It works well for forRoot since I use APP_INITIALIZER, but the factory is not called anymore in the forChild of a lazy loaded module. How can I execute the methods that I have in my factory in the forChild so that it also works with lazy loaded modules? Is there some sort of equivelant of the APP_INITIALIZER for lazy loaded modules or a workaround?
export const TRANSLATION_CONFIGURATION = new InjectionToken<TranslationConfiguration<any>>('');
function initializeAppFactory(config: TranslationConfiguration<any> & { language: Language }, locutus: LocutusService): () => void {
return () => {
if (config.language) {
locutus.registerRoot(config);
return;
}
locutus.registerChild({
scope: config.scope,
loaders: config.loaders
});
};
}
#NgModule({
declarations: [
NgxLocutusComponent,
LocutusDirective,
LocutussPipe
],
imports: [
CommonModule
],
exports: [
NgxLocutusComponent,
LocutusDirective,
LocutussPipe
]
})
export class LocutusModule {
static forRoot<T>(config: TranslationConfiguration<T> & { language: Language }): ModuleWithProviders<LocutusModule> {
return {
ngModule: LocutusModule,
providers: [
{
provide: TRANSLATION_CONFIGURATION,
useValue: config,
},
{
provide: APP_INITIALIZER,
useFactory: initializeAppFactory,
deps: [
TRANSLATION_CONFIGURATION,
LocutusService
],
multi: true
},
]
};
}
static forChild<T>(config: TranslationConfiguration<T>): ModuleWithProviders<LocutusModule> {
return {
ngModule: LocutusModule,
providers: [
{
provide: TRANSLATION_CONFIGURATION,
useValue: config,
},
{
provide: APP_INITIALIZER,
useFactory: initializeAppFactory,
deps: [
TRANSLATION_CONFIGURATION,
LocutusService
],
multi: true
},
]
};
}
}
I have some Service, which requires a config object literal in its constructor, something like this:
#Injectable()
export class BatteriesService {
constructor(private config: Config) { }//The provider needs a config object
}
If I simply add this class in the providers array of the module, I obviously get an error, being that a constructor argument is missing.
So, instead of just referencing the BatteriesService class, I need to somehow create an instance. I tried this:
#Module({
controllers: [BatteriesController],
providers: [{
useFactory: ()=>{
return new BatteriesService({'someProp': 'someValue'})
},
provide:'BatteriesService'
}]
})
And this:
#Module({
controllers: [BatteriesController],
providers: [{
useValue:new BatteriesService({'someProp': 'someValue'}),
provide:'BatteriesService'
}]
})
In both cases I get the following error:
Error: Nest can't resolve dependencies of the BatteriesController (?).
Please make sure that the argument BatteriesService at index [0] is
available in the BatteriesModule context.
How can this done, without "resorting" to bypassing the DI system, or creating another "inner" provider(config)?
When you need to have DI in service that has to be defined in the module.
In your case
#Injectable()
export class BatteriesService {
constructor(private config: ConfigService) { }
}
#Module({
imports: [ConfigModule.forRoot({})], // Configure it as needed
providers: [BatteriesService]
})
Your mistake is that you don't actually import ConfigModule while your service is dependent on it.
If you wish to use useFactory method then it would look like
#Module({
providers: [{
useFactory: (config: ConfigService) => {
return new BatteriesService(config);
},
provide: BatteriesService,
inject: [ConfigService]
}]
})
I assumed your Config is actually Nest ConfigModule.
But if it's some custom Module you still need to import it as in the above examples.
If you want to pass an object literal as a config try this
interface MyConfigType = {
something: string;
}
#Injectable()
export class BatteriesService {
constructor(#Inject('CONFIG') private config: MyConfigType) { }
}
#Module({
providers: [{
provide: 'CONFIG',
useValue: {
something: 'my-value'
}
}]
})
I have some service in which I inject the CACHE_MANAGER in the constructor
import { CACHE_MANAGER, Inject, Injectable } from '#nestjs/common';
import { Cache } from 'cache-manager';
...
export class ManagerService {
constructor(#Inject(CACHE_MANAGER) private cacheManager: Cache) {}
...
}
That gives me an error when I test the modules the import those service
Nest can't resolve dependencies of the ManagerService (?). Please make sure that the argument CACHE_MANAGER at index [0] is available in the Web3ManagerService context.
I'm relatively new to NestJs so I really cannot figure out how to solve it
To inject the cache manager provider under the CACHE_MANAGER, you need to import the nestjs module that creates this provider into the module that has the ManagerService
#Module({
imports: [CacheModule.register()], // <<<<
providers: [ManagerService],
})
export class AppModule {}
like the docs shows https://docs.nestjs.com/techniques/caching
I just had the same problem and resolved it this way:
manager.service.spec.ts
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [ManagerService, { provide: CACHE_MANAGER, useValue: {} }],
}).compile();
service = module.get<ManagerService>(ManagerService);
});
Set isGlobal: true:
CacheModule.register({
url: process.env.REDIS_URL,
db: 0,
port: parseInt(process.env.REDIS_PORT),
password: process.env.REDIS_PASSWORD,
isGlobal: true, //<<<<<<<
})
I am using the neo4j-graphql-js library to translate graphql queries to cypher and I need to implement an interceptor to verify that what is returning belongs to the user who is asking for it. For this I need to implement the interceptor but the problem I have is that I have no resolvers since it generates the liberia. How can I make it go through the interceptor? If the interceptor cannot be used, is there a way to implement a middleware in the response?
I'm using nestjs framework. And I use a neo4j database.
Thank you.
Module:
#Module({
imports: [
GraphQLModule.forRootAsync({
useClass: GraphqlConfigService,
}),
],
providers: [neo4jProvider],
})
export class GraphqlModule {
configure(consumer: MiddlewareConsumer) {
consumer
.apply(GraphQLAuthMiddleware,GraphQLRoleMiddleware)
.forRoutes('graphql');
}
}
#Injectable()
export class GraphqlConfigService implements GqlOptionsFactory {
async createGqlOptions(): Promise<GqlModuleOptions> {
const schema = buildSchema();
return {
playground: true,
schema: schema,
path: '/graphql/queries',
context: {
driver: neo4j.driver(
'bolt://neo4j_db:7687',
neo4j.auth.basic('neo4j', 'root')
)
}
};
}
}
function buildSchema(): GraphQLSchema {
return makeAugmentedSchema({
typeDefs,
config: {
query: true,
mutation: true
}
});
}
You can bind your interceptor globally either by using the app.useGlobalInterceptors(MyCustomInterceptor) method in your main.ts or in any module you can add the interceptor in your providers array
#Module({
imports: [/* your imports*/],
providers: [
{
provide: APP_INTERCEPTOR,
useClass: MyCustomInterceptor
},
/* the rest of your providers*/
],
})
export class GraphqlModule {}
APP_INTERCEPTOR is imported from #nestjs/core. Keep in mind, this does bind the interceptor globally. All requests to your server will go through this interceptor.