- Auth service: hashPassword/verifyPassword via bcrypt - Storage service: saveFile, getFilePath, deleteStoredFile with ENOENT handling - Types: JwtPayload interface - Logging middleware: createLogger writing AUTH_FAILURE, AUTH_SUCCESS, FILE_NOT_FOUND - 27 tests passing Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
43 lines
1.5 KiB
TypeScript
43 lines
1.5 KiB
TypeScript
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
import { mkdtempSync, rmSync, existsSync, readFileSync } from 'fs';
|
|
import { tmpdir } from 'os';
|
|
import { join } from 'path';
|
|
import { saveFile, deleteStoredFile, getFilePath } from '../../src/services/storage.ts';
|
|
|
|
describe('services/storage', () => {
|
|
let uploadDir: string;
|
|
|
|
beforeEach(() => {
|
|
uploadDir = mkdtempSync(join(tmpdir(), 'nanodrop-test-'));
|
|
});
|
|
|
|
afterEach(() => {
|
|
rmSync(uploadDir, { recursive: true, force: true });
|
|
});
|
|
|
|
it('saves a file buffer and returns stored name', async () => {
|
|
const content = Buffer.from('hello world');
|
|
const storedName = await saveFile(uploadDir, 'file1.txt', content);
|
|
expect(storedName).toBe('file1.txt');
|
|
expect(existsSync(join(uploadDir, 'file1.txt'))).toBe(true);
|
|
expect(readFileSync(join(uploadDir, 'file1.txt'))).toEqual(content);
|
|
});
|
|
|
|
it('returns full path for a stored file', () => {
|
|
const path = getFilePath(uploadDir, 'file1.txt');
|
|
expect(path).toBe(join(uploadDir, 'file1.txt'));
|
|
});
|
|
|
|
it('deletes a stored file', async () => {
|
|
const content = Buffer.from('to delete');
|
|
await saveFile(uploadDir, 'todelete.txt', content);
|
|
expect(existsSync(join(uploadDir, 'todelete.txt'))).toBe(true);
|
|
await deleteStoredFile(uploadDir, 'todelete.txt');
|
|
expect(existsSync(join(uploadDir, 'todelete.txt'))).toBe(false);
|
|
});
|
|
|
|
it('does not throw when deleting non-existent file', async () => {
|
|
await expect(deleteStoredFile(uploadDir, 'ghost.txt')).resolves.not.toThrow();
|
|
});
|
|
});
|