0

I've been trying to configure ng-html2js to work for my simple directive testing (whole project source can be found here).

The relevant pieces of code are:

angular\karma.conf.js

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

        basePath: './app',

        preprocessors: {
            'components/**/*.tpl.html': ["ng-html2js"]
        },

        ngHtml2JsPreprocessor: {
            cacheIdFromPath: function (filepath) {
                console.info('ngHtml2JsPreprocessor: Loaded template from path "' + filepath + '"');
                return filepath;
            },
            moduleName: 'jasmineTemplates'
        },

        files: [
            'bower_components/angular/angular.js',
            'bower_components/angular-mocks/angular-mocks.js',
            'components/**/*.js',
            'components/**/*.tpl.html'
        ],

        autoWatch: true,

        frameworks: ['jasmine'],

        browsers: ['PhantomJS'],

        plugins: [
            'karma-ng-html2js-preprocessor',
            'karma-phantomjs-launcher',
            'karma-chrome-launcher',
            'karma-firefox-launcher',
            'karma-jasmine'
        ]

    });
};

angular\app\components\paginatedTable\paginatedTable.js

var COMPONENT_NAME = 'PaginatedTable';
var EVENTS = {
    ORDERED_BY: COMPONENT_NAME + ': Ordered table',
    FILTERED_BY: COMPONENT_NAME + ': Filtered rows'
};

