如何使用 jest 和 Angular 18 测试信号?

问题描述 投票:0回答:1

我目前正在尝试从 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();
  });
});

如何使用信号来做到这一点?

angular jestjs angular-signals
1个回答
0
投票

实际上

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();
  });
});

服务.ts

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);
    }
  }
}

Stackblitz 演示

© www.soinside.com 2019 - 2024. All rights reserved.