diff --git a/lib/metadata/policies.json b/lib/metadata/policies.js similarity index 90% rename from lib/metadata/policies.json rename to lib/metadata/policies.js index 34bfe28..eedebe6 100644 --- a/lib/metadata/policies.json +++ b/lib/metadata/policies.js @@ -1,4 +1,6 @@ -{ +var debug = require('debug')('ylt:policies'); + +var policies = { "DOMelementsCount": { "tool": "phantomas", "label": "DOM elements count", @@ -103,24 +105,61 @@ "isBadThreshold": 50, "isAbnormalThreshold": 200 }, - "inBodyDomManipulations": { - "tool": "ylt", - "label": "DOM manipulations in body", - "message": "
This metric counts the number of DOM queries, DOM inserts, binds, etc. made by the JavaScript before the DOMContentLoaded event.
Wait for this event before manipulating the DOM. Do not execute JavaScript in the middle of the BODY as it slows down the construction of the DOM and makes a poor maintainability. This is what i call spaghetti code.
The JS Timeline tab can help you identify what's happening.
", - "isOkThreshold": 10, - "isBadThreshold": 50, - "isAbnormalThreshold": 100 - }, "jQueryVersion": { - "tool": "ylt", "label": "jQuery version", "message": "Current latest versions of jQuery are 1.11 (with support for old IE versions) and 2.1 (without).
Each new version of jQuery optimizes performances. Do not keep an old version of jQuery. Updating can sometimes break a few things, but it is generally quite easy to fix them up. So don't hesitate.
", - "isOkThreshold": 1, - "isBadThreshold": 2, - "isAbnormalThreshold": 3 + "scoreFn": function(data) { + var differentVersions = data.toolsResults.phantomas.metrics.jQueryDifferentVersions; + + if (differentVersions === 0 || differentVersions > 1) { + // Not applicable + return null; + } else { + var value = data.toolsResults.phantomas.metrics.jQueryVersion; + var score; + + if (value.indexOf('1.11.') === 0 || + value.indexOf('1.12.') === 0 || + value.indexOf('2.1.') === 0 || + value.indexOf('2.2.') === 0 || + value.indexOf('3.0.') === 0) { + score = 100; + } else if (value.indexOf('1.10.') === 0 || + value.indexOf('2.0.') === 0) { + score = 90; + } else if (value.indexOf('1.9.') === 0) { + score = 70; + } else if (value.indexOf('1.8.') === 0) { + score = 50; + } else if (value.indexOf('1.7.') === 0) { + score = 40; + } else if (value.indexOf('1.6.') === 0) { + score = 30; + } else if (value.indexOf('1.5.') === 0) { + score = 20; + } else if (value.indexOf('1.4.') === 0) { + score = 10; + } else if (value.indexOf('1.3.') === 0) { + score = 0; + } else if (value.indexOf('1.2.') === 0) { + score = 0; + } else { + debug('Unknown jQuery version "%s"', value); + return null; + } + + return { + value: value, + score: score, + bad: value < 100, + abnormal: false, + abnormalityScore: 0 + }; + } + } }, "jQueryDifferentVersions": { - "tool": "ylt", + "tool": "phantomas", "label": "Several versions loaded", "message": "jQuery is a heavy library. You should never load jQuery more than one on the same page.
", "isOkThreshold": 1, @@ -367,4 +406,6 @@ "isBadThreshold": 25, "isAbnormalThreshold": 50 } -} \ No newline at end of file +}; + +module.exports = policies; diff --git a/lib/metadata/scoreProfileGeneric.json b/lib/metadata/scoreProfileGeneric.json index 3b11c0d..2260afb 100644 --- a/lib/metadata/scoreProfileGeneric.json +++ b/lib/metadata/scoreProfileGeneric.json @@ -25,8 +25,7 @@ "evalCalls": 1, "documentWriteCalls": 2, "consoleMessages": 0.5, - "globalVariables": 0.5, - "inBodyDomManipulations": 1 + "globalVariables": 0.5 } }, "jQueryVersion": { diff --git a/lib/rulesChecker.js b/lib/rulesChecker.js index 9033f0e..f6f6d65 100644 --- a/lib/rulesChecker.js +++ b/lib/rulesChecker.js @@ -12,12 +12,14 @@ var RulesChecker = function() { for (var metricName in policies) { var policy = policies[metricName]; + var rule; - if (data.toolsResults[policy.tool] && + if (policy.tool && + data.toolsResults[policy.tool] && data.toolsResults[policy.tool].metrics && (data.toolsResults[policy.tool].metrics[metricName] || data.toolsResults[policy.tool].metrics[metricName] === 0)) { - - var rule = { + + rule = { value: data.toolsResults[policy.tool].metrics[metricName], policy: policy }; @@ -40,7 +42,29 @@ var RulesChecker = function() { rule.abnormalityScore = Math.min(Math.round(abnormalityScore), 0); results[metricName] = rule; + debug('Metric %s calculated. Score: %d', metricName, rule.score); + + } else if (policy.scoreFn) { + + debug('Custom score function for %s', metricName); + + // Custom score function + rule = policy.scoreFn(data); + + // Check returned values (if the result is null, just don't save) + if (rule) { + rule.policy = { + label: policy.label, + message: policy.message + }; + + results[metricName] = rule; + debug('Metric %s calculated. Score: %d', metricName, rule.score); + } else { + debug('Metric %s is null. Ignored.', metricName); + } + } else { debug('Metric %s not found for tool %s', metricName, policy.tool); diff --git a/lib/runner.js b/lib/runner.js index caa81a4..e48a306 100644 --- a/lib/runner.js +++ b/lib/runner.js @@ -21,11 +21,18 @@ var Runner = function(params) { phantomasWrapper.execute(data).then(function(phantomasResults) { data.toolsResults.phantomas = phantomasResults; - // Other tools go there + // Get the JS Execution Tree from offenders and put in the main object + try { + data.javascriptExecutionTree = JSON.parse(data.toolsResults.phantomas.offenders.javascriptExecutionTree[0]); + } catch(e) { + debug('Could not find nor parse phantomas.offenders.javascriptExecutionTree'); + } + + // Other tools go here // Rules checker - var policies = require('./metadata/policies.json'); + var policies = require('./metadata/policies'); data.rules = rulesChecker.check(data, policies); @@ -35,13 +42,6 @@ var Runner = function(params) { generic : scoreCalculator.calculate(data, scoreProfileGeneric) }; - - // Get the JS Execution Tree from offenders and put in the main object - try { - data.javascriptExecutionTree = JSON.parse(data.toolsResults.phantomas.offenders.javascriptExecutionTree[0]); - } catch(e) { - debug('Could not find nor parse phantomas.offenders.javascriptExecutionTree'); - } delete data.toolsResults.phantomas.metrics.javascriptExecutionTree; delete data.toolsResults.phantomas.offenders.javascriptExecutionTree; diff --git a/test/core/customPoliciesTest.js b/test/core/customPoliciesTest.js new file mode 100644 index 0000000..5593f2f --- /dev/null +++ b/test/core/customPoliciesTest.js @@ -0,0 +1,87 @@ +var should = require('chai').should(); +var rulesChecker = require('../../lib/rulesChecker'); + +describe('rulesChecker', function() { + + var policies = require('../../lib/metadata/policies.js'); + + + it('should grade correctly jQuery versions', function() { + + + var versions = { + '1.2.9': 0, + '1.3.9': 0, + '1.4.4': 10, + '1.5.0': 20, + '1.6.3': 30, + '1.7.0': 40, + '1.8.3a': 50, + '1.9.2': 70, + '1.10.1': 90, + '2.0.0-rc1': 90, + '1.11.1': 100, + '2.1.1-beta1': 100, + '3.0.0': 100 + }; + + for (var version in versions) { + results = rulesChecker.check({ + "toolsResults": { + "phantomas": { + "metrics": { + "jQueryVersion": version + } + } + } + }, policies); + results.jQueryVersion.score.should.equal(versions[version]); + } + + + // Unknown jQuery version + results = rulesChecker.check({ + "toolsResults": { + "phantomas": { + "metrics": { + "jQueryVersion": "wooot" + } + } + } + }, policies); + results.should.deep.equals({}); + + + // If jQueryDifferentVersions is 0 + results = rulesChecker.check({ + "toolsResults": { + "phantomas": { + "metrics": { + "jQueryVersion": "1.6.0", + "jQueryDifferentVersions": 0 + } + } + } + }, policies); + results.should.not.have.a.property('jQueryVersion'); + results.should.have.a.property('jQueryDifferentVersions'); + results.jQueryDifferentVersions.should.have.a.property('score').that.equals(100); + + + // If there are more than 1 jQuery version + results = rulesChecker.check({ + "toolsResults": { + "phantomas": { + "metrics": { + "jQueryVersion": "1.6.0", + "jQueryDifferentVersions": 2 + } + } + } + }, policies); + results.should.not.have.a.property('jQueryVersion'); + results.should.have.a.property('jQueryDifferentVersions'); + results.jQueryDifferentVersions.should.have.a.property('score').that.equals(0); + results.jQueryDifferentVersions.should.have.a.property('abnormal').that.equals(true); + }); +});