NullInjectorError: 运行 ng test 时没有 SwUpdate! 的提供程序



我用一个在devprod模式下运行良好的服务工作者做了一个Angular 8.2.14PWA。

但是当我使用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)

我认为问题出在您的测试中:

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

。 您需要将一个真实的或(最好(伪造的SwUpdate实例注入到您的 TestBed 模块中,以便至少对其进行编译。

您可以通过在单独的文件中创建类来模拟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 助手来存根它们:

spyOn(swUpdate, 'isEnabled').and.returnValue(false);

举个例子。这应该有效,但可能需要进一步调整

最新更新