343 lines
11 KiB
HTML
343 lines
11 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>RPG Companion - Test Runner</title>
|
|
<style>
|
|
:root {
|
|
--bg: #1a1a2e;
|
|
--surface: #16213e;
|
|
--border: #0f3460;
|
|
--text: #e8e8e8;
|
|
--accent: #e94560;
|
|
--success: #4caf50;
|
|
--error: #f44336;
|
|
--warning: #ff9800;
|
|
}
|
|
|
|
* {
|
|
box-sizing: border-box;
|
|
margin: 0;
|
|
padding: 0;
|
|
}
|
|
|
|
body {
|
|
font-family: 'Segoe UI', system-ui, sans-serif;
|
|
background: var(--bg);
|
|
color: var(--text);
|
|
padding: 2rem;
|
|
line-height: 1.6;
|
|
}
|
|
|
|
.container {
|
|
max-width: 900px;
|
|
margin: 0 auto;
|
|
}
|
|
|
|
h1 {
|
|
color: var(--accent);
|
|
margin-bottom: 1rem;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
}
|
|
|
|
h1::before {
|
|
content: '🧪';
|
|
}
|
|
|
|
.description {
|
|
background: var(--surface);
|
|
padding: 1rem;
|
|
border-radius: 8px;
|
|
margin-bottom: 2rem;
|
|
border-left: 4px solid var(--accent);
|
|
}
|
|
|
|
.controls {
|
|
display: flex;
|
|
gap: 1rem;
|
|
margin-bottom: 2rem;
|
|
}
|
|
|
|
button {
|
|
background: var(--accent);
|
|
color: white;
|
|
border: none;
|
|
padding: 0.75rem 1.5rem;
|
|
border-radius: 6px;
|
|
cursor: pointer;
|
|
font-size: 1rem;
|
|
font-weight: 600;
|
|
transition: all 0.2s;
|
|
}
|
|
|
|
button:hover {
|
|
transform: translateY(-2px);
|
|
box-shadow: 0 4px 12px rgba(233, 69, 96, 0.3);
|
|
}
|
|
|
|
button.secondary {
|
|
background: var(--surface);
|
|
border: 1px solid var(--border);
|
|
}
|
|
|
|
.results-summary {
|
|
display: flex;
|
|
gap: 2rem;
|
|
margin-bottom: 2rem;
|
|
padding: 1rem;
|
|
background: var(--surface);
|
|
border-radius: 8px;
|
|
}
|
|
|
|
.stat {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
}
|
|
|
|
.stat-value {
|
|
font-size: 2.5rem;
|
|
font-weight: bold;
|
|
}
|
|
|
|
.stat-label {
|
|
font-size: 0.85rem;
|
|
opacity: 0.7;
|
|
text-transform: uppercase;
|
|
}
|
|
|
|
.stat.passed .stat-value { color: var(--success); }
|
|
.stat.failed .stat-value { color: var(--error); }
|
|
.stat.total .stat-value { color: var(--accent); }
|
|
|
|
.test-output {
|
|
background: #0d1117;
|
|
border: 1px solid var(--border);
|
|
border-radius: 8px;
|
|
padding: 1rem;
|
|
font-family: 'Fira Code', 'Consolas', monospace;
|
|
font-size: 0.9rem;
|
|
max-height: 500px;
|
|
overflow-y: auto;
|
|
}
|
|
|
|
.test-output .pass { color: var(--success); }
|
|
.test-output .fail { color: var(--error); }
|
|
.test-output .section {
|
|
color: var(--accent);
|
|
font-weight: bold;
|
|
margin-top: 1rem;
|
|
}
|
|
.test-output .info { color: #8b949e; }
|
|
|
|
.test-section {
|
|
margin-bottom: 2rem;
|
|
}
|
|
|
|
h2 {
|
|
color: var(--accent);
|
|
margin-bottom: 1rem;
|
|
font-size: 1.25rem;
|
|
}
|
|
|
|
.json-sample {
|
|
background: #0d1117;
|
|
border: 1px solid var(--border);
|
|
border-radius: 8px;
|
|
padding: 1rem;
|
|
font-family: 'Fira Code', 'Consolas', monospace;
|
|
font-size: 0.8rem;
|
|
overflow-x: auto;
|
|
white-space: pre;
|
|
}
|
|
|
|
.tabs {
|
|
display: flex;
|
|
gap: 0.5rem;
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
.tab {
|
|
padding: 0.5rem 1rem;
|
|
background: var(--surface);
|
|
border: 1px solid var(--border);
|
|
border-radius: 6px 6px 0 0;
|
|
cursor: pointer;
|
|
transition: all 0.2s;
|
|
}
|
|
|
|
.tab.active {
|
|
background: var(--accent);
|
|
border-color: var(--accent);
|
|
}
|
|
|
|
.tab-content {
|
|
display: none;
|
|
}
|
|
|
|
.tab-content.active {
|
|
display: block;
|
|
}
|
|
|
|
.note {
|
|
background: rgba(255, 152, 0, 0.1);
|
|
border: 1px solid var(--warning);
|
|
padding: 1rem;
|
|
border-radius: 8px;
|
|
margin-top: 1rem;
|
|
}
|
|
|
|
.note::before {
|
|
content: '⚠️ ';
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="container">
|
|
<h1>RPG Companion Test Runner</h1>
|
|
|
|
<div class="description">
|
|
<p>This test suite validates the JSON format used for structured tracker data.</p>
|
|
<p>Tests cover: JSON extraction, parsing, data structure validation, and schema generation.</p>
|
|
</div>
|
|
|
|
<div class="controls">
|
|
<button onclick="runTests()">▶️ Run All Tests</button>
|
|
<button class="secondary" onclick="clearResults()">🗑️ Clear Results</button>
|
|
</div>
|
|
|
|
<div class="results-summary" id="results-summary" style="display: none;">
|
|
<div class="stat total">
|
|
<span class="stat-value" id="total-count">0</span>
|
|
<span class="stat-label">Total</span>
|
|
</div>
|
|
<div class="stat passed">
|
|
<span class="stat-value" id="passed-count">0</span>
|
|
<span class="stat-label">Passed</span>
|
|
</div>
|
|
<div class="stat failed">
|
|
<span class="stat-value" id="failed-count">0</span>
|
|
<span class="stat-label">Failed</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="test-section">
|
|
<h2>Test Output</h2>
|
|
<div class="test-output" id="test-output">
|
|
<span class="info">Click "Run All Tests" to start...</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="tabs">
|
|
<div class="tab active" onclick="showTab('valid')">Valid JSON</div>
|
|
<div class="tab" onclick="showTab('malformed')">Malformed JSON</div>
|
|
<div class="tab" onclick="showTab('simplified')">Simplified Inventory</div>
|
|
</div>
|
|
|
|
<div id="tab-valid" class="tab-content active">
|
|
<h2>Sample Valid JSON Response</h2>
|
|
<div class="json-sample" id="valid-json"></div>
|
|
</div>
|
|
|
|
<div id="tab-malformed" class="tab-content">
|
|
<h2>Sample Malformed JSON (with trailing comma)</h2>
|
|
<div class="json-sample" id="malformed-json"></div>
|
|
</div>
|
|
|
|
<div id="tab-simplified" class="tab-content">
|
|
<h2>Sample Simplified Inventory Response</h2>
|
|
<div class="json-sample" id="simplified-json"></div>
|
|
</div>
|
|
|
|
<div class="note">
|
|
<strong>Note:</strong> These tests run in isolation and don't require SillyTavern to be running.
|
|
For integration testing with actual LLM responses, use the Debug Mode in the extension settings.
|
|
</div>
|
|
</div>
|
|
|
|
<script type="module">
|
|
// Import test module
|
|
import {
|
|
runAllTests,
|
|
sampleValidJSONResponse,
|
|
sampleMalformedJSONResponse,
|
|
sampleSimplifiedInventoryResponse
|
|
} from './jsonFormat.test.js';
|
|
|
|
// Display sample JSON
|
|
document.getElementById('valid-json').textContent = sampleValidJSONResponse;
|
|
document.getElementById('malformed-json').textContent = sampleMalformedJSONResponse;
|
|
document.getElementById('simplified-json').textContent = sampleSimplifiedInventoryResponse;
|
|
|
|
// Override console for capturing test output
|
|
const originalLog = console.log;
|
|
const originalError = console.error;
|
|
let outputBuffer = [];
|
|
|
|
function captureConsole() {
|
|
outputBuffer = [];
|
|
console.log = (...args) => {
|
|
outputBuffer.push({ type: 'log', message: args.join(' ') });
|
|
originalLog.apply(console, args);
|
|
};
|
|
console.error = (...args) => {
|
|
outputBuffer.push({ type: 'error', message: args.join(' ') });
|
|
originalError.apply(console, args);
|
|
};
|
|
}
|
|
|
|
function restoreConsole() {
|
|
console.log = originalLog;
|
|
console.error = originalError;
|
|
}
|
|
|
|
function formatOutput(buffer) {
|
|
return buffer.map(item => {
|
|
let cls = 'info';
|
|
if (item.message.includes('✅')) cls = 'pass';
|
|
else if (item.message.includes('❌')) cls = 'fail';
|
|
else if (item.message.includes('📋') || item.message.includes('📦') ||
|
|
item.message.includes('⚔️') || item.message.includes('📜') ||
|
|
item.message.includes('👥') || item.message.includes('📍') ||
|
|
item.message.includes('📝')) cls = 'section';
|
|
return `<div class="${cls}">${escapeHtml(item.message)}</div>`;
|
|
}).join('');
|
|
}
|
|
|
|
function escapeHtml(text) {
|
|
const div = document.createElement('div');
|
|
div.textContent = text;
|
|
return div.innerHTML;
|
|
}
|
|
|
|
window.runTests = function() {
|
|
captureConsole();
|
|
const results = runAllTests();
|
|
restoreConsole();
|
|
|
|
document.getElementById('test-output').innerHTML = formatOutput(outputBuffer);
|
|
document.getElementById('results-summary').style.display = 'flex';
|
|
document.getElementById('total-count').textContent = results.passed + results.failed;
|
|
document.getElementById('passed-count').textContent = results.passed;
|
|
document.getElementById('failed-count').textContent = results.failed;
|
|
};
|
|
|
|
window.clearResults = function() {
|
|
document.getElementById('test-output').innerHTML = '<span class="info">Click "Run All Tests" to start...</span>';
|
|
document.getElementById('results-summary').style.display = 'none';
|
|
};
|
|
|
|
window.showTab = function(tabId) {
|
|
document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
|
|
document.querySelectorAll('.tab-content').forEach(t => t.classList.remove('active'));
|
|
event.target.classList.add('active');
|
|
document.getElementById('tab-' + tabId).classList.add('active');
|
|
};
|
|
</script>
|
|
</body>
|
|
</html>
|
|
|