diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..8f96039 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,10 @@ +# editorconfig.org +root = true + +[*] +indent_style = space +indent_size = 4 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true diff --git a/lib/processImage.js b/lib/processImage.js index 9bd04eb..1c00cce 100644 --- a/lib/processImage.js +++ b/lib/processImage.js @@ -30,8 +30,9 @@ module.exports = function (options) { getFilterInfosAndTargetContentTypeFromQueryString.sharp.cache(options.sharpCache); } return function (req, res, next) { + // Polyfill req.accepts for browser-sync compatibility if (typeof req.accepts !== 'function') { - req.accepts = function () { + req.accepts = function requestAccepts() { var accept = accepts(req); return accept.types.apply(accept, arguments); }; @@ -57,6 +58,14 @@ module.exports = function (options) { } delete req.headers['if-modified-since']; // Prevent false positive conditional GETs after enabling processimage hijackResponse(res, function (err, res) { + // Polyfill res.status for browser-sync compatibility + if (typeof res.status !== 'function') { + res.status = function status(statusCode) { + res.statusCode = statusCode; + return res; + }; + } + var sourceMetadata; function makeFilterInfosAndTargetFormat() { return getFilterInfosAndTargetContentTypeFromQueryString(queryString, _.defaults({ diff --git a/test/browsersync-compat.js b/test/browsersync-compat.js index 799f59f..167dad9 100644 --- a/test/browsersync-compat.js +++ b/test/browsersync-compat.js @@ -5,35 +5,31 @@ var pathModule = require('path'); var root = pathModule.resolve(__dirname, '..', 'testdata') + '/'; var processImage = require('../lib/processImage'); +var serverPort = '9999'; + expect.use(require('unexpected-http')) - .use(require('unexpected-image')) - .use(require('unexpected-resemble')) - .use(require('unexpected-sinon')) - .use(require('magicpen-prism')) - .addAssertion(' to respond with ', function (expect, subject, value) { - var modifiedSubject = subject.replace(' ', ' http://localhost:9999'); - return expect(modifiedSubject, 'to yield response', value); + .use(require('unexpected-image')); + +describe('browser-sync compatibility', function () { + before(function (done) { + bs.init({ + port: serverPort, + server: root, + open: false, + logLevel: 'silent', + middleware: [ + processImage({ root: root }) + ] + }, done); }); -before(function (done) { - bs.init({ - port: '9999', - server: root, - open: false, - logLevel: 'silent', - middleware: [ - processImage({ root: root }) - ] - }, done); -}); + after(function () { + bs.exit(); + }); -after(function () { - bs.exit(); -}); -describe('browser-sync compatibility', function () { it('should not mess with request for non-image file', function () { - return expect('GET /something.txt', 'to respond with', { + return expect(`GET http://localhost:${serverPort}/something.txt`, 'to yield response', { headers: { 'Content-Type': 'text/plain; charset=UTF-8' }, @@ -42,7 +38,7 @@ describe('browser-sync compatibility', function () { }); it('should not mess with request for image with no query string', function () { - return expect('GET /ancillaryChunks.png', 'to respond with', { + return expect(`GET http://localhost:${serverPort}/ancillaryChunks.png`, 'to yield response', { headers: { 'Content-Type': 'image/png' }, @@ -51,16 +47,38 @@ describe('browser-sync compatibility', function () { }); it('should not mess with request for image with an unsupported operation in the query string', function () { - return expect('GET /ancillaryChunks.png?foo=bar', 'to respond with', { + return expect(`GET http://localhost:${serverPort}/ancillaryChunks.png?foo=bar`, 'to yield response', { + headers: { + 'Content-Type': 'image/png' + }, + body: expect.it('to have length', 3711) + }); + }); + + it('should return a 304 status code when requesting the same image with unchanged modifications', function () { + return expect(`GET http://localhost:${serverPort}/ancillaryChunks.png?foo=bar`, 'to yield response', { + statusCode: 200, headers: { 'Content-Type': 'image/png' }, body: expect.it('to have length', 3711) + }).then(function (context) { + var etag = context.httpResponse.headers.get('ETag'); + return expect({ + url: `GET http://localhost:${serverPort}/ancillaryChunks.png?foo=bar`, + headers: { + 'If-None-Match': etag + } + }, 'to yield response', { + statusCode: 304, + headers: expect.it('to be empty'), + body: expect.it('to be', '') + }); }); }); it('should run the image through pngcrush when the pngcrush CGI param is specified', function () { - return expect('GET /ancillaryChunks.png?pngcrush=-rem+alla', 'to respond with', { + return expect(`GET http://localhost:${serverPort}/ancillaryChunks.png?pngcrush=-rem+alla`, 'to yield response', { statusCode: 200, headers: { 'Content-Type': 'image/png'