O retorno de chamada assíncrona não foi chamado dentro do tempo limite de 5000ms especificado por jest.setTimeout

238

Estou usando marionetistas e gracejos para executar alguns testes de front-end.

Meus testes têm a seguinte aparência:

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

Às vezes, quando executo os testes, tudo funciona como esperado. Outras vezes, recebo um erro:

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)

Isso é estranho porque:

  1. Especifiquei o tempo limite para 30000

  2. Se eu recebo ou não esse erro é aparentemente muito aleatório

Alguém pode adivinhar por que isso está acontecendo?

Asool
fonte
Qual linha está atingindo o tempo limite?
Lloyd
@Asool Você poderia fornecer um repositório do GitHub? Será mais fácil e rápido fornecer uma solução. :)
Shishir Anshuman /
@Asool, qualquer comentário sobre a resposta que eu postei
Tarun Lalwani
1
será que o teste realmente falha nos 30000ms, mas o erro do gracejo simplesmente não inclui o valor que você passou? ou seja, se você colocar 0ms no tempo limite, o erro de brincadeira muda?
Niev Levi
Vi esse erro ao depurar meus testes. Parando em um ponto de interrupção causada obter este erro
NEETS

Respostas:

259

Portanto, o tempo limite especificado aqui precisa ser menor que o tempo limite padrão.

O tempo limite padrão é 5000e a estrutura por padrão é jasmineno caso de jest. Você pode especificar o tempo limite dentro do teste adicionando

jest.setTimeout(30000);

Mas isso seria específico para o teste. Ou você pode configurar o arquivo de configuração para a estrutura.

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)

Veja também este tópico

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

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

O erro de ortografia PS setupFilesAfterEnv(ou seja setupFileAfterEnv) também gera o mesmo erro.

Tarun Lalwani
fonte
2
Obrigado por responder a uma pergunta que não consegui encontrar facilmente através da documentação do Jest.
HartleySan
21
Como isso me ajudou, talvez valha a pena notar que o setupTestFrameworkScriptFileitem foi substituído por setupFilesAfterEnv, então ele se tornasetupFilesAfterEnv: ["./jest.setup.js"]
Maxim Geerinck
1
Eu encontrei também que jest.setTimeout(10000)poderiam ser adicionados a um único teste para um caso extremo de modo toda a configuração não tinha necessidade de mudança :)
James
I deve perder algo, mas se eu adicionar jest.setTimeout(30000);em jest.config.jsI get "ReferenceError: jest não está definido". Tentei adicionar, const jest = require("jest");mas recebo "TypeError: jest.setTimeout não é uma função".
Jean Paul
Opa, eu li rápido demais: o setupFilesAfterEnvargumento em jest.config.jsapontará para outro arquivo em que colocamos a jest.setTimeout(30000)opção. É bom podermos configurar isso, mas me parece um pouco complicado.
Jean Paul
64

Ele deve chamar async/awaitquando estiver assíncrono do teste.

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);
});
código de schrodinger
fonte
24
Por que deveríamos ter doneuma função assíncrona? Nós simplesmente não devolvemos Promessa ou indefinidos?
Charlie Schliesser
2
Não, isso não está correto. Você não precisa ligar para done (), pois aguarda suas promessas ou pode simplesmente retornar page.click. done () é usado, pelo menos no meu caso, principalmente para testar com retornos de chamada.
30719 Justin
2
Obrigado pessoal, removi o doneretorno de chamada que não é necessário.
código de schrodinger
26
não é o mesmo código da pergunta original agora?
21419 Joe
1
A presença de um parâmetro (nomeado doneneste caso) no retorno de chamada faz com que o Jest aguarde até que esse parâmetro seja chamado. Sua presença é significativa, mesmo que não seja usada.
vaughan
54

A resposta a esta pergunta mudou conforme o Jest evoluiu. Resposta atual (março de 2019):

  1. Você pode substituir o tempo limite de qualquer teste individual adicionando um terceiro parâmetro ao it. ieit('runs slow', () => {...}, 9999)

  2. Você pode alterar o padrão usando jest.setTimeout. Para fazer isso:

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

