@kodeme-io/next-core-testing
Version:
Testing utilities and helpers for next-core applications
402 lines (292 loc) โข 7.84 kB
Markdown
# @kodeme-io/next-core-testing
Testing utilities and helpers for next-core applications. Provides test utilities, mock data factories, and a shared Jest configuration.
## Installation
```bash
npm install --save-dev @kodeme-io/next-core-testing @testing-library/react @testing-library/jest-dom jest jest-environment-jsdom
```
## Features
- ๐งช **Test Utilities**: Pre-configured `render` function with providers
- ๐ญ **Mock Factories**: Generate realistic test data
- ๐ญ **Mock Implementations**: Mock data clients and adapters
- โ๏ธ **Jest Configuration**: Shared config for consistency
- ๐ **TypeScript**: Full type safety
## Usage
### Test Utilities
```tsx
import { render, screen, userEvent } from '@kodeme-io/next-core-testing'
test('renders component', async () => {
render(<MyComponent />)
const button = screen.getByRole('button', { name: /submit/i })
await userEvent.click(button)
expect(screen.getByText('Success')).toBeInTheDocument()
})
```
### Mock Data Factories
```tsx
import { createMockSaleOrder, createMockPartner } from '@kodeme-io/next-core-testing'
test('displays order list', () => {
// Create 5 mock orders with default values
const orders = createMockSaleOrder(5)
render(<OrderList orders={orders} />)
expect(screen.getByText('SO001')).toBeInTheDocument()
})
test('displays VIP orders', () => {
// Create orders with custom overrides
const vipOrders = createMockSaleOrder(3, {
state: 'sale',
amount_total: 5000000
})
render(<OrderList orders={vipOrders} />)
expect(screen.getAllByText('sale')).toHaveLength(3)
})
```
### Mock Data Client
```tsx
import { mockDataClient, createMockSaleOrder } from '@kodeme-io/next-core-testing'
beforeEach(() => {
// Setup mock data
const orders = createMockSaleOrder(10, { state: 'sale' })
mockDataClient.setMockData('sale.order', orders)
})
afterEach(() => {
// Clean up after each test
mockDataClient.clearMockData()
})
test('fetches orders', async () => {
const orders = await mockDataClient.findMany('sale.order')
expect(orders).toHaveLength(10)
})
test('filters orders', async () => {
const confirmedOrders = await mockDataClient.search('sale.order', {
where: { state: 'sale' }
})
expect(confirmedOrders).toHaveLength(10)
})
```
### Mock Odoo Adapter
```tsx
import { mockOdooAdapter } from '@kodeme-io/next-core-testing'
beforeEach(() => {
mockOdooAdapter.setMockResponse('sale.order', 'search_read', [
{ id: 1, name: 'SO001', state: 'sale' }
])
})
afterEach(() => {
mockOdooAdapter.clearMockResponses()
})
test('calls Odoo API', async () => {
const result = await mockOdooAdapter.search_read(
'sale.order',
[],
['id', 'name', 'state']
)
expect(result).toHaveLength(1)
expect(result[0].name).toBe('SO001')
})
```
## Available Factories
All factories accept `count` and `overrides` parameters:
```typescript
createMockFactory(count: number = 1, overrides: Partial<Type> = {})
```
### `createMockSaleOrder`
Creates mock `SaleOrder` records with realistic defaults.
**Default fields:**
- `id`: Sequential (1, 2, 3...)
- `name`: SO001, SO002, SO003...
- `partner_id`: 1
- `state`: 'sale'
- `amount_total`: 1100000
- All required fields populated
**Example:**
```tsx
// Single order
const order = createMockSaleOrder()[0]
// Multiple orders
const orders = createMockSaleOrder(10)
// With overrides
const draftOrders = createMockSaleOrder(5, { state: 'draft' })
```
### `createMockSaleOrderLine`
Creates mock `SaleOrderLine` records.
**Example:**
```tsx
const lines = createMockSaleOrderLine(3, {
order_id: 1,
product_uom_qty: 10
})
```
### `createMockPartner`
Creates mock `Partner` records (customers/suppliers).
**Example:**
```tsx
const customers = createMockPartner(5, {
customer_type: 'vip',
is_company: true
})
```
### `createMockProduct`
Creates mock `Product` records.
**Example:**
```tsx
const products = createMockProduct(20, {
sale_ok: true,
qty_available: 100
})
```
### `createMockEmployee`
Creates mock `Employee` records.
**Example:**
```tsx
const staff = createMockEmployee(10, {
department: 'Sales',
active: true
})
```
### `createMockInventory`
Creates mock `Inventory` records.
**Example:**
```tsx
const stock = createMockInventory(50, {
available_quantity: 100,
location_name: 'Main Warehouse'
})
```
## Jest Configuration
### Setup
1. **Create `jest.config.js` in your app root:**
```js
const baseConfig = require('@kodeme-io/next-core-testing/jest-config')
module.exports = {
...baseConfig,
// Your app-specific overrides
displayName: 'next-sfa',
}
```
2. **Create `jest.setup.js` in your app root:**
```js
import '@testing-library/jest-dom'
// Add any global test setup here
```
3. **Add test script to `package.json`:**
```json
{
"scripts": {
"test": "jest",
"test:watch": "jest --watch",
"test:coverage": "jest --coverage"
}
}
```
### Run Tests
```bash
# Run all tests
npm test
# Watch mode
npm run test:watch
# With coverage
npm run test:coverage
```
## Utility Functions
### `createSpy()`
Create a simple spy to track function calls.
```tsx
const spy = createSpy()
spy('arg1', 'arg2')
spy('arg3')
expect(spy.calls).toHaveLength(2)
expect(spy.calls[0]).toEqual(['arg1', 'arg2'])
expect(spy.calls[1]).toEqual(['arg3'])
spy.reset() // Clear call history
```
### `waitForCondition()`
Wait for a condition to be true.
```tsx
await waitForCondition(
() => element.textContent === 'Loaded',
5000 // timeout in ms
)
```
### `mockLocalStorage()`
Mock localStorage for testing.
```tsx
beforeEach(() => {
global.localStorage = mockLocalStorage()
})
test('saves to localStorage', () => {
localStorage.setItem('key', 'value')
expect(localStorage.getItem('key')).toBe('value')
})
```
### `createMockFetch()`
Mock fetch API for testing.
```tsx
const mockFetch = createMockFetch()
mockFetch.setResponse('/api/orders', { data: [] })
global.fetch = mockFetch.fetch
test('fetches orders', async () => {
const response = await fetch('/api/orders')
const data = await response.json()
expect(data).toEqual({ data: [] })
})
```
## Best Practices
### 1. Use Factories for Test Data
โ
**Do:**
```tsx
const orders = createMockSaleOrder(5, { state: 'sale' })
```
โ **Don't:**
```tsx
const orders = [
{ id: 1, name: 'SO001', partner_id: 1, state: 'sale', /* 20 more fields */ },
{ id: 2, name: 'SO002', partner_id: 1, state: 'sale', /* 20 more fields */ },
// ...
]
```
### 2. Clean Up After Tests
```tsx
afterEach(() => {
mockDataClient.clearMockData()
mockOdooAdapter.clearMockResponses()
})
```
### 3. Use Descriptive Test Names
โ
**Do:**
```tsx
test('displays error message when order creation fails', () => {
// ...
})
```
โ **Don't:**
```tsx
test('test1', () => {
// ...
})
```
### 4. Test User Interactions
```tsx
import { userEvent } from '@kodeme-io/next-core-testing'
test('submits form on button click', async () => {
render(<OrderForm />)
await userEvent.type(screen.getByLabelText('Customer'), 'John Doe')
await userEvent.click(screen.getByRole('button', { name: /submit/i }))
expect(screen.getByText('Order created')).toBeInTheDocument()
})
```
## TypeScript Support
All exports are fully typed. Import types as needed:
```tsx
import type { SaleOrder, Partner } from '@next-core/shared-mock-data'
import { createMockSaleOrder } from '@kodeme-io/next-core-testing'
const orders: SaleOrder[] = createMockSaleOrder(5)
```
## Related Packages
- `@kodeme-io/next-core-ui` - UI components
- `@kodeme-io/next-core-client` - Data client
- `@kodeme-io/next-core-hooks` - React hooks
- `@next-core/shared-mock-data` - Type definitions
## License
MIT
## Contributing
Contributions welcome! Please see the main [next-core repository](https://github.com/your-org/next-core) for guidelines.