Fix e2e tests by removing installed running quotes before running (#2407)
This commit is contained in:
@@ -24,6 +24,7 @@
|
|||||||
"test-e2e:ui": "npm run generate-api && playwright test --ui",
|
"test-e2e:ui": "npm run generate-api && playwright test --ui",
|
||||||
"test-e2e:debug": "npm run generate-api && playwright test --debug",
|
"test-e2e:debug": "npm run generate-api && playwright test --debug",
|
||||||
"test-e2e:report": "playwright show-report",
|
"test-e2e:report": "playwright show-report",
|
||||||
|
"test-e2e:single": "npm run generate-api && playwright test -g",
|
||||||
"lint": "eslint \"src/**/*.{ts,tsx}\" --fix --no-warn-ignored",
|
"lint": "eslint \"src/**/*.{ts,tsx}\" --fix --no-warn-ignored",
|
||||||
"lint:check": "eslint \"src/**/*.{ts,tsx}\" --max-warnings 0 --no-warn-ignored",
|
"lint:check": "eslint \"src/**/*.{ts,tsx}\" --max-warnings 0 --no-warn-ignored",
|
||||||
"format": "prettier --write \"src/**/*.{ts,tsx,css,json}\"",
|
"format": "prettier --write \"src/**/*.{ts,tsx,css,json}\"",
|
||||||
|
|||||||
@@ -63,7 +63,6 @@ export default function ChatView({
|
|||||||
setView: (view: View, viewOptions?: ViewOptions) => void;
|
setView: (view: View, viewOptions?: ViewOptions) => void;
|
||||||
setIsGoosehintsModalOpen: (isOpen: boolean) => void;
|
setIsGoosehintsModalOpen: (isOpen: boolean) => void;
|
||||||
}) {
|
}) {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ContextManagerProvider>
|
<ContextManagerProvider>
|
||||||
<ChatContent
|
<ChatContent
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ interface MenuButtonProps {
|
|||||||
className?: string;
|
className?: string;
|
||||||
danger?: boolean;
|
danger?: boolean;
|
||||||
icon?: React.ReactNode;
|
icon?: React.ReactNode;
|
||||||
|
testId?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const MenuButton: React.FC<MenuButtonProps> = ({
|
const MenuButton: React.FC<MenuButtonProps> = ({
|
||||||
@@ -22,9 +23,11 @@ const MenuButton: React.FC<MenuButtonProps> = ({
|
|||||||
className = '',
|
className = '',
|
||||||
danger = false,
|
danger = false,
|
||||||
icon,
|
icon,
|
||||||
|
testId = '',
|
||||||
}) => (
|
}) => (
|
||||||
<button
|
<button
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
|
data-testid={testId}
|
||||||
className={`w-full text-left px-4 py-3 min-h-[64px] text-sm hover:bg-bgSubtle transition-[background] border-b border-borderSubtle ${
|
className={`w-full text-left px-4 py-3 min-h-[64px] text-sm hover:bg-bgSubtle transition-[background] border-b border-borderSubtle ${
|
||||||
danger ? 'text-red-400' : ''
|
danger ? 'text-red-400' : ''
|
||||||
} ${className}`}
|
} ${className}`}
|
||||||
@@ -259,6 +262,7 @@ export default function MoreMenu({
|
|||||||
}}
|
}}
|
||||||
subtitle="View all settings and options"
|
subtitle="View all settings and options"
|
||||||
icon={<Sliders className="w-4 h-4 rotate-90" />}
|
icon={<Sliders className="w-4 h-4 rotate-90" />}
|
||||||
|
testId="advanced-settings-button"
|
||||||
>
|
>
|
||||||
Advanced settings
|
Advanced settings
|
||||||
<span className="text-textSubtle ml-1">⌘,</span>
|
<span className="text-textSubtle ml-1">⌘,</span>
|
||||||
|
|||||||
@@ -99,8 +99,14 @@ async function selectProvider(mainWindow: any, provider: Provider) {
|
|||||||
|
|
||||||
// Find and verify the provider card container
|
// Find and verify the provider card container
|
||||||
console.log(`Looking for ${provider.name} card...`);
|
console.log(`Looking for ${provider.name} card...`);
|
||||||
const providerContainer = await mainWindow.waitForSelector(`[data-testid="provider-card-${provider.name.toLowerCase()}"]`);
|
let providerContainer;
|
||||||
expect(await providerContainer.isVisible()).toBe(true);
|
try {
|
||||||
|
providerContainer = await mainWindow.waitForSelector(`[data-testid="provider-card-${provider.name.toLowerCase()}"]`);
|
||||||
|
expect(await providerContainer.isVisible()).toBe(true);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Provider card not found for ${provider.name}. This could indicate a missing or incorrectly configured provider.`);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
// Find the Launch button within the provider container
|
// Find the Launch button within the provider container
|
||||||
console.log(`Looking for Launch button in ${provider.name} card...`);
|
console.log(`Looking for Launch button in ${provider.name} card...`);
|
||||||
@@ -162,7 +168,7 @@ test.describe('Goose App', () => {
|
|||||||
env: {
|
env: {
|
||||||
...process.env,
|
...process.env,
|
||||||
ELECTRON_IS_DEV: '1',
|
ELECTRON_IS_DEV: '1',
|
||||||
NODE_ENV: 'development'
|
NODE_ENV: 'development',
|
||||||
},
|
},
|
||||||
recordVideo: {
|
recordVideo: {
|
||||||
dir: 'test-results/videos/',
|
dir: 'test-results/videos/',
|
||||||
@@ -405,21 +411,6 @@ test.describe('Goose App', () => {
|
|||||||
fs.mkdirSync('test-results', { recursive: true });
|
fs.mkdirSync('test-results', { recursive: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clean up any existing running-quotes extensions from localStorage
|
|
||||||
// todo: extensions are no longer in localstorage so we need a way to delete extensions from the ui or config to actually clean these up
|
|
||||||
await mainWindow.evaluate(() => {
|
|
||||||
const USER_SETTINGS_KEY = 'user_settings';
|
|
||||||
const settings = JSON.parse(localStorage.getItem(USER_SETTINGS_KEY) || '{"extensions":[]}');
|
|
||||||
|
|
||||||
// Remove any running-quotes extensions
|
|
||||||
settings.extensions = settings.extensions.filter(ext => ext.id !== 'running-quotes');
|
|
||||||
|
|
||||||
// Save back to localStorage
|
|
||||||
localStorage.setItem(USER_SETTINGS_KEY, JSON.stringify(settings));
|
|
||||||
|
|
||||||
console.log('Cleaned up existing running-quotes extensions');
|
|
||||||
});
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Reload the page to ensure settings are fresh
|
// Reload the page to ensure settings are fresh
|
||||||
await mainWindow.reload();
|
await mainWindow.reload();
|
||||||
@@ -435,67 +426,122 @@ test.describe('Goose App', () => {
|
|||||||
// Take screenshot of initial state
|
// Take screenshot of initial state
|
||||||
await mainWindow.screenshot({ path: `test-results/${provider.name.toLowerCase()}-initial-state.png` });
|
await mainWindow.screenshot({ path: `test-results/${provider.name.toLowerCase()}-initial-state.png` });
|
||||||
|
|
||||||
|
// First navigate to Advanced Settings to check for existing Running Quotes extension
|
||||||
|
console.log('Checking for existing Running Quotes extension...');
|
||||||
|
|
||||||
// Click the menu button (3 dots)
|
// Click the menu button (3 dots)
|
||||||
console.log('Attempting to find menu button...');
|
|
||||||
const menuButton = await mainWindow.waitForSelector('[data-testid="more-options-button"]', {
|
const menuButton = await mainWindow.waitForSelector('[data-testid="more-options-button"]', {
|
||||||
timeout: 2000,
|
timeout: 2000,
|
||||||
state: 'visible'
|
state: 'visible'
|
||||||
});
|
});
|
||||||
|
|
||||||
// Verify menu button is visible and clickable
|
|
||||||
const isMenuButtonVisible = await menuButton.isVisible();
|
|
||||||
console.log('Menu button visible:', isMenuButtonVisible);
|
|
||||||
|
|
||||||
// Take screenshot before clicking menu
|
|
||||||
await mainWindow.screenshot({ path: `test-results/${provider.name.toLowerCase()}-before-menu.png` });
|
|
||||||
|
|
||||||
await menuButton.click();
|
await menuButton.click();
|
||||||
console.log('Clicked menu button');
|
|
||||||
|
// Wait for menu to appear
|
||||||
|
await mainWindow.waitForTimeout(1000);
|
||||||
|
|
||||||
|
// Click Advanced settings
|
||||||
|
const advancedSettingsButton = await mainWindow.waitForSelector('button:has-text("Advanced settings")', {
|
||||||
|
timeout: 2000,
|
||||||
|
state: 'visible'
|
||||||
|
});
|
||||||
|
await advancedSettingsButton.click();
|
||||||
|
|
||||||
|
// Wait for settings 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Click Back to return to main menu
|
||||||
|
let backButton = await mainWindow.waitForSelector('button:has-text("Back")', {
|
||||||
|
timeout: 2000,
|
||||||
|
state: 'visible'
|
||||||
|
});
|
||||||
|
await backButton.click();
|
||||||
|
|
||||||
|
// Wait for menu transition
|
||||||
|
await mainWindow.waitForTimeout(1000);
|
||||||
|
|
||||||
|
// Now proceed with adding the extension
|
||||||
|
console.log('Proceeding with adding Running Quotes extension...');
|
||||||
|
|
||||||
|
// Find and click the menu button (3 dots) again
|
||||||
|
console.log('Finding menu button again...');
|
||||||
|
const menuButtonAgain = await mainWindow.waitForSelector('[data-testid="more-options-button"]', {
|
||||||
|
timeout: 2000,
|
||||||
|
state: 'visible'
|
||||||
|
});
|
||||||
|
await menuButtonAgain.click();
|
||||||
|
|
||||||
// Wait for menu to appear and take screenshot
|
// Wait for menu to appear and take screenshot
|
||||||
await mainWindow.waitForTimeout(1000);
|
await mainWindow.waitForTimeout(1000);
|
||||||
await mainWindow.screenshot({ path: `test-results/${provider.name.toLowerCase()}-after-menu.png` });
|
await mainWindow.screenshot({ path: `test-results/${provider.name.toLowerCase()}-after-menu.png` });
|
||||||
|
|
||||||
// Click Advanced settings
|
// Click Advanced settings again
|
||||||
console.log('Looking for Advanced settings button...');
|
console.log('Looking for Advanced settings button again...');
|
||||||
const advancedSettingsButton = await mainWindow.waitForSelector('button:has-text("Advanced settings")', {
|
const advancedSettingsButtonAgain = await mainWindow.waitForSelector('button:has-text("Advanced settings")', {
|
||||||
timeout: 2000,
|
timeout: 2000,
|
||||||
state: 'visible'
|
state: 'visible'
|
||||||
});
|
});
|
||||||
|
await advancedSettingsButtonAgain.click();
|
||||||
// Verify advanced settings button is visible
|
|
||||||
const isAdvancedSettingsVisible = await advancedSettingsButton.isVisible();
|
|
||||||
console.log('Advanced settings button visible:', isAdvancedSettingsVisible);
|
|
||||||
|
|
||||||
await advancedSettingsButton.click();
|
|
||||||
console.log('Clicked Advanced settings');
|
console.log('Clicked Advanced settings');
|
||||||
|
|
||||||
// Wait for navigation and take screenshot
|
// Wait for navigation and take screenshot
|
||||||
await mainWindow.waitForTimeout(1000);
|
await mainWindow.waitForTimeout(1000);
|
||||||
await mainWindow.screenshot({ path: `test-results/${provider.name.toLowerCase()}-settings-page.png` });
|
await mainWindow.screenshot({ path: `test-results/${provider.name.toLowerCase()}-settings-page.png` });
|
||||||
|
|
||||||
// Click Add Custom Extension button
|
// Click "Add custom extension" button
|
||||||
console.log('Looking for Add Custom Extension button...');
|
console.log('Looking for Add custom extension button...');
|
||||||
const addExtensionButton = await mainWindow.waitForSelector('button:has-text("Add Custom Extension")', {
|
const addExtensionButton = await mainWindow.waitForSelector('button:has-text("Add custom extension")', {
|
||||||
timeout: 2000,
|
timeout: 2000,
|
||||||
state: 'visible'
|
state: 'visible'
|
||||||
});
|
});
|
||||||
|
|
||||||
// Verify add extension button is visible
|
// Verify add extension button is visible
|
||||||
const isAddExtensionVisible = await addExtensionButton.isVisible();
|
const isAddExtensionVisible = await addExtensionButton.isVisible();
|
||||||
console.log('Add Extension button visible:', isAddExtensionVisible);
|
console.log('Add custom extension button visible:', isAddExtensionVisible);
|
||||||
|
|
||||||
await addExtensionButton.click();
|
await addExtensionButton.click();
|
||||||
console.log('Clicked Add Custom Extension');
|
console.log('Clicked Add custom extension');
|
||||||
|
|
||||||
// Wait for modal and take screenshot
|
// Wait for modal and take screenshot
|
||||||
await mainWindow.waitForTimeout(1000);
|
await mainWindow.waitForTimeout(1000);
|
||||||
await mainWindow.screenshot({ path: `test-results/${provider.name.toLowerCase()}-modal.png` });
|
await mainWindow.screenshot({ path: `test-results/${provider.name.toLowerCase()}-modal.png` });
|
||||||
|
|
||||||
// Get page content for debugging
|
|
||||||
const modalContent = await mainWindow.evaluate(() => document.body.innerHTML);
|
|
||||||
console.log('Modal content:', modalContent);
|
|
||||||
|
|
||||||
// Fill the form
|
// Fill the form
|
||||||
console.log('Filling form fields...');
|
console.log('Filling form fields...');
|
||||||
|
|
||||||
@@ -515,7 +561,7 @@ test.describe('Goose App', () => {
|
|||||||
|
|
||||||
// Fill Command
|
// Fill Command
|
||||||
const mcpScriptPath = join(__dirname, 'basic-mcp.ts');
|
const mcpScriptPath = join(__dirname, 'basic-mcp.ts');
|
||||||
const commandInput = await mainWindow.waitForSelector('input[placeholder*="npx -y @modelcontextprotocol"]', {
|
const commandInput = await mainWindow.waitForSelector('input[placeholder="e.g. npx -y @modelcontextprotocol/my-extension <filepath>"]', {
|
||||||
timeout: 2000,
|
timeout: 2000,
|
||||||
state: 'visible'
|
state: 'visible'
|
||||||
});
|
});
|
||||||
@@ -524,18 +570,23 @@ test.describe('Goose App', () => {
|
|||||||
// Take screenshot of filled form
|
// Take screenshot of filled form
|
||||||
await mainWindow.screenshot({ path: `test-results/${provider.name.toLowerCase()}-filled-form.png` });
|
await mainWindow.screenshot({ path: `test-results/${provider.name.toLowerCase()}-filled-form.png` });
|
||||||
|
|
||||||
// Click Add Extension button
|
// Wait for any animations to complete
|
||||||
console.log('Looking for Add Extension button...');
|
await mainWindow.waitForTimeout(1000);
|
||||||
const addButton = await mainWindow.waitForSelector('button:has-text("Add Extension")', {
|
|
||||||
|
// Click Add Extension button in modal footer
|
||||||
|
console.log('Looking for Add Extension button in modal...');
|
||||||
|
const modalAddButton = await mainWindow.waitForSelector('button.text-textProminent', {
|
||||||
timeout: 2000,
|
timeout: 2000,
|
||||||
state: 'visible'
|
state: 'visible'
|
||||||
});
|
});
|
||||||
|
|
||||||
// Verify add button is visible
|
// Verify button is visible
|
||||||
const isAddButtonVisible = await addButton.isVisible();
|
const isModalAddButtonVisible = await modalAddButton.isVisible();
|
||||||
console.log('Add button visible:', isAddButtonVisible);
|
console.log('Add Extension button visible:', isModalAddButtonVisible);
|
||||||
|
|
||||||
|
// Click the button
|
||||||
|
await modalAddButton.click();
|
||||||
|
|
||||||
await addButton.click();
|
|
||||||
console.log('Clicked Add Extension button');
|
console.log('Clicked Add Extension button');
|
||||||
|
|
||||||
// Wait for the Running Quotes extension to appear in the list
|
// Wait for the Running Quotes extension to appear in the list
|
||||||
@@ -563,10 +614,6 @@ test.describe('Goose App', () => {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error verifying extension:', error);
|
console.error('Error verifying extension:', error);
|
||||||
|
|
||||||
// Get current page content
|
|
||||||
const pageContent = await mainWindow.evaluate(() => document.body.innerHTML);
|
|
||||||
console.log('Page content after clicking Add Extension:', pageContent);
|
|
||||||
|
|
||||||
// Get any error messages that might be visible
|
// 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)
|
elements => elements.map(el => el.textContent)
|
||||||
@@ -579,7 +626,7 @@ test.describe('Goose App', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Click Back button
|
// Click Back button
|
||||||
const backButton = await mainWindow.waitForSelector('button:has-text("Back")', {
|
backButton = await mainWindow.waitForSelector('button:has-text("Back")', {
|
||||||
timeout: 2000,
|
timeout: 2000,
|
||||||
state: 'visible'
|
state: 'visible'
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -20,11 +20,13 @@ async function showTestName(mainWindow: any, testName: string, providerName?: st
|
|||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
z-index: 2147483647; // maximum z-index integer value
|
z-index: 2147483647; // maximum z-index integer value
|
||||||
pointer-events: none;
|
pointer-events: none !important;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
max-width: 80%;
|
max-width: 80%;
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
|
box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
|
||||||
|
user-select: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const testText = `Running: ${name}`;
|
const testText = `Running: ${name}`;
|
||||||
|
|||||||
Reference in New Issue
Block a user