AngularJS/Karma/Jasmine - Сервисный звонок не возвращает значение
Я пытаюсь вызвать API-интерфейс Github, используя сервис, внедренный в компонент - и да, я использую AngularJS 1.5.3.
В модульном тесте я не получаю обратно значение (функция работает, когда я запускаю ее в браузере). Я не уверен, что я делаю неправильно, и надеюсь, что кто-то может указать мне правильное направление.
main.component.js
(function(){
angular.module("app").component("mainComponent", {
templateUrl: "/templates/main.component.html",
controllerAs: "vm",
controller: function(APIFactory, UserFactory, $state){
const vm = this;
vm.searchGithub = function(){
APIFactory.getAPI(vm.searchText).then(function(res){
res.status !== 200 ? $state.go("404", {errorData: res.data }) : (
vm.User = new UserFactory.User(res.data),
$state.go("profile", {userData: vm.User})
);
})
.catch(function(err){
$state.go("fourOFour");
});
};
}
});
})();
main.component.spec.js
describe("Main Component", function(){
var mainComponent, APIFactory, UserFactory, $httpBackend, $q, $state, $rootScope;
const addy = "https://api.github.com/users/";
beforeEach(angular.mock.module("app"));
beforeEach(inject(function(_APIFactory_, _UserFactory_, _$httpBackend_, _$state_, _$q_, _$rootScope_, _$componentController_){
APIFactory = _APIFactory_;
UserFactory = _UserFactory_;
$httpBackend = _$httpBackend_;
$state = _$state_;
$q = _$q_;
$rootScope = _$rootScope_;
$rootScope.$new();
mainComponent = _$componentController_("mainComponent", { $scope : {} });
}));
describe("Checking if the searchGithub() worked correctly", function(){
var result;
beforeEach(function(){
spyOn(mainComponent, "searchGithub").and.callThrough();
spyOn(APIFactory, "getAPI").and.callThrough();
result = {};
});
it("should make a call to UserFactory", function(){
mainComponent.searchText = "someName";
expect(mainComponent.searchText).toBeDefined();
// RESPONSE_SUCCESS does exist, I've omitted it.
$httpBackend.whenGET(addy + mainComponent.searchText).respond(200, $q.when(RESPONSE_SUCCESS));
// This is where I expect something to work
APIFactory.getAPI(mainComponent.searchText).then(function(res){
result = res;
});
$httpBackend.flush();
expect(APIFactory.getAPI).toHaveBeenCalledWith(mainComponent.searchText);
expect(mainComponent.User).toBeDefined();
});
});
});
2 ответа
В ответе выше вы вручную звоните UserFactoryMock.User
в тестовом примере, который создаст объект пользователя.
Но чтобы правильно проверить функционал, нужно проверять UserFactory.User
быть вызванным при вызове APIFactory.getAPI
это успех (без звонка UserFactory.User
вручную в тесте.
Я бы предложил изменить ваш тестовый пример на что-то вроде ниже:
describe("Main Component", function(){
var mainComponent, APIFactory, UserFactory, $httpBackend, $q, $state, $rootScope;
const addy = "https://api.github.com/users/";
beforeEach(angular.mock.module("app"));
beforeEach(inject(function(_APIFactory_, _UserFactory_, _$httpBackend_, _$state_, _$q_, _$rootScope_, _$componentController_){
APIFactory = _APIFactory_;
UserFactory = _UserFactory_;
$httpBackend = _$httpBackend_;
$state = _$state_;
$q = _$q_;
$rootScope = _$rootScope_;
var scope = $rootScope.$new();
var bindings = { APIFactory: APIFactory, UserFactory: UserFactory, $state: $state };
mainComponent = _$componentController_("mainComponent", { $scope : scope }, bindings);
}));
describe("Checking if the searchGithub() worked correctly", function(){
var result;
beforeEach(function(){
spyOn(mainComponent, "searchGithub").and.callThrough();
spyOn(APIFactory, "getAPI").and.callFake(function() {
var def = $q.defer();
def.resolve(RESPONSE_SUCCESS);
return def.promise;
});
spyOn(UserFactory, "User").and.callFake(function() {
var user = { id: 666, .... };
return user;
});
});
it("should make a call to UserFactory", function(){
mainComponent.searchText = "someName";
$rootScope.$apply();
expect(mainComponent.searchText).toBeDefined();
mainComponent.searchGithub(); // Call the same way as it works in the code actually.
$rootScope.$apply();
//No manual call to 'UserFactory.User' or 'APIFactory.getAPI'. The call to 'APIFactory.getAPI' is resolved/succeeds, hence a call to 'UserFactory.User' is made and the same is tested
expect(APIFactory.getAPI).toHaveBeenCalledWith(mainComponent.searchText);
expect(UserFactory.User).toHaveBeenCalledWith(RESPONSE_SUCCESS.data);
expect(mainComponent.User).toBeDefined();
expect(mainComponent.User.id).toEqual(666);
});
});
});
Так что это то, что я придумал для решения. Если кто-то хочет дать мне лучшее решение, я готов к идеям.
Сначала я сделал две насмешки, а затем ввел их в mainComponent
Шпион за моим издевательством APIFactoryMock.getAPI
функция:
const APIFactoryMock = {
getAPI: function(){}
};
const UserFactoryMock = {
User: function(data){
return {
login: data.login,
id: data.id,
avatar_url: data.avatar_url,
html_url: data.html_url,
followers: data.followers,
following: data.following,
public_repos: data.public_repos,
public_gists: data.public_gists,
created_at: data.created_at,
updated_at: data.updated_at,
name: data.name,
company: data.company,
blog: data.blog,
location: data.location,
bio: data.bio,
hireable: data.hireable,
email: data.email,
links: {
followers_url: data.followers_url,
following_url: data.following_url,
subscriptions_url: data.subscriptions_url,
repos_url: data.repos_url,
organizations_url: data.organizations_url
}
}
}
};
beforeEach(inject(function(_APIFactory_, _UserFactory_, _$httpBackend_, _$state_, _$q_, _$rootScope_, _$componentController_){
APIFactory = _APIFactory_;
UserFactory = _UserFactory_;
$httpBackend = _$httpBackend_;
$state = _$state_;
$q = _$q_;
$rootScope = _$rootScope_;
$rootScope.$new();
spyOn(APIFactoryMock, "getAPI").and.returnValue(RESPONSE_SUCCESS);
bindings = { APIFactory: APIFactoryMock, UserFactory: UserFactoryMock, $state: $state };
mainComponent = _$componentController_("mainComponent", { $scope : {} }, bindings);
}));
А потом я написал тесты на макеты:
it("should make a call to UserFactory", function(){
mainComponent.searchText = "someName";
expect(mainComponent.searchText).toBeDefined();
mainComponent.searchGithub(mainComponent.searchText);
$httpBackend.whenGET(addy + mainComponent.searchText).respond(200, $q.when(RESPONSE_SUCCESS));
$httpBackend.flush();
mainComponent.User = UserFactoryMock.User(RESPONSE_SUCCESS.data);
expect(mainComponent.searchGithub).toHaveBeenCalledWith(mainComponent.searchText);
expect(mainComponent.User).toBeDefined();
expect(mainComponent.User.id).toEqual(666);
});