mirror of
https://github.com/block/goose.git
synced 2026-07-17 12:56:20 +02:00
added isolated config.yaml
This commit is contained in:
@@ -49,63 +49,16 @@ test.afterEach(async () => {
|
||||
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"]', {
|
||||
timeout: 2000
|
||||
}).catch(() => null);
|
||||
|
||||
if (chatTextarea) {
|
||||
// Navigate to Settings via sidebar to reset providers
|
||||
console.log('Opening settings to reset providers...');
|
||||
const settingsButton = await mainWindow.waitForSelector('[data-testid="sidebar-settings-button"]', {
|
||||
timeout: 5000,
|
||||
state: 'visible'
|
||||
});
|
||||
await settingsButton.click();
|
||||
|
||||
// Wait for settings page to load and navigate to Models tab
|
||||
await mainWindow.waitForSelector('[data-testid="settings-models-tab"]', {
|
||||
timeout: 5000,
|
||||
state: 'visible'
|
||||
});
|
||||
|
||||
const modelsTab = await mainWindow.waitForSelector('[data-testid="settings-models-tab"]');
|
||||
await modelsTab.click();
|
||||
|
||||
// Wait for models section to load
|
||||
await mainWindow.waitForTimeout(1000);
|
||||
|
||||
// Click Reset Provider and Model button
|
||||
console.log('Clicking Reset provider and model...');
|
||||
const resetButton = await mainWindow.waitForSelector('button:has-text("Reset provider and model")', {
|
||||
timeout: 5000,
|
||||
state: 'visible'
|
||||
});
|
||||
await resetButton.click();
|
||||
|
||||
// Wait for the reset to complete
|
||||
await mainWindow.waitForTimeout(1000);
|
||||
}
|
||||
|
||||
// Wait for React app to be ready and animations to complete
|
||||
await mainWindow.waitForFunction(() => {
|
||||
const root = document.getElementById('root');
|
||||
return root && root.children.length > 0;
|
||||
});
|
||||
await mainWindow.waitForTimeout(10000);
|
||||
|
||||
// Take a screenshot before proceeding
|
||||
await mainWindow.screenshot({ path: `test-results/before-provider-${provider.name.toLowerCase()}-check.png` });
|
||||
|
||||
// Check if we're already at the chat interface (provider already configured)
|
||||
const chatInputAfterReset = await mainWindow.waitForSelector('[data-testid="chat-input"]', {
|
||||
timeout: 2000,
|
||||
// Each test gets a fresh app with an isolated config (via GOOSE_PATH_ROOT in fixtures).
|
||||
// The config is seeded with GOOSE_PROVIDER, so the chat interface should be available.
|
||||
const chatInput = await mainWindow.waitForSelector('[data-testid="chat-input"]', {
|
||||
timeout: 10000,
|
||||
state: 'visible'
|
||||
}).catch(() => null);
|
||||
|
||||
if (chatInputAfterReset) {
|
||||
if (chatInput) {
|
||||
console.log('Provider already configured, chat interface is available');
|
||||
return; // Provider is already selected, no need to do anything
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if we're on the welcome screen with "Other Providers" section
|
||||
@@ -501,19 +454,22 @@ test.describe('Goose App', () => {
|
||||
console.log('Clicked Add Extension button');
|
||||
|
||||
// Wait for the Running Quotes extension to appear in the list
|
||||
// ExtensionItem renders <Card id="extension-running-quotes">
|
||||
console.log('Waiting for Running Quotes extension to appear...');
|
||||
try {
|
||||
const extensionCard = await mainWindow.waitForSelector(
|
||||
'div.flex:has-text("Running Quotes")',
|
||||
await mainWindow.waitForSelector(
|
||||
'#extension-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"]');
|
||||
// Wait for the extension toggle to become checked (MCP server may take time to start)
|
||||
const toggleButton = await mainWindow.waitForSelector(
|
||||
'#extension-running-quotes button[role="switch"][data-state="checked"]',
|
||||
{ timeout: 10000, state: 'visible' }
|
||||
).catch(() => null);
|
||||
const isEnabled = !!toggleButton;
|
||||
console.log('Extension enabled:', isEnabled);
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@ import { test as base, Page, Browser, chromium } from '@playwright/test';
|
||||
import { spawn, ChildProcess } from 'child_process';
|
||||
import { join } from 'path';
|
||||
import { promisify } from 'util';
|
||||
import * as fs from 'fs';
|
||||
import * as os from 'os';
|
||||
|
||||
const execAsync = promisify(require('child_process').exec);
|
||||
|
||||
@@ -12,12 +14,10 @@ type GooseTestFixtures = {
|
||||
/**
|
||||
* Test-scoped fixture that launches a fresh Electron app for EACH test.
|
||||
*
|
||||
* Isolation: ⚠️ Partial - each test gets a fresh app instance, but uses ambient user config
|
||||
* Isolation: ✅ Full - each test gets a fresh app instance with an isolated config directory
|
||||
* via GOOSE_PATH_ROOT, so tests never touch ~/.config/goose/
|
||||
* Speed: ⚠️ Slow - ~3s startup overhead per test
|
||||
*
|
||||
* This ensures each test starts with a fresh app instance, but the app uses the
|
||||
* user's existing Goose configuration (providers, models, etc.).
|
||||
*
|
||||
* Usage:
|
||||
* import { test, expect } from './fixtures';
|
||||
*
|
||||
@@ -34,6 +34,15 @@ export const test = base.extend<GooseTestFixtures>({
|
||||
let appProcess: ChildProcess | null = null;
|
||||
let browser: Browser | null = null;
|
||||
|
||||
// Create an isolated config directory so tests never touch ~/.config/goose/
|
||||
const tempDir = fs.mkdtempSync(join(os.tmpdir(), 'goose-test-'));
|
||||
const configDir = join(tempDir, 'config');
|
||||
fs.mkdirSync(configDir, { recursive: true });
|
||||
fs.mkdirSync(join(tempDir, 'data'), { recursive: true });
|
||||
fs.mkdirSync(join(tempDir, 'state'), { recursive: true });
|
||||
fs.writeFileSync(join(configDir, 'config.yaml'), 'GOOSE_PROVIDER: databricks\nGOOSE_MODEL: databricks-claude-haiku-4-5\nGOOSE_TELEMETRY_ENABLED: false\nDATABRICKS_HOST: https://block-lakehouse-production.cloud.databricks.com/\n');
|
||||
console.log(`Using isolated config directory: ${tempDir}`);
|
||||
|
||||
try {
|
||||
// Assign a unique debug port for this test to enable parallel execution
|
||||
// Base port 9222, offset by worker index * 100 + parallel slot
|
||||
@@ -54,6 +63,7 @@ export const test = base.extend<GooseTestFixtures>({
|
||||
ENABLE_PLAYWRIGHT: 'true',
|
||||
PLAYWRIGHT_DEBUG_PORT: debugPort.toString(), // Unique port per test for parallel execution
|
||||
RUST_LOG: 'info', // Enable info-level logging for goosed backend
|
||||
GOOSE_PATH_ROOT: tempDir,
|
||||
}
|
||||
});
|
||||
|
||||
@@ -163,6 +173,14 @@ export const test = base.extend<GooseTestFixtures>({
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up the isolated config directory
|
||||
try {
|
||||
fs.rmSync(tempDir, { recursive: true, force: true });
|
||||
console.log('Cleaned up isolated config directory');
|
||||
} catch (error) {
|
||||
console.error('Error cleaning up temp directory:', error);
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user