Как издеваться над наблюдаемым? Я пытался издеваться над этим тремя разными способами

Я написал много модульных тестов для проверки наблюдаемых, но по какой-то причине этот тест не работает, как другие, которые я написал, но я не понимаю, в чем проблема.

Я хотел бы, чтобы макет для ChangePasswordFacade.successful$ возвращал Observable, который возвращает true. Несмотря на то, что я ранее использовал издевательскую стратегию ниже, она не работает. Я попытался внедрить ChangePasswordFacade в тест. Я попытался использовать функцию mock Success$ в useValue провайдера TestBed. И я попробовал подход ниже. Все они выдают успешный $ как ложный. Как я могу издеваться над этим по-другому, чтобы вернуть true?

import { ComponentFixture, TestBed } from '@angular/core/testing';
import { PasswordChangeModalComponent } from './password-change-modal.component';
import { ReactiveFormsModule } from '@angular/forms';
import { PasswordChangeFormComponent } from '../../..';
import { DefaultPopoverComponent } from '@bis-angular/shared-components/pattern-library';
import { Store, StoreModule } from '@ngrx/store';
import {
  ChangePasswordFacade,
  UserInformationFacade,
  changePasswordInitialState,
  CHANGEPASSWORD_FEATURE_KEY,
  changePasswordReducer
} from '@bis-angular/users';
import { configureTestSuite } from 'ng-bullet';
import { of } from 'rxjs';

