diff --git a/lib/plugins/analysisStorer.js b/lib/plugins/analysisStorer.js index ed8635c8e..518583168 100644 --- a/lib/plugins/analysisStorer.js +++ b/lib/plugins/analysisStorer.js @@ -7,7 +7,7 @@ let Promise = require('bluebird'), Promise.promisifyAll(fs); function shouldIgnoreMessage(message) { - return ['url', 'error', 'summarize'].indexOf(message.type) >= 0; + return ['url', 'error', 'summarize','browsertime.screenshot'].indexOf(message.type) >= 0; } module.exports = { diff --git a/lib/plugins/browsertime/index.js b/lib/plugins/browsertime/index.js index d166edc68..f64fd1f9f 100644 --- a/lib/plugins/browsertime/index.js +++ b/lib/plugins/browsertime/index.js @@ -158,7 +158,7 @@ module.exports = { run.har.log.pages[0].pageTimings._firstPaint = run.timings.firstPaint; results.har.log.pages[runIndex].pageTimings._firstPaint = run.timings.firstPaint; } - + // Kind of ugly way to add visualMetrics to a run // it's outside of browserScripts today // we could instead pass browsertime.visualMetrics maybe @@ -182,6 +182,13 @@ module.exports = { })); } }) + .tap((results) => { + if (results.screenshots) { + queue.postMessage(make('browsertime.screenshot', results.screenshots, { + url + })); + } + }) .catch(BrowsertimeError, (e) => { log.error('%s generated the following error in Browsertime %s', url, e); queue.postMessage(make('error', e.message, merge({url}, e.extra))); diff --git a/lib/plugins/html/assets/css/index.css b/lib/plugins/html/assets/css/index.css index cac40867e..9e77bf571 100644 --- a/lib/plugins/html/assets/css/index.css +++ b/lib/plugins/html/assets/css/index.css @@ -1387,3 +1387,9 @@ svg.water-fall-chart { display: table; clear: both; } +.screenshot { + padding: 4px; + background-color: #fff; + border: 1px solid #ddd; + border-radius: 4px; } + diff --git a/lib/plugins/html/assets/css/index.min.css b/lib/plugins/html/assets/css/index.min.css index dc20356be..f47c53140 100644 --- a/lib/plugins/html/assets/css/index.min.css +++ b/lib/plugins/html/assets/css/index.min.css @@ -1 +1 @@ -/*! normalize.css v4.1.1 | MIT License | github.com/necolas/normalize.css */progress,sub,sup{vertical-align:baseline}ol,ul{margin-top:0;padding-left:0}button,hr,input{overflow:visible}article,aside,details,figcaption,figure,footer,header,label,legend,main,menu,nav,section,summary{display:block}.column,.columns,.container{width:100%;box-sizing:border-box}h1,h2,h3{letter-spacing:-.1rem}code,tr:nth-child(odd){background:#fafafa}*,.column,.columns,.container,:after,:before,legend{box-sizing:border-box}html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}audio,canvas,progress,video{display:inline-block}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent;-webkit-text-decoration-skip:objects;color:#0095d2}a:active,a:hover{outline-width:0}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}.button,.nav a{text-decoration:none}b,strong{font-weight:bolder}dfn{font-style:italic}h1{margin:.67em 0}mark{background-color:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}svg:not(:root){overflow:hidden}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}figure{margin:1em 40px 2.5rem}button,input,optgroup,select,textarea{font:inherit;margin:0}.info-overlay-holder .requestID,.label,.summarynumber,.time-scale text,optgroup{font-weight:700}button,select{text-transform:none}.button,ul.menu{text-transform:uppercase}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:ButtonText dotted 1px}fieldset{border:1px solid silver;margin:0 2px}legend{color:inherit;max-width:100%;padding:0;white-space:normal}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-input-placeholder{color:inherit;opacity:.54}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}body,h6{line-height:1.6}form,ol,ul{margin-bottom:2.5rem}ul{list-style:circle inside}ol ol,ol ul,ul ol,ul ul{margin:1.5rem 0 1.5rem 3rem;font-size:.9rem}ol{list-style:decimal inside}.nav ul,ul.menu{list-style:none}li{margin-bottom:1rem}footer{text-align:center}hr{box-sizing:content-box;height:0;margin-top:3rem;margin-bottom:3.5rem;border-width:0;border-top:1px solid #e1e1e1}fieldset,input,select,textarea{margin-bottom:1.5rem}input[type=url],input[type=password],input[type=number],input[type=search],input[type=email],input[type=text],input[type=tel],select,textarea{height:38px;padding:6px 10px;background-color:#fff;border:1px solid #e1e1e1;border-radius:4px;box-shadow:none}input[type=url],input[type=password],input[type=number],input[type=search],input[type=email],input[type=text],input[type=tel]{-webkit-appearance:none;-moz-appearance:none;appearance:none}textarea{overflow:auto;-webkit-appearance:none;-moz-appearance:none;appearance:none;min-height:65px;padding-top:6px;padding-bottom:6px}input[type=url]:focus,input[type=password]:focus,input[type=number]:focus,input[type=search]:focus,input[type=email]:focus,input[type=text]:focus,input[type=tel]:focus,select:focus,textarea:focus{border:1px solid #0095d2;outline:0}label,legend{margin-bottom:.5rem;font-weight:600}fieldset{padding:0;border-width:0}input[type=checkbox],input[type=radio]{display:inline}label>.label-body{display:inline-block;margin-left:.5rem;font-weight:400}.container:after,.row:after{content:"";display:table;clear:both}.container{position:relative;max-width:960px;margin:0 auto;padding:0 20px}blockquote,dl,p,pre,table{margin-bottom:2.5rem}.column,.columns{float:left}@media (min-width:400px){.container{width:85%;padding:0}}@media (min-width:550px){.container{width:80%}.column,.columns{margin-left:4%}.column:first-child,.columns:first-child{margin-left:0}.one.column,.one.columns{width:4.66666666667%}.two.columns{width:13.3333333333%}.three.columns{width:22%}.four.columns{width:30.6666666667%}.five.columns{width:39.3333333333%}.six.columns{width:48%}.seven.columns{width:56.6666666667%}.eight.columns{width:65.3333333333%}.nine.columns{width:74%}.ten.columns{width:82.6666666667%}.eleven.columns{width:91.3333333333%}.twelve.columns{width:100%;margin-left:0}.one-third.column{width:30.6666666667%}.two-thirds.column{width:65.3333333333%}.one-half.column{width:48%}.offset-by-one.column,.offset-by-one.columns{margin-left:8.66666666667%}.offset-by-two.column,.offset-by-two.columns{margin-left:17.3333333333%}.offset-by-three.column,.offset-by-three.columns{margin-left:26%}.offset-by-four.column,.offset-by-four.columns{margin-left:34.6666666667%}.offset-by-five.column,.offset-by-five.columns{margin-left:43.3333333333%}.offset-by-six.column,.offset-by-six.columns{margin-left:52%}.offset-by-seven.column,.offset-by-seven.columns{margin-left:60.6666666667%}.offset-by-eight.column,.offset-by-eight.columns{margin-left:69.3333333333%}.offset-by-nine.column,.offset-by-nine.columns{margin-left:78%}.offset-by-ten.column,.offset-by-ten.columns{margin-left:86.6666666667%}.offset-by-eleven.column,.offset-by-eleven.columns{margin-left:95.3333333333%}.offset-by-one-third.column,.offset-by-one-third.columns{margin-left:34.6666666667%}.offset-by-two-thirds.column,.offset-by-two-thirds.columns{margin-left:69.3333333333%}.offset-by-one-half.column,.offset-by-one-half.columns{margin-left:52%}}table{width:100%;border-collapse:separate;border-spacing:1px;background-color:#e1e1e1}td,th{padding:4px 1rem;vertical-align:top;text-align:left}td:first-child,th:first-child{padding-left:1rem}td:last-child,th:last-child{padding-right:1rem}tr:nth-child(even){background:#fff}th{background:#f1fbff}td.number{text-align:right}td.url{overflow-wrap:break-word;word-wrap:break-word;-webkit-hyphens:auto;-ms-hyphens:auto;-moz-hyphens:auto;hyphens:auto}td.assetsurl{max-width:400px}td.pagesurl{max-width:350px}td.offendingurl{max-width:900px}@media only screen and (max-width:800px){.responsive table,.responsive tbody,.responsive td,.responsive th,.responsive thead,.responsive tr{display:block}.hidden-small,.responsive tr.u-hideable{display:none}.responsive thead tr{position:absolute;top:-9999px;left:-9999px}.responsive tr{border:4px solid #e1e1e1}.responsive td{border:none;border-bottom:1px solid #e1e1e1;position:relative;padding-left:50%;white-space:normal;text-align:left;max-width:none}.responsive td:before{position:absolute;top:6px;left:6px;width:30%;padding-right:10px;white-space:nowrap;text-align:left;font-weight:700;content:attr(data-title)}}html{font-size:15px}body{font-size:1em;font-weight:400;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;color:#222}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:2rem;font-weight:300}h1{font-size:3rem;line-height:1.2}h2{font-size:2.8rem;line-height:1.25}h3{font-size:2.6rem;line-height:1.3}h4{font-size:2.4rem;line-height:1.35;letter-spacing:-.08rem}h5{font-size:1.8rem;line-height:1.5;letter-spacing:-.05rem}h6{font-size:1.5rem;letter-spacing:0}p{margin-top:0}a:hover{color:#00719f}code{padding:.2rem .5rem;margin:0 .2rem;font-size:.9rem;white-space:nowrap;border:1px solid #e1e1e1;border-radius:4px}pre>code{display:block;padding:1rem 1.5rem;white-space:pre}.button,.label{text-align:center;white-space:nowrap}.u-full-width{width:100%}.u-max-full-width{max-width:100%}.u-pull-right{float:right}.u-pull-left{float:left}.u-cf{content:"";display:table;clear:both}.u-hideable{display:none}.button{display:inline-block;height:38px;padding:0 30px;margin-bottom:1rem;color:#222;font-size:11px;font-weight:600;line-height:38px;letter-spacing:.1rem;background-color:transparent;border-radius:4px;border:1px solid #e1e1e1;cursor:pointer}.button:active,.button:focus,.button:hover{color:#222;border-color:#aeaeae;outline:0}.button--primary{color:#fff;background-color:#0095d2;border-color:#0095d2}.button--primary:active,.button--primary:focus,.button--primary:hover{color:#fff;background-color:#0087be;border-color:#0087be}.navgrid{width:100%;min-width:0;margin-left:0;margin-right:0;padding-left:0;padding-right:10px}.nav{background:#0095d2}.nav ul{text-align:center;padding:0;margin:0;background-color:#0095d2}.nav a.active,.nav a:hover{background-color:#0073b0}.nav li{font-size:1em;line-height:40px;height:40px;border-bottom:none;margin-bottom:0}.nav a{color:#fff;display:block}.nav a.active{color:#fff;cursor:default}.logo{text-align:center;background-color:#0095d2}.navbar-brand{padding:0;font-size:18px;max-width:250px}@media screen and (min-width:820px){.nav,.nav ul{background-color:#0095d2}body{padding-top:50px}.navgrid{width:100%;max-width:1140px;min-width:755px;margin:0 auto;overflow:hidden}.nav{height:50px;width:100%;position:fixed;z-index:10;top:0}.navbar-brand{padding:0;font-size:18px;float:left;max-width:250px}.nav li{border-bottom:none;height:50px;line-height:50px;font-size:1em;float:left;display:inline-block;margin-right:0}.nav a{padding-left:20px;padding-right:20px;text-decoration:none;color:#fff;display:block}.nav ul{list-style:none;text-align:center;padding:0;margin:0}}.hidden-small,.label{display:inline}table[data-sortable] th[data-sorted=true]{color:#3a87ad;background:#d9edf7;border-bottom-color:#bce8f1}table[data-sortable] th:not([data-sortable=false]){cursor:pointer;color:#222;text-decoration:underline}.summarybox{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.summarybox.ok{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.summarybox.warning{color:#c09853;background-color:#fcf8e3;border-color:#fbeed5}.summarybox.error{color:#b94a48;background-color:#f2dede;border-color:#eed3d7}.summarybox.info{background-color:#D9EDF7;border-color:#BCE8F1;color:#3A87AD}.summarynumber{font-size:2rem;line-height:1}.summarysmall{font-size:1rem;line-height:1}.label{padding:.2em .6em .3em;font-size:75%;line-height:1;color:#fff;vertical-align:baseline;border-radius:.25em}.ok{background-color:#468847}.warning{background-color:#f0ad4e}.error{background-color:#d9534f}ul.menu{font-size:125%}.errors{margin-bottom:1.333em;background:#ffb6c1}.large{font-size:1.333rem;line-height:1.333rem}#page-selector{display:none;clear:both;margin:1em 0}#output{margin:2em 0;font-size:12px;line-height:1em}.water-fall-holder{fill:#ccc}svg.water-fall-chart{width:100%;overflow:visible}.water-fall-chart .left-fixed-holder{overflow:visible}.water-fall-chart .marker-holder{width:100%}.water-fall-chart .line-holder{stroke-width:1;stroke:#ccc;stroke-opacity:.5}.water-fall-chart .line-holder.active{stroke:#69009e;stroke-width:2;stroke-opacity:1}.water-fall-chart .type-onload .line-holder{stroke:#c0c0ff}.water-fall-chart .type-oncontentload .line-holder{stroke:#d888df}.water-fall-chart .labels{width:100%}.water-fall-chart .labels .inner-label{pointer-events:none}.water-fall-chart .time-block.active{opacity:.8}.water-fall-chart .line-end,.water-fall-chart .line-start{display:none;stroke-width:1;stroke-opacity:.5;stroke:#000}.water-fall-chart .line-end.active,.water-fall-chart .line-start.active{display:block}.water-fall-chart .mark-holder text{-webkit-writing-mode:tb;writing-mode:vertical-lr;writing-mode:tb}.left-fixed-holder .label-full-bg{fill:#fff;opacity:.9}.time-scale line{stroke:#0cc;stroke-width:1}.row-item .even{fill:#ccc;opacity:.05}.row-item .odd{fill:#000;opacity:.05}.row-item:hover .even,.row-item:hover .odd{fill:#000;opacity:.1}.row-item .rect-holder text{fill:#aaa}.row-item.status5xx .even{fill:#f66}.row-item.status5xx .odd{fill:red}.row-item.status4xx .even{fill:#c33}.row-item.status4xx .odd{fill:#c00}.row-item.status3xx .even{fill:#ff6}.row-item.status3xx .odd{fill:#ff0}.row-item.status3xx .even,.row-item.status3xx .odd,.row-item.status4xx .even,.row-item.status4xx .odd,.row-item.status5xx .even,.row-item.status5xx .odd{opacity:.3}.row-item.status3xx:hover .even,.row-item.status3xx:hover .odd,.row-item.status4xx:hover .even,.row-item.status4xx:hover .odd,.row-item.status5xx:hover .even,.row-item.status5xx:hover .odd{opacity:.5}.lables{overflow:hidden}.block-css{fill:#a6d18f}.block-html,.block-iframe,.block-internal,.block-svg{fill:#82a8de}.block-image,.block-img{fill:#b394cf}.block-javascript,.block-js,.block-script{fill:#e0b483}.block-link{fill:#89afe6}.block-flash,.block-swf{fill:#42aab1}.block-font{fill:#e15d4e}.block-ajax,.block-xmlhttprequest{fill:red}.block-other,.block-plain{fill:#b3b3b3}.block-total{fill:#ccc}.block-unload{fill:#909}.block-redirect{fill:#ffff60}.block-appcache{fill:#1f831f}.block-tcp{fill:#e58226}.block-ttfb{fill:#1fe11f}.block-response{fill:#1977dd}.block-dom{fill:#9cc}.block-dom-content-loaded{fill:#d888df}.block-onload{fill:#c0c0ff}.block-ms-first-paint-event{fill:#8fbc83}.block-dom-interactive-event{fill:#d888df}.block-network-server{fill:#8cd18c}.block-custom-measure{fill:red}.block-navigation-api-total{fill:#ccc}.block-blocked,.block-blocking{fill:#cdcdcd}.block-undefined{fill:#0f0}.block-blocked{fill:#ccc}.block-dns{fill:#1f7c83}.block-connect{fill:#e58226}.block-ssl{fill:#c141cd}.block-send{fill:#1fe110}.block-wait{fill:#1fe11f}.block-receive{fill:#1977dd}.info-overlay{fill:#fff;stroke:#cdcdcd}.info-overlay-close-btn{fill:rgba(205,205,205,.5);transform:translate(-23px,-23px);cursor:pointer}.info-overlay-close-btn text{fill:#111;pointer-events:none}.info-overlay-close-btn:focus{border:1px solid #36c}.type-css{background:#406B29}.type-html,.type-iframe,.type-internal,.type-svg{background:#1C4278}.type-image,.type-img{background:#4D2E69}.type-javascript,.type-js,.type-script{background:#7A4E1D}.type-link{background:#89afe6}.type-flash,.type-swf{background:#234980}.type-font{background:#AE2A1B}.type-ajax,.type-xmlhttprequest{background:#C00}.type-other,.type-plain{background:grey}.info-overlay-holder *{padding:0;margin:0;font-size:12px}.info-overlay-holder body{position:relative;height:450px;clear:both;padding:0;margin:0;width:100%;background:#fff;color:#666}.info-overlay-holder body .wrapper{height:450px;width:100%;overflow:scroll}.info-overlay-holder header{color:#fff;box-shadow:0 0 2px 2px rgba(0,0,0,.25)}.info-overlay-holder h3{font-size:1.1em;padding:1em;margin:0;font-weight:400}.info-overlay-holder h3 strong{font-size:1.1em}.info-overlay-holder .tab-nav ul{margin:0;padding:0}.info-overlay-holder .tab-nav li{margin:0;padding:0;display:inline-block}.info-overlay-holder button{background:0 0;outline:0;border:0;border-bottom:solid 2px transparent;padding:.5em 1em;margin:0 .25em}.info-overlay-holder li:first-child button{margin-left:1em}.info-overlay-holder button:focus,.info-overlay-holder button:hover{border-color:rgba(255,255,255,.6)}.info-overlay-holder button.active{border-color:#fff;cursor:default}.info-overlay-holder dt{float:left;clear:both;margin-top:.5em;width:25%;text-align:right;font-weight:700}.info-overlay-holder dd{float:left;width:73%;margin:.5em 0 0 2%;padding:0 0 .5em}.info-overlay-holder dt:after{content:":"}.info-overlay-holder pre{font-size:11px;line-height:23px;border-radius:0;background:#f6f3f3}.info-overlay-holder .tab{float:left;width:100%;height:350px;padding:12px 12px 24px}.info-overlay-holder .tab h2{font-size:1.2em;margin:.5em 0 0;padding:.5em 0 .5em 1em;clear:both;border-top:solid 1px #efefef}.info-overlay-holder .tab pre{overflow-y:hidden}.info-overlay-holder .tab .preview{width:auto;max-width:100%;max-height:500px;border:1px solid #666}.info-overlay-holder .tab dl:after{content:"";display:table;clear:both} \ No newline at end of file +/*! normalize.css v4.1.1 | MIT License | github.com/necolas/normalize.css */progress,sub,sup{vertical-align:baseline}ol,ul{margin-top:0;padding-left:0}button,hr,input{overflow:visible}article,aside,details,figcaption,figure,footer,header,label,legend,main,menu,nav,section,summary{display:block}.column,.columns,.container{width:100%;box-sizing:border-box}h1,h2,h3{letter-spacing:-.1rem}code,tr:nth-child(odd){background:#fafafa}*,.column,.columns,.container,:after,:before,legend{box-sizing:border-box}html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}audio,canvas,progress,video{display:inline-block}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent;-webkit-text-decoration-skip:objects;color:#0095d2}a:active,a:hover{outline-width:0}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}.button,.nav a{text-decoration:none}b,strong{font-weight:bolder}dfn{font-style:italic}h1{margin:.67em 0}mark{background-color:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}svg:not(:root){overflow:hidden}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}figure{margin:1em 40px 2.5rem}button,input,optgroup,select,textarea{font:inherit;margin:0}.info-overlay-holder .requestID,.label,.summarynumber,.time-scale text,optgroup{font-weight:700}button,select{text-transform:none}.button,ul.menu{text-transform:uppercase}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:ButtonText dotted 1px}fieldset{border:1px solid silver;margin:0 2px}legend{color:inherit;max-width:100%;padding:0;white-space:normal}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-input-placeholder{color:inherit;opacity:.54}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}body,h6{line-height:1.6}form,ol,ul{margin-bottom:2.5rem}ul{list-style:circle inside}ol ol,ol ul,ul ol,ul ul{margin:1.5rem 0 1.5rem 3rem;font-size:.9rem}ol{list-style:decimal inside}.nav ul,ul.menu{list-style:none}li{margin-bottom:1rem}footer{text-align:center}hr{box-sizing:content-box;height:0;margin-top:3rem;margin-bottom:3.5rem;border-width:0;border-top:1px solid #e1e1e1}fieldset,input,select,textarea{margin-bottom:1.5rem}input[type=url],input[type=password],input[type=number],input[type=search],input[type=email],input[type=text],input[type=tel],select,textarea{height:38px;padding:6px 10px;background-color:#fff;border:1px solid #e1e1e1;border-radius:4px;box-shadow:none}input[type=url],input[type=password],input[type=number],input[type=search],input[type=email],input[type=text],input[type=tel]{-webkit-appearance:none;-moz-appearance:none;appearance:none}textarea{overflow:auto;-webkit-appearance:none;-moz-appearance:none;appearance:none;min-height:65px;padding-top:6px;padding-bottom:6px}input[type=url]:focus,input[type=password]:focus,input[type=number]:focus,input[type=search]:focus,input[type=email]:focus,input[type=text]:focus,input[type=tel]:focus,select:focus,textarea:focus{border:1px solid #0095d2;outline:0}label,legend{margin-bottom:.5rem;font-weight:600}fieldset{padding:0;border-width:0}input[type=checkbox],input[type=radio]{display:inline}label>.label-body{display:inline-block;margin-left:.5rem;font-weight:400}.container:after,.row:after{content:"";display:table;clear:both}.container{position:relative;max-width:960px;margin:0 auto;padding:0 20px}blockquote,dl,p,pre,table{margin-bottom:2.5rem}.column,.columns{float:left}@media (min-width:400px){.container{width:85%;padding:0}}@media (min-width:550px){.container{width:80%}.column,.columns{margin-left:4%}.column:first-child,.columns:first-child{margin-left:0}.one.column,.one.columns{width:4.66666666667%}.two.columns{width:13.3333333333%}.three.columns{width:22%}.four.columns{width:30.6666666667%}.five.columns{width:39.3333333333%}.six.columns{width:48%}.seven.columns{width:56.6666666667%}.eight.columns{width:65.3333333333%}.nine.columns{width:74%}.ten.columns{width:82.6666666667%}.eleven.columns{width:91.3333333333%}.twelve.columns{width:100%;margin-left:0}.one-third.column{width:30.6666666667%}.two-thirds.column{width:65.3333333333%}.one-half.column{width:48%}.offset-by-one.column,.offset-by-one.columns{margin-left:8.66666666667%}.offset-by-two.column,.offset-by-two.columns{margin-left:17.3333333333%}.offset-by-three.column,.offset-by-three.columns{margin-left:26%}.offset-by-four.column,.offset-by-four.columns{margin-left:34.6666666667%}.offset-by-five.column,.offset-by-five.columns{margin-left:43.3333333333%}.offset-by-six.column,.offset-by-six.columns{margin-left:52%}.offset-by-seven.column,.offset-by-seven.columns{margin-left:60.6666666667%}.offset-by-eight.column,.offset-by-eight.columns{margin-left:69.3333333333%}.offset-by-nine.column,.offset-by-nine.columns{margin-left:78%}.offset-by-ten.column,.offset-by-ten.columns{margin-left:86.6666666667%}.offset-by-eleven.column,.offset-by-eleven.columns{margin-left:95.3333333333%}.offset-by-one-third.column,.offset-by-one-third.columns{margin-left:34.6666666667%}.offset-by-two-thirds.column,.offset-by-two-thirds.columns{margin-left:69.3333333333%}.offset-by-one-half.column,.offset-by-one-half.columns{margin-left:52%}}table{width:100%;border-collapse:separate;border-spacing:1px;background-color:#e1e1e1}td,th{padding:4px 1rem;vertical-align:top;text-align:left}td:first-child,th:first-child{padding-left:1rem}td:last-child,th:last-child{padding-right:1rem}tr:nth-child(even){background:#fff}th{background:#f1fbff}td.number{text-align:right}td.url{overflow-wrap:break-word;word-wrap:break-word;-webkit-hyphens:auto;-ms-hyphens:auto;-moz-hyphens:auto;hyphens:auto}td.assetsurl{max-width:400px}td.pagesurl{max-width:350px}td.offendingurl{max-width:900px}@media only screen and (max-width:800px){.responsive table,.responsive tbody,.responsive td,.responsive th,.responsive thead,.responsive tr{display:block}.hidden-small,.responsive tr.u-hideable{display:none}.responsive thead tr{position:absolute;top:-9999px;left:-9999px}.responsive tr{border:4px solid #e1e1e1}.responsive td{border:none;border-bottom:1px solid #e1e1e1;position:relative;padding-left:50%;white-space:normal;text-align:left;max-width:none}.responsive td:before{position:absolute;top:6px;left:6px;width:30%;padding-right:10px;white-space:nowrap;text-align:left;font-weight:700;content:attr(data-title)}}html{font-size:15px}body{font-size:1em;font-weight:400;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;color:#222}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:2rem;font-weight:300}h1{font-size:3rem;line-height:1.2}h2{font-size:2.8rem;line-height:1.25}h3{font-size:2.6rem;line-height:1.3}h4{font-size:2.4rem;line-height:1.35;letter-spacing:-.08rem}h5{font-size:1.8rem;line-height:1.5;letter-spacing:-.05rem}h6{font-size:1.5rem;letter-spacing:0}p{margin-top:0}a:hover{color:#00719f}code{padding:.2rem .5rem;margin:0 .2rem;font-size:.9rem;white-space:nowrap;border:1px solid #e1e1e1;border-radius:4px}pre>code{display:block;padding:1rem 1.5rem;white-space:pre}.button,.label{text-align:center;white-space:nowrap}.u-full-width{width:100%}.u-max-full-width{max-width:100%}.u-pull-right{float:right}.u-pull-left{float:left}.u-cf{content:"";display:table;clear:both}.u-hideable{display:none}.button{display:inline-block;height:38px;padding:0 30px;margin-bottom:1rem;color:#222;font-size:11px;font-weight:600;line-height:38px;letter-spacing:.1rem;background-color:transparent;border-radius:4px;border:1px solid #e1e1e1;cursor:pointer}.button:active,.button:focus,.button:hover{color:#222;border-color:#aeaeae;outline:0}.button--primary{color:#fff;background-color:#0095d2;border-color:#0095d2}.button--primary:active,.button--primary:focus,.button--primary:hover{color:#fff;background-color:#0087be;border-color:#0087be}.navgrid{width:100%;min-width:0;margin-left:0;margin-right:0;padding-left:0;padding-right:10px}.nav{background:#0095d2}.nav ul{text-align:center;padding:0;margin:0;background-color:#0095d2}.nav a.active,.nav a:hover{background-color:#0073b0}.nav li{font-size:1em;line-height:40px;height:40px;border-bottom:none;margin-bottom:0}.nav a{color:#fff;display:block}.nav a.active{color:#fff;cursor:default}.logo{text-align:center;background-color:#0095d2}.navbar-brand{padding:0;font-size:18px;max-width:250px}@media screen and (min-width:820px){.nav,.nav ul{background-color:#0095d2}body{padding-top:50px}.navgrid{width:100%;max-width:1140px;min-width:755px;margin:0 auto;overflow:hidden}.nav{height:50px;width:100%;position:fixed;z-index:10;top:0}.navbar-brand{padding:0;font-size:18px;float:left;max-width:250px}.nav li{border-bottom:none;height:50px;line-height:50px;font-size:1em;float:left;display:inline-block;margin-right:0}.nav a{padding-left:20px;padding-right:20px;text-decoration:none;color:#fff;display:block}.nav ul{list-style:none;text-align:center;padding:0;margin:0}}.hidden-small,.label{display:inline}table[data-sortable] th[data-sorted=true]{color:#3a87ad;background:#d9edf7;border-bottom-color:#bce8f1}table[data-sortable] th:not([data-sortable=false]){cursor:pointer;color:#222;text-decoration:underline}.summarybox{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.summarybox.ok{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.summarybox.warning{color:#c09853;background-color:#fcf8e3;border-color:#fbeed5}.summarybox.error{color:#b94a48;background-color:#f2dede;border-color:#eed3d7}.summarybox.info{background-color:#D9EDF7;border-color:#BCE8F1;color:#3A87AD}.summarynumber{font-size:2rem;line-height:1}.summarysmall{font-size:1rem;line-height:1}.label{padding:.2em .6em .3em;font-size:75%;line-height:1;color:#fff;vertical-align:baseline;border-radius:.25em}.ok{background-color:#468847}.warning{background-color:#f0ad4e}.error{background-color:#d9534f}ul.menu{font-size:125%}.errors{margin-bottom:1.333em;background:#ffb6c1}.large{font-size:1.333rem;line-height:1.333rem}#page-selector{display:none;clear:both;margin:1em 0}#output{margin:2em 0;font-size:12px;line-height:1em}.water-fall-holder{fill:#ccc}svg.water-fall-chart{width:100%;overflow:visible}.water-fall-chart .left-fixed-holder{overflow:visible}.water-fall-chart .marker-holder{width:100%}.water-fall-chart .line-holder{stroke-width:1;stroke:#ccc;stroke-opacity:.5}.water-fall-chart .line-holder.active{stroke:#69009e;stroke-width:2;stroke-opacity:1}.water-fall-chart .type-onload .line-holder{stroke:#c0c0ff}.water-fall-chart .type-oncontentload .line-holder{stroke:#d888df}.water-fall-chart .labels{width:100%}.water-fall-chart .labels .inner-label{pointer-events:none}.water-fall-chart .time-block.active{opacity:.8}.water-fall-chart .line-end,.water-fall-chart .line-start{display:none;stroke-width:1;stroke-opacity:.5;stroke:#000}.water-fall-chart .line-end.active,.water-fall-chart .line-start.active{display:block}.water-fall-chart .mark-holder text{-webkit-writing-mode:tb;writing-mode:vertical-lr;writing-mode:tb}.left-fixed-holder .label-full-bg{fill:#fff;opacity:.9}.time-scale line{stroke:#0cc;stroke-width:1}.row-item .even{fill:#ccc;opacity:.05}.row-item .odd{fill:#000;opacity:.05}.row-item:hover .even,.row-item:hover .odd{fill:#000;opacity:.1}.row-item .rect-holder text{fill:#aaa}.row-item.status5xx .even{fill:#f66}.row-item.status5xx .odd{fill:red}.row-item.status4xx .even{fill:#c33}.row-item.status4xx .odd{fill:#c00}.row-item.status3xx .even{fill:#ff6}.row-item.status3xx .odd{fill:#ff0}.row-item.status3xx .even,.row-item.status3xx .odd,.row-item.status4xx .even,.row-item.status4xx .odd,.row-item.status5xx .even,.row-item.status5xx .odd{opacity:.3}.row-item.status3xx:hover .even,.row-item.status3xx:hover .odd,.row-item.status4xx:hover .even,.row-item.status4xx:hover .odd,.row-item.status5xx:hover .even,.row-item.status5xx:hover .odd{opacity:.5}.lables{overflow:hidden}.block-css{fill:#a6d18f}.block-html,.block-iframe,.block-internal,.block-svg{fill:#82a8de}.block-image,.block-img{fill:#b394cf}.block-javascript,.block-js,.block-script{fill:#e0b483}.block-link{fill:#89afe6}.block-flash,.block-swf{fill:#42aab1}.block-font{fill:#e15d4e}.block-ajax,.block-xmlhttprequest{fill:red}.block-other,.block-plain{fill:#b3b3b3}.block-total{fill:#ccc}.block-unload{fill:#909}.block-redirect{fill:#ffff60}.block-appcache{fill:#1f831f}.block-tcp{fill:#e58226}.block-ttfb{fill:#1fe11f}.block-response{fill:#1977dd}.block-dom{fill:#9cc}.block-dom-content-loaded{fill:#d888df}.block-onload{fill:#c0c0ff}.block-ms-first-paint-event{fill:#8fbc83}.block-dom-interactive-event{fill:#d888df}.block-network-server{fill:#8cd18c}.block-custom-measure{fill:red}.block-navigation-api-total{fill:#ccc}.block-blocked,.block-blocking{fill:#cdcdcd}.block-undefined{fill:#0f0}.block-blocked{fill:#ccc}.block-dns{fill:#1f7c83}.block-connect{fill:#e58226}.block-ssl{fill:#c141cd}.block-send{fill:#1fe110}.block-wait{fill:#1fe11f}.block-receive{fill:#1977dd}.info-overlay{fill:#fff;stroke:#cdcdcd}.info-overlay-close-btn{fill:rgba(205,205,205,.5);transform:translate(-23px,-23px);cursor:pointer}.info-overlay-close-btn text{fill:#111;pointer-events:none}.info-overlay-close-btn:focus{border:1px solid #36c}.type-css{background:#406B29}.type-html,.type-iframe,.type-internal,.type-svg{background:#1C4278}.type-image,.type-img{background:#4D2E69}.type-javascript,.type-js,.type-script{background:#7A4E1D}.type-link{background:#89afe6}.type-flash,.type-swf{background:#234980}.type-font{background:#AE2A1B}.type-ajax,.type-xmlhttprequest{background:#C00}.type-other,.type-plain{background:grey}.info-overlay-holder *{padding:0;margin:0;font-size:12px}.info-overlay-holder body{position:relative;height:450px;clear:both;padding:0;margin:0;width:100%;background:#fff;color:#666}.info-overlay-holder body .wrapper{height:450px;width:100%;overflow:scroll}.info-overlay-holder header{color:#fff;box-shadow:0 0 2px 2px rgba(0,0,0,.25)}.info-overlay-holder h3{font-size:1.1em;padding:1em;margin:0;font-weight:400}.info-overlay-holder h3 strong{font-size:1.1em}.info-overlay-holder .tab-nav ul{margin:0;padding:0}.info-overlay-holder .tab-nav li{margin:0;padding:0;display:inline-block}.info-overlay-holder button{background:0 0;outline:0;border:0;border-bottom:solid 2px transparent;padding:.5em 1em;margin:0 .25em}.info-overlay-holder li:first-child button{margin-left:1em}.info-overlay-holder button:focus,.info-overlay-holder button:hover{border-color:rgba(255,255,255,.6)}.info-overlay-holder button.active{border-color:#fff;cursor:default}.info-overlay-holder dt{float:left;clear:both;margin-top:.5em;width:25%;text-align:right;font-weight:700}.info-overlay-holder dd{float:left;width:73%;margin:.5em 0 0 2%;padding:0 0 .5em}.info-overlay-holder dt:after{content:":"}.info-overlay-holder pre{font-size:11px;line-height:23px;border-radius:0;background:#f6f3f3}.info-overlay-holder .tab{float:left;width:100%;height:350px;padding:12px 12px 24px}.info-overlay-holder .tab h2{font-size:1.2em;margin:.5em 0 0;padding:.5em 0 .5em 1em;clear:both;border-top:solid 1px #efefef}.info-overlay-holder .tab pre{overflow-y:hidden}.info-overlay-holder .tab .preview{width:auto;max-width:100%;max-height:500px;border:1px solid #666}.info-overlay-holder .tab dl:after{content:"";display:table;clear:both}.screenshot{padding:4px;background-color:#fff;border:1px solid #ddd;border-radius:4px} \ No newline at end of file diff --git a/lib/plugins/html/htmlBuilder.js b/lib/plugins/html/htmlBuilder.js index bc2f8dda3..c0e161c51 100644 --- a/lib/plugins/html/htmlBuilder.js +++ b/lib/plugins/html/htmlBuilder.js @@ -15,8 +15,9 @@ const fs = require('fs'), Promise.promisifyAll(fs); class HTMLBuilder { - constructor(storageManager) { + constructor(storageManager, options) { this.storageManager = storageManager; + this.options = options; this.summaryPages = {}; this.urlPages = {}; this.urlRunPages = {}; @@ -133,7 +134,6 @@ class HTMLBuilder { version: packageInfo.version, h: helpers }, locals); - return this.storageManager.writeHtmlForUrl(url, name + '.html', renderer.renderTemplate('url/run', locals)); } diff --git a/lib/plugins/html/index.js b/lib/plugins/html/index.js index bf9d2a60e..664536a10 100644 --- a/lib/plugins/html/index.js +++ b/lib/plugins/html/index.js @@ -11,7 +11,7 @@ module.exports = { }, open(context, options) { - this.HTMLBuilder = new HTMLBuilder(context.storageManager); + this.HTMLBuilder = new HTMLBuilder(context.storageManager, options); this.options = options; }, diff --git a/lib/plugins/html/src/sass/components/screenshot.scss b/lib/plugins/html/src/sass/components/screenshot.scss new file mode 100644 index 000000000..878ad7909 --- /dev/null +++ b/lib/plugins/html/src/sass/components/screenshot.scss @@ -0,0 +1,11 @@ +// +// Screenshots +// =============== +// + +.screenshot { + padding: 4px; + background-color: #fff; + border: 1px solid #ddd; + border-radius: 4px; +} diff --git a/lib/plugins/html/src/sass/main.scss b/lib/plugins/html/src/sass/main.scss index beb3d25ed..1832088f6 100644 --- a/lib/plugins/html/src/sass/main.scss +++ b/lib/plugins/html/src/sass/main.scss @@ -34,3 +34,4 @@ @import 'components/summarybox'; @import 'components/misc'; @import 'components/waterfall'; +@import 'components/screenshot'; diff --git a/lib/plugins/html/templates/url/index.pug b/lib/plugins/html/templates/url/index.pug index c9646d668..3b7a013ef 100644 --- a/lib/plugins/html/templates/url/index.pug +++ b/lib/plugins/html/templates/url/index.pug @@ -1,9 +1,49 @@ extends ./layout.pug block content + - var d = pageInfo.data h1 Page summary + h5 #{daurl} - p Tested using #{h.cap(options.browsertime.browser)} #{h.plural(options.browsertime.iterations, 'time')}. + - var profile = options.mobile ? 'mobile' : 'desktop' + p Tested using #{h.cap(options.browsertime.browser)} #{h.plural(options.browsertime.iterations, 'run')} with #{profile} profile. + + .row + .one-half.column + table + tr + th Metric + th Value + if d.coach && d.coach.pageSummary + tr + td Performance score: + td #{d.coach.pageSummary.advice.performance.score} + if d.pagexray && d.pagexray.pageSummary + tr + td Total page size: + td #{h.size.format(d.pagexray.pageSummary.transferSize)} + if d.pagexray && d.pagexray.pageSummary + tr + td Requests: + td #{d.pagexray.pageSummary.requests} + if d.browsertime && d.browsertime.pageSummary && d.browsertime.pageSummary.statistics.timings.firstPaint + tr + td First Paint: + td #{d.browsertime.pageSummary.statistics.timings.firstPaint.median} + if d.browsertime && d.browsertime.pageSummary && d.browsertime.pageSummary.visualMetrics.SpeedIndex + tr + td SpeedIndex: + td #{d.browsertime.pageSummary.visualMetrics.SpeedIndex} + else if d.browsertime && d.browsertime.pageSummary + tr + td RUMSpeedIndex: + td #{d.browsertime.pageSummary.statistics.timings.rumSpeedIndex.median} + + .one-half.column + if d.browsertime.pageSummary.screenshots + - var width = options.mobile ? 150 : '100%'; + a(href='screenshots/0.png') + img.screenshot(src='screenshots/0.png', width=width, alt='Screenshot of run 0') include ./summaryBox.pug @@ -21,7 +61,6 @@ block content - run = 0 h3 Statistics from run #{run + 1} - - var d = pageInfo.data ul if d.coach && d.coach.pageSummary li: a(href='#coach') Coach diff --git a/lib/plugins/html/templates/url/run.pug b/lib/plugins/html/templates/url/run.pug index d9ac62061..9d2d80bd8 100644 --- a/lib/plugins/html/templates/url/run.pug +++ b/lib/plugins/html/templates/url/run.pug @@ -1,18 +1,56 @@ extends ./layout.pug block content + - var d = pageInfo.data - runNumber = Number(runIndex)+1 h1 Run #{runNumber} summary h5 #{daurl} - p Tested using #{h.cap(options.browsertime.browser)} #{h.plural(options.browsertime.iterations, 'time')}. + - var profile = options.mobile ? 'mobile' : 'desktop' + p Tested using #{h.cap(options.browsertime.browser)} #{h.plural(options.browsertime.iterations, 'run')} with #{profile} profile. + + .row + .one-half.column + table + tr + th Metric + th Value + if d.coach && d.coach.run + tr + td Performance score: + td #{d.coach.run.advice.performance.score} + if d.pagexray && d.pagexray.run + tr + td Total page size: + td #{h.size.format(d.pagexray.run.transferSize)} + if d.pagexray && d.pagexray.run + tr + td Requests: + td #{d.pagexray.run.requests} + if d.browsertime && d.browsertime.run && d.browsertime.run.timings.firstPaint + tr + td First Paint: + td #{d.browsertime.run.timings.firstPaint} + if d.browsertime && d.browsertime.run && d.browsertime.run.visualMetrics && d.browsertime.run.visualMetrics.SpeedIndex + tr + td SpeedIndex: + td #{d.browsertime.run.visualMetrics.SpeedIndex} + else if d.browsertime && d.browsertime.run + tr + td RUMSpeedIndex: + td #{d.browsertime.run.timings.rumSpeedIndex} + + .one-half.column + //- No good way to detect if we have screenshots or not right now for a run + - screenshotName = 'screenshots/' + runIndex + '.png' + - var width = options.mobile ? 150 : '100%'; + a(href=screenshotName) + img.screenshot(src=screenshotName, width=width, alt='Screenshot') if pageInfo.error .error= pageInfo.error else - | Quick links ul.menu - - d = pageInfo.data if d.pagexray && d.pagexray.run li: a(href='#pagexray') Page summary if d.coach && d.coach.run diff --git a/lib/plugins/html/templates/url/summaryBox.pug b/lib/plugins/html/templates/url/summaryBox.pug index fa060a160..732d0e0a3 100644 --- a/lib/plugins/html/templates/url/summaryBox.pug +++ b/lib/plugins/html/templates/url/summaryBox.pug @@ -1,6 +1,6 @@ if pageInfo.data.browsertime - var btStatistics = pageInfo.data.browsertime.pageSummary.statistics - h2 Summary + h2 Timings Summary - timingMetrics = ['firstPaint', 'fullyLoaded', 'rumSpeedIndex'] .responsive table @@ -33,7 +33,7 @@ if pageInfo.data.browsertime tr td(data-title= name) #{name} (visual metric) td.number(data-title='min') #{visualMetric.min} - td.number(data-title='median') #{visualMetric.median} + td.number(data-title='median') #{visualMetric.median} td.number(data-title='mean') #{visualMetric.mean} td.number(data-title='max') #{visualMetric.max} else diff --git a/lib/plugins/screenshot/index.js b/lib/plugins/screenshot/index.js new file mode 100644 index 000000000..0a7304113 --- /dev/null +++ b/lib/plugins/screenshot/index.js @@ -0,0 +1,65 @@ +'use strict'; + +const path = require('path'), + PNGCrop = require('png-crop'), + Promise = require('bluebird'); + +Promise.promisifyAll(PNGCrop); + +function getImagesAndName(images) { + const imagesAndName = []; + let i = 0; + images.forEach(function(image) { + imagesAndName.push({ + data: image, + name: i + '.png' + }); + i++; + }) + return imagesAndName; +} + +function storeFirefoxScreenshots(options, url, imagesAndName, storageManager) { + const width = Number(options.browsertime.viewPort.split('x')[0]); + const height = Number(options.browsertime.viewPort.split('x')[1]); + + // Firfox screenshots take the full height of the browser window, so Lets crop + return storageManager.createDirForUrl(url, 'screenshots'). + then((dirPath) => { + return Promise.map(imagesAndName, function(screenshot) { + return PNGCrop.cropAsync(screenshot.data, path.join(dirPath, screenshot.name), { + width, + height + }); + }) + }) +} + +function storeChromeScreenshots(url, imagesAndName, storageManager) { + return storageManager.createDirForUrl(url, 'screenshots'). + then((dirPath) => { + return Promise.map(imagesAndName, function(screenshot) { + return storageManager.writeInDir(dirPath, screenshot.name, screenshot.data); + }) + }) +} + +module.exports = { + name() { + return path.basename(__dirname); + }, + open(context, options) { + this.storageManager = context.storageManager; + this.options = options; + }, + processMessage(message) { + switch (message.type) { + case 'browsertime.screenshot': + if (this.options.browser === 'firefox') { + return storeFirefoxScreenshots(this.options, message.url, getImagesAndName(message.data), this.storageManager); + } else { + return storeChromeScreenshots(message.url, getImagesAndName(message.data), this.storageManager); + } + } + } +}; diff --git a/lib/sitespeed.js b/lib/sitespeed.js index ba09c5409..3b7084cca 100644 --- a/lib/sitespeed.js +++ b/lib/sitespeed.js @@ -57,6 +57,11 @@ module.exports = { coach: true }); } + if (allInArray(['browsertime', 'screenshot'], pluginNames)) { + options.browsertime = merge({}, options.browsertime, { + screenshot: true + }); + } return pluginNames; }) .then(() => { diff --git a/lib/support/pluginLoader.js b/lib/support/pluginLoader.js index daa177d9c..f6a5d77e4 100644 --- a/lib/support/pluginLoader.js +++ b/lib/support/pluginLoader.js @@ -6,7 +6,7 @@ const Promise = require('bluebird'), Promise.promisifyAll(fs); -const defaultPlugins = new Set(['browsertime', 'coach', 'domains', 'assets', 'html', 'analysisStorer']); +const defaultPlugins = new Set(['browsertime', 'coach', 'domains', 'assets', 'html', 'analysisStorer','screenshot']); const pluginsDir = path.join(__dirname, '..', 'plugins'); diff --git a/lib/support/storageManager.js b/lib/support/storageManager.js index 678e8155f..e515852cc 100644 --- a/lib/support/storageManager.js +++ b/lib/support/storageManager.js @@ -97,6 +97,10 @@ class StorageManager { .then((dirPath) => write(dirPath, filename, data)); } + writeInDir(dir, filename, data) { + return write(dir, filename, data); + } + writeHtmlForUrl(url, filename, data) { return write(this.createDirForUrl(url), filename, data); } diff --git a/package.json b/package.json index 00e7885ba..d0d80b586 100644 --- a/package.json +++ b/package.json @@ -88,6 +88,7 @@ "node-slack": "0.0.7", "node-uuid": "1.4.7", "pagexray": "0.9.0", + "png-crop": "0.0.1", "pug": "^2.0.0-beta2", "simplecrawler": "0.7.0", "webcoach": "0.23.0", diff --git a/test/prepostscripts/postSample.js b/test/prepostscripts/postSample.js index faed114b3..605ec1339 100644 --- a/test/prepostscripts/postSample.js +++ b/test/prepostscripts/postSample.js @@ -1,5 +1,5 @@ module.exports = { run(context) { - context.log.info('In posttask!!! (with results: ' + JSON.stringify(context.results) + ')'); + context.log.info('In posttask!!!'); } };