> ## Documentation Index
> Fetch the complete documentation index at: https://docs.stateset.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Comprehensive Testing Guide

> Complete guide to testing StateSet API integrations including unit tests, integration tests, and end-to-end testing strategies

# Comprehensive Testing Guide

Testing is crucial for building reliable StateSet integrations. This guide covers testing strategies from unit tests to end-to-end scenarios, helping you build confidence in your integration.

## Testing Overview

<CardGroup cols={3}>
  <Card title="Unit Testing" icon="microscope">
    Test individual functions and components in isolation
  </Card>

  <Card title="Integration Testing" icon="link">
    Test interactions between your code and StateSet APIs
  </Card>

  <Card title="End-to-End Testing" icon="route">
    Test complete workflows from start to finish
  </Card>
</CardGroup>

## Test Environment Setup

### Testing Pyramid Strategy

```mermaid theme={null}
graph TD
    A[E2E Tests] --> B[Integration Tests]
    B --> C[Unit Tests]
    
    style A fill:#ff6b6b
    style B fill:#feca57
    style C fill:#48dbfb
```

### Environment Configuration

<Tabs>
  <Tab title="Node.js / Jest">
    ```javascript theme={null}
    // jest.config.js
    module.exports = {
      testEnvironment: 'node',
      setupFilesAfterEnv: ['<rootDir>/tests/setup.js'],
      testMatch: [
        '**/__tests__/**/*.test.js',
        '**/*.test.js'
      ],
      collectCoverageFrom: [
        'src/**/*.js',
        '!src/**/*.test.js',
        '!src/index.js'
      ],
      coverageThreshold: {
        global: {
          branches: 80,
          functions: 80,
          lines: 80,
          statements: 80
        }
      },
      testTimeout: 30000
    };

    // tests/setup.js
    import dotenv from 'dotenv';
    import { jest } from '@jest/globals';

    // Load test environment variables
    dotenv.config({ path: '.env.test' });

    // Global test setup
    beforeAll(() => {
      // Mock console methods in tests
      global.console = {
        ...console,
        log: jest.fn(),
        error: jest.fn(),
        warn: jest.fn(),
      };
    });

    afterAll(() => {
      // Cleanup after all tests
      jest.restoreAllMocks();
    });
    ```
  </Tab>

  <Tab title="Python / pytest">
    ```python theme={null}
    # pytest.ini
    [tool:pytest]
    minversion = 6.0
    addopts = 
        -ra
        --strict-markers
        --strict-config
        --cov=src
        --cov-report=term-missing
        --cov-report=html
        --cov-fail-under=80
    testpaths = tests
    python_files = test_*.py
    python_classes = Test*
    python_functions = test_*

    # conftest.py
    import pytest
    import os
    from unittest.mock import Mock
    from StateSet import StateSetClient

    @pytest.fixture(scope="session")
    def test_config():
        """Test configuration fixture."""
        return {
            'api_key': os.getenv('STATESET_TEST_API_KEY', 'sk_test_fake_key'),
            'base_url': 'https://api.sandbox.StateSet.com',
            'timeout': 30
        }

    @pytest.fixture
    def mock_client():
        """Mock StateSet client for unit tests."""
        return Mock(spec=StateSetClient)

    @pytest.fixture
    def real_client(test_config):
        """Real StateSet client for integration tests."""
        return StateSetClient(**test_config)

    @pytest.fixture(autouse=True)
    def cleanup_test_data():
        """Cleanup test data after each test."""
        yield
        # Add cleanup logic here
        pass
    ```
  </Tab>

  <Tab title="Ruby / RSpec">
    ```ruby theme={null}
    # spec/spec_helper.rb
    require 'bundler/setup'
    require 'StateSet'
    require 'webmock/rspec'
    require 'vcr'

    # Configure VCR for HTTP recording
    VCR.configure do |config|
      config.cassette_library_dir = 'spec/vcr_cassettes'
      config.hook_into :webmock
      config.configure_rspec_metadata!
      config.filter_sensitive_data('<STATESET_API_KEY>') { ENV['STATESET_API_KEY'] }
    end

    RSpec.configure do |config|
      config.expect_with :rspec do |expectations|
        expectations.include_chain_clauses_in_custom_matcher_descriptions = true
      end

      config.mock_with :rspec do |mocks|
        mocks.verify_partial_doubles = true
      end

      config.shared_context_metadata_behavior = :apply_to_host_groups
      
      # Test environment setup
      config.before(:suite) do
        StateSet.configure do |StateSet_config|
          StateSet_config.api_key = ENV['STATESET_TEST_API_KEY'] || 'sk_test_fake'
          StateSet_config.environment = 'test'
        end
      end
    end
    ```
  </Tab>
</Tabs>

## Unit Testing

### Testing Individual Functions

