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


141

У мене є кутове обслуговування, яке називається 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
    };

});

Я намагаюся перевірити цю послугу за допомогою жасмину:

"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
Обробка подій зазвичай проводиться в дайджест-циклі. Спробуйте додати сферу застосування. $ Apply () до свого тесту замість того, щоб використовувати шаблон тестування асинхроніки Жасміна
Ейтан Пеер

це не спрацювало. Я додав сферу застосування. $ Apply (); одразу після виклику requestNotificationChannel.deleteMessage (1, 4), але я отримую ту саму помилку ...
Mdb

Я отримую таку ж помилку, коли для запуску тестів на асинхронізацію триває більше часу, ніж Jestочікується - дуже поширена під час налагодження та певний час для перевірки змінних.
Дан Даскалеску

Спробуйте скористатися меншим тайм-аутом. Я отримав цю помилку під час використання timeout = 5000. Я замінив її на 2000, і вона працювала на мене!
Марина

1
Залишивши це, щоб допомогти комусь у моєму взутті. У мене виникла помилка під час запуску тестів всередині контейнера докера. Тести іноді проходять без будь-яких питань, але іноді провалюються. Я подумав, що це був якийсь стан перегонів, але не міг зрозуміти, чому. Я зрозумів, що у мене був afterEachкрок, який очищав базу даних (використовуючи deleteManyметод). Додавання jest.setTimeout(30000);в beforeAllметоді, здається, виправило це для мене - я здогадуюсь, оскільки видалення бази даних - це мережевий дзвінок (усередині умови), іноді це зайняло більше 3 секунд і кидання.
nkhil

Відповіді:


231

Якщо аргумент у вашій itфункції ( doneу наведеному нижче коді) призведе до того, що Жасмін спроби виклику асинхронізації.

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

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

Це не має значення, як doneаргументується назва, його існування - це все, що має значення. Я зіткнувся з цим питанням із занадто багато копій / пасти.

Документи асинхронної підтримки Jasmine відзначають, що аргумент (названий doneвище) - це зворотний виклик, який можна викликати, щоб повідомити Жасмін про завершення асинхронної функції. Якщо ви ніколи цього не називаєте, Жасмін ніколи не дізнається, що ваш тест зроблений, і в кінцевому підсумку вичерпається час.


3
Те саме стосується аргументів в описі (у кутовій, для цього потрібно зателефонувати ввести
ін'єкцію

@MartinBliss Це документально підтверджено, я пропонував редагувати посилання на документацію: stackoverflow.com/sugges-edits/2434606
Vincent

39
Зверніть увагу на випадкових Google, які в майбутньому стикаються з цим питанням: якщо ви використовуєте Protractor і зіткнулися з цією проблемою, ця відповідь - це не те, що ви шукаєте - Protractor викликає зворотний виклик сам по собі.
Вінсент

Це вирішило мою проблему, і це було викликано тим самим куплрітом "копія / паста"
shaikh

1
@Vincent, що видають користувачі Protractor, якщо виникає ця помилка?
Бруно Бієрі

57

Навіть для тестів на асинхронізацію існує час очікування, який вимикається в цьому випадку. Ви можете подолати цю помилку, збільшивши значення для граничного тайм-ауту для оцінки зворотного виклику асинхронного жасмину

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

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

    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


1
Це здається не «правильним способом» зробити це, але після додавання декількох додаткових нулів, щоб мій тест Selenium запустився, це був необхідний злом.
emery

Оригінальний жасмин.DEFAULT_TIMEOUT_INTERVAL - 60000 мс. Тож цей приклад насправді зробить його в шість разів коротшим.
Уолтарі

Ви маєте рацію, я просто поставив випадковий номер у цьому прикладі, дякую :)
gsalgadotoledo

20

Ця помилка може бути також спричинена тим, що не вводити ін'єкцію при ініціалізації послуги / фабрики чи будь-чого іншого. Наприклад, його можна кинути, зробивши це:

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

Щоб виправити це, просто оберніть функцію ін'єкцією, щоб правильно отримати послугу:

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

13
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();
        }));
    });

6

Можна використовувати карму-жасмін плагін щоб встановити інтервал часу за замовчуванням у всьому світі.

Додайте цей конфігурацію в karma.conf.js

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

5

Ця помилка почалася для мене непросто, на тесті, який завжди працював. Я не міг знайти жодних пропозицій, які допомогли б, поки я не помітив, що мій Macbook працює повільно. Я помітив, що процесор був пов'язаний з іншим процесом, який я вбив. Помилка асинком Jasmine зникла, і мої тести ще раз добре.

Не питайте мене, чому я не знаю. Але за моєю обставиною, здавалося, це було недоліком системних ресурсів.


