jasmine: Callback Async tidak dipanggil dalam batas waktu yang ditentukan oleh jasmine.DEFAULT_TIMEOUT_INTERVAL


140

Saya memiliki layanan sudut bernama 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
    };

});

Saya mencoba untuk menguji layanan ini menggunakan melati:

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

Saya membaca tentang Dukungan Asinkron di Jasmine, tetapi karena saya agak baru dalam pengujian unit dengan javascript tidak dapat membuatnya berfungsi.

Saya menerima kesalahan:

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

dan pengujian saya terlalu lama untuk dijalankan (sekitar 5s).

Adakah yang bisa membantu saya memberikan contoh kerja kode saya dengan beberapa penjelasan?


1
Acara pengolahan biasanya dilakukan dalam siklus intisari. Coba tambahkan cakupan. $ Apply () ke pengujian Anda alih-alih menggunakan pola pengujian async Jasmine
Eitan Peer

ini tidak berhasil. Saya menambahkan ruang lingkup. $ Apply (); tepat setelah memanggil requestNotificationChannel.deleteMessage (1, 4) tapi saya menerima kesalahan yang sama ...
Mdb

Saya mendapatkan kesalahan yang sama ketika tes async membutuhkan waktu lebih lama untuk dijalankan daripada yang Jestdiharapkan - sangat umum saat debugging dan meluangkan waktu untuk memeriksa variabel.
Dan Dascalescu

Coba gunakan timeout yang lebih rendah. Saya mendapatkan kesalahan ini saat menggunakan batas waktu = 5000. Saya menggantinya dengan 2000 dan berhasil bagi saya!
Marina Riaz

1
Meninggalkan ini di sini untuk membantu seseorang di sepatuku. Saya memiliki kesalahan ini saat menjalankan tes di dalam wadah buruh pelabuhan. Tes terkadang lulus tanpa masalah, tetapi terkadang gagal. Saya pikir itu semacam kondisi balapan tetapi tidak tahu mengapa. Saya menyadari bahwa saya memiliki afterEachlangkah yang membersihkan database (menggunakan deleteManymetode). Menambahkan jest.setTimeout(30000);dalam beforeAllmetode ini tampaknya telah memperbaiki ini untuk saya - saya menduga karena penghapusan basis data adalah panggilan jaringan (di dalam kondisi), kadang-kadang membutuhkan waktu lebih dari 3 detik dan melempar.
nkhil

Jawaban:


231

Memiliki argumen dalam itfungsi Anda ( donedalam kode di bawah) akan menyebabkan Jasmine mencoba melakukan panggilan async.

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

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

Tidak ada bedanya apa nama doneargumen itu, keberadaannya adalah yang terpenting. Saya mengalami masalah ini karena terlalu banyak salin / pasta.

Dokumen Dukungan Jasmine Asynchronous mencatat bahwa argumen (disebutkan di doneatas) adalah panggilan balik yang dapat dipanggil untuk memberi tahu Jasmine ketika fungsi asinkron selesai. Jika Anda tidak pernah menyebutnya, Jasmine tidak akan pernah tahu tes Anda selesai dan pada akhirnya akan habis.


3
Hal yang sama berlaku untuk args dalam uraian (dalam sudut, Anda perlu memanggil inject dalam uraikan untuk melakukan itu)
Narretz

@ MartinBliss Sudah didokumentasikan, saya baru saja menyarankan mengedit untuk merujuk ke dokumentasi: stackoverflow.com/suggested-edits/2434606
Vincent

39
Catatan untuk Googler acak menemukan pertanyaan ini di masa depan: jika Anda menggunakan busur derajat dan mengalami masalah ini, jawaban ini bukan yang Anda cari - Busur Derajat memanggil panggilan balik dengan sendirinya.
Vincent

Itu memperbaiki masalah saya dan itu disebabkan oleh "copy / pasta" cuplrit yang sama
shaikh

1
@Incent apa masalah pengguna busur derajat lalu jika kesalahan ini terjadi?
Bruno Bieri

