MovieMapper/tests/legacy/test-folder-navigation-edge-cases.js
Jarian Cottingham 2ce7ab14c9 chore: reorganize repo layout, remove dead files
- Move phase/plan docs into docs/
- Move legacy node:test files into tests/legacy/ with README
- Remove .backup file, test audit artifacts, and unused AI prompt/skill files
- Remove broken iOS GitHub workflows (reference missing MovieMapper-iOS/)
2026-08-20 20:11:57 +00:00

456 lines
13 KiB
JavaScript

// Test edge cases and error handling for folder navigation
const { test } = require('node:test');
const assert = require('assert');
const fs = require('fs');
const path = require('path');
const UIManager = require('./utils/renderer/UIManager');
test('Navigation handles non-existent folder gracefully', async () => {
const mockUIManager = {
currentDirectory: '/test/source',
selectedDirEl: { textContent: '' },
appState: {
navigationStack: ['/test/source'],
currentDepth: 0,
addToNavigationStack: function(dir) {
this.navigationStack.push(dir);
this.currentDepth = this.navigationStack.length - 1;
},
getNavigationStack: function() {
return this.navigationStack;
}
},
scanDirectory: async (dir) => {
return { success: true, files: [] };
},
_logAuditEvent: async () => {},
openDirectory: async (directory) => {
this.appState.addToNavigationStack(directory);
this.currentDirectory = directory;
},
handleFolderClick: async (folderPath, folderName) => {
console.log('Folder clicked:', folderName, 'at path:', folderPath);
// Validate folder path exists
if (!fs.existsSync(folderPath) || !fs.statSync(folderPath).isDirectory()) {
console.error('Invalid folder path:', folderPath);
return; // Don't navigate
}
// Open the folder
await this.openDirectory(folderPath);
}
};
// Mock fs.existsSync and fs.statSync
const originalExistsSync = fs.existsSync;
const originalStatSync = fs.statSync;
fs.existsSync = (path) => {
if (path === '/non/existent/path') return false;
return originalExistsSync(path);
};
fs.statSync = () => {
throw new Error('ENOENT: no such file or directory');
};
const consoleError = console.error;
console.error = () => {};
try {
mockUIManager.handleFolderClick('/non/existent/path', 'nonexistent');
// Verify navigation stack wasn't modified
assert.strictEqual(mockUIManager.appState.getNavigationStack().length, 1);
assert.strictEqual(mockUIManager.currentDirectory, '/test/source');
console.log('Non-existent folder test passed');
} finally {
fs.existsSync = originalExistsSync;
fs.statSync = originalStatSync;
console.error = consoleError;
}
});
test('Navigation handles permission errors gracefully', async () => {
const mockUIManager = {
currentDirectory: '/test/source',
selectedDirEl: { textContent: '' },
appState: {
navigationStack: ['/test/source'],
currentDepth: 0,
addToNavigationStack: function(dir) {
this.navigationStack.push(dir);
this.currentDepth = this.navigationStack.length - 1;
},
getNavigationStack: function() {
return this.navigationStack;
}
},
scanDirectory: async (dir) => {
return { success: true, files: [] };
},
_logAuditEvent: async () => {},
openDirectory: async (directory) => {
this.appState.addToNavigationStack(directory);
this.currentDirectory = directory;
},
handleFolderClick: async (folderPath, folderName) => {
console.log('Folder clicked:', folderName, 'at path:', folderPath);
// Validate folder path exists
if (!fs.existsSync(folderPath) || !fs.statSync(folderPath).isDirectory()) {
console.error('Invalid folder path:', folderPath);
return; // Don't navigate
}
// Open the folder
await this.openDirectory(folderPath);
}
};
// Mock fs.statSync to throw permission error
const originalStatSync = fs.statSync;
fs.statSync = (path) => {
if (path === '/permission/denied') {
const error = new Error('EACCES: permission denied');
error.code = 'EACCES';
throw error;
}
return originalStatSync(path);
};
const consoleError = console.error;
console.error = () => {};
try {
mockUIManager.handleFolderClick('/permission/denied', 'denied');
// Verify navigation stack wasn't modified
assert.strictEqual(mockUIManager.appState.getNavigationStack().length, 1);
console.log('Permission error handling test passed');
} finally {
fs.statSync = originalStatSync;
console.error = consoleError;
}
});
test('Breadcrumb navigation handles empty stack', () => {
const mockUIManager = {
selectedDirEl: { textContent: '' },
appState: {
getNavigationStack: () => [],
canGoBack: () => false
}
};
mockUIManager.updateBreadcrumbNavigation = function() {
const breadcrumbs = this.appState.getNavigationStack();
// Should not throw for empty stack
breadcrumbs.forEach(() => {
assert.ok(false, 'Should not iterate over empty stack');
});
return document.createElement('div');
};
try {
const container = mockUIManager.updateBreadcrumbNavigation();
assert.ok(true, 'Should handle empty stack');
} catch (error) {
assert.ok(false, 'Should not throw for empty stack');
}
});
test('Breadcrumb navigation handles null stack', () => {
const mockUIManager = {
selectedDirEl: { textContent: '' },
appState: {
getNavigationStack: () => null,
canGoBack: () => false
}
};
mockUIManager.updateBreadcrumbNavigation = function() {
// Should handle null stack gracefully
return document.createElement('div');
};
try {
const container = mockUIManager.updateBreadcrumbNavigation();
assert.ok(true, 'Should handle null stack');
} catch (error) {
assert.ok(false, 'Should not throw for null stack');
}
});
test('Go back from root does not cause errors', () => {
const mockUIManager = {
currentDirectory: '/test/source',
selectedDirEl: { textContent: '' },
appState: {
navigationStack: ['/test/source'],
currentDepth: 0,
goBack: function() {
if (this.currentDepth > 0) {
this.navigationStack.pop();
this.currentDepth--;
return this.navigationStack[this.currentDepth];
}
return null;
},
canGoBack: function() {
return this.currentDepth > 0;
}
},
scanDirectory: async (dir) => {
return { success: true, files: [] };
},
_logAuditEvent: async () => {},
goBack: async () => {
const parentDirectory = this.appState.goBack();
if (parentDirectory) {
this.currentDirectory = parentDirectory;
}
return parentDirectory;
},
updateBreadcrumbNavigation: function() {
// Mock breadcrumb update
}
};
// Try to go back when already at root
const result = mockUIManager.goBack();
assert.strictEqual(result, null, 'Should return null when at root');
assert.strictEqual(mockUIManager.currentDirectory, '/test/source', 'Should not change directory');
});
test('Special folder names are valid', () => {
const specialNames = ['extras', 'behind the scenes', 'delete', 'trailers', 'featurettes'];
specialNames.forEach(name => {
// Verify name doesn't contain invalid characters
assert.ok(!name.includes(path.sep), `Folder name "${name}" contains path separator`);
// Verify name is not too long
assert.ok(name.length <= 255, `Folder name "${name}" exceeds 255 characters`);
// Verify name is not empty
assert.ok(name.length > 0, `Folder name "${name}" should not be empty`);
});
console.log('Special folder names validation passed');
});
test('Navigation preserves file list state', async () => {
const testDir = path.join(__dirname, 'test_state_preservation');
if (!fs.existsSync(testDir)) {
fs.mkdirSync(testDir);
}
try {
const mockUIManager = {
currentDirectory: null,
selectedDirEl: { textContent: '' },
fileListEl: { querySelectorAll: () => [] },
appState: {
navigationStack: [],
currentDepth: 0,
addToNavigationStack: function(dir) {
this.navigationStack.push(dir);
this.currentDepth = this.navigationStack.length - 1;
}
},
scanDirectory: async (dir) => {
// Mock different file lists for different directories
if (dir === path.join(testDir, 'folder1')) {
return { success: true, files: [{ name: 'file1.mp4' }] };
} else if (dir === path.join(testDir, 'folder2')) {
return { success: true, files: [{ name: 'file2.mkv' }] };
}
return { success: true, files: [] };
},
_logAuditEvent: async () => {},
openDirectory: async (directory) => {
this.appState.addToNavigationStack(directory);
this.currentDirectory = directory;
const result = await this.scanDirectory(directory);
return result;
}
};
// Navigate to folder1
const result1 = await mockUIManager.openDirectory(path.join(testDir, 'folder1'));
assert.strictEqual(result1.files.length, 1);
assert.strictEqual(result1.files[0].name, 'file1.mp4');
// Navigate to folder2
const result2 = await mockUIManager.openDirectory(path.join(testDir, 'folder2'));
assert.strictEqual(result2.files.length, 1);
assert.strictEqual(result2.files[0].name, 'file2.mkv');
// Go back to folder1
mockUIManager.appState.goBack();
assert.strictEqual(mockUIManager.currentDirectory, path.join(testDir, 'folder1'));
console.log('File list state preservation test passed');
} finally {
if (fs.existsSync(testDir)) {
fs.rmSync(testDir, { recursive: true });
}
}
});
test('Multiple rapid navigations', async () => {
const testDir = path.join(__dirname, 'test_rapid_nav');
if (!fs.existsSync(testDir)) {
fs.mkdirSync(testDir);
}
try {
const mockUIManager = {
currentDirectory: null,
selectedDirEl: { textContent: '' },
appState: {
navigationStack: [],
currentDepth: 0,
addToNavigationStack: function(dir) {
this.navigationStack.push(dir);
this.currentDepth = this.navigationStack.length - 1;
},
goBack: function() {
if (this.currentDepth > 0) {
this.navigationStack.pop();
this.currentDepth--;
return this.navigationStack[this.currentDepth];
}
return null;
}
},
scanDirectory: async (dir) => {
return { success: true, files: [] };
},
_logAuditEvent: async () => {},
openDirectory: async (directory) => {
this.appState.addToNavigationStack(directory);
this.currentDirectory = directory;
}
};
// Rapidly navigate between directories
for (let i = 0; i < 10; i++) {
await mockUIManager.openDirectory(path.join(testDir, `folder${i}`));
}
// Verify navigation stack
assert.strictEqual(mockUIManager.appState.getNavigationStack().length, 11); // testDir + 10 folders
assert.strictEqual(mockUIManager.currentDirectory, path.join(testDir, 'folder9'));
console.log('Multiple rapid navigations test passed');
} finally {
if (fs.existsSync(testDir)) {
fs.rmSync(testDir, { recursive: true });
}
}
});
test('Navigation with special characters in folder names', async () => {
const testDir = path.join(__dirname, 'test_special_chars');
if (!fs.existsSync(testDir)) {
fs.mkdirSync(testDir);
}
try {
// Create folders with special characters
const specialNames = ['folder with spaces', 'folder-dashes', 'folder_underscores'];
for (const name of specialNames) {
const folderPath = path.join(testDir, name);
if (!fs.existsSync(folderPath)) {
fs.mkdirSync(folderPath);
}
}
const mockUIManager = {
currentDirectory: null,
selectedDirEl: { textContent: '' },
appState: {
navigationStack: [],
currentDepth: 0,
addToNavigationStack: function(dir) {
this.navigationStack.push(dir);
this.currentDepth = this.navigationStack.length - 1;
}
},
scanDirectory: async (dir) => {
return { success: true, files: [] };
},
_logAuditEvent: async () => {},
openDirectory: async (directory) => {
this.appState.addToNavigationStack(directory);
this.currentDirectory = directory;
}
};
// Navigate to folders with special characters
for (const name of specialNames) {
const folderPath = path.join(testDir, name);
await mockUIManager.openDirectory(folderPath);
assert.strictEqual(mockUIManager.currentDirectory, folderPath);
}
console.log('Special characters in folder names test passed');
} finally {
if (fs.existsSync(testDir)) {
fs.rmSync(testDir, { recursive: true });
}
}
});
console.log('All edge case tests passed!');