angular.module('paginatedTable', [])

    .controller('paginatedTableCtrl',
        ["$scope", "$sce", "$filter",
            function($scope, $sce, $filter) {
                $scope.getHeader = function (column) {
                    var header = column.titleTpl ? column.titleTpl : column.title ? column.title : capitalizeFirstLetter(column.value);
                    var icon = ($scope.sortBy && $scope.sortBy.reverse) ? '▾' : '▴';
                    var isSelected = ($scope.sortBy && $scope.sortBy.property) === column.value;
                    return header + ' <span ng-show="' + (isSelected) + '">' + icon + '</span>';
                };

                $scope.getProperty = function (column, row) {
                    return column.format ? column.format(row) : row[column.value];
                };

                $scope.filterRows = function () {
                    if ($scope.data) {
                        $scope.rows = $filter('filter')($scope.data, $scope.filterQuery);
                        setMetadata('rowsCount', $scope.rows.length);
                        $scope.$emit(EVENTS.FILTERED_BY, {
                            id: $scope.id,
                            filterQuery: $scope.filterQuery
                        });
                    }
                };

                $scope.sortByColumn = function (column) {
                    $scope.sortBy = $scope.sortBy || {};

                    if ($scope.sortBy.property && $scope.sortBy.property == column.value) {
                        $scope.sortBy.reverse = !$scope.sortBy.reverse;
                    } else {
                        $scope.sortBy.property = column.value;
                        $scope.sortBy.reverse = column.reverseOrder || false;
                    }

                    $scope.sortTable();
                };

                $scope.sortTable = function (silent) {
                    if ($scope.rows && $scope.sortBy && $scope.sortBy.property) {
                        var sortingParameters = {
                            rows: $scope.rows,
                            property: $scope.sortBy.property,
                            reverse: $scope.sortBy.reverse,
                            // Optional
                            defaultProperty: $scope.sortBy.default,
                            defaultReverse: $scope.sortBy.defaultReverse
                        };

                        $scope.rows = sortRowsByProperty(sortingParameters);
                        $scope.currentPage = 0;

                        if (silent !== true) {
                            $scope.$emit(EVENTS.ORDERED_BY, {
                                id: $scope.id,
                                sortBy: $scope.sortBy
                            });
                        }
                    }
                };

                $scope.loadPreviousPage = function () {
                    $scope.currentPage = fixSmallerPage($scope.currentPage - 1);
                };

                $scope.loadNextPage = function () {
                    $scope.currentPage = fixLargerPage($scope.currentPage + 1);
                };

                $scope.loadPage = function (newPage) {
                    newPage = fixSmallerPage(newPage);
                    newPage = fixLargerPage(newPage);
                    $scope.currentPage = newPage;
                };

                $scope.getTotalPagesArray = function () {
                    return $scope.pageCount > 0 ? new Array($scope.pageCount) : [];
                };

                $scope.$watchGroup(['data', 'filterQuery'], function() {
                    $scope.filterRows();
                });

                $scope.$watch('rows', function(rows) {
                    if (rows) {
                        $scope.pageCount = getPageCount();
                        $scope.sortTable(true);
                    }
                });

                function getPageCount () {
                    return Math.ceil($scope.rows.length / $scope.pageSize);
                }

                function fixSmallerPage (newPage) {
                    return newPage >= 0 ? newPage : 0;
                }

                function fixLargerPage (newPage) {
                    return newPage < $scope.pageCount ? newPage : $scope.pageCount;
                }

                function capitalizeFirstLetter (string) {
                    return isString(string) && string.length ? string.charAt(0).toUpperCase() + string.slice(1) : '';
                }

                function sortRowsByProperty (settings) {
                    if (settings.rows) {
                        var propertySteps = settings.property.split('.');

                        settings.rows.sort(function (row_a, row_b) {
                            var value_a = getRowProperty(row_a, propertySteps),
                                value_b = getRowProperty(row_b, propertySteps),
                                reverse = settings.reverse;

                            if (value_a === value_b) {
                                if (!settings.defaultProperty || settings.defaultProperty === settings.property) {
                                    return 0;
                                } else {
                                    value_a = row_a[settings.defaultProperty];
                                    value_b = row_b[settings.defaultProperty];
                                    reverse = settings.defaultReverse;
                                }
                            }

                            return compareProperties(value_a, value_b, reverse);
                        });

                        return settings.rows;
                    }
                }

                function getRowProperty (row, propertySteps) {
                    var value = row;

                    for (var i in propertySteps) {
                        value = value[propertySteps[i]];
                    }

                    return value;
                }

                function setMetadata(key, value) {
                    if ($scope.metadata) {
                        $scope.metadata[key] = value;
                    }
                }

                function compareProperties (value_a, value_b, reverse) {
                    var sign = reverse ? -1 : 1;

                    if (isString(value_a) || isString(value_b)) {
                        return sign * compareStrings(value_a, value_b);
                    }
                    return sign * (value_a - value_b);
                }

                function compareStrings (str_a, str_b) {
                    if (str_a === '') return -1;
                    if (str_b === '') return 1;
                    str_a = ('' + str_a).toLowerCase();
                    str_b = ('' + str_b).toLowerCase();
                    return ((str_a < str_b) ? -1 : ((str_a > str_b) ? 1 : 0));
                }
            }
        ])

    .directive('paginatedTable',
        function() {
            return {
                restrict: 'E',
                replace: true,
                controller : 'paginatedTableCtrl',
                templateUrl: getPath() + 'paginatedTable.tpl.html',
                scope: {
                    id: '=',
                    columns: '=',
                    data: '=',
                    pageSize: '=',
                    sortBy: '=?',
                    filterQuery: '=?',
                    numeration: '=?',
                    scopeVariables: '=scope',
                    onLoad: '=?',
                    metadata: '=?'
                },
                link: function ($scope, element, attributes) {
                    var objectProperties = ['sortBy', 'metadata'];
                    bindScopeVariables($scope);

                    for (var i in objectProperties) {
                        var property = objectProperties[i];
                        $scope[property] = $scope[property] || {};
                    }

                    if (!$scope.sortBy.property) {
                        $scope.sortBy.property = $scope.sortBy.default;
                        $scope.sortBy.reverse = $scope.sortBy.defaultReverse;
                    }

                    $scope.currentPage = 0;
                    $scope.metadata.$scope = $scope;
                    $scope.filterRows();

                    if (typeof $scope.onLoad === 'function') $scope.onLoad($scope);
                }
            };

            function bindScopeVariables ($scope) {
                var scopeVariables = $scope.scopeVariables;

                if (isObject(scopeVariables)) {
                    var keys = Object.keys(scopeVariables);

                    for (var i in keys) {
                        var key = keys[i];
                        $scope[key] = scopeVariables[key];
                    }
                }

                delete $scope.scopeVariables;
            }

            function getPath () {
                var scripts = document.getElementsByTagName('script');

                for (var i in scripts) {
                    var scriptPath = scripts[i].src;

                    if (scriptPath.indexOf('paginatedTable.js') > -1) {
                        return scriptPath.substring(0, scriptPath.lastIndexOf('/') + 1);
                    }
                }
            }
        }
    )

    .directive('bindCompiledHtml', [
        "$compile",
        function ($compile) {
            return {
                restrict: 'A',
                link: function($scope, element, attrs) {
                    $scope.$watch(function () {
                        return $scope.$eval(attrs.bindCompiledHtml);

                    }, function (value) {
                        element.html(value);
                        $compile(element.contents())($scope);
                    });
                }
            }
        }
    ])

    .filter('limitToRange', function() {
        return function(rows, limits) {
            return rows ? rows.slice(+limits[0], +limits[1]) : undefined;
        }
    });