57

Bahkan untuk tes async, ada batas waktu yang padam dalam kasus ini, Anda bisa mengatasi kesalahan ini dengan meningkatkan nilai batas waktu batas untuk mengevaluasi panggilan balik Jasmine async

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

Sumber: http://jasmine.github.io/2.0/introduction.html#section-42


1
Ini sepertinya bukan "cara yang tepat" untuk melakukannya, tetapi setelah menambahkan beberapa nol ekstra untuk menjalankan tes Selenium saya, ini adalah peretasan yang diperlukan.
Amril

Melati asli.DEFAULT_TIMEOUT_INTERVAL adalah 60000 ms. Jadi contoh ini sebenarnya akan membuatnya enam kali lebih pendek.
Waltari

Anda benar, saya hanya memasukkan angka acak dalam contoh ini, terima kasih :)
gsalgadotoledo

20

Kesalahan ini juga dapat disebabkan oleh tidak menyuntikkan saat menginisialisasi layanan / pabrik atau apa pun. Sebagai contoh, itu dapat dibuang dengan melakukan ini:

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

Untuk memperbaikinya cukup bungkus fungsi dengan menyuntikkan untuk mengambil layanan dengan benar:

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

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

gunakan fakeAsync

beforeEach(fakeAsync (() => {

//your code

}));



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

6

Anda dapat menggunakan plugin karma-jasmine untuk mengatur interval waktu default secara global.

Tambahkan konfigurasi ini di karma.conf.js

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

5

Kesalahan ini berawal dari saya, pada tes yang selalu berhasil. Saya tidak dapat menemukan saran yang membantu sampai saya perhatikan Macbook saya berjalan lamban. Saya perhatikan CPU dipatok oleh proses lain, yang saya bunuh. Kesalahan Jasmine async menghilang dan tes saya baik-baik saja sekali lagi.

Jangan tanya kenapa, saya tidak tahu. Tetapi dalam keadaan saya tampaknya kekurangan sumber daya sistem kesalahan.


5
Mungkin, ketika CPU Anda bebas, tugas selesai sebelum batas waktu default. Saat CPU sedang sibuk, tugas yang Anda uji terlalu lama untuk diselesaikan.
Shane

5

Ini lebih merupakan pengamatan daripada jawaban, tetapi mungkin membantu orang lain yang sama frustrasinya dengan saya.

Saya terus mendapatkan kesalahan ini dari dua tes di suite saya. Saya pikir saya baru saja memecahkan tes dengan refactoring yang saya lakukan, jadi setelah mencadangkan perubahan tidak berhasil, saya kembali ke kode sebelumnya, dua kali (dua revisi kembali) berpikir itu akan menghilangkan kesalahan. Melakukan hal itu tidak mengubah apa pun. Saya mengejar ekor saya sepanjang hari kemarin, dan sebagian pagi ini tanpa menyelesaikan masalah.

Saya merasa frustrasi dan memeriksa kode ke laptop pagi ini. Jalankan seluruh test suite (sekitar 180 tes), tidak ada kesalahan. Jadi kesalahan tidak pernah ada dalam kode atau tes. Kembali ke kotak dev saya dan mem-boot ulang untuk menghapus semua yang ada di memori yang mungkin menyebabkan masalah. Tidak ada perubahan, kesalahan yang sama pada dua tes yang sama. Jadi saya menghapus direktori dari mesin saya, dan memeriksanya kembali. Voila! Tidak ada kesalahan

Tidak tahu apa yang menyebabkannya, atau bagaimana cara memperbaikinya, tetapi menghapus direktori kerja dan memeriksanya tetap apa pun itu.

Semoga ini bisa membantu seseorang.


1
Terima kasih kawan, aku sudah gila tentang ini. Saya reboot PC saya dan hanya itu
yngrdyn

Dalam kasus saya, saya hanya menjalankan kembali perintah dan menyelesaikan masalah ini. Saya memiliki reload panas untuk unit-tes dan setiap kali gagal. Saya harus berhenti dan menjalankan perintah lagi.
jignesh

