From 517206364a9f73fd6c43f07ff8d0e261fabd90d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20M=C3=A9tais?= Date: Thu, 14 Mar 2019 03:27:37 +0100 Subject: [PATCH] Work in progress: switch to Phantomas v2 --- .travis.yml | 1 - Gruntfile.js | 7 +- lib/offendersHelpers.js | 26 ++--- lib/runner.js | 6 - lib/tools/phantomas/phantomasWrapper.js | 121 ++++++++------------- lib/tools/redownload/contentTypeChecker.js | 48 ++++++++ lib/tools/redownload/redownload.js | 75 +++++++++++-- package.json | 5 +- test/api/apiTest.js | 33 ------ test/core/indexTest.js | 11 -- test/core/mediaQueriesCheckerTest.js | 94 +++++++++------- test/core/offendersHelpersTest.js | 46 -------- test/core/phantomasWrapperTest.js | 5 +- test/core/redownloadTest.js | 89 +++------------ 14 files changed, 248 insertions(+), 319 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3718230..c14434c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,6 @@ language: node_js sudo: false node_js: - "8.9" - - "6.2" env: - CXX=g++-4.8 addons: diff --git a/Gruntfile.js b/Gruntfile.js index 90eb3d2..4d5aea4 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -71,7 +71,10 @@ module.exports = function(grunt) { 'test/core/*.js', 'test/fixtures/*.js', 'front/src/js/**/*.js' - ] + ], + options: { + esversion: 6 + } }, clean: { tmp: { @@ -103,7 +106,7 @@ module.exports = function(grunt) { options: { reporter: 'spec', }, - src: ['test/api/apiTest.js'] + src: ['test/core/mediaQueriesCheckerTest.js'] } }, env: { diff --git a/lib/offendersHelpers.js b/lib/offendersHelpers.js index 482deaf..f2e9143 100644 --- a/lib/offendersHelpers.js +++ b/lib/offendersHelpers.js @@ -172,23 +172,15 @@ var OffendersHelpers = function() { }; this.cssOffenderPattern = function(offender) { - // Remove any line breaks - offender = offender.replace(/(\r\n|\n|\r)/gm, ''); - - var parts = /^(.*) (?:<([^ \(]*)>|\[inline CSS\]) ?@ ?(\d+):(\d+)$/.exec(offender); - - if (!parts) { - return { - offender: offender - }; - } else { - return { - css: parts[1], - file: parts[2] || null, - line: parseInt(parts[3], 10), - column: parseInt(parts[4], 10) - }; - } + // Used to work with strings + // As of Phantomas v2, offender is now in JSON format. + // Let's just adapt this for now and we'll see later if we remove completely this function + return { + css: offender.value.message, + file: offender.url, + line: offender.value.position.start.line, + column: offender.value.position.start.column + }; }; this.fileWithSizePattern = function(fileWithSize) { diff --git a/lib/runner.js b/lib/runner.js index aae7275..c201302 100644 --- a/lib/runner.js +++ b/lib/runner.js @@ -56,12 +56,6 @@ var Runner = function(params) { generic : scoreCalculator.calculate(data, scoreProfileGeneric) }; - - delete data.toolsResults.phantomas.metrics.javascriptExecutionTree; - delete data.toolsResults.phantomas.offenders.javascriptExecutionTree; - delete data.toolsResults.phantomas.metrics.scrollExecutionTree; - delete data.toolsResults.phantomas.offenders.scrollExecutionTree; - if (data.toolsResults.phantomas.offenders.blockedRequests) { data.blockedRequests = data.toolsResults.phantomas.offenders.blockedRequests; diff --git a/lib/tools/phantomas/phantomasWrapper.js b/lib/tools/phantomas/phantomasWrapper.js index e27e37f..8bd934f 100644 --- a/lib/tools/phantomas/phantomasWrapper.js +++ b/lib/tools/phantomas/phantomasWrapper.js @@ -87,91 +87,55 @@ var PhantomasWrapper = function() { debug('node node_modules/phantomas/bin/phantomas.js --url=' + task.url + optionsString + ' --verbose'); - var phantomasPid; - var isKilled = false; - - // Kill phantomas if nothing happens - var killer = setTimeout(function() { - console.log('Killing phantomas because the test on ' + task.url + ' was launched ' + 5*options.timeout + ' seconds ago'); - - if (phantomasPid) { - ps.kill(phantomasPid, function(err) { - - if (err) { - debug('Could not kill Phantomas process %s', phantomasPid); - - // Suicide - process.exit(1); - // If in server mode, forever will restart the server - } - - debug('Phantomas process %s was correctly killed', phantomasPid); - - // Then mark the test as failed - // Error 1003 = Phantomas not answering - deferred.reject(1003); - isKilled = true; - }); - } else { - // Suicide - process.exit(1); - } - - }, 5*options.timeout*1000); - - // It's time to launch the test!!! - var triesNumber = 2; - var currentTry = 0; + + const promise = phantomas(task.url, { + 'analyze-css': true + }); - async.retry(triesNumber, function(cb) { + // handle the promise + promise. + then(results => { + var json = { + generator: results.getGenerator(), + url: results.getUrl(), + metrics: results.getMetrics(), + offenders: results.getAllOffenders() + }; - currentTry ++; - - var process = phantomas(task.url, options, function(err, json, results) { - var errorCode = err ? parseInt(err.message, 10) : null; - - if (isKilled) { - debug('Process was killed, too late Phantomas, sorry...'); - return; - } - - - debug('Returning from Phantomas with error %s', errorCode); - - // Adding some YellowLabTools errors here - if (json && json.metrics && (!json.metrics.javascriptExecutionTree || !json.offenders.javascriptExecutionTree)) { - errorCode = 1001; - } - - if (!errorCode && (!json || !json.metrics)) { - errorCode = 1002; - } - - // Don't cancel test if it is a timeout and we've got some results - if (errorCode === 252 && json) { - debug('Timeout after ' + options.timeout + ' seconds. But it\'s not a problem, the test is valid.'); - errorCode = null; - } - - if (errorCode) { - debug('Attempt failed. Error code ' + errorCode); - } - - cb(errorCode, json); - - }).fail(function() { - // This function is useless, but the failing promise needs to be handled, - // otherwise the module meow writes in the console in case of a timeout (error code 252). - debug('Failing promise handled'); + deferred.resolve(json); + }). + catch(res => { + console.error(res); + deferred.reject('Phantomas failed: ' + res.message); }); - - phantomasPid = process.pid; + + /*var process = phantomas(task.url, options, function(err, json, results) { + var errorCode = err ? parseInt(err.message, 10) : null; + + debug('Returning from Phantomas with error %s', errorCode); + + // Adding some YellowLabTools errors here + if (json && json.metrics && (!json.metrics.javascriptExecutionTree || !json.offenders.javascriptExecutionTree)) { + errorCode = 1001; + } + + if (!errorCode && (!json || !json.metrics)) { + errorCode = 1002; + } + + // Don't cancel test if it is a timeout and we've got some results + if (errorCode === 252 && json) { + debug('Timeout after ' + options.timeout + ' seconds. But it\'s not a problem, the test is valid.'); + errorCode = null; + } + + if (errorCode) { + debug('Attempt failed. Error code ' + errorCode); + } }, function(err, json) { - clearTimeout(killer); - if (err) { debug('All ' + triesNumber + ' attemps failed for the test'); deferred.reject(err); @@ -182,6 +146,7 @@ var PhantomasWrapper = function() { } }); + */ return deferred.promise; }; diff --git a/lib/tools/redownload/contentTypeChecker.js b/lib/tools/redownload/contentTypeChecker.js index 49d242b..a55a536 100644 --- a/lib/tools/redownload/contentTypeChecker.js +++ b/lib/tools/redownload/contentTypeChecker.js @@ -4,6 +4,7 @@ var isJpg = require('is-jpg'); var isPng = require('is-png'); var isSvg = require('is-svg'); var isGif = require('is-gif'); +var isWebp = require('is-webp'); var isWoff = require('is-woff'); var isWoff2 = require('is-woff2'); var isOtf = require('is-otf'); @@ -17,6 +18,39 @@ var ContentTypeChecker = function() { debug('Entering contentTypeChecker'); + // Setting isSomething values: + switch(entry.type) { + case 'html': + entry.isHTML = true; + break; + case 'xml': + entry.isXML = true; + break; + case 'css': + entry.isCSS = true; + break; + case 'js': + entry.isJS = true; + break; + case 'json': + entry.isJSON = true; + break; + case 'image': + entry.isImage = true; + break; + case 'webfont': + entry.isWebFont = true; + break; + case 'video': + entry.isVideo = true; + break; + case 'favicon': + entry.isFavicon = true; + break; + } + + // Now let's check for mistakes by analysing body content. It happens more often then we think! + // Ignore very small files as they are generally tracking pixels if (entry.weightCheck && entry.weightCheck.bodyBuffer && entry.weightCheck.bodySize > 100) { var foundType; @@ -24,6 +58,9 @@ var ContentTypeChecker = function() { try { foundType = findContentType(entry.weightCheck.bodyBuffer); + // Note: as of Phantomas v2, entry.contentType is always undefined + // It could change, so let's keep the following code in place: + if (!entry.contentType || entry.contentType === '') { if (foundType === null) { debug('ContentType is empty for file %s', entry.url); @@ -71,6 +108,10 @@ var ContentTypeChecker = function() { return contentTypes.gif; } + if (isWebp(bodyBuffer)) { + return contentTypes.webp; + } + if (isWoff(bodyBuffer)) { return contentTypes.woff; } @@ -142,6 +183,13 @@ var ContentTypeChecker = function() { entry.isImage = true; } }, + webp: { + mimes: ['image/webp'], + updateFn: function(entry) { + entry.type = 'image'; + entry.isImage = true; + } + }, woff: { mimes: ['application/x-font-woff', 'application/font-woff', 'font/woff'], updateFn: function(entry) { diff --git a/lib/tools/redownload/redownload.js b/lib/tools/redownload/redownload.js index 9c5b04e..2b49753 100644 --- a/lib/tools/redownload/redownload.js +++ b/lib/tools/redownload/redownload.js @@ -34,9 +34,13 @@ var Redownload = function() { debug('Redownload started'); var deferred = Q.defer(); - var requestsList = JSON.parse(data.toolsResults.phantomas.offenders.requestsList); - delete data.toolsResults.phantomas.metrics.requestsList; - delete data.toolsResults.phantomas.offenders.requestsList; + var requestsOffenders = data.toolsResults.phantomas.offenders.requests; + var gzipOffenders = data.toolsResults.phantomas.offenders.gzipRequests; + var postOffenders = data.toolsResults.phantomas.offenders.postRequests; + var notFoundOffenders = data.toolsResults.phantomas.offenders.notFound; + var redirectOffenders = data.toolsResults.phantomas.offenders.redirects; + + var requestsList = mergeOffenders(requestsOffenders, gzipOffenders, postOffenders, notFoundOffenders, redirectOffenders); var httpAuth = null; if (data.params && data.params.options && data.params.options.authUser && data.params.options.authPass) { @@ -194,6 +198,57 @@ var Redownload = function() { return deferred.promise; } + function mergeOffenders(requests, compressedOffenders, postOffenders, notFoundOffenders, redirectOffenders) { + + // Parse each request and check if it can be found in other offenders + requests.forEach(function(request) { + + // Is it compressed? + if (compressedOffenders) { + compressedOffenders.some(function(entry) { + if (entry.url === request.url) { + request.compressed = true; + request.bodySize = entry.bodySize; + request.transferedSize = entry.transferedSize; + return true; + } + }); + } + + // Is it a POST request? + if (postOffenders) { + postOffenders.some(function(url) { + if (url === request.url) { + request.post = true; + return true; + } + }); + } + + // Is it a 404? + if (notFoundOffenders) { + notFoundOffenders.some(function(url) { + if (url === request.url) { + request.notFound = true; + return true; + } + }); + } + + // Is it a redirection? + if (redirectOffenders) { + redirectOffenders.some(function(message) { + if (message.split(' ')[0] === request.url) { + request.redirect = true; + return true; + } + }); + } + }); + + return requests; + } + function listIncorrectContentTypes(requests) { var results = []; @@ -639,13 +694,15 @@ var Redownload = function() { deferred.resolve(entry); } - if (entry.method !== 'GET') { + if (entry.post) { notDownloadableFile('only downloading GET'); + // ... at least trying to return deferred.promise; } - if (entry.status !== 200) { + if (entry.notFound || entry.redirect) { unwantedFile('only downloading requests with status code 200'); + // ...at least trying to return deferred.promise; } @@ -654,12 +711,12 @@ var Redownload = function() { return deferred.promise; } - debug('Downloading %s', entry.url); - // Always add a gzip header before sending, in case the server listens to it - var reqHeaders = entry.requestHeaders; - reqHeaders['Accept-Encoding'] = 'gzip, deflate'; + // Always add gzip and webp headers before sending, in case the server listens to them + var reqHeaders = []; + reqHeaders['Accept'] = '*/*,image/webp'; + reqHeaders['Accept-Encoding'] = 'gzip, deflate, br'; reqHeaders['Connection'] = 'keep-alive'; var requestOptions = { diff --git a/package.json b/package.json index d168c9d..b93711d 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "yellowlabtools": "./bin/cli.js" }, "engines": { - "node": ">= 6.0" + "node": ">= 8.0" }, "main": "./lib/index.js", "dependencies": { @@ -54,6 +54,7 @@ "is-png": "1.1.0", "is-svg": "3.0.0", "is-ttf": "0.2.2", + "is-webp": "1.0.1", "is-woff": "1.0.3", "is-woff2": "1.0.0", "jimp": "0.6.0", @@ -61,7 +62,7 @@ "meow": "5.0.0", "minimize": "2.2.0", "parse-color": "1.0.0", - "phantomas": "1.19.0", + "phantomas": "git://github.com/macbre/phantomas.git#phantomas-v2", "ps-node": "0.1.6", "q": "1.5.1", "request": "2.88.0", diff --git a/test/api/apiTest.js b/test/api/apiTest.js index 7d9d6d5..88daaf8 100644 --- a/test/api/apiTest.js +++ b/test/api/apiTest.js @@ -171,9 +171,6 @@ describe('api', function() { body.should.have.a.property('rules').that.is.an('object'); body.should.have.a.property('toolsResults').that.is.an('object'); - body.should.have.a.property('javascriptExecutionTree').that.is.an('object'); - body.javascriptExecutionTree.should.not.deep.equal({}); - // Check if settings are correctly sent and retrieved body.params.options.should.have.a.property('device').that.equals('tablet'); //body.params.options.should.have.a.property('waitForSelector').that.equals('*'); @@ -410,10 +407,6 @@ describe('api', function() { body.should.have.a.property('toolsResults').that.is.an('object'); body.toolsResults.should.have.a.property('phantomas').that.is.an('object'); - body.should.have.a.property('javascriptExecutionTree').that.is.an('object'); - body.javascriptExecutionTree.should.have.a.property('data').that.is.an('object'); - body.javascriptExecutionTree.data.should.have.a.property('type').that.equals('main'); - done(); } else { @@ -507,28 +500,6 @@ describe('api', function() { }); - it('should return the javascript execution tree', function(done) { - this.timeout(5000); - - request({ - method: 'GET', - url: serverUrl + '/api/results/' + asyncRunId + '/javascriptExecutionTree', - json: true, - }, function(error, response, body) { - if (!error && response.statusCode === 200) { - - body.should.have.a.property('data').that.is.an('object'); - body.data.should.have.a.property('type').that.equals('main'); - - done(); - - } else { - done(error || response.statusCode); - } - }); - }); - - it('should return the phantomas results', function(done) { this.timeout(5000); @@ -565,7 +536,6 @@ describe('api', function() { body.should.have.a.property('params').that.is.an('object'); body.should.have.a.property('scoreProfiles').that.is.an('object'); body.should.have.a.property('rules').that.is.an('object'); - body.should.have.a.property('javascriptExecutionTree').that.is.an('object'); body.should.not.have.a.property('toolsResults').that.is.an('object'); @@ -591,7 +561,6 @@ describe('api', function() { body.should.have.a.property('runId').that.equals(asyncRunId); body.should.have.a.property('scoreProfiles').that.is.an('object'); body.should.have.a.property('rules').that.is.an('object'); - body.should.have.a.property('javascriptExecutionTree').that.is.an('object'); body.should.not.have.a.property('params').that.is.an('object'); body.should.not.have.a.property('toolsResults').that.is.an('object'); @@ -617,7 +586,6 @@ describe('api', function() { body.should.have.a.property('runId').that.equals(asyncRunId); body.should.have.a.property('scoreProfiles').that.is.an('object'); body.should.have.a.property('rules').that.is.an('object'); - body.should.have.a.property('javascriptExecutionTree').that.is.an('object'); body.should.have.a.property('params').that.is.an('object'); body.should.have.a.property('toolsResults').that.is.an('object'); @@ -642,7 +610,6 @@ describe('api', function() { body.should.have.a.property('runId').that.equals(asyncRunId); body.should.have.a.property('scoreProfiles').that.is.an('object'); body.should.have.a.property('rules').that.is.an('object'); - body.should.have.a.property('javascriptExecutionTree').that.is.an('object'); body.should.have.a.property('params').that.is.an('object'); body.should.have.a.property('toolsResults').that.is.an('object'); diff --git a/test/core/indexTest.js b/test/core/indexTest.js index 71874d9..68f5196 100644 --- a/test/core/indexTest.js +++ b/test/core/indexTest.js @@ -87,17 +87,6 @@ describe('index.js', function() { } }); - // Test javascriptExecutionTree - data.toolsResults.phantomas.metrics.should.not.have.a.property('javascriptExecutionTree'); - data.toolsResults.phantomas.offenders.should.not.have.a.property('javascriptExecutionTree'); - data.should.have.a.property('javascriptExecutionTree').that.is.an('object'); - data.javascriptExecutionTree.should.have.a.property('data'); - data.javascriptExecutionTree.data.should.have.a.property('type').that.equals('main'); - data.javascriptExecutionTree.data.should.have.a.property('domInteractive').that.is.a('number'); - data.javascriptExecutionTree.data.should.have.a.property('domContentLoaded').that.is.a('number'); - data.javascriptExecutionTree.data.should.have.a.property('domContentLoadedEnd').that.is.a('number'); - data.javascriptExecutionTree.data.should.have.a.property('domComplete').that.is.a('number'); - /*jshint expr: true*/ console.log.should.not.have.been.called; diff --git a/test/core/mediaQueriesCheckerTest.js b/test/core/mediaQueriesCheckerTest.js index 7b3222b..2265921 100644 --- a/test/core/mediaQueriesCheckerTest.js +++ b/test/core/mediaQueriesCheckerTest.js @@ -2,54 +2,74 @@ var should = require('chai').should(); var mediaQueriesChecker = require('../../lib/tools/mediaQueriesChecker'); describe('mediaQueriesChecker', function() { + + function wrap(message) { + return { + url: 'http://domain.com/css/stylesheet.css', + value: { + message: message, + position: { + start: { + line: 269, + column: 1 + }, + end: { + line: 269, + column: 182 + } + } + } + }; + } it('should parse mediaQueryes correctly', function() { - mediaQueriesChecker.parseOneMediaQuery('@media screen and (max-width: 1024px) (1 rules) @ 269:1').should.deep.equal({ - mediaQuery: { - query: 'screen and (max-width: 1024px)', - rules: 1, - file: 'http://domain.com/css/stylesheet.css', - line: 269, - column: 1 - }, - isForMobile: true, - breakpoints: [{string: '1024px', pixels: 1024}] - }); + mediaQueriesChecker.parseOneMediaQuery(wrap('@media screen and (max-width: 1024px) (1 rules)')) + .should.deep.equal({ + mediaQuery: { + query: 'screen and (max-width: 1024px)', + rules: 1, + file: 'http://domain.com/css/stylesheet.css', + line: 269, + column: 1 + }, + isForMobile: true, + breakpoints: [{string: '1024px', pixels: 1024}] + }); }); it('should determine if it\'s for mobile correctly', function() { - mediaQueriesChecker.parseOneMediaQuery('@media screen and (max-width: 1024px) (1 rules) @ 1:1').isForMobile.should.equal(true); - mediaQueriesChecker.parseOneMediaQuery('@media (max-width:1024px) (1 rules) @ 1:1').isForMobile.should.equal(true); - mediaQueriesChecker.parseOneMediaQuery('@media screen and (max-width: 320px) (1 rules) @ 1:1').isForMobile.should.equal(true); - mediaQueriesChecker.parseOneMediaQuery('@media screen and (max-width: 290px) (1 rules) @ 1:1').isForMobile.should.equal(false); - mediaQueriesChecker.parseOneMediaQuery('@media screen and (min-width: 320px) (1 rules) @ 1:1').isForMobile.should.equal(false); - mediaQueriesChecker.parseOneMediaQuery('@media screen and (min-width: 600px) (1 rules) @ 1:1').isForMobile.should.equal(false); - mediaQueriesChecker.parseOneMediaQuery('@media screen and (max-width: 20em) (1 rules) @ 1:1').isForMobile.should.equal(true); - mediaQueriesChecker.parseOneMediaQuery('@media screen and (min-width: 40em) (1 rules) @ 1:1').isForMobile.should.equal(false); - mediaQueriesChecker.parseOneMediaQuery('@media (min-width: 600px) and (max-width: 1000px) (1 rules) @ 1:1').isForMobile.should.equal(false); - mediaQueriesChecker.parseOneMediaQuery('@media (min-width: 180px) and (max-width: 400px) (1 rules) @ 1:1').isForMobile.should.equal(true); - mediaQueriesChecker.parseOneMediaQuery('@media (min-width: 180px) and (max-width: 290px) (1 rules) @ 1:1').isForMobile.should.equal(false); - mediaQueriesChecker.parseOneMediaQuery('@media not all and (min-width: 600px) (1 rules) @ 1:1').isForMobile.should.equal(true); - mediaQueriesChecker.parseOneMediaQuery('@media not all and (min-width: 180px) (1 rules) @ 1:1').isForMobile.should.equal(false); - mediaQueriesChecker.parseOneMediaQuery('@media not all and (min-width: 1000px) and (max-width: 600px) (1 rules) @ 1:1').isForMobile.should.equal(false); - mediaQueriesChecker.parseOneMediaQuery('@media not all and (min-width: 400px) and (max-width: 180px) (1 rules) @ 1:1').isForMobile.should.equal(true); + mediaQueriesChecker.parseOneMediaQuery(wrap('@media screen and (max-width: 1024px) (1 rules)')).isForMobile.should.equal(true); + mediaQueriesChecker.parseOneMediaQuery(wrap('@media (max-width:1024px) (1 rules)')).isForMobile.should.equal(true); + mediaQueriesChecker.parseOneMediaQuery(wrap('@media screen and (max-width: 320px) (1 rules)')).isForMobile.should.equal(true); + mediaQueriesChecker.parseOneMediaQuery(wrap('@media screen and (max-width: 290px) (1 rules)')).isForMobile.should.equal(false); + mediaQueriesChecker.parseOneMediaQuery(wrap('@media screen and (min-width: 320px) (1 rules)')).isForMobile.should.equal(false); + mediaQueriesChecker.parseOneMediaQuery(wrap('@media screen and (min-width: 600px) (1 rules)')).isForMobile.should.equal(false); + mediaQueriesChecker.parseOneMediaQuery(wrap('@media screen and (max-width: 20em) (1 rules)')).isForMobile.should.equal(true); + mediaQueriesChecker.parseOneMediaQuery(wrap('@media screen and (min-width: 40em) (1 rules)')).isForMobile.should.equal(false); + mediaQueriesChecker.parseOneMediaQuery(wrap('@media (min-width: 600px) and (max-width: 1000px) (1 rules)')).isForMobile.should.equal(false); + mediaQueriesChecker.parseOneMediaQuery(wrap('@media (min-width: 180px) and (max-width: 400px) (1 rules)')).isForMobile.should.equal(true); + mediaQueriesChecker.parseOneMediaQuery(wrap('@media (min-width: 180px) and (max-width: 290px) (1 rules)')).isForMobile.should.equal(false); + mediaQueriesChecker.parseOneMediaQuery(wrap('@media not all and (min-width: 600px) (1 rules)')).isForMobile.should.equal(true); + mediaQueriesChecker.parseOneMediaQuery(wrap('@media not all and (min-width: 180px) (1 rules)')).isForMobile.should.equal(false); + mediaQueriesChecker.parseOneMediaQuery(wrap('@media not all and (min-width: 1000px) and (max-width: 600px) (1 rules)')).isForMobile.should.equal(false); + mediaQueriesChecker.parseOneMediaQuery(wrap('@media not all and (min-width: 400px) and (max-width: 180px) (1 rules)')).isForMobile.should.equal(true); }); it('should count breakpoints correctly', function() { - mediaQueriesChecker.parseOneMediaQuery('@media screen and (max-width: 1024px) (1 rules) @ 1:1').breakpoints.should.deep.equal([{string: '1024px', pixels: 1024}]); - mediaQueriesChecker.parseOneMediaQuery('@media (max-width:1024px) (1 rules) @ 1:1').breakpoints.should.deep.equal([{string: '1024px', pixels: 1024}]); - mediaQueriesChecker.parseOneMediaQuery('@media screen and (max-width: 320px) (1 rules) @ 1:1').breakpoints.should.deep.equal([{string: '320px', pixels: 320}]); - mediaQueriesChecker.parseOneMediaQuery('@media (min-width: 600px) and (max-width: 1000px) (1 rules) @ 1:1').breakpoints.should.deep.equal([{string: '600px', pixels: 600}, {string: '1000px', pixels: 1000}]); - mediaQueriesChecker.parseOneMediaQuery('@media not all and (min-width: 180px) (1 rules) @ 1:1').breakpoints.should.deep.equal([{string: '180px', pixels: 180}]); - mediaQueriesChecker.parseOneMediaQuery('@media not all and (min-width: 1000px) and (max-width: 600px) (1 rules) @ 1:1').breakpoints.should.deep.equal([{string: '1000px', pixels: 1000}, {string: '600px', pixels: 600}]); - mediaQueriesChecker.parseOneMediaQuery('@media (max-height:500px) (1 rules) @ 1:1').breakpoints.should.deep.equal([]); - mediaQueriesChecker.parseOneMediaQuery('@media screen and (max-width: 100em) (1 rules) @ 1:1').breakpoints.should.deep.equal([{string: '100em', pixels: 1600}]); - mediaQueriesChecker.parseOneMediaQuery('@media screen and (max-width: 120pt) (1 rules) @ 1:1').breakpoints.should.deep.equal([{string: '120pt', pixels: 160}]); - mediaQueriesChecker.parseOneMediaQuery('@media screen and (max-width: 40.2em) (1 rules) @ 1:1').breakpoints.should.deep.equal([{string: '40.2em', pixels: 643.2}]); + mediaQueriesChecker.parseOneMediaQuery(wrap('@media screen and (max-width: 1024px) (1 rules)')).breakpoints.should.deep.equal([{string: '1024px', pixels: 1024}]); + mediaQueriesChecker.parseOneMediaQuery(wrap('@media (max-width:1024px) (1 rules)')).breakpoints.should.deep.equal([{string: '1024px', pixels: 1024}]); + mediaQueriesChecker.parseOneMediaQuery(wrap('@media screen and (max-width: 320px) (1 rules)')).breakpoints.should.deep.equal([{string: '320px', pixels: 320}]); + mediaQueriesChecker.parseOneMediaQuery(wrap('@media (min-width: 600px) and (max-width: 1000px) (1 rules)')).breakpoints.should.deep.equal([{string: '600px', pixels: 600}, {string: '1000px', pixels: 1000}]); + mediaQueriesChecker.parseOneMediaQuery(wrap('@media not all and (min-width: 180px) (1 rules)')).breakpoints.should.deep.equal([{string: '180px', pixels: 180}]); + mediaQueriesChecker.parseOneMediaQuery(wrap('@media not all and (min-width: 1000px) and (max-width: 600px) (1 rules)')).breakpoints.should.deep.equal([{string: '1000px', pixels: 1000}, {string: '600px', pixels: 600}]); + mediaQueriesChecker.parseOneMediaQuery(wrap('@media (max-height:500px) (1 rules)')).breakpoints.should.deep.equal([]); + mediaQueriesChecker.parseOneMediaQuery(wrap('@media screen and (max-width: 100em) (1 rules)')).breakpoints.should.deep.equal([{string: '100em', pixels: 1600}]); + mediaQueriesChecker.parseOneMediaQuery(wrap('@media screen and (max-width: 120pt) (1 rules)')).breakpoints.should.deep.equal([{string: '120pt', pixels: 160}]); + mediaQueriesChecker.parseOneMediaQuery(wrap('@media screen and (max-width: 40.2em) (1 rules)')).breakpoints.should.deep.equal([{string: '40.2em', pixels: 643.2}]); }); it('should fail silently', function() { - mediaQueriesChecker.parseOneMediaQuery('@media bad syntax (1 rules) @ 1:1').isForMobile.should.equal(false); + mediaQueriesChecker.parseOneMediaQuery(wrap('@media bad syntax (1 rules)')).isForMobile.should.equal(false); }); }); diff --git a/test/core/offendersHelpersTest.js b/test/core/offendersHelpersTest.js index e054840..a01d67c 100644 --- a/test/core/offendersHelpersTest.js +++ b/test/core/offendersHelpersTest.js @@ -307,52 +307,6 @@ describe('offendersHelpers', function() { }); - - describe('cssOffenderPattern', function() { - - it('should transform a css offender into an object', function() { - var result = offendersHelpers.cssOffenderPattern('.pagination .plus ul li @ 30:31862'); - - result.should.deep.equal({ - css: '.pagination .plus ul li', - file: 'http://www.pouet.com/css/main.css', - line: 30, - column: 31862 - }); - }); - - it('should work with an inline css', function() { - var result = offendersHelpers.cssOffenderPattern('.pagination .plus ul li [inline CSS] @ 1:32'); - - result.should.deep.equal({ - css: '.pagination .plus ul li', - file: null, - line: 1, - column: 32 - }); - }); - - it('should handle the case where line and char are not here', function() { - var result = offendersHelpers.cssOffenderPattern('.pagination .plus ul li'); - - result.should.deep.equal({ - offender: '.pagination .plus ul li' - }); - }); - - it('should handle line breaks inside the string', function() { - var result = offendersHelpers.cssOffenderPattern('.card-mask-wrap { -moz-transform: translate3d(0, \n-288px\n, 0) } // was required by firefox 15 and earlier [inline CSS] @ 29:3'); - - result.should.deep.equal({ - css: '.card-mask-wrap { -moz-transform: translate3d(0, -288px, 0) } // was required by firefox 15 and earlier', - file: null, - line: 29, - column: 3 - }); - }); - - }); - describe('fileWithSizePattern', function() { it('should return an object', function() { diff --git a/test/core/phantomasWrapperTest.js b/test/core/phantomasWrapperTest.js index 1be8a88..3be60df 100644 --- a/test/core/phantomasWrapperTest.js +++ b/test/core/phantomasWrapperTest.js @@ -26,7 +26,6 @@ describe('phantomasWrapper', function() { data.should.have.a.property('url').that.equals(url); data.should.have.a.property('metrics').that.is.an('object').not.empty; data.should.have.a.property('offenders').that.is.an('object').not.empty; - data.offenders.should.have.a.property('javascriptExecutionTree').that.is.a('array').not.empty; done(); }).fail(function(err) { @@ -34,7 +33,7 @@ describe('phantomasWrapper', function() { }); }); - it('should fail with error 254', function(done) { + it('should fail when page cannot be fetched', function(done) { var url = 'http://localhost:8389/not-existing.html'; this.timeout(15000); @@ -52,8 +51,8 @@ describe('phantomasWrapper', function() { }).fail(function(err) { try { + console.log(err); should.exist(err); - err.should.equal(254); done(); } catch(error) { diff --git a/test/core/redownloadTest.js b/test/core/redownloadTest.js index a3c048a..9c200be 100644 --- a/test/core/redownloadTest.js +++ b/test/core/redownloadTest.js @@ -10,101 +10,42 @@ describe('redownload', function() { var requestsList = [ { - method: 'GET', url: 'http://localhost:8388/simple-page.html', - requestHeaders: { - 'User-Agent': 'something', - Referer: 'http://www.google.fr/', - Accept: '*/*' - }, - status: 200, - isHTML: true, - type: 'html' + type: 'html', + size: 30000 }, { - method: 'GET', url: 'http://localhost:8388/jquery1.8.3.js', - requestHeaders: { - 'User-Agent': 'something', - Referer: 'http://www.google.fr/', - Accept: '*/*' - }, - status: 200, - isJS: true, - type: 'js' + type: 'js', + size: 30000 }, { - method: 'GET', url: 'http://localhost:8388/jpeg-image.jpg', - requestHeaders: { - 'User-Agent': 'something', - Referer: 'http://www.google.fr/', - Accept: '*/*' - }, - status: 200, - isImage: true, type: 'image', - contentType: 'image/jpeg' + size: 30000 }, { - method: 'GET', url: 'http://localhost:8388/svg-image.svg', - requestHeaders: { - 'User-Agent': 'something', - Referer: 'http://www.google.fr/', - Accept: '*/*' - }, - status: 200, - isImage: true, - isSVG: true, type: 'image', - contentType: 'image/svg+xml' + size: 30000 }, { - method: 'GET', url: 'http://localhost:8388/unminified-script.js', - requestHeaders: { - 'User-Agent': 'something', - Referer: 'http://www.google.fr/', - Accept: '*/*' - }, - status: 200, - isJS: true, - type: 'js' + type: 'js', + size: 30000 }, { - method: 'GET', url: 'http://localhost:8388/unminified-stylesheet.css', - requestHeaders: { - 'User-Agent': 'something', - Referer: 'http://www.google.fr/', - Accept: '*/*' - }, - status: 200, - isCSS: true, - type: 'css' + type: 'css', + size: 30000 }, { - method: 'GET', url: 'http://localhost:8388/xml.xml', - requestHeaders: { - 'User-Agent': 'something', - Referer: 'http://www.google.fr/', - Accept: '*/*' - }, - status: 200, - isXML: true, - type: 'xml' + type: 'xml', + size: 30000 }, { - method: 'GET', - url: 'about:blank', - requestHeaders: { - 'User-Agent': 'something', - Referer: 'http://www.google.fr/', - Accept: '*/*' - }, - status: 200 + url: 'about:blank' } ]; @@ -117,10 +58,10 @@ describe('redownload', function() { toolsResults: { phantomas: { metrics: { - requestsList: true + requests: 8 }, offenders: { - requestsList: JSON.stringify(requestsList) + requests: requestsList } } }