sitespeed.io/lib/plugins/webhook/index.js

301 lines
8.8 KiB
JavaScript

'use strict';
const throwIfMissing = require('../../support/util').throwIfMissing;
const log = require('intel').getLogger('sitespeedio.plugin.webhook');
const path = require('path');
const get = require('lodash.get');
const cliUtil = require('../../cli/util');
const send = require('./send');
const Format = require('./format');
const friendlynames = require('../../support/friendlynames');
function getPageSummary(data, format, resultUrls, alias, screenshotType) {
let text = format.heading(
'Tested data for ' +
data.info.url +
(resultUrls.hasBaseUrl()
? format.link(
resultUrls.absoluteSummaryPagePath(
data.info.url,
alias[data.info.url]
),
'(result)'
)
: '')
);
if (resultUrls.hasBaseUrl()) {
text += format.image(
resultUrls.absoluteSummaryPagePath(data.info.url, alias[data.info.url]) +
'data/screenshots/1/afterPageCompleteCheck.' +
screenshotType
);
}
if (data.statistics.visualMetrics) {
let f = friendlynames['browsertime']['timnings']['FirstVisualChange'];
text += format.p(
f.name +
' ' +
f.format(data.statistics.visualMetrics['FirstVisualChange'].median)
);
f = friendlynames['browsertime']['timnings']['SpeedIndex'];
text += format.p(
f.name +
' ' +
f.format(data.statistics.visualMetrics['SpeedIndex'].median)
);
f = friendlynames['browsertime']['timnings']['LastVisualChange'];
text += format.p(
f.name +
' ' +
f.format(data.statistics.visualMetrics['LastVisualChange'].median)
);
}
if (data.statistics.googleWebVitals) {
for (let metric of Object.keys(data.statistics.googleWebVitals)) {
let f =
friendlynames.browsertime.timings[metric] ||
friendlynames.browsertime.cpu[metric] ||
friendlynames.browsertime.pageinfo[metric];
if (f) {
text += format.p(
f.name +
' ' +
f.format(data.statistics.googleWebVitals[metric].median)
);
} else {
// We do not have a mapping for FID
}
}
}
return text;
}
function getBrowserData(data) {
if (data && data.browser) {
return `${data.browser.name} ${data.browser.version} ${get(
data,
'android.model',
''
)} ${get(data, 'android.androidVersion', '')} ${get(
data,
'android.id',
''
)} `;
} else return '';
}
module.exports = {
name() {
return path.basename(__dirname);
},
get cliOptions() {
return require(path.resolve(__dirname, 'cli.js'));
},
open(context, options = {}) {
this.webHookOptions = options.webhook || {};
this.options = options;
log.info('Starting the webhook plugin');
throwIfMissing(options.webhook, ['url'], 'webhook');
this.format = new Format(this.webHookOptions.style);
this.resultUrls = context.resultUrls;
this.waitForUpload = false;
this.alias = {};
this.data = {};
this.errorTexts = {};
this.message = { text: '' };
if (options.webhook) {
for (let key of Object.keys(options.webhook)) {
if (key !== 'url' && key !== 'messages' && key !== 'style') {
this.message[key] = options.webhook[key];
}
}
}
},
async processMessage(message) {
const options = this.webHookOptions;
const format = this.format;
switch (message.type) {
case 'browsertime.browser': {
this.browserData = message.data;
break;
}
case 'gcs.setup':
case 'ftp.setup':
case 's3.setup': {
this.waitForUpload = true;
break;
}
case 'browsertime.alias': {
this.alias[message.url] = message.data;
break;
}
case 'browsertime.config': {
if (message.data.screenshot === true) {
this.screenshotType = message.data.screenshotType;
}
break;
}
case 'browsertime.pageSummary': {
if (this.waitForUpload && options.messages.indexOf('pageSumary') > -1) {
this.data[message.url] = message.data;
} else if (options.messages.indexOf('pageSumary') > -1) {
await send(options.url, {
text: `Test finished ${format.link(message.data.info.url)}`
});
}
break;
}
case 'error': {
// We can send too many messages to Matrix and get 429 so instead
// we bulk send them all one time
if (options.messages.indexOf('error') > -1) {
this.errorTexts += `${format.hr()} ⚠️ Error from ${format.bold(
message.source
)} testing ${
message.url ? format.link(message.url) : ''
} ${format.pre(message.data)}`;
}
break;
}
case 'budget.result': {
if (options.messages.indexOf('budget') > -1) {
let text = '';
// We have failing URLs in the budget
if (Object.keys(message.data.failing).length > 0) {
const failingURLs = Object.keys(message.data.failing);
text += format.heading(
`${'⚠️ Budget failing (' +
failingURLs.length +
' URLs)'}`
);
text += format.p(
`${get(this.options, 'name', '') +
' ' +
getBrowserData(this.browserData)}`
);
for (let url of failingURLs) {
text += format.bold(
`❌ ${url}` +
(this.resultUrls.hasBaseUrl()
? ` (${format.link(
this.resultUrls.absoluteSummaryPagePath(
url,
this.alias[url]
) + 'index.html',
'result'
)} - ${format.link(
this.resultUrls.absoluteSummaryPagePath(
url,
this.alias[url]
) +
'data/screenshots/1/afterPageCompleteCheck.' +
this.screenshotType,
'screenshot'
)}`
: '')
);
let items = '';
for (let failing of message.data.failing[url]) {
items += format.listItem(
`${failing.metric} : ${failing.friendlyValue} (${
failing.friendlyLimit
})`
);
}
text += format.list(items);
}
}
if (Object.keys(message.data.error).length > 0) {
const errorURLs = Object.keys(message.data.error);
text += format.heading(
`⚠️ Budget errors testing ${errorURLs.length} URLs`
);
for (let url of errorURLs) {
text += format.p(`❌ ${url}`);
text += format.pre(`${message.data.error[url]}`);
}
}
if (
Object.keys(message.data.error).length === 0 &&
Object.keys(message.data.failing).length === 0
) {
text += format.p(
`🎉 All (${
Object.keys(message.data.working).length
}) URL(s) passed the budget using ${get(
this.options,
'name',
''
)} ${getBrowserData(this.browserData)}`
);
}
if (!this.waitForUpload) {
await send(options.url, { text });
} else {
this.budgetText = text;
}
}
break;
}
case 'gcs.finished':
case 'ftp.finished':
case 's3.finished': {
if (
this.waitForUpload &&
options.messages.indexOf('pageSummary') > -1
) {
const message = {
text: ''
};
for (let url of Object.keys(this.data)) {
message.text += getPageSummary(
this.data[url],
format,
this.resultUrls,
this.alias,
this.screenshotType
);
}
if (this.resultUrls.reportSummaryUrl()) {
message.text += format.p(
format.link(
this.resultUrls.reportSummaryUrl() + '/index.html',
'Summary'
)
);
}
await send(options.url, message);
} else if (
this.waitForUpload &&
options.messages.indexOf('budget') > -1
) {
await send(options.url, { text: this.budgetText });
}
break;
}
case 'sitespeedio.render': {
if (this.errorTexts !== '') {
await send(options.url, { message: this.errorTexts });
}
break;
}
}
},
get config() {
return cliUtil.pluginDefaults(this.cliOptions);
}
};