Bläddra i källkod

Merge pull request #50 from gmetais/subqueries

Show subqueries in timeline
Gaël Métais 10 år sedan
förälder
incheckning
f95e94ac6d

+ 6 - 1
bin/cli.js

@@ -12,7 +12,8 @@ var cli = meow({
         '  yellowlabtools <url> <options>',
         '',
         'Options:',
-        '  --screenshot     Will take a screenshot and use this value as the output path. It needs to end with ".png".',
+        '  --screenshot         Will take a screenshot and use this value as the output path. It needs to end with ".png".',
+        '  --js-deep-analysis   When activated, the javascriptExecutionTree will contain sub-requests.',
         ''
     ].join('\n'),
     pkg: '../package.json'
@@ -44,6 +45,10 @@ if (screenshot) {
     options.screenshot = cli.flags.screenshot;
 }
 
+// Deep JS analysis option
+if (cli.flags.jsDeepAnalysis === true || cli.flags.jsDeepAnalysis === 'true') {
+    options.jsDeepAnalysis = true;
+}
 
 
 (function execute(url, options) {

+ 40 - 0
front/src/css/timeline.css

@@ -177,6 +177,46 @@ input.textFilter {
 .table > div > .type {
   white-space: nowrap;
 }
+.table .children {
+  margin-top: 0.2em;
+  font-size: 0.8em;
+  line-height: 1.6em;
+}
+.table .child {
+  margin-left: 0.5em;
+}
+.table .child > .child {
+  margin-left: 1em;
+}
+.table .child:before {
+  content: "↳";
+}
+.table .child .childArgs {
+  display: none;
+}
+.table .child span {
+  position: relative;
+}
+.table .child span:hover {
+  background: #EBD8E2;
+}
+.table .child span:hover .childArgs {
+  display: block;
+  position: absolute;
+  padding: 0 1em 0 2em;
+  left: 100%;
+  top: 0;
+  background: #EBD8E2;
+  line-height: 1.3em;
+  height: 1.3em;
+  z-index: 1;
+}
+.table .showingDetails .child span:hover {
+  background: inherit;
+}
+.table .showingDetails .child span:hover .childArgs {
+  display: none;
+}
 .table > div > .value {
   width: 70%;
   word-break: break-all;

+ 1 - 0
front/src/js/app.js

@@ -12,6 +12,7 @@ var yltApp = angular.module('YellowLabTools', [
     'apiService',
     'menuService',
     'gradeDirective',
+    'jsChildrenDirective',
     'offendersDirectives'
 ]);
 

+ 44 - 0
front/src/js/directives/jsChildrenDirective.js

@@ -0,0 +1,44 @@
+var jsChildrenDirective = angular.module('jsChildrenDirective', []);
+
+jsChildrenDirective.directive('jsChildren', function() {
+ 
+    return {
+        restrict: 'E',
+        scope: {
+            node: '=node'
+        },
+        template:   '<div class="children"></div>',
+        replace: true,
+        link: function(scope, element, attrs) {
+            
+            function recursiveHtmlBuilder(node) {
+                var html = '';
+                
+                if (node.children) {
+                    node.children.forEach(function(child) {
+                        
+                        var childArgs = '';
+                        if (child.data.callDetails && child.data.callDetails.arguments && child.data.callDetails.arguments.length > 0) {
+                            childArgs = child.data.callDetails.arguments.join(' : ');
+                            if (childArgs.length > 100) {
+                                childArgs = childArgs.substr(0, 98) + '...';
+                            }
+                        }
+
+                        html += '<div class="child"><span>' + child.data.type + '<div class="childArgs">' + childArgs + '</div></span>' + recursiveHtmlBuilder(child) + '</div>';
+                    });
+                }
+
+                return html;
+            }
+
+            element.append(recursiveHtmlBuilder(scope.node));
+
+            // Bind a very special behavior:
+            // We want to display something in the next table-cell, at the same hight.
+            element.find('span').on('mouseenter', function() {
+                
+            });
+        }
+    };
+});

+ 2 - 1
front/src/js/services/apiService.js

@@ -8,7 +8,8 @@ apiService.factory('API', ['$location', 'Runs', 'Results', function($location, R
             Runs.save({
                 url: url,
                 waitForResponse: false,
-                screenshot: true
+                screenshot: true,
+                jsTimeline: true
             }, function(data) {
                 $location.path('/queue/' + data.runId);
             }, function(response) {

+ 50 - 0
front/src/less/timeline.less

@@ -197,6 +197,56 @@ input.textFilter {
     white-space:nowrap;
 }
 
+.table .children {
+    margin-top: 0.2em;
+    font-size: 0.8em;
+    line-height: 1.6em;
+}
+
+.table .child {
+    margin-left: 0.5em;
+
+    > .child {
+        margin-left: 1em;
+    }
+
+    &:before {
+        content: "↳";
+    }
+
+    .childArgs {
+        display: none;
+    }
+
+    span {
+        position: relative;
+    }
+
+    span:hover {
+        background: #EBD8E2;
+
+        .childArgs {
+            display: block;
+            position: absolute;
+            padding: 0 1em 0 2em;
+            left: 100%;
+            top: 0;
+            background: #EBD8E2;
+            line-height: 1.3em;
+            height: 1.3em;
+            z-index: 1;
+        }
+    }
+}
+
+.table .showingDetails .child span:hover {
+    background: inherit;
+
+    .childArgs {
+        display: none;
+    }
+}
+
 .table > div > .value {
     width: 70%;
     word-break: break-all;

+ 1 - 0
front/src/main.html

@@ -35,6 +35,7 @@
     <script src="/js/services/apiService.js"></script>
     <script src="/js/services/menuService.js"></script>
     <script src="/js/directives/gradeDirective.js"></script>
+    <script src="/js/directives/jsChildrenDirective.js"></script>
     <script src="/js/directives/offendersDirectives.js"></script>
     <!-- endbuild -->
 <head>

+ 4 - 1
front/src/views/timeline.html

@@ -78,7 +78,10 @@
             }">
 
             <div class="index">{{$index + 1}}</div>
-            <div class="type">{{node.data.type}}</div>
+            <div class="type">
+                {{node.data.type}}
+                <js-children node="node"></js-children>
+            </div>
 
             <div class="value">
                 {{node.data.callDetails.arguments[0]}}

+ 13 - 2
lib/server/controllers/apiController.js

@@ -32,7 +32,8 @@ var ApiController = function(app) {
                 url: req.body.url,
                 waitForResponse: req.body.waitForResponse !== false && req.body.waitForResponse !== 'false' && req.body.waitForResponse !== 0,
                 partialResult: req.body.partialResult || null,
-                screenshot: req.body.screenshot || false
+                screenshot: req.body.screenshot || false,
+                jsTimeline: req.body.jsTimeline || false
             }
         };
 
@@ -64,7 +65,8 @@ var ApiController = function(app) {
             debug('Launching test %s on %s', run.runId, run.params.url);
 
             var runOptions = {
-                screenshot: run.params.screenshot ? screenshot.getTmpFilePath() : false
+                screenshot: run.params.screenshot ? screenshot.getTmpFilePath() : false,
+                jsDeepAnalysis: run.params.jsTimeline
             };
 
             return ylt(run.params.url, runOptions);
@@ -107,7 +109,16 @@ var ApiController = function(app) {
 
                 // Save results
                 .then(function() {
+                    // Remove uneeded temp screenshot path
                     delete data.params.options.screenshot;
+
+                    // Empty javascriptExecutionTree if not needed
+                    if (!run.params.jsTimeline) {
+                        data.javascriptExecutionTree = {};
+                    }
+
+                    // Remove tools results if not needed
+
                     return resultsDatastore.saveResult(data);
                 })
 

+ 5 - 1
test/api/apiTest.js

@@ -159,7 +159,10 @@ describe('api', function() {
                 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('toolsResults').that.is.an('object');
+
+                // javascriptExecutionTree should only be filled if option jsTimeline is true
                 body.should.have.a.property('javascriptExecutionTree').that.is.an('object');
+                body.javascriptExecutionTree.should.deep.equal({});
 
                 // Check if the screenshot temporary file was correctly removed
                 body.params.options.should.not.have.a.property('screenshot');
@@ -188,7 +191,8 @@ describe('api', function() {
             url: serverUrl + '/api/runs',
             body: {
                 url: wwwUrl + '/simple-page.html',
-                waitForResponse: false
+                waitForResponse: false,
+                jsTimeline: true
             },
             json: true,
             headers: {