콘텐츠로 이동

vitest hoisting — vi.mock factory 내 외부 변수 참조 시 ReferenceError

문제

vi.mock factory 내부에서 파일 상단에 선언한 const 변수를 참조하면 테스트 실행 시 ReferenceError: Cannot access 'X' before initialization가 발생한다.

재현 조건:

const capturedProps = {} as SomeType;  // 파일 상단 const 선언

vi.mock("@/components/ui/dialog", () => ({
  DialogContent: ({ onEscapeKeyDown }) => {
    capturedProps.onEscapeKeyDown = onEscapeKeyDown;  // ← ReferenceError!
    return <div />;
  },
}));

증상

  • 테스트 실행 시 ReferenceError: Cannot access 'capturedProps' before initialization
  • 빌드·린트는 통과 (TypeScript는 hoisting을 정적으로 잡지 않음)
  • vitest 실행 시점에만 에러 노출

시도했으나 실패한 것

  1. constlet 으로 변경 → 동일한 ReferenceError 발생 (TDZ는 let도 적용됨)
  2. factory를 파일 최하단으로 이동 → vitest가 다시 상단으로 hoisting하므로 무의미
  3. 변수 선언을 var로 변경 → 값 참조 시점에 여전히 undefined

해결

vi.hoisted()로 factory 실행 이전에 변수를 확보한다.

// ✅ vi.hoisted로 factory 이전에 변수를 확보
const { capturedProps } = vi.hoisted(() => ({
  capturedProps: {} as SomeType,
}));

vi.mock("@/components/ui/dialog", () => ({
  DialogContent: ({ onEscapeKeyDown }) => {
    capturedProps.onEscapeKeyDown = onEscapeKeyDown;  // 안전하게 참조 가능
    return <div />;
  },
}));

여러 hoisted 변수가 필요하면 객체로 묶어서 한 번에 선언한다:

const { capturedProps, mockState } = vi.hoisted(() => ({
  capturedProps: {} as CapturedProps,
  mockState: { isPending: false },
}));

원인

vitest는 ESM static analysis 단계에서 vi.mock()을 파일 최상단으로 hoisting한다. 따라서 vi.mock factory는 파일의 다른 import나 변수 선언보다 먼저 실행된다. 일반 const/let은 TDZ(Temporal Dead Zone) 때문에 선언 전 접근 시 ReferenceError가 발생한다.

vi.hoisted()는 hoisting 시스템에 의해 vi.mock보다 더 일찍 실행되도록 보장된다. 따라서 factory가 실행될 시점에 이미 변수가 초기화되어 있다.

실행 순서: 1. vi.hoisted() 콜백 실행 → 변수 초기화 2. vi.mock() factory 실행 → 변수 참조 가능 3. import 문 실행 4. 나머지 파일 코드 실행

재발 방지

  • vi.mock factory 내부에서 외부 변수를 참조해야 한다면 무조건 vi.hoisted()로 감싼다
  • 테스트에서 상태를 mock factory와 공유해야 할 때 (예: isPending 플래그 toggle) 동일하게 적용
  • beforeEach에서 hoisted 변수를 리셋하여 테스트 간 상태 오염을 방지한다:
    beforeEach(() => {
      capturedProps.onEscapeKeyDown = undefined;
      mockState.isPending = false;
    });
    
  • 프로젝트 개발 규칙(개발_규칙_FE.md)의 테스트 섹션에 이 패턴을 명시

관련 자료