> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/zhcndoc/bun/llms.txt
> Use this file to discover all available pages before exploring further.

# Lifecycle Hooks

> Set up and tear down test state with lifecycle hooks

Bun's test runner provides lifecycle hooks to set up and tear down test state. These hooks are compatible with Jest.

## Available hooks

### beforeAll

Runs once before all tests in a `describe` block:

```ts theme={null}
import { describe, test, beforeAll, expect } from "bun:test";

describe("database tests", () => {
  let db;

  beforeAll(async () => {
    // Runs once before all tests
    db = await connectToDatabase();
  });

  test("query 1", () => {
    expect(db.query("SELECT 1")).toBe(1);
  });

  test("query 2", () => {
    expect(db.query("SELECT 2")).toBe(2);
  });
});
```

### beforeEach

Runs before each test:

```ts theme={null}
import { describe, test, beforeEach, expect } from "bun:test";

describe("counter tests", () => {
  let counter;

  beforeEach(() => {
    // Runs before each test
    counter = 0;
  });

  test("increment", () => {
    counter++;
    expect(counter).toBe(1);
  });

  test("increment twice", () => {
    counter++;
    counter++;
    expect(counter).toBe(2);
  });
});
```

### afterEach

Runs after each test:

```ts theme={null}
import { describe, test, afterEach } from "bun:test";

describe("cleanup tests", () => {
  afterEach(() => {
    // Clean up after each test
    cleanupTempFiles();
  });

  test("creates temp file", () => {
    createTempFile("test1.txt");
  });

  test("creates another temp file", () => {
    createTempFile("test2.txt");
  });
});
```

### afterAll

Runs once after all tests in a `describe` block:

```ts theme={null}
import { describe, test, beforeAll, afterAll } from "bun:test";

describe("server tests", () => {
  let server;

  beforeAll(async () => {
    server = await startServer();
  });

  afterAll(async () => {
    // Runs once after all tests
    await server.stop();
  });

  test("responds to requests", async () => {
    const response = await fetch(server.url);
    expect(response.status).toBe(200);
  });
});
```

## Async hooks

All hooks support async operations:

```ts theme={null}
import { beforeEach, afterEach, test } from "bun:test";

beforeEach(async () => {
  await database.connect();
  await database.seed();
});

afterEach(async () => {
  await database.clear();
  await database.disconnect();
});

test("database query", async () => {
  const result = await database.query("SELECT * FROM users");
  expect(result).toHaveLength(5);
});
```

## Hook execution order

Hooks execute in the following order:

1. `beforeAll` (outer describe)
2. `beforeAll` (inner describe)
3. `beforeEach` (outer describe)
4. `beforeEach` (inner describe)
5. **test**
6. `afterEach` (inner describe)
7. `afterEach` (outer describe)
8. `afterAll` (inner describe)
9. `afterAll` (outer describe)

Example:

```ts theme={null}
import { describe, test, beforeAll, beforeEach, afterEach, afterAll } from "bun:test";

describe("outer", () => {
  beforeAll(() => console.log("outer beforeAll"));
  beforeEach(() => console.log("outer beforeEach"));
  afterEach(() => console.log("outer afterEach"));
  afterAll(() => console.log("outer afterAll"));

  test("outer test", () => {
    console.log("outer test");
  });

  describe("inner", () => {
    beforeAll(() => console.log("inner beforeAll"));
    beforeEach(() => console.log("inner beforeEach"));
    afterEach(() => console.log("inner afterEach"));
    afterAll(() => console.log("inner afterAll"));

    test("inner test", () => {
      console.log("inner test");
    });
  });
});

// Output:
// outer beforeAll
// outer beforeEach
// outer test
// outer afterEach
// inner beforeAll
// outer beforeEach
// inner beforeEach
// inner test
// inner afterEach
// outer afterEach
// inner afterAll
// outer afterAll
```

## Scoping

Hooks are scoped to the `describe` block they're defined in:

```ts theme={null}
import { describe, test, beforeEach } from "bun:test";

beforeEach(() => {
  // Runs before all tests in file
  console.log("global beforeEach");
});

describe("suite 1", () => {
  beforeEach(() => {
    // Only runs before tests in suite 1
    console.log("suite 1 beforeEach");
  });

  test("test 1", () => {});
});

describe("suite 2", () => {
  beforeEach(() => {
    // Only runs before tests in suite 2
    console.log("suite 2 beforeEach");
  });

  test("test 2", () => {});
});
```

## Timeout

Hooks can have custom timeouts:

```ts theme={null}
import { beforeAll } from "bun:test";

beforeAll(async () => {
  // Custom timeout of 30 seconds
  await slowSetup();
}, 30000);
```

## Done callback

Hooks support the done callback pattern:

```ts theme={null}
import { beforeEach } from "bun:test";

beforeEach((done) => {
  setTimeout(() => {
    // Setup complete
    done();
  }, 100);
});
```

<Note>
  Prefer using async/await over done callbacks when possible.
</Note>

## Error handling

If a hook throws an error:

* `beforeAll`/`beforeEach`: The test is marked as failed
* `afterEach`/`afterAll`: The test result is preserved, but the error is logged

```ts theme={null}
import { beforeEach, test, expect } from "bun:test";

beforeEach(() => {
  if (!setupSuccessful()) {
    throw new Error("Setup failed");
  }
});

test("will fail if setup fails", () => {
  expect(true).toBe(true);
});
```

## Resource cleanup with using

Bun supports JavaScript's `using` keyword for automatic resource cleanup:

```ts theme={null}
import { test } from "bun:test";

test("automatic cleanup", () => {
  using server = createTestServer();
  // server.stop() called automatically when test ends
  
  const response = fetch(server.url);
  expect(response.status).toBe(200);
});
```

## Related

* [Writing Tests](/test/writing)
* [Mocks](/test/mocks)
* [Configuration](/test/configuration)
