Wywołanie zwrotne asynchroniczne nie zostało wywołane w limicie czasu 5000 ms określonym w parametrze jest.setTimeout

238

Używam lalkarza i żartuję, żeby przeprowadzić testy frontonu.

Moje testy wyglądają następująco:

describe("Profile Tab Exists and Clickable: /settings/user", () => {
    test(`Assert that you can click the profile tab`, async () => {
      await page.waitForSelector(PROFILE.TAB);
      await page.click(PROFILE.TAB);
    }, 30000);
});

Czasami, gdy uruchamiam testy, wszystko działa zgodnie z oczekiwaniami. Innym razem pojawia się błąd:

Timeout - Async callback was not invoked within the 5000ms timeout specified by jest.setTimeout.

      at node_modules/jest-jasmine2/build/queue_runner.js:68:21
      at Timeout.callback [as _onTimeout] (node_modules/jsdom/lib/jsdom/browser/Window.js:633:19)

To dziwne, ponieważ:

  1. Podałem limit czasu na 30000

  2. To, czy dostaję ten błąd, jest pozornie bardzo przypadkowe

Czy ktoś może zgadnąć, dlaczego tak się dzieje?

Asool
źródło
Która linia się kończy?
Lloyd
@Asool Czy możesz zapewnić repozytorium GitHub? Dostarczenie rozwiązania będzie dla nas łatwiejsze i szybsze. :)
Shishir Anshuman
@Asool, wszelkie opinie na temat odpowiedzi, którą opublikowałem
Tarun Lalwani,
1
może być tak, że test faktycznie nie powiedzie się dla 30000ms, ale błąd z jest po prostu nie zawiera przekazanej wartości? co oznacza, że ​​jeśli przekroczysz limit czasu 0ms, to błąd się zmienia?
Nirit Levi
Widziałem ten błąd podczas debugowania moich testów. Zatrzymanie się w punkcie przerwania spowodowało otrzymanie tego błędu
Neets

Odpowiedzi:

259

Limit czasu określony w tym miejscu musi być krótszy niż domyślny limit czasu.

Domyślny limit czasu to, 5000a ramka domyślnie jest jasminew przypadku jest. Możesz określić limit czasu w teście, dodając

jest.setTimeout(30000);

Ale byłoby to specyficzne dla testu. Lub możesz skonfigurować plik konfiguracyjny dla frameworka.

https://facebook.github.io/jest/docs/en/configuration.html#setuptestframeworkscriptfile-string

// jest.config.js
module.exports = {
  // setupTestFrameworkScriptFile has been deprecated in
  // favor of setupFilesAfterEnv in jest 24
  setupFilesAfterEnv: ['./jest.setup.js']
}

// jest.setup.js
jest.setTimeout(30000)

Zobacz także ten wątek

https://github.com/facebook/jest/issues/5055

https://github.com/facebook/jest/issues/652

Błąd pisowni PS setupFilesAfterEnv(tj. setupFileAfterEnv) Spowoduje także zgłoszenie tego samego błędu.

Tarun Lalwani
źródło
2
Dziękujemy za odpowiedź na pytanie, którego nie mogłem łatwo znaleźć w dokumentacji Jest.
HartleySan
21
Ponieważ pomogło mi to, warto zauważyć, że setupTestFrameworkScriptFilezostało zastąpione setupFilesAfterEnv, więc staje sięsetupFilesAfterEnv: ["./jest.setup.js"]
Maxim Geerinck
1
Znalazłem też, że jest.setTimeout(10000)można go dodać do pojedynczego testu przypadku krawędzi, więc cała konfiguracja nie musiała się zmieniać :)
James
Powinienem coś przeoczyć, ale jeśli dodać jest.setTimeout(30000);w jest.config.jsotrzymuję „ReferenceError: jest nie jest zdefiniowana”. Próbowałem dodać, const jest = require("jest");ale potem pojawia się komunikat „TypeError: jest.setTimeout nie jest funkcją”.
Jean Paul
Ups, czytam za szybko: setupFilesAfterEnvargument w jest.config.jspowinien wskazywać na inny plik, w którym umieściliśmy jest.setTimeout(30000)opcję. Fajnie, że możemy to skonfigurować, ale wydaje mi się to trochę skomplikowane.
Jean Paul
64

Powinien wywoływać, async/awaitkiedy jest asynchroniczny z testu.

describe("Profile Tab Exists and Clickable: /settings/user", () => {
    test(`Assert that you can click the profile tab`, async (done) => {
        await page.waitForSelector(PROFILE.TAB);
        await page.click(PROFILE.TAB);
        done();
    }, 30000);
});
kod Schrodingera
źródło
24
Dlaczego powinniśmy mieć donefunkcję asynchroniczną? Czy nie zwracamy po prostu Obietnicy czy niezdefiniowanej?
Charlie Schliesser,
2
Nie, to nie jest poprawne. Nie musisz wywoływać polecenia done (), ponieważ czekasz na obietnice lub możesz po prostu wrócić page.click. done () jest używane, przynajmniej w moim przypadku, głównie do testowania z wywołaniami zwrotnymi.
Justin
2
Dzięki chłopaki, usunąłem doneoddzwonienie, które nie jest potrzebne.
kod Schrodingera
26
czy to nie jest ten sam kod, co w pierwotnym pytaniu?
Joe
1
Obecność parametru ( donew tym przypadku nazwanego ) w wywołaniu zwrotnym powoduje, że Jest czeka na wywołanie tego parametru. Jego obecność jest znacząca, nawet jeśli nie jest używana.
vaughan
54

