UNPKG

als-send-file

Version:

file serving with advanced options for caching, headers, and error handling, compatible with Express middleware.

153 lines (132 loc) 6.3 kB
const { describe, it, beforeEach, afterEach, after } = require('node:test'); const assert = require('node:assert'); const http = require('http'); const sendFile = require('../lib/send-file.js'); const { writeFileSync, unlinkSync, promises } = require('fs'); const path = require('path'); const { checkPrimeSync } = require('node:crypto'); // Создание временного файла для тестирования const testFilePath = path.join(__dirname, 'temp-test-file.txt'); const fileContent = 'Hello, this is a test file for testing sendFile functionality.'; writeFileSync(testFilePath, fileContent); describe('sendFile Module Tests', () => { let request, response; beforeEach(() => { request = new http.IncomingMessage(); response = new http.ServerResponse(request); response.setHeader = function (key, value) { this.headers = this.headers || {}; this.headers[key] = value; }; response.writeHead = function (statusCode, headers) { this.statusCode = statusCode; this.headers = { ...this.headers, ...headers }; }; response.end = function () { this.ended = true; }; }); afterEach(() => { response.end(); }); // Cleanup after tests after(() => { unlinkSync(testFilePath); }); //#region req.headers.range it('should handle range requests correctly', async () => { request.headers['range'] = 'bytes=0-5'; await sendFile(request, response, testFilePath, { size: fileContent.length }); const { statusCode, headers } = response; // console.log({statusCode,headers}) assert.strictEqual(response.statusCode, 206); assert.strictEqual(response.headers['Content-Range'], `bytes 0-5/${fileContent.length}`); assert.strictEqual(response.headers['Content-Length'], '6'); }); it('should reject invalid range requests', async () => { request.headers['range'] = 'bytes=-'; let error = null; await sendFile(request, response, testFilePath, { size: fileContent.length }, (res, code, msg) => { error = { res, code, msg }; }); assert(error); assert.strictEqual(error.code, 416); }); it('should handle range requests starting from a specific byte', async () => { request.headers['range'] = 'bytes=7-'; await sendFile(request, response, testFilePath, { size: fileContent.length }); const { statusCode, headers } = response; assert.strictEqual(response.statusCode, 206); assert.strictEqual(headers['Content-Range'], `bytes 7-${fileContent.length - 1}/${fileContent.length}`); assert.strictEqual(headers['Content-Length'], (fileContent.length - 7).toString()); }); it('should handle range requests ending at a specific byte', async () => { request.headers['range'] = 'bytes=-6'; await sendFile(request, response, testFilePath, { size: fileContent.length }); const { statusCode, headers } = response; assert.strictEqual(response.statusCode, 206); assert.strictEqual(headers['Content-Range'], `bytes ${fileContent.length - 6}-${fileContent.length - 1}/${fileContent.length}`); assert.strictEqual(headers['Content-Length'], '6'); }); it('should handle invalid range that is out of bounds', async () => { request.headers['range'] = `bytes=${fileContent.length}-1000`; let error = null; await sendFile(request, response, testFilePath, { size: fileContent.length }, (res, code, msg) => { error = { res, code, msg }; }); assert(error); assert.strictEqual(error.code, 416); }); it('should handle valid range that exceeds file length', async () => { request.headers['range'] = `bytes=0-${fileContent.length + 100}`; await sendFile(request, response, testFilePath, { size: fileContent.length }); const { statusCode, headers } = response; assert.strictEqual(response.statusCode, 206); assert.strictEqual(headers['Content-Range'], `bytes 0-${fileContent.length - 1}/${fileContent.length}`); assert.strictEqual(headers['Content-Length'], fileContent.length.toString()); }); //#endregion it('should send the entire file if no range is specified', async () => { request.headers['range'] = undefined; await sendFile(request, response, testFilePath, { size: fileContent.length }); assert.strictEqual(response.statusCode, 200); // assert.strictEqual(response.headers['Content-Length'], fileContent.length.toString()); assert.strictEqual(response.headers['Content-Length'], undefined); }); it('should handle errors from the file stream', async () => { const brokenFilePath = path.join(__dirname, 'nonexistent.txt'); let errorCaught = null; await sendFile(request, response, brokenFilePath, { size: 0 }, (res,code,msg) => { errorCaught = {code,msg} }); assert(errorCaught); assert(errorCaught.code === 500) assert(errorCaught.msg.includes('nonexistent.txt')) }); it('should handle interrupted download', async () => { let errorCaught = null; let ended = false const originalEnd = response.end response.end = () => {originalEnd(),ended = true} const promise = sendFile(request, response, testFilePath, { size: fileContent.length }, (res,code,msg) => { errorCaught = {code,msg} }); setTimeout(() => response.emit('close'), 1); // Имитация прерывания загрузки через 1 мс response.on('end',() => ended = true) const result = await promise assert(ended) assert(errorCaught === null) }); it('should handle file deletion error', async () => { const filePath = path.join(__dirname, 'temp-delete-file.txt'); const content = 'This file will be deleted during the request.'.repeat(10) writeFileSync(filePath, content); let errorCaught = null const promise = sendFile(request, response, filePath, { size: content.length }, (res, code, msg) => { errorCaught = { code, msg }; }); await promises.unlink(filePath) await promise assert(errorCaught) assert(errorCaught.code === 500) assert(errorCaught.msg.includes('temp-delete-file.txt')) }); });