Ошибка при попытке модульного тестирования базовой службы на AngularJS

0

Я новичок в модульном тестировании AngularJS с жасмином. Я пытаюсь создать очень простую среду.

Это мой файл karma.conf.js:

module.exports = function(config) {
  config.set({

    basePath: '',
    frameworks: ['jasmine'],
    files: [
        'angular/angular.min.js',
        '../node_modules/angular-mocks/angular-mocks.js',
        'app.js',
        'app-services/*.js',
        'app-services-tests/*.js'
    ],
    exclude: [
    ],
    preprocessors: {
    },
    reporters: ['progress'],
    port: 9876,
    colors: true,
    logLevel: config.LOG_INFO,
    autoWatch: true,
    browsers: ['PhantomJS'],
    singleRun: false,
    concurrency: Infinity
  })
}

В одной из функций я делаю вызов ajax, насколько я понимаю, я могу сделать что-то вроде этого (это мой тестовый файл):

describe('factory: ProductService',function(){
    var ProductService;
    beforeEach(inject(function(_ProductService_){
        ProductService = _ProductService_;
    }));
    describe('factory: ProductService',function(){
        var ProductService;
        beforeEach(inject(function(_ProductService_){
            ProductService = _ProductService_;
        }));

        var categorizedProducts = angular.fromJson('{ "ErrorMessage": null, "Result": { "0": { "CliClientId": "016VK9B90U", "InvProductCategoryId": "0LQIHDH2EM", "CategoryName": "LACA", "InvProductCategoryParentId": null, "ModifiedDate": "2016-01-28 16:36:37", "products": { "0": { "CliClientId": "016VK9B90U", "InvProductId": "030LFCE9KV", "InvProductCategoryId": "0LQIHDH2EM", "Name": "1055-B020 LACA NITRO MATE 4 LTS", "Description": "1055-B020 LACA NITRO MATE 4 LTS-VALRESA", "Barcode": null, "InternalCode": "L105525", "SaleUnitType": "Piece", "ApplicableTaxKeys": null, "Status": "Active", "CreatedDate": "2016-01-28 16:36:39", "CreatedBy": "0000000000", "ModifiedDate": "2016-01-28 16:36:39", "ModifiedBy": "0000000000", "CliLocationId": "2I1G4IHPOB", "prices": null } } }, "1": { "CliClientId": "016VK9B90U", "InvProductCategoryId": "W27Q71D4XJ", "CategoryName": "BROCHAS", "InvProductCategoryParentId": null, "ModifiedDate": "2016-01-28 16:36:38", "products": { "0": { "CliClientId": "016VK9B90U", "InvProductId": "0B23HD5PGL", "InvProductCategoryId": "W27Q71D4XJ", "Name": "BROCHA FAJA ROJA 2 1\/2", "Description": "BROCHA FAJA ROJA 2 1\/2", "Barcode": null, "InternalCode": "BFR2.5", "SaleUnitType": "Piece", "ApplicableTaxKeys": null, "Status": "Active", "CreatedDate": "2016-01-28 16:36:38", "CreatedBy": "0000000000", "ModifiedDate": "2016-01-28 16:36:38", "ModifiedBy": "0000000000", "CliLocationId": "2I1G4IHPOB", "prices": null }, "1": { "CliClientId": "016VK9B90U", "InvProductId": "0FQO5KJMX7", "InvProductCategoryId": "W27Q71D4XJ", "Name": "BROCHA LA BUENA 2\"", "Description": "BROCHA LA BUENA 2\"-BYP", "Barcode": null, "InternalCode": "BBU2", "SaleUnitType": "Piece", "ApplicableTaxKeys": null, "Status": "Active", "CreatedDate": "2016-01-28 16:36:38", "CreatedBy": "0000000000", "ModifiedDate": "2016-01-28 16:36:38", "ModifiedBy": "0000000000", "CliLocationId": "2I1G4IHPOB", "prices": null } } } } }');
        it("should return json with categorized products", function () {
            httpBackend.whenGET("http://test.dev/v1/getPOSProducts/E59576F6-E25A-4261-B1CA-66A7049C11DD").respond(categorizedProducts);
        });
    });
});

Наконец, это мое обслуживание продукта:

/**
 * Product service.
 *
 * Service that manages products. Including offline mode and sync tasks.
 *
 * @param {!angular.Http} $http
 * @param {!angular.RootScope} $rootScope
 * @ngInject
 * @export
 */
