vitest-dev/vitest · error · Error

expect.poll() must be called inside a test

Error message

expect.poll() must be called inside a test

What it means

expect.poll() wraps an unstable assertion in a retry loop and needs the current Test context (set via the chai 'vitest-test' flag) to hook into test lifecycle (onFinished, timeout). If that flag is undefined — meaning poll() was called outside any running test — it throws immediately. Common when poll is used at module top level or inside a beforeAll/beforeEach hook rather than inside the test body.

Solutions

  1. Move the expect.poll call inside an `it`/`test` callback body.
  2. If polling logic is needed in setup, use vi.waitFor or vi.waitUntil instead which do not require the test assertion context.
  3. Ensure custom assertion wrappers forward the chai context so the vitest-test flag is preserved.

Example fix

// before — poll called in beforeAll:
beforeAll(() => { await expect.poll(() => getStatus()).toBe('ready') })

// after — poll called inside the test:
it('waits', async () => { await expect.poll(() => getStatus()).toBe('ready') })
Defensive patterns

Strategy: validation

Validate before calling

// ensure you are inside a test callback before using expect.poll:
// move the call into it(...)/test(...), not beforeAll/beforeEach/module scope

Prevention

When it happens

Trigger: Calling expect.poll(fn).toBeX() outside of an `it`/`test` callback — e.g. in a beforeAll, at module scope, or in a standalone script. Also if the chai assertion context was not properly initialized with the test flag.

Common situations: Moving an assertion into a setup hook by mistake; calling expect.poll during module import; using expect.poll in a helper that is invoked outside a test boundary.

Related errors


AI-assisted analysis of vitest-dev/vitest@1fa9837ec2 (2026-08-11). Data as JSON: /api/errors/6fc9b2afe8efa1e9. Report an issue: GitHub.

Appendix: source

Thrown at packages/vitest/src/integrations/chai/poll.ts:67

    const state = getWorkerState()
    const defaults = state.config.expect?.poll ?? {}
    const {
      interval = defaults.interval ?? 50,
      timeout = defaults.timeout ?? 1000,
      message,
    } = options
    // @ts-expect-error private poll access
    const assertion = expect(null, message).withContext({
      poll: true,
    }) as Assertion
    fn = fn.bind(assertion)
    // injected so that domain snapshot can take over poll implementation.
    chai.util.flag(assertion, '_poll.fn', fn)
    chai.util.flag(assertion, '_poll.timeout', timeout)
    chai.util.flag(assertion, '_poll.interval', interval)
    const test = chai.util.flag(assertion, 'vitest-test') as Test | undefined
    if (!test) {
      throw new Error('expect.poll() must be called inside a test')
    }
    const proxy: any = new Proxy(assertion, {
      get(target, key, receiver) {
        const assertionFunction = Reflect.get(target, key, receiver)

        if (typeof assertionFunction !== 'function') {
          return assertionFunction instanceof chai.Assertion ? proxy : assertionFunction
        }

        if (key === 'assert') {
          return assertionFunction
        }

        if (typeof key === 'string' && unsupported.includes(key)) {
          throw new SyntaxError(
            `expect.poll() is not supported in combination with .${key}(). Use vi.waitFor() if your assertion condition is unstable.`,
          )
        }

View on GitHub (pinned to 1fa9837ec2)