e

// File: src/jest/defaultTimeout.js
/* global jest */
jest.setTimeout(1000)
  1. Como outros observaram, e não diretamente relacionados a isso, donenão é necessário com a abordagem assíncrona / aguardada.
ndp
fonte
5
esta é a versão mais moderna
jonashdown
23

Gostaria de acrescentar (isso é um pouco longo para um comentário) que, mesmo com o tempo limite dos 3000meus testes, algumas vezes (aleatoriamente) falhava com

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

Graças à ótima resposta de @ Tarun, acho que a maneira mais curta de corrigir muitos testes é:

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

  test('best jest test fest', async () => {
    // blah
  });
});
romano
fonte
9
Você não precisa ligar para jest.setTimeout()dentro beforeEach, chamá-lo uma vez é suficiente para todos os testes.
Marcos Pereira
19

Esta é uma atualização relativamente nova, mas é muito mais direta. Se você estiver usando o jest 24.9.0 ou superior, basta adicionar testTimeoutà sua configuração:

// in jest.config.js
module.exports = {
  testTimeout: 30000
}
e-shfiyut
fonte
17

Certifique-se de invocar done();retornos de chamada ou isso simplesmente não passará no teste.

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

Aplica-se a todas as outras funções que possuem um retorno de chamada done ().

ZenVentzi
fonte
1
Bem mencionado, @ZenVentzi. Obrigado :)!
ivanleoncz
11

Para o jest 24.9+, você também pode definir o tempo limite na linha de comando adicionando --testTimeout

Aqui está um trecho de seus documentos

--testTimeout=<number>
Default timeout of a test in milliseconds. Default value: 5000.
Mr. 14
fonte
3

Recentemente, deparei com esse problema por um motivo diferente: estava executando alguns testes de forma síncrona usando jest -i, e o tempo limite acabaria. Qualquer que seja o raciocínio, a execução dos mesmos testes usando jest --runInBand(mesmo que -iseja um alias) não atinge o tempo limite.

Talvez isso ajude alguém ¯\_(:/)_/¯

Jona
fonte
1

O problema do tempo limite ocorre quando a rede é lenta ou são feitas várias chamadas de rede await, esses cenários excedem o tempo limite padrão, ou seja, 5000 ms. Para evitar o erro de tempo limite, aumente o tempo limite das globais que suportam um tempo limite. Uma lista de globais e sua assinatura pode ser encontrada aqui .
For Jest 24.9

Neeraj Sewani
fonte
1
// in jest.setup.js
jest.setTimeout(30000)

Se em Jest <= 23:

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

Se estiver em Jest> 23:

// in jest.config.js
module.exports = {
  setupFilesAfterEnv: ['./jest.setup.js']
}
alexrogers
fonte
0

Caso alguém não conserte o problema, use os métodos acima, consertei o meu envolvendo a função assíncrona por uma função de seta. Como em:

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
fonte
1
Parece-me que, ao colocar a função de seta em torno do assíncrono, o teste não será aguardado até a conclusão do teste; portanto, embora você não tenha um erro agora, você terá um teste em execução fora do encadeamento e a) o todo o conjunto de testes pode ser concluído antes que o teste seja concluído, não testando esse código eb) erros futuros dentro desse teste podem aparecer durante um teste diferente no conjunto, tornando seus testes difíceis e difíceis de manter.
Mary Shaw
0

No meu caso, esse erro começou a aparecer aleatoriamente e não desapareceu mesmo depois de definir um tempo limite de 30000. Simplesmente encerrar o processo no terminal e executar novamente os testes resolveu o problema para mim. Também removi o tempo limite e os testes ainda estão passando novamente.

Saurabh Misra
fonte
-2

No nó ... o que vejo as pessoas fizeram como exemplo está abaixo, usando 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
fonte