我一直试图找到一种方法来测试一个订阅,这个订阅是在一个被模仿的服务上使用Jest来测试的。但是,我找不到一种方法来模拟可观察到的isMobile属性并测试其赋值。
当我尝试spyOn,然后模拟该服务以返回一个值时,它永远不会更新。我希望能够测试来自服务的不同响应的代码。
下面的代码。
组件
import { Component, Input, OnInit } from '@angular/core';
import { BREAKPOINT, BreakpointService } from '../../services';
@Component({
selector: 'auxiliary-bar',
templateUrl: './auxiliary-bar.component.html',
styleUrls: ['./auxiliary-bar.component.scss'],
})
export class AuxiliaryBarComponent implements OnInit {
public isMobile = false;
constructor(private breakpointService: BreakpointService) {}
ngOnInit(): void {
this.breakpointService.onBreakpoint$.subscribe(
(breakpoint) => (this.isMobile = breakpoint <= BREAKPOINT.SM),
);
}
}断点服务
import { Injectable, NgZone, OnDestroy } from '@angular/core';
import { Observable, Subject } from 'rxjs';
import { distinctUntilChanged } from 'rxjs/operators';
export enum BREAKPOINT {
XS,
SM,
MD,
LG,
XL,
}
@Injectable({
providedIn: 'root',
})
export class BreakpointService implements OnDestroy {
private breakpointSubject: Subject<BREAKPOINT> = new Subject();
private observer!: ResizeObserver;
private sizes = [
{
id: BREAKPOINT.SM,
width: 0,
},
{
id: BREAKPOINT.SM,
width: 320,
},
{
id: BREAKPOINT.MD,
width: 768,
},
{
id: BREAKPOINT.LG,
width: 1024,
},
{
id: BREAKPOINT.XL,
width: 1200,
},
];
constructor(private zone: NgZone) {
this.observer = new ResizeObserver((entries) => {
this.zone.run(() => {
const matchedSize = this.sizes
.slice(1)
.reverse()
.find(
(size) => window.matchMedia(`(min-width: ${size.width}px)`).matches,
);
this.breakpointSubject.next(
matchedSize ? matchedSize.id : BREAKPOINT.XS,
);
});
});
this.observer.observe(document.body);
}
ngOnDestroy(): void {
this.observer.unobserve(document.body);
}
public get onBreakpoint$(): Observable<BREAKPOINT> {
return this.breakpointSubject.asObservable().pipe(distinctUntilChanged());
}
}试用期套房
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { MockProvider } from 'ng-mocks';
import { Observable, of } from 'rxjs';
import { BreakpointService } from '../../services';
import { AuxiliaryBarComponent } from './auxiliary-bar.component';
describe('AuxiliaryBarComponent', () => {
let component: AuxiliaryBarComponent;
let fixture: ComponentFixture<AuxiliaryBarComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [
AuxiliaryBarComponent,
],
providers: [
MockProvider(BreakpointService, {
onBreakpoint$: new Observable(),
}),
],
}).compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(AuxiliaryBarComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
it('should', () => {
const breakpointService = TestBed.inject(BreakpointService);
const spy = jest
.spyOn(breakpointService, 'onBreakpoint$', 'get')
.mockReturnValue(of(3));
fixture.detectChanges();
expect(breakpointService.onBreakpoint$.subscribe).toHaveBeenCalled();
});
)};发布于 2022-03-03 20:52:19
我很确定为时已晚,因为组件已经被实例化,因此ngInit在it启动时已经被调用了。如果我是对的,那么修复可能就像在上一个component.ngOnInit()之前插入fixture.detectChanges()来重新触发它一样容易。
另外,如果您可以帮助组件,则不应该订阅它。相反,如果它适合您的需要,那么我会将组件的ngOnInit更改为
public isMobile$: Observable<boolean>;
ngOnInit(): void {
this.isMobile$ = this.breakpointService.onBreakpoint$.pipe(
map(breakpoint => breakpoint <= BREAKPOINT.SM)
);
}然后,在模板中,无论您曾经拥有isMobile,还是使用(isMobile$ | async)。
但是,如果您必须在服务或组件中订阅(或者为了安全和良好的编程实践也可以这样做),那么您的服务应该有一个调用ngOnDestroy的this.breakpointSubject?complete();。
https://stackoverflow.com/questions/71342382
复制相似问题