瀏覽代碼

Work in progress: switch to Phantomas v2

Gaël Métais 6 年之前
父節點
當前提交
517206364a

+ 0 - 1
.travis.yml

@@ -2,7 +2,6 @@ language: node_js
 sudo: false
 node_js:
   - "8.9"
-  - "6.2"
 env:
   - CXX=g++-4.8
 addons:

+ 5 - 2
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: {

+ 9 - 17
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) {

+ 0 - 6
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;

+ 38 - 73
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;
-
-        async.retry(triesNumber, function(cb) {
-
-            currentTry ++;
+    
+        const promise = phantomas(task.url, {
+            'analyze-css': true
+        });
 
-            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;
-                }
+        // handle the promise
+        promise.
+            then(results => {
+                var json = {
+                    generator: results.getGenerator(),
+                    url: results.getUrl(),
+                    metrics: results.getMetrics(),
+                    offenders: results.getAllOffenders()
+                };
 
+                deferred.resolve(json);
+            }).
+            catch(res => {
+                console.error(res);
+                deferred.reject('Phantomas failed: ' + res.message);
+            });
 
-                debug('Returning from Phantomas with error %s', errorCode);
+        /*var process = phantomas(task.url, options, function(err, json, results) {
+        var errorCode = err ? parseInt(err.message, 10) : null;
 
-                // Adding some YellowLabTools errors here
-                if (json && json.metrics && (!json.metrics.javascriptExecutionTree || !json.offenders.javascriptExecutionTree)) {
-                    errorCode = 1001;
-                }
+        debug('Returning from Phantomas with error %s', errorCode);
 
-                if (!errorCode && (!json || !json.metrics)) {
-                    errorCode = 1002;
-                }
+        // Adding some YellowLabTools errors here
+        if (json && json.metrics && (!json.metrics.javascriptExecutionTree || !json.offenders.javascriptExecutionTree)) {
+            errorCode = 1001;
+        }
 
-                // 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 && (!json || !json.metrics)) {
+            errorCode = 1002;
+        }
 
-                if (errorCode) {
-                    debug('Attempt failed. Error code ' + errorCode);
-                }
+        // 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;
+        }
 
-                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');
-            });
-            
-            phantomasPid = process.pid;
+        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;
     };

+ 48 - 0
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) {

+ 66 - 9
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 = {

+ 3 - 2
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",

+ 0 - 33
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');
 

+ 0 - 11
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;
 

+ 57 - 37
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) <http://domain.com/css/stylesheet.css> @ 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) <file> @ 1:1').isForMobile.should.equal(true);
-        mediaQueriesChecker.parseOneMediaQuery('@media (max-width:1024px) (1 rules) <file> @ 1:1').isForMobile.should.equal(true);
-        mediaQueriesChecker.parseOneMediaQuery('@media screen and (max-width: 320px) (1 rules) <file> @ 1:1').isForMobile.should.equal(true);
-        mediaQueriesChecker.parseOneMediaQuery('@media screen and (max-width: 290px) (1 rules) <file> @ 1:1').isForMobile.should.equal(false);
-        mediaQueriesChecker.parseOneMediaQuery('@media screen and (min-width: 320px) (1 rules) <file> @ 1:1').isForMobile.should.equal(false);
-        mediaQueriesChecker.parseOneMediaQuery('@media screen and (min-width: 600px) (1 rules) <file> @ 1:1').isForMobile.should.equal(false);
-        mediaQueriesChecker.parseOneMediaQuery('@media screen and (max-width: 20em) (1 rules) <file> @ 1:1').isForMobile.should.equal(true);
-        mediaQueriesChecker.parseOneMediaQuery('@media screen and (min-width: 40em) (1 rules) <file> @ 1:1').isForMobile.should.equal(false);
-        mediaQueriesChecker.parseOneMediaQuery('@media (min-width: 600px) and (max-width: 1000px) (1 rules) <file> @ 1:1').isForMobile.should.equal(false);
-        mediaQueriesChecker.parseOneMediaQuery('@media (min-width: 180px) and (max-width: 400px) (1 rules) <file> @ 1:1').isForMobile.should.equal(true);
-        mediaQueriesChecker.parseOneMediaQuery('@media (min-width: 180px) and (max-width: 290px) (1 rules) <file> @ 1:1').isForMobile.should.equal(false);
-        mediaQueriesChecker.parseOneMediaQuery('@media not all and (min-width: 600px) (1 rules) <file> @ 1:1').isForMobile.should.equal(true);
-        mediaQueriesChecker.parseOneMediaQuery('@media not all and (min-width: 180px) (1 rules) <file> @ 1:1').isForMobile.should.equal(false);
-        mediaQueriesChecker.parseOneMediaQuery('@media not all and (min-width: 1000px) and (max-width: 600px) (1 rules) <file> @ 1:1').isForMobile.should.equal(false);
-        mediaQueriesChecker.parseOneMediaQuery('@media not all and (min-width: 400px) and (max-width: 180px) (1 rules) <file> @ 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) <file> @ 1:1').breakpoints.should.deep.equal([{string: '1024px', pixels: 1024}]);
-        mediaQueriesChecker.parseOneMediaQuery('@media (max-width:1024px) (1 rules) <file> @ 1:1').breakpoints.should.deep.equal([{string: '1024px', pixels: 1024}]);
-        mediaQueriesChecker.parseOneMediaQuery('@media screen and (max-width: 320px) (1 rules) <file> @ 1:1').breakpoints.should.deep.equal([{string: '320px', pixels: 320}]);
-        mediaQueriesChecker.parseOneMediaQuery('@media (min-width: 600px) and (max-width: 1000px) (1 rules) <file> @ 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) <file> @ 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) <file> @ 1:1').breakpoints.should.deep.equal([{string: '1000px', pixels: 1000}, {string: '600px', pixels: 600}]);
-        mediaQueriesChecker.parseOneMediaQuery('@media (max-height:500px) (1 rules) <file> @ 1:1').breakpoints.should.deep.equal([]);
-        mediaQueriesChecker.parseOneMediaQuery('@media screen and (max-width: 100em) (1 rules) <file> @ 1:1').breakpoints.should.deep.equal([{string: '100em', pixels: 1600}]);
-        mediaQueriesChecker.parseOneMediaQuery('@media screen and (max-width: 120pt) (1 rules) <file> @ 1:1').breakpoints.should.deep.equal([{string: '120pt', pixels: 160}]);
-        mediaQueriesChecker.parseOneMediaQuery('@media screen and (max-width: 40.2em) (1 rules) <file> @ 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) <file> @ 1:1').isForMobile.should.equal(false); 
+        mediaQueriesChecker.parseOneMediaQuery(wrap('@media bad syntax (1 rules)')).isForMobile.should.equal(false); 
     });
 
 });

+ 0 - 46
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 <http://www.pouet.com/css/main.css> @ 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() {

+ 2 - 3
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) {

+ 15 - 74
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
                     }
                 }
             }