В настоящее время я пытаюсь перейти с объекта поведения rxjs на сигналы.
У нас есть несколько тестов, которые проверяют обновление сигнала.
Но когда я пытаюсь перенести наши шуточные тесты на новые сигналы, у меня возникают проблемы.
пример:
У меня есть этот сервис:
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();
});
});
Как это сделать с помощью сигналов?
🤔 А знаете ли вы, что...
Angular предоставляет средства для работы с HTTP-запросами и взаимодействия с внешними API.
На самом деле toObservable
просто преобразует сигнал в наблюдаемую величину, а не в BehaviourSubject
, поэтому нет next
метода, который можно было бы использовать.
Вместо этого напрямую обращайтесь к сигналу, используя метод доступа к точке в JavaScript (можете получить доступ к частным свойствам), и обновляйте значение, используя метод set
.
Кроме того, JSON.stringify
сравнение ненадежно, поскольку порядок свойств не гарантирован, вместо этого используйте isEqual
метод lodash.
По сути, мы проверяем метод 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);
}
}
}