概要
Angular での開発において、DOM 操作などのために window.document
を参照することはあるかと思います。
@angular/common
には、DOCUMENT
という DI Token が用意されています。こちらを利用することで、依存注入経由で document を参照することができますし、またテストも書きやすくなります。
※ この記事を執筆してる時点での Angular の最新バージョンは v13.1.2
になります。
サンプルコード
以下、 DOCUMENT
経由で querySelector
を利用するような Service クラスのサンプルコードです。
import { DOCUMENT } from '@angular/common'; import { Inject, Injectable } from '@angular/core'; @Injectable({ providedIn: 'root' }) class FooService { constructor( @Inject(DOCUMENT) private document: Document ) {} prependSomething() { const foo = this.document.querySelector('#foo') foo.prepend('something') } }
グローバル空間である window に直接依存しなくなりましたね。
依存注入を利用したので、テストが書きやすくなります。
以下、 DOCUMENT
を依存注入して querySelector
をモックするようなサンプルテストコードです
import { DOCUMENT } from '@angular/common'; import { getTestBed, TestBed } from '@angular/core/testing'; import { FooService } from './foo.service.ts' describe('FooService', () => { let service: FooService; const mockElement = { prepend: jasmine.createSpy('prepend'), // 必要な spy はここに適宜追加してください } beforeEach(() => { TestBed.configureTestingModule({ providers: [ FooService, { provide: DOCUMENT, useValue: { querySelector: () => mockElement } }, ], }); service = getTestBed().inject(DownloadReportDialogService); }) it('prependSomething', () => { service.prependSomething() expect(mockElement.prepend).toHaveBeenCalledWith('something') }) })
document を configureTestingModule
の中で依存注入したので、window.document をテストコードから直接参照せずに済みました。
また、window.document を直接触るような場合、他のテストに影響を与えないように、適切なリセット処理が必要になり、少し面倒くさい…という問題があります。
以上、「@angular/common の DOCUMENT を利用して、window.document を依存注入する」でした。
参考URL
- 公式ドキュメント: Angular - DOCUMENT
- Medium の解説記事: How to Inject Document in Angular | by Jared Youtsey | ngconf | Medium