anta
Version:
CLI tool and lib to gather app audits via [Lighthouse](https://github.com/GoogleChrome/lighthouse/).
255 lines • 21.5 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const chrome_launcher_1 = require("chrome-launcher");
const lighthouse = require('lighthouse');
const path = require('path');
const metrics = require('./metrics');
const expectations = require('./expectations');
const lhConfig = require('./lh-config');
const realDevice = require('./real-device');
const MAX_LIGHTHOUSE_TRIES = 2;
const getScore = (result) => {
let score = 0;
result.reportCategories.forEach((cate) => {
if (cate.name === 'Performance') {
score = cate.score;
}
});
return score;
};
class AntA {
constructor(urls, opts) {
this.urls = urls;
this.flags = {
runs: 3,
view: false,
expectations: false,
json: false,
chromeFlags: []
};
this.flags = Object.assign({}, this.flags, opts ? opts.flags : null);
this.runs = this.flags.runs;
this.expectations = opts ? opts.expectations : {};
this.tryLighthouseCounter = 0;
// normalize path if provided
if (this.flags.chromePath) {
this.flags.chromePath = path.normalize(this.flags.chromePath);
}
if (this.flags.expectations) {
if (this.expectations) {
expectations.validateMetrics(this.expectations);
this.expectations = expectations.normalizeMetrics(this.expectations);
}
else
throw new Error('NO_EXPECTATIONS_FOUND');
}
if (opts.runEnv === 'alipayApp') {
this.runEnv = 'alipayApp';
}
}
// public api, No arguments
start() {
return __awaiter(this, void 0, void 0, function* () {
let finalResults = [];
if (typeof this.urls === 'string') {
this.urls = [this.urls];
}
// on real device's Alipay APP
if (this.runEnv === 'alipayApp') {
// 重复设置 url 使之与 flags.runs 设置一样
const urls = [];
const resGroupArr = [];
this.urls.forEach(item => {
resGroupArr.push([]);
for (let index = 0; index < this.runs; index++) {
urls.push(item);
}
});
const res = yield realDevice(urls);
for (let index = 0; index < res.length; index++) {
const single = res[index];
resGroupArr[this.urls.indexOf(single.initialUrl)].push(single);
// console.log('res single', single.initialUrl);
}
// console.log('alipay...', urls, resGroupArr);
const newRes = [];
resGroupArr.forEach((arr) => {
// 多次运行结果,根据分数由高到低排序,只取最高分数返回
newRes.push(arr.sort((a, b) => getScore(b.runs[0]) - getScore(a.runs[0]))[0]);
});
return newRes;
}
// on pc chrome
for (let url of this.urls) {
const currentUrlMetric = yield this.startInner(url);
finalResults.push(currentUrlMetric);
}
return finalResults;
});
}
startInner(url) {
return __awaiter(this, void 0, void 0, function* () {
const runs = Array.apply(null, { length: +this.runs }).map(Number.call, Number);
let metricsResults = [];
let resultHasExpectationErrors = false;
for (let runIndex of runs) {
try {
const currentMetricResult = yield this.run(url);
if (!resultHasExpectationErrors && this.flags.expectations) {
resultHasExpectationErrors = this.resultHasExpectationErrors(currentMetricResult);
}
metricsResults[runIndex] = currentMetricResult;
console.log('SUCCESS', 'SUCCESS_RUN', `Run ${runIndex + 1} of ${runs.length} finished successfully.`);
}
catch (error) {
metricsResults[runIndex] = error;
console.error('ERROR', 'FAILED_RUN', runIndex, runs.length, error.message);
}
}
const res = metricsResults.filter(r => !(r instanceof Error));
// 多次运行结果,根据分数由高到低排序
let results = { runs: res.sort((a, b) => getScore(b) - getScore(a)) };
if (results.runs.length > 0) {
// if (this.runs > 1 && !this.flags.submit) {
// results.median = this.findMedianRun(results.runs);
// console.log(messages.getMessage('MEDIAN_RUN'));
// this.displayOutput(results.median);
// } else if (this.flags.submit) {
// const sheets = new Sheets(this.sheets, this.clientSecret);
// await sheets.appendResults(results.runs);
// }
}
if (resultHasExpectationErrors && this.flags.expectations) {
throw new Error('HAS_EXPECTATION_ERRORS');
}
return results;
});
}
resultHasExpectationErrors(metrics) {
return metrics.timings.some((timing) => {
const expectation = this.expectations[timing.id];
if (!expectation) {
return false;
}
const expectedErrorLimit = expectation.error;
return expectedErrorLimit !== undefined && timing.timing >= expectedErrorLimit;
});
}
run(url) {
return __awaiter(this, void 0, void 0, function* () {
try {
let lhResults;
yield this.launchChrome();
if (process.env.CI) {
// handling CRI_TIMEOUT issue - https://github.com/GoogleChrome/lighthouse/issues/833
this.tryLighthouseCounter = 0;
lhResults = yield this.runLighthouseOnCI(url).then((lhResults) => {
// fix for https://github.com/paulirish/pwmetrics/issues/63
return new Promise(resolve => {
console.log('WAITING');
setTimeout(_ => {
return resolve(lhResults);
}, 2000);
});
});
}
else {
// lhResults = await lighthouse(url, this.flags, null); // use lh default config
lhResults = yield lighthouse(url, this.flags, lhConfig);
}
const metricsResults = yield this.recordLighthouseTrace(lhResults);
yield this.killLauncher();
return metricsResults;
}
catch (error) {
yield this.killLauncher();
throw error;
}
});
}
killLauncher() {
return __awaiter(this, void 0, void 0, function* () {
if (typeof this.launcher !== 'undefined') {
yield this.launcher.kill();
}
});
}
runLighthouseOnCI(url) {
return __awaiter(this, void 0, void 0, function* () {
try {
return yield lighthouse(url, this.flags, lhConfig);
}
catch (error) {
if (error.code === 'CRI_TIMEOUT' && this.tryLighthouseCounter <= MAX_LIGHTHOUSE_TRIES) {
return yield this.retryLighthouseOnCI(url);
}
if (this.tryLighthouseCounter > MAX_LIGHTHOUSE_TRIES) {
throw new Error('CRI_TIMEOUT_REJECT');
}
}
});
}
retryLighthouseOnCI(url) {
return __awaiter(this, void 0, void 0, function* () {
this.tryLighthouseCounter++;
console.log('CRI_TIMEOUT_RELAUNCH');
try {
return yield this.runLighthouseOnCI(url);
}
catch (error) {
console.error(error.message);
console.error('CLOSING_CHROME');
yield this.killLauncher();
}
});
}
launchChrome() {
return __awaiter(this, void 0, void 0, function* () {
try {
console.log('LAUNCHING_CHROME');
this.launcher = yield chrome_launcher_1.launch({
port: this.flags.port,
chromeFlags: this.flags.chromeFlags,
chromePath: this.flags.chromePath
});
this.flags.port = this.launcher.port;
return this.launcher;
}
catch (error) {
yield this.killLauncher();
return error;
}
});
}
recordLighthouseTrace(data) {
return __awaiter(this, void 0, void 0, function* () {
try {
const preparedData = metrics.prepareData(data);
// if (this.flags.upload) {
// const driveResponse = await upload(data, this.clientSecret);
// this.view(driveResponse.id);
// }
// if (!this.flags.submit && this.runs <= 1) {
// this.displayOutput(preparedData);
// }
if (this.flags.expectations) {
expectations.checkExpectations(preparedData.timings, this.expectations);
}
return preparedData;
}
catch (error) {
throw error;
}
});
}
}
module.exports = AntA;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJpbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7O0FBSUEscURBQXlEO0FBRXpELE1BQU0sVUFBVSxHQUFHLE9BQU8sQ0FBQyxZQUFZLENBQUMsQ0FBQztBQUN6QyxNQUFNLElBQUksR0FBRyxPQUFPLENBQUMsTUFBTSxDQUFDLENBQUM7QUFDN0IsTUFBTSxPQUFPLEdBQUcsT0FBTyxDQUFDLFdBQVcsQ0FBQyxDQUFDO0FBQ3JDLE1BQU0sWUFBWSxHQUFHLE9BQU8sQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO0FBQy9DLE1BQU0sUUFBUSxHQUFHLE9BQU8sQ0FBQyxhQUFhLENBQUMsQ0FBQztBQUV4QyxNQUFNLFVBQVUsR0FBRyxPQUFPLENBQUMsZUFBZSxDQUFDLENBQUM7QUFNNUMsTUFBTSxvQkFBb0IsR0FBRyxDQUFDLENBQUM7QUFDL0IsTUFBTSxRQUFRLEdBQUcsQ0FBQyxNQUFzQixFQUFFLEVBQUU7SUFDMUMsSUFBSSxLQUFLLEdBQVcsQ0FBQyxDQUFDO0lBQ3RCLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQyxPQUFPLENBQUMsQ0FBQyxJQUFTLEVBQUUsRUFBRTtRQUM1QyxFQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxLQUFLLGFBQWEsQ0FBQyxDQUFDLENBQUM7WUFDaEMsS0FBSyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUM7UUFDckIsQ0FBQztJQUNILENBQUMsQ0FBQyxDQUFDO0lBQ0gsTUFBTSxDQUFDLEtBQUssQ0FBQztBQUNmLENBQUMsQ0FBQztBQUVGO0lBY0UsWUFBbUIsSUFBNEIsRUFBRSxJQUFvQjtRQUFsRCxTQUFJLEdBQUosSUFBSSxDQUF3QjtRQWIvQyxVQUFLLEdBQWlCO1lBQ3BCLElBQUksRUFBRSxDQUFDO1lBQ1AsSUFBSSxFQUFFLEtBQUs7WUFDWCxZQUFZLEVBQUUsS0FBSztZQUNuQixJQUFJLEVBQUUsS0FBSztZQUNYLFdBQVcsRUFBRSxF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