<Tabs>
  <Tab title="Node.js">
    ```javascript theme={null}
    // src/orderProcessor.js
    import { StateSetClient } from 'StateSet-node';
    import winston from 'winston';

    export class OrderProcessor {
      constructor(client, logger = winston.createLogger()) {
        this.client = client;
        this.logger = logger;
      }

      async processOrder(orderData) {
        try {
          // Validate order data
          const validation = this.validateOrder(orderData);
          if (!validation.isValid) {
            throw new Error(`Validation failed: ${validation.errors.join(', ')}`);
          }

          // Create order
          const order = await this.client.orders.create(orderData);
          
          this.logger.info('Order processed successfully', { orderId: order.id });
          return order;
        } catch (error) {
          this.logger.error('Order processing failed', { error: error.message });
          throw error;
        }
      }

      validateOrder(orderData) {
        const errors = [];
        
        if (!orderData.customer_email) {
          errors.push('Customer email is required');
        }
        
        if (!orderData.items || orderData.items.length === 0) {
          errors.push('Order must contain at least one item');
        }
        
        if (orderData.items) {
          orderData.items.forEach((item, index) => {
            if (!item.sku) errors.push(`Item ${index}: SKU is required`);
            if (!item.quantity || item.quantity <= 0) {
              errors.push(`Item ${index}: Quantity must be positive`);
            }
          });
        }
        
        return {
          isValid: errors.length === 0,
          errors
        };
      }
    }

    // __tests__/orderProcessor.test.js
    import { OrderProcessor } from '../src/orderProcessor.js';
    import { jest } from '@jest/globals';

    describe('OrderProcessor', () => {
      let orderProcessor;
      let mockClient;
      let mockLogger;

      beforeEach(() => {
        mockClient = {
          orders: {
            create: jest.fn()
          }
        };
        
        mockLogger = {
          info: jest.fn(),
          error: jest.fn()
        };
        
        orderProcessor = new OrderProcessor(mockClient, mockLogger);
      });

      describe('validateOrder', () => {
        it('should return valid for correct order data', () => {
          const orderData = {
            customer_email: 'test@example.com',
            items: [
              { sku: 'ITEM-001', quantity: 2 }
            ]
          };

          const result = orderProcessor.validateOrder(orderData);
          
          expect(result.isValid).toBe(true);
          expect(result.errors).toHaveLength(0);
        });

        it('should return invalid for missing email', () => {
          const orderData = {
            items: [{ sku: 'ITEM-001', quantity: 2 }]
          };

          const result = orderProcessor.validateOrder(orderData);
          
          expect(result.isValid).toBe(false);
          expect(result.errors).toContain('Customer email is required');
        });

        it('should return invalid for empty items', () => {
          const orderData = {
            customer_email: 'test@example.com',
            items: []
          };

          const result = orderProcessor.validateOrder(orderData);
          
          expect(result.isValid).toBe(false);
          expect(result.errors).toContain('Order must contain at least one item');
        });

        it('should validate individual items', () => {
          const orderData = {
            customer_email: 'test@example.com',
            items: [
              { sku: 'ITEM-001', quantity: 2 },
              { quantity: 1 }, // Missing SKU
              { sku: 'ITEM-003', quantity: -1 } // Invalid quantity
            ]
          };

          const result = orderProcessor.validateOrder(orderData);
          
          expect(result.isValid).toBe(false);
          expect(result.errors).toContain('Item 1: SKU is required');
          expect(result.errors).toContain('Item 2: Quantity must be positive');
        });
      });

      describe('processOrder', () => {
        it('should create order successfully', async () => {
          const orderData = {
            customer_email: 'test@example.com',
            items: [{ sku: 'ITEM-001', quantity: 2 }]
          };
          
          const expectedOrder = { id: 'order_123', ...orderData };
          mockClient.orders.create.mockResolvedValue(expectedOrder);

          const result = await orderProcessor.processOrder(orderData);

          expect(mockClient.orders.create).toHaveBeenCalledWith(orderData);
          expect(mockLogger.info).toHaveBeenCalledWith(
            'Order processed successfully',
            { orderId: 'order_123' }
          );
          expect(result).toEqual(expectedOrder);
        });

        it('should throw error for invalid order data', async () => {
          const orderData = { items: [] }; // Invalid data

          await expect(orderProcessor.processOrder(orderData)).rejects.toThrow(
            'Validation failed'
          );
          
          expect(mockClient.orders.create).not.toHaveBeenCalled();
          expect(mockLogger.error).toHaveBeenCalled();
        });

        it('should handle API errors', async () => {
          const orderData = {
            customer_email: 'test@example.com',
            items: [{ sku: 'ITEM-001', quantity: 2 }]
          };
          
          const apiError = new Error('API Error');
          mockClient.orders.create.mockRejectedValue(apiError);

          await expect(orderProcessor.processOrder(orderData)).rejects.toThrow('API Error');
          
          expect(mockLogger.error).toHaveBeenCalledWith(
            'Order processing failed',
            { error: 'API Error' }
          );
        });
      });
    });
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    # src/order_processor.py
    import logging
    from typing import Dict, List, Any
    from StateSet import StateSetClient

    class OrderProcessor:
        def __init__(self, client: StateSetClient, logger=None):
            self.client = client
            self.logger = logger or logging.getLogger(__name__)

        async def process_order(self, order_data: Dict[str, Any]) -> Dict[str, Any]:
            try:
                # Validate order data
                validation = self.validate_order(order_data)
                if not validation['is_valid']:
                    raise ValueError(f"Validation failed: {', '.join(validation['errors'])}")

                # Create order
                order = await self.client.orders.create(order_data)
                
                self.logger.info(f'Order processed successfully: {order["id"]}')
                return order
            except Exception as error:
                self.logger.error(f'Order processing failed: {str(error)}')
                raise

        def validate_order(self, order_data: Dict[str, Any]) -> Dict[str, Any]:
            errors = []
            
            if not order_data.get('customer_email'):
                errors.append('Customer email is required')
            
            items = order_data.get('items', [])
            if not items:
                errors.append('Order must contain at least one item')
            
            for index, item in enumerate(items):
                if not item.get('sku'):
                    errors.append(f'Item {index}: SKU is required')
                if not item.get('quantity') or item.get('quantity') <= 0:
                    errors.append(f'Item {index}: Quantity must be positive')
            
            return {
                'is_valid': len(errors) == 0,
                'errors': errors
            }

    # tests/test_order_processor.py
    import pytest
    from unittest.mock import AsyncMock, Mock
    from src.order_processor import OrderProcessor

    class TestOrderProcessor:
        @pytest.fixture
        def mock_client(self):
            client = Mock()
            client.orders = Mock()
            client.orders.create = AsyncMock()
            return client

        @pytest.fixture
        def mock_logger(self):
            return Mock()

        @pytest.fixture
        def order_processor(self, mock_client, mock_logger):
            return OrderProcessor(mock_client, mock_logger)

        def test_validate_order_valid_data(self, order_processor):
            order_data = {
                'customer_email': 'test@example.com',
                'items': [{'sku': 'ITEM-001', 'quantity': 2}]
            }

            result = order_processor.validate_order(order_data)
            
            assert result['is_valid'] is True
            assert len(result['errors']) == 0

        def test_validate_order_missing_email(self, order_processor):
            order_data = {
                'items': [{'sku': 'ITEM-001', 'quantity': 2}]
            }

            result = order_processor.validate_order(order_data)
            
            assert result['is_valid'] is False
            assert 'Customer email is required' in result['errors']

        def test_validate_order_empty_items(self, order_processor):
            order_data = {
                'customer_email': 'test@example.com',
                'items': []
            }

            result = order_processor.validate_order(order_data)
            
            assert result['is_valid'] is False
            assert 'Order must contain at least one item' in result['errors']

        def test_validate_order_invalid_items(self, order_processor):
            order_data = {
                'customer_email': 'test@example.com',
                'items': [
                    {'sku': 'ITEM-001', 'quantity': 2},
                    {'quantity': 1},  # Missing SKU
                    {'sku': 'ITEM-003', 'quantity': -1}  # Invalid quantity
                ]
            }

            result = order_processor.validate_order(order_data)
            
            assert result['is_valid'] is False
            assert 'Item 1: SKU is required' in result['errors']
            assert 'Item 2: Quantity must be positive' in result['errors']

        @pytest.mark.asyncio
        async def test_process_order_success(self, order_processor, mock_client, mock_logger):
            order_data = {
                'customer_email': 'test@example.com',
                'items': [{'sku': 'ITEM-001', 'quantity': 2}]
            }
            
            expected_order = {'id': 'order_123', **order_data}
            mock_client.orders.create.return_value = expected_order

            result = await order_processor.process_order(order_data)

            mock_client.orders.create.assert_called_once_with(order_data)
            mock_logger.info.assert_called_once_with('Order processed successfully: order_123')
            assert result == expected_order

        @pytest.mark.asyncio
        async def test_process_order_validation_error(self, order_processor, mock_client):
            order_data = {'items': []}  # Invalid data

            with pytest.raises(ValueError, match='Validation failed'):
                await order_processor.process_order(order_data)
            
            mock_client.orders.create.assert_not_called()

        @pytest.mark.asyncio
        async def test_process_order_api_error(self, order_processor, mock_client, mock_logger):
            order_data = {
                'customer_email': 'test@example.com',
                'items': [{'sku': 'ITEM-001', 'quantity': 2}]
            }
            
            mock_client.orders.create.side_effect = Exception('API Error')

            with pytest.raises(Exception, match='API Error'):
                await order_processor.process_order(order_data)
            
            mock_logger.error.assert_called_once_with('Order processing failed: API Error')
    ```
  </Tab>
