smart_monkey 0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.rspec +1 -0
- data/Gemfile +17 -0
- data/LICENSE.txt +21 -0
- data/README.md +77 -0
- data/Rakefile +57 -0
- data/Troubleshooting.md +61 -0
- data/VERSION +1 -0
- data/bin/smart_monkey +53 -0
- data/lib/bootstrap/css/bootstrap-responsive.css +1109 -0
- data/lib/bootstrap/css/bootstrap-responsive.min.css +9 -0
- data/lib/bootstrap/css/bootstrap.css +6167 -0
- data/lib/bootstrap/css/bootstrap.min.css +9 -0
- data/lib/bootstrap/img/glyphicons-halflings-white.png +0 -0
- data/lib/bootstrap/img/glyphicons-halflings.png +0 -0
- data/lib/bootstrap/js/bootstrap.js +2280 -0
- data/lib/bootstrap/js/bootstrap.min.js +6 -0
- data/lib/ios_device_log/deviceconsole +0 -0
- data/lib/smart_monkey.rb +2 -0
- data/lib/smart_monkey/command_helper.rb +71 -0
- data/lib/smart_monkey/monkey_runner.rb +549 -0
- data/lib/smart_monkey/templates/automation_result.xsl +61 -0
- data/lib/smart_monkey/templates/index.html.erb +77 -0
- data/lib/smart_monkey/templates/result.html.erb +110 -0
- data/lib/smart_monkey/templates/result_view.coffee +160 -0
- data/lib/smart_monkey/templates/result_view.js +250 -0
- data/lib/ui-auto-monkey/UIAutoMonkey.js +470 -0
- data/lib/ui-auto-monkey/custom.js +73 -0
- data/lib/ui-auto-monkey/handler/buttonHandler.js +111 -0
- data/lib/ui-auto-monkey/handler/wbScrollViewButtonHandler.js +114 -0
- data/lib/ui-auto-monkey/tuneup/LICENSE +20 -0
- data/lib/ui-auto-monkey/tuneup/assertions.js +402 -0
- data/lib/ui-auto-monkey/tuneup/image_asserter +26 -0
- data/lib/ui-auto-monkey/tuneup/image_assertion.js +65 -0
- data/lib/ui-auto-monkey/tuneup/image_assertion.rb +102 -0
- data/lib/ui-auto-monkey/tuneup/lang-ext.js +76 -0
- data/lib/ui-auto-monkey/tuneup/screen.js +11 -0
- data/lib/ui-auto-monkey/tuneup/test.js +71 -0
- data/lib/ui-auto-monkey/tuneup/test_runner/abbreviated_console_output.rb +38 -0
- data/lib/ui-auto-monkey/tuneup/test_runner/colored_console_output.rb +27 -0
- data/lib/ui-auto-monkey/tuneup/test_runner/console_output.rb +17 -0
- data/lib/ui-auto-monkey/tuneup/test_runner/preprocessor.rb +25 -0
- data/lib/ui-auto-monkey/tuneup/test_runner/run +343 -0
- data/lib/ui-auto-monkey/tuneup/test_runner/xunit_output.rb +114 -0
- data/lib/ui-auto-monkey/tuneup/tuneup.js +6 -0
- data/lib/ui-auto-monkey/tuneup/tuneup_js.podspec +52 -0
- data/lib/ui-auto-monkey/tuneup/uiautomation-ext.js +965 -0
- data/smart_monkey.gemspec +112 -0
- data/spec/spec_helper.rb +12 -0
- metadata +192 -0
@@ -0,0 +1,6 @@
|
|
1
|
+
/*!
|
2
|
+
* Bootstrap.js by @fat & @mdo
|
3
|
+
* Copyright 2012 Twitter, Inc.
|
4
|
+
* http://www.apache.org/licenses/LICENSE-2.0.txt
|
5
|
+
*/
|
6
|
+
!function(e){"use strict";e(function(){e.support.transition=function(){var e=function(){var e=document.createElement("bootstrap"),t={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"},n;for(n in t)if(e.style[n]!==undefined)return t[n]}();return e&&{end:e}}()})}(window.jQuery),!function(e){"use strict";var t='[data-dismiss="alert"]',n=function(n){e(n).on("click",t,this.close)};n.prototype.close=function(t){function s(){i.trigger("closed").remove()}var n=e(this),r=n.attr("data-target"),i;r||(r=n.attr("href"),r=r&&r.replace(/.*(?=#[^\s]*$)/,"")),i=e(r),t&&t.preventDefault(),i.length||(i=n.hasClass("alert")?n:n.parent()),i.trigger(t=e.Event("close"));if(t.isDefaultPrevented())return;i.removeClass("in"),e.support.transition&&i.hasClass("fade")?i.on(e.support.transition.end,s):s()};var r=e.fn.alert;e.fn.alert=function(t){return this.each(function(){var r=e(this),i=r.data("alert");i||r.data("alert",i=new n(this)),typeof t=="string"&&i[t].call(r)})},e.fn.alert.Constructor=n,e.fn.alert.noConflict=function(){return e.fn.alert=r,this},e(document).on("click.alert.data-api",t,n.prototype.close)}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.button.defaults,n)};t.prototype.setState=function(e){var t="disabled",n=this.$element,r=n.data(),i=n.is("input")?"val":"html";e+="Text",r.resetText||n.data("resetText",n[i]()),n[i](r[e]||this.options[e]),setTimeout(function(){e=="loadingText"?n.addClass(t).attr(t,t):n.removeClass(t).removeAttr(t)},0)},t.prototype.toggle=function(){var e=this.$element.closest('[data-toggle="buttons-radio"]');e&&e.find(".active").removeClass("active"),this.$element.toggleClass("active")};var n=e.fn.button;e.fn.button=function(n){return this.each(function(){var r=e(this),i=r.data("button"),s=typeof n=="object"&&n;i||r.data("button",i=new t(this,s)),n=="toggle"?i.toggle():n&&i.setState(n)})},e.fn.button.defaults={loadingText:"loading..."},e.fn.button.Constructor=t,e.fn.button.noConflict=function(){return e.fn.button=n,this},e(document).on("click.button.data-api","[data-toggle^=button]",function(t){var n=e(t.target);n.hasClass("btn")||(n=n.closest(".btn")),n.button("toggle")})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.$indicators=this.$element.find(".carousel-indicators"),this.options=n,this.options.pause=="hover"&&this.$element.on("mouseenter",e.proxy(this.pause,this)).on("mouseleave",e.proxy(this.cycle,this))};t.prototype={cycle:function(t){return t||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(e.proxy(this.next,this),this.options.interval)),this},getActiveIndex:function(){return this.$active=this.$element.find(".item.active"),this.$items=this.$active.parent().children(),this.$items.index(this.$active)},to:function(t){var n=this.getActiveIndex(),r=this;if(t>this.$items.length-1||t<0)return;return this.sliding?this.$element.one("slid",function(){r.to(t)}):n==t?this.pause().cycle():this.slide(t>n?"next":"prev",e(this.$items[t]))},pause:function(t){return t||(this.paused=!0),this.$element.find(".next, .prev").length&&e.support.transition.end&&(this.$element.trigger(e.support.transition.end),this.cycle(!0)),clearInterval(this.interval),this.interval=null,this},next:function(){if(this.sliding)return;return this.slide("next")},prev:function(){if(this.sliding)return;return this.slide("prev")},slide:function(t,n){var r=this.$element.find(".item.active"),i=n||r[t](),s=this.interval,o=t=="next"?"left":"right",u=t=="next"?"first":"last",a=this,f;this.sliding=!0,s&&this.pause(),i=i.length?i:this.$element.find(".item")[u](),f=e.Event("slide",{relatedTarget:i[0],direction:o});if(i.hasClass("active"))return;this.$indicators.length&&(this.$indicators.find(".active").removeClass("active"),this.$element.one("slid",function(){var t=e(a.$indicators.children()[a.getActiveIndex()]);t&&t.addClass("active")}));if(e.support.transition&&this.$element.hasClass("slide")){this.$element.trigger(f);if(f.isDefaultPrevented())return;i.addClass(t),i[0].offsetWidth,r.addClass(o),i.addClass(o),this.$element.one(e.support.transition.end,function(){i.removeClass([t,o].join(" ")).addClass("active"),r.removeClass(["active",o].join(" ")),a.sliding=!1,setTimeout(function(){a.$element.trigger("slid")},0)})}else{this.$element.trigger(f);if(f.isDefaultPrevented())return;r.removeClass("active"),i.addClass("active"),this.sliding=!1,this.$element.trigger("slid")}return s&&this.cycle(),this}};var n=e.fn.carousel;e.fn.carousel=function(n){return this.each(function(){var r=e(this),i=r.data("carousel"),s=e.extend({},e.fn.carousel.defaults,typeof n=="object"&&n),o=typeof n=="string"?n:s.slide;i||r.data("carousel",i=new t(this,s)),typeof n=="number"?i.to(n):o?i[o]():s.interval&&i.pause().cycle()})},e.fn.carousel.defaults={interval:5e3,pause:"hover"},e.fn.carousel.Constructor=t,e.fn.carousel.noConflict=function(){return e.fn.carousel=n,this},e(document).on("click.carousel.data-api","[data-slide], [data-slide-to]",function(t){var n=e(this),r,i=e(n.attr("data-target")||(r=n.attr("href"))&&r.replace(/.*(?=#[^\s]+$)/,"")),s=e.extend({},i.data(),n.data()),o;i.carousel(s),(o=n.attr("data-slide-to"))&&i.data("carousel").pause().to(o).cycle(),t.preventDefault()})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.collapse.defaults,n),this.options.parent&&(this.$parent=e(this.options.parent)),this.options.toggle&&this.toggle()};t.prototype={constructor:t,dimension:function(){var e=this.$element.hasClass("width");return e?"width":"height"},show:function(){var t,n,r,i;if(this.transitioning||this.$element.hasClass("in"))return;t=this.dimension(),n=e.camelCase(["scroll",t].join("-")),r=this.$parent&&this.$parent.find("> .accordion-group > .in");if(r&&r.length){i=r.data("collapse");if(i&&i.transitioning)return;r.collapse("hide"),i||r.data("collapse",null)}this.$element[t](0),this.transition("addClass",e.Event("show"),"shown"),e.support.transition&&this.$element[t](this.$element[0][n])},hide:function(){var t;if(this.transitioning||!this.$element.hasClass("in"))return;t=this.dimension(),this.reset(this.$element[t]()),this.transition("removeClass",e.Event("hide"),"hidden"),this.$element[t](0)},reset:function(e){var t=this.dimension();return this.$element.removeClass("collapse")[t](e||"auto")[0].offsetWidth,this.$element[e!==null?"addClass":"removeClass"]("collapse"),this},transition:function(t,n,r){var i=this,s=function(){n.type=="show"&&i.reset(),i.transitioning=0,i.$element.trigger(r)};this.$element.trigger(n);if(n.isDefaultPrevented())return;this.transitioning=1,this.$element[t]("in"),e.support.transition&&this.$element.hasClass("collapse")?this.$element.one(e.support.transition.end,s):s()},toggle:function(){this[this.$element.hasClass("in")?"hide":"show"]()}};var n=e.fn.collapse;e.fn.collapse=function(n){return this.each(function(){var r=e(this),i=r.data("collapse"),s=e.extend({},e.fn.collapse.defaults,r.data(),typeof n=="object"&&n);i||r.data("collapse",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.collapse.defaults={toggle:!0},e.fn.collapse.Constructor=t,e.fn.collapse.noConflict=function(){return e.fn.collapse=n,this},e(document).on("click.collapse.data-api","[data-toggle=collapse]",function(t){var n=e(this),r,i=n.attr("data-target")||t.preventDefault()||(r=n.attr("href"))&&r.replace(/.*(?=#[^\s]+$)/,""),s=e(i).data("collapse")?"toggle":n.data();n[e(i).hasClass("in")?"addClass":"removeClass"]("collapsed"),e(i).collapse(s)})}(window.jQuery),!function(e){"use strict";function r(){e(".dropdown-backdrop").remove(),e(t).each(function(){i(e(this)).removeClass("open")})}function i(t){var n=t.attr("data-target"),r;n||(n=t.attr("href"),n=n&&/#/.test(n)&&n.replace(/.*(?=#[^\s]*$)/,"")),r=n&&e(n);if(!r||!r.length)r=t.parent();return r}var t="[data-toggle=dropdown]",n=function(t){var n=e(t).on("click.dropdown.data-api",this.toggle);e("html").on("click.dropdown.data-api",function(){n.parent().removeClass("open")})};n.prototype={constructor:n,toggle:function(t){var n=e(this),s,o;if(n.is(".disabled, :disabled"))return;return s=i(n),o=s.hasClass("open"),r(),o||("ontouchstart"in document.documentElement&&e('<div class="dropdown-backdrop"/>').insertBefore(e(this)).on("click",r),s.toggleClass("open")),n.focus(),!1},keydown:function(n){var r,s,o,u,a,f;if(!/(38|40|27)/.test(n.keyCode))return;r=e(this),n.preventDefault(),n.stopPropagation();if(r.is(".disabled, :disabled"))return;u=i(r),a=u.hasClass("open");if(!a||a&&n.keyCode==27)return n.which==27&&u.find(t).focus(),r.click();s=e("[role=menu] li:not(.divider):visible a",u);if(!s.length)return;f=s.index(s.filter(":focus")),n.keyCode==38&&f>0&&f--,n.keyCode==40&&f<s.length-1&&f++,~f||(f=0),s.eq(f).focus()}};var s=e.fn.dropdown;e.fn.dropdown=function(t){return this.each(function(){var r=e(this),i=r.data("dropdown");i||r.data("dropdown",i=new n(this)),typeof t=="string"&&i[t].call(r)})},e.fn.dropdown.Constructor=n,e.fn.dropdown.noConflict=function(){return e.fn.dropdown=s,this},e(document).on("click.dropdown.data-api",r).on("click.dropdown.data-api",".dropdown form",function(e){e.stopPropagation()}).on("click.dropdown.data-api",t,n.prototype.toggle).on("keydown.dropdown.data-api",t+", [role=menu]",n.prototype.keydown)}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.options=n,this.$element=e(t).delegate('[data-dismiss="modal"]',"click.dismiss.modal",e.proxy(this.hide,this)),this.options.remote&&this.$element.find(".modal-body").load(this.options.remote)};t.prototype={constructor:t,toggle:function(){return this[this.isShown?"hide":"show"]()},show:function(){var t=this,n=e.Event("show");this.$element.trigger(n);if(this.isShown||n.isDefaultPrevented())return;this.isShown=!0,this.escape(),this.backdrop(function(){var n=e.support.transition&&t.$element.hasClass("fade");t.$element.parent().length||t.$element.appendTo(document.body),t.$element.show(),n&&t.$element[0].offsetWidth,t.$element.addClass("in").attr("aria-hidden",!1),t.enforceFocus(),n?t.$element.one(e.support.transition.end,function(){t.$element.focus().trigger("shown")}):t.$element.focus().trigger("shown")})},hide:function(t){t&&t.preventDefault();var n=this;t=e.Event("hide"),this.$element.trigger(t);if(!this.isShown||t.isDefaultPrevented())return;this.isShown=!1,this.escape(),e(document).off("focusin.modal"),this.$element.removeClass("in").attr("aria-hidden",!0),e.support.transition&&this.$element.hasClass("fade")?this.hideWithTransition():this.hideModal()},enforceFocus:function(){var t=this;e(document).on("focusin.modal",function(e){t.$element[0]!==e.target&&!t.$element.has(e.target).length&&t.$element.focus()})},escape:function(){var e=this;this.isShown&&this.options.keyboard?this.$element.on("keyup.dismiss.modal",function(t){t.which==27&&e.hide()}):this.isShown||this.$element.off("keyup.dismiss.modal")},hideWithTransition:function(){var t=this,n=setTimeout(function(){t.$element.off(e.support.transition.end),t.hideModal()},500);this.$element.one(e.support.transition.end,function(){clearTimeout(n),t.hideModal()})},hideModal:function(){var e=this;this.$element.hide(),this.backdrop(function(){e.removeBackdrop(),e.$element.trigger("hidden")})},removeBackdrop:function(){this.$backdrop&&this.$backdrop.remove(),this.$backdrop=null},backdrop:function(t){var n=this,r=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var i=e.support.transition&&r;this.$backdrop=e('<div class="modal-backdrop '+r+'" />').appendTo(document.body),this.$backdrop.click(this.options.backdrop=="static"?e.proxy(this.$element[0].focus,this.$element[0]):e.proxy(this.hide,this)),i&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in");if(!t)return;i?this.$backdrop.one(e.support.transition.end,t):t()}else!this.isShown&&this.$backdrop?(this.$backdrop.removeClass("in"),e.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one(e.support.transition.end,t):t()):t&&t()}};var n=e.fn.modal;e.fn.modal=function(n){return this.each(function(){var r=e(this),i=r.data("modal"),s=e.extend({},e.fn.modal.defaults,r.data(),typeof n=="object"&&n);i||r.data("modal",i=new t(this,s)),typeof n=="string"?i[n]():s.show&&i.show()})},e.fn.modal.defaults={backdrop:!0,keyboard:!0,show:!0},e.fn.modal.Constructor=t,e.fn.modal.noConflict=function(){return e.fn.modal=n,this},e(document).on("click.modal.data-api",'[data-toggle="modal"]',function(t){var n=e(this),r=n.attr("href"),i=e(n.attr("data-target")||r&&r.replace(/.*(?=#[^\s]+$)/,"")),s=i.data("modal")?"toggle":e.extend({remote:!/#/.test(r)&&r},i.data(),n.data());t.preventDefault(),i.modal(s).one("hide",function(){n.focus()})})}(window.jQuery),!function(e){"use strict";var t=function(e,t){this.init("tooltip",e,t)};t.prototype={constructor:t,init:function(t,n,r){var i,s,o,u,a;this.type=t,this.$element=e(n),this.options=this.getOptions(r),this.enabled=!0,o=this.options.trigger.split(" ");for(a=o.length;a--;)u=o[a],u=="click"?this.$element.on("click."+this.type,this.options.selector,e.proxy(this.toggle,this)):u!="manual"&&(i=u=="hover"?"mouseenter":"focus",s=u=="hover"?"mouseleave":"blur",this.$element.on(i+"."+this.type,this.options.selector,e.proxy(this.enter,this)),this.$element.on(s+"."+this.type,this.options.selector,e.proxy(this.leave,this)));this.options.selector?this._options=e.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},getOptions:function(t){return t=e.extend({},e.fn[this.type].defaults,this.$element.data(),t),t.delay&&typeof t.delay=="number"&&(t.delay={show:t.delay,hide:t.delay}),t},enter:function(t){var n=e.fn[this.type].defaults,r={},i;this._options&&e.each(this._options,function(e,t){n[e]!=t&&(r[e]=t)},this),i=e(t.currentTarget)[this.type](r).data(this.type);if(!i.options.delay||!i.options.delay.show)return i.show();clearTimeout(this.timeout),i.hoverState="in",this.timeout=setTimeout(function(){i.hoverState=="in"&&i.show()},i.options.delay.show)},leave:function(t){var n=e(t.currentTarget)[this.type](this._options).data(this.type);this.timeout&&clearTimeout(this.timeout);if(!n.options.delay||!n.options.delay.hide)return n.hide();n.hoverState="out",this.timeout=setTimeout(function(){n.hoverState=="out"&&n.hide()},n.options.delay.hide)},show:function(){var t,n,r,i,s,o,u=e.Event("show");if(this.hasContent()&&this.enabled){this.$element.trigger(u);if(u.isDefaultPrevented())return;t=this.tip(),this.setContent(),this.options.animation&&t.addClass("fade"),s=typeof this.options.placement=="function"?this.options.placement.call(this,t[0],this.$element[0]):this.options.placement,t.detach().css({top:0,left:0,display:"block"}),this.options.container?t.appendTo(this.options.container):t.insertAfter(this.$element),n=this.getPosition(),r=t[0].offsetWidth,i=t[0].offsetHeight;switch(s){case"bottom":o={top:n.top+n.height,left:n.left+n.width/2-r/2};break;case"top":o={top:n.top-i,left:n.left+n.width/2-r/2};break;case"left":o={top:n.top+n.height/2-i/2,left:n.left-r};break;case"right":o={top:n.top+n.height/2-i/2,left:n.left+n.width}}this.applyPlacement(o,s),this.$element.trigger("shown")}},applyPlacement:function(e,t){var n=this.tip(),r=n[0].offsetWidth,i=n[0].offsetHeight,s,o,u,a;n.offset(e).addClass(t).addClass("in"),s=n[0].offsetWidth,o=n[0].offsetHeight,t=="top"&&o!=i&&(e.top=e.top+i-o,a=!0),t=="bottom"||t=="top"?(u=0,e.left<0&&(u=e.left*-2,e.left=0,n.offset(e),s=n[0].offsetWidth,o=n[0].offsetHeight),this.replaceArrow(u-r+s,s,"left")):this.replaceArrow(o-i,o,"top"),a&&n.offset(e)},replaceArrow:function(e,t,n){this.arrow().css(n,e?50*(1-e/t)+"%":"")},setContent:function(){var e=this.tip(),t=this.getTitle();e.find(".tooltip-inner")[this.options.html?"html":"text"](t),e.removeClass("fade in top bottom left right")},hide:function(){function i(){var t=setTimeout(function(){n.off(e.support.transition.end).detach()},500);n.one(e.support.transition.end,function(){clearTimeout(t),n.detach()})}var t=this,n=this.tip(),r=e.Event("hide");this.$element.trigger(r);if(r.isDefaultPrevented())return;return n.removeClass("in"),e.support.transition&&this.$tip.hasClass("fade")?i():n.detach(),this.$element.trigger("hidden"),this},fixTitle:function(){var e=this.$element;(e.attr("title")||typeof e.attr("data-original-title")!="string")&&e.attr("data-original-title",e.attr("title")||"").attr("title","")},hasContent:function(){return this.getTitle()},getPosition:function(){var t=this.$element[0];return e.extend({},typeof t.getBoundingClientRect=="function"?t.getBoundingClientRect():{width:t.offsetWidth,height:t.offsetHeight},this.$element.offset())},getTitle:function(){var e,t=this.$element,n=this.options;return e=t.attr("data-original-title")||(typeof n.title=="function"?n.title.call(t[0]):n.title),e},tip:function(){return this.$tip=this.$tip||e(this.options.template)},arrow:function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},validate:function(){this.$element[0].parentNode||(this.hide(),this.$element=null,this.options=null)},enable:function(){this.enabled=!0},disable:function(){this.enabled=!1},toggleEnabled:function(){this.enabled=!this.enabled},toggle:function(t){var n=t?e(t.currentTarget)[this.type](this._options).data(this.type):this;n.tip().hasClass("in")?n.hide():n.show()},destroy:function(){this.hide().$element.off("."+this.type).removeData(this.type)}};var n=e.fn.tooltip;e.fn.tooltip=function(n){return this.each(function(){var r=e(this),i=r.data("tooltip"),s=typeof n=="object"&&n;i||r.data("tooltip",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.tooltip.Constructor=t,e.fn.tooltip.defaults={animation:!0,placement:"top",selector:!1,template:'<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover focus",title:"",delay:0,html:!1,container:!1},e.fn.tooltip.noConflict=function(){return e.fn.tooltip=n,this}}(window.jQuery),!function(e){"use strict";var t=function(e,t){this.init("popover",e,t)};t.prototype=e.extend({},e.fn.tooltip.Constructor.prototype,{constructor:t,setContent:function(){var e=this.tip(),t=this.getTitle(),n=this.getContent();e.find(".popover-title")[this.options.html?"html":"text"](t),e.find(".popover-content")[this.options.html?"html":"text"](n),e.removeClass("fade top bottom left right in")},hasContent:function(){return this.getTitle()||this.getContent()},getContent:function(){var e,t=this.$element,n=this.options;return e=(typeof n.content=="function"?n.content.call(t[0]):n.content)||t.attr("data-content"),e},tip:function(){return this.$tip||(this.$tip=e(this.options.template)),this.$tip},destroy:function(){this.hide().$element.off("."+this.type).removeData(this.type)}});var n=e.fn.popover;e.fn.popover=function(n){return this.each(function(){var r=e(this),i=r.data("popover"),s=typeof n=="object"&&n;i||r.data("popover",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.popover.Constructor=t,e.fn.popover.defaults=e.extend({},e.fn.tooltip.defaults,{placement:"right",trigger:"click",content:"",template:'<div class="popover"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'}),e.fn.popover.noConflict=function(){return e.fn.popover=n,this}}(window.jQuery),!function(e){"use strict";function t(t,n){var r=e.proxy(this.process,this),i=e(t).is("body")?e(window):e(t),s;this.options=e.extend({},e.fn.scrollspy.defaults,n),this.$scrollElement=i.on("scroll.scroll-spy.data-api",r),this.selector=(this.options.target||(s=e(t).attr("href"))&&s.replace(/.*(?=#[^\s]+$)/,"")||"")+" .nav li > a",this.$body=e("body"),this.refresh(),this.process()}t.prototype={constructor:t,refresh:function(){var t=this,n;this.offsets=e([]),this.targets=e([]),n=this.$body.find(this.selector).map(function(){var n=e(this),r=n.data("target")||n.attr("href"),i=/^#\w/.test(r)&&e(r);return i&&i.length&&[[i.position().top+(!e.isWindow(t.$scrollElement.get(0))&&t.$scrollElement.scrollTop()),r]]||null}).sort(function(e,t){return e[0]-t[0]}).each(function(){t.offsets.push(this[0]),t.targets.push(this[1])})},process:function(){var e=this.$scrollElement.scrollTop()+this.options.offset,t=this.$scrollElement[0].scrollHeight||this.$body[0].scrollHeight,n=t-this.$scrollElement.height(),r=this.offsets,i=this.targets,s=this.activeTarget,o;if(e>=n)return s!=(o=i.last()[0])&&this.activate(o);for(o=r.length;o--;)s!=i[o]&&e>=r[o]&&(!r[o+1]||e<=r[o+1])&&this.activate(i[o])},activate:function(t){var n,r;this.activeTarget=t,e(this.selector).parent(".active").removeClass("active"),r=this.selector+'[data-target="'+t+'"],'+this.selector+'[href="'+t+'"]',n=e(r).parent("li").addClass("active"),n.parent(".dropdown-menu").length&&(n=n.closest("li.dropdown").addClass("active")),n.trigger("activate")}};var n=e.fn.scrollspy;e.fn.scrollspy=function(n){return this.each(function(){var r=e(this),i=r.data("scrollspy"),s=typeof n=="object"&&n;i||r.data("scrollspy",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.scrollspy.Constructor=t,e.fn.scrollspy.defaults={offset:10},e.fn.scrollspy.noConflict=function(){return e.fn.scrollspy=n,this},e(window).on("load",function(){e('[data-spy="scroll"]').each(function(){var t=e(this);t.scrollspy(t.data())})})}(window.jQuery),!function(e){"use strict";var t=function(t){this.element=e(t)};t.prototype={constructor:t,show:function(){var t=this.element,n=t.closest("ul:not(.dropdown-menu)"),r=t.attr("data-target"),i,s,o;r||(r=t.attr("href"),r=r&&r.replace(/.*(?=#[^\s]*$)/,""));if(t.parent("li").hasClass("active"))return;i=n.find(".active:last a")[0],o=e.Event("show",{relatedTarget:i}),t.trigger(o);if(o.isDefaultPrevented())return;s=e(r),this.activate(t.parent("li"),n),this.activate(s,s.parent(),function(){t.trigger({type:"shown",relatedTarget:i})})},activate:function(t,n,r){function o(){i.removeClass("active").find("> .dropdown-menu > .active").removeClass("active"),t.addClass("active"),s?(t[0].offsetWidth,t.addClass("in")):t.removeClass("fade"),t.parent(".dropdown-menu")&&t.closest("li.dropdown").addClass("active"),r&&r()}var i=n.find("> .active"),s=r&&e.support.transition&&i.hasClass("fade");s?i.one(e.support.transition.end,o):o(),i.removeClass("in")}};var n=e.fn.tab;e.fn.tab=function(n){return this.each(function(){var r=e(this),i=r.data("tab");i||r.data("tab",i=new t(this)),typeof n=="string"&&i[n]()})},e.fn.tab.Constructor=t,e.fn.tab.noConflict=function(){return e.fn.tab=n,this},e(document).on("click.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"]',function(t){t.preventDefault(),e(this).tab("show")})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.typeahead.defaults,n),this.matcher=this.options.matcher||this.matcher,this.sorter=this.options.sorter||this.sorter,this.highlighter=this.options.highlighter||this.highlighter,this.updater=this.options.updater||this.updater,this.source=this.options.source,this.$menu=e(this.options.menu),this.shown=!1,this.listen()};t.prototype={constructor:t,select:function(){var e=this.$menu.find(".active").attr("data-value");return this.$element.val(this.updater(e)).change(),this.hide()},updater:function(e){return e},show:function(){var t=e.extend({},this.$element.position(),{height:this.$element[0].offsetHeight});return this.$menu.insertAfter(this.$element).css({top:t.top+t.height,left:t.left}).show(),this.shown=!0,this},hide:function(){return this.$menu.hide(),this.shown=!1,this},lookup:function(t){var n;return this.query=this.$element.val(),!this.query||this.query.length<this.options.minLength?this.shown?this.hide():this:(n=e.isFunction(this.source)?this.source(this.query,e.proxy(this.process,this)):this.source,n?this.process(n):this)},process:function(t){var n=this;return t=e.grep(t,function(e){return n.matcher(e)}),t=this.sorter(t),t.length?this.render(t.slice(0,this.options.items)).show():this.shown?this.hide():this},matcher:function(e){return~e.toLowerCase().indexOf(this.query.toLowerCase())},sorter:function(e){var t=[],n=[],r=[],i;while(i=e.shift())i.toLowerCase().indexOf(this.query.toLowerCase())?~i.indexOf(this.query)?n.push(i):r.push(i):t.push(i);return t.concat(n,r)},highlighter:function(e){var t=this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&");return e.replace(new RegExp("("+t+")","ig"),function(e,t){return"<strong>"+t+"</strong>"})},render:function(t){var n=this;return t=e(t).map(function(t,r){return t=e(n.options.item).attr("data-value",r),t.find("a").html(n.highlighter(r)),t[0]}),t.first().addClass("active"),this.$menu.html(t),this},next:function(t){var n=this.$menu.find(".active").removeClass("active"),r=n.next();r.length||(r=e(this.$menu.find("li")[0])),r.addClass("active")},prev:function(e){var t=this.$menu.find(".active").removeClass("active"),n=t.prev();n.length||(n=this.$menu.find("li").last()),n.addClass("active")},listen:function(){this.$element.on("focus",e.proxy(this.focus,this)).on("blur",e.proxy(this.blur,this)).on("keypress",e.proxy(this.keypress,this)).on("keyup",e.proxy(this.keyup,this)),this.eventSupported("keydown")&&this.$element.on("keydown",e.proxy(this.keydown,this)),this.$menu.on("click",e.proxy(this.click,this)).on("mouseenter","li",e.proxy(this.mouseenter,this)).on("mouseleave","li",e.proxy(this.mouseleave,this))},eventSupported:function(e){var t=e in this.$element;return t||(this.$element.setAttribute(e,"return;"),t=typeof this.$element[e]=="function"),t},move:function(e){if(!this.shown)return;switch(e.keyCode){case 9:case 13:case 27:e.preventDefault();break;case 38:e.preventDefault(),this.prev();break;case 40:e.preventDefault(),this.next()}e.stopPropagation()},keydown:function(t){this.suppressKeyPressRepeat=~e.inArray(t.keyCode,[40,38,9,13,27]),this.move(t)},keypress:function(e){if(this.suppressKeyPressRepeat)return;this.move(e)},keyup:function(e){switch(e.keyCode){case 40:case 38:case 16:case 17:case 18:break;case 9:case 13:if(!this.shown)return;this.select();break;case 27:if(!this.shown)return;this.hide();break;default:this.lookup()}e.stopPropagation(),e.preventDefault()},focus:function(e){this.focused=!0},blur:function(e){this.focused=!1,!this.mousedover&&this.shown&&this.hide()},click:function(e){e.stopPropagation(),e.preventDefault(),this.select(),this.$element.focus()},mouseenter:function(t){this.mousedover=!0,this.$menu.find(".active").removeClass("active"),e(t.currentTarget).addClass("active")},mouseleave:function(e){this.mousedover=!1,!this.focused&&this.shown&&this.hide()}};var n=e.fn.typeahead;e.fn.typeahead=function(n){return this.each(function(){var r=e(this),i=r.data("typeahead"),s=typeof n=="object"&&n;i||r.data("typeahead",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.typeahead.defaults={source:[],items:8,menu:'<ul class="typeahead dropdown-menu"></ul>',item:'<li><a href="#"></a></li>',minLength:1},e.fn.typeahead.Constructor=t,e.fn.typeahead.noConflict=function(){return e.fn.typeahead=n,this},e(document).on("focus.typeahead.data-api",'[data-provide="typeahead"]',function(t){var n=e(this);if(n.data("typeahead"))return;n.typeahead(n.data())})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.options=e.extend({},e.fn.affix.defaults,n),this.$window=e(window).on("scroll.affix.data-api",e.proxy(this.checkPosition,this)).on("click.affix.data-api",e.proxy(function(){setTimeout(e.proxy(this.checkPosition,this),1)},this)),this.$element=e(t),this.checkPosition()};t.prototype.checkPosition=function(){if(!this.$element.is(":visible"))return;var t=e(document).height(),n=this.$window.scrollTop(),r=this.$element.offset(),i=this.options.offset,s=i.bottom,o=i.top,u="affix affix-top affix-bottom",a;typeof i!="object"&&(s=o=i),typeof o=="function"&&(o=i.top()),typeof s=="function"&&(s=i.bottom()),a=this.unpin!=null&&n+this.unpin<=r.top?!1:s!=null&&r.top+this.$element.height()>=t-s?"bottom":o!=null&&n<=o?"top":!1;if(this.affixed===a)return;this.affixed=a,this.unpin=a=="bottom"?r.top-n:null,this.$element.removeClass(u).addClass("affix"+(a?"-"+a:""))};var n=e.fn.affix;e.fn.affix=function(n){return this.each(function(){var r=e(this),i=r.data("affix"),s=typeof n=="object"&&n;i||r.data("affix",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.affix.Constructor=t,e.fn.affix.defaults={offset:0},e.fn.affix.noConflict=function(){return e.fn.affix=n,this},e(window).on("load",function(){e('[data-spy="affix"]').each(function(){var t=e(this),n=t.data();n.offset=n.offset||{},n.offsetBottom&&(n.offset.bottom=n.offsetBottom),n.offsetTop&&(n.offset.top=n.offsetTop),t.affix(n)})})}(window.jQuery);
|
Binary file
|
data/lib/smart_monkey.rb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
module UIAutoMonkey
|
4
|
+
module CommandHelper
|
5
|
+
require 'open3'
|
6
|
+
|
7
|
+
def shell(cmds)
|
8
|
+
puts "Shell: #{cmds.inspect}"
|
9
|
+
Open3.popen3(*cmds) do |stdin, stdout, stderr|
|
10
|
+
stdin.close
|
11
|
+
return stdout.read
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# def run_process(cmds)
|
16
|
+
# puts "Run: #{cmds.inspect}"
|
17
|
+
# Kernel.system(cmds[0], *cmds[1..-1])
|
18
|
+
# end
|
19
|
+
|
20
|
+
def relaunch_app(device,app)
|
21
|
+
`idevicedebug -u #{device} run #{app} >/dev/null 2>&1 &`
|
22
|
+
end
|
23
|
+
|
24
|
+
def run_process(cmds)
|
25
|
+
puts "Run: #{cmds.inspect}"
|
26
|
+
device = cmds[2]
|
27
|
+
app = cmds[-7]
|
28
|
+
Open3.popen3(*cmds) do |stdin, stdout, stderr, thread|
|
29
|
+
@tmpline = ""
|
30
|
+
stdin.close
|
31
|
+
app_hang_monitor_thread = Thread.start{
|
32
|
+
sleep 30
|
33
|
+
while true
|
34
|
+
current_line = @tmpline
|
35
|
+
sleep 30
|
36
|
+
after_sleep_line = @tmpline
|
37
|
+
if current_line == after_sleep_line
|
38
|
+
puts "WARN: Application go to background! Auto-Re-Launch app!"
|
39
|
+
relaunch_app(device, app)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
}
|
43
|
+
instruments_stderr_thread = Thread.start{
|
44
|
+
stderr.each do |line|
|
45
|
+
puts line
|
46
|
+
end
|
47
|
+
}
|
48
|
+
stdout.each do |line|
|
49
|
+
@tmpline = line.strip
|
50
|
+
puts @tmpline
|
51
|
+
if @tmpline =~ /MonkeyTest finish/
|
52
|
+
app_hang_monitor_thread.kill
|
53
|
+
end
|
54
|
+
end
|
55
|
+
app_hang_monitor_thread.kill
|
56
|
+
instruments_stderr_thread.kill
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def kill_all(process_name, signal=nil)
|
61
|
+
signal = signal ? "-#{signal}" : ''
|
62
|
+
# puts "killall #{signal} #{process_name}"
|
63
|
+
Kernel.system("killall #{signal} '#{process_name}' >/dev/null 2>&1")
|
64
|
+
end
|
65
|
+
|
66
|
+
def xcode_path
|
67
|
+
@xcode_path ||= shell(%w(xcode-select -print-path)).strip
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,549 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
module UIAutoMonkey
|
4
|
+
require 'fileutils'
|
5
|
+
require 'timeout'
|
6
|
+
require 'rexml/document'
|
7
|
+
require 'erubis'
|
8
|
+
require 'json'
|
9
|
+
|
10
|
+
class MonkeyRunner
|
11
|
+
TRACE_TEMPLATE='/Applications/Xcode.app/Contents/Applications/Instruments.app/Contents/PlugIns/AutomationInstrument.xrplugin/Contents/Resources/Automation.tracetemplate'
|
12
|
+
RESULT_BASE_PATH = File.expand_path('smart_monkey_result')
|
13
|
+
INSTRUMENTS_TRACE_PATH = File.expand_path('*.trace')
|
14
|
+
TIME_STAP = Time.new.strftime("%Y%m%d%H%M%S")
|
15
|
+
|
16
|
+
include UIAutoMonkey::CommandHelper
|
17
|
+
|
18
|
+
def run(opts)
|
19
|
+
@options = opts
|
20
|
+
res_dir = @options[:result_base_dir] || RESULT_BASE_PATH
|
21
|
+
|
22
|
+
puts "INSTRUMENTS_TRACE_PATH : #{INSTRUMENTS_TRACE_PATH}"
|
23
|
+
puts "RESULT_BASE_PATH : #{res_dir}"
|
24
|
+
|
25
|
+
if @options[:show_config]
|
26
|
+
show_config
|
27
|
+
return true
|
28
|
+
elsif @options[:list_app]
|
29
|
+
list_app
|
30
|
+
return true
|
31
|
+
elsif @options[:list_devices]
|
32
|
+
list_devices
|
33
|
+
return true
|
34
|
+
elsif @options[:reset_iphone_simulator]
|
35
|
+
reset_iphone_simulator
|
36
|
+
return true
|
37
|
+
end
|
38
|
+
###########
|
39
|
+
log @options.inspect
|
40
|
+
FileUtils.remove_dir(result_base_dir, true)
|
41
|
+
FileUtils.makedirs(result_base_dir)
|
42
|
+
generate_ui_auto_monkey
|
43
|
+
###########
|
44
|
+
start_time = Time.new.strftime("%Y-%m-%d %H:%M:%S")
|
45
|
+
result_list = []
|
46
|
+
total_test_count.times do |times|
|
47
|
+
@times = times
|
48
|
+
setup_running
|
49
|
+
result = run_a_case
|
50
|
+
finish_running
|
51
|
+
result_list << result
|
52
|
+
end
|
53
|
+
create_index_html({
|
54
|
+
:start_time => start_time,
|
55
|
+
:end_time => Time.new.strftime("%Y-%m-%d %H:%M:%S"),
|
56
|
+
:result_list => result_list,
|
57
|
+
:ProductType => product_type(device),
|
58
|
+
:ProductVersion => product_version(device),
|
59
|
+
:UniqueDeviceID => device,
|
60
|
+
:DeviceName => device_name(device),
|
61
|
+
:Application => app_path
|
62
|
+
})
|
63
|
+
all_tests_ok?(result_list)
|
64
|
+
end
|
65
|
+
|
66
|
+
def setup_running
|
67
|
+
kill_all_need
|
68
|
+
# kill_all('iPhone Simulator')
|
69
|
+
FileUtils.remove_dir(result_dir, true)
|
70
|
+
ENV['UIARESULTSPATH'] = result_dir
|
71
|
+
@crashed = false
|
72
|
+
@no_run = false
|
73
|
+
@uia_trace = false
|
74
|
+
end
|
75
|
+
|
76
|
+
def run_a_case
|
77
|
+
log "=================================== Start Test (#{@times+1}/#{total_test_count}) ======================================="
|
78
|
+
FileUtils.makedirs(crash_save_dir(@times+1)) unless File.exists?(crash_save_dir(@times+1))
|
79
|
+
pull_crash_from_iphone(@times+1)
|
80
|
+
cr_list = crash_report_list(@times+1)
|
81
|
+
start_time = Time.now
|
82
|
+
watch_syslog do
|
83
|
+
begin
|
84
|
+
unless time_limit_sec.nil?
|
85
|
+
run_process(%W(instruments -w #{device} -l #{time_limit} -t #{TRACE_TEMPLATE} #{app_path} -e UIASCRIPT #{ui_custom_path} -e UIARESULTSPATH #{result_base_dir}))
|
86
|
+
else
|
87
|
+
run_process(%W(instruments -w #{device} -t #{TRACE_TEMPLATE} #{app_path} -e UIASCRIPT #{ui_custom_path} -e UIARESULTSPATH #{result_base_dir}))
|
88
|
+
end
|
89
|
+
rescue Timeout::Error
|
90
|
+
kill_all('instruments', '9')
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
pull_crash_from_iphone(@times+1)
|
95
|
+
new_cr_list = crash_report_list(@times+1)
|
96
|
+
# increase crash report?
|
97
|
+
diff_cr_list = new_cr_list - cr_list
|
98
|
+
|
99
|
+
if diff_cr_list.size > 0
|
100
|
+
@crashed = true
|
101
|
+
new_cr_name = File.basename(diff_cr_list[0]).gsub(/\.ips$/, '.crash')
|
102
|
+
new_cr_path = File.join(result_dir, new_cr_name)
|
103
|
+
log "Find new crash report: #{new_cr_path}"
|
104
|
+
if dsym_base_path != ''
|
105
|
+
puts "Symbolicating crash report..."
|
106
|
+
symbolicating_crash_report(diff_cr_list[0])
|
107
|
+
end
|
108
|
+
FileUtils.cp diff_cr_list[0], new_cr_path
|
109
|
+
end
|
110
|
+
# output result
|
111
|
+
create_result_html(parse_results)
|
112
|
+
|
113
|
+
{
|
114
|
+
:start_time => start_time,
|
115
|
+
:end_time => Time.now,
|
116
|
+
:times => @times,
|
117
|
+
:ok => !@crashed && !@no_run,
|
118
|
+
:crash => @crashed,
|
119
|
+
:result_dir => File.basename(result_history_dir(@times)),
|
120
|
+
:message => nil
|
121
|
+
}
|
122
|
+
end
|
123
|
+
|
124
|
+
def finish_running
|
125
|
+
kill_all_need
|
126
|
+
FileUtils.remove_dir(result_history_dir(@times), true)
|
127
|
+
FileUtils.remove_dir(crash_save_dir(@times+1), true)
|
128
|
+
FileUtils.move(result_dir, result_history_dir(@times))
|
129
|
+
if @options[:compress_rate]
|
130
|
+
compress_image(result_history_dir(@times))
|
131
|
+
end
|
132
|
+
rm_instruments_trace(INSTRUMENTS_TRACE_PATH)
|
133
|
+
kill_all('iPhone Simulator')
|
134
|
+
sleep 3
|
135
|
+
end
|
136
|
+
|
137
|
+
def create_index_html(result_hash)
|
138
|
+
er = Erubis::Eruby.new(File.read(template_path('index.html.erb')))
|
139
|
+
result_hash[:test_count] = result_hash[:result_list].size
|
140
|
+
result_hash[:ok_count] = result_hash[:result_list].select {|r| r[:ok]}.size
|
141
|
+
result_hash[:cr_count] = result_hash[:result_list].select {|r| r[:crash]}.size
|
142
|
+
result_hash[:nr_count] = result_hash[:test_count] - result_hash[:ok_count] - result_hash[:cr_count]
|
143
|
+
open("#{result_base_dir}/index.html", 'w') {|f| f.write er.result(result_hash)}
|
144
|
+
copy_html_resources
|
145
|
+
puts "Monkey Test Report:#{result_base_dir}/index.html"
|
146
|
+
end
|
147
|
+
|
148
|
+
def copy_html_resources
|
149
|
+
bootstrap_dir = File.expand_path('../../bootstrap', __FILE__)
|
150
|
+
FileUtils.copy("#{bootstrap_dir}/css/bootstrap.css", result_base_dir)
|
151
|
+
FileUtils.copy("#{bootstrap_dir}/js/bootstrap.js", result_base_dir)
|
152
|
+
end
|
153
|
+
|
154
|
+
def all_tests_ok?(result_list)
|
155
|
+
result_list.select {|r| !r[:ok]}.empty?
|
156
|
+
end
|
157
|
+
|
158
|
+
def show_config
|
159
|
+
puts File.read(config_custom_path)
|
160
|
+
end
|
161
|
+
|
162
|
+
def show_extend_javascript
|
163
|
+
if @options[:extend_javascript_path]
|
164
|
+
filename = @options[:extend_javascript_path]
|
165
|
+
return File.exist?(filename), filename
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def list_app
|
170
|
+
puts "============For iPhone Simulator:"
|
171
|
+
puts find_apps('*.app').map{|n| File.basename n}.uniq.sort.join("\n")
|
172
|
+
puts "============For iPhone Device:"
|
173
|
+
if device
|
174
|
+
puts `ideviceinstaller -u #{device} -l`
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
def list_devices
|
179
|
+
puts devices.join("\n")
|
180
|
+
end
|
181
|
+
|
182
|
+
def log(msg)
|
183
|
+
puts msg
|
184
|
+
end
|
185
|
+
|
186
|
+
def reset_iphone_simulator
|
187
|
+
FileUtils.rm_rf("#{Dir.home}/Library/Application\ Support/iPhone\ Simulator/")
|
188
|
+
puts 'reset iPhone Simulator successful'
|
189
|
+
end
|
190
|
+
|
191
|
+
def total_test_count
|
192
|
+
(@options[:run_count] || 2)
|
193
|
+
end
|
194
|
+
|
195
|
+
def device
|
196
|
+
@options[:device] || (devices[0].strip.split("[")[1].delete "]")
|
197
|
+
end
|
198
|
+
|
199
|
+
def app_path
|
200
|
+
@app_path ||= find_app_path(@options)
|
201
|
+
end
|
202
|
+
|
203
|
+
def app_name
|
204
|
+
File.basename(app_path).gsub(/\.app$/, '')
|
205
|
+
end
|
206
|
+
|
207
|
+
def find_apps(app)
|
208
|
+
`"ls" -dt #{ENV['HOME']}/Library/Developer/Xcode/DerivedData/*/Build/Products/*/#{app}`.strip.split(/\n/)
|
209
|
+
end
|
210
|
+
|
211
|
+
def devices
|
212
|
+
`"instruments" -s devices`.strip.split(/\n/).drop(2)
|
213
|
+
end
|
214
|
+
|
215
|
+
def product_type(device)
|
216
|
+
product_hash={
|
217
|
+
"iPhone7,2"=>"iPhone 6",
|
218
|
+
"iPhone7,1"=>"iPhone 6 Plus",
|
219
|
+
"iPhone6,2"=>"iPhone 5S (CDMA)",
|
220
|
+
"iPhone6,1"=>"iPhone 5S (GSM)",
|
221
|
+
"iPhone5,4"=>"iPhone 5C (CDMA)",
|
222
|
+
"iPhone5,3"=>"iPhone 5C (GSM)",
|
223
|
+
"iPhone5,2"=>"iPhone 5",
|
224
|
+
"iPhone5,1"=>"iPhone 5",
|
225
|
+
"iPhone4,1"=>"iPhone 4S",
|
226
|
+
"iPhone3,2"=>"iPhone 4 - CDMA",
|
227
|
+
"iPhone3,1"=>"iPhone 4 - GSM",
|
228
|
+
"iPhone2,1"=>"iPhone 3GS",
|
229
|
+
"iPhone1,2"=>"iPhone 3G",
|
230
|
+
"iPhone1,1"=>"iPhone",
|
231
|
+
}
|
232
|
+
type=`ideviceinfo -u #{device} -k ProductType`.strip
|
233
|
+
product_hash[type]
|
234
|
+
end
|
235
|
+
|
236
|
+
def product_version(device)
|
237
|
+
`ideviceinfo -u #{device} -k ProductVersion`.strip
|
238
|
+
end
|
239
|
+
|
240
|
+
def device_name(device)
|
241
|
+
`ideviceinfo -u #{device} -k DeviceName`.strip
|
242
|
+
end
|
243
|
+
|
244
|
+
def compress_image(path)
|
245
|
+
puts 'Compress screenshot images...'
|
246
|
+
compress_rate = @options[:compress_rate]
|
247
|
+
# `find #{path} -name "*.png" -exec convert {} -resize 50% -sample 50% {} \\\;`
|
248
|
+
`mogrify -resize #{compress_rate} "#{path}/*.png"`
|
249
|
+
end
|
250
|
+
|
251
|
+
def kill_all_need
|
252
|
+
kill_all('instruments', '9')
|
253
|
+
kill_all('Instruments', '9')
|
254
|
+
kill_all('idevicedebug', '9')
|
255
|
+
end
|
256
|
+
|
257
|
+
def find_app_path(opts)
|
258
|
+
app_path = nil
|
259
|
+
if opts[:app_path].include?('/')
|
260
|
+
app_path = File.expand_path(opts[:app_path])
|
261
|
+
elsif opts[:app_path] =~ /\.app$/
|
262
|
+
apps = find_apps(opts[:app_path])
|
263
|
+
app_path = apps[0]
|
264
|
+
log "#{apps.size} apps are found, USE NEWEST APP: #{app_path}" if apps.size > 1
|
265
|
+
else
|
266
|
+
app_path = opts[:app_path]
|
267
|
+
log "BundleID was found: #{app_path}"
|
268
|
+
end
|
269
|
+
|
270
|
+
unless app_path
|
271
|
+
raise 'Invalid AppName'
|
272
|
+
end
|
273
|
+
app_path
|
274
|
+
end
|
275
|
+
|
276
|
+
def time_limit
|
277
|
+
time_limit_sec * 1000
|
278
|
+
end
|
279
|
+
|
280
|
+
def time_limit_sec
|
281
|
+
@options[:time_limit_sec]
|
282
|
+
end
|
283
|
+
|
284
|
+
def deviceconsole_original_path
|
285
|
+
File.expand_path('../../ios_device_log/deviceconsole', __FILE__)
|
286
|
+
end
|
287
|
+
|
288
|
+
def ui_auto_monkey_original_path
|
289
|
+
File.expand_path('../../ui-auto-monkey/UIAutoMonkey.js', __FILE__)
|
290
|
+
end
|
291
|
+
|
292
|
+
def ui_custom_original_path
|
293
|
+
File.expand_path('../../ui-auto-monkey/custom.js', __FILE__)
|
294
|
+
end
|
295
|
+
|
296
|
+
def ui_hole_handler_original_path
|
297
|
+
File.expand_path('../../ui-auto-monkey/handler', __FILE__)
|
298
|
+
end
|
299
|
+
|
300
|
+
def ui_tuneup_original_path
|
301
|
+
File.expand_path('../../ui-auto-monkey/tuneup', __FILE__)
|
302
|
+
end
|
303
|
+
|
304
|
+
def ui_auto_monkey_path
|
305
|
+
"#{result_base_dir}/UIAutoMonkey.js"
|
306
|
+
end
|
307
|
+
|
308
|
+
def ui_custom_path
|
309
|
+
"#{result_base_dir}/custom.js"
|
310
|
+
end
|
311
|
+
|
312
|
+
def dsym_base_path
|
313
|
+
@options[:dsym_file_path] || ""
|
314
|
+
end
|
315
|
+
|
316
|
+
def xcode_developer_path
|
317
|
+
`xcode-select --print-path`.strip
|
318
|
+
end
|
319
|
+
|
320
|
+
def xcode_path
|
321
|
+
`dirname #{xcode_developer_path}`.strip
|
322
|
+
end
|
323
|
+
|
324
|
+
def symbolicatecrash_base_path()
|
325
|
+
`find #{xcode_path} -name symbolicatecrash`.strip
|
326
|
+
end
|
327
|
+
|
328
|
+
def symbolicating_crash_report(crash_base_path)
|
329
|
+
`DEVELOPER_DIR=#{xcode_developer_path} #{symbolicatecrash_base_path} -o #{crash_base_path} #{crash_base_path} #{dsym_base_path};wait;`
|
330
|
+
end
|
331
|
+
|
332
|
+
def result_base_dir
|
333
|
+
File.join(@options[:result_base_dir] || RESULT_BASE_PATH, "report_#{TIME_STAP}")
|
334
|
+
end
|
335
|
+
|
336
|
+
def crash_save_dir(times)
|
337
|
+
"#{result_base_dir}/crash_#{times}"
|
338
|
+
end
|
339
|
+
|
340
|
+
def result_dir
|
341
|
+
"#{result_base_dir}/Run 1"
|
342
|
+
end
|
343
|
+
|
344
|
+
def result_history_dir(times)
|
345
|
+
"#{result_base_dir}/result_#{sprintf('%03d', times)}"
|
346
|
+
end
|
347
|
+
|
348
|
+
def crash_report_dir
|
349
|
+
"#{ENV['HOME']}/Library/Logs/DiagnosticReports"
|
350
|
+
end
|
351
|
+
|
352
|
+
def pull_crash_from_iphone(times)
|
353
|
+
`idevicecrashreport -u #{device} -e -k #{crash_save_dir(times)}`
|
354
|
+
end
|
355
|
+
|
356
|
+
def crash_report_list(times)
|
357
|
+
# ios version >7.0 => *.ips
|
358
|
+
`ls -t #{crash_save_dir(times)}/*.crash 2>&1;ls -t #{crash_save_dir(times)}/*.ips 2>&1;`.strip.split(/\n/)
|
359
|
+
# `ls -t #{crash_save_dir}/#{app_name}_*.crash`.strip.split(/\n/)
|
360
|
+
end
|
361
|
+
|
362
|
+
def rm_instruments_trace(traces)
|
363
|
+
`rm -rf #{traces}`
|
364
|
+
end
|
365
|
+
|
366
|
+
def grep_syslog
|
367
|
+
'tail -n 0 -f /var/log/system.log'
|
368
|
+
end
|
369
|
+
|
370
|
+
def grep_ios_syslog
|
371
|
+
"#{deviceconsole_original_path} -u #{device}"
|
372
|
+
end
|
373
|
+
|
374
|
+
def console_log_path
|
375
|
+
"#{result_dir}/console.txt"
|
376
|
+
end
|
377
|
+
|
378
|
+
def uiautomation_xsl_path
|
379
|
+
File.expand_path("../templates/automation_result.xsl", __FILE__)
|
380
|
+
end
|
381
|
+
|
382
|
+
def template_path(name)
|
383
|
+
File.expand_path("../templates/#{name}", __FILE__)
|
384
|
+
end
|
385
|
+
|
386
|
+
def parse_uiautomation_plist
|
387
|
+
`xsltproc --output "#{result_dir}/uiautomation.html" #{uiautomation_xsl_path} "#{result_dir}/Automation Results.plist"`
|
388
|
+
end
|
389
|
+
|
390
|
+
def generate_ui_auto_monkey
|
391
|
+
# extend_javascript_flag, extend_javascript_path = show_extend_javascript
|
392
|
+
# orig = File.read(ui_custom_original_path)
|
393
|
+
# config = JSON.parse(File.read(config_json_path))
|
394
|
+
# replace_str = " this.config = #{JSON.pretty_generate(config, :indent => ' '*6)}; \n"
|
395
|
+
# js = replace_text(orig, replace_str, '__UIAutoMonkey Configuration Begin__', '__UIAutoMonkey Configuration End__')
|
396
|
+
# if extend_javascript_flag
|
397
|
+
# js = File.read(extend_javascript_path) + "\n" + js
|
398
|
+
# end
|
399
|
+
# File.open(ui_custom_path, 'w') {|f| f.write(js)}
|
400
|
+
FileUtils.copy(config_custom_path, result_base_dir)
|
401
|
+
FileUtils.copy(ui_auto_monkey_original_path, result_base_dir)
|
402
|
+
FileUtils.cp_r(ui_hole_handler_original_path, result_base_dir)
|
403
|
+
FileUtils.cp_r(ui_tuneup_original_path, result_base_dir)
|
404
|
+
# FileUtils.copy("#{bootstrap_dir}/js/bootstrap.js", result_base_dir)
|
405
|
+
end
|
406
|
+
|
407
|
+
def config_custom_path
|
408
|
+
@options[:custom_path] || ui_custom_original_path
|
409
|
+
end
|
410
|
+
|
411
|
+
def replace_text(orig, replace_str, marker_begin_line, marker_end_line)
|
412
|
+
results = []
|
413
|
+
status = 1
|
414
|
+
orig.each_line do |line|
|
415
|
+
if status == 1 && line =~ /#{marker_begin_line}/
|
416
|
+
status = 2
|
417
|
+
results << line
|
418
|
+
results << replace_str
|
419
|
+
elsif status == 2 && line =~/#{marker_end_line}/
|
420
|
+
status = 3
|
421
|
+
end
|
422
|
+
results << line unless status == 2
|
423
|
+
end
|
424
|
+
results.join('')
|
425
|
+
end
|
426
|
+
|
427
|
+
def parse_results
|
428
|
+
filename = "#{result_dir}/Automation Results.plist"
|
429
|
+
log_list = []
|
430
|
+
if File.exists?(filename)
|
431
|
+
doc = REXML::Document.new(open(filename))
|
432
|
+
doc.elements.each('plist/dict/array/dict') do |record|
|
433
|
+
ary = record.elements.to_a.map{|a| a.text}
|
434
|
+
log_list << Hash[*ary]
|
435
|
+
end
|
436
|
+
parse_uiautomation_plist
|
437
|
+
@uia_trace = true
|
438
|
+
end
|
439
|
+
@no_run = true if log_list.empty? || log_list[-1][MESSAGE] =~ /target application is not frontmost/
|
440
|
+
log_list
|
441
|
+
end
|
442
|
+
|
443
|
+
def create_result_html(log_list)
|
444
|
+
latest_list = LogDecoder.new(log_list).decode_latest(@options[:detail_event_count], @options[:drop_useless_img], result_dir)
|
445
|
+
hash = {}
|
446
|
+
hash[:log_list] = latest_list.reverse
|
447
|
+
hash[:log_list_json] = JSON.dump(hash[:log_list])
|
448
|
+
crash_report = Dir.glob("#{result_dir}/*.crash")[0]
|
449
|
+
hash[:crash_report] = crash_report ? File.basename(crash_report) : nil
|
450
|
+
hash[:uia_trace] = @uia_trace
|
451
|
+
hash[:crashed] = @crashed
|
452
|
+
hash[:no_run] = @no_run
|
453
|
+
|
454
|
+
er = Erubis::Eruby.new(File.read(template_path('result.html.erb')))
|
455
|
+
open("#{result_dir}/result.html", 'w') do |f|
|
456
|
+
f.write(er.result(hash))
|
457
|
+
end
|
458
|
+
FileUtils.copy(template_path('result_view.js'), "#{result_dir}/result_view.js")
|
459
|
+
end
|
460
|
+
|
461
|
+
def watch_syslog
|
462
|
+
STDOUT.sync = true
|
463
|
+
puts "Attempting iOS device system log capture via deviceconsole."
|
464
|
+
stdin, stdout, stderr = Open3.popen3(grep_ios_syslog)
|
465
|
+
log_filename = "#{result_base_dir}/console.txt"
|
466
|
+
thread = Thread.new do
|
467
|
+
File.open(log_filename, 'a') do |output|
|
468
|
+
begin
|
469
|
+
while true
|
470
|
+
line = stdout.readline
|
471
|
+
output.write(line)
|
472
|
+
# output.write(line) if line.include?(app_name)
|
473
|
+
end
|
474
|
+
rescue IOError
|
475
|
+
log 'Stop iOS system log capture.'
|
476
|
+
kill_all_need
|
477
|
+
end
|
478
|
+
end
|
479
|
+
end
|
480
|
+
yield
|
481
|
+
sleep 3
|
482
|
+
stdout.close; stderr.close; stdin.close
|
483
|
+
thread.join
|
484
|
+
FileUtils.makedirs(result_dir) unless File.exists?(result_dir)
|
485
|
+
if File.exists?(log_filename)
|
486
|
+
FileUtils.move(log_filename, console_log_path)
|
487
|
+
end
|
488
|
+
end
|
489
|
+
end
|
490
|
+
|
491
|
+
LOG_TYPE = 'LogType'
|
492
|
+
MESSAGE = 'Message'
|
493
|
+
TIMESTAMP = 'Timestamp'
|
494
|
+
SCREENSHOT = 'Screenshot'
|
495
|
+
|
496
|
+
class LogDecoder
|
497
|
+
def initialize(log_list)
|
498
|
+
@log_list = log_list
|
499
|
+
end
|
500
|
+
|
501
|
+
def rm_unused_imgs(used_imgs, dir)
|
502
|
+
used_strs = used_imgs.join("\\|")
|
503
|
+
`cd "#{dir}";find . -type 'f' -name '*.png' | grep -v "#{used_strs}" | xargs rm`
|
504
|
+
end
|
505
|
+
|
506
|
+
def decode_latest(num=10, drop_useless_img, drop_dir)
|
507
|
+
hash = {}
|
508
|
+
ret = []
|
509
|
+
used_imgs = []
|
510
|
+
@log_list.reverse.each do |log|
|
511
|
+
break if num == 0
|
512
|
+
if log[LOG_TYPE] == 'Screenshot'
|
513
|
+
if log[MESSAGE] =~ /^action/
|
514
|
+
hash[:action_image] = log[MESSAGE]
|
515
|
+
elsif log[MESSAGE] =~ /^monkey/
|
516
|
+
hash[:screen_image] = log[MESSAGE]
|
517
|
+
used_imgs << log[MESSAGE]
|
518
|
+
hash[:timestamp] = log[TIMESTAMP]
|
519
|
+
|
520
|
+
# emit and init
|
521
|
+
if block_given?
|
522
|
+
yield(hash)
|
523
|
+
else
|
524
|
+
ret << hash
|
525
|
+
end
|
526
|
+
hash = {}
|
527
|
+
num -= 1
|
528
|
+
end
|
529
|
+
elsif log[LOG_TYPE] == 'Debug' && log[MESSAGE] =~ /^target./
|
530
|
+
hash[:message] = log[MESSAGE] unless log[MESSAGE] =~ /^target.captureRectWithName/ && log[MESSAGE] =~ /switcherScrollView/
|
531
|
+
# elsif log[LOG_TYPE] == 'Default' && log[MESSAGE] =~ /^DeviceInfo/
|
532
|
+
# hash[:screen_size] = log[MESSAGE]
|
533
|
+
end
|
534
|
+
end
|
535
|
+
#drop unused imgs
|
536
|
+
if drop_useless_img
|
537
|
+
puts "Drop useless images..."
|
538
|
+
rm_unused_imgs(used_imgs, drop_dir)
|
539
|
+
end
|
540
|
+
if !@log_list.empty?
|
541
|
+
#add screen_size
|
542
|
+
hash = {}
|
543
|
+
hash[:screen_size] = @log_list[0][MESSAGE]
|
544
|
+
ret << hash
|
545
|
+
end
|
546
|
+
ret
|
547
|
+
end
|
548
|
+
end
|
549
|
+
end
|