Odpowiedź na to pytanie zmieniła się w miarę ewolucji Jest. Aktualna odpowiedź (marzec 2019 r.):

  1. Możesz zastąpić limit czasu dowolnego testu, dodając trzeci parametr do parametru it. to znaczy.it('runs slow', () => {...}, 9999)

  2. Możesz zmienić domyślną za pomocą jest.setTimeout. Aby to zrobić:

 // config
   "setupFilesAfterEnv": [  // NOT setupFiles
     "./src/jest/defaultTimeout.js"
   ],

i

// File: src/jest/defaultTimeout.js
/* global jest */
jest.setTimeout(1000)
  1. Jak zauważyli inni i nie są bezpośrednio z tym związane, donepodejście asynchroniczne / oczekiwanie nie jest konieczne.
ndp
źródło
5
jest to bardziej nowoczesna wersja
jonashdown
23

Chciałbym dodać (to trochę za długo na komentarz), że nawet po przekroczeniu limitu 3000moich testów czasami (losowo) zawodzi

Timeout - Async callback was not invoked within the 5000ms timeout specified by jest.setTimeout.

Dzięki świetnej odpowiedzi @ Tarun uważam, że najkrótszym sposobem na naprawienie wielu testów jest:

describe('puppeteer tests', () => {
  beforeEach(() => {
    jest.setTimeout(10000);
  });

  test('best jest test fest', async () => {
    // blah
  });
});
rzymski
źródło
9
Nie musisz dzwonić do jest.setTimeout()środka beforeEach, wystarczy raz zadzwonić do wszystkich testów.
Marcos Pereira
19

Jest to stosunkowo nowa aktualizacja, ale jest o wiele prostsza. Jeśli używasz wersji 24.9.0 lub nowszej, możesz po prostu dodać testTimeoutdo swojej konfiguracji:

// in jest.config.js
module.exports = {
  testTimeout: 30000
}
e-shfiyut
źródło
17

Pamiętaj, aby wywoływać done();wywołania zwrotne, aby nie przejść testu.

beforeAll((done /* call it or remove it*/) => {
  done(); // calling it
});

Dotyczy wszystkich innych funkcji, które mają wywołanie zwrotne done ().

ZenVentzi
źródło
1
Dobrze wspomniany, @ZenVentzi. Dzięki :)!
ivanleoncz
11

W przypadku wersji 24.9+ można również ustawić limit czasu z wiersza poleceń, dodając --testTimeout

Oto fragment jego dokumentów

--testTimeout=<number>
Default timeout of a test in milliseconds. Default value: 5000.
Pan 14
źródło
3

Niedawno natknąłem się na ten problem z innego powodu: uruchamiałem niektóre testy synchronicznie jest -i, i to po prostu limit czasu. Z jakiegokolwiek powodu uruchomienie tych samych testów przy użyciu jest --runInBand(chociaż -ima to być alias) nie kończy się.

Może to komuś pomoże ¯\_(:/)_/¯

Jona
źródło
1

Problem awaitprzekroczenia limitu czasu występuje, gdy sieć jest wolna lub wykonywanych jest wiele połączeń sieciowych , scenariusze te przekraczają domyślny limit czasu, tj. 5000 ms. Aby uniknąć błędu limitu czasu, po prostu zwiększ limit czasu globali, które obsługują limit czasu. Lista globali i ich podpis można znaleźć tutaj .
Dla Jest 24.9

Neeraj Sewani
źródło
1
// in jest.setup.js
jest.setTimeout(30000)

Jeśli jest Jest <= 23:

// in jest.config.js
module.exports = {
  setupTestFrameworkScriptFile: './jest.setup.js'
}

Jeśli na Jest> 23:

// in jest.config.js
module.exports = {
  setupFilesAfterEnv: ['./jest.setup.js']
}
alexrogers
źródło
0

W przypadku, gdy ktoś nie naprawi problemu z powyższymi metodami, naprawiłem mój, otaczając funkcję asynchroniczną funkcją strzałki. Jak w:

describe("Profile Tab Exists and Clickable: /settings/user", () => {
    test(`Assert that you can click the profile tab`, (() => {
      async () => {
        await page.waitForSelector(PROFILE.TAB)
        await page.click(PROFILE.TAB)
      }
    })(), 30000);
});
suga_e
źródło
1
Wydaje mi się, że umieszczenie funkcji strzałki wokół asynchronii nie powie testowi, aby czekał na zakończenie testu, więc chociaż nie możesz teraz otrzymać błędu, test będzie przebiegał poza jego wątkiem i a) cały pakiet testowy może zostać zakończony przed wykonaniem tego testu, nie testując tego kodu oraz b) przyszłe błędy w tym teście mogą pojawić się podczas innego testu w pakiecie, powodując, że testy będą niestabilne i trudne do utrzymania.
Mary Shaw,
0

W moim przypadku ten błąd zaczął pojawiać się losowo i nie znikał nawet po ustawieniu limitu czasu na 30000. Po prostu zakończenie procesu w terminalu i ponowne uruchomienie testów rozwiązało problem. Usunąłem również limit czasu i testy wciąż mija.

Saurabh Misra
źródło
-2

W Węźle ... to, co widzę, że ludzie zrobili jako przykład, jest poniżej fakeEventEmitter

import { EventEmitter } from 'events';
describe('your case', () => {
 let fakeEventEmitter: EventEmitter;
 beforeEach(async () => {
   fakeEventEmitter = new EventEmitter();
   (fakeEventEmitter as any).pid = 123;
 }),
 it('should do something you want to do', done => {
            anAsynchronouseFunction(testOptions, context).subscribe({
                complete: () => {
                    expect(something).toBeTruthy();
                    done();
                }
            });
            fakeEventEmitter.emit('exit', 0);
        });
});
WickStargazer
źródło