我和一个服务工作者做了一个Angular 8.2.14 PWA,它在dev和prod模式下运行得很好。
但是,当我使用ng test命令运行测试时,我得到以下错误:
NullInjectorError: No provider for SwUpdate!服务工作者被导入为:
imports: [
ServiceWorkerModule.register('ngsw-worker.js', { enabled: environment.production }),
],并用作:
export class AppComponent implements OnInit {
constructor(
private swUpdate: SwUpdate,
) {
}
ngOnInit() {
if (this.swUpdate.isEnabled) {
this.swUpdate.available.subscribe(() => {
const appNewVersion = this.translateService.instant('app.new_version_available');
if (confirm(appNewVersion)) {
window.location.reload();
}
});
}
}我的测试是:
describe('AppComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [
AppComponent
],
imports: [
RouterTestingModule,
MatGridListModule
],
}).compileComponents();
}));
it('should create the app', () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.debugElement.componentInstance;
expect(app).toBeTruthy();
});
});控制台日志输出:
Chromium 80.0.3987 (Linux 0.0.0) AppComponent should render title FAILED
NullInjectorError: StaticInjectorError(DynamicTestModule)[AppComponent -> SwUpdate]:
StaticInjectorError(Platform: core)[AppComponent -> SwUpdate]:
NullInjectorError: No provider for SwUpdate!
error properties: Object({ ngTempTokenPath: null, ngTokenPath: [ 'AppComponent', Function ], ngDebugContext: DebugContext_({ view: Object({ def: Object({ factory: Function, nodeFlags: 33669121, rootNodeFlags: 33554433, nodeMatchedQueries: 0, flags: 0, nodes: [ Object({ nodeIndex: 0, parent: null, renderParent: null, bindingIndex: 0, outputIndex: 0, checkIndex: 0, flags: 33554433, childFlags: 114688, directChildFlags: 114688, childMatchedQueries: 0, matchedQueries: Object({ }), matchedQueryIds: 0, references: Object({ }), ngContentIndex: null, childCount: 1, bindings: [ ], bindingFlags: 0, outputs: [ ], element: Object({ ns: '', name: 'app-root', attrs: [ ], template: null, componentProvider: Object({ nodeIndex: 1, parent: <circular reference: Object>, renderParent: <circular reference: Object>, bindingIndex: 0, outputIndex: 0, checkIndex: 1, flags: 114688, childFlags: 0, directChildFlags: 0, childMatchedQueries: 0, matchedQueries: Object, matchedQueryIds: 0, references: Object, ngContentIndex: -1, ...
at <Jasmine>
at NullInjector.get (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/fesm2015/core.js:855:1)
at resolveToken (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/fesm2015/core.js:17514:1)
at tryResolveToken (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/fesm2015/core.js:17440:1)
at StaticInjector.get (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/fesm2015/core.js:17266:1)
at resolveToken (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/fesm2015/core.js:17514:1)
at tryResolveToken (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/fesm2015/core.js:17440:1)
at StaticInjector.get (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/fesm2015/core.js:17266:1)
at resolveNgModuleDep (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/fesm2015/core.js:30393:1)
at NgModuleRef_.get (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/fesm2015/core.js:31578:1)发布于 2020-02-11 17:08:45
我认为问题出在你的测试中:
describe('AppComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [
AppComponent
],
imports: [
RouterTestingModule,
MatGridListModule
],
}).compileComponents();
}));
it('should create the app', () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.debugElement.componentInstance;
expect(app).toBeTruthy();
});
});在测试中,您正在构建一个具有组件所需的所有依赖项的模块。
您的组件依赖于SwUpdate,您的测试模块在imports和providers中都没有它。
您需要向您的TestBed模块注入一个真实的或(最好是)一个假的SwUpdate实例,以便至少对其进行编译。
您可以通过在单独的文件中创建SwUpdate类来模拟它,我从https://github.com/maciejtreder/ng-toolkit/blob/master/application/src/app/services/swUpdate-server.mock.service.ts中摘取了以下代码
import { Observable, Subject } from 'rxjs';
import { UpdateActivatedEvent, UpdateAvailableEvent } from '@angular/service-worker/src/low_level';
export class SwUpdateServerMock {
public available: Observable<UpdateAvailableEvent> = new Subject();
public activated: Observable<UpdateActivatedEvent> = new Subject();
public isEnabled: boolean = false;
public checkForUpdate(): Promise<void> {
return new Promise((resolve) => resolve());
}
public activateUpdate(): Promise<void> {
return new Promise((resolve) => resolve());
}
}然后在测试模块中,告诉TestBed模块使用SwUpdateServerMock而不是SwUpdate。
describe('AppComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [
AppComponent
],
imports: [
RouterTestingModule,
MatGridListModule
],
providers: [
{ provide: SwUpdate, useClass: SwUpdateServerMock }
]
}).compileComponents();
}));
it('should create the app', () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.debugElement.componentInstance;
expect(app).toBeTruthy();
});
});所以基本上这将注入一个假的服务。
您可以尝试注入真正的SwUpdate类,然后使用Jasmine helpers来将其存根:
spyOn(swUpdate, 'isEnabled').and.returnValue(false);作为一个例子。这应该是可行的,但可能需要进一步的调整
https://stackoverflow.com/questions/60165084
复制相似问题