UNPKG

@kodeme-io/next-core-testing

Version:

Testing utilities and helpers for next-core applications

402 lines (292 loc) โ€ข 7.84 kB
# @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.