spyOn 在 Angular 中无法使用异步管道
spyOn not working with async pipe in Angular
我有一个运行良好的简单组件,看起来像这样:
@Component({
selector: 'component',
template: `
{{userWithAsyncPipe | async | json}} <!-- = null in test -->
{{userFromOnInit | json}} <!-- working test -->
`,
})
export class Component implements OnInit {
constructor(private service: MyService) {
}
userWithAsyncPipe = this.service.getUser();
userFromOnInit;
ngOnInit() {
this.service.getUser().subscribe(user => this.userFromOnInit = user);
}
}
我正在尝试通过模拟 service.getUser()
方法来测试它。所以我写了一个大致如下所示的测试组件:
describe('', () => {
...
let myService;
beforeEach(() => {
myService = TestBed.inject(MyService);
});
it('', () => {
spyOn(myService, 'getUser').and.returnValue(of({name: 'Jacob'}));
});
});
但是我看karma浏览器,只有变量userFromOnInit
被解析了。 userWithAsyncPipe
等于 null
.
那是什么鬼?
这里有一个例子 ng-mocks
https://codesandbox.io/s/gallant-bas-is5zy?file=/src/test.spec.ts
import { CommonModule } from "@angular/common";
import {
Component,
EventEmitter,
Input,
NgModule,
Injectable,
Output
} from "@angular/core";
import { MockBuilder, MockInstance, MockRender, ngMocks } from "ng-mocks";
import { EMPTY, Observable, of } from "rxjs";
@Injectable()
class MyService {
getUser(): Observable<any> {
return EMPTY;
}
}
@Component({
selector: "app-target",
template: `
{{ userWithAsyncPipeFn() | async | json }}
{{ userWithAsyncPipe | async | json }}
{{ userFromOnInit | json }}
`
})
class TargetComponent {
userWithAsyncPipeFn = () => this.service.getUser();
userWithAsyncPipe = this.service.getUser();
userFromOnInit: any;
constructor(private service: MyService) {}
ngOnInit() {
this.service.getUser().subscribe((user) => (this.userFromOnInit = user));
}
}
@NgModule({
imports: [CommonModule],
declarations: [TargetComponent],
providers: [MyService]
})
class TargetModule {}
describe("my sandbox", () => {
beforeEach(() => MockBuilder(TargetComponent, TargetModule));
it("should do something", () => {
MockInstance(MyService, "getUser", () => of({ name: "Jacob" }));
const fixture = MockRender(TargetComponent);
expect(fixture.nativeElement.innerHTML.match(
/\{\s*"name":\s*"Jacob"\s*\}/g
).length).toEqual(3);
});
});
我有一个运行良好的简单组件,看起来像这样:
@Component({
selector: 'component',
template: `
{{userWithAsyncPipe | async | json}} <!-- = null in test -->
{{userFromOnInit | json}} <!-- working test -->
`,
})
export class Component implements OnInit {
constructor(private service: MyService) {
}
userWithAsyncPipe = this.service.getUser();
userFromOnInit;
ngOnInit() {
this.service.getUser().subscribe(user => this.userFromOnInit = user);
}
}
我正在尝试通过模拟 service.getUser()
方法来测试它。所以我写了一个大致如下所示的测试组件:
describe('', () => {
...
let myService;
beforeEach(() => {
myService = TestBed.inject(MyService);
});
it('', () => {
spyOn(myService, 'getUser').and.returnValue(of({name: 'Jacob'}));
});
});
但是我看karma浏览器,只有变量userFromOnInit
被解析了。 userWithAsyncPipe
等于 null
.
那是什么鬼?
这里有一个例子 ng-mocks
https://codesandbox.io/s/gallant-bas-is5zy?file=/src/test.spec.ts
import { CommonModule } from "@angular/common";
import {
Component,
EventEmitter,
Input,
NgModule,
Injectable,
Output
} from "@angular/core";
import { MockBuilder, MockInstance, MockRender, ngMocks } from "ng-mocks";
import { EMPTY, Observable, of } from "rxjs";
@Injectable()
class MyService {
getUser(): Observable<any> {
return EMPTY;
}
}
@Component({
selector: "app-target",
template: `
{{ userWithAsyncPipeFn() | async | json }}
{{ userWithAsyncPipe | async | json }}
{{ userFromOnInit | json }}
`
})
class TargetComponent {
userWithAsyncPipeFn = () => this.service.getUser();
userWithAsyncPipe = this.service.getUser();
userFromOnInit: any;
constructor(private service: MyService) {}
ngOnInit() {
this.service.getUser().subscribe((user) => (this.userFromOnInit = user));
}
}
@NgModule({
imports: [CommonModule],
declarations: [TargetComponent],
providers: [MyService]
})
class TargetModule {}
describe("my sandbox", () => {
beforeEach(() => MockBuilder(TargetComponent, TargetModule));
it("should do something", () => {
MockInstance(MyService, "getUser", () => of({ name: "Jacob" }));
const fixture = MockRender(TargetComponent);
expect(fixture.nativeElement.innerHTML.match(
/\{\s*"name":\s*"Jacob"\s*\}/g
).length).toEqual(3);
});
});