jasmine: Async callback ไม่ได้ถูกเรียกใช้ภายในระยะเวลาที่กำหนดโดย 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
การประมวลผลเหตุการณ์มักจะทำในรอบย่อย ลองเพิ่มขอบเขต $ ใช้ () กับการทดสอบของคุณแทนที่จะใช้รูปแบบการทดสอบ async ของจัสมิน
Eitan Peer

สิ่งนี้ใช้ไม่ได้ ฉันเพิ่มขอบเขต $ Apply (); หลังจากโทรไปยังการแจ้งเตือนการแจ้งเตือนช่องสัญญาณลบข้อความ (1, 4) แต่ฉันได้รับข้อผิดพลาดเดียวกัน ...
Mdb

ฉันได้รับข้อผิดพลาดเดียวกันเมื่อการทดสอบ async ใช้เวลานานกว่าที่Jestคาด - พบได้บ่อยมากขณะทำการดีบักและใช้เวลาสักครู่เพื่อตรวจสอบตัวแปร
Dan Dascalescu

ลองใช้การหมดเวลาที่น้อยลงแทน ฉันพบข้อผิดพลาดนี้ในขณะที่ใช้หมดเวลา = 5,000 ฉันแทนที่มันด้วย 2000 และใช้งานได้สำหรับฉัน!
Marina Riaz

1
ออกจากที่นี่เพื่อช่วยคนในรองเท้าของฉัน ฉันพบข้อผิดพลาดนี้ขณะทำการทดสอบภายในคอนเทนเนอร์ของนักเทียบท่า การทดสอบบางครั้งจะผ่านโดยไม่มีปัญหาใด ๆ แต่บางครั้งก็ล้มเหลว ฉันคิดว่ามันเป็นสภาพการแข่งขันบางอย่าง แต่ไม่สามารถหาสาเหตุได้ ฉันรู้ว่าฉันมีafterEachขั้นตอนที่จะล้างฐานข้อมูล (โดยใช้deleteManyวิธีการ) การเพิ่มjest.setTimeout(30000);ในbeforeAllวิธีดูเหมือนจะแก้ไขสิ่งนี้สำหรับฉัน - ฉันเดาเนื่องจากการลบฐานข้อมูลเป็นการโทรผ่านเครือข่าย (ภายในเงื่อนไข) บางครั้งใช้เวลานานกว่า 3 วินาทีและการขว้าง
nkhil

คำตอบ:


231

การมีข้อโต้แย้งในitฟังก์ชั่นของคุณ( doneในรหัสด้านล่าง) จะทำให้จัสมินพยายามโทร async

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

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

มันไม่ได้สร้างความแตกต่างในสิ่งที่doneชื่ออาร์กิวเมนต์การดำรงอยู่ของมันคือสิ่งที่สำคัญ ฉันพบปัญหานี้จากการคัดลอก / พาสต้ามากเกินไป

เอกสารสนับสนุน Asynchronous ของจัสมินทราบว่าอาร์กิวเมนต์ (ชื่อdoneด้านบน) คือการเรียกกลับที่สามารถเรียกให้จัสมินทราบได้เมื่อฟังก์ชันอะซิงโครนัสเสร็จสมบูรณ์ หากคุณไม่เคยเรียกมันว่าดอกมะลิจะไม่มีทางรู้ว่าการทดสอบของคุณเสร็จสิ้นและจะหมดเวลาในที่สุด


3
เช่นเดียวกับ args ในการอธิบาย (ในเชิงมุมคุณต้องเรียก inject เพื่ออธิบายให้ทำ)
Narretz

@MartinBliss มีเอกสารฉันเพิ่งแนะนำให้แก้ไขเพื่ออ้างถึงเอกสาร: stackoverflow.com/suggested-edits/2434606
Vincent

39
หมายเหตุสำหรับชาว Google สุ่มที่เจอคำถามนี้ในอนาคต: หากคุณใช้ Protractor และพบปัญหานี้คำตอบนี้ไม่ใช่สิ่งที่คุณต้องการ - Protractor จะโทรกลับด้วยตนเอง
Vincent