describe('PasswordChangeModalComponent', () => {
  let component: PasswordChangeModalComponent;
  let fixture: ComponentFixture<PasswordChangeModalComponent>;

  const childDefaultPopoverComponent = jasmine.createSpyObj('DefaultPopoverComponent', ['hideModal', 'showModal']);
  const childPasswordChangeFormComponent = jasmine.createSpyObj('PasswordChangeFormComponent', ['setFormControlsToEmpty']);

  const changePasswordFacadeSpy = jasmine.createSpyObj('ChangePasswordFacade', ['resetState']);

  configureTestSuite(() => {
    TestBed.configureTestingModule({
      imports: [
        ReactiveFormsModule,
        StoreModule.forRoot({}),
        StoreModule.forFeature(CHANGEPASSWORD_FEATURE_KEY, changePasswordReducer, {
          initialState: changePasswordInitialState
        })
      ],
      declarations: [PasswordChangeFormComponent, DefaultPopoverComponent, PasswordChangeModalComponent],
      providers: [Store, UserInformationFacade, ChangePasswordFacade]
    });
  });

  beforeEach(() => {
    fixture = TestBed.createComponent(PasswordChangeModalComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
    component.defaultPopoverComponent = childDefaultPopoverComponent;

    component.watchSuccessful = { unsubscribe: () => {} };
    spyOn(component.watchSuccessful, 'unsubscribe');
    const service = TestBed.get(ChangePasswordFacade);
    spyOn(service, 'successful$').and.returnValue(of(true));
  });


  describe('showPasswordChangeModal function ', () => {
    it('should call showModal and then not hide if not successful  ', () => {
      spyOn(component, 'hidePasswordChangeModal');
      component.successful$.subscribe((successful: boolean) => {
        expect(component.hidePasswordChangeModal).toHaveBeenCalled();
        expect(changePasswordFacadeSpy.resetState).toHaveBeenCalled();
        expect(component.watchSuccessful.unsubscribe).toHaveBeenCalled();
      });
      component.showPasswordChangeModal();
      expect(childDefaultPopoverComponent.showModal).toHaveBeenCalled();
    });
  });


});
import { Injectable } from '@angular/core';
import { select, Store } from '@ngrx/store';
import { ChangePasswordPartialState } from './change-password.reducer';
import { changePasswordQuery } from './change-password.selectors';
import { ChangePassword, ChangePasswordResetState } from './change-password.actions';
import { NewPassword } from '@bis-angular/users';

@Injectable()
export class ChangePasswordFacade {
  successful$ = this.store.pipe(select(changePasswordQuery.getSuccessful));

  initiated$ = this.store.pipe(select(changePasswordQuery.getInitiated));

  constructor(private store: Store<ChangePasswordPartialState>) {}

  changePassword(newPassword: NewPassword, userId: string) {
    this.store.dispatch(new ChangePassword(newPassword, userId));
  }

  resetState() {
    this.store.dispatch(new ChangePasswordResetState());
  }
}

Вы случайно не объявляете ChangePasswordFacade в массиве provider декоратора @Component для определения класса PasswordChangeModalComponent? Если это так, вам нужно будет использовать overrideComponent для успешного внедрения фиктивного провайдера.

dmcgrandle 09.03.2019 06:22
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Angular и React для вашего проекта веб-разработки?
Angular и React для вашего проекта веб-разработки?
Когда дело доходит до веб-разработки, выбор правильного front-end фреймворка имеет решающее значение. Angular и React - два самых популярных...
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Мы провели Twitter Space, обсудив несколько проблем, связанных с последними дополнениями в Angular. Также прошла Angular Tiny Conf с 25 докладами.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
Мое недавнее углубление в Angular
Мое недавнее углубление в Angular
Недавно я провел некоторое время, изучая фреймворк Angular, и я хотел поделиться своим опытом со всеми вами. Как человек, который любит глубоко...
Освоение Observables и Subjects в Rxjs:
Освоение Observables и Subjects в Rxjs:
Давайте начнем с основ и постепенно перейдем к более продвинутым концепциям в RxJS в Angular
0
1
657
2

Ответы 2

Поскольку вы хотите получить доступ к successful$, который определен на уровне класса ChangePasswordFacade.

что-то типа:

export class ChangePasswordFacade{
   successful$:observable // ... something like this
}

Вы должны попробовать useValue:

 configureTestSuite(() => {
    TestBed.configureTestingModule({
      imports: [
        ReactiveFormsModule,
        StoreModule.forRoot({}),
        StoreModule.forFeature(CHANGEPASSWORD_FEATURE_KEY, changePasswordReducer, {
          initialState: changePasswordInitialState
        })
      ],
      declarations: [PasswordChangeFormComponent, DefaultPopoverComponent, PasswordChangeModalComponent],
      providers: [Store, UserInformationFacade, 
                   {provide: ChangePasswordFacade , useValue: 
                     {
                         successful$ : of(true)
                     }
                   }'
                 ]
    });
  });

Спасибо за предложение. Я попробовал именно тот подход, который вы предложили выше, как я отметил в своем первоначальном описании проблемы. Это не работает.

user372225 09.03.2019 05:23

@ user372225: какие значения вы получили от succeessful$, когда попробовали мое предложение?

Shashank Vivek 09.03.2019 06:37

привет @ShashankVivek, я получаю «ложное» значение для успешного $, используя ваше предложение.

user372225 11.03.2019 14:48

@ user372225, даже когда вы настраиваете его of(true)true? какая-то переменная, кажется, манипулирует ею тогда

Shashank Vivek 12.03.2019 05:58

вот как я это сделал: я использовал хранилище для отправки действия, чтобы изменить успешное $ на true. теперь это интеграционный тест, а не модульный тест.

import { ChangePasswordFacade, UserInformationFacade } from '@bis-angular/users';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { StoreModule, Store } from '@ngrx/store';
import { PasswordChangeModalComponent, PasswordChangeFormComponent } from '../../..';
import * as fromFeature from '@bis-angular/users';
import { ReactiveFormsModule } from '@angular/forms';
import { configureTestSuite } from 'ng-bullet';
import { DefaultPopoverComponent } from '@bis-angular/shared-components/pattern-library';

describe('PasswordChangeModalComponent', () => {
  let component: PasswordChangeModalComponent;
  let fixture: ComponentFixture<PasswordChangeModalComponent>;
  let store: Store<fromFeature.ChangePasswordState>;

  const childDefaultPopoverComponent = jasmine.createSpyObj('DefaultPopoverComponent', ['hideModal', 'showModal']);
  const childPasswordChangeFormComponent = jasmine.createSpyObj('PasswordChangeFormComponent', ['setFormControlsToEmpty']);

  configureTestSuite(() => {
    TestBed.configureTestingModule({
      imports: [
        StoreModule.forRoot({}),
        ReactiveFormsModule,
        StoreModule.forFeature(fromFeature.CHANGEPASSWORD_FEATURE_KEY, fromFeature.changePasswordReducer, {
          initialState: fromFeature.changePasswordInitialState
        })
      ],
      declarations: [PasswordChangeModalComponent, DefaultPopoverComponent, PasswordChangeFormComponent],
      providers: [ChangePasswordFacade, UserInformationFacade]
    });
  });

  beforeEach(() => {
    store = TestBed.get(Store);
    spyOn(store, 'dispatch').and.callThrough();

    fixture = TestBed.createComponent(PasswordChangeModalComponent);
    component = fixture.componentInstance;
    component.defaultPopoverComponent = childDefaultPopoverComponent;
    component.watchSuccessful = { unsubscribe: () => {} };

    spyOn(component.watchSuccessful, 'unsubscribe');
    fixture.detectChanges();
  });

  it('should be created', () => {
    expect(component).toBeTruthy();
  });


  describe('showPasswordChangeModal function ', () => {
    it('should call showModal and then hide if successful  ', () => {
      spyOn(component, 'hidePasswordChangeModal');
      spyOn(component.changePasswordService, 'resetState');
      const action = new fromFeature.ChangePasswordSuccessful({});

      store.dispatch(action);
      component.showPasswordChangeModal();

      component.successful$.subscribe((successful: boolean) => {
        expect(component.hidePasswordChangeModal).toHaveBeenCalled();
        expect(component.changePasswordService.resetState).toHaveBeenCalled();
      });
      expect(childDefaultPopoverComponent.showModal).toHaveBeenCalled();
    });
  });
});

Другие вопросы по теме