Жасмин: обратный вызов Async не вызывался в течение таймаута, указанного jasmine.DEFAULT_TIMEOUT_INTERVAL

У меня есть служба angular, называемая requestNotificationChannel:

app.factory("requestNotificationChannel", function($rootScope) {

    var _DELETE_MESSAGE_ = "_DELETE_MESSAGE_";

    function deleteMessage(id, index) {
        $rootScope.$broadcast(_DELETE_MESSAGE_, { id: id, index: index });
    };

    return {
       deleteMessage: deleteMessage
    };

});

Я пытаюсь выполнить unit test эту службу с помощью jasmine:

"use strict";

describe("Request Notification Channel", function() {
    var requestNotificationChannel, rootScope, scope;

    beforeEach(function(_requestNotificationChannel_) {
        module("messageAppModule");

        inject(function($injector, _requestNotificationChannel_) {
            rootScope = $injector.get("$rootScope");
            scope = rootScope.$new();
            requestNotificationChannel = _requestNotificationChannel_;
        })

        spyOn(rootScope, '$broadcast');
    });


    it("should broadcast delete message notification", function(done) {

        requestNotificationChannel.deleteMessage(1, 4);
        expect(rootScope.$broadcast).toHaveBeenCalledWith("_DELETE_MESSAGE_", { id: 1, index: 4 });
        done();       
    });
});

Я читал об асинхронной поддержке в Жасмине, но, поскольку я довольно новичок в модульном тестировании с javascript, я не мог заставить его работать.

Я получаю сообщение об ошибке:

Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL

и мой тест слишком длительный, чтобы выполнить (около 5 секунд).

Может ли кто-нибудь помочь мне предоставить рабочий пример моего кода с некоторым объяснением?

Ответ 1

Наличие аргумента в вашей функции it (done в приведенном ниже коде) заставит Jasimne предпринять асинхронный вызов.

//this block signature will trigger async behavior.
it("should work", function(done){
  //...
});

//this block signature will run synchronously
it("should work", function(){
  //...
});

Не имеет значения, как назван аргумент done, его существование - все, что имеет значение. Я столкнулся с этой проблемой из-за слишком большого количества копий/пасты.

В документации по асинхронной поддержке Jasmin отмечается, что аргумент (с именем done выше) является обратным вызовом, который можно вызвать, чтобы сообщить Jasmine о завершении асинхронной функции. Если вы никогда не позвоните, Жасмин никогда не узнает, что ваш тест завершен, и в конечном итоге прекратит работу.

Ответ 2

В качестве обходного пути вы можете увеличить ограничение времени ожидания для оценки асинхронного обратного вызова Jasmine.

describe('Helper', function () {
    var originalTimeout;

    beforeEach(function() {
        originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL;
        jasmine.DEFAULT_TIMEOUT_INTERVAL = 100000;
    });

    afterEach(function() {
      jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout;
    });

    it('Template advance', function(doneFn) {
        $.ajax({
            url: 'public/your-end-point.mock.json',
            dataType: 'json',
            success: function (data, response) {
                // Here your expected using data
                expect(1).toBe(1)
                doneFn();
            },
            error: function (data, response) {
                // Here your expected using data
                expect(1).toBe(1)
                doneFn();
            }
        });
    });
});

Источник: http://jasmine.github.io/2.0/introduction.html#section-42

Ответ 3

Эта ошибка также может быть вызвана пропуском inject при инициализации службы/фабрики или чего-либо еще. Например, это может быть брошено, делая это:

var service;
beforeEach(function(_TestService_) {
    service = _TestService_;
});

Чтобы исправить это, просто оберните функцию с помощью inject, чтобы правильно получить сервис:

var service;
beforeEach(inject(function(_TestService_) {
    service = _TestService_;
}));

Ответ 4

import { fakeAsync, ComponentFixture, TestBed } from '@angular/core/testing';

использовать fakeAsync

beforeEach(fakeAsync (() => {

//your code

}));



describe('Intilalize', () => {
        it('should have a defined component', fakeAsync(() => {
            createComponent();
            expect(_AddComponent.ngOnInit).toBeDefined();
        }));
    });

Ответ 5

Эта ошибка начала для меня синим, в тесте, который всегда работал. Я не мог найти предложений, которые помогли, пока я не заметил, что мой Macbook работает вяло. Я заметил, что процессор был привязан другим процессом, который я убил. Ошибка async Jasmine исчезла, и мои тесты снова прекрасны.

Не спрашивай меня, почему, я не знаю. Но в моих обстоятельствах это казалось недостатком системных ресурсов в вине.

Ответ 6

