Refactor: fetch image dimensions from local file storage (#8900)

refs #8868

- Removed image-size in blog logo fn for meta data and made it synchronous
- Renamed `image-size-from-url.js` to `image-size.js` (incl. the test)
- Added second fn `getImageSizeFromFilePath` that reads from local file storage
- Added guard in `getImageSizeFromUrl` that checks if the image should be on local file storage and uses the new fn then instead
- Added a fn `fetchDimensionsFromBuffer` that takes the file buffer and returns an `imageObject` with dimensions.
- Added a new utils.js in `adapters/storage` for getting the file storage path
This commit is contained in:
Aileen Nowak 2017-09-05 19:13:22 +07:00 committed by Katharina Irrgang
parent a9e668a949
commit eef7932e94
14 changed files with 791 additions and 638 deletions

View File

@ -0,0 +1,27 @@
var globalUtils = require('../../utils');
/**
* @TODO: move `index.js` to here - e.g. storageUtils.getStorage
*/
/**
* Sanitizes a given URL or path for an image to be readable by the local file storage
* Always returns {string} url
* @param {string} imagePath
* @returns {string} imagePath
* @description Takes a url or filepath and returns a filepath with is readable
* for the local file storage.
*/
exports.getLocalFileStoragePath = function getLocalFileStoragePath(imagePath) {
if (imagePath.match(new RegExp('^' + globalUtils.url.urlJoin(globalUtils.url.urlFor('home', true), globalUtils.url.getSubdir(), '/', globalUtils.url.STATIC_IMAGE_URL_PREFIX)))) {
// Storage needs the path without `/content/images/` prefix
// The '/' in urlJoin is necessary to add the '/' to `content/images`, if no subdirectory is setup
return imagePath.replace(new RegExp('^' + globalUtils.url.urlJoin(globalUtils.url.urlFor('home', true), globalUtils.url.getSubdir(), '/', globalUtils.url.STATIC_IMAGE_URL_PREFIX)), '');
} else if (imagePath.match(new RegExp('^' + globalUtils.url.urlJoin(globalUtils.url.getSubdir(), '/', globalUtils.url.STATIC_IMAGE_URL_PREFIX)))) {
// Storage needs the path without `/content/images/` prefix
// The '/' in urlJoin is necessary to add the '/' to `content/images`, if no subdirectory is setup
return imagePath.replace(new RegExp('^' + globalUtils.url.urlJoin(globalUtils.url.getSubdir(), '/', globalUtils.url.STATIC_IMAGE_URL_PREFIX)), '');
} else {
return imagePath;
}
};

View File

@ -1,46 +1,20 @@
var utils = require('../../utils'),
settingsCache = require('../../settings/cache'),
blogIconUtils = require('../../utils/blog-icon'),
Promise = require('bluebird'),
config = require('../../config'),
path = require('path');
blogIconUtils = require('../../utils/blog-icon');
function getBlogLogo() {
return new Promise(function getIconSize(resolve, reject) {
var logo = {},
filePath;
var logo = {};
if (settingsCache.get('logo')) {
logo.url = utils.url.urlFor('image', {image: settingsCache.get('logo')}, true);
} else {
// CASE: no publication logo is updated. We can try to use either an uploaded publication icon
// or use the default one to make
// Google happy with it. See https://github.com/TryGhost/Ghost/issues/7558
logo.url = blogIconUtils.getIconUrl(true);
if (settingsCache.get('logo')) {
logo.url = utils.url.urlFor('image', {image: settingsCache.get('logo')}, true);
} else {
// CASE: no publication logo is updated. We can try to use either an uploaded publication icon
// or use the default one to make
// Google happy with it. See https://github.com/TryGhost/Ghost/issues/7558
logo.url = blogIconUtils.getIconUrl(true);
}
if (blogIconUtils.isIcoImageType(logo.url)) {
filePath = blogIconUtils.getIconPath();
// getIconDimensions needs the physical path of the ico file
if (settingsCache.get('icon')) {
// CASE: custom uploaded icon
filePath = path.join(config.getContentPath('images'), filePath);
}
return blogIconUtils.getIconDimensions(filePath).then(function (response) {
logo.dimensions = {
width: response.width,
height: response.height
};
return resolve(logo);
}).catch(function (err) {
return reject(err);
});
}
}
return resolve(logo);
});
return logo;
}
module.exports = getBlogLogo;

View File

@ -14,9 +14,7 @@ function getImageDimensions(metaData) {
coverImage: getCachedImageSizeFromUrl(metaData.coverImage.url),
authorImage: getCachedImageSizeFromUrl(metaData.authorImage.url),
ogImage: getCachedImageSizeFromUrl(metaData.ogImage.url),
// CASE: check if logo has hard coded image dimension. In that case it's an `ico` file, which
// is not supported by `image-size` and would produce an error
logo: metaData.blog.logo && metaData.blog.logo.dimensions ? metaData.blog.logo.dimensions : getCachedImageSizeFromUrl(metaData.blog.logo.url)
logo: getCachedImageSizeFromUrl(metaData.blog.logo.url)
};
return Promise.props(fetch).then(function (resolve) {
@ -43,11 +41,8 @@ function getImageDimensions(metaData) {
height: key.height
}
});
} else if ((metaData.blog.logo && metaData.blog.logo.dimensions) || key.width === key.height) {
// CASES:
// 1. .ico files have image dimensions assigned already. If they're not
// within the requirements of Google, we fake them...
// 2. the logo (non-ico) is too large, but it is a square. We fake it as well...
} else if (key.width === key.height) {
// CASE: the logo is too large, but it is a square. We fake it...
_.assign(metaData.blog[value], {
dimensions: {
width: 60,

View File

@ -68,38 +68,37 @@ function getMetaData(data, root) {
navigation: settingsCache.get('navigation'),
icon: settingsCache.get('icon'),
cover_image: settingsCache.get('cover_image'),
logo: settingsCache.get('logo'),
logo: getBlogLogo(),
amp: settingsCache.get('amp')
}
};
},
customExcerpt,
metaDescription,
fallbackExcerpt;
return Promise.props(getBlogLogo()).then(function (result) {
metaData.blog.logo = result;
// TODO: cleanup these if statements
if (data.post) {
// There's a specific order for description fields (not <meta name="description" /> !!) in structured data
// and schema.org which is used the description fields (see https://github.com/TryGhost/Ghost/issues/8793):
// 1. CASE: custom_excerpt is populated via the UI
// 2. CASE: no custom_excerpt, but meta_description is poplated via the UI
// 3. CASE: fall back to automated excerpt of 50 words if neither custom_excerpt nor meta_description is provided
customExcerpt = data.post.custom_excerpt;
metaDescription = data.post.meta_description;
fallbackExcerpt = data.post.html ? getExcerpt(data.post.html, {words: 50}) : '';
// TODO: cleanup these if statements
if (data.post) {
// There's a specific order for description fields (not <meta name="description" /> !!) in structured data
// and schema.org which is used the description fields (see https://github.com/TryGhost/Ghost/issues/8793):
// 1. CASE: custom_excerpt is populated via the UI
// 2. CASE: no custom_excerpt, but meta_description is poplated via the UI
// 3. CASE: fall back to automated excerpt of 50 words if neither custom_excerpt nor meta_description is provided
var customExcerpt = data.post.custom_excerpt,
metaDescription = data.post.meta_description,
fallbackExcerpt = data.post.html ? getExcerpt(data.post.html, {words: 50}) : '';
metaData.excerpt = customExcerpt ? customExcerpt : metaDescription ? metaDescription : fallbackExcerpt;
}
metaData.excerpt = customExcerpt ? customExcerpt : metaDescription ? metaDescription : fallbackExcerpt;
}
if (data.post && data.post.author && data.post.author.name) {
metaData.authorName = data.post.author.name;
}
if (data.post && data.post.author && data.post.author.name) {
metaData.authorName = data.post.author.name;
}
return Promise.props(getImageDimensions(metaData)).then(function () {
metaData.structuredData = getStructuredData(metaData);
metaData.schema = getSchema(metaData, data);
return Promise.props(getImageDimensions(metaData)).then(function () {
metaData.structuredData = getStructuredData(metaData);
metaData.schema = getSchema(metaData, data);
return metaData;
});
return metaData;
}).catch(function (err) {
logging.error(err);
return metaData;

View File

@ -1,13 +1,13 @@
var sizeOf = require('image-size'),
errors = require('../errors'),
url = require('./url'),
Promise = require('bluebird'),
i18n = require('../i18n'),
settingsCache = require('../settings/cache'),
_ = require('lodash'),
path = require('path'),
config = require('../config'),
utils = require('../utils'),
var sizeOf = require('image-size'),
errors = require('../errors'),
url = require('./url'),
Promise = require('bluebird'),
i18n = require('../i18n'),
settingsCache = require('../settings/cache'),
_ = require('lodash'),
path = require('path'),
config = require('../config'),
storageUtils = require('../adapters/storage/utils'),
getIconDimensions,
isIcoImageType,
getIconType,
@ -105,8 +105,7 @@ getIconPath = function getIconPath() {
var blogIcon = settingsCache.get('icon');
if (blogIcon) {
// The '/' in urlJoin is necessary to add the '/' to `content/images`, if no subdirectory is setup
return blogIcon.replace(new RegExp('^' + utils.url.urlJoin(utils.url.getSubdir(), '/', utils.url.STATIC_IMAGE_URL_PREFIX)), '');
return storageUtils.getLocalFileStoragePath(blogIcon);
} else {
return path.join(config.get('paths:publicFilePath'), 'favicon.ico');
}

View File

@ -1,8 +1,8 @@
var Promise = require('bluebird'),
size = require('./image-size-from-url'),
sizeOf = require('./image-size'),
logging = require('../logging'),
errors = require('../errors'),
getImageSizeFromUrl = size.getImageSizeFromUrl,
getImageSizeFromUrl = sizeOf.getImageSizeFromUrl,
imageSizeCache = {};
/**

View File

@ -1,103 +0,0 @@
// Supported formats of https://github.com/image-size/image-size:
// BMP, GIF, JPEG, PNG, PSD, TIFF, WebP, SVG
// ***
// Takes the url of the image and an optional timeout
// getImageSizeFromUrl returns an Object like this
// {
// height: 50,
// url: 'http://myblog.com/images/cat.jpg',
// width: 50
// };
// if the dimensions can be fetched and rejects with error, if not.
// ***
// In case we get a locally stored image or a not complete url (like //www.gravatar.com/andsoon),
// we add the protocol to the incomplete one and use urlFor() to get the absolute URL.
// If the request fails or image-size is not able to read the file, we reject with error.
var sizeOf = require('image-size'),
url = require('url'),
Promise = require('bluebird'),
got = require('got'),
config = require('../config'),
utils = require('../utils'),
errors = require('../errors'),
dimensions;
/**
* @description read image dimensions from URL
* @param {String} imagePath
* @returns {Promise<Object>} imageObject or error
*/
module.exports.getImageSizeFromUrl = function getImageSizeFromUrl(imagePath) {
var imageObject = {},
requestOptions,
timeout = config.get('times:getImageSizeTimeoutInMS') || 10000;
imageObject.url = imagePath;
// check if we got an url without any protocol
if (imagePath.indexOf('http') === -1) {
// our gravatar urls start with '//' in that case add 'http:'
if (imagePath.indexOf('//') === 0) {
// it's a gravatar url
imagePath = 'http:' + imagePath;
} else {
// get absolute url for image
imagePath = utils.url.urlFor('image', {image: imagePath}, true);
}
}
imagePath = url.parse(imagePath);
requestOptions = {
headers: {
'User-Agent': 'Mozilla/5.0'
},
timeout: timeout,
encoding: null
};
return got(
imagePath,
requestOptions
).then(function (response) {
try {
// response.body contains the Buffer. Using the Buffer rather than an URL
// requires to use sizeOf synchronously. See https://github.com/image-size/image-size#asynchronous
dimensions = sizeOf(response.body);
imageObject.width = dimensions.width;
imageObject.height = dimensions.height;
return Promise.resolve(imageObject);
} catch (err) {
return Promise.reject(new errors.InternalServerError({
code: 'IMAGE_SIZE',
err: err,
context: imagePath.href
}));
}
}).catch(function (err) {
if (err.statusCode === 404) {
return Promise.reject(new errors.NotFoundError({
message: 'Image not found.',
code: 'IMAGE_SIZE',
statusCode: err.statusCode,
context: err.url || imagePath.href || imagePath
}));
} else if (err.code === 'ETIMEDOUT') {
return Promise.reject(new errors.InternalServerError({
message: 'Request timed out.',
code: 'IMAGE_SIZE',
statusCode: err.statusCode,
context: err.url || imagePath.href || imagePath
}));
} else {
return Promise.reject(new errors.InternalServerError({
message: 'Unknown Request error.',
code: 'IMAGE_SIZE',
statusCode: err.statusCode,
context: err.url || imagePath.href || imagePath
}));
}
});
};

View File

@ -0,0 +1,189 @@
var sizeOf = require('image-size'),
url = require('url'),
Promise = require('bluebird'),
got = require('got'),
utils = require('../utils'),
errors = require('../errors'),
config = require('../config'),
storage = require('../adapters/storage'),
_ = require('lodash'),
storageUtils = require('../adapters/storage/utils'),
dimensions,
imageObject = {},
getImageSizeFromUrl,
getImageSizeFromFilePath;
/**
* @description compares the imagePath with a regex that reflects our local file storage
* @param {String} imagePath as URL or filepath
* @returns {Array} if match is true or null if not
*/
function isLocalImage(imagePath) {
imagePath = utils.url.urlFor('image', {image: imagePath}, true);
return imagePath.match(new RegExp('^' + utils.url.urlJoin(utils.url.urlFor('home', true), utils.url.getSubdir(), '/', utils.url.STATIC_IMAGE_URL_PREFIX)));
}
/**
* @description processes the Buffer result of an image file
* @param {Object} options
* @returns {Object} dimensions
*/
function fetchDimensionsFromBuffer(options) {
var buffer = options.buffer,
imagePath = options.imagePath;
try {
// Using the Buffer rather than an URL requires to use sizeOf synchronously.
// See https://github.com/image-size/image-size#asynchronous
dimensions = sizeOf(buffer);
// CASE: `.ico` files might have multiple images and therefore multiple sizes.
// We return the largest size found (image-size default is the first size found)
if (dimensions.images) {
dimensions.width = _.maxBy(dimensions.images, function (w) {return w.width;}).width;
dimensions.height = _.maxBy(dimensions.images, function (h) {return h.height;}).height;
}
imageObject.width = dimensions.width;
imageObject.height = dimensions.height;
return Promise.resolve(imageObject);
} catch (err) {
return Promise.reject(new errors.InternalServerError({
code: 'IMAGE_SIZE',
err: err,
context: imagePath
}));
}
}
// Supported formats of https://github.com/image-size/image-size:
// BMP, GIF, JPEG, PNG, PSD, TIFF, WebP, SVG, ICO
// ***
// Takes the url of the image and an optional timeout
// getImageSizeFromUrl returns an Object like this
// {
// height: 50,
// url: 'http://myblog.com/images/cat.jpg',
// width: 50
// };
// if the dimensions can be fetched, and rejects with error, if not.
// ***
// In case we get a locally stored image, which is checked withing the `isLocalImage`
// function we switch to read the image from the local file storage with `getImageSizeFromFilePath`.
// In case the image is not stored locally and is missing the protocol (like //www.gravatar.com/andsoon),
// we add the protocol and use urlFor() to get the absolute URL.
// If the request fails or image-size is not able to read the file, we reject with error.
/**
* @description read image dimensions from URL
* @param {String} imagePath as URL
* @returns {Promise<Object>} imageObject or error
*/
getImageSizeFromUrl = function getImageSizeFromUrl(imagePath) {
var requestOptions,
timeout = config.get('times:getImageSizeTimeoutInMS') || 10000;
imageObject.url = imagePath;
if (isLocalImage(imagePath)) {
// don't make a request for a locally stored image
return Promise.resolve(getImageSizeFromFilePath(imagePath));
}
// check if we got an url without any protocol
if (imagePath.indexOf('http') === -1) {
// our gravatar urls start with '//' in that case add 'http:'
if (imagePath.indexOf('//') === 0) {
// it's a gravatar url
imagePath = 'http:' + imagePath;
}
}
imagePath = url.parse(imagePath);
requestOptions = {
headers: {
'User-Agent': 'Mozilla/5.0'
},
timeout: timeout,
encoding: null
};
return got(
imagePath,
requestOptions
).then(function (response) {
return fetchDimensionsFromBuffer({
buffer: response.body,
imagePath: imagePath.href
});
}).catch(function (err) {
if (err.statusCode === 404) {
return Promise.reject(new errors.NotFoundError({
message: 'Image not found.',
code: 'IMAGE_SIZE',
statusCode: err.statusCode,
context: err.url || imagePath.href || imagePath
}));
} else if (err.code === 'ETIMEDOUT') {
return Promise.reject(new errors.InternalServerError({
message: 'Request timed out.',
code: 'IMAGE_SIZE',
statusCode: err.statusCode,
context: err.url || imagePath.href || imagePath
}));
} else {
return Promise.reject(new errors.InternalServerError({
message: 'Unknown Request error.',
code: 'IMAGE_SIZE',
statusCode: err.statusCode,
context: err.url || imagePath.href || imagePath
}));
}
});
};
// Supported formats of https://github.com/image-size/image-size:
// BMP, GIF, JPEG, PNG, PSD, TIFF, WebP, SVG, ICO
// ***
// Takes the url or filepath of the image and reads it form the local
// file storage.
// getImageSizeFromFilePath returns an Object like this
// {
// height: 50,
// url: 'http://myblog.com/images/cat.jpg',
// width: 50
// };
// if the image is found and dimensions can be fetched, and rejects with error, if not.
/**
* @description read image dimensions from local file storage
* @param {String} imagePath
* @returns {object} imageObject or error
*/
getImageSizeFromFilePath = function getImageSizeFromFilePath(imagePath) {
imagePath = utils.url.urlFor('image', {image: imagePath}, true);
imageObject.url = imagePath;
imagePath = storageUtils.getLocalFileStoragePath(imagePath);
return storage.getStorage()
.read({path: imagePath})
.then(function readFile(buf) {
return fetchDimensionsFromBuffer({
buffer: buf,
imagePath: imagePath
});
})
.catch(function (err) {
return Promise.reject(new errors.InternalServerError({
message: err.message,
code: 'IMAGE_SIZE',
err: err,
context: imagePath
}));
});
};
module.exports.getImageSizeFromUrl = getImageSizeFromUrl;
module.exports.getImageSizeFromFilePath = getImageSizeFromFilePath;

View File

@ -0,0 +1,93 @@
var should = require('should'),
sinon = require('sinon'),
utils = require('../../../../server/utils'),
// Stuff we are testing
storageUtils = require('../../../../server/adapters/storage/utils'),
sandbox = sinon.sandbox.create();
describe('storage utils', function () {
var urlForStub,
urlGetSubdirStub;
beforeEach(function () {
urlForStub = sandbox.stub();
});
afterEach(function () {
sandbox.restore();
});
describe('fn: getLocalFileStoragePath', function () {
it('should return local file storage path for absolute URL', function () {
var url = 'http://myblog.com/content/images/2017/07/ghost-logo.png',
result;
urlForStub = sandbox.stub(utils.url, 'urlFor');
urlForStub.withArgs('home').returns('http://myblog.com/');
urlGetSubdirStub = sandbox.stub(utils.url, 'getSubdir');
urlGetSubdirStub.returns('');
result = storageUtils.getLocalFileStoragePath(url);
should.exist(result);
result.should.be.equal('/2017/07/ghost-logo.png');
});
it('should return local file storage path for absolute URL with subdirectory', function () {
var url = 'http://myblog.com/blog/content/images/2017/07/ghost-logo.png',
result;
urlForStub = sandbox.stub(utils.url, 'urlFor');
urlForStub.withArgs('home').returns('http://myblog.com/');
urlGetSubdirStub = sandbox.stub(utils.url, 'getSubdir');
urlGetSubdirStub.returns('/blog');
result = storageUtils.getLocalFileStoragePath(url);
should.exist(result);
result.should.be.equal('/2017/07/ghost-logo.png');
});
it('should return local file storage path for relative URL', function () {
var filePath = '/content/images/2017/07/ghost-logo.png',
result;
urlForStub = sandbox.stub(utils.url, 'urlFor');
urlForStub.withArgs('home').returns('http://myblog.com/');
urlGetSubdirStub = sandbox.stub(utils.url, 'getSubdir');
urlGetSubdirStub.returns('');
result = storageUtils.getLocalFileStoragePath(filePath);
should.exist(result);
result.should.be.equal('/2017/07/ghost-logo.png');
});
it('should return local file storage path for relative URL with subdirectory', function () {
var filePath = '/blog/content/images/2017/07/ghost-logo.png',
result;
urlForStub = sandbox.stub(utils.url, 'urlFor');
urlForStub.withArgs('home').returns('http://myblog.com/');
urlGetSubdirStub = sandbox.stub(utils.url, 'getSubdir');
urlGetSubdirStub.returns('/blog');
result = storageUtils.getLocalFileStoragePath(filePath);
should.exist(result);
result.should.be.equal('/2017/07/ghost-logo.png');
});
it('should not sanitize URL if not local file storage', function () {
var url = 'http://example-blog.com/ghost-logo.png',
result;
urlForStub = sandbox.stub(utils.url, 'urlFor');
urlForStub.withArgs('home').returns('http://myblog.com/');
urlGetSubdirStub = sandbox.stub(utils.url, 'getSubdir');
urlGetSubdirStub.returns('');
result = storageUtils.getLocalFileStoragePath(url);
should.exist(result);
result.should.be.equal('http://example-blog.com/ghost-logo.png');
});
});
});

View File

@ -1,9 +1,7 @@
var should = require('should'),
getBlogLogo = require('../../../server/data/meta/blog_logo'),
sinon = require('sinon'),
Promise = require('bluebird'),
settingsCache = require('../../../server/settings/cache'),
blogIconUtils = require('../../../server/utils/blog-icon'),
sandbox = sinon.sandbox.create();
@ -12,7 +10,9 @@ describe('getBlogLogo', function () {
sandbox.restore();
});
it('should return logo if uploaded', function (done) {
it('should return logo if uploaded', function () {
var blogLogo;
sandbox.stub(settingsCache, 'get', function (key) {
return {
logo: '/content/images/logo.png',
@ -20,15 +20,14 @@ describe('getBlogLogo', function () {
}[key];
});
getBlogLogo().then(function (blogLogo) {
should.exist(blogLogo);
blogLogo.should.have.property('url', 'http://127.0.0.1:2369/content/images/logo.png');
}).catch(done);
done();
blogLogo = getBlogLogo();
should.exist(blogLogo);
blogLogo.should.have.property('url', 'http://127.0.0.1:2369/content/images/logo.png');
});
it('should return custom uploaded png icon if no logo given', function (done) {
it('should return custom uploaded png icon if no logo given', function () {
var blogLogo;
sandbox.stub(settingsCache, 'get', function (key) {
return {
logo: null,
@ -36,63 +35,8 @@ describe('getBlogLogo', function () {
}[key];
});
getBlogLogo().then(function (blogLogo) {
should.exist(blogLogo);
blogLogo.should.have.property('url', 'http://127.0.0.1:2369/favicon.png');
}).catch(done);
done();
});
it('should return custom uploaded ico icon incl. dimensions if no logo given', function (done) {
sandbox.stub(settingsCache, 'get', function (key) {
return {
logo: null,
icon: '/content/images/myicon.ico'
}[key];
});
sandbox.stub(blogIconUtils, 'getIconDimensions').returns(Promise.resolve({width: 48, height: 48}));
getBlogLogo().then(function (blogLogo) {
should.exist(blogLogo);
blogLogo.should.have.property('url', 'http://127.0.0.1:2369/favicon.ico');
blogLogo.should.have.property('dimensions');
blogLogo.dimensions.should.have.property('width', 48);
blogLogo.dimensions.should.have.property('height', 48);
}).catch(done);
done();
});
it('should return default favicon with dimensions if no logo or icon uploaded', function (done) {
getBlogLogo().then(function (blogLogo) {
should.exist(blogLogo);
blogLogo.should.have.property('url', 'http://127.0.0.1:2369/favicon.ico');
blogLogo.should.have.property('dimensions');
blogLogo.dimensions.should.have.property('width', 64);
blogLogo.dimensions.should.have.property('height', 64);
}).catch(done);
done();
});
it.skip('[failure] can handle errors', function (done) {
sandbox.stub(settingsCache, 'get', function (key) {
return {
logo: null,
icon: '/content/images/myicon.ico'
}[key];
});
sandbox.stub(blogIconUtils, 'getIconDimensions').returns(Promise.reject(new Error({message: 'could not fetch icon size'})));
getBlogLogo().then(function (blogLogo) {
should.not.exist(blogLogo);
done(new Error('should not resolve'));
}).catch(function (err) {
err.message.should.equal('could not fetch icon size');
done();
});
blogLogo = getBlogLogo();
should.exist(blogLogo);
blogLogo.should.have.property('url', 'http://127.0.0.1:2369/favicon.png');
});
});

View File

@ -115,7 +115,7 @@ describe('getImageDimensions', function () {
}).catch(done);
});
it('should not try to fetch image dimensions for logo if already set', function (done) {
it('should fake image dimension for publisher.logo if file is too big and square', function (done) {
var metaData = {
coverImage: {
url: 'http://mysite.com/content/image/mypostcoverimage.jpg'
@ -128,120 +128,7 @@ describe('getImageDimensions', function () {
},
blog: {
logo: {
url: 'http://mysite.com/author/image/url/favicon.ico',
dimensions: {
width: 60,
height: 60
}
}
}
};
sizeOfStub.returns({
width: 480,
height: 80,
type: 'jpg'
});
getImageDimensions.__set__('getCachedImageSizeFromUrl', sizeOfStub);
getImageDimensions(metaData).then(function (result) {
should.exist(result);
sizeOfStub.calledWith(metaData.coverImage.url).should.be.true();
sizeOfStub.calledWith(metaData.authorImage.url).should.be.true();
sizeOfStub.calledWith(metaData.ogImage.url).should.be.true();
sizeOfStub.calledWith(metaData.blog.logo.url).should.be.false();
result.coverImage.should.have.property('dimensions');
result.coverImage.should.have.property('url');
result.coverImage.dimensions.should.have.property('height', 80);
result.coverImage.dimensions.should.have.property('width', 480);
result.authorImage.should.have.property('dimensions');
result.authorImage.should.have.property('url');
result.authorImage.dimensions.should.have.property('height', 80);
result.authorImage.dimensions.should.have.property('width', 480);
result.ogImage.should.have.property('dimensions');
result.ogImage.should.have.property('url');
result.ogImage.dimensions.should.have.property('height', 80);
result.ogImage.dimensions.should.have.property('width', 480);
result.blog.logo.should.have.property('dimensions');
result.blog.logo.should.have.property('url');
result.blog.logo.dimensions.should.have.property('height', 60);
result.blog.logo.dimensions.should.have.property('width', 60);
done();
}).catch(done);
});
it('should fake image dimension for publisher.logo if .ico file is too big', function (done) {
var metaData = {
coverImage: {
url: 'http://mysite.com/content/image/mypostcoverimage.jpg'
},
authorImage: {
url: 'http://mysite.com/author/image/url/me.jpg'
},
ogImage: {
url: 'http://mysite.com/content/image/super-facebook-image.jpg'
},
blog: {
logo: {
url: 'http://mysite.com/author/image/url/favicon.ico',
dimensions: {
width: 128,
height: 128
}
}
}
};
sizeOfStub.returns({
width: 480,
height: 480,
type: 'jpg'
});
getImageDimensions.__set__('getCachedImageSizeFromUrl', sizeOfStub);
getImageDimensions(metaData).then(function (result) {
should.exist(result);
sizeOfStub.calledWith(metaData.coverImage.url).should.be.true();
sizeOfStub.calledWith(metaData.authorImage.url).should.be.true();
sizeOfStub.calledWith(metaData.ogImage.url).should.be.true();
sizeOfStub.calledWith(metaData.blog.logo.url).should.be.false();
result.coverImage.should.have.property('dimensions');
result.coverImage.should.have.property('url');
result.coverImage.dimensions.should.have.property('height', 480);
result.coverImage.dimensions.should.have.property('width', 480);
result.authorImage.should.have.property('dimensions');
result.authorImage.should.have.property('url');
result.authorImage.dimensions.should.have.property('height', 480);
result.authorImage.dimensions.should.have.property('width', 480);
result.ogImage.should.have.property('dimensions');
result.ogImage.should.have.property('url');
result.ogImage.dimensions.should.have.property('height', 480);
result.ogImage.dimensions.should.have.property('width', 480);
result.blog.logo.should.have.property('dimensions');
result.blog.logo.should.have.property('url');
result.blog.logo.dimensions.should.have.property('height', 60);
result.blog.logo.dimensions.should.have.property('width', 60);
done();
}).catch(done);
});
it('should fake image dimension for publisher.logo if non-.ico file is too big and square', function (done) {
var metaData = {
coverImage: {
url: 'http://mysite.com/content/image/mypostcoverimage.jpg'
},
authorImage: {
url: 'http://mysite.com/author/image/url/me.jpg'
},
ogImage: {
url: 'http://mysite.com/content/image/super-facebook-image.jpg'
},
blog: {
logo: {
url: 'http://mysite.com/author/image/url/favicon.png'
url: 'http://mysite.com/author/image/url/favicon.ico'
}
}
};

View File

@ -144,7 +144,7 @@ describe('Blog Icon', function () {
should.exist(result);
result.should.eql({
width: 48,
height:48
height: 48
});
done();
}).catch(done);
@ -156,7 +156,7 @@ describe('Blog Icon', function () {
should.exist(result);
result.should.eql({
width: 100,
height:100
height: 100
});
done();
}).catch(done);
@ -168,7 +168,7 @@ describe('Blog Icon', function () {
should.exist(result);
result.should.eql({
width: 64,
height:64
height: 64
});
done();
}).catch(done);

View File

@ -1,265 +0,0 @@
var should = require('should'),
sinon = require('sinon'),
rewire = require('rewire'),
nock = require('nock'),
configUtils = require('../../utils/configUtils'),
utils = require('../../../server/utils'),
// Stuff we are testing
imageSize = rewire('../../../server/utils/image-size-from-url'),
sandbox = sinon.sandbox.create();
describe('Image Size', function () {
var sizeOfStub,
result,
requestMock,
secondRequestMock;
beforeEach(function () {
sizeOfStub = sandbox.stub();
});
afterEach(function () {
sandbox.restore();
configUtils.restore();
imageSize = rewire('../../../server/utils/image-size-from-url');
});
it('should have an image size function', function () {
should.exist(imageSize);
});
it('should return image dimensions with http request', function (done) {
var url = 'http://img.stockfresh.com/files/f/feedough/x/11/1540353_20925115.jpg',
expectedImageObject =
{
height: 50,
url: 'http://img.stockfresh.com/files/f/feedough/x/11/1540353_20925115.jpg',
width: 50
};
requestMock = nock('http://img.stockfresh.com')
.get('/files/f/feedough/x/11/1540353_20925115.jpg')
.reply(200);
sizeOfStub.returns({width: 50, height: 50, type: 'jpg'});
imageSize.__set__('sizeOf', sizeOfStub);
result = imageSize.getImageSizeFromUrl(url).then(function (res) {
requestMock.isDone().should.be.true();
should.exist(res);
should.exist(res.width);
res.width.should.be.equal(expectedImageObject.width);
should.exist(res.height);
res.height.should.be.equal(expectedImageObject.height);
should.exist(res.url);
res.url.should.be.equal(expectedImageObject.url);
done();
}).catch(done);
});
it('should return image dimensions with https request', function (done) {
var url = 'https://static.wixstatic.com/media/355241_d31358572a2542c5a44738ddcb59e7ea.jpg_256',
expectedImageObject =
{
height: 256,
url: 'https://static.wixstatic.com/media/355241_d31358572a2542c5a44738ddcb59e7ea.jpg_256',
width: 256
};
requestMock = nock('https://static.wixstatic.com')
.get('/media/355241_d31358572a2542c5a44738ddcb59e7ea.jpg_256')
.reply(200, {
body: '<Buffer 2c be a4 40 f7 87 73 1e 57 2c c1 e4 0d 79 03 95 42 f0 42 2e 41 95 27 c9 5c 35 a7 71 2c 09 5a 57 d3 04 1e 83 03 28 07 96 b0 c8 88 65 07 7a d1 d6 63 50>'
});
sizeOfStub.returns({width: 256, height: 256, type: 'png'});
imageSize.__set__('sizeOf', sizeOfStub);
result = imageSize.getImageSizeFromUrl(url).then(function (res) {
requestMock.isDone().should.be.true();
should.exist(res);
should.exist(res.width);
res.width.should.be.equal(expectedImageObject.width);
should.exist(res.height);
res.height.should.be.equal(expectedImageObject.height);
should.exist(res.url);
res.url.should.be.equal(expectedImageObject.url);
done();
}).catch(done);
});
it('should return image dimensions for gravatar images request', function (done) {
var url = '//www.gravatar.com/avatar/ef6dcde5c99bb8f685dd451ccc3e050a?s=250&d=mm&r=x',
expectedImageObject =
{
height: 250,
url: '//www.gravatar.com/avatar/ef6dcde5c99bb8f685dd451ccc3e050a?s=250&d=mm&r=x',
width: 250
};
requestMock = nock('http://www.gravatar.com')
.get('/avatar/ef6dcde5c99bb8f685dd451ccc3e050a?s=250&d=mm&r=x')
.reply(200, {
body: '<Buffer 2c be a4 40 f7 87 73 1e 57 2c c1 e4 0d 79 03 95 42 f0 42 2e 41 95 27 c9 5c 35 a7 71 2c 09 5a 57 d3 04 1e 83 03 28 07 96 b0 c8 88 65 07 7a d1 d6 63 50>'
});
sizeOfStub.returns({width: 250, height: 250, type: 'jpg'});
imageSize.__set__('sizeOf', sizeOfStub);
result = imageSize.getImageSizeFromUrl(url).then(function (res) {
requestMock.isDone().should.be.true();
should.exist(res);
should.exist(res.width);
res.width.should.be.equal(expectedImageObject.width);
should.exist(res.height);
res.height.should.be.equal(expectedImageObject.height);
should.exist(res.url);
res.url.should.be.equal(expectedImageObject.url);
done();
}).catch(done);
});
it('should return image dimensions relative url request', function (done) {
var url = '/content/images/cat.jpg',
urlForStub,
expectedImageObject =
{
height: 100,
url: '/content/images/cat.jpg',
width: 100
};
urlForStub = sandbox.stub(utils.url, 'urlFor');
urlForStub.withArgs('image').returns('http://myblog.com/content/images/cat.jpg');
requestMock = nock('http://myblog.com')
.get('/content/images/cat.jpg')
.reply(200, {
body: '<Buffer 2c be a4 40 f7 87 73 1e 57 2c c1 e4 0d 79 03 95 42 f0 42 2e 41 95 27 c9 5c 35 a7 71 2c 09 5a 57 d3 04 1e 83 03 28 07 96 b0 c8 88 65 07 7a d1 d6 63 50>'
});
sizeOfStub.returns({width: 100, height: 100, type: 'jpg'});
imageSize.__set__('sizeOf', sizeOfStub);
result = imageSize.getImageSizeFromUrl(url).then(function (res) {
requestMock.isDone().should.be.true();
should.exist(res);
should.exist(res.width);
res.width.should.be.equal(expectedImageObject.width);
should.exist(res.height);
res.height.should.be.equal(expectedImageObject.height);
should.exist(res.url);
res.url.should.be.equal(expectedImageObject.url);
done();
}).catch(done);
});
it('can handle an error a statuscode not 200', function (done) {
var url = 'http://noimagehere.com/files/f/feedough/x/11/1540353_20925115.jpg';
requestMock = nock('http://noimagehere.com')
.get('/files/f/feedough/x/11/1540353_20925115.jpg')
.reply(404);
result = imageSize.getImageSizeFromUrl(url)
.catch(function (err) {
requestMock.isDone().should.be.true();
should.exist(err);
done();
});
});
it('can handle redirect', function (done) {
var url = 'http://noimagehere.com/files/f/feedough/x/11/1540353_20925115.jpg',
expectedImageObject =
{
height: 100,
url: 'http://noimagehere.com/files/f/feedough/x/11/1540353_20925115.jpg',
width: 100
};
requestMock = nock('http://noimagehere.com')
.get('/files/f/feedough/x/11/1540353_20925115.jpg')
.reply(301, {
body: '<Buffer 2c be a4 40 f7 87 73 1e 57 2c c1 e4 0d 79 03 95 42 f0 42 2e 41 95 27 c9 5c 35 a7 71 2c 09 5a 57 d3 04 1e 83 03 28 07 96 b0 c8 88 65 07 7a d1 d6 63 50>'
},
{
location: 'http://someredirectedurl.com/files/f/feedough/x/11/1540353_20925115.jpg'
});
secondRequestMock = nock('http://someredirectedurl.com')
.get('/files/f/feedough/x/11/1540353_20925115.jpg')
.reply(200, {
body: '<Buffer 2c be a4 40 f7 87 73 1e 57 2c c1 e4 0d 79 03 95 42 f0 42 2e 41 95 27 c9 5c 35 a7 71 2c 09 5a 57 d3 04 1e 83 03 28 07 96 b0 c8 88 65 07 7a d1 d6 63 50>'
});
sizeOfStub.returns({width: 100, height: 100, type: 'jpg'});
imageSize.__set__('sizeOf', sizeOfStub);
result = imageSize.getImageSizeFromUrl(url).then(function (res) {
requestMock.isDone().should.be.true();
secondRequestMock.isDone().should.be.true();
should.exist(res);
should.exist(res.width);
res.width.should.be.equal(expectedImageObject.width);
should.exist(res.height);
res.height.should.be.equal(expectedImageObject.height);
should.exist(res.url);
res.url.should.be.equal(expectedImageObject.url);
done();
}).catch(done);
});
it('will timeout', function (done) {
var url = 'https://static.wixstatic.com/media/355241_d31358572a2542c5a44738ddcb59e7ea.jpg_256';
requestMock = nock('https://static.wixstatic.com')
.get('/media/355241_d31358572a2542c5a44738ddcb59e7ea.jpg_256')
.socketDelay(11)
.reply(408);
configUtils.set('times:getImageSizeTimeoutInMS', 10);
result = imageSize.getImageSizeFromUrl(url)
.catch(function (err) {
requestMock.isDone().should.be.true();
should.exist(err);
done();
});
});
it('returns error if \`image-size`\ module throws error', function (done) {
var url = 'https://static.wixstatic.com/media/355241_d31358572a2542c5a44738ddcb59e7ea.jpg_256',
requestMock = nock('https://static.wixstatic.com')
.get('/media/355241_d31358572a2542c5a44738ddcb59e7ea.jpg_256')
.reply(200, {
body: '<Buffer 2c be a4 40 f7 87 73 1e 57 2c c1 e4 0d 79 03 95 42 f0 42 2e 41 95 27 c9 5c 35 a7 71 2c 09 5a 57 d3 04 1e 83 03 28 07 96 b0 c8 88 65 07 7a d1 d6 63 50>'
});
sizeOfStub.throws({error: 'image-size could not find dimensions'});
imageSize.__set__('sizeOf', sizeOfStub);
result = imageSize.getImageSizeFromUrl(url)
.catch(function (err) {
requestMock.isDone().should.be.true();
should.exist(err);
done();
});
});
it('returns error if request errors', function (done) {
var url = 'https://notarealwebsite.com/images/notapicture.jpg',
requestMock = nock('https://notarealwebsite.com')
.get('/images/notapicture.jpg')
.replyWithError({message: 'something awful happened', code: 'AWFUL_ERROR'});
configUtils.set('times:getImageSizeTimeoutInMS', 5);
result = imageSize.getImageSizeFromUrl(url)
.catch(function (err) {
requestMock.isDone().should.be.true();
should.exist(err);
done();
});
});
});

View File

@ -0,0 +1,414 @@
var should = require('should'),
sinon = require('sinon'),
rewire = require('rewire'),
nock = require('nock'),
configUtils = require('../../utils/configUtils'),
utils = require('../../../server/utils'),
storage = require('../../../server/adapters/storage'),
path = require('path'),
// Stuff we are testing
imageSize = rewire('../../../server/utils/image-size'),
sandbox = sinon.sandbox.create();
describe('Image Size', function () {
var sizeOfStub,
result,
requestMock,
originalStoragePath;
beforeEach(function () {
originalStoragePath = storage.getStorage().storagePath;
});
afterEach(function () {
sandbox.restore();
configUtils.restore();
imageSize = rewire('../../../server/utils/image-size');
storage.getStorage().storagePath = originalStoragePath;
});
it('[success] should have an image size function', function () {
should.exist(imageSize.getImageSizeFromUrl);
should.exist(imageSize.getImageSizeFromFilePath);
});
describe('getImageSizeFromUrl', function () {
it('[success] should return image dimensions with http request', function (done) {
var url = 'http://img.stockfresh.com/files/f/feedough/x/11/1540353_20925115.jpg',
expectedImageObject =
{
height: 50,
url: 'http://img.stockfresh.com/files/f/feedough/x/11/1540353_20925115.jpg',
width: 50
};
requestMock = nock('http://img.stockfresh.com')
.get('/files/f/feedough/x/11/1540353_20925115.jpg')
.reply(200);
sizeOfStub = sandbox.stub();
sizeOfStub.returns({width: 50, height: 50, type: 'jpg'});
imageSize.__set__('sizeOf', sizeOfStub);
result = imageSize.getImageSizeFromUrl(url).then(function (res) {
requestMock.isDone().should.be.true();
should.exist(res);
should.exist(res.width);
res.width.should.be.equal(expectedImageObject.width);
should.exist(res.height);
res.height.should.be.equal(expectedImageObject.height);
should.exist(res.url);
res.url.should.be.equal(expectedImageObject.url);
done();
}).catch(done);
});
it('[success] should return image dimensions with https request', function (done) {
var url = 'https://static.wixstatic.com/media/355241_d31358572a2542c5a44738ddcb59e7ea.jpg_256',
expectedImageObject =
{
height: 256,
url: 'https://static.wixstatic.com/media/355241_d31358572a2542c5a44738ddcb59e7ea.jpg_256',
width: 256
};
requestMock = nock('https://static.wixstatic.com')
.get('/media/355241_d31358572a2542c5a44738ddcb59e7ea.jpg_256')
.reply(200, {
data: '<Buffer 2c be a4 40 f7 87 73 1e 57 2c c1 e4 0d 79 03 95 42 f0 42 2e 41 95 27 c9 5c 35 a7 71 2c 09 5a 57 d3 04 1e 83 03 28 07 96 b0 c8 88 65 07 7a d1 d6 63 50>'
});
sizeOfStub = sandbox.stub();
sizeOfStub.returns({width: 256, height: 256, type: 'png'});
imageSize.__set__('sizeOf', sizeOfStub);
result = imageSize.getImageSizeFromUrl(url).then(function (res) {
requestMock.isDone().should.be.true();
should.exist(res);
should.exist(res.width);
res.width.should.be.equal(expectedImageObject.width);
should.exist(res.height);
res.height.should.be.equal(expectedImageObject.height);
should.exist(res.url);
res.url.should.be.equal(expectedImageObject.url);
done();
}).catch(done);
});
it('[success] should returns largest image value for .ico files', function (done) {
var url = 'https://super-website.com/media/icon.ico',
expectedImageObject =
{
height: 48,
url: 'https://super-website.com/media/icon.ico',
width: 48
};
requestMock = nock('https://super-website.com')
.get('/media/icon.ico')
.reply(200, {
data: '<Buffer 2c be a4 40 f7 87 73 1e 57 2c c1 e4 0d 79 03 95 42 f0 42 2e 41 95 27 c9 5c 35 a7 71 2c 09 5a 57 d3 04 1e 83 03 28 07 96 b0 c8 88 65 07 7a d1 d6 63 50>'
});
sizeOfStub = sandbox.stub();
sizeOfStub.returns({
width: 32,
height: 32,
type: 'ico',
images: [
{width: 48, height: 48},
{width: 32, height: 32},
{width: 16, height: 16}
]
});
imageSize.__set__('sizeOf', sizeOfStub);
result = imageSize.getImageSizeFromUrl(url).then(function (res) {
requestMock.isDone().should.be.true();
should.exist(res);
should.exist(res.width);
res.width.should.be.equal(expectedImageObject.width);
should.exist(res.height);
res.height.should.be.equal(expectedImageObject.height);
should.exist(res.url);
res.url.should.be.equal(expectedImageObject.url);
done();
}).catch(done);
});
it('[success] should return image dimensions for gravatar images request', function (done) {
var url = '//www.gravatar.com/avatar/ef6dcde5c99bb8f685dd451ccc3e050a?s=250&d=mm&r=x',
expectedImageObject =
{
height: 250,
url: '//www.gravatar.com/avatar/ef6dcde5c99bb8f685dd451ccc3e050a?s=250&d=mm&r=x',
width: 250
};
requestMock = nock('http://www.gravatar.com')
.get('/avatar/ef6dcde5c99bb8f685dd451ccc3e050a?s=250&d=mm&r=x')
.reply(200, {
data: '<Buffer 2c be a4 40 f7 87 73 1e 57 2c c1 e4 0d 79 03 95 42 f0 42 2e 41 95 27 c9 5c 35 a7 71 2c 09 5a 57 d3 04 1e 83 03 28 07 96 b0 c8 88 65 07 7a d1 d6 63 50>'
});
sizeOfStub = sandbox.stub();
sizeOfStub.returns({width: 250, height: 250, type: 'jpg'});
imageSize.__set__('sizeOf', sizeOfStub);
result = imageSize.getImageSizeFromUrl(url).then(function (res) {
requestMock.isDone().should.be.true();
should.exist(res);
should.exist(res.width);
res.width.should.be.equal(expectedImageObject.width);
should.exist(res.height);
res.height.should.be.equal(expectedImageObject.height);
should.exist(res.url);
res.url.should.be.equal(expectedImageObject.url);
done();
}).catch(done);
});
it('[success] should switch to local file storage if available', function (done) {
var url = '/content/images/favicon.png',
urlForStub,
urlGetSubdirStub,
expectedImageObject =
{
height: 100,
url: 'http://myblog.com/content/images/favicon.png',
width: 100
};
storage.getStorage().storagePath = path.join(__dirname, '../../../test/utils/fixtures/images/');
urlForStub = sandbox.stub(utils.url, 'urlFor');
urlForStub.withArgs('image').returns('http://myblog.com/content/images/favicon.png');
urlForStub.withArgs('home').returns('http://myblog.com/');
urlGetSubdirStub = sandbox.stub(utils.url, 'getSubdir');
urlGetSubdirStub.returns('');
requestMock = nock('http://myblog.com')
.get('/content/images/favicon.png')
.reply(200, {
data: '<Buffer 2c be a4 40 f7 87 73 1e 57 2c c1 e4 0d 79 03 95 42 f0 42 2e 41 95 27 c9 5c 35 a7 71 2c 09 5a 57 d3 04 1e 83 03 28 07 96 b0 c8 88 65 07 7a d1 d6 63 50>'
});
result = imageSize.getImageSizeFromUrl(url).then(function (res) {
requestMock.isDone().should.be.false();
should.exist(res);
should.exist(res.width);
res.width.should.be.equal(expectedImageObject.width);
should.exist(res.height);
res.height.should.be.equal(expectedImageObject.height);
should.exist(res.url);
res.url.should.be.equal(expectedImageObject.url);
done();
}).catch(done);
});
it('[failure] can handle an error with statuscode not 200', function (done) {
var url = 'http://noimagehere.com/files/f/feedough/x/11/1540353_20925115.jpg';
requestMock = nock('http://noimagehere.com')
.get('/files/f/feedough/x/11/1540353_20925115.jpg')
.reply(404);
result = imageSize.getImageSizeFromUrl(url)
.catch(function (err) {
requestMock.isDone().should.be.true();
should.exist(err);
done();
});
});
it('[failure] will timeout', function (done) {
var url = 'https://static.wixstatic.com/media/355241_d31358572a2542c5a44738ddcb59e7ea.jpg_256';
requestMock = nock('https://static.wixstatic.com')
.get('/media/355241_d31358572a2542c5a44738ddcb59e7ea.jpg_256')
.socketDelay(11)
.reply(408);
configUtils.set('times:getImageSizeTimeoutInMS', 10);
result = imageSize.getImageSizeFromUrl(url)
.catch(function (err) {
requestMock.isDone().should.be.true();
should.exist(err);
done();
});
});
it('[failure] returns error if \`image-size`\ module throws error', function (done) {
var url = 'https://static.wixstatic.com/media/355241_d31358572a2542c5a44738ddcb59e7ea.jpg_256';
requestMock = nock('https://static.wixstatic.com')
.get('/media/355241_d31358572a2542c5a44738ddcb59e7ea.jpg_256')
.reply(200, {
data: '<Buffer 2c be a4 40 f7 87 73 1e 57 2c c1 e4 0d 79 03 95 42 f0 42 2e 41 95 27 c9 5c 35 a7 71 2c 09 5a 57 d3 04 1e 83 03 28 07 96 b0 c8 88 65 07 7a d1 d6 63 50>'
});
sizeOfStub = sandbox.stub();
sizeOfStub.throws({error: 'image-size could not find dimensions'});
imageSize.__set__('sizeOf', sizeOfStub);
result = imageSize.getImageSizeFromUrl(url)
.catch(function (err) {
requestMock.isDone().should.be.true();
should.exist(err);
done();
});
});
it('[failure] returns error if request errors', function (done) {
var url = 'https://notarealwebsite.com/images/notapicture.jpg';
requestMock = nock('https://notarealwebsite.com')
.get('/images/notapicture.jpg')
.reply(404, {message: 'something awful happened', code: 'AWFUL_ERROR'});
result = imageSize.getImageSizeFromUrl(url)
.catch(function (err) {
requestMock.isDone().should.be.true();
should.exist(err);
done();
});
});
});
describe('getImageSizeFromFilePath', function () {
it('[success] should return image dimensions for locally stored images', function (done) {
var url = '/content/images/ghost-logo.png',
urlForStub,
urlGetSubdirStub,
expectedImageObject =
{
height: 257,
url: 'http://myblog.com/content/images/ghost-logo.png',
width: 800
};
storage.getStorage().storagePath = path.join(__dirname, '../../../test/utils/fixtures/images/');
urlForStub = sandbox.stub(utils.url, 'urlFor');
urlForStub.withArgs('image').returns('http://myblog.com/content/images/ghost-logo.png');
urlForStub.withArgs('home').returns('http://myblog.com/');
urlGetSubdirStub = sandbox.stub(utils.url, 'getSubdir');
urlGetSubdirStub.returns('');
result = imageSize.getImageSizeFromFilePath(url).then(function (res) {
should.exist(res);
should.exist(res.width);
res.width.should.be.equal(expectedImageObject.width);
should.exist(res.height);
res.height.should.be.equal(expectedImageObject.height);
should.exist(res.url);
res.url.should.be.equal(expectedImageObject.url);
done();
}).catch(done);
});
it('[success] should return image dimensions for locally stored images with subdirectory', function (done) {
var url = '/content/images/favicon_too_large.png',
urlForStub,
urlGetSubdirStub,
expectedImageObject =
{
height: 1010,
url: 'http://myblog.com/blog/content/images/favicon_too_large.png',
width: 1010
};
storage.getStorage().storagePath = path.join(__dirname, '../../../test/utils/fixtures/images/');
urlForStub = sandbox.stub(utils.url, 'urlFor');
urlForStub.withArgs('image').returns('http://myblog.com/blog/content/images/favicon_too_large.png');
urlForStub.withArgs('home').returns('http://myblog.com/');
urlGetSubdirStub = sandbox.stub(utils.url, 'getSubdir');
urlGetSubdirStub.returns('/blog');
result = imageSize.getImageSizeFromFilePath(url).then(function (res) {
should.exist(res);
should.exist(res.width);
res.width.should.be.equal(expectedImageObject.width);
should.exist(res.height);
res.height.should.be.equal(expectedImageObject.height);
should.exist(res.url);
res.url.should.be.equal(expectedImageObject.url);
done();
}).catch(done);
});
it('[success] should return largest image dimensions for locally stored .ico image', function (done) {
var url = 'http://myblog.com/content/images/favicon_multi_sizes.ico',
urlForStub,
urlGetSubdirStub,
expectedImageObject =
{
height: 64,
url: 'http://myblog.com/content/images/favicon_multi_sizes.ico',
width: 64
};
storage.getStorage().storagePath = path.join(__dirname, '../../../test/utils/fixtures/images/');
urlForStub = sandbox.stub(utils.url, 'urlFor');
urlForStub.withArgs('image').returns('http://myblog.com/content/images/favicon_multi_sizes.ico');
urlForStub.withArgs('home').returns('http://myblog.com/');
urlGetSubdirStub = sandbox.stub(utils.url, 'getSubdir');
urlGetSubdirStub.returns('');
result = imageSize.getImageSizeFromFilePath(url).then(function (res) {
should.exist(res);
should.exist(res.width);
res.width.should.be.equal(expectedImageObject.width);
should.exist(res.height);
res.height.should.be.equal(expectedImageObject.height);
should.exist(res.url);
res.url.should.be.equal(expectedImageObject.url);
done();
}).catch(done);
});
it('[failure] returns error if storage adapter errors', function (done) {
var url = '/content/images/not-existing-image.png',
urlForStub,
urlGetSubdirStub;
storage.getStorage().storagePath = path.join(__dirname, '../../../test/utils/fixtures/images/');
urlForStub = sandbox.stub(utils.url, 'urlFor');
urlForStub.withArgs('image').returns('http://myblog.com/content/images/not-existing-image.png');
urlForStub.withArgs('home').returns('http://myblog.com/');
urlGetSubdirStub = sandbox.stub(utils.url, 'getSubdir');
urlGetSubdirStub.returns('');
result = imageSize.getImageSizeFromFilePath(url)
.catch(function (err) {
should.exist(err);
err.message.should.match(/Could not read image:/);
done();
});
});
it('[failure] returns error if \`image-size`\ module throws error', function (done) {
var url = '/content/images/ghost-logo.pngx',
urlForStub,
urlGetSubdirStub;
sizeOfStub = sandbox.stub();
sizeOfStub.throws({error: 'image-size could not find dimensions'});
imageSize.__set__('sizeOf', sizeOfStub);
storage.getStorage().storagePath = path.join(__dirname, '../../../test/utils/fixtures/images/');
urlForStub = sandbox.stub(utils.url, 'urlFor');
urlForStub.withArgs('image').returns('http://myblog.com/content/images/ghost-logo.pngx');
urlForStub.withArgs('home').returns('http://myblog.com/');
urlGetSubdirStub = sandbox.stub(utils.url, 'getSubdir');
urlGetSubdirStub.returns('');
result = imageSize.getImageSizeFromFilePath(url)
.catch(function (err) {
should.exist(err);
err.error.should.be.equal('image-size could not find dimensions');
done();
});
});
});
});