Weboldal keresés

javascript - Aszinkron kód tesztelése Jest-ben: a done() nem hívódik meg a vártnak megfelelően


Itt egy Jest (v20.0.4) verzióban írt tesztcsomag található.

Az első 3 teszt várható viselkedés, a kérdésem a Teszt4-hez kapcsolódik.

test('Test1: the list should contain 7', () => {
  const data = [1, 2, 7, 9];
  expect(data).toContain(7);
});
// > Passes as expected
test('Test2: the list should contain 7', () => {
  const data = [1, 2, 7, 9];
  expect(data).toContain(8);
});
// > Fails as expected; Expected array: [1, 2, 7, 9] To contain value: 8
test('Test3: the list should contain 7', (done) => {
  function callback(data) {
    expect(data).toContain(7);
    done();
  }
  setTimeout(() => {
    callback([1, 2, 7, 9]);
  }, 500);
});
// > Passes as expected
test('Test4: the list should contain 7', (done) => {
  function callback(data) {
    expect(data).toContain(8);
    done();
  }
  setTimeout(() => {
    callback([1, 2, 7, 9]);
  }, 500);
});
// > Fails with Error "Timeout - Async callback was not invoked within timeout specified"

Itt van a kérdésem:

A Test4-ben a done() közvetlenül az expect utasítás után kerül meghívásra.
Tehát, még ha az expect utasítás nem is teljesül, azt gondoltam, hogy hibával kellene végződnie, hasonlóan a Test2-höz: (Várt tömb: [1, 2, 7, 9] hogy tartalmazza az értéket: 8)

Azonban időtúllépési hibával sikertelen, ahogyan fent látható, ami arra utal, hogy a done() soha nincs meghívva.

Miért? Nem értem!

Tudna valaki végigvezetni ezen a viselkedésen?

Átbogarásztam a dokumentumokat, de nem találtam semmit ezzel kapcsolatban.

Válasz #1

A kódodban a expect hívás hibát dob, és a done soha nem érhető el. Emiatt a Jest vár, amíg időtúllépés következik be, és kiadja a kellemetlen, zavaros hibát, amit észrevettél.

A megoldás az, hogy elkapjuk a dobást, és meghívjuk a done(error)-t, hogy jelezzük a Jest futtatónak, hogy a teszt megbukott.

test('Test4: the list should contain 7', done => {
  function callback(data) {
    try {
      expect(data).toContain(8);
      done();
    }
    catch (err) {
      done(err);
    }
  }
  setTimeout(() => {
    callback([1, 2, 7, 9]);
  }, 500);
});

Ennek a futtatása adja a kívánt eredményt:

Error: expect(received).toContain(expected) // indexOf

Expected value: 8
Received array: [1, 2, 7, 9]

A dokumentációból:

Ha a expect állítás sikertelen, hibát dob, és a done() nem hívódik meg. Ha látni szeretnénk a teszt naplóban, hogy miért sikertelen, a expect-et egy try blokkba kell csomagolnunk, és a hibát a catch blokkban át kell adni a done-nak. Ellenkező esetben egy átláthatatlan időtúllépés hibát kapunk, ami nem mutatja, hogy milyen értéket kapott a expect(data).

Válasz #2

Rájöttem, hogy a setTimeout és a Jest nem úgy működik, ahogy az ember gondolná. De van egy jó módja annak, hogyan lehet vele megbirkózni:

  • A tesztje kezdete előtt megadhatja a Jestnek, hogy hamis időzítőket használjon: jest.useFakeTimers();

  • Amikor szükséged van arra, hogy a visszahívás végrehajtódjon, akkor a jest.runAllTimers(); segítségével indíthatod el.

https://jestjs.io/docs/en/timer-mocks.html