javascript - 测试可观察回调以更改对象状态

标签 javascript angular typescript jasmine

我有一项服务可以执行以下操作:

  updateProperties(properties: any) {
    return this.http.put(environment.adminApiURLPrefix+'api/v1/properties', properties);
  }

在我的组件中,我有两个对象:providers 和providerProperties。 Providers 包含 API 提供者及其状态的键值对,而providerProperties 是从 API 返回的实际响应(必须存储,因为任何后续请求都需要整个对象)。

import { Component, OnInit } from '@angular/core';
import { ProviderService } from '../../services/provider.service';
import { Status } from 'src/app/models/status.enum';
import { AlertService } from 'src/app/services/alert.service';

@Component({
  selector: 'app-providers',
  templateUrl: './providers.component.html',
  styleUrls: ['./providers.component.scss']
})
export class ProvidersComponent implements OnInit {

  providers: any;
  providerProperties: any;
  status: Status;

  constructor(private providerService: ProviderService, private alertService: AlertService) {
    this.providers = {
      'API1': false,
      'API2': false,
      'API3': false
    }
    this.status = Status.Loading;
  }

  ngOnInit() {
    this.providerService.getProperties().subscribe((response: any) => {
      this.setProviderValues(response);
      this.status = Status.Ready;
    },
    error => {
      this.alertService.error('Error');
      this.status = Status.Error;
    })
  }

  setProviderValues(response: any) {
    this.providerProperties = response;
    Object.keys(this.providers).forEach(key => {
      let providerStatus: string = this.providerProperties[key.toLowerCase() + '.enabled'];
      if(providerStatus == 'true' || providerStatus == 'false') {
        this.providers[key] = providerStatus == 'true' ? true : false;
      } else {
        this.alertService.error('Error.');
        this.status = Status.Error;
        return;
      }
    });
  }

  changeProviderProperty(provider: string, isEnabled: boolean) {
    let providerKey: string = this.providerDisplayNameToPropertyKey(provider);

    let tempProviderProperties = Object.assign({}, this.providerProperties);
    tempProviderProperties[providerKey] = isEnabled ? true : false;

    this.providerService.updateProperties(tempProviderProperties).subscribe(
      response => {
        this.setProviderValues(response);
        this.alertService.success('Successfully '+ (isEnabled ? 'Enabled ' : 'Disabled ') + provider);
      },
      err => {
        if(err['status'] == 0) {
          this.alertService.error('Error');
        } else {
          let errorArray = err['error']['Errors']['Error'];
          for(let errorKey in errorArray) {
            let errorValue = errorArray[errorKey];
            this.alertService.error('Error Updating Properties: ' + errorValue['ReasonCode'] + ' ' + errorValue['Description']);
          }
        }
      }
    )
  }

  providerDisplayNameToPropertyKey(provider: string) {
    return provider.toLowerCase() + '.enabled';
  }
}

我有以下测试:

import { async, ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing';
import { HttpClientTestingModule } from '@angular/common/http/testing';

import { ProvidersComponent } from './providers.component';
import { ProviderService } from 'src/app/services/provider.service';
import { of, Observable, throwError } from 'rxjs';
import { AlertComponent } from '../shared/alert/alert.component';
import { RouterTestingModule } from '@angular/router/testing';
import { AlertService } from 'src/app/services/alert.service';
import { HttpErrorResponse } from '@angular/common/http';

describe('ProvidersComponent', () => {
  let component: ProvidersComponent;
  let providerService: ProviderService;
  let alertService: AlertService;
  let fixture: ComponentFixture<ProvidersComponent>;
  let getPropertiesSpy: jasmine.Spy<() => Observable<String>>;
  let changeProviderPropertySpy: jasmine.Spy<(provider: string, isEnabled: boolean) => Promise<void>>;

  let providerProperties:any;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [ 
        ProvidersComponent,
        AlertComponent
      ],
      imports: [
        HttpClientTestingModule,
        RouterTestingModule
      ],
      providers: [
        ProviderService,
        AlertService
      ]
    })
    .compileComponents();
  }));

  beforeEach(() => {
    providerService = TestBed.get(ProviderService);
    alertService = TestBed.get(AlertService);
    fixture = TestBed.createComponent(ProvidersComponent);

    providerProperties = {
      'api1.enabled': 'true',
      'api2.enabled': 'true',
      'api3.enabled': 'false',
    };

    component = fixture.componentInstance;

    component.providers = {
      'API1': false,
      'API2': false,
      'API3': false
    };

    getPropertiesSpy = spyOn(providerService, 'getProperties').and.callFake(() => {
      return of(providerProperties);
    });

    changeProviderPropertySpy = spyOn(component, 'changeProviderProperty');

    fixture.detectChanges();
  });

  it('should enable provider', fakeAsync(() => {
    spyOn(providerService, 'updateProperties').and.returnValue(of({
      'api1.enabled': 'true',
      'api2.enabled': 'false',
      'api3.enabled': 'false'
    }));

    component.changeProviderProperty('API1', true);

    fixture.detectChanges();

    expect(component.providers['API1']).toEqual(true);
  }));
});

由于某种原因,对象的状态不会改变。我相当确定可观察的内容没有被订阅,或者我没有等待响应。

更新 在我调用changeProviderProperties之后监视提供者服务并检查它是否被调用后,结果发现它从未被调用过。

更新2 监视了providerDisplayNameToPropertyKey方法,发现无论出于什么原因它都没有被调用。

最佳答案

方法component.changeProviderProperty包含异步代码。因为您知道这一点,所以您正在 fakeAsync 区域中运行测试。您缺少的是对 tick 的调用,它模拟 fakeAsync 区域中计时器的异步时间流逝。

it('should enable provider', fakeAsync(() => {
    ...    
    component.changeProviderProperty('API1', true);
    tick();
    ...
}));

关于javascript - 测试可观察回调以更改对象状态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59397755/

相关文章:

javascript - Google map API v3 每个域的配额限制?

javascript - Phoenix - 使用数据表的站点范围搜索功能

angular - ng build 时从 nginx 获取 404 Not Found

typescript - 如何使用空格安全地访问对象属性(JSONP 属性如 "First Name": "...")

c# - 从 C# 类名列表中渲染打字机

javascript - React 路由器 - setState(...) : Can only update a mounted or mounting component

javascript - 获取用户位置的免费 JavaScript 插件

angular - 如何将 NativeScript 集成到@nrwl/nx

angular - Ionic、Angular - ChangeDetectorRef 未定义

javascript - 使用Angular 2调用基于jQuery的Javascript ajax库