You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

451 lines
14 KiB

'use strict';
const fs = require('fs');
const md5 = require('md5');
const path = require('path');
const request = require('supertest');
const server = require('./server');
const fileDir = server.fileDir;
const tempDir = server.tempDir;
const uploadDir = server.uploadDir;
const clearTempDir = server.clearTempDir;
const clearUploadsDir = server.clearUploadsDir;
const mockFiles = ['car.png', 'tree.png', 'basketball.png', 'emptyfile.txt'];
const mockUser = {
firstName: 'Joe',
lastName: 'Schmo',
email: 'joe@mailinator.com'
};
// Reset response body.uploadDir/uploadPath for testing.
const resetBodyUploadData = (res) => {
res.body.uploadDir = '';
res.body.uploadPath = '';
};
const genUploadResult = (fileName, filePath) => {
const fileStat = fs.statSync(filePath);
const fileBuffer = fs.readFileSync(filePath);
return {
name: fileName,
md5: md5(fileBuffer),
size: fileStat.size,
uploadDir: '',
uploadPath: ''
};
};
describe('Test Directory Cleaning Method', function() {
it('emptied "uploads" directory', function(done) {
clearUploadsDir();
const filesFound = fs.readdirSync(uploadDir).length;
done(filesFound ? `Directory not empty. Found ${filesFound} files.` : null);
});
});
describe('Test Single File Upload', function() {
const app = server.setup();
mockFiles.forEach((fileName) => {
const filePath = path.join(fileDir, fileName);
const uploadedFilePath = path.join(uploadDir, fileName);
const result = genUploadResult(fileName, filePath);
it(`upload ${fileName} with POST`, function(done) {
clearUploadsDir();
request(app)
.post('/upload/single')
.attach('testFile', filePath)
.expect(resetBodyUploadData)
.expect(200, result, err => (err ? done(err) : fs.stat(uploadedFilePath, done)));
});
it(`upload ${fileName} with PUT`, function(done) {
clearUploadsDir();
request(app)
.post('/upload/single')
.attach('testFile', filePath)
.expect(resetBodyUploadData)
.expect(200, result, err => (err ? done(err) : fs.stat(uploadedFilePath, done)));
});
});
it('fail when no files were attached', function(done) {
request(app)
.post('/upload/single')
.expect(400)
.end(done);
});
it('fail when using GET', function(done) {
request(app)
.get('/upload/single')
.attach('testFile', path.join(fileDir, mockFiles[0]))
.expect(400)
.end(done);
});
it('fail when using HEAD', function(done) {
request(app)
.head('/upload/single')
.attach('testFile', path.join(fileDir, mockFiles[0]))
.expect(400)
.end(done);
});
});
describe('Test Single File Upload w/ .mv()', function() {
const app = server.setup();
mockFiles.forEach((fileName) => {
const filePath = path.join(fileDir, fileName);
const uploadedFilePath = path.join(uploadDir, fileName);
const result = genUploadResult(fileName, filePath);
it(`upload ${fileName} with POST w/ .mv()`, function(done) {
clearUploadsDir();
request(app)
.post('/upload/single')
.attach('testFile', filePath)
.expect(resetBodyUploadData)
.expect(200, result, err => (err ? done(err) : fs.stat(uploadedFilePath, done)));
});
it(`upload ${fileName} with PUT w/ .mv()`, function(done) {
clearUploadsDir();
request(app)
.post('/upload/single')
.attach('testFile', filePath)
.expect(resetBodyUploadData)
.expect(200, result, err => (err ? done(err) : fs.stat(uploadedFilePath, done)));
});
});
});
describe('Test Single File Upload with useTempFiles option.', function() {
const app = server.setup({ useTempFiles: true, tempFileDir: tempDir });
mockFiles.forEach((fileName) => {
const filePath = path.join(fileDir, fileName);
const uploadedFilePath = path.join(uploadDir, fileName);
const result = genUploadResult(fileName, filePath);
it(`upload ${fileName} with POST`, function(done) {
clearUploadsDir();
request(app)
.post('/upload/single')
.attach('testFile', filePath)
.expect(resetBodyUploadData)
.expect(200, result, err => (err ? done(err) : fs.stat(uploadedFilePath, done)));
});
it(`upload ${fileName} with PUT`, function(done) {
clearUploadsDir();
request(app)
.post('/upload/single')
.attach('testFile', filePath)
.expect(resetBodyUploadData)
.expect(200, result, err => (err ? done(err) : fs.stat(uploadedFilePath, done)));
});
});
it('fail when no files were attached', function(done) {
request(app)
.post('/upload/single')
.expect(400)
.end(done);
});
it('fail when using GET', function(done) {
request(app)
.get('/upload/single')
.attach('testFile', path.join(fileDir, mockFiles[0]))
.expect(400)
.end(done);
});
it('fail when using HEAD', function(done) {
request(app)
.head('/upload/single')
.attach('testFile', path.join(fileDir, mockFiles[0]))
.expect(400)
.end(done);
});
});
describe('Test Single File Upload with useTempFiles option and empty tempFileDir.', function() {
const app = server.setup({ useTempFiles: true, tempFileDir: '' });
mockFiles.forEach((fileName) => {
const filePath = path.join(fileDir, fileName);
const uploadedFilePath = path.join(uploadDir, fileName);
const result = genUploadResult(fileName, filePath);
it(`upload ${fileName} with POST`, function(done) {
clearUploadsDir();
request(app)
.post('/upload/single')
.attach('testFile', filePath)
.expect(resetBodyUploadData)
.expect(200, result, err => (err ? done(err) : fs.stat(uploadedFilePath, done)));
});
});
});
describe('Test Single File Upload w/ .mv() Promise', function() {
const app = server.setup();
mockFiles.forEach((fileName) => {
const filePath = path.join(fileDir, fileName);
const uploadedFilePath = path.join(uploadDir, fileName);
const result = genUploadResult(fileName, filePath);
it(`upload ${fileName} with POST w/ .mv() Promise`, function(done) {
clearUploadsDir();
request(app)
.post('/upload/single/promise')
.attach('testFile', filePath)
.expect(resetBodyUploadData)
.expect(200, result, err => (err ? done(err) : fs.stat(uploadedFilePath, done)));
});
it(`upload ${fileName} with PUT w/ .mv() Promise`, function(done) {
clearUploadsDir();
request(app)
.post('/upload/single/promise')
.attach('testFile', filePath)
.expect(resetBodyUploadData)
.expect(200, result, err => (err ? done(err) : fs.stat(uploadedFilePath, done)));
});
});
it('fail when no files were attached', function(done) {
request(app)
.post('/upload/single')
.expect(400)
.end(done);
});
it('fail when using GET', function(done) {
request(app)
.get('/upload/single')
.attach('testFile', path.join(fileDir, mockFiles[0]))
.expect(400)
.end(done);
});
it('fail when using HEAD', function(done) {
request(app)
.head('/upload/single')
.attach('testFile', path.join(fileDir, mockFiles[0]))
.expect(400)
.end(done);
});
});
describe('Test Single File Upload w/ .mv() Promise and useTempFiles set to true', function() {
const app = server.setup({ useTempFiles: true, tempFileDir: tempDir });
mockFiles.forEach((fileName) => {
const filePath = path.join(fileDir, fileName);
const uploadedFilePath = path.join(uploadDir, fileName);
const result = genUploadResult(fileName, filePath);
it(`upload ${fileName} with POST w/ .mv() Promise`, function(done) {
clearUploadsDir();
request(app)
.post('/upload/single/promise')
.attach('testFile', filePath)
.expect(resetBodyUploadData)
.expect(200, result, err => (err ? done(err) : fs.stat(uploadedFilePath, done)));
});
it(`upload ${fileName} with PUT w/ .mv() Promise`, function(done) {
clearUploadsDir();
request(app)
.post('/upload/single/promise')
.attach('testFile', filePath)
.expect(resetBodyUploadData)
.expect(200, result, err => (err ? done(err) : fs.stat(uploadedFilePath, done)));
});
});
it('fail when no files were attached', (done) => {
request(app)
.post('/upload/single')
.expect(400)
.end(done);
});
it('fail when using GET', (done) => {
request(app)
.get('/upload/single')
.attach('testFile', path.join(fileDir, mockFiles[0]))
.expect(400)
.end(done);
});
it('fail when using HEAD', (done) => {
request(app)
.head('/upload/single')
.attach('testFile', path.join(fileDir, mockFiles[0]))
.expect(400)
.end(done);
});
});
describe('Test Multi-File Upload', function() {
const app = server.setup();
it('upload multiple files with POST', (done) => {
clearUploadsDir();
const req = request(app).post('/upload/multiple');
const expectedResult = [];
const expectedResultSorted = [];
const uploadedFilesPath = [];
mockFiles.forEach((fileName, index) => {
const filePath = path.join(fileDir, fileName);
req.attach(`testFile${index + 1}`, filePath);
uploadedFilesPath.push(path.join(uploadDir, fileName));
expectedResult.push(genUploadResult(fileName, filePath));
});
req
.expect((res) => {
res.body.forEach((fileInfo) => {
fileInfo.uploadDir = '';
fileInfo.uploadPath = '';
const index = mockFiles.indexOf(fileInfo.name);
expectedResultSorted.push(expectedResult[index]);
});
})
.expect(200, expectedResultSorted)
.end((err) => {
if (err) return done(err);
fs.stat(uploadedFilesPath[0], (err) => {
if (err) return done(err);
fs.stat(uploadedFilesPath[1], (err) => {
if (err) return done(err);
fs.stat(uploadedFilesPath[2], done);
});
});
});
});
});
describe('Test File Array Upload', function() {
const app = server.setup();
it('upload array of files with POST', (done) => {
clearUploadsDir();
const req = request(app).post('/upload/array');
const expectedResult = [];
const expectedResultSorted = [];
const uploadedFilesPath = [];
mockFiles.forEach((fileName) => {
const filePath = path.join(fileDir, fileName);
uploadedFilesPath.push(path.join(uploadDir, fileName));
expectedResult.push(genUploadResult(fileName, filePath));
req.attach('testFiles', filePath);
});
req
.expect((res)=>{
res.body.forEach((fileInfo) => {
fileInfo.uploadDir = '';
fileInfo.uploadPath = '';
const index = mockFiles.indexOf(fileInfo.name);
expectedResultSorted.push(expectedResult[index]);
});
})
.expect(200, expectedResultSorted)
.end((err) => {
if (err) return done(err);
uploadedFilesPath.forEach((uploadedFilePath) => {
fs.statSync(uploadedFilePath);
});
done();
});
});
});
describe('Test Upload With Fields', function() {
const app = server.setup();
mockFiles.forEach((fileName) => {
const filePath = path.join(fileDir, fileName);
const uploadedFilePath = path.join(uploadDir, fileName);
// Expected results
const result = genUploadResult(fileName, filePath);
result.firstName = mockUser.firstName;
result.lastName = mockUser.lastName;
result.email = mockUser.email;
it(`upload ${fileName} and submit fields at the same time with POST`, function(done) {
clearUploadsDir();
request(app)
.post('/upload/single/withfields')
.attach('testFile', filePath)
.field('firstName', mockUser.firstName)
.field('lastName', mockUser.lastName)
.field('email', mockUser.email)
.expect(resetBodyUploadData)
.expect(200, result, err => (err ? done(err) : fs.stat(uploadedFilePath, done)));
});
it(`upload ${fileName} and submit fields at the same time with PUT`, function(done) {
clearUploadsDir();
request(app)
.put('/upload/single/withfields')
.attach('testFile', filePath)
.field('firstName', mockUser.firstName)
.field('lastName', mockUser.lastName)
.field('email', mockUser.email)
.expect(resetBodyUploadData)
.expect(200, result, err => (err ? done(err) : fs.stat(uploadedFilePath, done)));
});
});
});
describe('Test Aborting/Canceling during upload', function() {
this.timeout(4000); // Set timeout for async tests.
const uploadTimeout = 1000;
const app = server.setup({
useTempFiles: true,
tempFileDir: tempDir,
debug: true,
uploadTimeout
});
clearTempDir();
clearUploadsDir();
mockFiles.forEach((fileName) => {
const filePath = path.join(fileDir, fileName);
it(`Delete temp file if ${fileName} upload was aborted`, (done) => {
const req = request(app)
.post('/upload/single')
.attach('testFile', filePath)
.on('progress', (e) => {
const progress = (e.loaded * 100) / e.total;
// Aborting request, use req.req since it is original superagent request.
if (progress > 50) req.req.abort();
})
.end((err) => {
if (!err) return done(`Connection hasn't been aborted!`);
if (err.code !== 'ECONNRESET') return done(err);
// err.code === 'ECONNRESET' that means upload has been aborted.
// Checking temp directory after upload timeout.
setTimeout(() => {
fs.readdir(tempDir, (err, files) => {
if (err) return done(err);
return files.length ? done(`Temporary directory contains files!`) : done();
});
}, uploadTimeout * 2);
});
});
});
});