scopeYLT.js 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. /**
  2. * Overwritting the original spying functions in scope.js
  3. * This is done so we now have a before AND an after callback on the spy
  4. *
  5. * @see http://code.jquery.com/jquery-1.10.2.js
  6. * @see http://code.jquery.com/jquery-2.0.3.js
  7. */
  8. /* global document: true, window: true */
  9. exports.version = '0.1';
  10. exports.module = function(phantomas) {
  11. 'use strict';
  12. var responseEndTime = Date.now();
  13. phantomas.on('responseEnd', function() {
  14. responseEndTime = Date.now();
  15. });
  16. phantomas.once('init', function() {
  17. phantomas.evaluate(function(responseEndTime, deepAnalysis) {
  18. (function(phantomas) {
  19. // Overwritting phantomas spy function
  20. (function() {
  21. var enabled = true;
  22. // turn off spying to not include internal phantomas actions
  23. function spyEnabled(state, reason) {
  24. enabled = (state === true);
  25. phantomas.log('Spying ' + (enabled ? 'enabled' : 'disabled') + (reason ? ' - ' + reason : ''));
  26. }
  27. phantomas.log('Overwritting phantomas spy function');
  28. function spy(obj, fn, callbackBefore, callbackAfter) {
  29. var origFn = obj[fn];
  30. if (typeof origFn !== 'function') {
  31. return false;
  32. }
  33. phantomas.log('Attaching a spy to "' + fn + '" function...');
  34. obj[fn] = function() {
  35. var result;
  36. // Before
  37. if (enabled) {
  38. callbackBefore.apply(this, arguments);
  39. }
  40. // Execute
  41. try {
  42. result = origFn.apply(this, arguments);
  43. } catch(e) {
  44. phantomas.log('Error catched on spyed function "' + fn + '": ' + e);
  45. phantomas.log(arguments);
  46. } finally {
  47. // After
  48. if (enabled && callbackAfter) {
  49. callbackAfter.apply(this, arguments);
  50. }
  51. }
  52. return result;
  53. };
  54. // copy custom properties of original function to the mocked one
  55. Object.keys(origFn).forEach(function(key) {
  56. obj[fn][key] = origFn[key];
  57. });
  58. obj[fn].prototype = origFn.prototype;
  59. return true;
  60. }
  61. phantomas.spyEnabled = spyEnabled;
  62. phantomas.spy = spy;
  63. })();
  64. // Adding some code for the Javascript execution tree construction
  65. (function() {
  66. var root = new ContextTreeNode(null, {type: 'main'});
  67. var currentContext = root;
  68. if (deepAnalysis) {
  69. phantomas.log('Entering deep Javascript analysis mode');
  70. }
  71. var depth = 0;
  72. // Add a child but don't enter his context
  73. function pushContext(data) {
  74. if (depth === 0 || deepAnalysis) {
  75. data.timestamp = Date.now() - responseEndTime;
  76. currentContext.addChild(data);
  77. }
  78. }
  79. // Add a child to the current context and enter his context
  80. function enterContext(data) {
  81. if (depth === 0 || deepAnalysis) {
  82. data.timestamp = Date.now() - responseEndTime;
  83. currentContext = currentContext.addChild(data);
  84. }
  85. depth ++;
  86. }
  87. // Save given data in the current context and jump change current context to its parent
  88. function leaveContext() {
  89. if (depth === 1 || deepAnalysis) {
  90. currentContext.data.time = Date.now() - currentContext.data.timestamp - responseEndTime;
  91. var parent = currentContext.parent;
  92. if (parent === null) {
  93. console.error('Error: trying to close root context in ContextTree');
  94. } else {
  95. currentContext = parent;
  96. }
  97. }
  98. depth --;
  99. }
  100. function getContextData() {
  101. return currentContext.data;
  102. }
  103. // Returns a clean object, without the parent which causes recursive loops
  104. function readFullTree() {
  105. // Return null if the contextTree is not correctly closed
  106. if (root !== currentContext) {
  107. return null;
  108. }
  109. var current = currentContext;
  110. function recusiveRead(node) {
  111. if (node.children.length === 0) {
  112. delete node.children;
  113. } else {
  114. for (var i=0, max=node.children.length ; i<max ; i++) {
  115. recusiveRead(node.children[i]);
  116. }
  117. }
  118. delete node.parent;
  119. }
  120. recusiveRead(root);
  121. return root;
  122. }
  123. function ContextTreeNode(parent, data) {
  124. this.data = data;
  125. this.parent = parent;
  126. this.children = [];
  127. this.addChild = function(data) {
  128. var child = new ContextTreeNode(this, data);
  129. this.children.push(child);
  130. return child;
  131. };
  132. }
  133. phantomas.log('Adding some contextTree functions to phantomas');
  134. phantomas.pushContext = pushContext;
  135. phantomas.enterContext = enterContext;
  136. phantomas.leaveContext = leaveContext;
  137. phantomas.getContextData = getContextData;
  138. phantomas.readFullTree = readFullTree;
  139. })();
  140. })(window.__phantomas);
  141. }, responseEndTime, phantomas.getParam('js-deep-analysis'));
  142. });
  143. };