Issue with Dependency Injection in Angular 5 and Webpacker Integration
Upon integrating webpacker with Angular 5 into an existing Rails application, everything seemed to be functioning properly except for a peculiar issue with Dependency Injection during testing.
It appears that my Angular components are only functional when created through the browser; however, when tested using Jasmine/Karma, the Dependency Injector fails to recognize injection tokens. Here is some pseudo code illustrating the problem:
@Component({...})
export class SomeComponent {
constructor(private service: SomeService) {}
}
In the browser environment, the above code works without any issues. However, during testing, it throws an error stating
Error: Can't resolve all parameters for SomeComponent: (?).
. Upon further investigation, I noticed that this issue extends to all @Injectable()s. A temporary workaround involves replacing each injection with explicit @Inject as shown below:
@Component({...})
export class SomeComponent {
constructor(@Inject(SomeService) private service: SomeService) {}
}
While this solution resolves the problem, it is not ideal due to its cumbersome nature. Is there any obvious reason causing this behavior?
Code Snippets
Here's a simple service utilizing HttpClient:
import { Injectable } from "@angular/core";
import { HttpClient } from "@angular/common/http";
import 'rxjs/add/operator/map'
@Injectable()
export class GeneralStatsService {
constructor(
private http : HttpClient
) {}
getMinDate() {
return this.http.get("/api/v1/general_stats/min_date")
.map(r => new Date(r))
}
}
The service functions correctly within components calling it but encounters failures during Jasmine tests:
import { TestBed } from "@angular/core/testing";
import { HttpClientTestingModule, HttpTestingController } from "@angular/common/http/testing";
import { GeneralStatsService } from "./general-stats.service";
describe('GeneralStatsService', () => {
let service : GeneralStatsService;
let httpMock : HttpTestingController;
beforeEach(()=> {
TestBed.configureTestingModule({
imports: [
HttpClientTestingModule
],
providers: [
GeneralStatsService
]
})
});
beforeEach(() => {
service = TestBed.get(GeneralStatsService);
httpMock = TestBed.get(HttpTestingController);
});
afterEach(() => {
httpMock.verify();
});
describe('getMinDate()', () => {
let fakeResponse : string = "2015-03-05T12:39:11.467Z";
it('returns instance of Date', (done) => {
service.getMinDate().subscribe((result : Date) => {
expect(result.getFullYear()).toBe(2015);
expect(result.getMonth()).toBe(2); // January is 0
expect(result.getDate()).toBe(5);
done();
});
const req = httpMock.expectOne("/api/v1/general_stats/min_date");
expect(req.request.method).toBe('GET');
req.flush(fakeResponse);
})
});
});
Explicitly adding @Inject(HttpClient)
resolves the test failures, though I seek alternatives to avoid using such workarounds.
Configuration Details
Karma Configuration:
const webpackConfig = require('./config/webpack/test.js');
module.exports = function(config) {
// Karma configuration setup here
};
... (remaining content omitted for brevity) ...