</Tabs>

## Integration Testing

### Testing API Interactions

<Tabs>
  <Tab title="Node.js">
    ```javascript theme={null}
    // __tests__/integration/orders.integration.test.js
    import { StateSetClient } from 'StateSet-node';
    import { OrderProcessor } from '../../src/orderProcessor.js';

    describe('Orders Integration Tests', () => {
      let client;
      let orderProcessor;
      let createdOrderIds = [];

      beforeAll(() => {
        client = new StateSetClient({
          apiKey: process.env.STATESET_TEST_API_KEY,
          environment: 'sandbox'
        });
        orderProcessor = new OrderProcessor(client);
      });

      afterAll(async () => {
        // Cleanup created orders
        for (const orderId of createdOrderIds) {
          try {
            await client.orders.delete(orderId);
          } catch (error) {
            console.warn(`Failed to cleanup order ${orderId}:`, error.message);
          }
        }
      });

      it('should create and retrieve an order', async () => {
        const orderData = {
          customer_email: 'integration-test@example.com',
          items: [
            {
              sku: 'TEST-ITEM-001',
              quantity: 2,
              price: 1999
            }
          ],
          shipping_address: {
            line1: '123 Test Street',
            city: 'Test City',
            state: 'CA',
            postal_code: '90210',
            country: 'US'
          }
        };

        // Create order
        const createdOrder = await orderProcessor.processOrder(orderData);
        createdOrderIds.push(createdOrder.id);

        expect(createdOrder.id).toBeDefined();
        expect(createdOrder.customer_email).toBe(orderData.customer_email);
        expect(createdOrder.status).toBe('pending');

        // Retrieve order
        const retrievedOrder = await client.orders.get(createdOrder.id);
        expect(retrievedOrder.id).toBe(createdOrder.id);
        expect(retrievedOrder.customer_email).toBe(orderData.customer_email);
      });

      it('should handle order status updates', async () => {
        const orderData = {
          customer_email: 'status-test@example.com',
          items: [{ sku: 'TEST-ITEM-002', quantity: 1, price: 999 }],
          shipping_address: {
            line1: '456 Status Street',
            city: 'Status City',
            state: 'NY',
            postal_code: '10001',
            country: 'US'
          }
        };

        const order = await orderProcessor.processOrder(orderData);
        createdOrderIds.push(order.id);

        // Update order status
        const updatedOrder = await client.orders.update(order.id, {
          status: 'confirmed'
        });

        expect(updatedOrder.status).toBe('confirmed');

        // Verify status change
        const retrievedOrder = await client.orders.get(order.id);
        expect(retrievedOrder.status).toBe('confirmed');
      });

      it('should handle order cancellation', async () => {
        const orderData = {
          customer_email: 'cancel-test@example.com',
          items: [{ sku: 'TEST-ITEM-003', quantity: 1, price: 1500 }],
          shipping_address: {
            line1: '789 Cancel Street',
            city: 'Cancel City',
            state: 'TX',
            postal_code: '75001',
            country: 'US'
          }
        };

        const order = await orderProcessor.processOrder(orderData);
        createdOrderIds.push(order.id);

        // Cancel order
        const cancelledOrder = await client.orders.cancel(order.id, {
          reason: 'Customer requested cancellation'
        });

        expect(cancelledOrder.status).toBe('cancelled');
        expect(cancelledOrder.cancellation_reason).toBe('Customer requested cancellation');
      });

      it('should handle API errors gracefully', async () => {
        const invalidOrderData = {
          customer_email: 'invalid-test@example.com',
          items: [
            {
              sku: 'INVALID-SKU-THAT-DOES-NOT-EXIST',
              quantity: 1,
              price: 999
            }
          ]
        };

        await expect(orderProcessor.processOrder(invalidOrderData)).rejects.toThrow();
      });

      it('should handle rate limiting', async () => {
        const requests = [];
        
        // Make multiple concurrent requests to test rate limiting
        for (let i = 0; i < 10; i++) {
          requests.push(
            client.orders.list({ limit: 1 })
          );
        }

        const results = await Promise.allSettled(requests);
        
        // At least some requests should succeed
        const successful = results.filter(r => r.status === 'fulfilled');
        expect(successful.length).toBeGreaterThan(0);
        
        // Check if any were rate limited
        const rateLimited = results.filter(
          r => r.status === 'rejected' && r.reason.status === 429
        );
        
        if (rateLimited.length > 0) {
          logger.info(`${rateLimited.length} requests were rate limited (expected behavior);`);
        }
      });
    });
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    # tests/integration/test_orders_integration.py
    import pytest
    import asyncio
    from StateSet import StateSetClient
    from src.order_processor import OrderProcessor

    @pytest.mark.integration
    class TestOrdersIntegration:
        @pytest.fixture(scope="class")
        async def client(self):
            return StateSetClient(
                api_key=os.getenv('STATESET_TEST_API_KEY'),
                environment='sandbox'
            )

        @pytest.fixture(scope="class")
        async def order_processor(self, client):
            return OrderProcessor(client)

        @pytest.fixture
        def order_data(self):
            return {
                'customer_email': 'integration-test@example.com',
                'items': [
                    {
                        'sku': 'TEST-ITEM-001',
                        'quantity': 2,
                        'price': 1999
                    }
                ],
                'shipping_address': {
                    'line1': '123 Test Street',
                    'city': 'Test City',
                    'state': 'CA',
                    'postal_code': '90210',
                    'country': 'US'
                }
            }

        @pytest.mark.asyncio
        async def test_create_and_retrieve_order(self, order_processor, client, order_data):
            # Create order
            created_order = await order_processor.process_order(order_data)
            
            assert created_order['id'] is not None
            assert created_order['customer_email'] == order_data['customer_email']
            assert created_order['status'] == 'pending'

            # Retrieve order
            retrieved_order = await client.orders.get(created_order['id'])
            assert retrieved_order['id'] == created_order['id']
            assert retrieved_order['customer_email'] == order_data['customer_email']

            # Cleanup
            await client.orders.delete(created_order['id'])

        @pytest.mark.asyncio
        async def test_order_status_updates(self, order_processor, client, order_data):
            order_data['customer_email'] = 'status-test@example.com'
            
            order = await order_processor.process_order(order_data)
            
            # Update order status
            updated_order = await client.orders.update(order['id'], {
                'status': 'confirmed'
            })
            
            assert updated_order['status'] == 'confirmed'

            # Verify status change
            retrieved_order = await client.orders.get(order['id'])
            assert retrieved_order['status'] == 'confirmed'

            # Cleanup
            await client.orders.delete(order['id'])

        @pytest.mark.asyncio
        async def test_rate_limiting_handling(self, client):
            # Make multiple concurrent requests
            tasks = [client.orders.list(limit=1) for _ in range(10)]
            results = await asyncio.gather(*tasks, return_exceptions=True)
            
            # At least some should succeed
            successful = [r for r in results if not isinstance(r, Exception)]
            assert len(successful) > 0
            
            # Check for rate limiting
            rate_limited = [r for r in results if isinstance(r, Exception) and getattr(r, 'status', None) == 429]
            
            if rate_limited:
                print(f"{len(rate_limited)} requests were rate limited (expected)")
    ```
  </Tab>
