264 lines
12 KiB
TypeScript
264 lines
12 KiB
TypeScript
import { test, expect } from './fixtures';
|
|
|
|
test.describe('Context Management E2E Tests', () => {
|
|
test.beforeEach(async ({ goosePage }) => {
|
|
// Ensure the app is ready before each test
|
|
await goosePage.waitForSelector('[data-testid="chat-input"]', { timeout: 10000 });
|
|
});
|
|
|
|
test('should show context window alert when tokens are being used', async ({ goosePage }) => {
|
|
// Type a message to generate some token usage
|
|
const chatInput = goosePage.locator('[data-testid="chat-input"]');
|
|
await chatInput.fill('Hello, this is a test message to generate some token usage.');
|
|
|
|
// Submit the message
|
|
await goosePage.keyboard.press('Enter');
|
|
|
|
// Wait for response and check for context window alert
|
|
await goosePage.waitForSelector('[data-testid="alert-indicator"]', { timeout: 15000 });
|
|
|
|
// Click on the alert indicator to open the popover
|
|
await goosePage.click('[data-testid="alert-indicator"]');
|
|
|
|
// Verify the context window alert is shown
|
|
const alertBox = goosePage.locator('[role="alert"]');
|
|
await expect(alertBox).toBeVisible();
|
|
await expect(alertBox).toContainText('Context window');
|
|
|
|
// Verify progress bar is shown
|
|
const progressBar = goosePage.locator('[role="progressbar"]');
|
|
await expect(progressBar).toBeVisible();
|
|
|
|
// Verify compact button is present
|
|
const compactButton = goosePage.locator('text=Compact now');
|
|
await expect(compactButton).toBeVisible();
|
|
});
|
|
|
|
test('should perform manual compaction when compact button is clicked', async ({ goosePage }) => {
|
|
// First, generate enough conversation to have tokens
|
|
const chatInput = goosePage.locator('[data-testid="chat-input"]');
|
|
|
|
// Send multiple messages to build up context
|
|
const messages = [
|
|
'Hello, I need help with a programming task.',
|
|
'Can you explain how React hooks work?',
|
|
'What are the best practices for state management?',
|
|
'How do I optimize performance in React applications?',
|
|
];
|
|
|
|
for (const message of messages) {
|
|
await chatInput.fill(message);
|
|
await goosePage.keyboard.press('Enter');
|
|
|
|
// Wait for response before sending next message
|
|
await goosePage.waitForSelector('[data-testid="loading-goose"]', { state: 'hidden', timeout: 30000 });
|
|
await goosePage.waitForTimeout(1000); // Brief pause between messages
|
|
}
|
|
|
|
// Open the alert popover
|
|
await goosePage.waitForSelector('[data-testid="alert-indicator"]', { timeout: 15000 });
|
|
await goosePage.click('[data-testid="alert-indicator"]');
|
|
|
|
// Click the compact button
|
|
const compactButton = goosePage.locator('text=Compact now');
|
|
await expect(compactButton).toBeVisible();
|
|
await compactButton.click();
|
|
|
|
// Verify compaction loading state
|
|
const loadingGoose = goosePage.locator('[data-testid="loading-goose"]');
|
|
await expect(loadingGoose).toBeVisible();
|
|
await expect(loadingGoose).toContainText('goose is compacting the conversation...');
|
|
|
|
// Wait for compaction to complete
|
|
await goosePage.waitForSelector('[data-testid="loading-goose"]', { state: 'hidden', timeout: 30000 });
|
|
|
|
// Verify compaction marker appears
|
|
const compactionMarker = goosePage.locator('text=Conversation compacted and summarized');
|
|
await expect(compactionMarker).toBeVisible();
|
|
|
|
// Verify alert popover is closed after compaction
|
|
const alertBox = goosePage.locator('[role="alert"]');
|
|
await expect(alertBox).not.toBeVisible();
|
|
});
|
|
|
|
test('should allow scrolling to see past messages after compaction', async ({ goosePage }) => {
|
|
// Generate conversation content
|
|
const chatInput = goosePage.locator('[data-testid="chat-input"]');
|
|
|
|
const testMessages = [
|
|
'First message in the conversation',
|
|
'Second message with some content',
|
|
'Third message to build context',
|
|
];
|
|
|
|
// Send messages and store their content for verification
|
|
for (const message of testMessages) {
|
|
await chatInput.fill(message);
|
|
await goosePage.keyboard.press('Enter');
|
|
await goosePage.waitForSelector('[data-testid="loading-goose"]', { state: 'hidden', timeout: 30000 });
|
|
await goosePage.waitForTimeout(1000);
|
|
}
|
|
|
|
// Perform manual compaction
|
|
await goosePage.waitForSelector('[data-testid="alert-indicator"]', { timeout: 15000 });
|
|
await goosePage.click('[data-testid="alert-indicator"]');
|
|
await goosePage.click('text=Compact now');
|
|
|
|
// Wait for compaction to complete
|
|
await goosePage.waitForSelector('[data-testid="loading-goose"]', { state: 'hidden', timeout: 30000 });
|
|
await expect(goosePage.locator('text=Conversation compacted and summarized')).toBeVisible();
|
|
|
|
// Scroll up to verify past messages are still visible
|
|
const chatContainer = goosePage.locator('[data-testid="chat-container"]');
|
|
await chatContainer.hover();
|
|
|
|
// Scroll up multiple times to reach earlier messages
|
|
for (let i = 0; i < 5; i++) {
|
|
await goosePage.mouse.wheel(0, -500);
|
|
await goosePage.waitForTimeout(200);
|
|
}
|
|
|
|
// Verify that we can still see the original messages
|
|
// Note: The exact messages might be in ancestor messages, so we check for partial content
|
|
const messageElements = goosePage.locator('[data-testid="message"]');
|
|
const messageCount = await messageElements.count();
|
|
|
|
// Should have more than just the compaction marker and summary
|
|
expect(messageCount).toBeGreaterThan(2);
|
|
});
|
|
|
|
test('should handle compaction errors gracefully', async ({ goosePage }) => {
|
|
// Mock a backend error by intercepting the compaction request
|
|
await goosePage.route('**/api/sessions/*/manage-context', async (route) => {
|
|
await route.fulfill({
|
|
status: 500,
|
|
contentType: 'application/json',
|
|
body: JSON.stringify({ error: 'Backend compaction error' }),
|
|
});
|
|
});
|
|
|
|
// Generate some conversation
|
|
const chatInput = goosePage.locator('[data-testid="chat-input"]');
|
|
await chatInput.fill('Test message for error handling');
|
|
await goosePage.keyboard.press('Enter');
|
|
|
|
await goosePage.waitForSelector('[data-testid="loading-goose"]', { state: 'hidden', timeout: 30000 });
|
|
|
|
// Attempt compaction
|
|
await goosePage.waitForSelector('[data-testid="alert-indicator"]', { timeout: 15000 });
|
|
await goosePage.click('[data-testid="alert-indicator"]');
|
|
await goosePage.click('text=Compact now');
|
|
|
|
// Wait for compaction to fail
|
|
await goosePage.waitForSelector('[data-testid="loading-goose"]', { state: 'hidden', timeout: 30000 });
|
|
|
|
// Verify error message appears
|
|
const errorMarker = goosePage.locator('text=Compaction failed. Please try again or start a new session.');
|
|
await expect(errorMarker).toBeVisible();
|
|
});
|
|
|
|
test('should not show compaction UI when no tokens are used', async ({ goosePage }) => {
|
|
// On a fresh goosePage with no messages, there should be no alert indicator
|
|
const alertIndicator = goosePage.locator('[data-testid="alert-indicator"]');
|
|
await expect(alertIndicator).not.toBeVisible();
|
|
|
|
// The chat input should be available but no context alerts
|
|
const chatInput = goosePage.locator('[data-testid="chat-input"]');
|
|
await expect(chatInput).toBeVisible();
|
|
});
|
|
|
|
test('should maintain conversation flow after compaction', async ({ goosePage }) => {
|
|
// Generate initial conversation
|
|
const chatInput = goosePage.locator('[data-testid="chat-input"]');
|
|
|
|
await chatInput.fill('What is React?');
|
|
await goosePage.keyboard.press('Enter');
|
|
await goosePage.waitForSelector('[data-testid="loading-goose"]', { state: 'hidden', timeout: 30000 });
|
|
|
|
await chatInput.fill('Can you give me an example?');
|
|
await goosePage.keyboard.press('Enter');
|
|
await goosePage.waitForSelector('[data-testid="loading-goose"]', { state: 'hidden', timeout: 30000 });
|
|
|
|
// Perform compaction
|
|
await goosePage.waitForSelector('[data-testid="alert-indicator"]', { timeout: 15000 });
|
|
await goosePage.click('[data-testid="alert-indicator"]');
|
|
await goosePage.click('text=Compact now');
|
|
await goosePage.waitForSelector('[data-testid="loading-goose"]', { state: 'hidden', timeout: 30000 });
|
|
|
|
// Verify compaction marker
|
|
await expect(goosePage.locator('text=Conversation compacted and summarized')).toBeVisible();
|
|
|
|
// Continue conversation after compaction
|
|
await chatInput.fill('Thank you, that was helpful. What about Vue.js?');
|
|
await goosePage.keyboard.press('Enter');
|
|
|
|
// Verify that the conversation continues normally
|
|
await goosePage.waitForSelector('[data-testid="loading-goose"]', { timeout: 30000 });
|
|
await expect(goosePage.locator('[data-testid="loading-goose"]')).toBeVisible();
|
|
|
|
// Wait for response
|
|
await goosePage.waitForSelector('[data-testid="loading-goose"]', { state: 'hidden', timeout: 30000 });
|
|
|
|
// Verify new message appears after compaction
|
|
const messages = goosePage.locator('[data-testid="message"]');
|
|
const messageCount = await messages.count();
|
|
expect(messageCount).toBeGreaterThan(1); // Should have compaction marker + new messages
|
|
});
|
|
|
|
test('should show appropriate loading states during compaction', async ({ goosePage }) => {
|
|
// Generate conversation
|
|
const chatInput = goosePage.locator('[data-testid="chat-input"]');
|
|
await chatInput.fill('Test message for loading state verification');
|
|
await goosePage.keyboard.press('Enter');
|
|
await goosePage.waitForSelector('[data-testid="loading-goose"]', { state: 'hidden', timeout: 30000 });
|
|
|
|
// Start compaction
|
|
await goosePage.waitForSelector('[data-testid="alert-indicator"]', { timeout: 15000 });
|
|
await goosePage.click('[data-testid="alert-indicator"]');
|
|
await goosePage.click('text=Compact now');
|
|
|
|
// Verify loading state immediately after clicking compact
|
|
const loadingGoose = goosePage.locator('[data-testid="loading-goose"]');
|
|
await expect(loadingGoose).toBeVisible();
|
|
await expect(loadingGoose).toContainText('goose is compacting the conversation...');
|
|
|
|
// Verify chat input is disabled during compaction
|
|
const submitButton = goosePage.locator('[data-testid="submit-button"]');
|
|
await expect(submitButton).toBeDisabled();
|
|
|
|
// Wait for compaction to complete
|
|
await goosePage.waitForSelector('[data-testid="loading-goose"]', { state: 'hidden', timeout: 30000 });
|
|
|
|
// Verify chat input is re-enabled after compaction
|
|
await expect(submitButton).toBeEnabled();
|
|
});
|
|
|
|
test('should handle multiple rapid compaction attempts', async ({ goosePage }) => {
|
|
// Generate conversation
|
|
const chatInput = goosePage.locator('[data-testid="chat-input"]');
|
|
await chatInput.fill('Test message for rapid compaction test');
|
|
await goosePage.keyboard.press('Enter');
|
|
await goosePage.waitForSelector('[data-testid="loading-goose"]', { state: 'hidden', timeout: 30000 });
|
|
|
|
// Open alert and try to click compact multiple times rapidly
|
|
await goosePage.waitForSelector('[data-testid="alert-indicator"]', { timeout: 15000 });
|
|
await goosePage.click('[data-testid="alert-indicator"]');
|
|
|
|
const compactButton = goosePage.locator('text=Compact now');
|
|
await expect(compactButton).toBeVisible();
|
|
|
|
// Click multiple times rapidly
|
|
await compactButton.click();
|
|
|
|
// The alert should be hidden immediately after first click
|
|
const alertBox = goosePage.locator('[role="alert"]');
|
|
await expect(alertBox).not.toBeVisible();
|
|
|
|
// Verify only one compaction occurs
|
|
await goosePage.waitForSelector('[data-testid="loading-goose"]', { state: 'hidden', timeout: 30000 });
|
|
|
|
const compactionMarkers = goosePage.locator('text=Conversation compacted and summarized');
|
|
await expect(compactionMarkers).toHaveCount(1);
|
|
});
|
|
});
|