Files
openhuman/app/test/e2e/specs/conversations-web-channel-flow.spec.ts
T
8381283c52 Fix/update api (#319)
* feat(webhooks): refactor webhook URL handling and enhance API endpoints

- Introduced a new utility function `buildWebhookIngressUrl` to standardize the construction of webhook URLs across components.
- Updated `WebhooksDebugPanel` and `TunnelList` components to utilize the new URL builder for improved consistency and maintainability.
- Refactored API endpoints in `tunnelsApi` to reflect changes in webhook routing, ensuring all references to tunnel management are aligned with the new structure.
- Adjusted user API calls to replace `/telegram/me` with `/auth/me` for better clarity and consistency in authentication flows.
- Enhanced socket service to normalize channel connection update payloads, improving error handling and data integrity.

These changes streamline webhook management and enhance the overall developer experience when working with webhooks.

* feat(messaging): enhance Telegram and Discord channel linking functionality

- Added support for managed DM linking with Telegram and OAuth flow for Discord.
- Introduced `createChannelLinkToken` API to generate short-lived link tokens for messaging channels.
- Updated `MessagingPanel` to handle managed linking flows, including building launch URLs and user instructions.
- Enhanced configuration to include a Telegram bot username for fallback linking.
- Updated tests to mock new configuration values for consistent testing.

These changes improve the user experience for linking messaging channels and streamline the authentication process.

* feat(api): introduce core command client and refactor API calls

- Added a new `coreCommandClient` to facilitate RPC calls to core services.
- Refactored existing API endpoints in `authApi`, `billingApi`, `creditsApi`, `tunnelsApi`, and `userApi` to utilize the new command client for improved consistency and maintainability.
- Updated the billing API to include new endpoints for fetching balance, transactions, and managing auto-recharge settings.
- Enhanced the user API to streamline user data retrieval.
- Improved error handling and logging across the refactored API calls.

These changes enhance the overall architecture of the API services, making them more modular and easier to maintain.

* refactor(api): streamline API calls and enhance error handling

- Refactored `creditsApi` and `tunnelsApi` to ensure consistent use of the new core command client.
- Updated API methods to improve error handling and response parsing.
- Introduced a new `authed_json` method in `BackendOAuthClient` for standardized authenticated requests.
- Cleaned up unused imports and optimized code structure across various modules.

These changes enhance the maintainability and reliability of the API services.

* refactor(api): streamline API calls and improve code readability

- Reorganized API calls in `authApi`, `billingApi`, `creditsApi`, and `tunnelsApi` to enhance consistency and maintainability.
- Updated function formatting for better readability, ensuring parameters are clearly defined.
- Cleaned up import statements and removed unnecessary line breaks to improve code clarity.

These changes contribute to a more maintainable codebase and enhance the overall developer experience.

* refactor(MessagingPanel): clean up imports and remove unused constants

- Reorganized import statements for clarity and consistency.
- Removed unused constants related to channel definitions and status styles to streamline the component.
- Simplified the `updateField` function call in the rendering logic for better readability.

These changes enhance the maintainability of the MessagingPanel component.

* fix: restore helper functions removed during merge cleanup

buildManagedChannelLaunchUrl and buildManagedChannelInstruction were
stripped by the linter after merge resolution, breaking the build.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat(messaging): enhance MessagingPanel with pending instruction handling

- Introduced a new state for pending instructions to improve user feedback during channel connection processes.
- Updated error handling to ensure users receive clear instructions, including URLs for manual access if automatic opening fails.
- Refactored connection status updates to streamline the dispatch process and improve code readability.
- Enhanced the rendering logic to display pending instructions in the UI, providing better context for users during authentication flows.

* fix(api): encode channel and ID parameters in webhook and OAuth URLs

- Updated the URL construction in the BackendOAuthClient to encode the channel parameter, ensuring proper formatting for requests.
- Modified the get_tunnel, update_tunnel, and delete_tunnel functions to encode the ID parameter in webhook URLs, enhancing security and compatibility with special characters.

* fix(auth): validate channel input for link token creation

- Added validation to ensure the channel is not empty and is one of the supported types (telegram, discord).
- Converted the channel string to lowercase for consistent matching.
- Updated the call to create_channel_link_token to use a reference to the channel variable.

* chore(todos): update TODO list with completed tasks and new feature requests

- Marked several tasks as completed, including integration of the custom memory engine and skills registry into the core.
- Added new items to the TODO list, including improvements for voiceover functionalities, screen intelligence, and Gmail skill enhancements.
- Included tasks for debugging skills from the UI and improving prompts to reduce hallucinations.

* refactor(webhooks): improve formatting of get_tunnel function for readability

- Reformatted the get_tunnel function to enhance code clarity by adjusting the indentation and line breaks in the call to get_authed_value.
- This change improves the maintainability of the code and aligns with the overall code style.

* test(userApi): enhance userApi tests with improved mocking and error handling

- Added a mock function for core command calls to streamline test setup.
- Introduced a helper function to generate mock user data for consistent test cases.
- Updated tests to use the mock function for simulating API responses, improving clarity and maintainability.
- Enhanced error handling in tests to cover various API error scenarios, ensuring robustness in userApi.getMe functionality.

* refactor(billingApi): update tests to use core command mocking and improve error handling

- Replaced apiClient mocks with core command mocks for better alignment with the new API structure.
- Updated test cases to reflect changes in API call expectations, enhancing clarity and maintainability.
- Improved error handling in tests to ensure proper propagation of errors from core command calls.

* refactor(billingApi): simplify test cases by consolidating mock function calls

- Streamlined mock function calls in billingApi tests for improved readability and consistency.
- Removed unnecessary line breaks in mock responses, enhancing clarity in test definitions.
- Ensured that error handling and API call expectations are clearly represented in the tests.

* refactor(api): rename settings endpoint to current_user for clarity

- Updated the endpoint handling authenticated profile fetches to improve clarity in the codebase.
- Adjusted the routing to reflect the new function name, enhancing maintainability and understanding of the API's purpose.

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 02:59:31 -07:00

167 lines
6.0 KiB
TypeScript

// @ts-nocheck
import { waitForApp, waitForAppReady } from '../helpers/app-helpers';
import { triggerAuthDeepLinkBypass } from '../helpers/deep-link-helpers';
import {
clickText,
dumpAccessibilityTree,
textExists,
waitForText,
waitForWebView,
waitForWindowVisible,
} from '../helpers/element-helpers';
import {
completeOnboardingIfVisible,
navigateToConversations,
navigateViaHash,
} from '../helpers/shared-flows';
import { clearRequestLog, getRequestLog, startMockServer, stopMockServer } from '../mock-server';
function stepLog(message: string, context?: unknown) {
const stamp = new Date().toISOString();
if (context === undefined) {
console.log(`[ConversationsE2E][${stamp}] ${message}`);
return;
}
console.log(`[ConversationsE2E][${stamp}] ${message}`, JSON.stringify(context, null, 2));
}
async function waitForRequest(method, urlFragment, timeout = 20_000) {
const deadline = Date.now() + timeout;
while (Date.now() < deadline) {
const log = getRequestLog();
const match = log.find(r => r.method === method && r.url.includes(urlFragment));
if (match) return match;
await browser.pause(500);
}
return undefined;
}
// This spec tests the full agent chat loop (UI → core sidecar → backend → streaming response).
// On Linux CI, the core sidecar's chat pipeline may not be fully functional in the E2E
// environment (mock backend lacks streaming SSE support). Skip on Linux only.
const suiteRunner = process.platform === 'linux' ? describe.skip : describe;
suiteRunner('Conversations web channel flow', () => {
before(async () => {
stepLog('starting mock server');
await startMockServer();
stepLog('waiting for app');
await waitForApp();
stepLog('clearing request log');
clearRequestLog();
});
after(async () => {
stepLog('stopping mock server');
await stopMockServer();
});
it('sends UI message through agent loop and renders response', async () => {
stepLog('trigger deep link');
await triggerAuthDeepLinkBypass('e2e-conversations-token');
stepLog('wait for window');
await waitForWindowVisible(25_000);
stepLog('wait for webview');
await waitForWebView(15_000);
stepLog('wait for app ready');
await waitForAppReady(15_000);
// triggerAuthDeepLinkBypass uses key=auth which sets the token directly
// (no /telegram/login-tokens/ consume call). Wait for user profile instead.
stepLog('wait for user profile request');
const profileCall = await waitForRequest('GET', '/auth/me', 15_000);
if (!profileCall) {
stepLog('user profile call not found — bypass token may have been set without API call');
}
stepLog('complete onboarding');
await completeOnboardingIfVisible('[ConversationsE2E]');
stepLog('open conversations');
// Navigate via hash — "Message OpenHuman" button may not reliably open conversations
await navigateToConversations();
// If navigating to /conversations doesn't open a thread, try clicking the input area
const hasInput = await textExists('Type a message...');
if (!hasInput) {
// Try the home page "Message OpenHuman" button as fallback
await navigateViaHash('/home');
try {
await waitForText('Message OpenHuman', 10_000);
await clickText('Message OpenHuman', 10_000);
} catch {
stepLog('Message OpenHuman button not found, staying on conversations');
await navigateToConversations();
}
}
stepLog('send message');
// The chat input uses a textarea with placeholder attribute — not visible as text content.
// Use browser.execute to find and focus it, then type.
const foundInput = await browser.execute(() => {
const textarea = document.querySelector(
'textarea[placeholder*="Type a message"]'
) as HTMLTextAreaElement;
if (textarea) {
textarea.focus();
textarea.click();
return true;
}
// Fallback: any textarea or contenteditable
const fallback = document.querySelector('textarea, [contenteditable="true"]') as HTMLElement;
if (fallback) {
fallback.focus();
(fallback as HTMLElement).click();
return true;
}
return false;
});
if (!foundInput) {
const tree = await dumpAccessibilityTree();
stepLog('Chat input not found. Tree:', tree.slice(0, 4000));
throw new Error('Chat input textarea not found');
}
stepLog('Chat input focused');
await browser.pause(500);
// Set value via JS and dispatch input event (browser.keys unreliable on tauri-driver)
await browser.execute(() => {
const textarea = document.querySelector(
'textarea[placeholder*="Type a message"]'
) as HTMLTextAreaElement;
if (!textarea) return;
const nativeInputValueSetter = Object.getOwnPropertyDescriptor(
window.HTMLTextAreaElement.prototype,
'value'
)?.set;
nativeInputValueSetter?.call(textarea, 'hello from e2e web channel');
textarea.dispatchEvent(new Event('input', { bubbles: true }));
textarea.dispatchEvent(new Event('change', { bubbles: true }));
});
await browser.pause(500);
// Submit by pressing Enter via JS (simulates form submission)
await browser.execute(() => {
const textarea = document.querySelector(
'textarea[placeholder*="Type a message"]'
) as HTMLTextAreaElement;
if (!textarea) return;
textarea.dispatchEvent(
new KeyboardEvent('keydown', { key: 'Enter', code: 'Enter', bubbles: true })
);
});
await browser.pause(1_000);
await waitForText('hello from e2e web channel', 20_000);
await waitForText('Hello from e2e mock agent', 30_000);
stepLog('validate backend request');
const chatReq = await waitForRequest('POST', '/openai/v1/chat/completions', 30_000);
if (!chatReq) {
const tree = await dumpAccessibilityTree();
console.log('[ConversationsE2E] Missing openai chat request. Tree:\n', tree.slice(0, 5000));
}
expect(chatReq).toBeDefined();
expect(await textExists('chat_send is not available')).toBe(false);
});
});