Jamsine выдает ошибку несмотря на тот же код, работающий в браузере - PullRequest
0 голосов
/ 31 августа 2018

Я добавил этот код в свой компонентный контроллер для фокусировки ввода, и он отлично работал в браузере, но он сломал все мои тесты шаблонов. Я думал, что могу просто сбросить $timeout, и все будет хорошо, но это не так.

vm.$onInit = init;

function init(){
    focusInput();
}

function focusInput(){
    $timeout(function(){
        $document[0]
            .querySelector('md-autocomplete-wrap')
            .querySelector('input')
            .focus();
    }, 0);
}

Однако в моем модульном тесте Жасмин сообщает, что .querySelector недоступен, потому что результат первого querySelector равен нулю в тестовой среде.

it('should render', function(){
    var wrap, searchBarDirective, $scope;
    $scope = $rootScope.$new();
    searchBarDirective = $compile(angular.element(template))($scope);
    $scope.$digest(); 

    $timeout.flush();

    wrap = searchBarDirective.find('md-autocomplete-wrap')[0];
    expect(wrap).toBeDefined();
});

Для меня очевидно, что $document не содержит визуализированной директивы и, следовательно, вторая querySelector завершается неудачно. Но почему $ document не содержит директивы?

Я попытался смоделировать querySelector с помощью spyOn($document[0], "querySelector").and.returnValues($document[0],$document[0]), но это не помогло мне преодолеть focus. Думая, у меня есть много пути здесь.

* Пересмотрено *

Я думаю, что важно продолжать использовать $ document, но я решил отказаться от querySelector для метода jqLite find.

function focusInput(){
    $timeout(function(){
        var input;
        try {
            // can throw an error if the first find fails
            input = $document.find('md-autocomplete').find('input');
        }
        catch (e) {
            angular.noop(e);
        }
        if(input && angular.isFunction(input.focus)) {
            input.focus();
        }
    }, 0);
}

Тест, который я изменил в комментариях к ниже. У меня есть Karma загрузки jquery, чтобы упростить тестирование, что позволяет мне искать :focus

beforeEach(function(){
    element = angular.element(template);
    $document[0].body.appendChild(element[0]);
    $scope = $rootScope.$new();
});
afterEach(function(){
    element[0].remove();
});
it('should be focused', function(){
    var input, searchBarDirective;
    searchBarDirective = $compile(element)($scope);

    $scope.$digest();
    $timeout.flush();

    input = searchBarDirective.find(':focus')[0];
    expect(input).toBeDefined();
});

1 Ответ

0 голосов
/ 02 сентября 2018

Причина, по которой ваш вызов querySelector работает в браузере, но не в тестах, заключается в том, что вы создаете элемент DOM с angular.element, но никогда не присоединяете его к документу. Есть два способа решения этой проблемы:

Во-первых, вы могли бы просто сделать это. Вместо:

searchBarDirective = $compile(angular.element(template))($scope);

Do:

let element; // declare this in the describe block so it is available later

element = angular.element(template);
document.body.appendChild(element[0]);
searchBarDirective = $compile(element)($scope);

А затем сделайте это:

afterEach(() => element[0].remove());

Но это немного грязно. Вы не должны манипулировать глобальной областью действия (т. Е. Документом) в своих модульных тестах, если это не требуется. В вашем не тестовом коде было бы лучше избежать доступа к документу и вместо этого получить доступ к элементу области действия или другому элементу DOM, который вы также можете смоделировать в своих тестах. Это будет немного сложнее сделать, так как может потребоваться немного изменить архитектуру вашего кода. Однако в целом для создания модульного и тестируемого кода необходимо избегать максимально возможного доступа к объекту document.

...