(function () {
    'use strict';
    angular
        .module('inspinia')
        .factory('ProductService', ProductService);
    /**
     * clientUpdatesQueue
     *
     * Will hold all the offline operations on the following format:
     * {'Section':SectionEnum.SECTION, 'Operation':OperationEnum.OPERATION, 'Record':record, 'Timestamp':currentTimeStamp}
     */
    var clientUpdatesQueue = [];
    var products = [];
    /**
     * Enum for sections used by the clientUpdatesQueue array.
     */
    var SectionEnum = {
        PRODUCTS : 0
    };
    /**
     * Enum for operations used by the clientUpdatesQueue array.
     */
    var OperationEnum = {
        CREATE : 0,
        UPDATE : 1,
        DELETE : 2
    };
    /**
     * Initializes the client updates queue
     */
    (function initClientUpdatesQueue(){
        clientUpdatesQueue = angular.fromJson(localStorage.clientUpdatesQueue || "[]");
        if(localStorage.products === undefined){
            //GetAllFromServer();
        }
        clientUpdatesQueue = angular.fromJson(localStorage.clientUpdatesQueue || "[]");
    })();
    ProductService.$inject = ['$http', '$rootScope'];
    function ProductService($http, $rootScope) {
        /**
         * TODO
         * Will write a function that sends the offline operations updates to the server
         *
         * service.SendUpdates = SendUpdates;
        */
        var service = {};
        service.GetAllFromServer = GetAllFromServer;
        service.GetAll = GetAll;
        service.Get = Get;
        service.Create = Create;
        service.Update = Update;
        service.Delete = Delete;
        service.Synchronize = Synchronize;
        return service;

        /***************SYNCHRONIZATION TASKS***************
         ***************************************************/
        /**
         * Synchronize
         * Iterates through the pending updates queue and performs the corresponding call to the server
         */
        function Synchronize(){
            for (var key in clientUpdatesQueue) {
                switch(clientUpdatesQueue[key].Operation){
                    case 0:
                        CreateOnServer(clientUpdatesQueue[key].Record);
                        break;
                    case 1:
                        UpdateOnServer(clientUpdatesQueue[key].Record);
                        break;
                    case 2:
                        DeleteOnServer(clientUpdatesQueue[key].Record);
                        break;
                }
                clientUpdatesQueue.splice(key, 1);
            }
            updateLocalStorage();
        }
        /**
         * updateLocalStorage
         * Updates local storage with the lastest operations.
         */
        function updateLocalStorage(){
            localStorage.products = angular.toJson(products || "[]");
            localStorage.clientUpdatesQueue = angular.toJson(clientUpdatesQueue || "[]");
        }
        /**
         * GetAllFromServer
         * Gets all products matching the current session from the server and store them on the local storage.
         */
        function GetAllFromServer(){
            var session = angular.fromJson(localStorage.session);
            $http({
                method: 'GET',
                url: $rootScope.apiURL+'getAllClientProducts/'+session,
                headers: {'Content-Type': 'application/x-www-form-urlencoded'}
            }).success(function(response){
                if(response.ErrorMessage === null && response.Result !== null){
                    localStorage.products = angular.toJson(Object.keys(response.Result).map(function (key) {return response.Result[key]}));
                }else if(response.ErrorMessage !==null){
                    alert(response.ErrorMesage);
                }
            })
            .error(function(response){
                alert('Something went wrong. Please try again: '+response);
            });
        }
        /***************LOCAL TASKS*************************
         ***************************************************/
        /**
         * GetAll
         * Gets all the products from the local storage
         *
         * @return {Array} products
         */
        function GetAll(){
            if(localStorage.products !== undefined) {
                return angular.fromJson(localStorage.products);
            }else{
                GetAllFromServer();
            }
        }
        /**
         * Gets the specified product by its primary key
         *
         * @param {String} InvProductId
         * @return {Object} product
         */
        function Get(id){
            products = GetAll();
            var thisProduct = products.filter(function(p){
                return p.InvProductId === id;
            });
            updateLocalStorage();
            return thisProduct[0];
        }
        /**
         * Creates a product
         *
         * @param {Object} product
         */
        function Create(product){
            var result = true;
            if(!ValidateSnapshot(product)){
                return false;
            }
            products = GetAll();
            products.push(product);
            clientUpdatesQueue.push({'Section':SectionEnum.PRODUCTS, 'Operation':OperationEnum.CREATE, 'Record':product, 'Timestamp':Date.now()});
            updateLocalStorage();
            return result;
        }
        /**
         * Updates a product
         *
         * @param {Object} product
         */
        function Update(product){
            var result = true;
            if(!ValidateSnapshot(product)){
                return false;
            }
            products = GetAll();
            for (var key in products) {
                if(products[key].InvProductId === product.InvProductId){
                    products[key] = product;
                }
            }
            clientUpdatesQueue.push({'Section':SectionEnum.PRODUCTS, 'Operation':OperationEnum.UPDATE, 'Record':product, 'Timestamp':Date.now()});
            updateLocalStorage();
            return result;
        }
        /**
         * Deletes a product
         *
         * @param {Object} product
         */
        function Delete(product){
            var result = true;
            products = GetAll();
            for (var key in products) {
                if(products[key].InvProductId === product.InvProductId){
                    products.splice(key, 1);
                }
            }
            clientUpdatesQueue.push({'Section':SectionEnum.PRODUCTS, 'Operation':OperationEnum.DELETE, 'Record':product, 'Timestamp':Date.now()});
            updateLocalStorage();
            return result;
        }
        /***************SERVER COMMUNICATION****************
         ***************************************************/
        /**
         * Creates a product on the server
         *
         * @param {Object} product
         */
        function CreateOnServer(product){
            var session = angular.fromJson(localStorage.session);
            $http({
                method: 'POST',
                url: $rootScope.apiURL+'createProduct/'+session,
                data: $.param(product),
                headers: {'Content-Type': 'application/x-www-form-urlencoded'}
            }).success(function(response){
                if(response.ErrorMessage === null && response.Result !== null){
                    mixpanel.track("Product successfuly created at server: " + response.Result.InvProductId);
                }
            })
            .error(function(data){
                mixpanel.track("Create Product Went Wrong: "+data);
                alert('Something went wrong with product creation: '+data);
            });
        }
        /**
         * Updates a product on the server
         *
         * @param {Object} product
         */
        function UpdateOnServer(product){
            var session = angular.fromJson(localStorage.session);
            $http({
                method: 'POST',
                url: $rootScope.apiURL+'updateProduct/'+session,
                data: $.param(product),
                headers: {'Content-Type': 'application/x-www-form-urlencoded'}
            }).success(function(response){
                if(response.ErrorMessage === null && response.Result !== null){
                    mixpanel.track("Product successfuly edited: " + response.Result.InvProductId);
                }
            })
            .error(function(data){
                mixpanel.track("Create Product Went Wrong: "+data);
                alert('Something went wrong with product creation: '+data);
            });
        }
        /**
         * TODO
         * Deletes a product on the server
         *
         * @param {Object} product
         */
        function DeleteOnServer(product){
            return true;
        }
        /***************VALIDATION UTILITIES****************
         ***************************************************/
        function ValidateSnapshot(product){
            var result = true;
            if(product === null || product === undefined){
                return false;
            }
            if(!product.ApplicableTaxKeys.split(',') instanceof Array || product.ApplicableTaxKeys !== null){
                return false;
            }
            if(product.Barcode.length < 1 || product.Barcode === null || product.Barcode === undefined){
                return false;
            }
            if(product.CliClientId.length !== 10){
                return false;
            }
            if(product.Description.length < 1 || product.Description === null || product.Description === undefined){
                return false;
            }
            if(product.InternalCode.length < 1 || product.InternalCode === null || product.InternalCode === undefined){
                return false;
            }
            if(!product.InvProductCategoryId.split(',') instanceof Array || product.InvProductCategoryId !== null){
                return false;
            }
            if(product.Name.length < 1 || product.Name === null || product.Name === undefined){
                return false;
            }
            if(product.SaleUnitType.length < 1 || product.SaleUnitType === null || product.SaleUnitType === undefined){
                return false;
            }
            if(product.Status.length < 1 || product.Status === null || product.Status === undefined){
                return false;
            }
            if(product.UnitMeasure.length < 1 || product.UnitMeasure === null || product.UnitMeasure === undefined){
                return false;
            }
            return result;
        }
    }
})();

