Files
bookmarksite/tests/test_json_import_export.html
2025-07-20 20:43:06 +02:00

381 lines
16 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>JSON Import/Export Test</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
.test-section {
margin: 20px 0;
padding: 15px;
border: 1px solid #ddd;
border-radius: 5px;
}
.test-result {
margin: 10px 0;
padding: 10px;
border-radius: 3px;
}
.test-pass {
background-color: #d4edda;
color: #155724;
border: 1px solid #c3e6cb;
}
.test-fail {
background-color: #f8d7da;
color: #721c24;
border: 1px solid #f5c6cb;
}
button {
margin: 5px;
padding: 8px 16px;
background: #007bff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
button:hover {
background: #0056b3;
}
pre {
background: #f8f9fa;
padding: 10px;
border-radius: 4px;
overflow-x: auto;
font-size: 12px;
}
</style>
</head>
<body>
<h1>JSON Import/Export Test</h1>
<div class="test-section">
<h2>Test JSON Export Format</h2>
<button onclick="testJSONExport()">Test JSON Export</button>
<div id="exportResults"></div>
<pre id="exportSample"></pre>
</div>
<div class="test-section">
<h2>Test JSON Import Parsing</h2>
<button onclick="testJSONImport()">Test JSON Import</button>
<div id="importResults"></div>
</div>
<div class="test-section">
<h2>Test Round-trip (Export → Import)</h2>
<button onclick="testRoundTrip()">Test Round-trip</button>
<div id="roundtripResults"></div>
</div>
<script>
// Mock BookmarkManager for testing
class MockBookmarkManager {
constructor() {
this.bookmarks = [
{
id: '1',
title: 'Test Bookmark 1',
url: 'https://example.com',
folder: 'Test Folder',
tags: ['test', 'example'],
notes: 'Test notes',
rating: 4,
favorite: true,
addDate: Date.now(),
lastModified: null,
lastVisited: null,
icon: '',
status: 'valid',
errorCategory: null,
lastTested: null
},
{
id: '2',
title: 'Test Bookmark 2',
url: 'https://test.com',
folder: '',
tags: [],
notes: '',
rating: 0,
favorite: false,
addDate: Date.now() - 86400000,
lastModified: Date.now(),
lastVisited: Date.now() - 3600000,
icon: 'https://test.com/favicon.ico',
status: 'unknown',
errorCategory: null,
lastTested: null
}
];
}
// Generate JSON export (matching the actual implementation)
generateJSONExport(bookmarksToExport) {
const exportData = {
exportDate: new Date().toISOString(),
version: '1.1',
totalBookmarks: bookmarksToExport.length,
bookmarks: bookmarksToExport.map(bookmark => ({
id: bookmark.id,
title: bookmark.title,
url: bookmark.url,
folder: bookmark.folder || '',
tags: bookmark.tags || [],
notes: bookmark.notes || '',
rating: bookmark.rating || 0,
favorite: bookmark.favorite || false,
addDate: bookmark.addDate,
lastModified: bookmark.lastModified,
lastVisited: bookmark.lastVisited,
icon: bookmark.icon || '',
status: bookmark.status,
errorCategory: bookmark.errorCategory,
lastTested: bookmark.lastTested
}))
};
return JSON.stringify(exportData, null, 2);
}
// Parse JSON bookmarks (matching the actual implementation)
parseJSONBookmarks(content) {
try {
const data = JSON.parse(content);
// Check if it's our export format
if (data.bookmarks && Array.isArray(data.bookmarks)) {
return data.bookmarks.map(bookmark => ({
id: bookmark.id || Date.now() + Math.random(),
title: bookmark.title || 'Untitled',
url: bookmark.url || '',
folder: bookmark.folder || '',
tags: bookmark.tags || [],
notes: bookmark.notes || '',
rating: bookmark.rating || 0,
favorite: bookmark.favorite || false,
addDate: bookmark.addDate || Date.now(),
lastModified: bookmark.lastModified || null,
lastVisited: bookmark.lastVisited || null,
icon: bookmark.icon || '',
status: 'unknown', // Reset status on import
errorCategory: null,
lastTested: null
}));
}
// If it's just an array of bookmarks
if (Array.isArray(data)) {
return data.map(bookmark => ({
id: bookmark.id || Date.now() + Math.random(),
title: bookmark.title || 'Untitled',
url: bookmark.url || '',
folder: bookmark.folder || '',
tags: bookmark.tags || [],
notes: bookmark.notes || '',
rating: bookmark.rating || 0,
favorite: bookmark.favorite || false,
addDate: bookmark.addDate || Date.now(),
lastModified: bookmark.lastModified || null,
lastVisited: bookmark.lastVisited || null,
icon: bookmark.icon || '',
status: 'unknown',
errorCategory: null,
lastTested: null
}));
}
throw new Error('Invalid JSON bookmark format');
} catch (error) {
throw new Error(`Failed to parse JSON bookmarks: ${error.message}`);
}
}
}
const mockManager = new MockBookmarkManager();
function displayResult(containerId, message, isPass) {
const container = document.getElementById(containerId);
const resultDiv = document.createElement('div');
resultDiv.className = `test-result ${isPass ? 'test-pass' : 'test-fail'}`;
resultDiv.textContent = message;
container.appendChild(resultDiv);
}
function testJSONExport() {
const container = document.getElementById('exportResults');
const sampleContainer = document.getElementById('exportSample');
container.innerHTML = '';
sampleContainer.innerHTML = '';
try {
const jsonExport = mockManager.generateJSONExport(mockManager.bookmarks);
const exportData = JSON.parse(jsonExport);
// Test export structure
const hasExportDate = exportData.exportDate && typeof exportData.exportDate === 'string';
displayResult('exportResults', `Export date present: ${hasExportDate ? 'PASS' : 'FAIL'}`, hasExportDate);
const hasVersion = exportData.version && exportData.version === '1.1';
displayResult('exportResults', `Version correct: ${hasVersion ? 'PASS' : 'FAIL'}`, hasVersion);
const hasCorrectCount = exportData.totalBookmarks === mockManager.bookmarks.length;
displayResult('exportResults', `Bookmark count correct: ${hasCorrectCount ? 'PASS' : 'FAIL'}`, hasCorrectCount);
const hasBookmarksArray = Array.isArray(exportData.bookmarks);
displayResult('exportResults', `Bookmarks array present: ${hasBookmarksArray ? 'PASS' : 'FAIL'}`, hasBookmarksArray);
// Test first bookmark structure
if (exportData.bookmarks.length > 0) {
const firstBookmark = exportData.bookmarks[0];
const hasRequiredFields = firstBookmark.id && firstBookmark.title && firstBookmark.url;
displayResult('exportResults', `Required fields present: ${hasRequiredFields ? 'PASS' : 'FAIL'}`, hasRequiredFields);
const hasOptionalFields = 'tags' in firstBookmark && 'notes' in firstBookmark && 'rating' in firstBookmark;
displayResult('exportResults', `Optional fields present: ${hasOptionalFields ? 'PASS' : 'FAIL'}`, hasOptionalFields);
}
// Show sample export
sampleContainer.textContent = jsonExport;
} catch (error) {
displayResult('exportResults', `Export error: ${error.message}`, false);
}
}
function testJSONImport() {
const container = document.getElementById('importResults');
container.innerHTML = '';
try {
// Test with our export format
const sampleExport = {
exportDate: new Date().toISOString(),
version: '1.1',
totalBookmarks: 2,
bookmarks: [
{
id: 'test1',
title: 'Import Test 1',
url: 'https://import-test.com',
folder: 'Import Folder',
tags: ['import', 'test'],
notes: 'Import test notes',
rating: 3,
favorite: false,
addDate: Date.now(),
lastModified: null,
lastVisited: null,
icon: '',
status: 'valid',
errorCategory: null,
lastTested: null
},
{
id: 'test2',
title: 'Import Test 2',
url: 'https://import-test2.com',
folder: '',
tags: [],
notes: '',
rating: 0,
favorite: true,
addDate: Date.now(),
lastModified: null,
lastVisited: null,
icon: '',
status: 'unknown',
errorCategory: null,
lastTested: null
}
]
};
const importedBookmarks = mockManager.parseJSONBookmarks(JSON.stringify(sampleExport));
const correctCount = importedBookmarks.length === 2;
displayResult('importResults', `Import count correct: ${correctCount ? 'PASS' : 'FAIL'}`, correctCount);
const firstBookmarkCorrect = importedBookmarks[0].title === 'Import Test 1' &&
importedBookmarks[0].url === 'https://import-test.com';
displayResult('importResults', `First bookmark correct: ${firstBookmarkCorrect ? 'PASS' : 'FAIL'}`, firstBookmarkCorrect);
const statusReset = importedBookmarks[0].status === 'unknown';
displayResult('importResults', `Status reset on import: ${statusReset ? 'PASS' : 'FAIL'}`, statusReset);
const tagsPreserved = Array.isArray(importedBookmarks[0].tags) &&
importedBookmarks[0].tags.includes('import');
displayResult('importResults', `Tags preserved: ${tagsPreserved ? 'PASS' : 'FAIL'}`, tagsPreserved);
// Test with simple array format
const simpleArray = [
{ title: 'Simple Test', url: 'https://simple.com', folder: 'Simple' }
];
const simpleImported = mockManager.parseJSONBookmarks(JSON.stringify(simpleArray));
const simpleWorking = simpleImported.length === 1 && simpleImported[0].title === 'Simple Test';
displayResult('importResults', `Simple array format: ${simpleWorking ? 'PASS' : 'FAIL'}`, simpleWorking);
} catch (error) {
displayResult('importResults', `Import error: ${error.message}`, false);
}
}
function testRoundTrip() {
const container = document.getElementById('roundtripResults');
container.innerHTML = '';
try {
// Export bookmarks
const exported = mockManager.generateJSONExport(mockManager.bookmarks);
// Import them back
const imported = mockManager.parseJSONBookmarks(exported);
// Compare
const countMatch = imported.length === mockManager.bookmarks.length;
displayResult('roundtripResults', `Count preserved: ${countMatch ? 'PASS' : 'FAIL'}`, countMatch);
const titlesMatch = imported.every((bookmark, index) =>
bookmark.title === mockManager.bookmarks[index].title
);
displayResult('roundtripResults', `Titles preserved: ${titlesMatch ? 'PASS' : 'FAIL'}`, titlesMatch);
const urlsMatch = imported.every((bookmark, index) =>
bookmark.url === mockManager.bookmarks[index].url
);
displayResult('roundtripResults', `URLs preserved: ${urlsMatch ? 'PASS' : 'FAIL'}`, urlsMatch);
const foldersMatch = imported.every((bookmark, index) =>
bookmark.folder === mockManager.bookmarks[index].folder
);
displayResult('roundtripResults', `Folders preserved: ${foldersMatch ? 'PASS' : 'FAIL'}`, foldersMatch);
const tagsMatch = imported.every((bookmark, index) =>
JSON.stringify(bookmark.tags) === JSON.stringify(mockManager.bookmarks[index].tags)
);
displayResult('roundtripResults', `Tags preserved: ${tagsMatch ? 'PASS' : 'FAIL'}`, tagsMatch);
const ratingsMatch = imported.every((bookmark, index) =>
bookmark.rating === mockManager.bookmarks[index].rating
);
displayResult('roundtripResults', `Ratings preserved: ${ratingsMatch ? 'PASS' : 'FAIL'}`, ratingsMatch);
const favoritesMatch = imported.every((bookmark, index) =>
bookmark.favorite === mockManager.bookmarks[index].favorite
);
displayResult('roundtripResults', `Favorites preserved: ${favoritesMatch ? 'PASS' : 'FAIL'}`, favoritesMatch);
} catch (error) {
displayResult('roundtripResults', `Round-trip error: ${error.message}`, false);
}
}
</script>
</body>
</html>