我目前正在尝试从 rxjs BehaviourObject 迁移到信号。
我们确实有一些测试信号更新的测试。
但是当我尝试将笑话测试迁移到新信号时,我遇到了问题。
示例:
我有这项服务:
import { Injectable, signal } from '@angular/core';
import { toObservable } from '@angular/core/rxjs-interop';
import { BehaviorSubject } from 'rxjs';
export interface SignalState {
foo: string;
bar: boolean | undefined;
}
@Injectable({
providedIn: 'root',
})
export class SignalService {
// private signalState$ = new BehaviorSubject<SignalState>({ foo: '', bar: undefined }); //signalState bevor
private signaltState = signal<SignalState>({ foo: '', bar: undefined });
private signalState$ = toObservable(this.signaltState);
public getValue = this.signaltState.asReadonly();
public getSignalState() {
return this.signalState$;
}
public updateFoo(foo: string) {
this.updateSignal({ foo });
}
private isChanged(currentState: SignalState, updatedState: SignalState) {
return JSON.stringify(currentState) !== JSON.stringify(updatedState);
}
private updateSignal(newState: Partial<SignalState>) {
const currentState = this.getValue();
const updatedState: SignalState = { ...currentState, ...newState };
if (this.isChanged(currentState, updatedState)) {
this.signaltState.set(updatedState);
}
}
}
我想测试变更检测。所以基本上如果
this.signaltState.set(updatedState);
没有被调用,那么变化检测就不会被触发。
在我进行以下测试之前
import { SpectatorService } from '@ngneat/spectator';
import { createServiceFactory } from '@ngneat/spectator/jest';
import { SignalService, SignalState } from './lead-request-state.service';
describe('LeadRequestStateService', () => {
let spectator: SpectatorService<SignalService>;
let service: SignalService;
const currentState: SignalState = {
foo: 'someString',
bar: false
};
const createService = createServiceFactory({
service: SignalService,
});
beforeEach(() => {
spectator = createService();
service = spectator.inject(SignalService);
service.getSignalState().next(currentState);
});
it('should created service', () => {
expect(service).toBeTruthy();
});
it('should not update state if value is not changed', () => {
const nextSpy = jest.spyOn(service.getSignalState(), 'next');
service.updateFoo(currentState.foo);
expect(nextSpy).not.toHaveBeenCalled();
});
});
如何使用信号来做到这一点?
实际上
toObservable
只是将信号转换为可观察值,而不是 BehaviourSubject
,因此没有 next
方法可供使用。
而是使用 JavaScript 的点访问器方法直接访问信号并更新值。
此外,
JSON.stringify
比较不可靠,因为不能保证属性的顺序,而是使用lodash的isEqual
方法。
基本上我们检查信号的
set
方法并且测试用例通过。
import { SpectatorService } from '@ngneat/spectator';
import { createServiceFactory } from '@ngneat/spectator/jest';
import { SignalService, SignalState } from './test.service';
describe('LeadRequestStateService', () => {
let spectator: SpectatorService<SignalService>;
let service: SignalService;
const currentState: SignalState = {
foo: 'someString',
bar: false,
};
const createService = createServiceFactory({
service: SignalService,
});
beforeEach(() => {
spectator = createService();
service = spectator.inject(SignalService);
service['signaltState'].set(currentState);
});
it('should created service', () => {
expect(service).toBeTruthy();
});
it('should not update state if value is not changed', () => {
const nextSpy = jest.spyOn(service['signaltState'], 'set');
service.updateFoo(currentState.foo);
expect(nextSpy).not.toHaveBeenCalled();
});
});
import { Injectable, signal } from '@angular/core';
import { toObservable } from '@angular/core/rxjs-interop';
import { BehaviorSubject } from 'rxjs';
import { isEqual } from 'lodash';
export interface SignalState {
foo: string;
bar: boolean | undefined;
}
@Injectable({
providedIn: 'root',
})
export class SignalService {
// private signalState$ = new BehaviorSubject<SignalState>({ foo: '', bar: undefined }); //signalState bevor
private signaltState = signal<SignalState>({ foo: '', bar: undefined });
private signalState$ = toObservable(this.signaltState);
public getValue = this.signaltState.asReadonly();
public getSignalState() {
return this.signalState$;
}
public updateFoo(foo: string) {
this.updateSignal({ foo });
}
private isChanged(currentState: SignalState, updatedState: SignalState) {
return !isEqual(currentState, updatedState);
}
private updateSignal(newState: Partial<SignalState>) {
const currentState = this.getValue();
const updatedState: SignalState = { ...currentState, ...newState };
if (this.isChanged(currentState, updatedState)) {
this.signaltState.set(updatedState);
}
}
}