Когда я запускаю начало кармы на терминале, я получаю следующие ошибки:

$ karma start 01 02 2016 18: 41: 39.939: WARN [карма]: нет захваченного браузера, откройте http://localhost: 9876/01 02 2016 18: 41: 39.948: INFO [karma]: запущен сервер Karma v0.13.19 на http://localhost: 9876/01 02 2016 18: 41: 39.953: INFO [пусковая установка]: запуск браузера PhantomJS 01 02 2016 18: 41: 40.203: INFO [PhantomJS 2.1.1 (Linux 0.0.0)]: подключен on socket/# yTkMYAHDCJhxIwALAAAA с id 3944707 PhantomJS 2.1.1 (Linux 0.0.0) factory: ProductService столкнулся с исключением извещения FAILED Ошибка: [$ injector: unpr] http://errors.angularjs.org/1.3.7/ $ инжектор /unpr? p0 = ProductServiceProvider %20% 3C- %20ProductService (строка 38)/home/eduardo/ventamia/vm2/clientside/www-app/js/angular/angular.min.js:38:332 d @/home/eduardo/ventamia/vm2/clientside/www-app/js/angular/angular.min.js:36:309/home/eduardo/ventamia/vm2/clientside/www-app/js/angular/angular.min.js: 38: 384 d@/home/eduardo/ventamia/vm2/clientside/www-app/js/angular/angular.min.js: 36: 309 e @/home/eduardo/ventamia/vm2/clientside/www-app/JS/угловой/анг ular.min.js: 37: 65 workFn@/home/eduardo/ventamia/vm2/clientside/www-app/node_modules/angular-mocks/angular-mocks.js: 2517: 26 undefined СинтаксисError: JSON Ошибка анализа: ожидается " } 'в /home/eduardo/ventamia/vm2/clientside/www-app/js/angular/angular.min.js (строка 14) parse @[собственный код] oc @/home/eduardo/ventamia/vm2/clientside/www-app/js/angular/angular.min.js: 14: 161/home/eduardo/ventamia/vm2/clientside/www-app/js/app-services-tests/product.service.test.js:7: 47 global code@/home/eduardo/ventamia/vm2/clientside/www-app/js/app-services-tests/product.service.test.js: 1: 9 PhantomJS 2.1.1 (Linux 0.0.0): Выполнено 1 из 1 (1 НЕИСПРАВНОСТЬ) ОШИБКА (0.041 сек. /0.008 сек) 01 02 2016 18: 48: 37.489: INFO [наблюдатель]: измененный файл "/home/eduardo/ventamia/vm2/clientside/www-app/js/app -Услуги-тесты/product.service.test.js". PhantomJS 2.1.1 (Linux 0.0.0): Выполнено 0 из 0 ОШИБКА (0,04 сек /0 сек) ^ Ceduardo @vmdev2: ~/ventamia/vm2/clientside/www-app/js $ karma start 01 02 2016 18:48: 42.020: WARN [карма]: нет захваченного браузера, откройте http://localhost: 9876/01 02 2016 18: 48: 42.029: INFO [karma]: Карма v0.13.19 сервер запущен по адресу http://localhost: 9876/ 01 02 2016 18: 48: 42.034: INFO [пусковая установка]: запуск браузера PhantomJS 01 02 2016 18: 48: 42.277: INFO [PhantomJS 2.1.1 (Linux 0.0.0)]: подключен к сокету /# 9-zdfLe9rv-EOnGvAAAA с id 57338630 PhantomJS 2.1.1 (Linux 0.0.0): Выполнено 0 из 0 ОШИБКА (0.037 сек /0 сек)

Заранее спасибо.

Теги:
unit-testing
jasmine

1 ответ

1
Лучший ответ

Угловой дает вам сообщение об ошибке в виде этого URL:

https://docs.angularjs.org/error/ $ injector/unpr? p0 = ProductServiceProvider %20% 3C- %20ProductService

Он говорит, что не знает, как найти свой ProductService.

На вашей фабрике вы объявляете ProductService в модуле с именем inspinia, поэтому вам нужно загрузить этот модуль до запуска ваших тестов.

Добавьте это до вашего существующего beforeEach:

beforeEach(module('inspinia'));

Затем Angular должен найти сервис и уметь его вводить.

PS: В тесте есть дубликат кода, вы можете удалить второе вхождение var ProductService; и beforeEach и просто использовать внешний.

  • 0
    Спасибо, это решило мою проблему, теперь у меня есть еще несколько ошибок, но я постараюсь их исправить.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню