Examples & Best Practices - Session Initialization
Real-world examples and best practices for RKT Chat Client session initialization
Examples & Best Practices
This guide provides real-world examples and best practices for implementing session initialization in various scenarios.
Basic Examples
Simple Chat Widget
A minimal chat widget with session initialization:
import React, { useState } from 'react';
import { useChat } from '@rkt/rkt-chat-client';
const SimpleChatWidget: React.FC = () => {
  const [isOpen, setIsOpen] = useState(false);
  
  const {
    sessionId,
    isSessionReady,
    messages,
    sendMessage,
    isChatLoading,
  } = useChat({
    chatbot: {
      id: 'support-chatbot',
      prompt: 'You are a helpful customer support assistant.',
    },
    baseUrl: 'https://api.example.com/chat',
  });
  if (!isSessionReady) {
    return (
      <div className="fixed bottom-4 right-4 w-12 h-12 bg-blue-500 rounded-full flex items-center justify-center">
        <div className="animate-spin w-6 h-6 border-2 border-white border-t-transparent rounded-full"></div>
      </div>
    );
  }
  return (
    <div className="fixed bottom-4 right-4">
      {!isOpen ? (
        <button
          onClick={() => setIsOpen(true)}
          className="w-12 h-12 bg-blue-500 text-white rounded-full shadow-lg hover:bg-blue-600 transition-colors"
        >
          💬
        </button>
      ) : (
        <div className="w-80 h-96 bg-white border rounded-lg shadow-lg flex flex-col">
          <div className="p-4 border-b flex justify-between items-center">
            <h3 className="font-semibold">Support Chat</h3>
            <button
              onClick={() => setIsOpen(false)}
              className="text-gray-500 hover:text-gray-700"
            >
              ✕
            </button>
          </div>
          
          <div className="flex-1 p-4 overflow-y-auto">
            {messages.map((message, index) => (
              <div key={index} className={`mb-2 ${message.role === 'user' ? 'text-right' : 'text-left'}`}>
                <div className={`inline-block p-2 rounded ${
                  message.role === 'user' 
                    ? 'bg-blue-500 text-white' 
                    : 'bg-gray-100 text-gray-800'
                }`}>
                  {message.content}
                </div>
              </div>
            ))}
            {isChatLoading && (
              <div className="text-center text-gray-500">
                <div className="animate-pulse">Typing...</div>
              </div>
            )}
          </div>
          
          <div className="p-4 border-t">
            <div className="flex gap-2">
              <input
                type="text"
                placeholder="Type your message..."
                className="flex-1 p-2 border rounded"
                onKeyPress={(e) => {
                  if (e.key === 'Enter') {
                    sendMessage(e.currentTarget.value);
                    e.currentTarget.value = '';
                  }
                }}
                disabled={isChatLoading}
              />
              <button
                onClick={() => {
                  const input = document.querySelector('input');
                  if (input?.value) {
                    sendMessage(input.value);
                    input.value = '';
                  }
                }}
                disabled={isChatLoading}
                className="px-4 py-2 bg-blue-500 text-white rounded disabled:bg-gray-300"
              >
                Send
              </button>
            </div>
          </div>
        </div>
      )}
    </div>
  );
};
export default SimpleChatWidget;E-commerce Support Chat
A more sophisticated chat for e-commerce with user context:
import React, { useState, useEffect } from 'react';
import { useChat } from '@rkt/rkt-chat-client';
interface EcommerceChatProps {
  userId?: string;
  orderId?: string;
  productId?: string;
}
const EcommerceChat: React.FC<EcommerceChatProps> = ({ userId, orderId, productId }) => {
  const [userContext, setUserContext] = useState<any>(null);
  
  const {
    sessionId,
    isSessionReady,
    telemetryInitialized,
    messages,
    sendMessage,
    isChatLoading,
  } = useChat({
    chatbot: {
      id: 'ecommerce-support',
      prompt: `You are a helpful e-commerce support assistant. 
               User ID: ${userId || 'Guest'}
               Order ID: ${orderId || 'None'}
               Product ID: ${productId || 'None'}`,
    },
    baseUrl: 'https://api.example.com/chat',
    telemetry: {
      initializeSession: (data) => {
        // Send to analytics
        fetch('/api/analytics/session', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            ...data,
            userId,
            orderId,
            productId,
          }),
        });
      },
      trackEvent: (event, properties) => {
        // Track user interactions
        fetch('/api/analytics/events', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            event,
            properties: {
              ...properties,
              userId,
              sessionId,
            },
          }),
        });
      },
      trackError: (error, context) => {
        // Send to error tracking
        console.error('Chat error:', error, context);
      },
    },
    onReady: (sessionId) => {
      // Load user context when session is ready
      if (userId) {
        fetch(`/api/users/${userId}/context`)
          .then(res => res.json())
          .then(setUserContext)
          .catch(console.error);
      }
    },
  });
  const handleSendMessage = (message: string) => {
    // Add user context to message
    const enrichedMessage = userContext 
      ? `${message}\n\nUser Context: ${JSON.stringify(userContext)}`
      : message;
    
    sendMessage(enrichedMessage);
  };
  if (!isSessionReady) {
    return (
      <div className="flex items-center justify-center p-8">
        <div className="text-center">
          <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-500 mx-auto mb-2"></div>
          <p>Initializing support chat...</p>
          {telemetryInitialized && (
            <p className="text-sm text-gray-500">Analytics ready</p>
          )}
        </div>
      </div>
    );
  }
  return (
    <div className="max-w-4xl mx-auto p-6">
      <div className="bg-white border rounded-lg shadow-lg">
        <div className="p-4 border-b bg-gray-50">
          <h2 className="text-xl font-semibold">Customer Support</h2>
          <div className="text-sm text-gray-600 mt-1">
            Session: {sessionId} | User: {userId || 'Guest'}
          </div>
        </div>
        
        <div className="h-96 overflow-y-auto p-4">
          {messages.map((message, index) => (
            <div key={index} className={`mb-4 ${message.role === 'user' ? 'text-right' : 'text-left'}`}>
              <div className={`inline-block max-w-xs lg:max-w-md px-4 py-2 rounded-lg ${
                message.role === 'user' 
                  ? 'bg-blue-500 text-white' 
                  : 'bg-gray-100 text-gray-800'
              }`}>
                {message.content}
              </div>
            </div>
          ))}
          {isChatLoading && (
            <div className="text-center text-gray-500">
              <div className="animate-pulse">Support agent is typing...</div>
            </div>
          )}
        </div>
        
        <div className="p-4 border-t">
          <div className="flex gap-2">
            <input
              type="text"
              placeholder="Describe your issue..."
              className="flex-1 p-3 border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
              onKeyPress={(e) => {
                if (e.key === 'Enter' && e.currentTarget.value.trim()) {
                  handleSendMessage(e.currentTarget.value);
                  e.currentTarget.value = '';
                }
              }}
              disabled={isChatLoading}
            />
            <button
              onClick={() => {
                const input = document.querySelector('input');
                if (input?.value.trim()) {
                  handleSendMessage(input.value);
                  input.value = '';
                }
              }}
              disabled={isChatLoading}
              className="px-6 py-3 bg-blue-500 text-white rounded-lg hover:bg-blue-600 disabled:bg-gray-300 transition-colors"
            >
              Send
            </button>
          </div>
        </div>
      </div>
    </div>
  );
};
export default EcommerceChat;Advanced Examples
Multi-Tenant Chat System
A chat system that supports multiple tenants with different configurations:
import React, { useState, useEffect } from 'react';
import { useChat } from '@rkt/rkt-chat-client';
interface TenantConfig {
  id: string;
  name: string;
  chatbotId: string;
  apiUrl: string;
  theme: 'light' | 'dark';
  branding: {
    primaryColor: string;
    logo: string;
  };
}
interface MultiTenantChatProps {
  tenantId: string;
  userId?: string;
}
const MultiTenantChat: React.FC<MultiTenantChatProps> = ({ tenantId, userId }) => {
  const [tenantConfig, setTenantConfig] = useState<TenantConfig | null>(null);
  const [isLoading, setIsLoading] = useState(true);
  // Load tenant configuration
  useEffect(() => {
    fetch(`/api/tenants/${tenantId}/config`)
      .then(res => res.json())
      .then(setTenantConfig)
      .catch(console.error)
      .finally(() => setIsLoading(false));
  }, [tenantId]);
  const {
    sessionId,
    isSessionReady,
    telemetryInitialized,
    messages,
    sendMessage,
    isChatLoading,
  } = useChat({
    chatbot: {
      id: tenantConfig?.chatbotId,
      prompt: `You are a helpful assistant for ${tenantConfig?.name}. 
               Provide support and answer questions about their services.`,
    },
    baseUrl: tenantConfig?.apiUrl,
    telemetry: {
      initializeSession: (data) => {
        // Send to tenant-specific analytics
        fetch(`/api/tenants/${tenantId}/analytics/session`, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            ...data,
            tenantId,
            userId,
          }),
        });
      },
      trackEvent: (event, properties) => {
        fetch(`/api/tenants/${tenantId}/analytics/events`, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            event,
            properties: {
              ...properties,
              tenantId,
              userId,
              sessionId,
            },
          }),
        });
      },
      trackError: (error, context) => {
        // Send to tenant-specific error tracking
        fetch(`/api/tenants/${tenantId}/errors`, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            error: error.message,
            stack: error.stack,
            context: {
              ...context,
              tenantId,
              userId,
            },
          }),
        });
      },
    },
    onReady: (sessionId) => {
      console.log(`Chat ready for tenant ${tenantId}:`, sessionId);
    },
  });
  if (isLoading || !tenantConfig) {
    return (
      <div className="flex items-center justify-center p-8">
        <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-500"></div>
      </div>
    );
  }
  if (!isSessionReady) {
    return (
      <div className="flex items-center justify-center p-8">
        <div className="text-center">
          <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-500 mx-auto mb-2"></div>
          <p>Initializing {tenantConfig.name} chat...</p>
        </div>
      </div>
    );
  }
  return (
    <div 
      className="max-w-4xl mx-auto p-6"
      style={{ 
        '--primary-color': tenantConfig.branding.primaryColor 
      } as React.CSSProperties}
    >
      <div className={`border rounded-lg shadow-lg ${
        tenantConfig.theme === 'dark' ? 'bg-gray-800 text-white' : 'bg-white'
      }`}>
        <div className={`p-4 border-b ${
          tenantConfig.theme === 'dark' ? 'bg-gray-700' : 'bg-gray-50'
        }`}>
          <div className="flex items-center gap-3">
            <img 
              src={tenantConfig.branding.logo} 
              alt={tenantConfig.name}
              className="w-8 h-8 rounded"
            />
            <h2 className="text-xl font-semibold">{tenantConfig.name} Support</h2>
          </div>
          <div className="text-sm opacity-75 mt-1">
            Session: {sessionId} | Tenant: {tenantId}
          </div>
        </div>
        
        <div className="h-96 overflow-y-auto p-4">
          {messages.map((message, index) => (
            <div key={index} className={`mb-4 ${message.role === 'user' ? 'text-right' : 'text-left'}`}>
              <div 
                className={`inline-block max-w-xs lg:max-w-md px-4 py-2 rounded-lg ${
                  message.role === 'user' 
                    ? 'text-white' 
                    : tenantConfig.theme === 'dark' 
                      ? 'bg-gray-700 text-white' 
                      : 'bg-gray-100 text-gray-800'
                }`}
                style={{
                  backgroundColor: message.role === 'user' 
                    ? tenantConfig.branding.primaryColor 
                    : undefined
                }}
              >
                {message.content}
              </div>
            </div>
          ))}
          {isChatLoading && (
            <div className="text-center opacity-75">
              <div className="animate-pulse">Support agent is typing...</div>
            </div>
          )}
        </div>
        
        <div className="p-4 border-t">
          <div className="flex gap-2">
            <input
              type="text"
              placeholder="How can we help you?"
              className={`flex-1 p-3 border rounded-lg focus:ring-2 focus:ring-opacity-50 ${
                tenantConfig.theme === 'dark' 
                  ? 'bg-gray-700 border-gray-600 text-white focus:ring-white' 
                  : 'bg-white border-gray-300 focus:ring-blue-500'
              }`}
              onKeyPress={(e) => {
                if (e.key === 'Enter' && e.currentTarget.value.trim()) {
                  sendMessage(e.currentTarget.value);
                  e.currentTarget.value = '';
                }
              }}
              disabled={isChatLoading}
            />
            <button
              onClick={() => {
                const input = document.querySelector('input');
                if (input?.value.trim()) {
                  sendMessage(input.value);
                  input.value = '';
                }
              }}
              disabled={isChatLoading}
              className="px-6 py-3 text-white rounded-lg hover:opacity-90 disabled:opacity-50 transition-opacity"
              style={{ backgroundColor: tenantConfig.branding.primaryColor }}
            >
              Send
            </button>
          </div>
        </div>
      </div>
    </div>
  );
};
export default MultiTenantChat;Real-time Collaboration Chat
A chat system with real-time collaboration features:
import React, { useState, useEffect, useRef } from 'react';
import { useChat } from '@rkt/rkt-chat-client';
interface CollaborationChatProps {
  roomId: string;
  userId: string;
  userName: string;
}
const CollaborationChat: React.FC<CollaborationChatProps> = ({ 
  roomId, 
  userId, 
  userName 
}) => {
  const [typingUsers, setTypingUsers] = useState<string[]>([]);
  const [isTyping, setIsTyping] = useState(false);
  const typingTimeoutRef = useRef<NodeJS.Timeout>();
  
  const {
    sessionId,
    isSessionReady,
    messages,
    sendMessage,
    isChatLoading,
  } = useChat({
    chatbot: {
      id: 'collaboration-assistant',
      prompt: `You are a helpful assistant in a collaborative workspace. 
               Room ID: ${roomId}
               Current user: ${userName}
               Help users collaborate effectively.`,
    },
    baseUrl: 'https://api.example.com/chat',
    telemetry: {
      initializeSession: (data) => {
        // Join collaboration room
        fetch('/api/collaboration/join', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            ...data,
            roomId,
            userId,
            userName,
          }),
        });
      },
      trackEvent: (event, properties) => {
        // Track collaboration events
        fetch('/api/collaboration/events', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            event,
            properties: {
              ...properties,
              roomId,
              userId,
              sessionId,
            },
          }),
        });
      },
      trackError: (error, context) => {
        console.error('Collaboration chat error:', error, context);
      },
    },
    onReady: (sessionId) => {
      // Set up real-time collaboration
      const eventSource = new EventSource(`/api/collaboration/room/${roomId}/events`);
      
      eventSource.onmessage = (event) => {
        const data = JSON.parse(event.data);
        
        switch (data.type) {
          case 'user_typing':
            setTypingUsers(prev => {
              const filtered = prev.filter(user => user !== data.userName);
              return [...filtered, data.userName];
            });
            break;
          case 'user_stopped_typing':
            setTypingUsers(prev => prev.filter(user => user !== data.userName));
            break;
          case 'message':
            // Handle real-time messages if needed
            break;
        }
      };
      
      return () => eventSource.close();
    },
  });
  const handleTyping = (e: React.KeyboardEvent<HTMLInputElement>) => {
    if (!isTyping) {
      setIsTyping(true);
      fetch('/api/collaboration/typing', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          roomId,
          userId,
          userName,
          isTyping: true,
        }),
      });
    }
    // Clear existing timeout
    if (typingTimeoutRef.current) {
      clearTimeout(typingTimeoutRef.current);
    }
    // Set new timeout to stop typing
    typingTimeoutRef.current = setTimeout(() => {
      setIsTyping(false);
      fetch('/api/collaboration/typing', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          roomId,
          userId,
          userName,
          isTyping: false,
        }),
      });
    }, 1000);
  };
  const handleSendMessage = (message: string) => {
    // Stop typing indicator
    setIsTyping(false);
    if (typingTimeoutRef.current) {
      clearTimeout(typingTimeoutRef.current);
    }
    
    sendMessage(message);
  };
  if (!isSessionReady) {
    return (
      <div className="flex items-center justify-center p-8">
        <div className="text-center">
          <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-500 mx-auto mb-2"></div>
          <p>Joining collaboration room...</p>
        </div>
      </div>
    );
  }
  return (
    <div className="max-w-4xl mx-auto p-6">
      <div className="bg-white border rounded-lg shadow-lg">
        <div className="p-4 border-b bg-gray-50">
          <h2 className="text-xl font-semibold">Collaboration Chat</h2>
          <div className="text-sm text-gray-600 mt-1">
            Room: {roomId} | User: {userName} | Session: {sessionId}
          </div>
        </div>
        
        <div className="h-96 overflow-y-auto p-4">
          {messages.map((message, index) => (
            <div key={index} className={`mb-4 ${message.role === 'user' ? 'text-right' : 'text-left'}`}>
              <div className={`inline-block max-w-xs lg:max-w-md px-4 py-2 rounded-lg ${
                message.role === 'user' 
                  ? 'bg-blue-500 text-white' 
                  : 'bg-gray-100 text-gray-800'
              }`}>
                {message.content}
              </div>
            </div>
          ))}
          
          {typingUsers.length > 0 && (
            <div className="text-sm text-gray-500 italic">
              {typingUsers.join(', ')} {typingUsers.length === 1 ? 'is' : 'are'} typing...
            </div>
          )}
          
          {isChatLoading && (
            <div className="text-center text-gray-500">
              <div className="animate-pulse">AI is responding...</div>
            </div>
          )}
        </div>
        
        <div className="p-4 border-t">
          <div className="flex gap-2">
            <input
              type="text"
              placeholder="Type your message..."
              className="flex-1 p-3 border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
              onKeyPress={(e) => {
                if (e.key === 'Enter' && e.currentTarget.value.trim()) {
                  handleSendMessage(e.currentTarget.value);
                  e.currentTarget.value = '';
                }
              }}
              onKeyDown={handleTyping}
              disabled={isChatLoading}
            />
            <button
              onClick={() => {
                const input = document.querySelector('input');
                if (input?.value.trim()) {
                  handleSendMessage(input.value);
                  input.value = '';
                }
              }}
              disabled={isChatLoading}
              className="px-6 py-3 bg-blue-500 text-white rounded-lg hover:bg-blue-600 disabled:bg-gray-300 transition-colors"
            >
              Send
            </button>
          </div>
        </div>
      </div>
    </div>
  );
};
export default CollaborationChat;Best Practices
Error Handling
Always implement comprehensive error handling:
const useChatWithErrorHandling = (options) => {
  const [error, setError] = useState<string | null>(null);
  const [retryCount, setRetryCount] = useState(0);
  const chat = useChat({
    ...options,
    onError: (error) => {
      setError(error.message);
      console.error('Chat error:', error);
      
      // Implement retry logic
      if (retryCount < 3) {
        setTimeout(() => {
          setRetryCount(prev => prev + 1);
          setError(null);
        }, 1000 * Math.pow(2, retryCount));
      }
    },
  });
  return {
    ...chat,
    error,
    retryCount,
    clearError: () => setError(null),
  };
};Performance Optimization
Optimize for performance with proper memoization:
const OptimizedChatComponent = React.memo(({ chatbotId, apiUrl }) => {
  const chat = useChat({
    chatbot: { id: chatbotId },
    baseUrl: apiUrl,
  });
  const handleSendMessage = useCallback((message: string) => {
    chat.sendMessage(message);
  }, [chat.sendMessage]);
  return (
    <div>
      {/* Chat UI */}
    </div>
  );
});Accessibility
Ensure your chat is accessible:
const AccessibleChat = () => {
  const chat = useChat(options);
  const [announcements, setAnnouncements] = useState<string[]>([]);
  const announceMessage = useCallback((message: string) => {
    setAnnouncements(prev => [...prev, message]);
    // Clear announcement after a delay
    setTimeout(() => {
      setAnnouncements(prev => prev.slice(1));
    }, 3000);
  }, []);
  useEffect(() => {
    if (chat.messages.length > 0) {
      const lastMessage = chat.messages[chat.messages.length - 1];
      if (lastMessage.role === 'assistant') {
        announceMessage(`New message: ${lastMessage.content}`);
      }
    }
  }, [chat.messages, announceMessage]);
  return (
    <div>
      {/* Screen reader announcements */}
      <div aria-live="polite" aria-atomic="true" className="sr-only">
        {announcements.map((announcement, index) => (
          <div key={index}>{announcement}</div>
        ))}
      </div>
      
      {/* Chat UI with proper ARIA labels */}
      <div role="log" aria-label="Chat messages">
        {chat.messages.map((message, index) => (
          <div key={index} role="article" aria-label={`Message from ${message.role}`}>
            {message.content}
          </div>
        ))}
      </div>
    </div>
  );
};Security Considerations
Implement proper security measures:
const SecureChat = () => {
  const [csrfToken, setCsrfToken] = useState<string>('');
  useEffect(() => {
    // Get CSRF token
    fetch('/api/csrf-token')
      .then(res => res.json())
      .then(data => setCsrfToken(data.token));
  }, []);
  const chat = useChat({
    chatbot: { id: 'secure-chatbot' },
    baseUrl: 'https://api.example.com/chat',
    // Add security headers
    headers: {
      'X-CSRF-Token': csrfToken,
      'Authorization': `Bearer ${localStorage.getItem('authToken')}`,
    },
  });
  // Sanitize user input
  const sanitizeInput = (input: string) => {
    return input.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '');
  };
  const handleSendMessage = (message: string) => {
    const sanitizedMessage = sanitizeInput(message);
    chat.sendMessage(sanitizedMessage);
  };
  return (
    <div>
      {/* Secure chat UI */}
    </div>
  );
};Testing Examples
Unit Tests
import { renderHook, act } from '@testing-library/react';
import { useChat } from '@rkt/rkt-chat-client';
describe('useChat Session Initialization', () => {
  it('should initialize session correctly', async () => {
    const { result } = renderHook(() => useChat({
      chatbot: { id: 'test-chatbot' },
      baseUrl: 'https://api.example.com/chat',
    }));
    // Wait for session initialization
    await act(async () => {
      await new Promise(resolve => setTimeout(resolve, 100));
    });
    expect(result.current.sessionId).toBeTruthy();
    expect(result.current.isSessionReady).toBe(true);
  });
  it('should handle telemetry initialization', async () => {
    const mockTelemetry = {
      initializeSession: jest.fn(),
      trackEvent: jest.fn(),
      trackError: jest.fn(),
    };
    const { result } = renderHook(() => useChat({
      chatbot: { id: 'test-chatbot' },
      baseUrl: 'https://api.example.com/chat',
      telemetry: mockTelemetry,
    }));
    await act(async () => {
      await new Promise(resolve => setTimeout(resolve, 100));
    });
    expect(mockTelemetry.initializeSession).toHaveBeenCalled();
    expect(result.current.telemetryInitialized).toBe(true);
  });
});Integration Tests
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import ChatComponent from './ChatComponent';
describe('ChatComponent Integration', () => {
  it('should send messages and receive responses', async () => {
    render(<ChatComponent chatbotId="test-chatbot" apiUrl="https://api.example.com/chat" />);
    // Wait for session initialization
    await waitFor(() => {
      expect(screen.getByText(/Session ID:/)).toBeInTheDocument();
    });
    // Send a message
    const input = screen.getByPlaceholderText(/Type your message/);
    const sendButton = screen.getByText('Send');
    fireEvent.change(input, { target: { value: 'Hello, AI!' } });
    fireEvent.click(sendButton);
    // Verify message was sent
    await waitFor(() => {
      expect(screen.getByText('Hello, AI!')).toBeInTheDocument();
    });
  });
});Next Steps
- API Reference - Complete API documentation
 - Integration Guide - Step-by-step integration
 - Troubleshooting - Common issues and solutions
 
Last updated on