Vetterjack
Vetterjack

Reputation: 2505

Jest cleanup after test case failed

What is a good and clean way to cleanup after a test case failed? For a lot of test cases, I first create a clean database environment, which needs to be cleaned up after a test case finishes.

test('some test', async () => {
  const { sheetService, cleanup } = await makeUniqueTestSheetService();

  // do tests with expect()

  await cleanup();
});

Problem is: If one of the expects fails, cleanup() is not invoked and thus the database environment is not cleaned up and jest complains Jest did not exit one second after the test run has completed. because the connection is not closed.

My current workaround looks like this, but it doesn't feel good and clean to push the cleanup hooks to an array which than is handled in the afterAll event.

const cleanUpHooks: (() => Promise<void>)[] = [];

afterAll(async () => {
  await Promise.all(cleanUpHooks.map(hook => hook()));
});

test('some test', async () => {
  const { sheetService, cleanup } = await makeUniqueTestSheetService();

  // do tests with expect()

  await cleanup();
});

Upvotes: 7

Views: 5401

Answers (3)

Erwan d&#39;Orgeville
Erwan d&#39;Orgeville

Reputation: 23

Building on top of rahulserver's answer, you can use create a wrapper function to avoir repeating try / finally syntax over and over:

async function withCleanup (fn, cleanup) {
  try {
    await fn();
  } finally {
    await cleanup();
  }
}

test('some test', async () => {
  const { sheetService, cleanup } = await makeUniqueTestSheetService();

  await withCleanup (async () => {
    // do tests with expect()
  });
});

You could also go one step further and wrap your setup logic as well, for example:

async function withService (fn) {
  const { sheetService, cleanup } = await makeUniqueTestSheetService();
  try {
    await fn(sheetService);
  } finally {
    await cleanup();
  }
}

test('some test', async () => {
  await withService (async (sheetService) => {
    // do tests with expect()
  });
});

Upvotes: 0

rahulserver
rahulserver

Reputation: 11205

Use try/finally block for such cases.

For example:

  it("some test case", async done => {
    try {
      expect(false).toEqual(true);
      console.log("abc");
      done();
    }finally{
      console.log("finally");
      // cleanup code below...
    }
  });

Above code would just execute the finally block (hence "finally" gets printed in console instead of "abc". Note that the catch block gives a timeout so just use finally.

This answer must be useful.

Upvotes: 8

Jayanath
Jayanath

Reputation: 67

What if you use afterEach()? it will execute after each test

test('some test', async () => {
  const { sheetService, cleanup } = await makeUniqueTestSheetService();

  // do tests with expect()

});

afterEach(async()=>{
    await cleanup();
});

Upvotes: 1

Related Questions