Это скорее наблюдение, чем ответ, но оно может помочь другим, которые были так же разочарованы, как и я.

Я продолжал получать эту ошибку из двух тестов в моем наборе. Я думал, что просто сломал тесты с помощью рефакторинга, который я делал, поэтому после возврата изменений не сработал, я вернулся к более раннему коду, дважды (две ревизии назад), думая, что это избавит от ошибки. Это ничего не изменило. Я преследовал свой хвост весь день вчера и часть этого утра, не решая проблему.

Я расстроился и проверил код на ноутбуке этим утром. Запустил весь набор тестов (около 180 тестов), ошибок нет. Таким образом, ошибки никогда не были в коде или тестах. Вернулся к моей коробке разработчика и перезагрузил ее, чтобы очистить все, что в памяти могло вызвать проблему. Без изменений, те же ошибки на тех же двух тестах. Поэтому я удалил каталог со своего компьютера и проверил его обратно. Вуаля! Нет ошибок

Не знаю, что вызвало это, или как это исправить, но удаление рабочего каталога и его восстановление исправили, что бы это ни было.

Надеюсь, это кому-нибудь поможет.

Ответ 7

Вы также получаете эту ошибку, ожидая чего-то в функции beforeAll!

describe('...', function () {

    beforeAll(function () {
        ...

        expect(element(by.css('[id="title"]')).isDisplayed()).toBe(true);
    });

    it('should successfully ...', function () {

    }
}

Ответ 8

Вы можете использовать плагин karma-jasmine, чтобы установить интервал ожидания по умолчанию во всем мире.

Добавьте этот конфиг в karma.conf.js

module.exports = function(config) {
  config.set({
    client: {
      jasmine: {
        timeoutInterval: 10000
      }
    }
  })
}

Ответ 9

В моем случае эта ошибка была вызвана неправильным использованием "fixture.detectChanges()". Кажется, этот метод является прослушивателем событий (асинхронным), который будет отвечать на обратный вызов только при обнаружении изменений. Если никаких изменений не обнаружено, он не будет вызывать обратный вызов, что приведет к ошибке тайм-аута. Надеюсь это поможет :)

Ответ 10

Работает после удаления ссылки на scope и аргументов функции:

"use strict";

describe("Request Notification Channel", function() {
    var requestNotificationChannel, rootScope;

    beforeEach(function() {
        module("messageAppModule");

        inject(function($injector, _requestNotificationChannel_) {
            rootScope = $injector.get("$rootScope");
            requestNotificationChannel = _requestNotificationChannel_;
        })
        spyOn(rootScope, "$broadcast");
    });


    it("should broadcast delete message notification with provided params", function() {
        requestNotificationChannel.deleteMessage(1, 4);
        expect(rootScope.$broadcast).toHaveBeenCalledWith("_DELETE_MESSAGE_", { id: 1, index: 4} );
    });
});

Ответ 11

Вместо

beforeEach(() => {..

использовать

beforeEach(fakeAsync(() => {..

Ответ 12

Если у вас есть аргумент (done) в функции it попробуйте удалить его, а также вызвать его внутри самой функции:

it("should broadcast delete message notification", function(/*done -> YOU SHOULD REMOVE IT */) {

    requestNotificationChannel.deleteMessage(1, 4);
    expect(rootScope.$broadcast).toHaveBeenCalledWith("_DELETE_MESSAGE_", { id: 1, index: 4 });
    // done(); -> YOU SHOULD REMOVE IT        
});

Ответ 13

Как отмечает @mastablasta, но также добавим, что если вы вызываете аргумент 'done' или скорее называете его завершенным, вы просто вызываете callback complete() в своем тесте, когда это будет сделано.

// this block signature will trigger async behavior.
it("should work", function(done){
  // do stuff and then call done...
  done();
});

// this block signature will run synchronously
it("should work", function(){
  //...
});

Ответ 14

jasmine.DEFAULT_TIMEOUT_INTERVAL = 100000;

Хранение этого в блоке решило мою проблему.

it('', () => {
 jasmine.DEFAULT_TIMEOUT_INTERVAL = 100000;
});

Ответ 15

не делайте длинный код, разбивающий его на маленькие блоки "it". так работает

Ответ 16

Попробуйте использовать меньшее время ожидания. Я получил эту ошибку при использовании timeout = 5000. Я заменил его на 2000, и он работал для меня!

Ответ 17

Что я сделал: добавил/обновил следующий код:

framework: 'jasmine',
jasmineNodeOpts: 
{
    // Jasmine default timeout
    defaultTimeoutInterval: 60000,
    expectationResultHandler(passed, assertion) 
    {
      // do something
    },
}