learningcircuit--local-deep-research
7a0da7932b
OSV-Scanner (Scheduled) / scan-scheduled (push) Failing after 0s
Create Release / test-gate (push) Has been cancelled
Create Release / release-gate (push) Has been cancelled
Create Release / ci-gate (push) Has been cancelled
Create Release / version-check (push) Has been cancelled
Create Release / e2e-test-gate (push) Has been cancelled
Create Release / responsive-test-gate (push) Has been cancelled
Create Release / compat-test-gate (push) Has been cancelled
Create Release / compose-integration-gate (push) Has been cancelled
Create Release / vulture-gate (push) Has been cancelled
Create Release / build (push) Has been cancelled
Create Release / provenance (push) Has been cancelled
Create Release / prerelease-docker (push) Has been cancelled
Create Release / publish-docker (push) Has been cancelled
Create Release / create-release (push) Has been cancelled
Create Release / cleanup-changelog (push) Has been cancelled
Create Release / trigger-pypi (push) Has been cancelled
Create Release / monitor-pypi (push) Has been cancelled
Create Release / Clean up orphan prerelease tags and signatures (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-form] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-metrics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-workflow] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-core] (push) Has been cancelled
CodeQL Advanced / Analyze (javascript-typescript) (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [history-news] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [library] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [link-analytics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-core] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-lifecycle] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [error-benchmark] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) (push) Has been cancelled
Docker Tests (Consolidated) / Accessibility Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Unit Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Example Tests (push) Has been cancelled
Docker Tests (Consolidated) / Production Image Smoke Test (push) Has been cancelled
Docker Tests (Consolidated) / Infrastructure Tests (push) Has been cancelled
OSSF Scorecard / OSSF Security Scorecard Analysis (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [mobile] (push) Has been cancelled
Backwards Compatibility / Verify Encryption Constants (push) Has been cancelled
Backwards Compatibility / PyPI Version Compatibility (push) Has been cancelled
Backwards Compatibility / Database Migration Tests (push) Has been cancelled
CodeQL Advanced / Analyze (python) (push) Has been cancelled
Docker Tests (Consolidated) / detect-changes (push) Has been cancelled
Docker Tests (Consolidated) / Build Test Image (push) Has been cancelled
Docker Tests (Consolidated) / All Pytest Tests + Coverage (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [accessibility] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [api-crud] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-login] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-register] (push) Has been cancelled
313 行
12 KiB
JavaScript
313 行
12 KiB
JavaScript
/**
|
|
* Puppeteer test for OpenAI API key configuration through the UI.
|
|
*
|
|
* This test verifies:
|
|
* 1. User can navigate to settings
|
|
* 2. User can enter OpenAI API key
|
|
* 3. Settings are saved correctly
|
|
* 4. API key is used for research
|
|
*/
|
|
|
|
const puppeteer = require('puppeteer');
|
|
const { expect } = require('chai');
|
|
const { getLaunchOptions } = require('./helpers');
|
|
|
|
// Test configuration
|
|
const BASE_URL = process.env.TEST_URL || 'http://localhost:5000';
|
|
const TEST_USERNAME = 'test_openai_user';
|
|
const TEST_PASSWORD = 'Test_password_123';
|
|
const TEST_OPENAI_KEY = 'sk-test-1234567890abcdef';
|
|
|
|
describe('OpenAI API Key Configuration UI Test', function() {
|
|
this.timeout(60000); // 60 second timeout for UI tests
|
|
|
|
let browser;
|
|
let page;
|
|
|
|
before(async () => {
|
|
// Shared options include the seeded profile that disables Chrome's
|
|
// password leak detection (see helpers/index.js and #4430).
|
|
browser = await puppeteer.launch(getLaunchOptions());
|
|
page = await browser.newPage();
|
|
|
|
// Set viewport for consistent testing
|
|
await page.setViewport({ width: 1280, height: 720 });
|
|
|
|
// Enable console logging for debugging
|
|
page.on('console', msg => console.log('Browser console:', msg.text()));
|
|
});
|
|
|
|
after(async () => {
|
|
if (browser) {
|
|
await browser.close();
|
|
}
|
|
});
|
|
|
|
beforeEach(async () => {
|
|
// Navigate to home page before each test
|
|
await page.goto(BASE_URL, { waitUntil: 'domcontentloaded' });
|
|
});
|
|
|
|
describe('User Registration and Login', () => {
|
|
it('should register a new user', async () => {
|
|
// Click on Register link
|
|
await page.waitForSelector('a[href="/register"]');
|
|
await page.click('a[href="/register"]');
|
|
|
|
// Wait for registration form
|
|
await page.waitForSelector('form#registerForm');
|
|
|
|
// Fill registration form
|
|
await page.type('input[name="username"]', TEST_USERNAME);
|
|
await page.type('input[name="password"]', TEST_PASSWORD);
|
|
await page.type('input[name="confirm_password"]', TEST_PASSWORD);
|
|
|
|
// Submit form
|
|
await page.click('button[type="submit"]');
|
|
|
|
// Wait for redirect to login or dashboard
|
|
await page.waitForNavigation({ waitUntil: 'domcontentloaded' });
|
|
|
|
// Check if registration was successful
|
|
const url = page.url();
|
|
expect(url).to.include('/login').or.to.include('/');
|
|
});
|
|
|
|
it('should login with credentials', async () => {
|
|
// Navigate to login if not already there
|
|
const currentUrl = page.url();
|
|
if (!currentUrl.includes('/login')) {
|
|
await page.goto(`${BASE_URL}/login`, { waitUntil: 'domcontentloaded' });
|
|
}
|
|
|
|
// Wait for login form
|
|
await page.waitForSelector('form');
|
|
|
|
// Fill login form
|
|
await page.type('input[name="username"]', TEST_USERNAME);
|
|
await page.type('input[name="password"]', TEST_PASSWORD);
|
|
|
|
// Submit form
|
|
await page.click('button[type="submit"]');
|
|
|
|
// Wait for redirect to dashboard
|
|
await page.waitForNavigation({ waitUntil: 'domcontentloaded' });
|
|
|
|
// Verify we're logged in
|
|
const dashboardElement = await page.$('.dashboard, #dashboard, [data-page="home"]');
|
|
expect(dashboardElement).to.not.be.null;
|
|
});
|
|
});
|
|
|
|
describe('OpenAI API Key Configuration', () => {
|
|
beforeEach(async () => {
|
|
// Ensure we're logged in
|
|
await loginUser(page, TEST_USERNAME, TEST_PASSWORD);
|
|
});
|
|
|
|
it('should navigate to settings page', async () => {
|
|
// Click on Settings link/button
|
|
const settingsSelector = 'a[href="/settings"], button:contains("Settings"), .settings-link';
|
|
await page.waitForSelector(settingsSelector);
|
|
await page.click(settingsSelector);
|
|
|
|
// Wait for settings page to load
|
|
await page.waitForSelector('.settings-page, #settings, [data-page="settings"]');
|
|
|
|
// Verify we're on settings page
|
|
const url = page.url();
|
|
expect(url).to.include('/settings');
|
|
});
|
|
|
|
it('should configure OpenAI provider and API key', async () => {
|
|
// Navigate to settings
|
|
await page.goto(`${BASE_URL}/settings`, { waitUntil: 'domcontentloaded' });
|
|
|
|
// Select OpenAI as provider
|
|
const providerSelect = await page.$('select[name="llm.provider"], #llm-provider');
|
|
if (providerSelect) {
|
|
await page.select('select[name="llm.provider"], #llm-provider', 'openai');
|
|
} else {
|
|
// Alternative: click on OpenAI option if using custom dropdown
|
|
await page.click('[data-provider="openai"], .provider-option[data-value="openai"]');
|
|
}
|
|
|
|
// Wait for OpenAI settings to appear
|
|
await page.waitForSelector('input[name="llm.openai.api_key"], #openai-api-key', { visible: true });
|
|
|
|
// Clear and enter API key
|
|
const apiKeyInput = await page.$('input[name="llm.openai.api_key"], #openai-api-key');
|
|
await apiKeyInput.click({ clickCount: 3 }); // Select all
|
|
await apiKeyInput.type(TEST_OPENAI_KEY);
|
|
|
|
// Select model (optional)
|
|
const modelSelect = await page.$('select[name="llm.model"], #llm-model');
|
|
if (modelSelect) {
|
|
await page.select('select[name="llm.model"], #llm-model', 'gpt-3.5-turbo');
|
|
}
|
|
|
|
// Save settings
|
|
await page.click('button[type="submit"], .save-settings, #save-settings');
|
|
|
|
// Wait for save confirmation
|
|
await page.waitForSelector('.success-message, .toast-success, [data-status="success"]', {
|
|
timeout: 5000
|
|
});
|
|
|
|
// Verify settings were saved
|
|
const successMessage = await page.$eval(
|
|
'.success-message, .toast-success, [data-status="success"]',
|
|
el => el.textContent
|
|
);
|
|
expect(successMessage).to.include('saved').or.to.include('success');
|
|
});
|
|
|
|
it('should mask API key after saving', async () => {
|
|
// Navigate to settings
|
|
await page.goto(`${BASE_URL}/settings`, { waitUntil: 'domcontentloaded' });
|
|
|
|
// Wait for settings to load
|
|
await page.waitForSelector('input[name="llm.openai.api_key"], #openai-api-key');
|
|
|
|
// Check if API key is masked
|
|
const apiKeyInput = await page.$('input[name="llm.openai.api_key"], #openai-api-key');
|
|
const inputType = await apiKeyInput.evaluate(el => el.type);
|
|
const inputValue = await apiKeyInput.evaluate(el => el.value);
|
|
|
|
// Should be password type or show masked value
|
|
expect(inputType).to.equal('password').or.expect(inputValue).to.match(/\*{4,}/);
|
|
});
|
|
});
|
|
|
|
describe('Research with OpenAI', () => {
|
|
beforeEach(async () => {
|
|
// Ensure we're logged in and have OpenAI configured
|
|
await loginUser(page, TEST_USERNAME, TEST_PASSWORD);
|
|
});
|
|
|
|
it('should perform research using configured OpenAI API', async () => {
|
|
// Navigate to home/research page
|
|
await page.goto(BASE_URL, { waitUntil: 'domcontentloaded' });
|
|
|
|
// Find and fill research query input
|
|
await page.waitForSelector('input[name="query"], #query, .search-input');
|
|
await page.type('input[name="query"], #query, .search-input', 'What is machine learning?');
|
|
|
|
// Click search/research button
|
|
await page.click('button[type="submit"], .search-button, #start-research');
|
|
|
|
// Wait for research to start
|
|
await page.waitForSelector('.research-status, .loading, [data-status="running"]', {
|
|
timeout: 10000
|
|
});
|
|
|
|
// Wait for research to complete (with longer timeout)
|
|
await page.waitForSelector('.research-complete, .research-summary, [data-status="completed"]', {
|
|
timeout: 30000
|
|
});
|
|
|
|
// Verify results contain expected content
|
|
const summaryText = await page.$eval(
|
|
'.research-summary, .summary-content, [data-content="summary"]',
|
|
el => el.textContent
|
|
);
|
|
|
|
expect(summaryText).to.include('machine learning').or.to.include('Machine Learning');
|
|
expect(summaryText.length).to.be.greaterThan(100); // Should have substantial content
|
|
});
|
|
|
|
it('should show error if API key is invalid', async () => {
|
|
// Configure with invalid API key
|
|
await page.goto(`${BASE_URL}/settings`, { waitUntil: 'domcontentloaded' });
|
|
|
|
// Set invalid API key
|
|
const apiKeyInput = await page.$('input[name="llm.openai.api_key"], #openai-api-key');
|
|
await apiKeyInput.click({ clickCount: 3 });
|
|
await apiKeyInput.type('sk-invalid-key');
|
|
|
|
// Save settings
|
|
await page.click('button[type="submit"], .save-settings, #save-settings');
|
|
await page.waitForTimeout(1000); // Wait for save
|
|
|
|
// Try to perform research
|
|
await page.goto(BASE_URL, { waitUntil: 'domcontentloaded' });
|
|
await page.type('input[name="query"], #query, .search-input', 'Test query');
|
|
await page.click('button[type="submit"], .search-button, #start-research');
|
|
|
|
// Wait for error message
|
|
await page.waitForSelector('.error-message, .toast-error, [data-status="error"]', {
|
|
timeout: 15000
|
|
});
|
|
|
|
// Verify error message mentions API key or authentication
|
|
const errorText = await page.$eval(
|
|
'.error-message, .toast-error, [data-status="error"]',
|
|
el => el.textContent
|
|
);
|
|
|
|
expect(errorText.toLowerCase()).to.include('api').or.include('auth').or.include('key');
|
|
});
|
|
});
|
|
|
|
describe('Settings Persistence', () => {
|
|
it('should persist OpenAI settings across sessions', async () => {
|
|
// Login
|
|
await loginUser(page, TEST_USERNAME, TEST_PASSWORD);
|
|
|
|
// Configure OpenAI
|
|
await page.goto(`${BASE_URL}/settings`, { waitUntil: 'domcontentloaded' });
|
|
await page.select('select[name="llm.provider"], #llm-provider', 'openai');
|
|
await page.type('input[name="llm.openai.api_key"], #openai-api-key', TEST_OPENAI_KEY);
|
|
await page.click('button[type="submit"], .save-settings, #save-settings');
|
|
|
|
// Wait for save
|
|
await page.waitForTimeout(2000);
|
|
|
|
// Logout
|
|
await page.click('a[href="/logout"], .logout-button, #logout');
|
|
await page.waitForNavigation({ waitUntil: 'domcontentloaded' });
|
|
|
|
// Login again
|
|
await loginUser(page, TEST_USERNAME, TEST_PASSWORD);
|
|
|
|
// Go to settings
|
|
await page.goto(`${BASE_URL}/settings`, { waitUntil: 'domcontentloaded' });
|
|
|
|
// Verify provider is still OpenAI
|
|
const selectedProvider = await page.$eval(
|
|
'select[name="llm.provider"], #llm-provider',
|
|
el => el.value
|
|
);
|
|
expect(selectedProvider).to.equal('openai');
|
|
|
|
// Verify API key field has value (even if masked)
|
|
const apiKeyValue = await page.$eval(
|
|
'input[name="llm.openai.api_key"], #openai-api-key',
|
|
el => el.value
|
|
);
|
|
expect(apiKeyValue).to.not.be.empty;
|
|
});
|
|
});
|
|
});
|
|
|
|
// Helper function to login
|
|
async function loginUser(page, username, password) {
|
|
const currentUrl = page.url();
|
|
|
|
// Check if already logged in
|
|
if (currentUrl.includes('/settings') || currentUrl.includes('/research')) {
|
|
return;
|
|
}
|
|
|
|
// Navigate to login
|
|
await page.goto(`${BASE_URL}/login`, { waitUntil: 'domcontentloaded' });
|
|
|
|
// Fill and submit login form
|
|
await page.type('input[name="username"]', username);
|
|
await page.type('input[name="password"]', password);
|
|
await page.click('button[type="submit"]');
|
|
|
|
// Wait for redirect
|
|
await page.waitForNavigation({ waitUntil: 'domcontentloaded' });
|
|
}
|