Scope.Requestを使うケース
こういうの
https://qiita.com/rdlabo/items/7c25b711fa8db99512a6
起きること
@Injectable({
scope: Scope.Request
})
class AwesomeService {...}
こういうサービスを使っているクラスのテストがコケる。
● Site Controller › list site api › should return items
TypeError: Cannot read property 'loadCurrentUser' of undefined
35 | })
36 | public async listSites(): Promise<SiteResponseItemDTO[]> {
> 37 | const { Username: username } = this.cognito.loadCurrentUser();
|
DIしたはずのクラスがundefinedになっており、メソッドが見つからないというエラーが出る。
実動作について
yarn start
やsls offline
などで動かす分には問題がない。
あくまでテストだけ。
対応方法:Scopeをdefaultにする
要はScopeをテストの時だけDefaultにすればOKです。
対応1: テストコードで上書きする
createTestingModule
する時にscopeを上書きしてやると、undefinedにならなくなります。
const mod = await Test.createTestingModule({
providers: [{
provide: LoginService,
useClass: LoginService,
scope: Scope.DEFAULT
}],
}).compile();
対応2: module.get
をmodule.resolve
にする
対応1で動かない場合、テスト対象クラスを取得する処理をget
からresolve
に変えると動く場合もあります。
const mod = await Test.createTestingModule({
controllers: [AdminController],
providers: [{
provide: LoginService,
useClass: LoginService,
scope: Scope.DEFAULT
}],
}).compile();
// Before
const controller = mod.get<AdminController>(AdminController)
// After
const controller = await mod.resolve<AdminController>(AdminController)
対応3: 定義側で変える
@Injectable
する時に環境変数で変えてしまうという手もあります。
@Injectable({
// @See https://github.com/nestjs/nest/issues/2049#issuecomment-559959575
scope: process.env.NODE_ENV === 'test' ? Scope.DEFAULT : Scope.REQUEST,
})
class AwesomeService {...}
そのほか
Scope.Requestの場合、module.get
ではなくawait module.resolve
を使う必要がある。
const mod = await Test.createTestingModule({
providers: [LoginService],
}).compile();
// Error
// LoginService is marked as a scoped provider.
// Request and transient-scoped providers can't be used in combination with "get()" method.
// Please, use "resolve()" instead.
const service = mod.get<LoginService>(LoginService);
// うごく
service = await mod.resolve<LoginService>(LoginService)
参考
結構遭遇している人が多いみたい。
https://github.com/nestjs/nest/issues/2049