</Tabs>

## End-to-End Testing

### Complete Workflow Testing

<Tabs>
  <Tab title="Playwright (Node.js)">
    ```javascript theme={null}
    // tests/e2e/order-workflow.e2e.test.js
    import { test, expect } from '@playwright/test';
    import { StateSetClient } from 'StateSet-node';

    test.describe('Complete Order Workflow', () => {
      let client;
      let testOrderId;

      test.beforeAll(async () => {
        client = new StateSetClient({
          apiKey: process.env.STATESET_TEST_API_KEY,
          environment: 'sandbox'
        });
      });

      test.afterAll(async () => {
        // Cleanup
        if (testOrderId) {
          try {
            await client.orders.delete(testOrderId);
          } catch (error) {
            console.warn('Failed to cleanup test order:', error.message);
          }
        }
      });

      test('should complete full order lifecycle', async ({ page }) => {
        // 1. Create order via API
        const orderData = {
          customer_email: 'e2e-test@example.com',
          items: [
            {
              sku: 'E2E-TEST-ITEM',
              quantity: 1,
              price: 2999,
              name: 'E2E Test Product'
            }
          ],
          shipping_address: {
            line1: '123 E2E Street',
            city: 'Test City',
            state: 'CA',
            postal_code: '90210',
            country: 'US'
          }
        };

        const order = await client.orders.create(orderData);
        testOrderId = order.id;
        
        expect(order.status).toBe('pending');

        // 2. Navigate to order management dashboard
        await page.goto(`${process.env.DASHBOARD_URL}/orders/${order.id}`);
        
        // 3. Verify order details in UI
        await expect(page.locator('[data-testid="order-id"]')).toContainText(order.id);
        await expect(page.locator('[data-testid="customer-email"]')).toContainText('e2e-test@example.com');
        await expect(page.locator('[data-testid="order-status"]')).toContainText('pending');

        // 4. Process order through UI
        await page.click('[data-testid="confirm-order-btn"]');
        await page.waitForSelector('[data-testid="order-status"]:has-text("confirmed")');

        // 5. Verify status change via API
        const updatedOrder = await client.orders.get(order.id);
        expect(updatedOrder.status).toBe('confirmed');

        // 6. Ship order
        await page.click('[data-testid="ship-order-btn"]');
        await page.fill('[data-testid="tracking-number"]', 'TEST-TRACKING-123');
        await page.click('[data-testid="confirm-shipment-btn"]');
        
        await page.waitForSelector('[data-testid="order-status"]:has-text("shipped")');

        // 7. Verify final status
        const shippedOrder = await client.orders.get(order.id);
        expect(shippedOrder.status).toBe('shipped');
        expect(shippedOrder.tracking_number).toBe('TEST-TRACKING-123');

        // 8. Check customer notification
        const notifications = await client.notifications.list({
          order_id: order.id,
          type: 'shipment'
        });
        
        expect(notifications.data.length).toBeGreaterThan(0);
        expect(notifications.data[0].recipient_email).toBe('e2e-test@example.com');
      });

      test('should handle order cancellation workflow', async ({ page }) => {
        // Create order
        const orderData = {
          customer_email: 'cancel-e2e-test@example.com',
          items: [{ sku: 'CANCEL-TEST-ITEM', quantity: 1, price: 1999 }],
          shipping_address: {
            line1: '456 Cancel Street',
            city: 'Cancel City',
            state: 'NY',
            postal_code: '10001',
            country: 'US'
          }
        };

        const order = await client.orders.create(orderData);
        testOrderId = order.id;

        // Navigate to order
        await page.goto(`${process.env.DASHBOARD_URL}/orders/${order.id}`);

        // Cancel order through UI
        await page.click('[data-testid="cancel-order-btn"]');
        await page.fill('[data-testid="cancellation-reason"]', 'Customer requested cancellation');
        await page.click('[data-testid="confirm-cancellation-btn"]');

        // Wait for status update
        await page.waitForSelector('[data-testid="order-status"]:has-text("cancelled")');

        // Verify via API
        const cancelledOrder = await client.orders.get(order.id);
        expect(cancelledOrder.status).toBe('cancelled');
        expect(cancelledOrder.cancellation_reason).toBe('Customer requested cancellation');
      });
    });
    ```
  </Tab>

  <Tab title="Cypress">
    ```javascript theme={null}
    // cypress/e2e/order-management.cy.js
    describe('Order Management E2E', () => {
      let testOrderId;

      beforeEach(() => {
        // Login to dashboard
        cy.login();
      });

      afterEach(() => {
        // Cleanup test orders
        if (testOrderId) {
          cy.cleanupOrder(testOrderId);
        }
      });

      it('should create and manage order through complete lifecycle', () => {
        // Create order via API
        cy.createTestOrder().then((order) => {
          testOrderId = order.id;
          
          // Visit order details page
          cy.visit(`/orders/${order.id}`);
          
          // Verify order details
          cy.get('[data-cy="order-id"]').should('contain', order.id);
          cy.get('[data-cy="order-status"]').should('contain', 'pending');
          cy.get('[data-cy="customer-email"]').should('contain', order.customer_email);
          
          // Confirm order
          cy.get('[data-cy="confirm-order"]').click();
          cy.get('[data-cy="order-status"]').should('contain', 'confirmed');
          
          // Add shipping information
          cy.get('[data-cy="add-shipping"]').click();
          cy.get('[data-cy="tracking-number"]').type('CY-TEST-123');
          cy.get('[data-cy="carrier"]').select('UPS');
          cy.get('[data-cy="submit-shipping"]').click();
          
          // Verify shipping status
          cy.get('[data-cy="order-status"]').should('contain', 'shipped');
          cy.get('[data-cy="tracking-number"]').should('contain', 'CY-TEST-123');
          
          // Verify API state
          cy.verifyOrderStatus(order.id, 'shipped');
        });
      });

      it('should handle order search and filtering', () => {
        // Create multiple test orders
        cy.createMultipleTestOrders(5).then((orders) => {
          orders.forEach(order => testOrderId = order.id); // Keep last for cleanup
          
          cy.visit('/orders');
          
          // Test search functionality
          cy.get('[data-cy="order-search"]').type(orders[0].customer_email);
          cy.get('[data-cy="search-results"]').should('contain', orders[0].id);
          
          // Test status filtering
          cy.get('[data-cy="status-filter"]').select('pending');
          cy.get('[data-cy="order-list"] tr').should('have.length.at.least', 1);
          
          // Test date range filtering
          cy.get('[data-cy="date-from"]').type('2023-01-01');
          cy.get('[data-cy="date-to"]').type('2023-12-31');
          cy.get('[data-cy="apply-filters"]').click();
          
          cy.get('[data-cy="order-list"]').should('be.visible');
        });
      });
    });

    // cypress/support/commands.js
    Cypress.Commands.add('login', () => {
      cy.session('login', () => {
        cy.visit('/login');
        cy.get('[data-cy="email"]').type(Cypress.env('TEST_USER_EMAIL'));
        cy.get('[data-cy="password"]').type(Cypress.env('TEST_USER_PASSWORD'));
        cy.get('[data-cy="login-button"]').click();
        cy.url().should('include', '/dashboard');
      });
    });

    Cypress.Commands.add('createTestOrder', () => {
      return cy.request({
        method: 'POST',
        url: `${Cypress.env('API_BASE_URL')}/orders`,
        headers: {
          'Authorization': `Bearer ${Cypress.env('STATESET_API_KEY')}`,
          'Content-Type': 'application/json'
        },
        body: {
          customer_email: 'cypress-test@example.com',
          items: [
            {
              sku: 'CY-TEST-ITEM',
              quantity: 1,
              price: 2999
            }
          ],
          shipping_address: {
            line1: '123 Cypress Street',
            city: 'Test City',
            state: 'CA',
            postal_code: '90210',
            country: 'US'
          }
        }
      }).then((response) => response.body);
    });

    Cypress.Commands.add('verifyOrderStatus', (orderId, expectedStatus) => {
      cy.request({
        method: 'GET',
        url: `${Cypress.env('API_BASE_URL')}/orders/${orderId}`,
        headers: {
          'Authorization': `Bearer ${Cypress.env('STATESET_API_KEY')}`
        }
      }).then((response) => {
        expect(response.body.status).to.equal(expectedStatus);
      });
    });

    Cypress.Commands.add('cleanupOrder', (orderId) => {
      cy.request({
        method: 'DELETE',
        url: `${Cypress.env('API_BASE_URL')}/orders/${orderId}`,
        headers: {
          'Authorization': `Bearer ${Cypress.env('STATESET_API_KEY')}`
        },
        failOnStatusCode: false
      });
    });
    ```
  </Tab>
