added isolated config.yaml

This commit is contained in:
Lifei Zhou
2026-02-12 19:05:14 +11:00
parent ac0ceddf88
commit 1abc98be1b
2 changed files with 36 additions and 62 deletions
+14 -58
View File
@@ -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);
+22 -4
View File
@@ -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);
}
}
},
});