Enhanced onboarding page visual design (#4156)
Co-authored-by: Zane Staggs <zane@squareup.com>
This commit is contained in:
@@ -37,11 +37,11 @@ test.beforeEach(async ({ }, testInfo) => {
|
||||
if (mainWindow) {
|
||||
// Get a clean test name without the full hierarchy
|
||||
const testName = testInfo.titlePath[testInfo.titlePath.length - 1];
|
||||
|
||||
|
||||
// Get provider name if we're in a provider suite
|
||||
const providerSuite = testInfo.titlePath.find(t => t.startsWith('Provider:'));
|
||||
const providerName = providerSuite ? providerSuite.split(': ')[1] : undefined;
|
||||
|
||||
|
||||
console.log(`Setting overlay for test: "${testName}"${providerName ? ` (Provider: ${providerName})` : ''}`);
|
||||
await showTestName(mainWindow, testName, providerName);
|
||||
}
|
||||
@@ -56,9 +56,9 @@ test.afterEach(async () => {
|
||||
// Helper function to select a provider
|
||||
async function selectProvider(mainWindow: any, provider: Provider) {
|
||||
console.log(`Selecting provider: ${provider.name}`);
|
||||
|
||||
|
||||
// If we're already in the chat interface, we need to reset providers
|
||||
const chatTextarea = await mainWindow.waitForSelector('[data-testid="chat-input"]', {
|
||||
const chatTextarea = await mainWindow.waitForSelector('[data-testid="chat-input"]', {
|
||||
timeout: 2000
|
||||
}).catch(() => null);
|
||||
|
||||
@@ -76,7 +76,7 @@ async function selectProvider(mainWindow: any, provider: Provider) {
|
||||
timeout: 5000,
|
||||
state: 'visible'
|
||||
});
|
||||
|
||||
|
||||
const modelsTab = await mainWindow.waitForSelector('[data-testid="settings-models-tab"]');
|
||||
await modelsTab.click();
|
||||
|
||||
@@ -90,7 +90,7 @@ async function selectProvider(mainWindow: any, provider: Provider) {
|
||||
state: 'visible'
|
||||
});
|
||||
await resetButton.click();
|
||||
|
||||
|
||||
// Wait for the reset to complete
|
||||
await mainWindow.waitForTimeout(1000);
|
||||
}
|
||||
@@ -117,13 +117,13 @@ async function selectProvider(mainWindow: any, provider: Provider) {
|
||||
}
|
||||
|
||||
// Check if we need to click "configure other providers (advanced)" button
|
||||
const configureAdvancedButton = await mainWindow.waitForSelector('button:has-text("configure other providers (advanced)")', {
|
||||
const configureAdvancedButton = await mainWindow.waitForSelector('h3:has-text("Other providers")', {
|
||||
timeout: 3000,
|
||||
state: 'visible'
|
||||
}).catch(() => null);
|
||||
|
||||
if (configureAdvancedButton) {
|
||||
console.log('Found "configure other providers (advanced)" button, clicking it...');
|
||||
console.log('Found "configure other providers" button, clicking it...');
|
||||
await configureAdvancedButton.click();
|
||||
await mainWindow.waitForTimeout(1500);
|
||||
}
|
||||
@@ -213,7 +213,7 @@ test.describe('Goose App', () => {
|
||||
// Get the main window once for all tests
|
||||
mainWindow = await electronApp.firstWindow();
|
||||
await mainWindow.waitForLoadState('domcontentloaded');
|
||||
|
||||
|
||||
// Try to wait for networkidle, but don't fail if it times out due to MCP activity
|
||||
try {
|
||||
await mainWindow.waitForLoadState('networkidle', { timeout: 10000 });
|
||||
@@ -307,13 +307,13 @@ test.describe('Goose App', () => {
|
||||
timeout: 5000,
|
||||
state: 'visible'
|
||||
});
|
||||
|
||||
|
||||
const appTab = await mainWindow.waitForSelector('[data-testid="settings-app-tab"]');
|
||||
await appTab.click();
|
||||
|
||||
// Wait for the theme selector to be visible
|
||||
await mainWindow.waitForTimeout(1000);
|
||||
|
||||
|
||||
// Find and click the dark mode toggle button
|
||||
const darkModeButton = await mainWindow.waitForSelector('[data-testid="dark-mode-button"]');
|
||||
const lightModeButton = await mainWindow.waitForSelector('[data-testid="light-mode-button"]');
|
||||
@@ -341,13 +341,13 @@ test.describe('Goose App', () => {
|
||||
|
||||
// check that system mode is clickable
|
||||
await systemModeButton.click();
|
||||
|
||||
|
||||
// Toggle back to light mode
|
||||
await lightModeButton.click();
|
||||
|
||||
|
||||
// Pause to show return to original state
|
||||
await mainWindow.waitForTimeout(2000);
|
||||
|
||||
|
||||
// Navigate back to home
|
||||
const homeButton = await mainWindow.waitForSelector('[data-testid="sidebar-home-button"]');
|
||||
await homeButton.click();
|
||||
@@ -364,75 +364,75 @@ test.describe('Goose App', () => {
|
||||
test.describe('Chat', () => {
|
||||
test('chat interaction', async () => {
|
||||
console.log(`Testing chat interaction with ${provider.name}...`);
|
||||
|
||||
|
||||
// Find the chat input
|
||||
const chatInput = await mainWindow.waitForSelector('[data-testid="chat-input"]');
|
||||
expect(await chatInput.isVisible()).toBe(true);
|
||||
|
||||
|
||||
// Type a message
|
||||
await chatInput.fill('Hello, can you help me with a simple task?');
|
||||
|
||||
|
||||
// Take screenshot before sending
|
||||
await mainWindow.screenshot({ path: `test-results/${provider.name.toLowerCase()}-before-send.png` });
|
||||
|
||||
|
||||
// Send message
|
||||
await chatInput.press('Enter');
|
||||
|
||||
|
||||
// Wait for loading indicator to appear
|
||||
console.log('Waiting for loading indicator...');
|
||||
const loadingGoose = await mainWindow.waitForSelector('[data-testid="loading-indicator"]',
|
||||
{ timeout: 2000 });
|
||||
expect(await loadingGoose.isVisible()).toBe(true);
|
||||
|
||||
|
||||
// Take screenshot of loading state
|
||||
await mainWindow.screenshot({ path: `test-results/${provider.name.toLowerCase()}-loading-state.png` });
|
||||
|
||||
|
||||
// Wait for loading indicator to disappear
|
||||
console.log('Waiting for response...');
|
||||
await mainWindow.waitForSelector('[data-testid="loading-indicator"]',
|
||||
{ state: 'hidden', timeout: 30000 });
|
||||
|
||||
|
||||
// Get the latest response
|
||||
const response = await mainWindow.locator('[data-testid="message-container"]').last();
|
||||
expect(await response.isVisible()).toBe(true);
|
||||
|
||||
|
||||
// Verify response has content
|
||||
const responseText = await response.textContent();
|
||||
expect(responseText).toBeTruthy();
|
||||
expect(responseText.length).toBeGreaterThan(0);
|
||||
|
||||
|
||||
// Take screenshot of response
|
||||
await mainWindow.screenshot({ path: `test-results/${provider.name.toLowerCase()}-chat-response.png` });
|
||||
});
|
||||
|
||||
|
||||
test('verify chat history', async () => {
|
||||
console.log(`Testing chat history with ${provider.name}...`);
|
||||
|
||||
|
||||
// Find the chat input again
|
||||
const chatInput = await mainWindow.waitForSelector('[data-testid="chat-input"]');
|
||||
|
||||
|
||||
// Test message sending with a specific question
|
||||
await chatInput.fill('What is 2+2?');
|
||||
|
||||
|
||||
// Send message
|
||||
await chatInput.press('Enter');
|
||||
|
||||
|
||||
// Wait for loading indicator and response
|
||||
await mainWindow.waitForSelector('[data-testid="loading-indicator"]',
|
||||
{ state: 'hidden', timeout: 30000 });
|
||||
|
||||
|
||||
// Get the latest response
|
||||
const response = await mainWindow.locator('[data-testid="message-container"]').last();
|
||||
const responseText = await response.textContent();
|
||||
expect(responseText).toBeTruthy();
|
||||
|
||||
|
||||
// Check for message history
|
||||
const messages = await mainWindow.locator('[data-testid="message-container"]').all();
|
||||
expect(messages.length).toBeGreaterThanOrEqual(2);
|
||||
|
||||
|
||||
// Take screenshot of chat history
|
||||
await mainWindow.screenshot({ path: `test-results/${provider.name.toLowerCase()}-chat-history.png` });
|
||||
|
||||
|
||||
// Test command history (up arrow)
|
||||
await chatInput.press('Control+ArrowUp');
|
||||
const inputValue = await chatInput.inputValue();
|
||||
@@ -443,7 +443,7 @@ test.describe('Goose App', () => {
|
||||
test.describe('MCP Integration', () => {
|
||||
test('running quotes MCP server integration', async () => {
|
||||
console.log(`Testing Running Quotes MCP server integration with ${provider.name}...`);
|
||||
|
||||
|
||||
// Create test-results directory if it doesn't exist
|
||||
const fs = require('fs');
|
||||
if (!fs.existsSync('test-results')) {
|
||||
@@ -460,7 +460,7 @@ test.describe('Goose App', () => {
|
||||
console.log('NetworkIdle timeout (likely due to MCP activity), continuing with test...');
|
||||
}
|
||||
await mainWindow.waitForLoadState('domcontentloaded');
|
||||
|
||||
|
||||
// Wait for React app to be ready
|
||||
await mainWindow.waitForFunction(() => {
|
||||
const root = document.getElementById('root');
|
||||
@@ -477,47 +477,47 @@ test.describe('Goose App', () => {
|
||||
state: 'visible'
|
||||
});
|
||||
await extensionsButton.click();
|
||||
|
||||
|
||||
// Wait for extensions page to load
|
||||
await mainWindow.waitForTimeout(1000);
|
||||
|
||||
|
||||
// Look for Running Quotes extension card
|
||||
console.log('Looking for existing Running Quotes extension...');
|
||||
const existingExtension = await mainWindow.$('div.flex:has-text("Running Quotes")');
|
||||
|
||||
|
||||
if (existingExtension) {
|
||||
console.log('Found existing Running Quotes extension, removing it...');
|
||||
|
||||
|
||||
// Find and click the settings gear icon next to Running Quotes
|
||||
const settingsButton = await existingExtension.$('button[aria-label="Extension settings"]');
|
||||
if (settingsButton) {
|
||||
await settingsButton.click();
|
||||
|
||||
|
||||
// Wait for modal to appear
|
||||
await mainWindow.waitForTimeout(500);
|
||||
|
||||
|
||||
// Click the Remove Extension button
|
||||
const removeButton = await mainWindow.waitForSelector('button:has-text("Remove Extension")', {
|
||||
timeout: 2000,
|
||||
state: 'visible'
|
||||
});
|
||||
await removeButton.click();
|
||||
|
||||
|
||||
// Wait for confirmation modal
|
||||
await mainWindow.waitForTimeout(500);
|
||||
|
||||
|
||||
// Click the Remove button in confirmation dialog
|
||||
const confirmButton = await mainWindow.waitForSelector('button:has-text("Remove")', {
|
||||
timeout: 2000,
|
||||
state: 'visible'
|
||||
});
|
||||
await confirmButton.click();
|
||||
|
||||
|
||||
// Wait for extension to be removed
|
||||
await mainWindow.waitForTimeout(1000);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Now proceed with adding the extension
|
||||
console.log('Proceeding with adding Running Quotes extension...');
|
||||
|
||||
@@ -527,11 +527,11 @@ test.describe('Goose App', () => {
|
||||
timeout: 2000,
|
||||
state: 'visible'
|
||||
});
|
||||
|
||||
|
||||
// Verify add extension button is visible
|
||||
const isAddExtensionVisible = await addExtensionButton.isVisible();
|
||||
console.log('Add custom extension button visible:', isAddExtensionVisible);
|
||||
|
||||
|
||||
await addExtensionButton.click();
|
||||
console.log('Clicked Add custom extension');
|
||||
|
||||
@@ -541,21 +541,21 @@ test.describe('Goose App', () => {
|
||||
|
||||
// Fill the form
|
||||
console.log('Filling form fields...');
|
||||
|
||||
|
||||
// Fill Extension Name
|
||||
const nameInput = await mainWindow.waitForSelector('input[placeholder="Enter extension name..."]', {
|
||||
timeout: 2000,
|
||||
state: 'visible'
|
||||
});
|
||||
await nameInput.fill('Running Quotes');
|
||||
|
||||
|
||||
// Fill Description
|
||||
const descriptionInput = await mainWindow.waitForSelector('input[placeholder="Optional description..."]', {
|
||||
timeout: 2000,
|
||||
state: 'visible'
|
||||
});
|
||||
await descriptionInput.fill('Inspirational running quotes MCP server');
|
||||
|
||||
|
||||
// Fill Command
|
||||
const mcpScriptPath = join(__dirname, 'basic-mcp.ts');
|
||||
const commandInput = await mainWindow.waitForSelector('input[placeholder="e.g. npx -y @modelcontextprotocol/my-extension <filepath>"]', {
|
||||
@@ -576,50 +576,50 @@ test.describe('Goose App', () => {
|
||||
timeout: 2000,
|
||||
state: 'visible'
|
||||
});
|
||||
|
||||
|
||||
// Verify button is visible
|
||||
const isModalAddButtonVisible = await modalAddButton.isVisible();
|
||||
console.log('Add Extension button visible:', isModalAddButtonVisible);
|
||||
|
||||
// Click the button
|
||||
await modalAddButton.click();
|
||||
|
||||
|
||||
console.log('Clicked Add Extension button');
|
||||
|
||||
// Wait for the Running Quotes extension to appear in the list
|
||||
console.log('Waiting for Running Quotes extension to appear...');
|
||||
try {
|
||||
const extensionCard = await mainWindow.waitForSelector(
|
||||
'div.flex:has-text("Running Quotes")',
|
||||
'div.flex:has-text("Running Quotes")',
|
||||
{
|
||||
timeout: 30000,
|
||||
state: 'visible'
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
// Verify the extension is enabled
|
||||
await mainWindow.waitForTimeout(1000);
|
||||
const toggleButton = await extensionCard.$('button[role="switch"][data-state="checked"]');
|
||||
const isEnabled = !!toggleButton;
|
||||
console.log('Extension enabled:', isEnabled);
|
||||
|
||||
|
||||
if (!isEnabled) {
|
||||
throw new Error('Running Quotes extension was added but not enabled');
|
||||
}
|
||||
|
||||
|
||||
await mainWindow.screenshot({ path: `test-results/${provider.name.toLowerCase()}-extension-added.png` });
|
||||
console.log('Extension added successfully');
|
||||
} catch (error) {
|
||||
console.error('Error verifying extension:', error);
|
||||
|
||||
|
||||
// Get any error messages that might be visible
|
||||
const errorElements = await mainWindow.$$eval('.text-red-500, .text-error',
|
||||
const errorElements = await mainWindow.$$eval('.text-red-500, .text-error',
|
||||
elements => elements.map(el => el.textContent)
|
||||
);
|
||||
if (errorElements.length > 0) {
|
||||
console.log('Found error messages:', errorElements);
|
||||
}
|
||||
|
||||
|
||||
throw error;
|
||||
}
|
||||
|
||||
@@ -631,36 +631,36 @@ test.describe('Goose App', () => {
|
||||
} catch (error) {
|
||||
// Take error screenshot and log details
|
||||
await mainWindow.screenshot({ path: `test-results/${provider.name.toLowerCase()}-error.png` });
|
||||
|
||||
|
||||
// Get page content
|
||||
const pageContent = await mainWindow.evaluate(() => document.body.innerHTML);
|
||||
console.log('Page content at error:', pageContent);
|
||||
|
||||
|
||||
console.error('Test failed:', error);
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
test('test running quotes functionality', async () => {
|
||||
console.log(`Testing running quotes functionality with ${provider.name}...`);
|
||||
|
||||
|
||||
// Find the chat input
|
||||
const chatInput = await mainWindow.waitForSelector('[data-testid="chat-input"]');
|
||||
expect(await chatInput.isVisible()).toBe(true);
|
||||
|
||||
|
||||
// Type a message requesting a running quote
|
||||
await chatInput.fill('Can you give me an inspirational running quote using the runningQuotes tool?');
|
||||
|
||||
|
||||
// Take screenshot before sending
|
||||
await mainWindow.screenshot({ path: `test-results/${provider.name.toLowerCase()}-before-quote-request.png` });
|
||||
|
||||
|
||||
// Send message
|
||||
await chatInput.press('Enter');
|
||||
|
||||
// Get the latest response
|
||||
const response = await mainWindow.waitForSelector('.goose-message-tool', { timeout: 5000 });
|
||||
expect(await response.isVisible()).toBe(true);
|
||||
|
||||
|
||||
// Click the Output dropdown to reveal the actual quote
|
||||
await mainWindow.screenshot({ path: `test-results/${provider.name.toLowerCase()}-quote-response-debug.png` });
|
||||
|
||||
@@ -668,12 +668,12 @@ test.describe('Goose App', () => {
|
||||
const outputContent = await mainWindow.waitForSelector('.whitespace-pre-wrap', { timeout: 5000 });
|
||||
const outputText = await outputContent.textContent();
|
||||
console.log('Output text:', outputText);
|
||||
|
||||
|
||||
// Take screenshot of expanded response
|
||||
await mainWindow.screenshot({ path: `test-results/${provider.name.toLowerCase()}-quote-response.png` });
|
||||
|
||||
|
||||
// Check if the output contains one of our known quotes
|
||||
const containsKnownQuote = runningQuotes.some(({ quote, author }) =>
|
||||
const containsKnownQuote = runningQuotes.some(({ quote, author }) =>
|
||||
outputText.includes(`"${quote}" - ${author}`)
|
||||
);
|
||||
expect(containsKnownQuote).toBe(true);
|
||||
|
||||
Reference in New Issue
Block a user