function isString (object) {
    return typeof object === 'string';
}

function isObject (object) {
    return typeof object === 'object';
}

angular\app\components\paginatedTable\paginatedTableDirective.spec.js

(function () {

describe('paginatedTable directive', function () {
    var $scope, $compile, dummyRows;

    beforeEach(function () {
        module("jasmineTemplates");
        module("paginatedTable");
        //module("components/paginatedTable/paginatedTable.tpl.html");

        inject(["$compile", "$rootScope",
            function ($compile_, $rootScope) {
                $scope = $rootScope.$new();
                $compile = $compile_;
            }
        ]);

        dummyRows = [
            { keyName: 'value0' },
            { keyName: 'value2', drawSolver: '2' },
            { keyName: 'value1' },
            { keyName: 'value2', drawSolver: '1' },
            { keyName: 'value4' }
        ];
    });

    describe('link function', function () {
        it('should call the onLoad callback if defined', function() {
            // Arrange
            $scope.onLoad = function () {
                console.log('Loaded directive');
            }
            spyOn(console, 'log');

            initializeScopePaginatedTableSettings();

            var directive = getCompiledDirective($scope);
            dump(directive);

            // Act
            $scope.$apply();
            $httpBackend.flush();

            // Assert
            expect(console.log).toHaveBeenCalled();
        });
    });

    /*describe('something', function () {
        it('should do something', function () {

        });
    });*/

    function initializeScopePaginatedTableSettings() {
        $scope.paginatedTable = {
            'columns': [
                {
                    value: 'keyName',
                    title: 'Title',
                    format: function (row) {
                        return '<span>' + row.title + '</span>';
                    }
                },
                {
                    value: 'score',
                    mouseover: 'Sort by score',
                    reverseOrder: true
                },
            ],
            'sortBy': {
                property: 'title',
                default: 'title'
            },
            'pageSize': 1,
            'rows': dummyRows
        }
    }

    function getCompiledDirective($scope) {
        var html = '<paginated-table '
            + 'columns="paginatedTable.columns" '
            + 'data="paginatedTable.rows" '
            + 'sort-by="paginatedTable.sortBy" '
            + 'page-size="paginatedTable.pageSize" '
            + 'numeration="paginatedTable.numeration" '
            + 'filter-query="filterQuery" '
            + 'metadata="paginatedTable.metadata" '
            + 'on-load="onLoad"'
            + '/></paginated-table>';

        var compiledDirective = $compile(html)(angular.extend($scope, {}));

        return compiledDirective;
    }
});

This returns an error of unexpected get request, which should've been solved by importing the "jasmineTemplates" generated by ng-html2js as configured on karma.conf.js.

And the TPL path is the same ng-html2js processed beforehand:

enter image description here

The tree structure, in case it helps, goes like follows:

enter image description here

EDIT: Running karma on Chrome instead of PhantomJS still throws the same error so I'd suppose this isn't PhantomJS specific.

Jesús Cruz
  • 192
  • 2
  • 18

1 Answers1

0

While creating the controller in your test case file, create mocks for all the dependencies in your actual controller. I got a similar error which I fixed by including all the dependencies in test case.

user2427829
  • 128
  • 1
  • 7
  • Could you please elaborate a bit? I don't understand what you're telling me to do, @user2427829 – Jesús Cruz Jul 12 '16 at 10:36
  • Your paginatedTableCtrl is injecting $sce and $filter services, but these are not mocked in your test cases. Try to add mocks for these. It might fix the issue. – user2427829 Jul 12 '16 at 10:54
  • Thanks for the tip, but it sadly didn't solve the issue. I injected the dependencies on both test files but it changed nothing. In any case, "paginatedTableCtrl.spec.js" is already passing the tests. Only "paginatedTableDirective.spec.js" is failing because of the "unexpected request" error. – Jesús Cruz Jul 12 '16 at 11:40