Work in progress: switch to Phantomas v2

This commit is contained in:
Gaël Métais
2019-03-14 03:27:37 +01:00
parent 5e82eea9f1
commit 517206364a
14 changed files with 248 additions and 319 deletions
-1
View File
@@ -2,7 +2,6 @@ language: node_js
sudo: false
node_js:
- "8.9"
- "6.2"
env:
- CXX=g++-4.8
addons:
+5 -2
View File
@@ -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
View File
@@ -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) {
-6
View File
@@ -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;
+43 -78
View File
@@ -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;
};
@@ -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
View File
@@ -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
View File
@@ -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",
-33
View File
@@ -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');
-11
View File
@@ -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
View File
@@ -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);
});
});
-46
View File
@@ -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
View File
@@ -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
View File
@@ -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
}
}
}