如何测试角度服务承诺电话?

时间:2018-12-12 22:12:31

标签: angular unit-testing karma-jasmine

我有一个服务SmsService,该服务会在组件的submit()方法内返回一个承诺。

在我的组件中,我从SmsService调用this.sms.send()方法,并附加then()catch()this.sms.send(this.messageInput).then(....).catch(....)

在调用expect(smsSpy.send).toHaveBeenCalledWith(component.messageInput)之后,this.sms.send()的断言可以正常工作,但是this.messageInput不会重置为null并且断言失败。我究竟做错了什么?我没有正确运行变更检测吗?

我正在尝试编写一些测试,以确保根据我的then间谍返回的Promise分别调用组件中的catchsend()。我该怎么办? 。

import { async, ComponentFixture, TestBed } from '@angular/core/testing';

import {MomentModule} from 'angular2-moment'
import { FormsModule } from '@angular/forms';
import { AngularFirestore } from '@angular/fire/firestore';
import { Observable, of } from "rxjs";
import { ActivatedRoute } from '@angular/router';
import {SmsService} from './sms.service'


//my component

import {
    Component,
    OnInit,
    AfterViewChecked,
    ViewChild,
    ElementRef,
    AfterViewInit
  } from "@angular/core";

  @Component({
    selector: "app-sms",
    templateUrl: "./sms.component.pug",
    styleUrls: ["./sms.component.scss"]
  })
  export class SmsComponent {
    @ViewChild("scrollMe") private myScrollContainer: ElementRef;
    public messageInput;
    public list;
    public err;
    constructor(public sms: SmsService, private route:ActivatedRoute) {

        this.list = this.sms.getItems()//this.route.data['value']['messages']
    }

    submit() {
      this.sms
        .send(this.messageInput)
        .then(res => {
          // console.log(res);
          this.messageInput = null
        })
        .catch(err => {
          this.err = `Could not send - ${err}`
        });
    }
  }


//my test
describe('SmsComponent', () => {
  let component: SmsComponent;
  let fixture: ComponentFixture<SmsComponent>;
  var afSpy = jasmine.createSpyObj('AngularFirestore', ['collection', 'valueChanges', 'snapshotChanges', 'pipe', 'add']);

  var smsSpy = jasmine.createSpyObj('SmsService', ['send', 'then','catch']);

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [ SmsComponent ],
      providers:[
        { provide: SmsService, useValue: smsSpy },
        { provide: AngularFirestore, useValue: afSpy },
        {
          provide: ActivatedRoute, useValue: {
            params: of([{ id: 'test' }])
          }
        }
      ],   
      imports:[MomentModule, FormsModule],
    })
    .compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(SmsComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('expect err', () => {
    smsSpy.send.and.returnValue(Promise.resolve('asdf')); 
    smsSpy.catch.and.returnValue('caught');

    component.messageInput = 'my new message'
    component.submit()
    fixture.detectChanges();
    expect(smsSpy.send).toHaveBeenCalledWith(component.messageInput) //<-- this passes
    expect(component.messageInput).toBe(null) //<---- this fails
  });
});

1 个答案:

答案 0 :(得分:0)

您的服务没有任何thencatch方法。它只有一个send()方法,该方法返回Promise。返回的Promise是具有then和catch方法的对象。所以这行毫无意义:

var smsSpy = jasmine.createSpyObj('SmsService', ['send', 'then','catch']);

您需要使间谍返回承诺,并且需要控制异步,例如通过使用fakeAsync()

这是一个几乎与您匹配的完整示例(我只保留了重要部分):

组件:

import { Component } from '@angular/core';
import { SmsService } from '../sms.service';

@Component({
  selector: 'app-sms',
  templateUrl: './sms.component.html',
  styleUrls: ['./sms.component.scss']
})
export class SmsComponent {

  public messageInput: string;

  constructor(private sms: SmsService) { }

  submit() {
    this.sms
      .send(this.messageInput)
      .then(res => {
        this.messageInput = null;
      });
  }

}

测试:

import { fakeAsync, TestBed, tick } from '@angular/core/testing';

import { SmsComponent } from './sms.component';
import { SmsService } from '../sms.service';

describe('SmsComponent', () => {
  let component: SmsComponent;

  beforeEach(() => {
    TestBed.configureTestingModule({
      declarations: [ SmsComponent ]
    });
  });

  beforeEach(() => {
    component = TestBed.createComponent(SmsComponent).componentInstance;
  });

  it('should sublut and clear', fakeAsync(() => {
    // obtain the service injected in the component by Angular
    const smsService: SmsService = TestBed.get(SmsService);

    // spy on its send method, and make it return a resolved promise
    spyOn(smsService, 'send').and.returnValue(Promise.resolve('hello world'));

    // set the message input in the component
    component.messageInput = 'world';

    // call submit()
    component.submit();

    // check that the service call has been made
    expect(smsService.send).toHaveBeenCalledWith('world');

    // tick in order to trigger the execution of the then callback registered on the promise
    tick();

    // check that the callback has rset the messageInput to null
    expect(component.messageInput).toBeNull();
  }));
});