UNPKG

codeceptjs-testit-reporter

Version:

Plugin for sending CodeceptJS test run reports to TestIT

331 lines (330 loc) 16.8 kB
"use strict"; var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 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) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (g && (g = 0, op[0] && (_ = 0)), _) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); var testit_api_client_1 = require("testit-api-client"); var StepsProcessor_1 = __importDefault(require("./StepsProcessor")); var constants_1 = require("./constants"); var utils_1 = require("./utils"); var defaultConfig = { namespace: constants_1.CJS_NAMESPACE, }; var Adapter = /** @class */ (function () { function Adapter(config) { var _this = this; this.initTestRun = function () { return __awaiter(_this, void 0, void 0, function () { var testRunData, testRun, e_1; return __generator(this, function (_a) { switch (_a.label) { case 0: _a.trys.push([0, 3, , 4]); testRunData = this._prepareTestRunData(); return [4 /*yield*/, this.client.createTestRun(testRunData)]; case 1: testRun = _a.sent(); this.testRunId = testRun.id; return [4 /*yield*/, this.client.startTestRun(this.testRunId)]; case 2: _a.sent(); return [3 /*break*/, 4]; case 3: e_1 = _a.sent(); (0, utils_1.log)("Failed to create and start test run: ".concat((0, utils_1.parseError)(e_1))); return [3 /*break*/, 4]; case 4: return [2 /*return*/]; } }); }); }; this._prepareTestRunData = function () { var testRunDate = new Date(); return { projectId: _this.config.projectId, name: "".concat(testRunDate.toISOString(), ": ").concat(_this.config.namespace, " Run"), }; }; this.completeTestRun = function () { return __awaiter(_this, void 0, void 0, function () { var existingTests, existingTestsIds_1, filteredResults_1, testRunLink, e_2; return __generator(this, function (_a) { switch (_a.label) { case 0: if (!this.testRunId) { (0, utils_1.log)("Failed to complete test run: testRunId cannot be null"); return [2 /*return*/]; } _a.label = 1; case 1: _a.trys.push([1, 5, , 6]); return [4 /*yield*/, this.client.getAutotest({ projectId: this.config.projectId })]; case 2: existingTests = _a.sent(); existingTestsIds_1 = new Set(); existingTests.forEach(function (t) { return existingTestsIds_1.add(t.externalId); }); filteredResults_1 = []; this.testRunResults.forEach(function (r) { // Autotest creates in TestIT only when test passed. // If test failed at first run, autotest will not exist, // so we cannot load results for it. if (existingTestsIds_1.has(r.autotestExternalId)) filteredResults_1.push(r); else (0, utils_1.log)("Not found \"".concat(r.autotestExternalId, "\" in existing tests ids, test run result ignored")); }); return [4 /*yield*/, this.client.completeTestRun(this.testRunId)]; case 3: _a.sent(); return [4 /*yield*/, this.client.loadTestRunResults(this.testRunId, filteredResults_1)]; case 4: _a.sent(); testRunLink = this._prepareTestRunLink(); if (testRunLink) (0, utils_1.log)("Test run link: ".concat(testRunLink)); return [3 /*break*/, 6]; case 5: e_2 = _a.sent(); (0, utils_1.log)("Failed to complete test run: ".concat((0, utils_1.parseError)(e_2))); return [3 /*break*/, 6]; case 6: return [2 /*return*/]; } }); }); }; this.forceCompleteTestRun = function () { if (!_this.testRunId) return; (0, utils_1.log)('Trying to force complete test run..'); _this.client.completeTestRun(_this.testRunId) .catch(function (e) { return (0, utils_1.log)("Failed to force complete test run: ".concat((0, utils_1.parseError)(e))); }) .finally(process.exit); _this.testRunId = null; }; this.initAutoTest = function (test) { return __awaiter(_this, void 0, void 0, function () { var autoTest, autoTests, e_3, autoTestData, e_4; return __generator(this, function (_a) { switch (_a.label) { case 0: autoTest = null; _a.label = 1; case 1: _a.trys.push([1, 3, , 4]); return [4 /*yield*/, this.client.getAutotest({ projectId: this.config.projectId, externalId: (0, utils_1.getTestId)(test), })]; case 2: autoTests = _a.sent(); autoTest = autoTests[0]; return [3 /*break*/, 4]; case 3: e_3 = _a.sent(); (0, utils_1.log)("Failed to fetch autotest: ".concat((0, utils_1.parseError)(e_3))); return [3 /*break*/, 4]; case 4: autoTestData = this._prepareAutoTestData(test); _a.label = 5; case 5: _a.trys.push([5, 10, , 11]); if (!!autoTest) return [3 /*break*/, 7]; return [4 /*yield*/, this.client.createAutotest(autoTestData)]; case 6: _a.sent(); return [3 /*break*/, 9]; case 7: return [4 /*yield*/, this.client.updateAutotest(autoTestData)]; case 8: _a.sent(); _a.label = 9; case 9: return [3 /*break*/, 11]; case 10: e_4 = _a.sent(); (0, utils_1.log)("Failed to create/update autotest: ".concat((0, utils_1.parseError)(e_4))); return [3 /*break*/, 11]; case 11: return [2 /*return*/]; } }); }); }; this._prepareAutoTestData = function (test) { var _a; return { projectId: _this.config.projectId, externalId: (0, utils_1.getTestId)(test), namespace: _this.config.namespace, classname: (_a = test.parent) === null || _a === void 0 ? void 0 : _a.title, name: test.title, title: test.title, steps: _this.stepsProcessor.getSteps(), labels: test.tags.map(function (t) { return ({ name: t }); }), }; }; this.resetTestState = function () { return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_a) { this.stepsProcessor.reset(); return [2 /*return*/]; }); }); }; this.initTest = function (test) { _this.testTimeMap[(0, utils_1.getTestId)(test)] = new Date(); }; this.completeTest = function (test) { return __awaiter(_this, void 0, void 0, function () { var attachment, testRunResult; var _a; return __generator(this, function (_b) { switch (_b.label) { case 0: if (!((_a = test.artifacts) === null || _a === void 0 ? void 0 : _a.screenshot)) return [3 /*break*/, 2]; return [4 /*yield*/, this._uploadAttachment(test.artifacts.screenshot)]; case 1: attachment = _b.sent(); if (attachment === null || attachment === void 0 ? void 0 : attachment.id) this.testAttachments[(0, utils_1.getTestId)(test)] = attachment.id; _b.label = 2; case 2: testRunResult = this._prepareTestRunResult(test); if (testRunResult) this.testRunResults.push(testRunResult); return [2 /*return*/]; } }); }); }; this._uploadAttachment = function (filepath) { return __awaiter(_this, void 0, void 0, function () { var attachment, e_5; return __generator(this, function (_a) { switch (_a.label) { case 0: _a.trys.push([0, 2, , 3]); return [4 /*yield*/, this.client.loadAttachment(filepath)]; case 1: attachment = _a.sent(); return [3 /*break*/, 3]; case 2: e_5 = _a.sent(); (0, utils_1.log)("Failed to upload attachment: ".concat((0, utils_1.parseError)(e_5))); return [2 /*return*/, null]; case 3: return [2 /*return*/, attachment]; } }); }); }; this._prepareTestRunResult = function (test) { var status = (0, utils_1.cjs2testItStatus)(test.state); if (!status) { (0, utils_1.log)("Cannot map CodeceptJS status \"".concat(test.state, "\" to TestIT status, test run result ignored")); return null; } var testRunResult; try { testRunResult = { configurationId: _this.config.configurationId, autotestExternalId: (0, utils_1.getTestId)(test), outcome: status, duration: _this._getTestDuration(test), startedOn: _this._getTestStartTime(test), traces: (0, utils_1.parseTestError)(test), stepResults: _this.stepsProcessor.getStepResults(), }; if (_this.testAttachments[(0, utils_1.getTestId)(test)]) testRunResult.attachments = [{ id: _this.testAttachments[(0, utils_1.getTestId)(test)] }]; } catch (e) { (0, utils_1.log)("Failed to prepare test run result: ".concat(e === null || e === void 0 ? void 0 : e.toString())); return null; } return testRunResult; }; this._getTestDuration = function (test) { return _this.testTimeMap[(0, utils_1.getTestId)(test)] ? Date.now() - _this.testTimeMap[(0, utils_1.getTestId)(test)].getTime() : 0; }; this._getTestStartTime = function (test) { return _this.testTimeMap[(0, utils_1.getTestId)(test)] ? _this.testTimeMap[(0, utils_1.getTestId)(test)].toISOString() : undefined; }; this.initStep = function (step) { _this.stepsProcessor.patchStepId(step); }; this.completeStep = function (step) { _this.stepsProcessor.processStep(step); }; this.handleStepComment = function (step) { _this.stepsProcessor.processComment(step); }; this.testTimeMap = {}; this.testRunId = null; this.testRunResults = []; this.testAttachments = {}; this.stepsProcessor = new StepsProcessor_1.default(); this.config = __assign(__assign({}, defaultConfig), config); var testItClientConfig = { url: this.config.url, configurationId: this.config.configurationId, privateToken: this.config.privateToken, projectId: this.config.projectId, }; var emptyRequiredProps = Object.keys(testItClientConfig) .filter(function (p) { return !testItClientConfig[p]; }) .map(function (p) { return p; }); if (emptyRequiredProps.length) throw new Error("Invalid TestIT config, following properties are required: ".concat(emptyRequiredProps.join(", "))); this.client = new testit_api_client_1.Client(testItClientConfig); // axios default content-type for empty POST is "application/x-www-form-urlencoded", // TestIT server rejects such requests with 415 status code starting from 4+ versions, // so we can fix it changing defaults in TestIT client instance // @ts-ignore this.client.axios.defaults.headers.post['Content-Type'] = 'application/json'; } Adapter.prototype._prepareTestRunLink = function () { if (!this.config.url || !this.config.globalProjectId || !this.testRunId) return null; return "".concat(this.config.url, "/projects/").concat(this.config.globalProjectId, "/test-runs/").concat(this.testRunId); }; return Adapter; }()); exports.default = Adapter;