2
respostas

Teste de promisses em aplicação AngulaJS usarndo Karma e Jasmine

Olá,

Estou com uma aplicação em AngularJS e eu quis garantir a qualidade do meu código fazendo testes unitários e estou usando Karma e Jasmine pra isso. Depois de ter tido uma certa dificuldade para configurar as injeções de dependências e etc consegui finalmente "acessar" as funções da minha controller e realizar os testes. porém estou com dificuldades de fazer os testes das promisses , não estou conseguindo encontrar como faço pra simular o retorno da chamada assincrona para poder seguir com o teste da minha função.

será que alguém saberia como me dar ajudar?

Segue exemplo do meu Service:

angular.module('projetoServices', [])
    .factory('projetoService', ['$http', function ($http) {

        return {
            consultaLink: function (entrada) {
                return $http.post('http://localhost:7001', entrada})
                    .then(tratarResposta, tratarErro);
            },
        };

        function tratarResposta(response) {
            if (response.data.data == null) {
                return response.data;
            } else {
                return response.data.data;
            }
        }

        function tratarErro(error) {
            if (error.data.data == null) {
                return error.data;
            } else {
                return error.data.data;
            }
        }

    }]);

Segue função dentro da minha controller que quero testar:

vm = this;
vm.abreLink = abreLink;

function abreLink(id) {
            projetoService.consultaLink({ "id": id }).then(function (response) {
                if (response) {
                       var html = response.url;
            $window.open(html, '_Blank',);
                }
            });
 }

Dentro da minha classe de teste estou injetando meu service através de um arquivo com modulos comuns

(function (angular) {

    angular.mock.moduleCommonsInit = function () {

        module(function ($provide) {
            $provide.factory('projetoService', function ($q) {
                return {
                        consultaLink: function () {
                        var defer = $q.defer();
                        defer.resolve({ id: 1, url: www.alura.com.br });
                        return defer.promise;
                    },
                };
            });

        });
    };
}(angular));

e esta é meu arquivo de testes:

describe('testes da projeto
Controller', function () {
    var $rootScope, $scope, $q, $httpBackend, $controller, vm;

    beforeEach(function () {
        angular.mock.moduleCommonsInit();
        angular.mock.module('projeto
Controllers');
    });

    beforeEach(inject(function (_$rootScope_, _$controller_, _$q_, _$httpBackend_, projetoService) {

        $q = _$q_;
        $rootScope = _$rootScope_;
        $scope = _$rootScope_.$new();
        $httpBackend = _$httpBackend_;
        $controller = _$controller_;

        vm = _$controller_('projetoController', {
            $scope: $scope,
            projetoService : projetoService
        });

    }));

    it('Teste AbreLink()...', function () {
        var id = "1";

        vm.abreLink(id);

    });

});
2 respostas

Opa Rafael, tudo bem? Conseguiu dar algum progresso? Complexo código pra testar, visto que tem várias funções anônimas dentro dos callbacks.

Veja que como a função abre link não retorna nada, como você acessaria o resultado da promise pra validar o teste? Não tem como concorda?

E por que injetar um objeto que tem um método consultaLink sendo que no teste você está chamando o abreLink. Não entendi a relação dessas duas coisas :(

Pode me explicar pra mim tentar te ajudar?

Pois bem... continuo na saga em busca de como realizar esses testes, já tentei algumas soluções q encontrei na internet mas ainda não consegui fazer funcionar como gostaria.

Deixe eu te contextualizar sobre o meu projeto, pra ver se fica mais clara a minha dificuldade.

Peguei um projeto legado que preciso manter e continuar as evoluções dai meio que só continuei nos moldes que já estavam implementador ( afinal de contas querer reinventar o que já funciona costuma criar mais problemas do que soluciona).

Minha aplicação funciona como uma spa onde concentro todas as regras de negócio em uma única controller e injeto diversos componentes que uso na minha aplicação. Nesse caso que trouxe, estou querendo testar as funções da minha controller.

Boa parte das minhas rotinas buscam alguma informação do meu banco de dados, que é acionado através da minha api rest, que concentro todos os meus end points no meu service, e com o retorno desta chamada (que quase sempre é um post) aplico as minhas regras de negócio.

Criei aquele módulo comum só pra separar as injeções que preciso para começar os testes da controller de onde irão ficar os testes (só pra esse js não ficar tão grande) e por isso injeto ele no meu teste.

Sobre o teste estou querendo testar abreLink pois é essa chamada que será feita na minha view, ela chama abreLink enviando os parâmetros que vou usar para fazer uma requisição ao meu BD, dentro da função abreLink faço uma chamada a projetoService.consultaLink e com o retorno dessa promise executo o $window para abrir a url de retorno em outra aba.

Meu teste do jeito que está está executando a chamada, consegue identificar projetoService.consultaLink (pois foi devidamente injetado) mas a cobertura acaba no .then e n consigo terminar se percorrer o restante da lógica.

Também precisei fazer testes na minha api que é em Java. Lá usando jUnit e Mockito consigo criar um mock para quando acionado um método dentro de outro método retornar um valor definido e a partir daí continuar minha lógica. Queria algo parecido com o angular (até li sobre os spyOn mas n consigo usar) já li muita coisa online mas continuo parado nesses testes assíncronos.

Quer mergulhar em tecnologia e aprendizagem?

Receba a newsletter que o nosso CEO escreve pessoalmente, com insights do mercado de trabalho, ciência e desenvolvimento de software