2016-11-08 2 views
1

У меня есть метод в службе Angular 2, который получает всю информацию о конкретной учетной записи пользователя - той, которая вошла в систему, и возвращает Observable.Угловое тестирование модуляции обратного вызова с проверкой и обещанием

(я использую AngularFire2 для проверки подлинности, для чего это стоит)

Как вы можете видеть, метод getData использует getAuth метод, который возвращает состояние аутентификации (как наблюдаемые), который, в свою очередь, используется методом getToken (который возвращает Promise), чтобы получить токен, который используется для заполнения заголовков Authorization и выполняет HTTP-запрос. (я понимаю, что мой код может потребоваться рефакторинг, и я был бы признателен за любую обратную связь о том, что)

getData(): Observable<IData> { 
    let authHeaders = new Headers(); 

    return Observable.create((o: Observer<IData>) => { 
     this.getAuth().subscribe((authState: IState) => { 
      this.getToken(authState).then(token => { 
       /* ... 
       * Do things with that token, call an http service etc. 
       */ ... 
       authHeaders.set('Authorization', token); 

       this.http.get('myendpoint/', { 
        headers: this.authHeaders 
       }) 
       .map((response: Response) => response.json()) 
       .map((data: IData) => { 
        o.next(data); 
       }); 
      }) 
      .catch((error: Error) => { 
       Observable.throw(new Error(`Error: ${error}`)); 
      }); 
     }); 
    }); 
} 

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

Вот что мой блок тест выглядит следующим образом:

describe('Service: UserDataService',() => { 
    let mockHttp: Http; 
    let service: UserDataService; 
    let getAuthSpy: jasmine.Spy; 
    let getTokenSpy: jasmine.Spy; 

    beforeEach(() => { 
     mockHttp = { get: null } as Http; 

     TestBed.configureTestingModule({ 
      providers: [ 
       { provide: Http, useValue: mockHttp }, 
       AngularFire, 
       UserDataService, 
      ] 
     }); 

     service = new UserDataService(AngularFire, mockHttp); 

     spyOn(mockHttp, 'get').and.returnValue(Observable.of({ 
      json:() => { 
       "nickname": "MockNickname" 
      } 
     })); 

     getAuthSpy = spyOn(service, 'getAuth').and.returnValue(Observable.of({ 
      "auth": { 
      "uid": "12345" 
     })); 

     getTokenSpy = spyOn(service, 'getToken').and.returnValue(new Promise((resolve, reject) => { 
      resolve('test promise response'); 
     })); 
    }); 

    describe('getLead',() => { 
     beforeEach(() => { 
      spyOn(service, 'getLead').and.callThrough(); 
     }); 

     it('should return an object of user data and set the dataStore.userEmail if state exists',() => { 
      service.getLead().subscribe(res => { 
       expect(res).toEqual(jasmine.objectContaining({ 
        nickname: 'MockNickname' 
       })); 
      }); 

      expect(service.getLead).toHaveBeenCalled(); 
     }); 

     it('should throw, if no authState is provided',() => { 
      getAuthSpy.and.returnValue(Observable.of(false)); 

      service.getLead(); 

      expect(service.getLead).toThrow(); 
     }); 

     it('should throw, if getToken() fails to return a token',() => { 
      getTokenSpy.and.returnValue(new Promise((resolve, reject) => { 
       reject('test error response'); 
      })); 

      /* 
      * This is where I am getting lost 
      */ 

      service.getLead(); 

      expect(service.getLead).toThrow(); 
     }); 
    }); 
}); 

Из того, что я понимаю, что я должен каким-то образом сделать это обещание от getToken отказаться, и тест, чтобы увидеть, если мой наблюдаемым выбросит.

Любая помощь или отзывы с большой благодарностью.

+0

'spyOn (...). and.returnValue (Observable.throw (...). toPromise())'? Вы можете сделать это немного более линейным с 'Observable.map', шаг за шагом, а не увеличивая вложенность, конвертируя' fromPromise' и 'toPromise' по мере необходимости. – jonrsharpe

ответ

1

Я не использую ни jasmine, ни AngularFire2, так что я не могу сказать, что именно вы должны сделать, но от вас код, очевидно, что this.getToken(authState) возвращает Promise.

Вопрос: из какой библиотеки этот класс Promise происходит из (как то, что вы используете полипол).

Насколько я знаю, реализации Promises/A должны обернуть обратные вызовы с попыткой - поймать, так что если ваш обратный вызов в then(...) бросает исключение, что обещание будет распространяться на catch(). Таким образом, я думаю, вы можете подделать ответ от this.http.get('myendpoint/') с некорректным JSON, который приведет к ошибке на response.json().

Вторая вещь внутренний обратный вызов для catch():

.catch((error: Error) => { 
    Observable.throw(new Error(`Error: ${error}`)); 
}); 

Это делает буквально ничего. Нет возврата, и Observable.throw() должно появиться внутри цепи Observable, чтобы что-то сделать. Обратите внимание, что этот метод .catch() происходит от вашего класса Promise, а не от Observable.

Если вы хотите, чтобы он на самом деле распространять ошибки для наблюдателей, то вы должны явно вызвать:

.catch((error: Error) => { 
    o.error(error); 
}); 

Может быть, если ошибка ым до Observable.create() он будет передан в наблюдатель, а также, я Я не уверен в этом.

0

я имел, я подобный вопрос, то я использовал Observable.from:

spyOn(service, 'function').and.returnValue(Observable.fromPromise(Promise.reject({}))); 

Вы возвратите ошибку в Promise.reject