</Tabs>

## Performance Testing

### Load Testing with Artillery

```yaml theme={null}
# artillery-config.yml
config:
  target: 'https://api.sandbox.StateSet.com'
  phases:
    - duration: 60
      arrivalRate: 5
      name: "Warm up"
    - duration: 120
      arrivalRate: 10
      name: "Load test"
    - duration: 60
      arrivalRate: 20
      name: "Stress test"
  variables:
    api_key: "{{ $env.STATESET_TEST_API_KEY }}"
  processor: "./test-helpers.js"

scenarios:
  - name: "Order Management"
    weight: 70
    flow:
      - post:
          url: "/v1/orders"
          headers:
            Authorization: "Bearer {{ api_key }}"
            Content-Type: "application/json"
          json:
            customer_email: "load-test-{{ $randomString() }}@example.com"
            items:
              - sku: "LOAD-TEST-ITEM"
                quantity: "{{ $randomInt(1, 5) }}"
                price: 1999
            shipping_address:
              line1: "123 Load Test St"
              city: "Test City"
              state: "CA"
              postal_code: "90210"
              country: "US"
          capture:
            - json: "$.id"
              as: "orderId"
      - get:
          url: "/v1/orders/{{ orderId }}"
          headers:
            Authorization: "Bearer {{ api_key }}"
      - put:
          url: "/v1/orders/{{ orderId }}"
          headers:
            Authorization: "Bearer {{ api_key }}"
            Content-Type: "application/json"
          json:
            status: "confirmed"

  - name: "Order Listing"
    weight: 30
    flow:
      - get:
          url: "/v1/orders"
          qs:
            limit: "{{ $randomInt(10, 50) }}"
            status: "pending"
          headers:
            Authorization: "Bearer {{ api_key }}"
```

