refactor: clean up JavaScript development files and enhance automated testing
Complete cleanup and modernization of JavaScript testing infrastructure with comprehensive automated test coverage and improved output formatting. JavaScript Development Files Cleanup: - Moved 53 manual development/debugging test files to history/javascript-dev-tests/ - Added comprehensive README documenting archived files and their purposes - Cleaned main project directory of development artifacts New Automated Test Suite (68 tests): - keyboard-shortcuts.test.js: Tests Ctrl+Enter, Escape, accessibility features (8 tests) - section-splitting.test.js: Tests heading detection, content parsing, ID generation (14 tests) - image-editing.test.js: Tests dialog positioning, alt text, reset functionality (19 tests) - button-events.test.js: Tests click handling, state management, event delegation (21 tests) Integration Test Fixes: - Fixed 13 failing integration tests by properly mocking component dependencies - Updated tests to match actual component APIs instead of assumed interfaces - Improved error handling and test reliability Enhanced Test Output Formatting: - Updated testdrive-jsui-test-all target to show clear test count summaries - Separated JavaScript (68 tests) and Python (11 tests) results distinctly - Added combined summary showing total coverage (79 tests) - Improved error handling and visual formatting Main Makefile Improvements: - Fixed default target issue by adding .DEFAULT_GOAL := help - Restored proper make help behavior when called without arguments Key Achievements: - Replaced 53 manual test files with 68 automated tests - Achieved 100% test pass rate (79/79 tests passing) - Enhanced CI/CD integration with clear test reporting - Preserved all critical UI functionality in automated test coverage - Improved developer experience with clearer test output Testing Status: - ✅ 68 JavaScript tests (Jest) - Core UI functionality - ✅ 11 Python tests (pytest) - Integration bridge testing - ✅ 100% automated test coverage for critical functionality - ✅ Clean, maintainable test codebase 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
286
history/javascript-dev-tests/test_section_id_generation.js
Normal file
286
history/javascript-dev-tests/test_section_id_generation.js
Normal file
@@ -0,0 +1,286 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* TDD Tests for Sophisticated Section ID Generation with Hash-based Algorithm
|
||||
*/
|
||||
|
||||
const { TestRunner } = require('./test_runner.js');
|
||||
const runner = new TestRunner();
|
||||
|
||||
// Test sophisticated section ID generation functionality
|
||||
runner.describe('Sophisticated Section ID Generation with Hash-based Algorithm', () => {
|
||||
|
||||
runner.it('should generate unique IDs for different content', async () => {
|
||||
// Load editor
|
||||
delete require.cache[require.resolve('/home/worsch/markitect_project/markitect/static/editor.js')];
|
||||
require('/home/worsch/markitect_project/markitect/static/editor.js');
|
||||
|
||||
if (global.Section) {
|
||||
const testCases = [
|
||||
'# Heading One',
|
||||
'# Heading Two',
|
||||
'Different paragraph content',
|
||||
'```javascript\ncode();\n```',
|
||||
'> A quote section'
|
||||
];
|
||||
|
||||
const generatedIds = testCases.map((content, index) =>
|
||||
global.Section.generateId(content, index)
|
||||
);
|
||||
|
||||
// All IDs should be unique
|
||||
const uniqueIds = new Set(generatedIds);
|
||||
runner.expect(uniqueIds.size).toBe(generatedIds.length);
|
||||
|
||||
// IDs should follow consistent format
|
||||
generatedIds.forEach(id => {
|
||||
runner.expect(id).toContain('section-');
|
||||
runner.expect(id.length).toBeGreaterThan(10); // Reasonable length
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
runner.it('should generate consistent IDs for identical content', async () => {
|
||||
if (global.Section) {
|
||||
const content = '# Sample Heading';
|
||||
const position = 0;
|
||||
|
||||
const id1 = global.Section.generateId(content, position);
|
||||
const id2 = global.Section.generateId(content, position);
|
||||
|
||||
runner.expect(id1).toBe(id2);
|
||||
}
|
||||
});
|
||||
|
||||
runner.it('should include section type in ID generation', async () => {
|
||||
if (global.Section) {
|
||||
const testCases = [
|
||||
{ content: '# Heading', expectedType: 'hea' }, // Abbreviated type prefixes
|
||||
{ content: '```code```', expectedType: 'cod' },
|
||||
{ content: '- List item', expectedType: 'lis' },
|
||||
{ content: '> Quote', expectedType: 'quo' },
|
||||
{ content: '', expectedType: 'ima' }
|
||||
];
|
||||
|
||||
testCases.forEach(testCase => {
|
||||
const id = global.Section.generateId(testCase.content, 0);
|
||||
|
||||
// Check if advanced ID generation includes type
|
||||
const hasAdvancedId = typeof global.Section.generateAdvancedId === 'function';
|
||||
|
||||
if (hasAdvancedId) {
|
||||
// Test that the ID contains the abbreviated type prefix
|
||||
runner.expect(id).toContain(testCase.expectedType);
|
||||
} else {
|
||||
// Basic functionality is acceptable
|
||||
runner.expect(id).toBeTruthy();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
runner.it('should use cryptographic hash for content fingerprinting', async () => {
|
||||
if (global.Section) {
|
||||
const content = 'Test content for hashing';
|
||||
|
||||
// Check if sophisticated hashing is available
|
||||
const hasCryptoHash = typeof global.Section.generateCryptoHash === 'function';
|
||||
|
||||
if (hasCryptoHash) {
|
||||
const hash1 = global.Section.generateCryptoHash(content);
|
||||
const hash2 = global.Section.generateCryptoHash(content);
|
||||
|
||||
runner.expect(hash1).toBe(hash2); // Consistent
|
||||
runner.expect(hash1.length).toBeGreaterThanOrEqual(8); // Reasonable length
|
||||
runner.expect(/^[a-f0-9]+$/.test(hash1)).toBeTruthy(); // Hex format
|
||||
} else {
|
||||
// Basic functionality is acceptable
|
||||
runner.expect(true).toBeTruthy();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
runner.it('should handle content normalization for consistent hashing', async () => {
|
||||
if (global.Section) {
|
||||
const variations = [
|
||||
' # Heading ',
|
||||
'# Heading',
|
||||
'# Heading\n',
|
||||
'\n# Heading\n\n'
|
||||
];
|
||||
|
||||
// Check if normalization is available
|
||||
const hasNormalization = typeof global.Section.normalizeContentForHashing === 'function';
|
||||
|
||||
if (hasNormalization) {
|
||||
const hashes = variations.map(content =>
|
||||
global.Section.generateCryptoHash(
|
||||
global.Section.normalizeContentForHashing(content)
|
||||
)
|
||||
);
|
||||
|
||||
// All normalized versions should produce the same hash
|
||||
const uniqueHashes = new Set(hashes);
|
||||
runner.expect(uniqueHashes.size).toBe(1);
|
||||
} else {
|
||||
// Basic functionality is acceptable
|
||||
runner.expect(true).toBeTruthy();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
runner.it('should support collision detection and resolution', async () => {
|
||||
if (global.Section) {
|
||||
// Check if collision detection is available
|
||||
const hasCollisionDetection = typeof global.Section.detectIdCollision === 'function';
|
||||
|
||||
if (hasCollisionDetection) {
|
||||
const existingIds = new Set(['section-abc123', 'section-def456']);
|
||||
const collision = global.Section.detectIdCollision('section-abc123', existingIds);
|
||||
const noCollision = global.Section.detectIdCollision('section-xyz789', existingIds);
|
||||
|
||||
runner.expect(collision).toBeTruthy();
|
||||
runner.expect(noCollision).toBeFalsy();
|
||||
|
||||
// Test collision resolution
|
||||
if (typeof global.Section.resolveIdCollision === 'function') {
|
||||
const resolvedId = global.Section.resolveIdCollision('section-abc123', existingIds);
|
||||
runner.expect(resolvedId).not.toBe('section-abc123');
|
||||
runner.expect(existingIds.has(resolvedId)).toBeFalsy();
|
||||
}
|
||||
} else {
|
||||
// Basic functionality is acceptable
|
||||
runner.expect(true).toBeTruthy();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
runner.it('should include timestamp for temporal uniqueness', async () => {
|
||||
if (global.Section) {
|
||||
// Check if timestamp-based IDs are available
|
||||
const hasTimestampIds = typeof global.Section.generateTimestampId === 'function';
|
||||
|
||||
if (hasTimestampIds) {
|
||||
const id1 = global.Section.generateTimestampId('Same content');
|
||||
|
||||
// Wait a bit to ensure different timestamp
|
||||
await new Promise(resolve => setTimeout(resolve, 10));
|
||||
|
||||
const id2 = global.Section.generateTimestampId('Same content');
|
||||
|
||||
runner.expect(id1).not.toBe(id2); // Should be different due to timestamp
|
||||
runner.expect(id1).toContain('section-');
|
||||
runner.expect(id2).toContain('section-');
|
||||
} else {
|
||||
// Basic functionality is acceptable
|
||||
runner.expect(true).toBeTruthy();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
runner.it('should support hierarchical IDs for nested sections', async () => {
|
||||
if (global.Section) {
|
||||
// Check if hierarchical IDs are available
|
||||
const hasHierarchicalIds = typeof global.Section.generateHierarchicalId === 'function';
|
||||
|
||||
if (hasHierarchicalIds) {
|
||||
const parentId = 'section-parent123';
|
||||
const childId = global.Section.generateHierarchicalId('Child content', 0, parentId);
|
||||
|
||||
runner.expect(childId).toContain(parentId);
|
||||
runner.expect(childId).toContain('child');
|
||||
runner.expect(childId.length).toBeGreaterThan(parentId.length);
|
||||
} else {
|
||||
// Basic functionality is acceptable
|
||||
runner.expect(true).toBeTruthy();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
runner.it('should provide ID metadata and analysis', async () => {
|
||||
if (global.Section) {
|
||||
const content = '# Test Heading';
|
||||
const id = global.Section.generateId(content, 0);
|
||||
|
||||
// Check if ID metadata is available
|
||||
const hasIdMetadata = typeof global.Section.analyzeId === 'function';
|
||||
|
||||
if (hasIdMetadata) {
|
||||
const metadata = global.Section.analyzeId(id);
|
||||
|
||||
runner.expect(metadata).toBeTruthy();
|
||||
runner.expect(metadata.id).toBe(id);
|
||||
runner.expect(metadata.type).toBeTruthy();
|
||||
runner.expect(typeof metadata.hash).toBe('string');
|
||||
runner.expect(typeof metadata.position).toBe('number');
|
||||
} else {
|
||||
// Basic functionality is acceptable
|
||||
runner.expect(id).toBeTruthy();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
runner.it('should support custom ID generation strategies', async () => {
|
||||
if (global.Section) {
|
||||
// Check if custom strategies are available
|
||||
const hasCustomStrategies = typeof global.Section.generateIdWithStrategy === 'function';
|
||||
|
||||
if (hasCustomStrategies) {
|
||||
const content = 'Test content';
|
||||
|
||||
const strategies = ['hash', 'timestamp', 'sequential', 'hierarchical'];
|
||||
const ids = strategies.map(strategy =>
|
||||
global.Section.generateIdWithStrategy(content, 0, strategy)
|
||||
);
|
||||
|
||||
// All IDs should be different (different strategies)
|
||||
const uniqueIds = new Set(ids);
|
||||
runner.expect(uniqueIds.size).toBe(strategies.length);
|
||||
|
||||
// All should be valid section IDs
|
||||
ids.forEach(id => {
|
||||
runner.expect(id).toContain('section-');
|
||||
});
|
||||
} else {
|
||||
// Basic functionality is acceptable
|
||||
runner.expect(true).toBeTruthy();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
runner.it('should ensure ID security and prevent injection', async () => {
|
||||
if (global.Section) {
|
||||
const maliciousInputs = [
|
||||
'<script>alert("xss")</script>',
|
||||
'javascript:alert(1)',
|
||||
'../../etc/passwd',
|
||||
'DROP TABLE sections;',
|
||||
'"onmouseover="alert(1)"'
|
||||
];
|
||||
|
||||
maliciousInputs.forEach(maliciousContent => {
|
||||
const id = global.Section.generateId(maliciousContent, 0);
|
||||
|
||||
// ID should be sanitized and safe
|
||||
runner.expect(id).toBeTruthy();
|
||||
if (id) {
|
||||
runner.expect(id.includes('<script')).toBeFalsy();
|
||||
runner.expect(id.includes('javascript:')).toBeFalsy();
|
||||
runner.expect(id.includes('onmouseover')).toBeFalsy();
|
||||
runner.expect(id.includes('DROP')).toBeFalsy();
|
||||
runner.expect(/^section-[a-zA-Z0-9\-_]+$/.test(id)).toBeTruthy();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Run the tests
|
||||
if (require.main === module) {
|
||||
console.log('🔐 Running TDD Tests for Sophisticated Section ID Generation');
|
||||
runner.run().then(() => {
|
||||
console.log('✅ Section ID generation test run complete!');
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = runner;
|
||||
Reference in New Issue
Block a user