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
345 lines
13 KiB
JavaScript
345 lines
13 KiB
JavaScript
/**
|
|
* Test for toast notifications when saving settings
|
|
*
|
|
* This test verifies that toast notifications appear when checkbox settings are changed.
|
|
*/
|
|
|
|
const puppeteer = require('puppeteer');
|
|
const AuthHelper = require('./auth_helper');
|
|
const { getPuppeteerLaunchOptions } = require('./puppeteer_config');
|
|
|
|
const TEST_CONFIG = {
|
|
TIMEOUTS: {
|
|
SETTINGS_LOAD: 5000,
|
|
TOAST_APPEAR: 5000,
|
|
AJAX_SAVE: 3000,
|
|
NAVIGATION: 30000
|
|
},
|
|
URLS: {
|
|
BASE: 'http://localhost:5000',
|
|
SETTINGS: 'http://localhost:5000/settings'
|
|
},
|
|
SELECTORS: {
|
|
CHECKBOX: 'input[type="checkbox"].ldr-settings-checkbox',
|
|
TOAST_CONTAINER: '#toast-container',
|
|
TOAST: '.toast, .ldr-toast',
|
|
TOAST_VISIBLE: '.toast.visible, .ldr-toast.visible'
|
|
}
|
|
};
|
|
|
|
(async () => {
|
|
let browser;
|
|
let page;
|
|
const consoleLogs = [];
|
|
const networkRequests = [];
|
|
const networkResponses = [];
|
|
|
|
try {
|
|
console.log('=== Testing Toast Notifications ===\n');
|
|
|
|
browser = await puppeteer.launch(getPuppeteerLaunchOptions());
|
|
page = await browser.newPage();
|
|
await page.setViewport({ width: 1920, height: 1080 });
|
|
|
|
// Capture ONLY toast-related console logs
|
|
page.on('console', msg => {
|
|
const text = msg.text();
|
|
const type = msg.type();
|
|
|
|
// Only log toast-related items
|
|
if (text.includes('showMessage') ||
|
|
text.includes('[Notification]') ||
|
|
text.includes('toast') ||
|
|
text.includes('Toast') ||
|
|
text.includes('[DEBUG]') ||
|
|
text.includes('[submitSettingsData]') ||
|
|
text.includes('originalSettings cache')) {
|
|
consoleLogs.push({ type, text, timestamp: Date.now() });
|
|
console.log(`[BROWSER] ${text}`);
|
|
}
|
|
});
|
|
|
|
// Capture page errors
|
|
page.on('pageerror', error => {
|
|
console.error(`[PAGE ERROR] ${error.message}`);
|
|
consoleLogs.push({ type: 'pageerror', text: error.message, timestamp: Date.now() });
|
|
});
|
|
|
|
// Capture network requests
|
|
page.on('request', req => {
|
|
if (req.url().includes('save_all_settings') || req.url().includes('settings')) {
|
|
networkRequests.push({
|
|
url: req.url(),
|
|
method: req.method(),
|
|
timestamp: Date.now()
|
|
});
|
|
}
|
|
});
|
|
|
|
// Capture network responses
|
|
page.on('response', async resp => {
|
|
if (resp.url().includes('save_all_settings')) {
|
|
try {
|
|
const text = await resp.text();
|
|
networkResponses.push({
|
|
url: resp.url(),
|
|
status: resp.status(),
|
|
body: text.substring(0, 500),
|
|
timestamp: Date.now()
|
|
});
|
|
console.log(`[NETWORK] Response from save_all_settings: ${resp.status()}`);
|
|
} catch {
|
|
// Response already consumed
|
|
}
|
|
}
|
|
});
|
|
|
|
// Authenticate with a consistent user
|
|
console.log('🔐 Authenticating...');
|
|
const authHelper = new AuthHelper(page);
|
|
const testUser = 'toast_test_user';
|
|
const testPassword = 'T3st!Secure#2024$LDR';
|
|
|
|
// Try to register/login this specific user
|
|
try {
|
|
await authHelper.ensureAuthenticated(testUser, testPassword);
|
|
} catch {
|
|
console.log('Initial auth failed, trying direct registration...');
|
|
try {
|
|
await authHelper.register(testUser, testPassword);
|
|
} catch {
|
|
console.log('Registration failed (user may exist), trying login...');
|
|
await authHelper.login(testUser, testPassword);
|
|
}
|
|
}
|
|
console.log('✅ Authenticated\n');
|
|
|
|
// Navigate to settings
|
|
console.log('📄 Navigating to settings page...');
|
|
await page.goto(TEST_CONFIG.URLS.SETTINGS, {
|
|
waitUntil: 'domcontentloaded',
|
|
timeout: TEST_CONFIG.TIMEOUTS.NAVIGATION
|
|
});
|
|
|
|
// Check current URL
|
|
let currentUrl = page.url();
|
|
console.log(`Current URL: ${currentUrl}`);
|
|
|
|
// Check if we got redirected to login - try login with our test user
|
|
if (currentUrl.includes('/auth/login')) {
|
|
console.log('⚠️ Redirected to login, attempting login...');
|
|
await authHelper.login(testUser, testPassword);
|
|
await page.goto(TEST_CONFIG.URLS.SETTINGS, {
|
|
waitUntil: 'domcontentloaded',
|
|
timeout: TEST_CONFIG.TIMEOUTS.NAVIGATION
|
|
});
|
|
currentUrl = page.url();
|
|
console.log(`After re-login URL: ${currentUrl}`);
|
|
}
|
|
|
|
// Wait longer for settings to load (they load dynamically)
|
|
console.log('Waiting for settings page to fully load...');
|
|
await new Promise(resolve => setTimeout(resolve, 5000));
|
|
|
|
// Debug: check page content
|
|
const pageDebug = await page.evaluate(() => ({
|
|
title: document.title,
|
|
url: window.location.href,
|
|
allCheckboxes: document.querySelectorAll('input[type="checkbox"]').length,
|
|
ldrCheckboxes: document.querySelectorAll('input[type="checkbox"].ldr-settings-checkbox').length,
|
|
anyInputs: document.querySelectorAll('input').length,
|
|
settingsContent: !!document.getElementById('settings-content'),
|
|
bodyText: document.body.textContent.substring(0, 500)
|
|
}));
|
|
console.log('Page debug info:', JSON.stringify(pageDebug, null, 2));
|
|
|
|
// Try different selectors
|
|
let checkboxSelector = TEST_CONFIG.SELECTORS.CHECKBOX;
|
|
let checkboxes = await page.$$(checkboxSelector);
|
|
|
|
if (checkboxes.length === 0) {
|
|
console.log('No ldr-settings-checkbox found, trying any checkbox...');
|
|
checkboxSelector = 'input[type="checkbox"]';
|
|
checkboxes = await page.$$(checkboxSelector);
|
|
}
|
|
|
|
if (checkboxes.length === 0) {
|
|
// Take screenshot for debugging
|
|
await page.screenshot({ path: '/tmp/settings_no_checkboxes.png', fullPage: true });
|
|
console.log('📸 Screenshot saved to /tmp/settings_no_checkboxes.png');
|
|
throw new Error(`No checkboxes found. Page has ${pageDebug.anyInputs} inputs total.`);
|
|
}
|
|
|
|
console.log(`✅ Settings page loaded - found ${checkboxes.length} checkboxes\n`);
|
|
|
|
// Check if window.ui is available
|
|
const uiCheck = await page.evaluate(() => {
|
|
return {
|
|
windowUi: !!window.ui,
|
|
showMessage: !!(window.ui && window.ui.showMessage),
|
|
toastContainer: !!document.getElementById('toast-container')
|
|
};
|
|
});
|
|
console.log('UI availability check:', JSON.stringify(uiCheck, null, 2));
|
|
|
|
// Get first checkbox info
|
|
const firstCheckbox = checkboxes[0];
|
|
const checkboxInfo = await firstCheckbox.evaluate(el => ({
|
|
name: el.name,
|
|
checked: el.checked,
|
|
id: el.id
|
|
}));
|
|
console.log('Testing checkbox:', JSON.stringify(checkboxInfo, null, 2));
|
|
|
|
// Clear console logs before toggling
|
|
consoleLogs.length = 0;
|
|
networkRequests.length = 0;
|
|
networkResponses.length = 0;
|
|
|
|
console.log('\n🔄 Toggling checkbox...');
|
|
const initialState = checkboxInfo.checked;
|
|
await firstCheckbox.click();
|
|
|
|
// Wait for AJAX save to complete
|
|
console.log('⏳ Waiting for AJAX save...');
|
|
await new Promise(resolve => setTimeout(resolve, TEST_CONFIG.TIMEOUTS.AJAX_SAVE));
|
|
|
|
// Check checkbox state changed
|
|
const newState = await firstCheckbox.evaluate(el => el.checked);
|
|
console.log(`Checkbox state: ${initialState} → ${newState}`);
|
|
|
|
// Check for toast in DOM
|
|
const toastCheck = await page.evaluate(() => {
|
|
const container = document.getElementById('toast-container');
|
|
const toasts = document.querySelectorAll('.toast, .ldr-toast');
|
|
const visibleToasts = document.querySelectorAll('.toast.visible, .ldr-toast.visible');
|
|
|
|
let containerStyles = null;
|
|
if (container) {
|
|
const computed = window.getComputedStyle(container);
|
|
containerStyles = {
|
|
position: computed.position,
|
|
top: computed.top,
|
|
right: computed.right,
|
|
zIndex: computed.zIndex,
|
|
display: computed.display,
|
|
visibility: computed.visibility
|
|
};
|
|
}
|
|
|
|
const toastInfo = [];
|
|
toasts.forEach((t, i) => {
|
|
const computed = window.getComputedStyle(t);
|
|
toastInfo.push({
|
|
index: i,
|
|
className: t.className,
|
|
innerHTML: t.innerHTML.substring(0, 100),
|
|
opacity: computed.opacity,
|
|
transform: computed.transform,
|
|
display: computed.display,
|
|
visibility: computed.visibility
|
|
});
|
|
});
|
|
|
|
return {
|
|
containerExists: !!container,
|
|
containerStyles,
|
|
totalToasts: toasts.length,
|
|
visibleToasts: visibleToasts.length,
|
|
toastInfo
|
|
};
|
|
});
|
|
|
|
console.log('\n📋 Toast DOM state:');
|
|
console.log(JSON.stringify(toastCheck, null, 2));
|
|
|
|
// Wait a bit more for toast animation
|
|
await new Promise(resolve => setTimeout(resolve, 500));
|
|
|
|
// Check again for visible toasts
|
|
const finalToastCheck = await page.evaluate(() => {
|
|
const visibleToasts = document.querySelectorAll('.toast.visible, .ldr-toast.visible');
|
|
return {
|
|
visibleToastsCount: visibleToasts.length,
|
|
visibleToastsHTML: Array.from(visibleToasts).map(t => t.innerHTML.substring(0, 100))
|
|
};
|
|
});
|
|
console.log('\n📋 Final toast check:');
|
|
console.log(JSON.stringify(finalToastCheck, null, 2));
|
|
|
|
// Print relevant console logs
|
|
console.log('\n📝 Relevant browser console logs:');
|
|
const relevantLogs = consoleLogs.filter(log =>
|
|
log.text.includes('showMessage') ||
|
|
log.text.includes('Notification') ||
|
|
log.text.includes('toast') ||
|
|
log.text.includes('DEBUG') ||
|
|
log.text.includes('submitSettingsData') ||
|
|
log.text.includes('originalSettings') ||
|
|
log.type === 'error'
|
|
);
|
|
|
|
if (relevantLogs.length === 0) {
|
|
console.log(' (No relevant logs captured - this is suspicious!)');
|
|
} else {
|
|
relevantLogs.forEach(log => {
|
|
console.log(` [${log.type}] ${log.text}`);
|
|
});
|
|
}
|
|
|
|
// Print network activity
|
|
console.log('\n🌐 Network activity:');
|
|
console.log(` Requests: ${networkRequests.length}`);
|
|
networkRequests.forEach(req => {
|
|
console.log(` ${req.method} ${req.url}`);
|
|
});
|
|
console.log(` Responses: ${networkResponses.length}`);
|
|
networkResponses.forEach(resp => {
|
|
console.log(` ${resp.status} ${resp.url}`);
|
|
if (resp.body) {
|
|
console.log(` Body: ${resp.body.substring(0, 200)}`);
|
|
}
|
|
});
|
|
|
|
// Take screenshot
|
|
const screenshotPath = '/tmp/toast_test_screenshot.png';
|
|
await page.screenshot({ path: screenshotPath, fullPage: false });
|
|
console.log(`\n📸 Screenshot saved to: ${screenshotPath}`);
|
|
|
|
// Toggle back to original state
|
|
console.log('\n🔄 Restoring original checkbox state...');
|
|
await firstCheckbox.click();
|
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
|
|
// Final verdict
|
|
console.log('\n' + '='.repeat(60));
|
|
if (finalToastCheck.visibleToastsCount > 0) {
|
|
console.log('✅ SUCCESS: Toast notification appeared!');
|
|
} else if (toastCheck.totalToasts > 0) {
|
|
console.log('⚠️ PARTIAL: Toast created but not visible (CSS issue)');
|
|
} else if (networkResponses.length > 0 && networkResponses[0].status === 200) {
|
|
console.log('❌ ISSUE: Save succeeded but no toast was created');
|
|
console.log(' Check if notification code is being reached');
|
|
} else {
|
|
console.log('❌ ISSUE: No save request or toast notification detected');
|
|
}
|
|
console.log('='.repeat(60));
|
|
|
|
} catch (error) {
|
|
console.error('\n❌ Test failed:', error.message);
|
|
console.error(error.stack);
|
|
|
|
// Print all console logs on failure
|
|
console.log('\n📝 All browser console logs:');
|
|
consoleLogs.forEach(log => {
|
|
console.log(` [${log.type}] ${log.text}`);
|
|
});
|
|
|
|
process.exit(1);
|
|
} finally {
|
|
if (browser) {
|
|
await browser.close();
|
|
}
|
|
}
|
|
})();
|