@ourongxing/downloader
Version:
A file downloader for NodeJs
838 lines (722 loc) • 34.2 kB
JavaScript
const expect = require('expect')
const fs = require('fs');
const Path = require('path');
const rimraf = require('rimraf')
const Downloader = require('./Downloader');
const { Readable } = require('stream');
const nock = require('nock')
describe('Main tests', () => {
before((done) => {
rimraf.sync("./downloads");
done();
})
it('Should download a picture from data URI', async () => {
const downloader = new Downloader({
url: `data:image/jpeg;base64,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`,
directory: "./downloads",
onProgress: (p, chunk) => {
expect(p).toBe('100.00')
},
onResponse: (r) => {
expect(r.constructor.name).toBe('IncomingMessage');
}
})
const { downloadStatus, filePath } = await downloader.download();
expect(downloadStatus).toBe('COMPLETE')
expect(filePath).toBe('./downloads/9k=.jpeg')
await verifyFile(filePath, 2339);
})
it('Should download a picture from data URI, with custom name', async () => {
const downloader = new Downloader({
fileName: "buba.jpeg",
url: `data:image/jpeg;base64,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`,
directory: "./downloads",
onProgress: (p, chunk) => {
expect(p).toBe('100.00')
},
onResponse: (r) => {
expect(r.constructor.name).toBe('IncomingMessage');
},
onBeforeSave: (r) => {
return r.split(".")[0] + "2" + ".jpeg"
}
})
const { downloadStatus, filePath } = await downloader.download();
expect(downloadStatus).toBe('COMPLETE')
expect(filePath).toBe('./downloads/buba2.jpeg')
await verifyFile(filePath, 2339);
})
it('Should download a picture and use content-type', async () => {
const host = randomHost()
nock(`http://www.${host}.com`)
.get('/contentType1')
.reply(200, (uri, requestBody) => {
return fs.createReadStream(Path.join(__dirname, 'fixtures/Desert.jpg'))
}, {
'Content-Type': 'image/jpeg',
'Content-Length': '23642'
})
const downloader = new Downloader({
url: `http://www.${host}.com/contentType1`,
directory: "./downloads",
cloneFiles: false,
onProgress: (p, chunk) => {
expect(!isNaN(parseFloat(p)) && isFinite(p)).toBe(true)
expect(Object.getPrototypeOf(chunk).constructor.name).toBe('Buffer')
},
onResponse: (r) => {
expect(r.constructor.name).toBe('IncomingMessage');
}
})
const { downloadStatus, filePath } = await downloader.download();
expect(downloadStatus).toBe('COMPLETE')
expect(filePath).toBe('./downloads/contentType1.jpeg')
await verifyFile('./downloads/contentType1.jpeg', 23642);
})
it('Should get the deduced name', async () => {
let deducedName;
const host = randomHost()
nock(`http://www.${host}.com`)
.get('/contentType')
.reply(200, (uri, requestBody) => {
return fs.createReadStream(Path.join(__dirname, 'fixtures/Desert.jpg'))
}, {
'Content-Type': 'image/jpeg',
'Content-Length': '23642'
})
const downloader = new Downloader({
url: `http://www.${host}.com/contentType`,
directory: "./downloads",
cloneFiles: false,
onBeforeSave: (name) => {
deducedName = name;
}
})
const { downloadStatus, filePath } = await downloader.download();
expect(deducedName).toBe('contentType.jpeg')
expect(downloadStatus).toBe('COMPLETE')
expect(filePath).toBe('./downloads/contentType.jpeg')
await verifyFile('./downloads/contentType.jpeg', 23642);
})
it('Should override the deduced name', async () => {
let deducedName;
const host = randomHost()
nock(`http://www.${host}.com`)
.get('/contentType')
.reply(200, (uri, requestBody) => {
return fs.createReadStream(Path.join(__dirname, 'fixtures/Desert.jpg'))
}, {
'Content-Type': 'image/jpeg',
'Content-Length': '23642'
})
const downloader = new Downloader({
url: `http://www.${host}.com/contentType`,
directory: "./downloads",
cloneFiles: false,
onBeforeSave: (name) => {
deducedName = name;
return 'override.jpg'
}
})
await downloader.download();
expect(deducedName).toBe('contentType.jpeg')
await verifyFile('./downloads/override.jpg', 23642);
})
it('Should skip same name request', async () => {
let deducedName;
const host = randomHost()
let downloadTimes = 0;
nock(`http://www.${host}.com`)
.get('/contentType')
.reply(200, (uri, requestBody) => {
downloadTimes++
return fs.createReadStream(Path.join(__dirname, 'fixtures/Desert.jpg'))
}, {
'Content-Type': 'image/jpeg',
'Content-Length': '23642'
}).persist()
const downloader = new Downloader({
url: `http://www.${host}.com/contentType`,
directory: "./downloads",
fileName: "testfile.jpg",
cloneFiles: true
})
const downloader2 = new Downloader({
url: `http://www.${host}.com/contentType`,
directory: "./downloads",
fileName: "testfile.jpg",
cloneFiles: true,
skipExistingFileName: true
})
var { downloadStatus, filePath } = await downloader.download();
expect(downloadStatus).toBe('COMPLETE')
expect(filePath).toBe('./downloads/testfile.jpg')
var { downloadStatus, filePath } = await downloader2.download();
expect(downloadStatus).toBe('ABORTED')
expect(filePath).toBe(null)
await verifyFile('./downloads/testfile.jpg', 23642);
expect(downloadTimes).toBe(1);
})
it('Should skip same name request, without config.fileName', async () => {
const host = randomHost()
nock(`http://www.${host}.com`)
.get('/contentType')
.reply(200, (uri, requestBody) => {
return fs.createReadStream(Path.join(__dirname, 'fixtures/Desert.jpg'))
}, {
'Content-Type': 'image/jpeg',
'Content-Length': '23642',
'Content-Disposition': 'attachment; filename="testfile2.jpg"'
}).persist()
const downloader = new Downloader({
url: `http://www.${host}.com/contentType`,
directory: "./downloads",
})
const downloader2 = new Downloader({
url: `http://www.${host}.com/contentType`,
directory: "./downloads",
skipExistingFileName: true
})
var { filePath, downloadStatus } = await downloader.download();
expect(filePath).toBe('./downloads/testfile2.jpg')
expect(downloadStatus).toBe('COMPLETE')
var { filePath, downloadStatus } = await downloader2.download();
expect(filePath).toBe(null)
expect(downloadStatus).toBe('ABORTED')
await verifyFile('./downloads/testfile2.jpg', 23642);
let error = false;
try {
//Make sure no clone is present
await verifyFile('./downloads/testfile2_2.jpg', 23642);
} catch (e) {
error = true
}
expect(error).toBe(true);
})
it('Should skip file saving based on skipexisting flag, despite usage of onBeforeSave', async () => {
rimraf.sync("./downloads");
const host = randomHost()
let timesSaved = 0;
nock(`http://www.${host}.com`)
.get('/contentType')
.reply(200, (uri, requestBody) => {
return fs.createReadStream(Path.join(__dirname, 'fixtures/Desert.jpg'))
}, {
'Content-Type': 'image/jpeg',
'Content-Length': '23642'
}).persist()
const downloader = new Downloader({
url: `http://www.${host}.com/contentType`,
directory: "./downloads",
onBeforeSave: (deducedName) => {
timesSaved++
return deducedName;
}
})
const downloader2 = new Downloader({
url: `http://www.${host}.com/contentType`,
directory: "./downloads",
skipExistingFileName: true,
onBeforeSave: (deducedName) => {
timesSaved++//The hook should not be called because skipExistingFileName is true
const fileExt = Path.extname(deducedName);
if (fileExt) return `${"aaa"}-${"bbb"}${fileExt}`;
return deducedName;
}
})
var { downloadStatus, filePath } = await downloader.download();
expect(downloadStatus).toBe('COMPLETE')
expect(filePath).toBe('./downloads/contentType.jpeg')
var { downloadStatus, filePath } = await downloader2.download();
expect(downloadStatus).toBe('ABORTED')
expect(filePath).toBe(null)
await verifyFile('./downloads/contentType.jpeg', 23642);
expect(timesSaved).toBe(1);
});
it('Should download a file, without a known fileName, and skip the second one', async () => {
rimraf.sync('./downloads')
const host = randomHost()
nock(`http://www.${host}.com`)
.get('/contentType')
.reply(200, (uri, requestBody) => {
return fs.createReadStream(Path.join(__dirname, 'fixtures/Desert.jpg'))
}, {
'Content-Type': 'image/jpeg',
'Content-Length': '23642',
}).persist()
const downloader = new Downloader({
url: `http://www.${host}.com/contentType`,
directory: "./downloads",
skipExistingFileName: true
})
const downloader2 = new Downloader({
url: `http://www.${host}.com/contentType`,
directory: "./downloads",
skipExistingFileName: true,
cloneFiles: true
})
var { filePath, downloadStatus } = await downloader.download();
expect(filePath).toBe('./downloads/contentType.jpeg')
expect(downloadStatus).toBe('COMPLETE')
var { filePath, downloadStatus } = await downloader2.download();
expect(filePath).toBe(null)
expect(downloadStatus).toBe('ABORTED')
await verifyFile('./downloads/contentType.jpeg', 23642);
const files = fs.readdirSync('./downloads');
expect(files.length).toBe(1)
})
it('Should get NaN in onProgress', async () => {
const host = randomHost()
nock(`http://www.${host}.com`)
.get('/contentType')
.reply(200, (uri, requestBody) => {
return fs.createReadStream(Path.join(__dirname, 'fixtures/Desert.jpg'))
}, {
'Content-Type': 'image/jpeg',
})
const downloader = new Downloader({
url: `http://www.${host}.com/contentType`,
directory: "./downloads",
cloneFiles: false,
onProgress: (p, chunk, remaining) => {
expect(isNaN(p)).toBe(true)
expect(isNaN(remaining)).toBe(true)
expect(Object.getPrototypeOf(chunk).constructor.name).toBe('Buffer')
}
})
await downloader.download();
await verifyFile('./downloads/contentType.jpeg', 23642);
})
it('Should download a picture and overwrite the name', async () => {
const host = randomHost()
nock(`http://www.${host}.com`)
.get('/Desert.jpg')
.reply(200, (uri, requestBody) => {
return fs.createReadStream(Path.join(__dirname, 'fixtures/Desert.jpg'))
}, {
'Content-Type': 'image/jpeg',
'Content-Length': '23642'
})
const downloader = new Downloader({
url: `http://www.${host}.com/Desert.jpg`,
directory: "./downloads",
cloneFiles: false,
fileName: 'alternativeName.jpg'
})
await downloader.download();
await verifyFile('./downloads/alternativeName.jpg', 23642);
})
it('Should download into a nested non-existing path', async () => {
const host = randomHost()
nock(`http://www.${host}.com`)
.get('/Desert.jpg')
.reply(200, (uri, requestBody) => {
return fs.createReadStream(Path.join(__dirname, 'fixtures/Desert.jpg'))
}, {
'Content-Type': 'image/jpeg',
'Content-Length': '23642'
})
const downloader = new Downloader({
url: `http://www.${host}.com/Desert.jpg`,
directory: "./downloads/May/2020",
cloneFiles: false
})
await downloader.download();
await verifyFile('./downloads/May/2020/Desert.jpg', 23642);
})
// **Assumes an already existing Desert.js file */
it('Should create a number-appended file', async () => {
const host = randomHost()
nock(`http://www.${host}.com`)
.get('/Desert.jpg')
.reply(200, (uri, requestBody) => {
return fs.createReadStream(Path.join(__dirname, 'fixtures/Desert.jpg'))
}, {
'Content-Type': 'image/jpeg',
'Content-Length': '23642'
})
const downloader = new Downloader({
url: `http://www.${host}.com/Desert.jpg`,
directory: "./downloads/May/2020",
})
await downloader.download();
await verifyFile('./downloads/May/2020/Desert_2.jpg', 23642);
})
it('Should handle a file without content-length', async () => {
const host = randomHost()
nock(`http://www.${host}.com`)
.get('/Koala.jpg')
.reply(200, (uri, requestBody) => {
return fs.createReadStream(Path.join(__dirname, 'fixtures/Koala.jpg'))
}, {
'Content-Type': 'image/jpeg',
'Content-Length': '845941'
})
const downloader = new Downloader({
url: `http://www.${host}.com/Koala.jpg`,
directory: "./downloads",
})
await downloader.download();
await verifyFile('./downloads/Koala.jpg');
})
it('Should handle a file without content-type', async () => {
const host = randomHost()
nock(`http://www.${host}.com`)
.get('/Lighthouse.jpg')
.reply(200, (uri, requestBody) => {
return fs.createReadStream(Path.join(__dirname, 'fixtures/Lighthouse.jpg'))
}, {
'Content-Type': 'image/jpeg',
'Content-Length': '845941'
})
const downloader = new Downloader({
url: `http://www.${host}.com/Lighthouse.jpg`,
directory: "./downloads",
})
await downloader.download();
await verifyFile('./downloads/Lighthouse.jpg');
})
it('Should download a picture and get the name from content-disposition ', async () => {
const host = randomHost()
nock(`http://www.${host}.com`)
.get('/contentDisposition')
.reply(200, (uri, requestBody) => {
return fs.createReadStream(Path.join(__dirname, 'fixtures/Hydrangeas.jpg'))
}, {
'Content-Type': 'image/jpeg',
'Content-Disposition': 'Content-Disposition: attachment; filename="contentDispositionFile.jpg"',
'Content-Length': '845941'
})
const downloader = new Downloader({
url: `http://www.${host}.com/contentDisposition`,
directory: "./downloads"
})
await downloader.download();
await verifyFile('./downloads/contentDispositionFile.jpg');
})
it('Should download a picture with a querystring after the extension ', async () => {
const host = randomHost()
nock(`http://www.${host}.com`)
.get('/Hydrangeas.jpg?width=400&height=300')
.reply(200, (uri, requestBody) => {
return fs.createReadStream(Path.join(__dirname, 'fixtures/Hydrangeas.jpg'))
}, {
'Content-Type': 'image/jpeg',
'Content-Length': '845941'
})
const downloader = new Downloader({
url: `http://www.${host}.com/Hydrangeas.jpg?width=400&height=300`,
directory: "./downloads"
})
await downloader.download();
await verifyFile('./downloads/Hydrangeas.jpg');
})
it('Should download two pictures, with name appending', async () => {
try {
const host = randomHost()
nock(`http://www.${host}.com`)
.get('/Koala.jpg')
.reply(200, (uri, requestBody) => {
return fs.createReadStream(Path.join(__dirname, 'fixtures/Koala.jpg'))
}, {
'Content-Type': 'image/jpeg',
'Content-Length': '29051'
}).persist()
const downloader = new Downloader({
url: `http://www.${host}.com/Koala.jpg`,
directory: "./downloads",
cloneFiles: false
})
await downloader.download();
await verifyFile('./downloads/Koala.jpg', 29051);
const downloader2 = new Downloader({
url: `http://www.${host}.com/Koala.jpg`,
directory: "./downloads",
})
await downloader2.download();
} catch (error) {
console.log(error)
throw error
}
})
it('Should download an image, with shouldBufferResponse', async () => {
const stream = fs.createReadStream(Path.join(__dirname, 'fixtures/Koala.jpg'));
const chunks = []
for await (let chunk of stream) {
chunks.push(chunk)
}
const buffer = Buffer.concat(chunks);
const host = randomHost();
nock(`http://www.${host}.com`)
.get('/Koala.jpg')
.reply(200, (uri, requestBody) => {
return buffer
}, {
'Content-Type': 'image/jpeg',
'Content-Length': '29051'
})
try {
const downloader = new Downloader({
url: `http://www.${host}.com/Koala.jpg`,
directory: "./downloads",
cloneFiles: false,
fileName: 'buffer.jpeg',
shouldBufferResponse: true
})
await downloader.download();
} catch (error) {
throw error;
} finally {
await verifyFile('./downloads/buffer.jpeg', 29051);
}
})
it('Should repeat a request few times and fail', async () => {
const host = randomHost()
nock(`http://www.${host}.com`)
.get('/400')
.reply(400).persist()
var error;
try {
var counter = 0;
const downloader = new Downloader({
url: `http://www.${host}.com/400`,
directory: "./downloads",
maxAttempts: 3,
onError: function () {
counter++;
},
})
await downloader.download();
} catch (e) {
debugger;
error = e
} finally {
expect(counter).toBe(3)
expect(error.message).toBe('Request failed with status code 400')
}
})
it('Should repeat fail after first attempt, because of shouldStop hook', async () => {
const host = randomHost()
nock(`http://www.${host}.com`)
.get('/404')
.reply(404).persist()
try {
var counter = 0;
const downloader = new Downloader({
url: `http://www.${host}.com/404`,
directory: "./downloads",
maxAttempts: 3,
onError: function () {
counter++;
},
shouldStop: function (e) {
if (e.statusCode && e.statusCode === 404) {
return true;
}
}
})
await downloader.download();
} catch (error) {
expect(counter).toBe(1);
expect(error.message).toBe('Request failed with status code 404')
expect(error.statusCode).toBe(404);
}
})
it('Should fail once and finally fail', async () => {
const host = randomHost()
nock(`http://www.${host}.com`)
.get('/500')
.reply(500).persist()
var onErrorCount = 0;
try {
const downloader = new Downloader({
timeout: 1000,
url: `http://www.${host}.com/500`,
directory: "./downloads",
maxAttempts: 1,
onError: (e) => {
onErrorCount++;
}
})
await downloader.download();
} catch (error) {
} finally {
expect(onErrorCount).toBe(1)
}
})
it('Should use onResponse to stop download', async function () {
const host = randomHost()
fs.unlinkSync('./downloads/Koala.jpg')
nock(`http://www.${host}.com`)
.get('/Koala.jpg')
.reply(200, (uri, requestBody) => {
return fs.createReadStream(Path.join(__dirname, 'fixtures/Koala.jpg'))
}, {
'message': 'terminate'
}).persist()
const downloader = new Downloader({
timeout: 1000,
maxAttempts: 4,
onResponse: function (response) {
if (response.headers['message'] === 'terminate') {
return false;
}
},
url: `http://www.${host}.com/Koala.jpg`,
directory: "./downloads",
})
let fileExists = false
var { filePath, downloadStatus } = await downloader.download();
expect(filePath).toBe(null)
expect(downloadStatus).toBe('ABORTED')
try {
await verifyFile('./downloads/Koala.jpg', 29051);
fileExists = true//Aint supposed to reach this, verifyFile should throw an error.
} catch (error) { }
if (fileExists) throw new Error("Download hasn't stopped")
})
it('Should use onResponse to continue download', async function () {
const host = randomHost()
nock(`http://www.${host}.com`)
.get('/Koala.jpg')
.reply(200, (uri, requestBody) => {
return fs.createReadStream(Path.join(__dirname, 'fixtures/Koala.jpg'))
}, { 'message': 'do not terminate' }).persist()
const downloader = new Downloader({
timeout: 1000,
maxAttempts: 4,
onResponse: function (response) {
if (response.headers['message'] !== 'terminate') {
return;
}
return false;
},
fileName: 'yoyo.jpg',
url: `http://www.${host}.com/Koala.jpg`,
directory: "./downloads",
})
try {
const prom = await downloader.download();
} catch (error) {
} finally {
await verifyFile('./downloads/yoyo.jpg', 29051);
}
})
it('Should use shouldCotinue to stop download', async function () {
const host = randomHost()
nock(`http://www.${host}.com`)
.get('/Koala.jpg')
.reply(200, (uri, requestBody) => {
return fs.createReadStream(Path.join(__dirname, 'fixtures/Koala.jpg'))
}, { 'message': 'terminate' }).persist()
let error;
const downloader = new Downloader({
timeout: 1000,
maxAttempts: 4,
onResponse: function (response) {
if (response.headers['message'] === 'terminate') {
return false;
}
return false;
},
fileName: 'yoyo2.jpg',
url: `http://www.${host}.com/Koala.jpg`,
directory: "./downloads",
})
try {
const prom = await downloader.download();
await verifyFile('./downloads/yoyo2.jpg', 29051);
} catch (e) {
error = e;
} finally {
if (!error.code === 'ENOENT') {
throw error;
}
}
})
it('Should get the underlying responseBody an Error, as JSON', async function () {
const host = randomHost()
nock(`http://www.${host}.com`)
.get('/Koala.jpg')
.reply(400, (uri, requestBody) => {
return {
customErrorCode: 'SOME_CODE'
}
}, { 'message': 'terminate' }).persist()
let error;
const downloader = new Downloader({
fileName: 'yoyo2.jpg',
url: `http://www.${host}.com/Koala.jpg`,
directory: "./downloads",
})
try {
await downloader.download();
} catch (e) {
const body = e.responseBody;
expect(body.customErrorCode).toBe('SOME_CODE')
}
})
it('Should get the underlying responseBody an Error, as string', async function () {
const host = randomHost()
nock(`http://www.${host}.com`)
.get('/Koala.jpg')
.reply(400, (uri, requestBody) => {
return 'SOME_CODE'
}, { 'message': 'terminate' }).persist()
let error;
const downloader = new Downloader({
fileName: 'yoyo2.jpg',
url: `http://www.${host}.com/Koala.jpg`,
directory: "./downloads",
})
try {
await downloader.download();
} catch (e) {
const body = e.responseBody;
expect(body).toBe('SOME_CODE')
}
})
})
function randomHost(length = 5) {
var result = '';
var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
var charactersLength = characters.length;
for (var i = 0; i < length; i++) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
}
return result;
}
function timeout(mil) {
return new Promise((res) => {
setTimeout(() => {
res();
}, mil)
})
}
/**
*
* @param {string} path
* @param {number} [size]
*/
function verifyFile(path, size) {
return new Promise((resolve, reject) => {
fs.readFile(path, (err, data) => {
if (err)
return reject(err);
if (!size || data.length == size) {
resolve();
} else {
reject(err);
}
});
})
}
function doesFileExist(path) {
return new Promise((resolve, reject) => {
fs.readFile(path, (err, data) => {
if (err)
return resolve(false);
resolve(true);
});
})
}