TESTING.md
Rama main · réplica de lectura del repositorio original.
# Testing Guide for Writers Guild
This document provides information about the testing setup and how to write and run tests for Writers Guild.
## Overview
Writers Guild uses **Vitest** as the primary testing framework for both backend and frontend code. Vitest is a fast, modern testing framework that works seamlessly with ES modules and provides a Jest-compatible API.
**Test Coverage:**
- **Server**: 223 tests covering services and providers
- **Client**: 118 tests covering composables and components
- **Total**: 341 tests
## Test Structure
```
writers-guild/
├── server/
│ ├── vitest.config.js
│ └── src/
│ ├── services/
│ │ └── __tests__/ # Service unit tests
│ │ ├── macro-processor.test.js
│ │ ├── template-engine.test.js
│ │ ├── prompt-builder.test.js
│ │ └── lorebook-activator.test.js
│ └── providers/
│ └── __tests__/ # Provider unit tests
│ ├── anthropic-provider.test.js
│ └── openai-provider.test.js
└── vue_client/
├── vite.config.js # Includes Vitest config
└── src/
├── composables/
│ └── __tests__/ # Composable unit tests
│ ├── useConfirm.test.js
│ └── useToast.test.js
└── components/
└── __tests__/ # Component tests
├── ConfirmDialog.test.js
└── Tabs.test.js
```
## Running Tests
### All Tests
```bash
# Run all tests (server + client)
npm test
# Run all tests with coverage
npm run test:coverage
```
### Server Tests
```bash
# Run all server tests
npm run test:server
# Run specific server test file
cd server && npm test -- macro-processor
# Run server tests with coverage
npm run test:server:coverage
# Run tests in watch mode
cd server && npm test
```
### Client Tests
```bash
# Run all client tests
npm run test:client
# Run specific client test file
cd vue_client && npm test -- useConfirm
# Run client tests with coverage
npm run test:client:coverage
# Run tests in watch mode
cd vue_client && npm test
```
## Writing Tests
### Backend Service Tests
Backend tests focus on business logic in services and providers. They mock external dependencies like `fetch`.
**Example: Service Test**
```javascript
import { describe, it, expect, beforeEach } from 'vitest';
import { MacroProcessor } from '../macro-processor.js';
describe('MacroProcessor', () => {
let processor;
beforeEach(() => {
processor = new MacroProcessor({
userName: 'Alice',
charName: 'Bob',
});
});
describe('Context Macros', () => {
it('should replace {{user}} with user name', () => {
const result = processor.processContextMacros('Hello {{user}}!');
expect(result).toBe('Hello Alice!');
});
});
});
```
**Example: Provider Test with Mocked Fetch**
```javascript
import { describe, it, expect, beforeEach, vi } from 'vitest';
import { AnthropicProvider } from '../anthropic-provider.js';
describe('AnthropicProvider', () => {
let provider;
let mockFetch;
beforeEach(() => {
mockFetch = vi.fn();
global.fetch = mockFetch;
provider = new AnthropicProvider({
apiKey: 'test-api-key',
model: 'claude-3-5-sonnet-20241022',
});
});
it('should generate content successfully', async () => {
mockFetch.mockResolvedValueOnce({
ok: true,
json: async () => ({
content: [{ type: 'text', text: 'Generated response' }],
}),
});
const result = await provider.generate('System prompt', 'User prompt');
expect(result.content).toBe('Generated response');
});
});
```
### Frontend Composable Tests
Composable tests verify Vue 3 composition API logic.
**Example: Composable Test**
```javascript
import { describe, it, expect, beforeEach } from 'vitest';
import { useConfirm } from '../useConfirm.js';
describe('useConfirm', () => {
let confirmInstance;
beforeEach(() => {
confirmInstance = useConfirm();
confirmInstance.isVisible.value = false;
});
it('should show dialog when confirm is called', () => {
confirmInstance.confirm({ message: 'Test message' });
expect(confirmInstance.isVisible.value).toBe(true);
});
it('should resolve promise with true when confirmed', async () => {
const promise = confirmInstance.confirm({ message: 'Test' });
confirmInstance.handleConfirm();
const result = await promise;
expect(result).toBe(true);
});
});
```
### Frontend Component Tests
Component tests use Vue Test Utils to mount and interact with components.
**Example: Component Test**
```javascript
import { describe, it, expect } from 'vitest';
import { mount } from '@vue/test-utils';
import ConfirmDialog from '../ConfirmDialog.vue';
describe('ConfirmDialog', () => {
it('should render with required props', () => {
const wrapper = mount(ConfirmDialog, {
props: {
message: 'Are you sure?',
},
});
expect(wrapper.text()).toContain('Are you sure?');
});
it('should emit confirm event when confirm button clicked', async () => {
const wrapper = mount(ConfirmDialog, {
props: { message: 'Test' },
});
const confirmButton = wrapper.findAll('button')[1];
await confirmButton.trigger('click');
expect(wrapper.emitted('confirm')).toBeTruthy();
});
});
```
## Testing Best Practices
### 1. Test Organization
- Group related tests with `describe` blocks
- Use clear, descriptive test names
- Follow the Arrange-Act-Assert pattern
- One assertion per test when possible
### 2. beforeEach and afterEach
```javascript
beforeEach(() => {
// Setup runs before each test
vi.useFakeTimers();
});
afterEach(() => {
// Cleanup runs after each test
vi.restoreAllMocks();
});
```
### 3. Mocking
**Mock functions:**
```javascript
const mockCallback = vi.fn();
mockCallback('test');
expect(mockCallback).toHaveBeenCalledWith('test');
```
**Mock timers:**
```javascript
vi.useFakeTimers();
setTimeout(() => doSomething(), 1000);
vi.advanceTimersByTime(1000);
expect(doSomething).toHaveBeenCalled();
```
**Mock modules:**
```javascript
vi.mock('./module.js', () => ({
default: vi.fn(() => 'mocked'),
}));
```
### 4. Testing Async Code
```javascript
it('should handle async operations', async () => {
const result = await asyncFunction();
expect(result).toBe(expected);
});
it('should reject with error', async () => {
await expect(failingFunction()).rejects.toThrow('Error message');
});
```
### 5. Component Testing Tips
**Finding elements:**
```javascript
wrapper.find('.class-name');
wrapper.findAll('button');
wrapper.find('[data-testid="my-element"]');
```
**Triggering events:**
```javascript
await wrapper.find('button').trigger('click');
await wrapper.find('input').setValue('value');
```
**Checking emissions:**
```javascript
expect(wrapper.emitted('event-name')).toBeTruthy();
expect(wrapper.emitted('event-name')[0]).toEqual(['arg1', 'arg2']);
```
**Using slots:**
```javascript
mount(Component, {
slots: {
default: '<div>Slot content</div>',
},
});
```
## Coverage Reports
After running tests with coverage, reports are available in:
- `server/coverage/` - Server code coverage
- `vue_client/coverage/` - Client code coverage
Open `coverage/index.html` in a browser to view detailed coverage reports.
## Continuous Integration
Tests are automatically run on:
- Pre-commit hooks (if configured)
- Pull requests
- Main branch commits
Ensure all tests pass before submitting a PR:
```bash
npm test
```
## Common Issues
### Issue: Tests fail with "Cannot find module"
**Solution:** Ensure you're using the correct import paths and that modules are exported correctly.
### Issue: Component tests fail with "Cannot read property of undefined"
**Solution:** Check that all required props are provided in the mount() call.
### Issue: Async tests timeout
**Solution:** Ensure you're using `async/await` properly and not forgetting to resolve promises.
### Issue: Mocked timers don't work
**Solution:** Remember to call `vi.useFakeTimers()` in beforeEach and restore with `vi.restoreAllMocks()`.
## Test Coverage Goals
| Category | Current | Goal |
| ----------- | ------- | ---- |
| Services | 100% | 100% |
| Providers | 90% | 90% |
| Composables | 95% | 95% |
| Components | 70% | 80% |
| Overall | 85% | 85% |
## Adding New Tests
When adding new features:
1. **Write tests first** (TDD approach) or alongside implementation
2. **Cover edge cases**: null/undefined inputs, empty arrays, boundary conditions
3. **Test error handling**: What happens when things go wrong?
4. **Mock external dependencies**: Don't test API services directly
5. **Keep tests fast**: Avoid unnecessary delays or real API calls
6. **Update this guide** if you introduce new testing patterns
## Resources
- [Vitest Documentation](https://vitest.dev/)
- [Vue Test Utils](https://test-utils.vuejs.org/)
- [Testing Library Best Practices](https://kentcdodds.com/blog/common-mistakes-with-react-testing-library)
## Questions?
If you have questions about testing or need help writing tests for a specific feature, feel free to:
- Check existing test files for examples
- Review this guide
- Ask in the project discussions