From df4c93356e1792ab1d4e6665f4de247f8cd24c67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20M=C3=A9tais?= Date: Tue, 5 Aug 2014 00:08:22 +0200 Subject: [PATCH] Back to a clean phantomas version + modules --- app/public/scripts/resultsController.js | 6 +- app/views/results.html | 26 +- package.json | 2 +- phantomas_custom/core/scopeYLT/scopeYLT.js | 176 ++++++++++ .../modules/domComplexYLT/domComplexYLT.js | 154 +++++++++ phantomas_custom/modules/domQYLT/domQYLT.js | 214 ++++++++++++ phantomas_custom/modules/jQYLT/jQYLT.js | 312 ++++++++++++++++++ phantomas_custom/modules/jsErrYLT/jsErrYLT.js | 42 +++ .../modules/jsTreeYLT/jsTreeYLT.js | 31 ++ server.js | 35 +- 10 files changed, 988 insertions(+), 10 deletions(-) create mode 100644 phantomas_custom/core/scopeYLT/scopeYLT.js create mode 100644 phantomas_custom/modules/domComplexYLT/domComplexYLT.js create mode 100644 phantomas_custom/modules/domQYLT/domQYLT.js create mode 100644 phantomas_custom/modules/jQYLT/jQYLT.js create mode 100644 phantomas_custom/modules/jsErrYLT/jsErrYLT.js create mode 100644 phantomas_custom/modules/jsTreeYLT/jsTreeYLT.js diff --git a/app/public/scripts/resultsController.js b/app/public/scripts/resultsController.js index d9d40c8..c94c070 100644 --- a/app/public/scripts/resultsController.js +++ b/app/public/scripts/resultsController.js @@ -7,11 +7,15 @@ app.controller('ResultsCtrl', function ($scope) { $scope.slowRequestsOn = false; $scope.slowRequestsLimit = 5; + if ($scope.phantomasResults.offenders && $scope.phantomasResults.offenders.javascriptExecutionTree) { + $scope.javascript = JSON.parse($scope.phantomasResults.offenders.javascriptExecutionTree); + } + $scope.onNodeDetailsClick = function(node) { var isOpen = node.data.showDetails; if (!isOpen) { // Close all other nodes - $scope.phantomasResults.javascript.children.forEach(function(currentNode) { + $scope.javascript.children.forEach(function(currentNode) { currentNode.data.showDetails = false; }); diff --git a/app/views/results.html b/app/views/results.html index d08607a..497fc5e 100644 --- a/app/views/results.html +++ b/app/views/results.html @@ -18,13 +18,13 @@
Tested url: {{phantomasResults.url}}
-
+

Error: {{phantomasResults.error}}

Phantomas timed out
Phantomas config error
Phantomas failed to load page
Phantomas internal error
-
Javascript execution tree error
+
Javascript execution tree error
@@ -49,12 +49,26 @@
Duration
-
+
{{$index}}
{{node.data.type}}
-
{{node.data.callDetails.arguments[0]}}
+ +
+ {{node.data.callDetails.arguments[0]}} + : {{node.data.callDetails.arguments[1]}} + : {{node.data.callDetails.arguments[2]}} + : {{node.data.callDetails.arguments[3]}} +
+
diff --git a/package.json b/package.json index f93e35c..22b1246 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "url": "git://github.com/gmetais/YellowLabTools.git" }, "dependencies": { - "phantomas": "git+https://git@github.com/gmetais/phantomas.git#jquery-profiler", + "phantomas": "^1.5.0", "express": "^4.6.1", "async": "^0.9.0", "socket.io": "^1.0.6", diff --git a/phantomas_custom/core/scopeYLT/scopeYLT.js b/phantomas_custom/core/scopeYLT/scopeYLT.js new file mode 100644 index 0000000..d6bd690 --- /dev/null +++ b/phantomas_custom/core/scopeYLT/scopeYLT.js @@ -0,0 +1,176 @@ +/** + * Overwritting the original spying functions in scope.js + * This is done so we now have a before AND an after callback on the spy + * + * @see http://code.jquery.com/jquery-1.10.2.js + * @see http://code.jquery.com/jquery-2.0.3.js + */ +/* global document: true, window: true */ +'use strict'; + +exports.version = '0.1'; + +exports.module = function(phantomas) { + + phantomas.once('init', function() { + phantomas.evaluate(function(deepAnalysis) { + (function(phantomas) { + + // Overwritting phantomas spy function + (function() { + var enabled = true; + + // turn off spying to not include internal phantomas actions + function spyEnabled(state, reason) { + enabled = (state === true); + + phantomas.log('Spying ' + (enabled ? 'enabled' : 'disabled') + (reason ? ' - ' + reason : '')); + } + + phantomas.log('Overwritting phantomas spy function'); + + function spy(obj, fn, callbackBefore, callbackAfter) { + var origFn = obj[fn]; + + if (typeof origFn !== 'function') { + return false; + } + + phantomas.log('Attaching a spy to "' + fn + '" function...'); + + obj[fn] = function() { + var result; + + // Before + if (enabled) { + var args = Array.prototype.slice.call(arguments); + callbackBefore.apply(this, args); + } + + // Execute + try { + result = origFn.apply(this, arguments); + } catch(e) { + phantomas.log('Error catched on spyed function "' + fn + '"": ' + e); + } finally { + + // After + if (enabled && callbackAfter) { + var args = Array.prototype.slice.call(arguments); + callbackAfter.apply(this, args); + } + } + + return result; + }; + + // copy custom properties of original function to the mocked one + Object.keys(origFn).forEach(function(key) { + obj[fn][key] = origFn[key]; + }); + + obj[fn].prototype = origFn.prototype; + + return true; + } + + phantomas.spyEnabled = spyEnabled; + phantomas.spy = spy; + })(); + + + + // Adding some code for the Javascript execution tree construction + (function() { + + var root = new ContextTreeNode(null, {type: 'main'}); + var currentContext = root; + if (deepAnalysis) { + phantomas.log('Entering deep Javascript analysis mode'); + } + var depth = 0; + + // Add a child but don't enter his context + function pushContext(data) { + if (depth === 0 || deepAnalysis) { + data.timestamp = Date.now(); + currentContext.addChild(data); + } + } + + // Add a child to the current context and enter his context + function enterContext(data) { + if (depth === 0 || deepAnalysis) { + data.timestamp = Date.now(); + currentContext = currentContext.addChild(data); + } + depth ++; + } + + // Save given data in the current context and jump change current context to its parent + function leaveContext() { + if (depth === 1 || deepAnalysis) { + currentContext.time = Date.now() - currentContext.data.timestamp; + var parent = currentContext.parent; + if (parent === null) { + console.error('Error: trying to close root context in ContextTree'); + } else { + currentContext = parent; + } + } + depth --; + } + + function getContextData() { + return currentContext.data; + } + + // Returns a clean object, without the parent which causes recursive loops + function readFullTree() { + // Return null if the contextTree is not correctly closed + if (root !== currentContext) { + return null; + } + var current = currentContext; + + function recusiveRead(node) { + if (node.children.length === 0) { + delete node.children; + } else { + for (var i=0, max=node.children.length ; i brackets) + phantomas.setMetric('commentsSize'); // @desc the size of HTML comments on the page @offenders + + // total length of HTML of hidden elements (i.e. display: none) + phantomas.setMetric('hiddenContentSize'); // @desc the size of content of hidden elements on the page (with CSS display: none) @offenders + + // total length of text nodes with whitespaces only (i.e. pretty formatting of HTML) + phantomas.setMetric('whiteSpacesSize'); // @desc the size of text nodes with whitespaces only + + // count all tags + phantomas.setMetric('DOMelementsCount'); // @desc total number of HTML element nodes + phantomas.setMetric('DOMelementMaxDepth'); // @desc maximum level on nesting of HTML element node + + phantomas.setMetric('DOMidDuplicated'); // @desc duplicated id found in DOM + + // nodes with inlines CSS (style attribute) + phantomas.setMetric('nodesWithInlineCSS'); // @desc number of nodes with inline CSS styling (with style attribute) @offenders + + // HTML size + phantomas.on('report', function() { + phantomas.setMetricEvaluate('bodyHTMLSize', function() { // @desc the size of body tag content (document.body.innerHTML.length) + return document.body && document.body.innerHTML.length || 0; + }); + + phantomas.evaluate(function() { + (function(phantomas) { + var runner = new phantomas.nodeRunner(), + whitespacesRegExp = /^\s+$/, + DOMelementMaxDepth = 0, + size = 0; + + // include all nodes + runner.isSkipped = function(node) { + return false; + }; + + runner.walk(document.body, function(node, depth) { + switch (node.nodeType) { + case Node.COMMENT_NODE: + size = node.textContent.length + 7; // ''.length + phantomas.incrMetric('commentsSize', size); + + // log HTML comments bigger than 64 characters + if (size > 64) { + phantomas.addOffender('commentsSize', phantomas.getDOMPath(node) + ' (' + size + ' characters)'); + } + break; + + case Node.ELEMENT_NODE: + phantomas.incrMetric('DOMelementsCount'); + DOMelementMaxDepth = Math.max(DOMelementMaxDepth, depth); + + if (node.id) { + // Send id to a collection so that duplicated ids can be counted + phantomas.emit('domId', node.id); + } + + // ignore inline