5
Ймовірно, коли ваш процесор був вільним, завдання закінчилося до часу очікування за замовчуванням. Коли процесор був зайнятий, завдання, яке ви тестували, зайняло занадто багато часу, щоб виконати.
Шейн

5

Це скоріше спостереження, ніж відповідь, але це може допомогти іншим, хто був так само розчарований, як я.

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

Я розчарувався і перевірив код на ноутбуці сьогодні вранці. Пройшов весь тестовий набір (близько 180 тестів), помилок не було. Тож помилки ніколи не були в коді чи тестах. Повернувся до своєї скриньки розробників і перезавантажив її, щоб очистити що-небудь у пам'яті, що, можливо, спричинило проблему. Ніяких змін, однакові помилки на тих самих двох тестах. Тому я видалив каталог зі своєї машини і перевірив його назад. Вуаля! Немає помилок.

Ніякої ідеї, що це спричинило, чи як його виправити, але видалення робочого каталогу та перевірка його виправлено, як би там не було.

Сподіваюся, що це комусь допоможе.


1
Спасибі тобі, я зійшов з розуму з цього приводу. Я перезавантажив свій комп’ютер, і це було все
yngrdyn

У моєму випадку я просто перезапустив команду і це вирішило це питання. У мене було гаряче перезавантаження для одиничних тестів, і кожен раз, коли він провалювався. Мені довелося знову зупинитися і запустити команду.
джигнеш

4

Не використовуйте done, просто залиште виклик функції порожнім.


Будь ласка, виправте мене, якщо я помиляюся, але, як я зрозумів, він просто закінчує тестовий набір перед самим тестом, і замість цього скидається повідомлення про помилку. Це означає, що будь-яке твердження, яке не вдалося, не порушить тест, оскільки тестовий набір закінчений до запуску затвердження. Це також може означати (я бачив подібну поведінку), що інший тест показує помилку, яку створив цей тест. Зрештою, це означає, що для початку все виглядає нормально, але в міру збільшення кількості тестів проблема з періодичністю з’явиться.
LosManos

3

Ви також отримуєте цю помилку, коли очікуєте чогось у beforeAllфункції!

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

    beforeAll(function () {
        ...

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

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

    }
}

2

У моєму випадку ця помилка була викликана неправильним використанням "fixture.detectChanges ()" Здається, цей метод є слухачем подій (async), який відповість на зворотний дзвінок лише тоді, коли виявлені зміни. Якщо жодних змін не буде виявлено, це не призведе до зворотного виклику, що призведе до помилки очікування. Сподіваюся, це допомагає :)


2

Працює після видалення 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} );
    });
});

0

Як зазначає @mastablasta, але також додати, що якщо ви викликаєте аргумент 'done' або, швидше, його ім'я завершено, ви просто зателефонуєте, зворотний виклик завершився () у вашому тесті, коли це буде зроблено.

// 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(){
  //...
});

0

жасмин.DEFAULT_TIMEOUT_INTERVAL = 100000;

Зберігання цього блоку вирішило мою проблему.

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

0

Що я зробив: додав / оновив наступний код:

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

3
Поясніть, чому цей код працює, а не просто публікувати його без пояснень.
Кобе

Таким чином, коли ви виконуєте тест, і це займає більше часу, ніж очікувалося, воно виходить з ладу, оскільки час за замовчуванням був досягнутий, а сценарій не рухався вперед у виконанні. Це може статися через невиконання деяких умов (наприклад, видимість, завантаження сторінки). Тепер, якщо ваш час за замовчуванням такий, як 1000 мс >>, сценарії часто виходили з ладу, тому що це лише одна секунда, і до помилки вашого сценарію може бути кілька факторів. Однак збільшення інтервалу очікування може змусити браузер / драйвер чекати довше, коли умови будуть дотримані.
Zeeshan

2
Гаразд, тепер це слово до своєї посади; ви повинні намагатися уникати відповіді з кодом без пояснень :)
Kobe


0

Схоже, тест чекає деякого зворотного дзвінка, який ніколи не приходить. Це, мабуть, тому, що тест не виконується з асинхронною поведінкою.

По-перше, подивіться, чи просто ви використовуєте fakeAsync у своєму "it" сценарії:

it('should do something', fakeAsync(() => {

Ви також flush()можете чекати закінчення черги мікрозадач або tick()чекати певний час.


-2

Якщо у вас є аргумент ( 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        
});

4
Без будь-якого пояснення, чому ця відповідь не так корисна.
Гері

2
ця відповідь вирішила мою проблему ... кутове тестування - це кошмар!
Бенджамін Каур
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.