Add test environment configuration and update Jest setup
- Created `.env.test.example` with test environment variables - Updated `jest.config.cjs` to simplify configuration and improve test setup - Added `jest.setup.ts` to load and configure test environment variables - Updated test files to use dynamic test environment configuration - Enhanced README.md with additional configuration details for testing
This commit is contained in:
11
.env.test.example
Normal file
11
.env.test.example
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# Test Environment Configuration
|
||||||
|
|
||||||
|
# Home Assistant Test Instance
|
||||||
|
TEST_HASS_HOST=http://localhost:8123
|
||||||
|
TEST_HASS_TOKEN=test_token
|
||||||
|
TEST_HASS_SOCKET_URL=ws://localhost:8123/api/websocket
|
||||||
|
|
||||||
|
# Test Server Configuration
|
||||||
|
TEST_PORT=3001
|
||||||
|
NODE_ENV=test
|
||||||
|
DEBUG=false
|
||||||
293
README.md
293
README.md
@@ -136,6 +136,11 @@ npm run build
|
|||||||
# Server Configuration
|
# Server Configuration
|
||||||
PORT=3000
|
PORT=3000
|
||||||
NODE_ENV=production
|
NODE_ENV=production
|
||||||
|
DEBUG=false
|
||||||
|
|
||||||
|
# Test Configuration
|
||||||
|
TEST_HASS_HOST=http://localhost:8123
|
||||||
|
TEST_HASS_TOKEN=test_token
|
||||||
```
|
```
|
||||||
|
|
||||||
3. **Launch with Docker Compose:**
|
3. **Launch with Docker Compose:**
|
||||||
@@ -143,6 +148,32 @@ npm run build
|
|||||||
docker-compose up -d
|
docker-compose up -d
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
### Environment Variables
|
||||||
|
|
||||||
|
```env
|
||||||
|
# Home Assistant Configuration
|
||||||
|
HASS_HOST=http://homeassistant.local:8123 # Your Home Assistant instance URL
|
||||||
|
HASS_TOKEN=your_home_assistant_token # Long-lived access token
|
||||||
|
HASS_SOCKET_URL=ws://homeassistant.local:8123/api/websocket # WebSocket URL
|
||||||
|
|
||||||
|
# Server Configuration
|
||||||
|
PORT=3000 # Server port (default: 3000)
|
||||||
|
NODE_ENV=production # Environment (production/development)
|
||||||
|
DEBUG=false # Enable debug mode
|
||||||
|
|
||||||
|
# Test Configuration
|
||||||
|
TEST_HASS_HOST=http://localhost:8123 # Test instance URL
|
||||||
|
TEST_HASS_TOKEN=test_token # Test token
|
||||||
|
```
|
||||||
|
|
||||||
|
### Configuration Files
|
||||||
|
|
||||||
|
1. **Development**: Copy `.env.example` to `.env.development`
|
||||||
|
2. **Production**: Copy `.env.example` to `.env.production`
|
||||||
|
3. **Testing**: Copy `.env.example` to `.env.test`
|
||||||
|
|
||||||
## API Reference
|
## API Reference
|
||||||
|
|
||||||
### Device Control
|
### Device Control
|
||||||
@@ -258,6 +289,268 @@ npm run build
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Core Functions
|
||||||
|
|
||||||
|
#### State Management
|
||||||
|
```http
|
||||||
|
GET /api/state
|
||||||
|
POST /api/state
|
||||||
|
```
|
||||||
|
|
||||||
|
Manages the current state of the system.
|
||||||
|
|
||||||
|
**Example Request:**
|
||||||
|
```json
|
||||||
|
POST /api/state
|
||||||
|
{
|
||||||
|
"context": "living_room",
|
||||||
|
"state": {
|
||||||
|
"lights": "on",
|
||||||
|
"temperature": 22
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Context Updates
|
||||||
|
```http
|
||||||
|
POST /api/context
|
||||||
|
```
|
||||||
|
|
||||||
|
Updates the current context with new information.
|
||||||
|
|
||||||
|
**Example Request:**
|
||||||
|
```json
|
||||||
|
POST /api/context
|
||||||
|
{
|
||||||
|
"user": "john",
|
||||||
|
"location": "kitchen",
|
||||||
|
"time": "morning",
|
||||||
|
"activity": "cooking"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Action Endpoints
|
||||||
|
|
||||||
|
#### Execute Action
|
||||||
|
```http
|
||||||
|
POST /api/action
|
||||||
|
```
|
||||||
|
|
||||||
|
Executes a specified action with given parameters.
|
||||||
|
|
||||||
|
**Example Request:**
|
||||||
|
```json
|
||||||
|
POST /api/action
|
||||||
|
{
|
||||||
|
"action": "turn_on_lights",
|
||||||
|
"parameters": {
|
||||||
|
"room": "living_room",
|
||||||
|
"brightness": 80
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Batch Actions
|
||||||
|
```http
|
||||||
|
POST /api/actions/batch
|
||||||
|
```
|
||||||
|
|
||||||
|
Executes multiple actions in sequence.
|
||||||
|
|
||||||
|
**Example Request:**
|
||||||
|
```json
|
||||||
|
POST /api/actions/batch
|
||||||
|
{
|
||||||
|
"actions": [
|
||||||
|
{
|
||||||
|
"action": "turn_on_lights",
|
||||||
|
"parameters": {
|
||||||
|
"room": "living_room"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "set_temperature",
|
||||||
|
"parameters": {
|
||||||
|
"temperature": 22
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Query Functions
|
||||||
|
|
||||||
|
#### Get Available Actions
|
||||||
|
```http
|
||||||
|
GET /api/actions
|
||||||
|
```
|
||||||
|
|
||||||
|
Returns a list of all available actions.
|
||||||
|
|
||||||
|
**Example Response:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"actions": [
|
||||||
|
{
|
||||||
|
"name": "turn_on_lights",
|
||||||
|
"parameters": ["room", "brightness"],
|
||||||
|
"description": "Turns on lights in specified room"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "set_temperature",
|
||||||
|
"parameters": ["temperature"],
|
||||||
|
"description": "Sets temperature in current context"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Context Query
|
||||||
|
```http
|
||||||
|
GET /api/context?type=current
|
||||||
|
```
|
||||||
|
|
||||||
|
Retrieves context information.
|
||||||
|
|
||||||
|
**Example Response:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"current_context": {
|
||||||
|
"user": "john",
|
||||||
|
"location": "kitchen",
|
||||||
|
"time": "morning",
|
||||||
|
"activity": "cooking"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### WebSocket Events
|
||||||
|
|
||||||
|
The server supports real-time updates via WebSocket connections.
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Client-side connection example
|
||||||
|
const ws = new WebSocket('ws://localhost:3000/ws');
|
||||||
|
|
||||||
|
ws.onmessage = (event) => {
|
||||||
|
const data = JSON.parse(event.data);
|
||||||
|
console.log('Received update:', data);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Supported Events
|
||||||
|
|
||||||
|
- `state_change`: Emitted when system state changes
|
||||||
|
- `context_update`: Emitted when context is updated
|
||||||
|
- `action_executed`: Emitted when an action is completed
|
||||||
|
- `error`: Emitted when an error occurs
|
||||||
|
|
||||||
|
**Example Event Data:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"event": "state_change",
|
||||||
|
"data": {
|
||||||
|
"previous_state": {
|
||||||
|
"lights": "off"
|
||||||
|
},
|
||||||
|
"current_state": {
|
||||||
|
"lights": "on"
|
||||||
|
},
|
||||||
|
"timestamp": "2024-03-20T10:30:00Z"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Error Handling
|
||||||
|
|
||||||
|
All endpoints return standard HTTP status codes:
|
||||||
|
|
||||||
|
- 200: Success
|
||||||
|
- 400: Bad Request
|
||||||
|
- 401: Unauthorized
|
||||||
|
- 403: Forbidden
|
||||||
|
- 404: Not Found
|
||||||
|
- 500: Internal Server Error
|
||||||
|
|
||||||
|
**Error Response Format:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": {
|
||||||
|
"code": "INVALID_PARAMETERS",
|
||||||
|
"message": "Missing required parameter: room",
|
||||||
|
"details": {
|
||||||
|
"missing_fields": ["room"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Rate Limiting
|
||||||
|
|
||||||
|
The API implements rate limiting to prevent abuse:
|
||||||
|
|
||||||
|
- 100 requests per minute per IP for regular endpoints
|
||||||
|
- 1000 requests per minute per IP for WebSocket connections
|
||||||
|
|
||||||
|
When rate limit is exceeded, the server returns:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": {
|
||||||
|
"code": "RATE_LIMIT_EXCEEDED",
|
||||||
|
"message": "Too many requests",
|
||||||
|
"reset_time": "2024-03-20T10:31:00Z"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example Usage
|
||||||
|
|
||||||
|
#### Using curl
|
||||||
|
```bash
|
||||||
|
# Get current state
|
||||||
|
curl -X GET \
|
||||||
|
http://localhost:3000/api/state \
|
||||||
|
-H 'Authorization: ApiKey your_api_key_here'
|
||||||
|
|
||||||
|
# Execute action
|
||||||
|
curl -X POST \
|
||||||
|
http://localhost:3000/api/action \
|
||||||
|
-H 'Authorization: ApiKey your_api_key_here' \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-d '{
|
||||||
|
"action": "turn_on_lights",
|
||||||
|
"parameters": {
|
||||||
|
"room": "living_room",
|
||||||
|
"brightness": 80
|
||||||
|
}
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Using JavaScript
|
||||||
|
```javascript
|
||||||
|
// Execute action
|
||||||
|
async function executeAction() {
|
||||||
|
const response = await fetch('http://localhost:3000/api/action', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'ApiKey your_api_key_here',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
action: 'turn_on_lights',
|
||||||
|
parameters: {
|
||||||
|
room: 'living_room',
|
||||||
|
brightness: 80
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
console.log('Action result:', data);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@@ -4,9 +4,15 @@ import { LiteMCP } from 'litemcp';
|
|||||||
import { get_hass } from '../src/hass/index.js';
|
import { get_hass } from '../src/hass/index.js';
|
||||||
import type { WebSocket } from 'ws';
|
import type { WebSocket } from 'ws';
|
||||||
|
|
||||||
// Mock environment variables
|
// Load test environment variables with defaults
|
||||||
process.env.HASS_HOST = 'http://localhost:8123';
|
const TEST_HASS_HOST = process.env.TEST_HASS_HOST || 'http://localhost:8123';
|
||||||
process.env.HASS_TOKEN = 'test_token';
|
const TEST_HASS_TOKEN = process.env.TEST_HASS_TOKEN || 'test_token';
|
||||||
|
const TEST_HASS_SOCKET_URL = process.env.TEST_HASS_SOCKET_URL || 'ws://localhost:8123/api/websocket';
|
||||||
|
|
||||||
|
// Set environment variables for testing
|
||||||
|
process.env.HASS_HOST = TEST_HASS_HOST;
|
||||||
|
process.env.HASS_TOKEN = TEST_HASS_TOKEN;
|
||||||
|
process.env.HASS_SOCKET_URL = TEST_HASS_SOCKET_URL;
|
||||||
|
|
||||||
// Mock fetch
|
// Mock fetch
|
||||||
const mockFetchResponse = {
|
const mockFetchResponse = {
|
||||||
@@ -230,11 +236,11 @@ describe('Home Assistant MCP Server', () => {
|
|||||||
|
|
||||||
// Verify the fetch call
|
// Verify the fetch call
|
||||||
expect(mockFetch).toHaveBeenCalledWith(
|
expect(mockFetch).toHaveBeenCalledWith(
|
||||||
'http://localhost:8123/api/services/light/turn_on',
|
`${TEST_HASS_HOST}/api/services/light/turn_on`,
|
||||||
{
|
{
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: 'Bearer test_token',
|
Authorization: `Bearer ${TEST_HASS_TOKEN}`,
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
@@ -312,11 +318,11 @@ describe('Home Assistant MCP Server', () => {
|
|||||||
|
|
||||||
// Verify the fetch call
|
// Verify the fetch call
|
||||||
expect(mockFetch).toHaveBeenCalledWith(
|
expect(mockFetch).toHaveBeenCalledWith(
|
||||||
'http://localhost:8123/api/services/climate/set_temperature',
|
`${TEST_HASS_HOST}/api/services/climate/set_temperature`,
|
||||||
{
|
{
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: 'Bearer test_token',
|
Authorization: `Bearer ${TEST_HASS_TOKEN}`,
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
@@ -354,11 +360,11 @@ describe('Home Assistant MCP Server', () => {
|
|||||||
|
|
||||||
// Verify the fetch call
|
// Verify the fetch call
|
||||||
expect(mockFetch).toHaveBeenCalledWith(
|
expect(mockFetch).toHaveBeenCalledWith(
|
||||||
'http://localhost:8123/api/services/cover/set_position',
|
`${TEST_HASS_HOST}/api/services/cover/set_position`,
|
||||||
{
|
{
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: 'Bearer test_token',
|
Authorization: `Bearer ${TEST_HASS_TOKEN}`,
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
@@ -415,7 +421,7 @@ describe('Home Assistant MCP Server', () => {
|
|||||||
expect.stringContaining('/api/history/period/2024-01-01T00:00:00Z?'),
|
expect.stringContaining('/api/history/period/2024-01-01T00:00:00Z?'),
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: 'Bearer test_token',
|
Authorization: `Bearer ${TEST_HASS_TOKEN}`,
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -513,11 +519,11 @@ describe('Home Assistant MCP Server', () => {
|
|||||||
expect(result.message).toBe('Successfully activated scene scene.movie_time');
|
expect(result.message).toBe('Successfully activated scene scene.movie_time');
|
||||||
|
|
||||||
expect(mockFetch).toHaveBeenCalledWith(
|
expect(mockFetch).toHaveBeenCalledWith(
|
||||||
'http://localhost:8123/api/services/scene/turn_on',
|
`${TEST_HASS_HOST}/api/services/scene/turn_on`,
|
||||||
{
|
{
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: 'Bearer test_token',
|
Authorization: `Bearer ${TEST_HASS_TOKEN}`,
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
@@ -550,11 +556,11 @@ describe('Home Assistant MCP Server', () => {
|
|||||||
expect(result.message).toBe('Notification sent successfully');
|
expect(result.message).toBe('Notification sent successfully');
|
||||||
|
|
||||||
expect(mockFetch).toHaveBeenCalledWith(
|
expect(mockFetch).toHaveBeenCalledWith(
|
||||||
'http://localhost:8123/api/services/notify/mobile_app_phone',
|
`${TEST_HASS_HOST}/api/services/notify/mobile_app_phone`,
|
||||||
{
|
{
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: 'Bearer test_token',
|
Authorization: `Bearer ${TEST_HASS_TOKEN}`,
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
@@ -581,7 +587,7 @@ describe('Home Assistant MCP Server', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
expect(mockFetch).toHaveBeenCalledWith(
|
expect(mockFetch).toHaveBeenCalledWith(
|
||||||
'http://localhost:8123/api/services/notify/notify',
|
`${TEST_HASS_HOST}/api/services/notify/notify`,
|
||||||
expect.any(Object)
|
expect.any(Object)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -657,11 +663,11 @@ describe('Home Assistant MCP Server', () => {
|
|||||||
expect(result.message).toBe('Successfully toggled automation automation.morning_routine');
|
expect(result.message).toBe('Successfully toggled automation automation.morning_routine');
|
||||||
|
|
||||||
expect(mockFetch).toHaveBeenCalledWith(
|
expect(mockFetch).toHaveBeenCalledWith(
|
||||||
'http://localhost:8123/api/services/automation/toggle',
|
`${TEST_HASS_HOST}/api/services/automation/toggle`,
|
||||||
{
|
{
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: 'Bearer test_token',
|
Authorization: `Bearer ${TEST_HASS_TOKEN}`,
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
@@ -690,11 +696,11 @@ describe('Home Assistant MCP Server', () => {
|
|||||||
expect(result.message).toBe('Successfully triggered automation automation.morning_routine');
|
expect(result.message).toBe('Successfully triggered automation automation.morning_routine');
|
||||||
|
|
||||||
expect(mockFetch).toHaveBeenCalledWith(
|
expect(mockFetch).toHaveBeenCalledWith(
|
||||||
'http://localhost:8123/api/services/automation/trigger',
|
`${TEST_HASS_HOST}/api/services/automation/trigger`,
|
||||||
{
|
{
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: 'Bearer test_token',
|
Authorization: `Bearer ${TEST_HASS_TOKEN}`,
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
@@ -782,11 +788,11 @@ describe('Home Assistant MCP Server', () => {
|
|||||||
expect(result.message).toBe('Successfully installed add-on core_configurator');
|
expect(result.message).toBe('Successfully installed add-on core_configurator');
|
||||||
|
|
||||||
expect(mockFetch).toHaveBeenCalledWith(
|
expect(mockFetch).toHaveBeenCalledWith(
|
||||||
'http://localhost:8123/api/hassio/addons/core_configurator/install',
|
`${TEST_HASS_HOST}/api/hassio/addons/core_configurator/install`,
|
||||||
{
|
{
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: 'Bearer test_token',
|
Authorization: `Bearer ${TEST_HASS_TOKEN}`,
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
},
|
},
|
||||||
body: JSON.stringify({ version: '5.6.0' })
|
body: JSON.stringify({ version: '5.6.0' })
|
||||||
@@ -851,11 +857,11 @@ describe('Home Assistant MCP Server', () => {
|
|||||||
expect(result.message).toBe('Successfully installed package hacs/integration');
|
expect(result.message).toBe('Successfully installed package hacs/integration');
|
||||||
|
|
||||||
expect(mockFetch).toHaveBeenCalledWith(
|
expect(mockFetch).toHaveBeenCalledWith(
|
||||||
'http://localhost:8123/api/hacs/repository/install',
|
`${TEST_HASS_HOST}/api/hacs/repository/install`,
|
||||||
{
|
{
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: 'Bearer test_token',
|
Authorization: `Bearer ${TEST_HASS_TOKEN}`,
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
@@ -910,11 +916,11 @@ describe('Home Assistant MCP Server', () => {
|
|||||||
expect(result.automation_id).toBe('new_automation_1');
|
expect(result.automation_id).toBe('new_automation_1');
|
||||||
|
|
||||||
expect(mockFetch).toHaveBeenCalledWith(
|
expect(mockFetch).toHaveBeenCalledWith(
|
||||||
'http://localhost:8123/api/config/automation/config',
|
`${TEST_HASS_HOST}/api/config/automation/config`,
|
||||||
{
|
{
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: 'Bearer test_token',
|
Authorization: `Bearer ${TEST_HASS_TOKEN}`,
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
},
|
},
|
||||||
body: JSON.stringify(mockAutomationConfig)
|
body: JSON.stringify(mockAutomationConfig)
|
||||||
@@ -950,17 +956,17 @@ describe('Home Assistant MCP Server', () => {
|
|||||||
|
|
||||||
// Verify both API calls
|
// Verify both API calls
|
||||||
expect(mockFetch).toHaveBeenCalledWith(
|
expect(mockFetch).toHaveBeenCalledWith(
|
||||||
'http://localhost:8123/api/config/automation/config/automation.test',
|
`${TEST_HASS_HOST}/api/config/automation/config/automation.test`,
|
||||||
expect.any(Object)
|
expect.any(Object)
|
||||||
);
|
);
|
||||||
|
|
||||||
const duplicateConfig = { ...mockAutomationConfig, alias: 'Test Automation (Copy)' };
|
const duplicateConfig = { ...mockAutomationConfig, alias: 'Test Automation (Copy)' };
|
||||||
expect(mockFetch).toHaveBeenCalledWith(
|
expect(mockFetch).toHaveBeenCalledWith(
|
||||||
'http://localhost:8123/api/config/automation/config',
|
`${TEST_HASS_HOST}/api/config/automation/config`,
|
||||||
{
|
{
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: 'Bearer test_token',
|
Authorization: `Bearer ${TEST_HASS_TOKEN}`,
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
},
|
},
|
||||||
body: JSON.stringify(duplicateConfig)
|
body: JSON.stringify(duplicateConfig)
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
/** @type {import('ts-jest').JestConfigWithTsJest} */
|
/** @type {import('ts-jest').JestConfigWithTsJest} */
|
||||||
module.exports = {
|
module.exports = {
|
||||||
preset: 'ts-jest/presets/default-esm',
|
preset: 'ts-jest',
|
||||||
testEnvironment: 'node',
|
testEnvironment: 'node',
|
||||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
|
setupFiles: ['./jest.setup.ts'],
|
||||||
extensionsToTreatAsEsm: ['.ts', '.tsx'],
|
|
||||||
moduleNameMapper: {
|
moduleNameMapper: {
|
||||||
'^(\\.{1,2}/.*)\\.js$': '$1',
|
'^(\\.{1,2}/.*)\\.js$': '$1',
|
||||||
'#(.*)': '<rootDir>/node_modules/$1',
|
'#(.*)': '<rootDir>/node_modules/$1',
|
||||||
@@ -13,20 +12,15 @@ module.exports = {
|
|||||||
'#supports-color': '<rootDir>/node_modules/supports-color/index.js'
|
'#supports-color': '<rootDir>/node_modules/supports-color/index.js'
|
||||||
},
|
},
|
||||||
transform: {
|
transform: {
|
||||||
'^.+\\.(ts|tsx|js|jsx)$': [
|
'^.+\\.tsx?$': ['ts-jest', {
|
||||||
'ts-jest',
|
|
||||||
{
|
|
||||||
useESM: true,
|
useESM: true,
|
||||||
tsconfig: 'tsconfig.json'
|
}],
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
transformIgnorePatterns: [
|
transformIgnorePatterns: [
|
||||||
'node_modules/(?!(@digital-alchemy|chalk|#ansi-styles|#supports-color)/)'
|
'node_modules/(?!(@digital-alchemy|chalk|#ansi-styles|#supports-color)/)'
|
||||||
],
|
],
|
||||||
resolver: '<rootDir>/jest-resolver.cjs',
|
resolver: '<rootDir>/jest-resolver.cjs',
|
||||||
testMatch: ['**/__tests__/**/*.test.ts'],
|
testMatch: ['**/__tests__/**/*.test.ts'],
|
||||||
setupFilesAfterEnv: ['<rootDir>/jest.setup.cjs'],
|
|
||||||
globals: {
|
globals: {
|
||||||
'ts-jest': {
|
'ts-jest': {
|
||||||
useESM: true,
|
useESM: true,
|
||||||
@@ -36,9 +30,9 @@ module.exports = {
|
|||||||
coverageDirectory: 'coverage',
|
coverageDirectory: 'coverage',
|
||||||
coverageReporters: ['text', 'lcov', 'clover', 'html'],
|
coverageReporters: ['text', 'lcov', 'clover', 'html'],
|
||||||
collectCoverageFrom: [
|
collectCoverageFrom: [
|
||||||
'src/**/*.{ts,tsx}',
|
'src/**/*.ts',
|
||||||
'!src/**/*.d.ts',
|
'!src/**/*.d.ts',
|
||||||
'!src/**/*.test.{ts,tsx}',
|
'!src/**/*.test.ts',
|
||||||
'!src/types/**/*',
|
'!src/types/**/*',
|
||||||
'!src/polyfills.ts'
|
'!src/polyfills.ts'
|
||||||
],
|
],
|
||||||
@@ -49,5 +43,6 @@ module.exports = {
|
|||||||
lines: 80,
|
lines: 80,
|
||||||
statements: 80
|
statements: 80
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
verbose: true
|
||||||
};
|
};
|
||||||
15
jest.setup.ts
Normal file
15
jest.setup.ts
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import { config } from 'dotenv';
|
||||||
|
import { resolve } from 'path';
|
||||||
|
|
||||||
|
// Load test environment variables
|
||||||
|
const envFile = process.env.NODE_ENV === 'test' ? '.env.test' : '.env';
|
||||||
|
config({ path: resolve(__dirname, envFile) });
|
||||||
|
|
||||||
|
// Set default test environment variables if not provided
|
||||||
|
process.env.TEST_HASS_HOST = process.env.TEST_HASS_HOST || 'http://localhost:8123';
|
||||||
|
process.env.TEST_HASS_TOKEN = process.env.TEST_HASS_TOKEN || 'test_token';
|
||||||
|
process.env.TEST_HASS_SOCKET_URL = process.env.TEST_HASS_SOCKET_URL || 'ws://localhost:8123/api/websocket';
|
||||||
|
process.env.TEST_PORT = process.env.TEST_PORT || '3001';
|
||||||
|
|
||||||
|
// Ensure test environment
|
||||||
|
process.env.NODE_ENV = 'test';
|
||||||
Reference in New Issue
Block a user