From cf84f1af6854a99975903192b5770c790521be55 Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Mon, 2 Jun 2025 21:46:20 -0700 Subject: [PATCH] Docs: Enhance "Writing Tests" section in GEMINI.md (#688) --- GEMINI.md | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/GEMINI.md b/GEMINI.md index 8a8afdbb..fd6c8996 100644 --- a/GEMINI.md +++ b/GEMINI.md @@ -16,7 +16,47 @@ npm run preflight ## Writing Tests -When writing tests look at existing tests in packages/core and packages/cli to conform with the conventions in those files. +This project uses **Vitest** as its primary testing framework. When writing tests, aim to follow existing patterns. Key conventions include: + +### Test Structure and Framework + +- **Framework**: All tests are written using Vitest (`describe`, `it`, `expect`, `vi`). +- **File Location**: Test files (`*.test.ts` for logic, `*.test.tsx` for React components) are co-located with the source files they test. +- **Configuration**: Test environments are defined in `vitest.config.ts` files. +- **Setup/Teardown**: Use `beforeEach` and `afterEach`. Commonly, `vi.resetAllMocks()` is called in `beforeEach` and `vi.restoreAllMocks()` in `afterEach`. + +### Mocking (`vi` from Vitest) + +- **ES Modules**: Mock with `vi.mock('module-name', async (importOriginal) => { ... })`. Use `importOriginal` for selective mocking. + - _Example_: `vi.mock('os', async (importOriginal) => { const actual = await importOriginal(); return { ...actual, homedir: vi.fn() }; });` +- **Mocking Order**: For critical dependencies (e.g., `os`, `fs`) that affect module-level constants, place `vi.mock` at the _very top_ of the test file, before other imports. +- **Hoisting**: Use `const myMock = vi.hoisted(() => vi.fn());` if a mock function needs to be defined before its use in a `vi.mock` factory. +- **Mock Functions**: Create with `vi.fn()`. Define behavior with `mockImplementation()`, `mockResolvedValue()`, or `mockRejectedValue()`. +- **Spying**: Use `vi.spyOn(object, 'methodName')`. Restore spies with `mockRestore()` in `afterEach`. + +### Commonly Mocked Modules + +- **Node.js built-ins**: `fs`, `fs/promises`, `os` (especially `os.homedir()`), `path`, `child_process` (`execSync`, `spawn`). +- **External SDKs**: `@google/genai`, `@modelcontextprotocol/sdk`. +- **Internal Project Modules**: Dependencies from other project packages are often mocked. + +### React Component Testing (CLI UI - Ink) + +- Use `render()` from `ink-testing-library`. +- Assert output with `lastFrame()`. +- Wrap components in necessary `Context.Provider`s. +- Mock custom React hooks and complex child components using `vi.mock()`. + +### Asynchronous Testing + +- Use `async/await`. +- For timers, use `vi.useFakeTimers()`, `vi.advanceTimersByTimeAsync()`, `vi.runAllTimersAsync()`. +- Test promise rejections with `await expect(promise).rejects.toThrow(...)`. + +### General Guidance + +- When adding tests, first examine existing tests to understand and conform to established conventions. +- Pay close attention to the mocks at the top of existing test files; they reveal critical dependencies and how they are managed in a test environment. ## Git Repo