### Stress Testing

```javascript theme={null}
// stress-test.js
import { StateSetClient } from 'StateSet-node';
import { performance } from 'perf_hooks';

class StressTest {
  constructor() {
    this.client = new StateSetClient({
      apiKey: process.env.STATESET_TEST_API_KEY,
      environment: 'sandbox'
    });
    this.metrics = {
      requests: 0,
      errors: 0,
      latencies: []
    };
  }

  async runConcurrentOrders(concurrency = 10, duration = 60000) {
    logger.info(`Starting stress test: ${concurrency} concurrent users for ${duration}ms`);
    
    const startTime = Date.now();
    const workers = [];

    // Start concurrent workers
    for (let i = 0; i < concurrency; i++) {
      workers.push(this.orderWorker(startTime + duration));
    }

    // Wait for all workers to complete
    await Promise.all(workers);

    // Calculate results
    const totalDuration = Date.now() - startTime;
    const avgLatency = this.metrics.latencies.reduce((a, b) => a + b, 0) / this.metrics.latencies.length;
    const errorRate = (this.metrics.errors / this.metrics.requests) * 100;
    const throughput = this.metrics.requests / (totalDuration / 1000);

    logger.info('Stress Test Results:');
    logger.info(`Total Requests: ${this.metrics.requests}`);
    logger.info(`Errors: ${this.metrics.errors} (${errorRate.toFixed(2);}%)`);
    logger.info(`Average Latency: ${avgLatency.toFixed(2);}ms`);
    logger.info(`Throughput: ${throughput.toFixed(2);} req/sec`);
    
    return {
      requests: this.metrics.requests,
      errors: this.metrics.errors,
      errorRate,
      avgLatency,
      throughput
    };
  }

  async orderWorker(endTime) {
    while (Date.now() < endTime) {
      const start = performance.now();
      
      try {
        await this.createTestOrder();
        this.metrics.requests++;
        this.metrics.latencies.push(performance.now() - start);
      } catch (error) {
        this.metrics.errors++;
        logger.error('Order creation failed:', error.message);
      }

      // Small delay to prevent overwhelming
      await new Promise(resolve => setTimeout(resolve, 100));
    }
  }

  async createTestOrder() {
    const orderData = {
      customer_email: `stress-test-${Date.now()}@example.com`,
      items: [
        {
          sku: 'STRESS-TEST-ITEM',
          quantity: Math.floor(Math.random() * 5) + 1,
          price: Math.floor(Math.random() * 5000) + 1000
        }
      ],
      shipping_address: {
        line1: '123 Stress Test Street',
        city: 'Test City',
        state: 'CA',
        postal_code: '90210',
        country: 'US'
      }
    };

    return this.client.orders.create(orderData);
  }
}

// Run stress test
const stressTest = new StressTest();
stressTest.runConcurrentOrders(20, 120000) // 20 concurrent users for 2 minutes
  .then(results => {
    logger.info('Stress test completed successfully');
    process.exit(0);
  })
  .catch(error => {
    logger.error('Stress test failed:', error);
    process.exit(1);
  });
```