มันคงปัญหาของฉันและมันก็เกิดจาก cuplrit เดียวกัน "คัดลอก / พาสต้า"
Shaikh

1
@Vincent ปัญหาผู้ใช้ Protractor เกิดอะไรขึ้นถ้าเกิดข้อผิดพลาดนี้
Bruno Bieri

57

แม้สำหรับการทดสอบ async มีการหมดเวลาใช้งานในกรณีนี้คุณสามารถแก้ไขข้อผิดพลาดนี้ได้โดยเพิ่มค่าสำหรับการหมดเวลา จำกัด เพื่อประเมินการโทรกลับ async Jasmine

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 มิลลิวินาที ตัวอย่างนี้จะทำให้สั้นลงหกเท่า
Waltari

คุณขวาฉันเพียงแค่ใส่หมายเลขสุ่มในตัวอย่างนี้ขอบคุณ :)
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-jasmineเพื่อตั้งค่าช่วงหมดเวลาเริ่มต้นทั่วโลก

เพิ่มการกำหนดค่านี้ใน karma.conf.js

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

5

ข้อผิดพลาดนี้เริ่มต้นจากสีน้ำเงินสำหรับฉันในการทดสอบที่ได้ผลเสมอ ฉันไม่พบข้อเสนอแนะใด ๆ ที่ช่วยจนกระทั่งฉันสังเกตเห็นว่า Macbook ของฉันทำงานช้า ฉันสังเกตว่าซีพียูถูกตรึงด้วยกระบวนการอื่นซึ่งฉันฆ่า ข้อผิดพลาด async ของ Jasmine หายไปและการทดสอบของฉันกลับมาใช้งานได้อีกครั้ง

อย่าถามฉันทำไมฉันไม่รู้ แต่ในสถานการณ์ของฉันมันดูเหมือนจะขาดทรัพยากรระบบที่ผิด


5
อาจเป็นไปได้เมื่อ CPU ของคุณว่างภารกิจจะเสร็จสิ้นก่อนที่จะหมดเวลาเริ่มต้น เมื่อ CPU ไม่ว่างงานที่คุณกำลังทดสอบใช้เวลาในการดำเนินการนานเกินไป
เชน

5

นี่เป็นข้อสังเกตมากกว่าคำตอบ แต่อาจช่วยคนอื่นที่รู้สึกหงุดหงิดเหมือนฉัน

ฉันได้รับข้อผิดพลาดจากการทดสอบสองครั้งในชุดของฉัน ฉันคิดว่าฉันทำแบบทดสอบหักด้วยการปรับโครงสร้างที่ฉันทำอยู่ดังนั้นหลังจากการสำรองการเปลี่ยนแปลงไม่ได้ผลฉันจึงเปลี่ยนรหัสก่อนหน้าเป็นสองเท่า (แก้ไขสองครั้งหลัง) คิดว่าจะกำจัดข้อผิดพลาดได้ การทำเช่นนั้นไม่ได้เปลี่ยนแปลงอะไรเลย ฉันไล่ตามหางของฉันทั้งวันเมื่อวานและเป็นส่วนหนึ่งของเช้านี้โดยไม่ต้องแก้ไขปัญหา

ฉันหงุดหงิดและลองดูโค้ดบนแล็ปท็อปเมื่อเช้านี้ เรียกใช้ชุดทดสอบทั้งหมด (ประมาณ 180 การทดสอบ) ไม่มีข้อผิดพลาด ดังนั้นข้อผิดพลาดไม่เคยอยู่ในรหัสหรือการทดสอบ กลับไปที่กล่อง dev ของฉันและรีบูตมันเพื่อล้างอะไรในหน่วยความจำที่อาจทำให้เกิดปัญหา ไม่มีการเปลี่ยนแปลงข้อผิดพลาดเดียวกันในการทดสอบทั้งสองแบบเดียวกัน ดังนั้นฉันจึงลบไดเรกทอรีออกจากเครื่องของฉันและตรวจสอบมันกลับออกมา Voila! ไม่มีข้อผิดพลาด

