teleReceiver.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.baseFullConfig = exports.TeleTestCase = exports.TeleSuite = exports.TeleReporterReceiver = void 0;
  6. exports.parseRegexPatterns = parseRegexPatterns;
  7. exports.serializeRegexPatterns = serializeRegexPatterns;
  8. var _stringInternPool = require("./stringInternPool");
  9. /**
  10. * Copyright (c) Microsoft Corporation.
  11. *
  12. * Licensed under the Apache License, Version 2.0 (the "License");
  13. * you may not use this file except in compliance with the License.
  14. * You may obtain a copy of the License at
  15. *
  16. * http://www.apache.org/licenses/LICENSE-2.0
  17. *
  18. * Unless required by applicable law or agreed to in writing, software
  19. * distributed under the License is distributed on an "AS IS" BASIS,
  20. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  21. * See the License for the specific language governing permissions and
  22. * limitations under the License.
  23. */
  24. class TeleReporterReceiver {
  25. constructor(pathSeparator, reporter, reuseTestCases, reportConfig) {
  26. this._rootSuite = void 0;
  27. this._pathSeparator = void 0;
  28. this._reporter = void 0;
  29. this._tests = new Map();
  30. this._rootDir = void 0;
  31. this._listOnly = false;
  32. this._clearPreviousResultsWhenTestBegins = false;
  33. this._reuseTestCases = void 0;
  34. this._reportConfig = void 0;
  35. this._config = void 0;
  36. this._stringPool = new _stringInternPool.StringInternPool();
  37. this._rootSuite = new TeleSuite('', 'root');
  38. this._pathSeparator = pathSeparator;
  39. this._reporter = reporter;
  40. this._reuseTestCases = reuseTestCases;
  41. this._reportConfig = reportConfig;
  42. }
  43. dispatch(message) {
  44. const {
  45. method,
  46. params
  47. } = message;
  48. if (method === 'onConfigure') {
  49. this._onConfigure(params.config);
  50. return;
  51. }
  52. if (method === 'onProject') {
  53. this._onProject(params.project);
  54. return;
  55. }
  56. if (method === 'onBegin') {
  57. this._onBegin();
  58. return;
  59. }
  60. if (method === 'onTestBegin') {
  61. this._onTestBegin(params.testId, params.result);
  62. return;
  63. }
  64. if (method === 'onTestEnd') {
  65. this._onTestEnd(params.test, params.result);
  66. return;
  67. }
  68. if (method === 'onStepBegin') {
  69. this._onStepBegin(params.testId, params.resultId, params.step);
  70. return;
  71. }
  72. if (method === 'onStepEnd') {
  73. this._onStepEnd(params.testId, params.resultId, params.step);
  74. return;
  75. }
  76. if (method === 'onError') {
  77. this._onError(params.error);
  78. return;
  79. }
  80. if (method === 'onStdIO') {
  81. this._onStdIO(params.type, params.testId, params.resultId, params.data, params.isBase64);
  82. return;
  83. }
  84. if (method === 'onEnd') return this._onEnd(params.result);
  85. if (method === 'onExit') return this._onExit();
  86. }
  87. _setClearPreviousResultsWhenTestBegins() {
  88. this._clearPreviousResultsWhenTestBegins = true;
  89. }
  90. _onConfigure(config) {
  91. var _this$_reporter$onCon, _this$_reporter;
  92. this._rootDir = config.rootDir;
  93. this._listOnly = config.listOnly;
  94. this._config = this._parseConfig(config);
  95. (_this$_reporter$onCon = (_this$_reporter = this._reporter).onConfigure) === null || _this$_reporter$onCon === void 0 ? void 0 : _this$_reporter$onCon.call(_this$_reporter, this._config);
  96. }
  97. _onProject(project) {
  98. let projectSuite = this._rootSuite.suites.find(suite => suite.project().__projectId === project.id);
  99. if (!projectSuite) {
  100. projectSuite = new TeleSuite(project.name, 'project');
  101. this._rootSuite.suites.push(projectSuite);
  102. projectSuite.parent = this._rootSuite;
  103. }
  104. const p = this._parseProject(project);
  105. projectSuite.project = () => p;
  106. this._mergeSuitesInto(project.suites, projectSuite);
  107. // Remove deleted tests when listing. Empty suites will be auto-filtered
  108. // in the UI layer.
  109. if (this._listOnly) {
  110. const testIds = new Set();
  111. const collectIds = suite => {
  112. suite.tests.map(t => t.testId).forEach(testId => testIds.add(testId));
  113. suite.suites.forEach(collectIds);
  114. };
  115. project.suites.forEach(collectIds);
  116. const filterTests = suite => {
  117. suite.tests = suite.tests.filter(t => testIds.has(t.id));
  118. suite.suites.forEach(filterTests);
  119. };
  120. filterTests(projectSuite);
  121. }
  122. }
  123. _onBegin() {
  124. var _this$_reporter$onBeg, _this$_reporter2;
  125. (_this$_reporter$onBeg = (_this$_reporter2 = this._reporter).onBegin) === null || _this$_reporter$onBeg === void 0 ? void 0 : _this$_reporter$onBeg.call(_this$_reporter2, this._rootSuite);
  126. }
  127. _onTestBegin(testId, payload) {
  128. var _this$_reporter$onTes, _this$_reporter3;
  129. const test = this._tests.get(testId);
  130. if (this._clearPreviousResultsWhenTestBegins) test._clearResults();
  131. const testResult = test._createTestResult(payload.id);
  132. testResult.retry = payload.retry;
  133. testResult.workerIndex = payload.workerIndex;
  134. testResult.parallelIndex = payload.parallelIndex;
  135. testResult.setStartTimeNumber(payload.startTime);
  136. testResult.statusEx = 'running';
  137. (_this$_reporter$onTes = (_this$_reporter3 = this._reporter).onTestBegin) === null || _this$_reporter$onTes === void 0 ? void 0 : _this$_reporter$onTes.call(_this$_reporter3, test, testResult);
  138. }
  139. _onTestEnd(testEndPayload, payload) {
  140. var _result$errors, _this$_reporter$onTes2, _this$_reporter4;
  141. const test = this._tests.get(testEndPayload.testId);
  142. test.timeout = testEndPayload.timeout;
  143. test.expectedStatus = testEndPayload.expectedStatus;
  144. test.annotations = testEndPayload.annotations;
  145. const result = test.resultsMap.get(payload.id);
  146. result.duration = payload.duration;
  147. result.status = payload.status;
  148. result.statusEx = payload.status;
  149. result.errors = payload.errors;
  150. result.error = (_result$errors = result.errors) === null || _result$errors === void 0 ? void 0 : _result$errors[0];
  151. result.attachments = this._parseAttachments(payload.attachments);
  152. (_this$_reporter$onTes2 = (_this$_reporter4 = this._reporter).onTestEnd) === null || _this$_reporter$onTes2 === void 0 ? void 0 : _this$_reporter$onTes2.call(_this$_reporter4, test, result);
  153. // Free up the memory as won't see these step ids.
  154. result.stepMap = new Map();
  155. }
  156. _onStepBegin(testId, resultId, payload) {
  157. var _this$_reporter$onSte, _this$_reporter5;
  158. const test = this._tests.get(testId);
  159. const result = test.resultsMap.get(resultId);
  160. const parentStep = payload.parentStepId ? result.stepMap.get(payload.parentStepId) : undefined;
  161. const location = this._absoluteLocation(payload.location);
  162. const step = new TeleTestStep(payload, parentStep, location);
  163. if (parentStep) parentStep.steps.push(step);else result.steps.push(step);
  164. result.stepMap.set(payload.id, step);
  165. (_this$_reporter$onSte = (_this$_reporter5 = this._reporter).onStepBegin) === null || _this$_reporter$onSte === void 0 ? void 0 : _this$_reporter$onSte.call(_this$_reporter5, test, result, step);
  166. }
  167. _onStepEnd(testId, resultId, payload) {
  168. var _this$_reporter$onSte2, _this$_reporter6;
  169. const test = this._tests.get(testId);
  170. const result = test.resultsMap.get(resultId);
  171. const step = result.stepMap.get(payload.id);
  172. step.duration = payload.duration;
  173. step.error = payload.error;
  174. (_this$_reporter$onSte2 = (_this$_reporter6 = this._reporter).onStepEnd) === null || _this$_reporter$onSte2 === void 0 ? void 0 : _this$_reporter$onSte2.call(_this$_reporter6, test, result, step);
  175. }
  176. _onError(error) {
  177. var _this$_reporter$onErr, _this$_reporter7;
  178. (_this$_reporter$onErr = (_this$_reporter7 = this._reporter).onError) === null || _this$_reporter$onErr === void 0 ? void 0 : _this$_reporter$onErr.call(_this$_reporter7, error);
  179. }
  180. _onStdIO(type, testId, resultId, data, isBase64) {
  181. const chunk = isBase64 ? globalThis.Buffer ? Buffer.from(data, 'base64') : atob(data) : data;
  182. const test = testId ? this._tests.get(testId) : undefined;
  183. const result = test && resultId ? test.resultsMap.get(resultId) : undefined;
  184. if (type === 'stdout') {
  185. var _this$_reporter$onStd, _this$_reporter8;
  186. result === null || result === void 0 ? void 0 : result.stdout.push(chunk);
  187. (_this$_reporter$onStd = (_this$_reporter8 = this._reporter).onStdOut) === null || _this$_reporter$onStd === void 0 ? void 0 : _this$_reporter$onStd.call(_this$_reporter8, chunk, test, result);
  188. } else {
  189. var _this$_reporter$onStd2, _this$_reporter9;
  190. result === null || result === void 0 ? void 0 : result.stderr.push(chunk);
  191. (_this$_reporter$onStd2 = (_this$_reporter9 = this._reporter).onStdErr) === null || _this$_reporter$onStd2 === void 0 ? void 0 : _this$_reporter$onStd2.call(_this$_reporter9, chunk, test, result);
  192. }
  193. }
  194. async _onEnd(result) {
  195. var _this$_reporter$onEnd, _this$_reporter10;
  196. await ((_this$_reporter$onEnd = (_this$_reporter10 = this._reporter).onEnd) === null || _this$_reporter$onEnd === void 0 ? void 0 : _this$_reporter$onEnd.call(_this$_reporter10, {
  197. status: result.status,
  198. startTime: new Date(result.startTime),
  199. duration: result.duration
  200. }));
  201. }
  202. _onExit() {
  203. var _this$_reporter$onExi, _this$_reporter11;
  204. // Free up the memory from the string pool.
  205. this._stringPool = new _stringInternPool.StringInternPool();
  206. return (_this$_reporter$onExi = (_this$_reporter11 = this._reporter).onExit) === null || _this$_reporter$onExi === void 0 ? void 0 : _this$_reporter$onExi.call(_this$_reporter11);
  207. }
  208. _parseConfig(config) {
  209. const result = {
  210. ...baseFullConfig,
  211. ...config
  212. };
  213. if (this._reportConfig) {
  214. result.configFile = this._reportConfig.configFile;
  215. result.reportSlowTests = this._reportConfig.reportSlowTests;
  216. result.quiet = this._reportConfig.quiet;
  217. result.reporter = [...this._reportConfig.reporter];
  218. }
  219. return result;
  220. }
  221. _parseProject(project) {
  222. return {
  223. __projectId: project.id,
  224. metadata: project.metadata,
  225. name: project.name,
  226. outputDir: this._absolutePath(project.outputDir),
  227. repeatEach: project.repeatEach,
  228. retries: project.retries,
  229. testDir: this._absolutePath(project.testDir),
  230. testIgnore: parseRegexPatterns(project.testIgnore),
  231. testMatch: parseRegexPatterns(project.testMatch),
  232. timeout: project.timeout,
  233. grep: parseRegexPatterns(project.grep),
  234. grepInvert: parseRegexPatterns(project.grepInvert),
  235. dependencies: project.dependencies,
  236. teardown: project.teardown,
  237. snapshotDir: this._absolutePath(project.snapshotDir),
  238. use: {}
  239. };
  240. }
  241. _parseAttachments(attachments) {
  242. return attachments.map(a => {
  243. return {
  244. ...a,
  245. body: a.base64 && globalThis.Buffer ? Buffer.from(a.base64, 'base64') : undefined
  246. };
  247. });
  248. }
  249. _mergeSuitesInto(jsonSuites, parent) {
  250. for (const jsonSuite of jsonSuites) {
  251. let targetSuite = parent.suites.find(s => s.title === jsonSuite.title);
  252. if (!targetSuite) {
  253. targetSuite = new TeleSuite(jsonSuite.title, jsonSuite.type);
  254. targetSuite.parent = parent;
  255. parent.suites.push(targetSuite);
  256. }
  257. targetSuite.location = this._absoluteLocation(jsonSuite.location);
  258. targetSuite._fileId = jsonSuite.fileId;
  259. targetSuite._parallelMode = jsonSuite.parallelMode;
  260. this._mergeSuitesInto(jsonSuite.suites, targetSuite);
  261. this._mergeTestsInto(jsonSuite.tests, targetSuite);
  262. }
  263. }
  264. _mergeTestsInto(jsonTests, parent) {
  265. for (const jsonTest of jsonTests) {
  266. let targetTest = this._reuseTestCases ? parent.tests.find(s => s.title === jsonTest.title) : undefined;
  267. if (!targetTest) {
  268. targetTest = new TeleTestCase(jsonTest.testId, jsonTest.title, this._absoluteLocation(jsonTest.location));
  269. targetTest.parent = parent;
  270. parent.tests.push(targetTest);
  271. this._tests.set(targetTest.id, targetTest);
  272. }
  273. this._updateTest(jsonTest, targetTest);
  274. }
  275. }
  276. _updateTest(payload, test) {
  277. test.id = payload.testId;
  278. test.location = this._absoluteLocation(payload.location);
  279. test.retries = payload.retries;
  280. return test;
  281. }
  282. _absoluteLocation(location) {
  283. if (!location) return location;
  284. return {
  285. ...location,
  286. file: this._absolutePath(location.file)
  287. };
  288. }
  289. _absolutePath(relativePath) {
  290. if (!relativePath) return relativePath;
  291. return this._stringPool.internString(this._rootDir + this._pathSeparator + relativePath);
  292. }
  293. }
  294. exports.TeleReporterReceiver = TeleReporterReceiver;
  295. class TeleSuite {
  296. constructor(title, type) {
  297. this.title = void 0;
  298. this.location = void 0;
  299. this.parent = void 0;
  300. this._requireFile = '';
  301. this.suites = [];
  302. this.tests = [];
  303. this._timeout = void 0;
  304. this._retries = void 0;
  305. this._fileId = void 0;
  306. this._parallelMode = 'none';
  307. this._type = void 0;
  308. this.title = title;
  309. this._type = type;
  310. }
  311. allTests() {
  312. const result = [];
  313. const visit = suite => {
  314. for (const entry of [...suite.suites, ...suite.tests]) {
  315. if (entry instanceof TeleSuite) visit(entry);else result.push(entry);
  316. }
  317. };
  318. visit(this);
  319. return result;
  320. }
  321. titlePath() {
  322. const titlePath = this.parent ? this.parent.titlePath() : [];
  323. // Ignore anonymous describe blocks.
  324. if (this.title || this._type !== 'describe') titlePath.push(this.title);
  325. return titlePath;
  326. }
  327. project() {
  328. return undefined;
  329. }
  330. }
  331. exports.TeleSuite = TeleSuite;
  332. class TeleTestCase {
  333. constructor(id, title, location) {
  334. this.title = void 0;
  335. this.fn = () => {};
  336. this.results = [];
  337. this.location = void 0;
  338. this.parent = void 0;
  339. this.expectedStatus = 'passed';
  340. this.timeout = 0;
  341. this.annotations = [];
  342. this.retries = 0;
  343. this.repeatEachIndex = 0;
  344. this.id = void 0;
  345. this.resultsMap = new Map();
  346. this.id = id;
  347. this.title = title;
  348. this.location = location;
  349. }
  350. titlePath() {
  351. const titlePath = this.parent ? this.parent.titlePath() : [];
  352. titlePath.push(this.title);
  353. return titlePath;
  354. }
  355. outcome() {
  356. // Ignore initial skips that may be a result of "skipped because previous test in serial mode failed".
  357. const results = [...this.results];
  358. while (((_results$ = results[0]) === null || _results$ === void 0 ? void 0 : _results$.status) === 'skipped' || ((_results$2 = results[0]) === null || _results$2 === void 0 ? void 0 : _results$2.status) === 'interrupted') {
  359. var _results$, _results$2;
  360. results.shift();
  361. }
  362. // All runs were skipped.
  363. if (!results.length) return 'skipped';
  364. const failures = results.filter(result => result.status !== 'skipped' && result.status !== 'interrupted' && result.status !== this.expectedStatus);
  365. if (!failures.length)
  366. // all passed
  367. return 'expected';
  368. if (failures.length === results.length)
  369. // all failed
  370. return 'unexpected';
  371. return 'flaky'; // mixed bag
  372. }
  373. ok() {
  374. const status = this.outcome();
  375. return status === 'expected' || status === 'flaky' || status === 'skipped';
  376. }
  377. _clearResults() {
  378. this.results = [];
  379. this.resultsMap.clear();
  380. }
  381. _createTestResult(id) {
  382. const result = new TeleTestResult(this.results.length);
  383. this.results.push(result);
  384. this.resultsMap.set(id, result);
  385. return result;
  386. }
  387. }
  388. exports.TeleTestCase = TeleTestCase;
  389. class TeleTestStep {
  390. constructor(payload, parentStep, location) {
  391. this.title = void 0;
  392. this.category = void 0;
  393. this.location = void 0;
  394. this.parent = void 0;
  395. this.duration = -1;
  396. this.steps = [];
  397. this._startTime = 0;
  398. this.title = payload.title;
  399. this.category = payload.category;
  400. this.location = location;
  401. this.parent = parentStep;
  402. this._startTime = payload.startTime;
  403. }
  404. titlePath() {
  405. var _this$parent;
  406. const parentPath = ((_this$parent = this.parent) === null || _this$parent === void 0 ? void 0 : _this$parent.titlePath()) || [];
  407. return [...parentPath, this.title];
  408. }
  409. get startTime() {
  410. return new Date(this._startTime);
  411. }
  412. set startTime(value) {
  413. this._startTime = +value;
  414. }
  415. }
  416. class TeleTestResult {
  417. constructor(retry) {
  418. this.retry = void 0;
  419. this.parallelIndex = -1;
  420. this.workerIndex = -1;
  421. this.duration = -1;
  422. this.stdout = [];
  423. this.stderr = [];
  424. this.attachments = [];
  425. this.status = 'skipped';
  426. this.steps = [];
  427. this.errors = [];
  428. this.error = void 0;
  429. this.stepMap = new Map();
  430. this.statusEx = 'scheduled';
  431. this._startTime = 0;
  432. this.retry = retry;
  433. }
  434. setStartTimeNumber(startTime) {
  435. this._startTime = startTime;
  436. }
  437. get startTime() {
  438. return new Date(this._startTime);
  439. }
  440. set startTime(value) {
  441. this._startTime = +value;
  442. }
  443. }
  444. const baseFullConfig = exports.baseFullConfig = {
  445. forbidOnly: false,
  446. fullyParallel: false,
  447. globalSetup: null,
  448. globalTeardown: null,
  449. globalTimeout: 0,
  450. grep: /.*/,
  451. grepInvert: null,
  452. maxFailures: 0,
  453. metadata: {},
  454. preserveOutput: 'always',
  455. projects: [],
  456. reporter: [[process.env.CI ? 'dot' : 'list']],
  457. reportSlowTests: {
  458. max: 5,
  459. threshold: 15000
  460. },
  461. configFile: '',
  462. rootDir: '',
  463. quiet: false,
  464. shard: null,
  465. updateSnapshots: 'missing',
  466. version: '',
  467. workers: 0,
  468. webServer: null
  469. };
  470. function serializeRegexPatterns(patterns) {
  471. if (!Array.isArray(patterns)) patterns = [patterns];
  472. return patterns.map(s => {
  473. if (typeof s === 'string') return {
  474. s
  475. };
  476. return {
  477. r: {
  478. source: s.source,
  479. flags: s.flags
  480. }
  481. };
  482. });
  483. }
  484. function parseRegexPatterns(patterns) {
  485. return patterns.map(p => {
  486. if (p.s) return p.s;
  487. return new RegExp(p.r.source, p.r.flags);
  488. });
  489. }