scopeYLT.js 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  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. data.loadingStep = phantomas.currentStep || '';
  77. currentContext.addChild(data);
  78. }
  79. }
  80. // Add a child to the current context and enter his context
  81. function enterContext(data) {
  82. if (depth === 0 || deepAnalysis) {
  83. data.timestamp = Date.now() - responseEndTime;
  84. data.loadingStep = phantomas.currentStep || '';
  85. currentContext = currentContext.addChild(data);
  86. }
  87. depth ++;
  88. }
  89. // Save given data in the current context and jump change current context to its parent
  90. function leaveContext() {
  91. if (depth === 1 || deepAnalysis) {
  92. currentContext.data.time = Date.now() - currentContext.data.timestamp - responseEndTime;
  93. var parent = currentContext.parent;
  94. if (parent === null) {
  95. console.error('Error: trying to close root context in ContextTree');
  96. } else {
  97. currentContext = parent;
  98. }
  99. }
  100. depth --;
  101. }
  102. function getContextData() {
  103. return currentContext.data;
  104. }
  105. // Returns a clean object, without the parent which causes recursive loops
  106. function readFullTree() {
  107. // Return null if the contextTree is not correctly closed
  108. if (root !== currentContext) {
  109. return null;
  110. }
  111. var current = currentContext;
  112. function recusiveRead(node) {
  113. if (node.children.length === 0) {
  114. delete node.children;
  115. } else {
  116. for (var i=0, max=node.children.length ; i<max ; i++) {
  117. recusiveRead(node.children[i]);
  118. }
  119. }
  120. delete node.parent;
  121. }
  122. recusiveRead(root);
  123. return root;
  124. }
  125. function ContextTreeNode(parent, data) {
  126. this.data = data;
  127. this.parent = parent;
  128. this.children = [];
  129. this.addChild = function(data) {
  130. var child = new ContextTreeNode(this, data);
  131. this.children.push(child);
  132. return child;
  133. };
  134. }
  135. phantomas.log('Adding some contextTree functions to phantomas');
  136. phantomas.pushContext = pushContext;
  137. phantomas.enterContext = enterContext;
  138. phantomas.leaveContext = leaveContext;
  139. phantomas.getContextData = getContextData;
  140. phantomas.readFullTree = readFullTree;
  141. })();
  142. })(window.__phantomas);
  143. }, responseEndTime, phantomas.getParam('js-deep-analysis'));
  144. });
  145. };