> For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt.

# Scoped cleanup

Rstest supports scoped cleanup for temporary test changes. When your runtime or toolchain supports explicit resource management, you can use `using` to automatically restore resources at the end of a block.

This is useful when a test temporarily changes shared state, such as spies, environment variables, globals, or fake timers.

## `using` syntax


[Added in v0.10.3](https://github.com/web-infra-dev/rstest/releases/tag/v0.10.3)

[`rs.stubEnv()`](/api/runtime-api/rstest/utilities.md#rsstubenv), [`rs.stubGlobal()`](/api/runtime-api/rstest/utilities.md#rsstubglobal), and [`rs.useFakeTimers()`](/api/runtime-api/rstest/fake-timers.md#rsusefaketimers) return disposable resources that work with the `using` syntax.

## Spy cleanup

Mocks and spies implement `Symbol.dispose`, so a spy created with [`rs.spyOn()`](/api/runtime-api/rstest/mock-functions.md#rsspyon) is restored when the `using` block exits.

```ts title="logger.test.ts"
import { expect, rs, test } from '@rstest/core';

test('logs a warning', () => {
  {
    using warn = rs.spyOn(console, 'warn').mockImplementation(() => undefined);

    console.warn('invalid payload');
    expect(warn).toHaveBeenCalledWith('invalid payload');
  }

  // console.warn is restored here
});
```

See [Mock](/guide/basic/mock.md#using-syntax) for more spy examples.

## Environment variables

[`rs.stubEnv()`](/api/runtime-api/rstest/utilities.md#rsstubenv) returns a disposable resource. When it leaves a `using` scope, only that scoped env stub is restored.

```ts title="env.test.ts"
import { expect, rs, test } from '@rstest/core';

test('uses test env', () => {
  {
    using _env = rs.stubEnv('NODE_ENV', 'test');

    expect(process.env.NODE_ENV).toBe('test');
  }

  // NODE_ENV is restored here
});
```

Nested env stubs are restored in reverse order:

```ts
using _outer = rs.stubEnv('FEATURE_FLAG', 'on');
expect(process.env.FEATURE_FLAG).toBe('on');

{
  using _inner = rs.stubEnv('FEATURE_FLAG', 'off');
  expect(process.env.FEATURE_FLAG).toBe('off');
}

expect(process.env.FEATURE_FLAG).toBe('on');
```

You can still call [`rs.unstubAllEnvs()`](/api/runtime-api/rstest/utilities.md#rsunstuballenvs) to restore all env stubs in the current test.

## Globals

[`rs.stubGlobal()`](/api/runtime-api/rstest/utilities.md#rsstubglobal) also returns a disposable resource. This is convenient for temporarily replacing global APIs.

```ts title="global.test.ts"
import { expect, rs, test } from '@rstest/core';

test('uses a global feature flag', () => {
  {
    using _global = rs.stubGlobal('__FEATURE_ENABLED__', true);

    expect(globalThis.__FEATURE_ENABLED__).toBe(true);
  }

  // __FEATURE_ENABLED__ is restored here
});
```

You can still call [`rs.unstubAllGlobals()`](/api/runtime-api/rstest/utilities.md#rsunstuballglobals) to restore all global stubs in the current test.

## Fake timers

[`rs.useFakeTimers()`](/api/runtime-api/rstest/fake-timers.md#rsusefaketimers) returns a disposable resource that restores real timers when the block exits.

```ts title="timer.test.ts"
import { expect, rs, test } from '@rstest/core';

test('runs delayed work', () => {
  {
    using _timers = rs.useFakeTimers();

    const fn = rs.fn();
    setTimeout(fn, 1000);

    rs.advanceTimersByTime(1000);
    expect(fn).toHaveBeenCalledTimes(1);
  }

  expect(rs.isFakeTimers()).toBe(false);
});
```

## Async resources

For asynchronous resources that implement `Symbol.asyncDispose`, use `await using`. Rstest's browser provider resources support async disposal internally so provider pages, contexts, and browsers can be closed by the same explicit resource management protocol.

```ts
await using resource = createAsyncResource();

await resource.run();
// resource[Symbol.asyncDispose]() is awaited here
```

Use `using` for synchronous cleanup and `await using` when cleanup needs to await asynchronous work.