4

Jangan gunakan done, biarkan saja fungsi panggilan kosong.


Tolong perbaiki saya jika saya salah tetapi karena saya mengerti itu hanya membuat test suite selesai sebelum tes dan dan pesan kesalahan dibuang sebagai gantinya. Yang berarti bahwa setiap pernyataan yang gagal tidak akan merusak tes karena paket tes selesai sebelum pernyataan dijalankan. Mungkin juga berarti (saya telah melihat perilaku serupa) bahwa tes lain menunjukkan kesalahan yang dibuat oleh tes ini. Akhirnya itu berarti bahwa semuanya terlihat baik-baik saja untuk memulainya tetapi karena jumlah tes tumbuh masalah akan muncul sebentar-sebentar.
LosManos

3

Anda juga mendapatkan kesalahan ini saat mengharapkan sesuatu di beforeAllfungsi!

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

    beforeAll(function () {
        ...

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

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

    }
}

2

Dalam kasus saya, kesalahan ini disebabkan oleh penggunaan yang tidak benar dari "fixture.detectChanges ()" Tampaknya metode ini adalah pendengar acara (async) yang hanya akan merespons panggilan balik ketika perubahan terdeteksi. Jika tidak ada perubahan yang terdeteksi, itu tidak akan memanggil balik, menghasilkan kesalahan waktu habis. Semoga ini membantu :)


2

Bekerja setelah menghapus scopereferensi dan argumen fungsi:

"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

Seperti dicatat oleh @mastablasta, tetapi juga untuk menambahkan bahwa jika Anda memanggil argumen 'selesai' atau lebih tepatnya nama itu selesai Anda hanya memanggil panggilan balik selesai () dalam pengujian Anda ketika sudah selesai.

// 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

jasmine.DEFAULT_TIMEOUT_INTERVAL = 100000;

Menjaga ini di blok memecahkan masalah saya.

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

0

Apa yang saya lakukan adalah: Menambahkan / Memperbarui kode berikut:

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

3
Tolong jelaskan mengapa kode ini berfungsi, bukan hanya mempostingnya tanpa penjelasan.
Kobe

Jadi pada dasarnya ketika Anda menjalankan tes dan butuh waktu lebih lama dari yang diharapkan, itu gagal karena batas waktu default terpenuhi dan skrip tidak bergerak maju dalam eksekusi. Ini bisa terjadi karena beberapa kondisi tidak terpenuhi (Misalnya visibilitas, pemuatan halaman). Sekarang jika batas waktu default Anda seperti skrip 1000ms >> akan sering gagal karena hanya satu detik dan mungkin ada beberapa faktor yang menambah kegagalan skrip Anda. Namun, meningkatkan interval waktu habis Anda dapat membuat browser / driver menunggu lebih lama untuk memenuhi kondisi.
Zeeshan

2
Oke, sekarang kata itu ke posting Anda; Anda harus mencoba untuk menghindari hanya menjawab dengan kode tanpa penjelasan :)
Kobe

0

Dari pada

beforeEach(() => {..

menggunakan

beforeEach(fakeAsync(() => {..

0

Sepertinya tes sedang menunggu panggilan balik yang tidak pernah datang. Kemungkinan karena tes tidak dijalankan dengan perilaku asinkron.

Pertama, lihat apakah hanya menggunakan fakeAsync dalam skenario "it" Anda:

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

Anda juga dapat menggunakan flush()untuk menunggu antrian microTask selesai atau tick()menunggu sejumlah waktu tertentu.


-2

Jika Anda memiliki argumen ( done) dalam itfungsi, cobalah untuk menghapusnya dan itu juga panggilan dalam fungsi itu sendiri:

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
Tanpa penjelasan mengapa jawaban ini tidak berguna.
Gary

2
jawaban ini memecahkan masalah saya ... pengujian sudut adalah mimpi buruk!
Benjamin Caure
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.