mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-03-16 21:53:07 +00:00
* Changes from feature/worktree-view-customization * Feature: Git sync, set-tracking, and push divergence handling (#796) * Add quick-add feature with improved workflows (#802) * Changes from feature/quick-add * feat: Clarify system prompt and improve error handling across services. Address PR Feedback * feat: Improve PR description parsing and refactor event handling * feat: Add context options to pipeline orchestrator initialization * fix: Deduplicate React and handle CJS interop for use-sync-external-store Resolve "Cannot read properties of null (reading 'useState')" errors by deduplicating React/react-dom and ensuring use-sync-external-store is bundled together with React to prevent CJS packages from resolving to different React instances. * Changes from feature/worktree-view-customization * refactor: Remove unused worktree swap and highlight props * refactor: Consolidate feature completion logic and improve thinking level defaults * feat: Increase max turn limit to 10000 - Update DEFAULT_MAX_TURNS from 1000 to 10000 in settings-helpers.ts and agent-executor.ts - Update MAX_ALLOWED_TURNS from 2000 to 10000 in settings-helpers.ts - Update UI clamping logic from 2000 to 10000 in app-store.ts - Update fallback values from 1000 to 10000 in use-settings-sync.ts - Update default value from 1000 to 10000 in DEFAULT_GLOBAL_SETTINGS - Update documentation to reflect new range: 1-10000 Allows agents to perform up to 10000 turns for complex feature execution. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> * feat: Add model resolution, improve session handling, and enhance UI stability * refactor: Remove unused sync and tracking branch props from worktree components * feat: Add PR number update functionality to worktrees. Address pr feedback * feat: Optimize Gemini CLI startup and add tool result tracking * refactor: Improve error handling and simplify worktree task cleanup --------- Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com>
201 lines
6.7 KiB
TypeScript
201 lines
6.7 KiB
TypeScript
import { Page } from '@playwright/test';
|
|
import { clickElement } from '../core/interactions';
|
|
import { handleLoginScreenIfPresent } from '../core/interactions';
|
|
import { waitForElement, waitForSplashScreenToDisappear } from '../core/waiting';
|
|
import { authenticateForTests } from '../api/client';
|
|
|
|
/**
|
|
* Navigate to the board/kanban view
|
|
* Note: Navigates directly to /board since index route shows WelcomeView
|
|
*/
|
|
export async function navigateToBoard(page: Page): Promise<void> {
|
|
// Authenticate before navigating
|
|
await authenticateForTests(page);
|
|
|
|
// Navigate directly to /board route
|
|
await page.goto('/board');
|
|
await page.waitForLoadState('load');
|
|
|
|
// Wait for splash screen to disappear (safety net)
|
|
await waitForSplashScreenToDisappear(page, 3000);
|
|
|
|
// Handle login redirect if needed
|
|
await handleLoginScreenIfPresent(page);
|
|
|
|
// Wait for the board view to be visible
|
|
await waitForElement(page, 'board-view', { timeout: 10000 });
|
|
}
|
|
|
|
/**
|
|
* Navigate to the context view
|
|
* Note: Navigates directly to /context since index route shows WelcomeView
|
|
*/
|
|
export async function navigateToContext(page: Page): Promise<void> {
|
|
// Authenticate before navigating
|
|
await authenticateForTests(page);
|
|
|
|
// Navigate directly to /context route
|
|
await page.goto('/context');
|
|
await page.waitForLoadState('load');
|
|
|
|
// Wait for splash screen to disappear (safety net)
|
|
await waitForSplashScreenToDisappear(page, 3000);
|
|
|
|
// Handle login redirect if needed
|
|
await handleLoginScreenIfPresent(page);
|
|
|
|
// Wait for loading to complete (if present)
|
|
const loadingElement = page.locator('[data-testid="context-view-loading"]');
|
|
try {
|
|
const loadingVisible = await loadingElement.isVisible({ timeout: 2000 });
|
|
if (loadingVisible) {
|
|
// Wait for loading to disappear (context view will appear)
|
|
await loadingElement.waitFor({ state: 'hidden', timeout: 10000 });
|
|
}
|
|
} catch {
|
|
// Loading element not found or already hidden, continue
|
|
}
|
|
|
|
// Wait for the context view to be visible
|
|
// Increase timeout to handle slower server startup
|
|
await waitForElement(page, 'context-view', { timeout: 15000 });
|
|
}
|
|
|
|
/**
|
|
* Navigate to the spec view
|
|
* Note: Navigates directly to /spec since index route shows WelcomeView
|
|
*/
|
|
export async function navigateToSpec(page: Page): Promise<void> {
|
|
// Authenticate before navigating
|
|
await authenticateForTests(page);
|
|
|
|
// Navigate directly to /spec route
|
|
await page.goto('/spec');
|
|
await page.waitForLoadState('load');
|
|
|
|
// Wait for splash screen to disappear (safety net)
|
|
await waitForSplashScreenToDisappear(page, 3000);
|
|
|
|
// Wait for loading state to complete first (if present)
|
|
const loadingElement = page.locator('[data-testid="spec-view-loading"]');
|
|
try {
|
|
const loadingVisible = await loadingElement.isVisible({ timeout: 2000 });
|
|
if (loadingVisible) {
|
|
// Wait for loading to disappear (spec view or empty state will appear)
|
|
await loadingElement.waitFor({ state: 'hidden', timeout: 10000 });
|
|
}
|
|
} catch {
|
|
// Loading element not found or already hidden, continue
|
|
}
|
|
|
|
// Wait for either the main spec view or empty state to be visible
|
|
// The spec-view element appears when loading is complete and spec exists
|
|
// The spec-view-empty element appears when loading is complete and spec doesn't exist
|
|
await Promise.race([
|
|
waitForElement(page, 'spec-view', { timeout: 10000 }).catch(() => null),
|
|
waitForElement(page, 'spec-view-empty', { timeout: 10000 }).catch(() => null),
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Navigate to the agent view
|
|
* Note: Navigates directly to /agent since index route shows WelcomeView
|
|
*/
|
|
export async function navigateToAgent(page: Page): Promise<void> {
|
|
// Authenticate before navigating
|
|
await authenticateForTests(page);
|
|
|
|
// Navigate directly to /agent route
|
|
await page.goto('/agent');
|
|
await page.waitForLoadState('load');
|
|
|
|
// Wait for splash screen to disappear (safety net)
|
|
await waitForSplashScreenToDisappear(page, 3000);
|
|
|
|
// Handle login redirect if needed
|
|
await handleLoginScreenIfPresent(page);
|
|
|
|
// Wait for the agent view to be visible
|
|
await waitForElement(page, 'agent-view', { timeout: 10000 });
|
|
}
|
|
|
|
/**
|
|
* Navigate to the settings view
|
|
* Note: Navigates directly to /settings since index route shows WelcomeView
|
|
*/
|
|
export async function navigateToSettings(page: Page): Promise<void> {
|
|
// Authenticate before navigating
|
|
await authenticateForTests(page);
|
|
|
|
// Navigate directly to /settings route
|
|
await page.goto('/settings');
|
|
await page.waitForLoadState('load');
|
|
|
|
// Wait for splash screen to disappear (safety net)
|
|
await waitForSplashScreenToDisappear(page, 3000);
|
|
|
|
// Wait for the settings view to be visible
|
|
await waitForElement(page, 'settings-view', { timeout: 10000 });
|
|
}
|
|
|
|
/**
|
|
* Navigate to the setup view directly
|
|
* Note: This function uses setupFirstRun from project/setup to avoid circular dependency
|
|
*/
|
|
export async function navigateToSetup(page: Page): Promise<void> {
|
|
// Dynamic import to avoid circular dependency
|
|
const { setupFirstRun } = await import('../project/setup');
|
|
await setupFirstRun(page);
|
|
await page.goto('/');
|
|
await page.waitForLoadState('load');
|
|
await waitForElement(page, 'setup-view', { timeout: 10000 });
|
|
}
|
|
|
|
/**
|
|
* Navigate to the welcome/dashboard view (clear project selection)
|
|
* Note: The app redirects from / to /dashboard when no project is selected
|
|
*/
|
|
export async function navigateToWelcome(page: Page): Promise<void> {
|
|
// Authenticate before navigating
|
|
await authenticateForTests(page);
|
|
|
|
await page.goto('/');
|
|
await page.waitForLoadState('load');
|
|
|
|
// Wait for splash screen to disappear (safety net)
|
|
await waitForSplashScreenToDisappear(page, 3000);
|
|
|
|
// Handle login redirect if needed
|
|
await handleLoginScreenIfPresent(page);
|
|
|
|
// Wait for either welcome-view, dashboard-view, or overview-view (app redirects based on project state)
|
|
await page
|
|
.locator(
|
|
'[data-testid="welcome-view"], [data-testid="dashboard-view"], [data-testid="overview-view"]'
|
|
)
|
|
.first()
|
|
.waitFor({ state: 'visible', timeout: 10000 });
|
|
}
|
|
|
|
/**
|
|
* Navigate to a specific view using the sidebar navigation
|
|
*/
|
|
export async function navigateToView(page: Page, viewId: string): Promise<void> {
|
|
const navSelector = viewId === 'settings' ? 'settings-button' : `nav-${viewId}`;
|
|
await clickElement(page, navSelector);
|
|
await page.waitForTimeout(100);
|
|
}
|
|
|
|
/**
|
|
* Get the current view from the URL or store (checks which view is active)
|
|
*/
|
|
export async function getCurrentView(page: Page): Promise<string | null> {
|
|
// Get the current view from zustand store via localStorage
|
|
const storage = await page.evaluate(() => {
|
|
const item = localStorage.getItem('automaker-storage');
|
|
return item ? JSON.parse(item) : null;
|
|
});
|
|
|
|
return storage?.state?.currentView || null;
|
|
}
|