项目文件夹

文件
wehub-resource-sync 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
chore: import upstream snapshot with attribution
2026-07-13 13:08:55 +08:00

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' });
}