@julesl23/s5js
Version:
Enhanced TypeScript SDK for S5 decentralized storage with path-based API, media processing, and directory utilities
132 lines • 5.56 kB
JavaScript
// test/fs/utils/utils-integration.test.ts
import { describe, it, expect, beforeEach } from 'vitest';
import { DirectoryWalker } from '../../../src/fs/utils/walker.js';
import { BatchOperations } from '../../../src/fs/utils/batch.js';
import { FS5 } from '../../../src/fs/fs5.js';
import { setupMockS5 } from '../../test-utils.js';
describe('Utility Functions Integration', () => {
let fs;
beforeEach(async () => {
const { s5, identity } = await setupMockS5();
fs = new FS5(s5, identity);
});
it('should combine walker and batch operations for selective copy', async () => {
// Create source structure
await fs.put('project/src/index.ts', 'export default {}');
await fs.put('project/src/utils.ts', 'export function util() {}');
await fs.put('project/test/index.test.ts', 'test()');
await fs.put('project/node_modules/package/index.js', 'module');
await fs.put('project/README.md', '# Project');
await fs.put('project/.gitignore', 'node_modules');
// Walk and filter to find only source files
const walker = new DirectoryWalker(fs, 'project');
const sourceFiles = [];
for await (const item of walker.walk({
filter: (name, type) => {
if (type === 'directory')
return !name.includes('node_modules');
return name.endsWith('.ts') || name.endsWith('.md');
}
})) {
if (item.type === 'file') {
sourceFiles.push(item.path);
}
}
// Copy only source files
const batch = new BatchOperations(fs);
for (const sourcePath of sourceFiles) {
const relativePath = sourcePath.substring('project'.length);
const destPath = `backup${relativePath}`;
const content = await fs.get(sourcePath);
const metadata = await fs.getMetadata(sourcePath);
await fs.put(destPath, content, {
mediaType: metadata?.mediaType
});
}
// Verify selective copy
expect(await fs.get('backup/src/index.ts')).toBe('export default {}');
expect(await fs.get('backup/README.md')).toBe('# Project');
expect(await fs.get('backup/node_modules/package/index.js')).toBeUndefined();
});
it('should use walker to verify batch copy completeness', async () => {
// Create complex source
for (let i = 0; i < 20; i++) {
await fs.put(`data/batch${i}/file${i}.dat`, `data${i}`);
}
// Copy with batch operations
const batch = new BatchOperations(fs);
const copyResult = await batch.copyDirectory('data', 'backup');
// Walk both directories to compare
const sourceWalker = new DirectoryWalker(fs, 'data');
const sourceStats = await sourceWalker.count();
const destWalker = new DirectoryWalker(fs, 'backup');
const destStats = await destWalker.count();
// Verify complete copy
expect(destStats.files).toBe(sourceStats.files);
expect(destStats.directories).toBe(sourceStats.directories);
expect(copyResult.errors).toBe(0);
});
it('should handle large directory operations with cursors', async () => {
// Create large directory
const files = [];
for (let i = 0; i < 100; i++) {
const path = `large/file${i.toString().padStart(3, '0')}.txt`;
await fs.put(path, `content ${i}`);
files.push(path);
}
// Walk with batches using cursor
const walker = new DirectoryWalker(fs, 'large');
const batches = [];
let cursor;
while (true) {
const batch = [];
let count = 0;
for await (const item of walker.walk({ cursor })) {
batch.push(item.name);
cursor = item.cursor;
count++;
if (count >= 10)
break; // 10 items per batch
}
if (batch.length === 0)
break;
batches.push(batch);
}
// Verify we got all files in order
expect(batches.length).toBe(10); // 100 files / 10 per batch
const allFiles = batches.flat();
expect(allFiles.length).toBe(100);
expect(allFiles[0]).toBe('file000.txt');
expect(allFiles[99]).toBe('file099.txt');
});
it('should clean up failed operations', async () => {
// Create source
await fs.put('source/important.txt', 'important data');
await fs.put('source/temp/cache.tmp', 'cache');
// Partial copy that "fails"
const batch = new BatchOperations(fs);
try {
await batch.copyDirectory('source', 'dest', {
onProgress: (progress) => {
// Simulate failure on temp files during copy
if (progress.processed > 1) {
throw new Error('Simulated failure');
}
},
onError: "stop"
});
}
catch (error) {
// Expected error
}
// Clean up partial destination
const deleteResult = await batch.deleteDirectory('dest', {
recursive: true
});
// Verify cleanup
expect(deleteResult.errors).toBe(0);
const destMeta = await fs.getMetadata('dest');
expect(destMeta).toBeUndefined();
});
});
//# sourceMappingURL=utils-integration.test.js.map