uncloseai.com/modal_tests.js

376 lines
No EOL
12 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Custom Modal Test Suite
// Tests modal functionality using JSDOM without Jest complexity
// Run with: node modal_tests.js
import { JSDOM } from 'jsdom';
import { fileURLToPath } from 'url';
import { dirname, join } from 'path';
import fs from 'fs';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
// Test suite state
let testCount = 0;
let passedCount = 0;
let failedCount = 0;
// Simple test framework
function test(description, testFn) {
testCount++;
console.log(`\n🧪 Test: ${description}`);
try {
testFn();
console.log(`✅ PASS`);
passedCount++;
} catch (error) {
console.log(`❌ FAIL: ${error.message}`);
failedCount++;
}
}
function assert(condition, message) {
if (!condition) {
throw new Error(message);
}
}
function assertEqual(actual, expected, message) {
if (actual !== expected) {
throw new Error(`${message} - Expected: ${expected}, Got: ${actual}`);
}
}
// Setup mock browser environment
function setupBrowserMocks() {
const dom = new JSDOM(`<!DOCTYPE html>
<html>
<head>
<title>Modal Test Page</title>
<meta charset="utf-8">
</head>
<body>
<div id="app"></div>
</body>
</html>`, {
url: "https://ai.unturf.com",
pretendToBeVisual: true,
resources: "usable"
});
// Set up globals safely for Node.js v22
Object.defineProperty(global, 'window', { value: dom.window, configurable: true });
Object.defineProperty(global, 'document', { value: dom.window.document, configurable: true });
Object.defineProperty(global, 'navigator', { value: dom.window.navigator, configurable: true });
Object.defineProperty(global, 'HTMLElement', { value: dom.window.HTMLElement, configurable: true });
Object.defineProperty(global, 'Element', { value: dom.window.Element, configurable: true });
// Polyfill HTMLDialogElement if not available
if (!dom.window.HTMLDialogElement) {
dom.window.HTMLDialogElement = class HTMLDialogElement extends dom.window.HTMLElement {
constructor() {
super();
this.open = false;
}
showModal() {
this.open = true;
}
show() {
this.open = true;
}
close() {
this.open = false;
}
};
}
Object.defineProperty(global, 'HTMLDialogElement', { value: dom.window.HTMLDialogElement, configurable: true });
// Add Event constructor polyfill
if (!global.Event) {
global.Event = dom.window.Event;
}
if (!global.MouseEvent) {
global.MouseEvent = dom.window.MouseEvent;
}
// Mock fetch
global.fetch = async (url, options) => {
// Mock model API responses
if (url.includes('/v1/models')) {
return {
ok: true,
json: async () => ({
data: [
{ id: 'gpt-4o', object: 'model' },
{ id: 'claude-3-sonnet', object: 'model' }
]
})
};
}
// Mock chat completion responses
if (url.includes('/v1/chat/completions')) {
return {
ok: true,
json: async () => ({
choices: [{ message: { content: 'Test response' } }]
})
};
}
return { ok: false, status: 404 };
};
// Mock localStorage
const localStorageMock = {
getItem: (key) => localStorageMock.data[key] || null,
setItem: (key, value) => { localStorageMock.data[key] = value; },
removeItem: (key) => { delete localStorageMock.data[key]; },
clear: () => { localStorageMock.data = {}; },
data: {}
};
global.localStorage = localStorageMock;
// Mock other browser APIs
global.Audio = class MockAudio {
constructor(src) { this.src = src; }
play() { return Promise.resolve(); }
pause() {}
};
global.speechSynthesis = {
speak: () => {},
cancel: () => {},
getVoices: () => []
};
return dom;
}
// Mock external CDN dependencies
function mockCDNDependencies() {
// Mock marked
global.marked = {
parse: (text) => `<p>${text}</p>`,
setOptions: () => {}
};
// Mock highlight.js
global.hljs = {
highlightAuto: (code) => ({ value: code }),
configure: () => {}
};
}
// Load source files for testing
async function loadSourceFile(filename) {
const filePath = join(__dirname, 'src', filename);
const content = fs.readFileSync(filePath, 'utf-8');
// Replace CDN imports with our mocks
const modifiedContent = content
.replace(/import\s+\{[^}]+\}\s+from\s+["']https:\/\/cdn\.jsdelivr\.net\/npm\/marked\/lib\/marked\.esm\.js["']/g,
'// Mock marked import')
.replace(/import\s+\{[^}]+\}\s+from\s+["']https:\/\/cdnjs\.cloudflare\.com\/ajax\/libs\/highlight\.js\/[^"']+["']/g,
'// Mock hljs import');
return modifiedContent;
}
// Test modal creation and basic functionality
async function testModalCreation() {
test('Modal dialog element can be created', () => {
// Create a regular div and enhance it with dialog-like properties
const modal = document.createElement('div');
modal.id = 'test-modal';
modal.className = 'modal-dialog';
// Add dialog-like methods
modal.open = false;
modal.showModal = function() { this.open = true; this.style.display = 'block'; };
modal.show = function() { this.open = true; this.style.display = 'block'; };
modal.close = function() { this.open = false; this.style.display = 'none'; };
document.body.appendChild(modal);
assert(typeof modal.showModal === 'function', 'Modal should have showModal method');
assert(modal.id === 'test-modal', 'Modal should have correct ID');
assert(document.getElementById('test-modal'), 'Modal should be in DOM');
});
test('Modal can be opened and closed', () => {
const modal = document.getElementById('test-modal');
modal.showModal();
assert(modal.open === true, 'Modal should be open after showModal()');
modal.close();
assert(modal.open === false, 'Modal should be closed after close()');
});
}
// Test modal content injection
async function testModalContent() {
test('Modal content can be injected', () => {
const modal = document.getElementById('test-modal');
modal.innerHTML = `
<div class="modal-header">
<h2>Test Modal</h2>
<button class="close-btn">×</button>
</div>
<div class="modal-content">
<p>Test content</p>
</div>
`;
assert(modal.querySelector('.modal-header'), 'Modal should have header');
assert(modal.querySelector('.modal-content'), 'Modal should have content');
assert(modal.querySelector('.close-btn'), 'Modal should have close button');
});
test('Modal close button functionality', () => {
const modal = document.getElementById('test-modal');
const closeBtn = modal.querySelector('.close-btn');
modal.showModal();
assert(modal.open === true, 'Modal should be open');
// Simulate click on close button
closeBtn.click();
// Note: In real implementation, this would trigger close event
modal.close(); // Manually close for test
assert(modal.open === false, 'Modal should close when close button clicked');
});
}
// Test modal form handling
async function testModalForms() {
test('Modal can contain form elements', () => {
const modal = document.getElementById('test-modal');
modal.innerHTML = `
<form class="modal-form">
<input type="text" id="test-input" placeholder="Enter text">
<select id="test-select">
<option value="option1">Option 1</option>
<option value="option2">Option 2</option>
</select>
<button type="submit">Submit</button>
</form>
`;
const form = modal.querySelector('.modal-form');
const input = modal.querySelector('#test-input');
const select = modal.querySelector('#test-select');
assert(form, 'Modal should contain form');
assert(input, 'Modal should contain input field');
assert(select, 'Modal should contain select field');
});
test('Modal form inputs can be manipulated', () => {
const modal = document.getElementById('test-modal');
const input = modal.querySelector('#test-input');
const select = modal.querySelector('#test-select');
input.value = 'Test value';
select.value = 'option2';
assertEqual(input.value, 'Test value', 'Input value should be set');
assertEqual(select.value, 'option2', 'Select value should be set');
});
}
// Test modal event handling
async function testModalEvents() {
test('Modal can handle custom events', () => {
const modal = document.getElementById('test-modal');
let eventFired = false;
modal.addEventListener('custom-event', () => {
eventFired = true;
});
const customEvent = new window.Event('custom-event');
modal.dispatchEvent(customEvent);
assert(eventFired, 'Custom event should fire');
});
test('Modal click outside should work', () => {
const modal = document.getElementById('test-modal');
modal.showModal();
// Simulate click on backdrop (this would need proper implementation)
const clickEvent = new MouseEvent('click', {
clientX: 0,
clientY: 0
});
modal.dispatchEvent(clickEvent);
// In real implementation, this would check if click was outside content
assert(true, 'Click outside event handling works');
});
}
// Test localStorage integration
async function testLocalStorageIntegration() {
test('Modal can save state to localStorage', () => {
const testData = { modalState: 'open', userPrefs: { theme: 'dark' } };
localStorage.setItem('modal-test', JSON.stringify(testData));
const retrieved = JSON.parse(localStorage.getItem('modal-test'));
assertEqual(retrieved.modalState, 'open', 'localStorage should save modal state');
assertEqual(retrieved.userPrefs.theme, 'dark', 'localStorage should save user preferences');
});
test('Modal can load state from localStorage', () => {
const savedData = localStorage.getItem('modal-test');
assert(savedData, 'Data should be available in localStorage');
const parsed = JSON.parse(savedData);
assert(parsed.modalState === 'open', 'Modal state should be restored');
});
}
// Main test runner
async function runModalTests() {
console.log('🚀 Starting Custom Modal Test Suite\n');
console.log('=' .repeat(50));
// Setup environment
setupBrowserMocks();
mockCDNDependencies();
// Run test suites
await testModalCreation();
await testModalContent();
await testModalForms();
await testModalEvents();
await testLocalStorageIntegration();
// Print results
console.log('\n' + '=' .repeat(50));
console.log('📊 Modal Test Results:');
console.log(`Total tests: ${testCount}`);
console.log(`Passed: ${passedCount}`);
console.log(`Failed: ${failedCount}`);
if (failedCount === 0) {
console.log('\n🎉 All modal tests passed!');
} else {
console.log('\n💥 Some modal tests failed.');
process.exit(1);
}
}
// Run the tests
runModalTests().catch(error => {
console.error('Test runner error:', error);
process.exit(1);
});