## Testing Best Practices

<CardGroup cols={2}>
  <Card title="Test Organization" icon="folder-tree">
    * Separate unit, integration, and E2E tests
    * Use descriptive test names
    * Group related tests together
    * Follow AAA pattern (Arrange, Act, Assert)
  </Card>

  <Card title="Test Data Management" icon="database">
    * Use factories for test data generation
    * Clean up test data after tests
    * Use isolated test environments
    * Mock external dependencies
  </Card>
</CardGroup>

<CardGroup cols={2}>
  <Card title="CI/CD Integration" icon="gear">
    * Run tests on every commit
    * Separate fast and slow test suites
    * Use parallel test execution
    * Generate coverage reports
  </Card>

  <Card title="Monitoring & Alerting" icon="chart-line">
    * Monitor test execution times
    * Alert on test failures
    * Track test coverage trends
    * Performance regression detection
  </Card>
</CardGroup>

## Continuous Integration Setup

```yaml theme={null}
# .github/workflows/test.yml
name: Test Suite

on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main ]

jobs:
  unit-tests:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: '18'
          cache: 'npm'
      
      - run: npm ci
      - run: npm run test:unit
        env:
          STATESET_TEST_API_KEY: ${{ secrets.STATESET_TEST_API_KEY }}
      
      - name: Upload coverage reports
        uses: codecov/codecov-action@v3

  integration-tests:
    runs-on: ubuntu-latest
    needs: unit-tests
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: '18'
          cache: 'npm'
      
      - run: npm ci
      - run: npm run test:integration
        env:
          STATESET_TEST_API_KEY: ${{ secrets.STATESET_TEST_API_KEY }}

  e2e-tests:
    runs-on: ubuntu-latest
    needs: integration-tests
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: '18'
          cache: 'npm'
      
      - run: npm ci
      - run: npx playwright install
      - run: npm run test:e2e
        env:
          STATESET_TEST_API_KEY: ${{ secrets.STATESET_TEST_API_KEY }}
          DASHBOARD_URL: ${{ secrets.DASHBOARD_URL }}
```

## Next Steps

After implementing comprehensive testing:

1. **Monitor Test Metrics**: Track coverage, execution time, and flakiness
2. **Expand Test Scenarios**: Add edge cases and error conditions
3. **Performance Baselines**: Establish performance benchmarks
4. **Test Automation**: Integrate with deployment pipelines

For more testing strategies, see:

* [Error Handling Best Practices](/guides/error-handling-best-practices)
* [Performance Optimization](/guides/performance-optimization)
* [API Rate Limiting](/guides/api-rate-limiting)
