add tmux sessions
This commit is contained in:
@@ -0,0 +1,248 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
// Use unique filename for each test run to avoid conflicts
|
||||
const TEST_FILE = `e2e-autoaccept-test-${Date.now()}.md`;
|
||||
const TEST_FILE_PATH = path.join(process.env.HOME || '/home/ajet', TEST_FILE);
|
||||
|
||||
test.describe('Claude Auto-Accept Edits', () => {
|
||||
test.afterEach(async () => {
|
||||
// Cleanup: Delete the test file directly via filesystem
|
||||
console.log('[Cleanup] Attempting to delete test file:', TEST_FILE_PATH);
|
||||
try {
|
||||
if (fs.existsSync(TEST_FILE_PATH)) {
|
||||
fs.unlinkSync(TEST_FILE_PATH);
|
||||
console.log('[Cleanup] Deleted test file');
|
||||
} else {
|
||||
console.log('[Cleanup] Test file does not exist');
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('[Cleanup] Could not clean up:', e);
|
||||
}
|
||||
});
|
||||
|
||||
test('auto-accept enables file operations without permission prompts', async ({ page }) => {
|
||||
// Increase timeout for this test since it involves real Claude interaction
|
||||
test.setTimeout(300000); // 5 minutes
|
||||
|
||||
// Enable console logging for debugging
|
||||
page.on('console', (msg) => {
|
||||
console.log(`[Browser ${msg.type()}]`, msg.text());
|
||||
});
|
||||
|
||||
// Log WebSocket frames for debugging
|
||||
page.on('websocket', (ws) => {
|
||||
console.log(`[WebSocket] Connected to ${ws.url()}`);
|
||||
ws.on('framesent', (frame) => console.log(`[WS Sent]`, frame.payload));
|
||||
ws.on('framereceived', (frame) => console.log(`[WS Received]`, frame.payload));
|
||||
});
|
||||
|
||||
// 1. Navigate to homepage
|
||||
await page.goto('/');
|
||||
await expect(page).toHaveTitle(/Spiceflow/i);
|
||||
|
||||
// 2. Click the + button to open new session menu
|
||||
const createButton = page.locator('button[title="New Session"]');
|
||||
await expect(createButton).toBeVisible();
|
||||
await createButton.click();
|
||||
|
||||
// 3. Select Claude Code from the dropdown
|
||||
const claudeOption = page.locator('button:has-text("Claude Code")');
|
||||
await expect(claudeOption).toBeVisible();
|
||||
await claudeOption.click();
|
||||
|
||||
// 4. Wait for navigation to session page
|
||||
await page.waitForURL(/\/session\/.+/);
|
||||
console.log('[Test] Navigated to session page:', page.url());
|
||||
|
||||
// 5. Wait for the page to load
|
||||
await expect(page.locator('text=Loading')).not.toBeVisible({ timeout: 5000 });
|
||||
await expect(page.locator('text=No messages yet')).toBeVisible();
|
||||
|
||||
// 6. Enable auto-accept edits via settings
|
||||
const settingsButton = page.locator('button[aria-label="Session settings"]');
|
||||
await expect(settingsButton).toBeVisible();
|
||||
await settingsButton.click();
|
||||
console.log('[Test] Opened settings dropdown');
|
||||
|
||||
// Wait for dropdown to appear and click the auto-accept checkbox
|
||||
const autoAcceptLabel = page.locator('label:has-text("Auto-accept edits")');
|
||||
await expect(autoAcceptLabel).toBeVisible();
|
||||
const autoAcceptCheckbox = autoAcceptLabel.locator('input[type="checkbox"]');
|
||||
|
||||
// Listen for the API response to ensure setting is persisted
|
||||
const updatePromise = page.waitForResponse(
|
||||
(response) => response.url().includes('/api/sessions/') && response.request().method() === 'PATCH'
|
||||
);
|
||||
await autoAcceptCheckbox.check();
|
||||
const updateResponse = await updatePromise;
|
||||
console.log('[Test] Auto-accept update response:', updateResponse.status());
|
||||
|
||||
// Verify the response contains auto-accept-edits: true
|
||||
const responseBody = await updateResponse.json();
|
||||
console.log('[Test] Updated session:', JSON.stringify(responseBody));
|
||||
expect(responseBody['auto-accept-edits']).toBe(true);
|
||||
console.log('[Test] Verified auto-accept-edits is persisted');
|
||||
|
||||
// Close dropdown by clicking elsewhere
|
||||
await page.locator('header').click();
|
||||
await expect(autoAcceptLabel).not.toBeVisible();
|
||||
|
||||
// 7. Send message asking Claude to CREATE a file
|
||||
const textarea = page.locator('textarea');
|
||||
await expect(textarea).toBeVisible();
|
||||
await textarea.fill(
|
||||
`Create a file called ${TEST_FILE} with the content "# Test File\\n\\nOriginal content for testing auto-accept.". Just create the file, no other commentary.`
|
||||
);
|
||||
|
||||
const sendButton = page.locator('button[type="submit"]');
|
||||
await expect(sendButton).toBeEnabled();
|
||||
await sendButton.click();
|
||||
console.log('[Test] Sent create file request');
|
||||
|
||||
// 8. Verify user message appears
|
||||
await expect(page.locator(`text=Create a file called ${TEST_FILE}`)).toBeVisible();
|
||||
|
||||
// 9. Verify thinking indicator appears
|
||||
const bouncingDots = page.locator('.animate-bounce');
|
||||
await expect(bouncingDots.first()).toBeVisible({ timeout: 5000 });
|
||||
console.log('[Test] Thinking indicator appeared');
|
||||
|
||||
// 10. CRITICAL: Permission UI should NOT appear (auto-accept should handle it)
|
||||
// Wait a bit to give permission request time to appear if it would
|
||||
await page.waitForTimeout(3000);
|
||||
|
||||
// Check that permission UI is not visible
|
||||
const permissionUI = page.locator('text=Claude needs permission');
|
||||
const permissionVisible = await permissionUI.isVisible();
|
||||
|
||||
if (permissionVisible) {
|
||||
// If permission UI appears, the auto-accept didn't work - fail the test
|
||||
console.log('[Test] ERROR: Permission UI appeared when auto-accept should have handled it');
|
||||
// Take screenshot for debugging
|
||||
await page.screenshot({ path: 'test-results/autoaccept-permission-appeared.png' });
|
||||
expect(permissionVisible).toBe(false);
|
||||
}
|
||||
console.log('[Test] Confirmed: No permission UI appeared (auto-accept working)');
|
||||
|
||||
// 11. Wait for streaming to complete
|
||||
const pulsingCursor = page.locator('.markdown-content .animate-pulse');
|
||||
await expect(bouncingDots).toHaveCount(0, { timeout: 120000 });
|
||||
await expect(pulsingCursor).toHaveCount(0, { timeout: 120000 });
|
||||
console.log('[Test] Create file streaming complete');
|
||||
|
||||
// 12. Check for permission message in history with "accept" status (green)
|
||||
// The permission message should be in the message list with status "accept"
|
||||
// Look for the "Permission granted" header text which indicates accepted status
|
||||
const acceptedPermissionHeader = page.locator('text=Permission granted');
|
||||
await expect(acceptedPermissionHeader.first()).toBeVisible({ timeout: 10000 });
|
||||
console.log('[Test] Found "Permission granted" header in history');
|
||||
|
||||
// Find the permission message container with green styling
|
||||
const acceptedPermission = page.locator('.rounded-lg.border.bg-green-500\\/10');
|
||||
const permissionCount = await acceptedPermission.count();
|
||||
console.log('[Test] Found accepted permission messages with green styling:', permissionCount);
|
||||
expect(permissionCount).toBeGreaterThan(0);
|
||||
|
||||
// Verify the permission message contains Write tool and the test file
|
||||
const firstPermission = acceptedPermission.first();
|
||||
const permissionText = await firstPermission.textContent();
|
||||
console.log('[Test] Permission message content:', permissionText?.substring(0, 200));
|
||||
expect(permissionText).toContain('Write');
|
||||
expect(permissionText).toContain('e2e-autoaccept-test');
|
||||
console.log('[Test] Verified accepted permission shows Write tool and test file');
|
||||
|
||||
// Verify the green checkmark icon is present
|
||||
const greenCheckmark = firstPermission.locator('svg.text-green-400');
|
||||
await expect(greenCheckmark).toBeVisible();
|
||||
console.log('[Test] Verified green checkmark icon is present');
|
||||
|
||||
// 13. Verify file was created by asking Claude to read it
|
||||
await textarea.fill(`Read the contents of ${TEST_FILE} and quote what it says.`);
|
||||
await sendButton.click();
|
||||
console.log('[Test] Sent read file request');
|
||||
|
||||
// Wait for response
|
||||
await expect(bouncingDots.first()).toBeVisible({ timeout: 5000 });
|
||||
await expect(bouncingDots).toHaveCount(0, { timeout: 60000 });
|
||||
await expect(pulsingCursor).toHaveCount(0, { timeout: 60000 });
|
||||
console.log('[Test] Read file streaming complete');
|
||||
|
||||
// Verify response contains the original content
|
||||
const assistantMessages = page.locator('.rounded-lg.border').filter({
|
||||
has: page.locator('.markdown-content')
|
||||
});
|
||||
const readResponse = await assistantMessages.last().locator('.markdown-content').textContent();
|
||||
console.log('[Test] Read response:', readResponse?.substring(0, 200));
|
||||
expect(readResponse).toContain('Original content');
|
||||
console.log('[Test] Verified file was created with correct content');
|
||||
|
||||
// 14. EDIT the file (should also auto-accept)
|
||||
await textarea.fill(
|
||||
`Edit the file ${TEST_FILE} to change "Original content" to "UPDATED content". Just make the edit.`
|
||||
);
|
||||
await sendButton.click();
|
||||
console.log('[Test] Sent edit file request');
|
||||
|
||||
// Wait and verify no permission UI
|
||||
await expect(bouncingDots.first()).toBeVisible({ timeout: 5000 });
|
||||
await page.waitForTimeout(3000);
|
||||
|
||||
const editPermissionVisible = await permissionUI.isVisible();
|
||||
if (editPermissionVisible) {
|
||||
console.log('[Test] ERROR: Permission UI appeared for edit when auto-accept should have handled it');
|
||||
await page.screenshot({ path: 'test-results/autoaccept-edit-permission-appeared.png' });
|
||||
expect(editPermissionVisible).toBe(false);
|
||||
}
|
||||
console.log('[Test] Confirmed: No permission UI for edit (auto-accept working)');
|
||||
|
||||
// Wait for edit to complete
|
||||
await expect(bouncingDots).toHaveCount(0, { timeout: 120000 });
|
||||
await expect(pulsingCursor).toHaveCount(0, { timeout: 120000 });
|
||||
console.log('[Test] Edit file streaming complete');
|
||||
|
||||
// 14b. Verify Edit permission was also auto-accepted and appears in history
|
||||
// Should now have at least 2 accepted permissions (Write + Edit)
|
||||
const acceptedPermissionCountAfterEdit = await acceptedPermission.count();
|
||||
console.log('[Test] Accepted permission count after edit:', acceptedPermissionCountAfterEdit);
|
||||
expect(acceptedPermissionCountAfterEdit).toBeGreaterThanOrEqual(2);
|
||||
|
||||
// Find the Edit permission message (should be the latest one)
|
||||
const editPermissionMessages = page.locator('.rounded-lg.border.bg-green-500\\/10').filter({
|
||||
hasText: /Edit.*e2e-autoaccept-test/i
|
||||
});
|
||||
const editPermCount = await editPermissionMessages.count();
|
||||
console.log('[Test] Found Edit permission messages:', editPermCount);
|
||||
expect(editPermCount).toBeGreaterThan(0);
|
||||
console.log('[Test] Verified Edit permission was auto-accepted and appears in history');
|
||||
|
||||
// 15. Verify edit worked by reading file again
|
||||
await textarea.fill(`Read ${TEST_FILE} again and tell me what it says now.`);
|
||||
await sendButton.click();
|
||||
console.log('[Test] Sent second read request');
|
||||
|
||||
await expect(bouncingDots.first()).toBeVisible({ timeout: 5000 });
|
||||
await expect(bouncingDots).toHaveCount(0, { timeout: 60000 });
|
||||
await expect(pulsingCursor).toHaveCount(0, { timeout: 60000 });
|
||||
|
||||
const editVerifyResponse = await assistantMessages.last().locator('.markdown-content').textContent();
|
||||
console.log('[Test] Edit verify response:', editVerifyResponse?.substring(0, 200));
|
||||
expect(editVerifyResponse).toContain('UPDATED');
|
||||
console.log('[Test] Verified file was edited successfully');
|
||||
|
||||
// 16. Verify file exists on filesystem
|
||||
const fileExists = fs.existsSync(TEST_FILE_PATH);
|
||||
expect(fileExists).toBe(true);
|
||||
console.log('[Test] Verified file exists on filesystem');
|
||||
|
||||
// Read actual file content to double-check
|
||||
const fileContent = fs.readFileSync(TEST_FILE_PATH, 'utf-8');
|
||||
console.log('[Test] Actual file content:', fileContent);
|
||||
expect(fileContent).toContain('UPDATED');
|
||||
console.log('[Test] Verified file contains UPDATED content');
|
||||
|
||||
console.log('[Test] Auto-accept E2E test completed successfully!');
|
||||
// File cleanup happens in afterEach
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user