ไม่ทราบว่าเกิดจากสาเหตุใดหรือแก้ไขอย่างไร แต่การลบไดเรกทอรีทำงานและตรวจสอบกลับไปแก้ไขสิ่งที่มันเป็น

หวังว่านี่จะช่วยใครซักคน


1
ขอบคุณชายฉันบ้าไปแล้ว ฉันรีบูตเครื่อง PC และนั่นก็เป็นเช่นนั้น
yngrdyn

ในกรณีของฉันฉันเพิ่งรันคำสั่งอีกครั้งและมันแก้ไขปัญหานี้ได้ ฉันมีการรีโหลดร้อนสำหรับการทดสอบหน่วยและทุกครั้งที่มันล้มเหลว ฉันต้องหยุดและเรียกใช้คำสั่งอีกครั้ง
jignesh

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 แต่ยังต้องเพิ่มว่าถ้าคุณเรียกอาร์กิวเมนต์ 'เสร็จสิ้น' หรือแทนที่จะตั้งชื่อให้สมบูรณ์คุณเพียงแค่โทรกลับเสร็จสมบูรณ์ () ในการทดสอบของคุณเมื่อเสร็จสิ้น

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

การเก็บสิ่งนี้ไว้ในบล็อกช่วยแก้ไขปัญหาของฉัน

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

0

สิ่งที่ฉันทำคือ: เพิ่ม / อัปเดตรหัสต่อไปนี้:

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

3
โปรดอธิบายว่าเพราะเหตุใดรหัสนี้จึงใช้งานได้แทนที่จะโพสต์โดยไม่มีคำอธิบาย
Kobe

ดังนั้นโดยทั่วไปเมื่อคุณทำการทดสอบและใช้เวลานานกว่าที่คาดไว้มันจะล้มเหลวเนื่องจากพบการหมดเวลาเริ่มต้นและสคริปต์ไม่ได้เลื่อนไปข้างหน้าในการดำเนินการ สิ่งนี้อาจเกิดขึ้นเนื่องจากเงื่อนไขบางประการไม่เป็นไปตาม (เช่นการมองเห็นการโหลดหน้าเว็บ) ตอนนี้หากการหมดเวลาเริ่มต้นของคุณเป็นเหมือนสคริปต์ 1,000ms >> จะล้มเหลวบ่อยครั้งเนื่องจากเป็นเพียงหนึ่งวินาทีและอาจมีหลายปัจจัยที่ทำให้สคริปต์ของคุณล้มเหลว อย่างไรก็ตามการเพิ่มช่วงหมดเวลาของคุณสามารถทำให้เบราว์เซอร์ / ไดรเวอร์รออีกต่อไปเพื่อให้ตรงตามเงื่อนไข
Zeeshan

2
ตกลงตอนนี้คำที่โพสต์ของคุณ; คุณควรพยายามหลีกเลี่ยงเพียงแค่ตอบด้วยรหัสโดยไม่มีคำอธิบาย :)
โกเบ


0

ดูเหมือนว่าการทดสอบกำลังรอการติดต่อกลับที่ไม่เคยเกิดขึ้นมาก่อน อาจเป็นเพราะการทดสอบไม่ได้ดำเนินการกับพฤติกรรมแบบอะซิงโครนัส

ก่อนอื่นดูว่าเพียงแค่ใช้ fakeAsync ในสถานการณ์ "มัน" ของคุณ:

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

คุณยังสามารถใช้flush()เพื่อรอคิว microTask ให้เสร็จหรือ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
หากไม่มีคำอธิบายว่าทำไมคำตอบนี้จึงไม่มีประโยชน์
Gary

2
คำตอบนี้แก้ปัญหาของฉันได้ ... การทดสอบเชิงมุมเป็นฝันร้าย!
Benjamin Caure
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.