test.js 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.TestCase = exports.Suite = void 0;
  6. var _testType = require("./testType");
  7. /**
  8. * Copyright Microsoft Corporation. All rights reserved.
  9. *
  10. * Licensed under the Apache License, Version 2.0 (the "License");
  11. * you may not use this file except in compliance with the License.
  12. * You may obtain a copy of the License at
  13. *
  14. * http://www.apache.org/licenses/LICENSE-2.0
  15. *
  16. * Unless required by applicable law or agreed to in writing, software
  17. * distributed under the License is distributed on an "AS IS" BASIS,
  18. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  19. * See the License for the specific language governing permissions and
  20. * limitations under the License.
  21. */
  22. class Base {
  23. constructor(title) {
  24. this.title = void 0;
  25. this._only = false;
  26. this._requireFile = '';
  27. this.title = title;
  28. }
  29. }
  30. class Suite extends Base {
  31. constructor(title, type) {
  32. super(title);
  33. this.location = void 0;
  34. this.parent = void 0;
  35. this._use = [];
  36. this._entries = [];
  37. this._hooks = [];
  38. this._timeout = void 0;
  39. this._retries = void 0;
  40. this._staticAnnotations = [];
  41. this._modifiers = [];
  42. this._parallelMode = 'none';
  43. this._fullProject = void 0;
  44. this._fileId = void 0;
  45. this._type = void 0;
  46. this._type = type;
  47. }
  48. get suites() {
  49. return this._entries.filter(entry => entry instanceof Suite);
  50. }
  51. get tests() {
  52. return this._entries.filter(entry => entry instanceof TestCase);
  53. }
  54. _addTest(test) {
  55. test.parent = this;
  56. this._entries.push(test);
  57. }
  58. _addSuite(suite) {
  59. suite.parent = this;
  60. this._entries.push(suite);
  61. }
  62. _prependSuite(suite) {
  63. suite.parent = this;
  64. this._entries.unshift(suite);
  65. }
  66. allTests() {
  67. const result = [];
  68. const visit = suite => {
  69. for (const entry of suite._entries) {
  70. if (entry instanceof Suite) visit(entry);else result.push(entry);
  71. }
  72. };
  73. visit(this);
  74. return result;
  75. }
  76. _hasTests() {
  77. let result = false;
  78. const visit = suite => {
  79. for (const entry of suite._entries) {
  80. if (result) return;
  81. if (entry instanceof Suite) visit(entry);else result = true;
  82. }
  83. };
  84. visit(this);
  85. return result;
  86. }
  87. titlePath() {
  88. const titlePath = this.parent ? this.parent.titlePath() : [];
  89. // Ignore anonymous describe blocks.
  90. if (this.title || this._type !== 'describe') titlePath.push(this.title);
  91. return titlePath;
  92. }
  93. _getOnlyItems() {
  94. const items = [];
  95. if (this._only) items.push(this);
  96. for (const suite of this.suites) items.push(...suite._getOnlyItems());
  97. items.push(...this.tests.filter(test => test._only));
  98. return items;
  99. }
  100. _deepClone() {
  101. const suite = this._clone();
  102. for (const entry of this._entries) {
  103. if (entry instanceof Suite) suite._addSuite(entry._deepClone());else suite._addTest(entry._clone());
  104. }
  105. return suite;
  106. }
  107. _deepSerialize() {
  108. const suite = this._serialize();
  109. suite.entries = [];
  110. for (const entry of this._entries) {
  111. if (entry instanceof Suite) suite.entries.push(entry._deepSerialize());else suite.entries.push(entry._serialize());
  112. }
  113. return suite;
  114. }
  115. static _deepParse(data) {
  116. const suite = Suite._parse(data);
  117. for (const entry of data.entries) {
  118. if (entry.kind === 'suite') suite._addSuite(Suite._deepParse(entry));else suite._addTest(TestCase._parse(entry));
  119. }
  120. return suite;
  121. }
  122. forEachTest(visitor) {
  123. for (const entry of this._entries) {
  124. if (entry instanceof Suite) entry.forEachTest(visitor);else visitor(entry, this);
  125. }
  126. }
  127. _serialize() {
  128. return {
  129. kind: 'suite',
  130. title: this.title,
  131. type: this._type,
  132. location: this.location,
  133. only: this._only,
  134. requireFile: this._requireFile,
  135. timeout: this._timeout,
  136. retries: this._retries,
  137. staticAnnotations: this._staticAnnotations.slice(),
  138. modifiers: this._modifiers.slice(),
  139. parallelMode: this._parallelMode,
  140. hooks: this._hooks.map(h => ({
  141. type: h.type,
  142. location: h.location,
  143. title: h.title
  144. })),
  145. fileId: this._fileId
  146. };
  147. }
  148. static _parse(data) {
  149. const suite = new Suite(data.title, data.type);
  150. suite.location = data.location;
  151. suite._only = data.only;
  152. suite._requireFile = data.requireFile;
  153. suite._timeout = data.timeout;
  154. suite._retries = data.retries;
  155. suite._staticAnnotations = data.staticAnnotations;
  156. suite._modifiers = data.modifiers;
  157. suite._parallelMode = data.parallelMode;
  158. suite._hooks = data.hooks.map(h => ({
  159. type: h.type,
  160. location: h.location,
  161. title: h.title,
  162. fn: () => {}
  163. }));
  164. suite._fileId = data.fileId;
  165. return suite;
  166. }
  167. _clone() {
  168. const data = this._serialize();
  169. const suite = Suite._parse(data);
  170. suite._use = this._use.slice();
  171. suite._hooks = this._hooks.slice();
  172. suite._fullProject = this._fullProject;
  173. return suite;
  174. }
  175. project() {
  176. var _this$_fullProject, _this$parent;
  177. return ((_this$_fullProject = this._fullProject) === null || _this$_fullProject === void 0 ? void 0 : _this$_fullProject.project) || ((_this$parent = this.parent) === null || _this$parent === void 0 ? void 0 : _this$parent.project());
  178. }
  179. }
  180. exports.Suite = Suite;
  181. class TestCase extends Base {
  182. constructor(title, fn, testType, location) {
  183. super(title);
  184. this.fn = void 0;
  185. this.results = [];
  186. this.location = void 0;
  187. this.parent = void 0;
  188. this.expectedStatus = 'passed';
  189. this.timeout = 0;
  190. this.annotations = [];
  191. this.retries = 0;
  192. this.repeatEachIndex = 0;
  193. this._testType = void 0;
  194. this.id = '';
  195. this._pool = void 0;
  196. this._poolDigest = '';
  197. this._workerHash = '';
  198. this._projectId = '';
  199. // Annotations known statically before running the test, e.g. `test.skip()` or `test.describe.skip()`.
  200. this._staticAnnotations = [];
  201. this.fn = fn;
  202. this._testType = testType;
  203. this.location = location;
  204. }
  205. titlePath() {
  206. const titlePath = this.parent ? this.parent.titlePath() : [];
  207. titlePath.push(this.title);
  208. return titlePath;
  209. }
  210. outcome() {
  211. // Ignore initial skips that may be a result of "skipped because previous test in serial mode failed".
  212. const results = [...this.results];
  213. 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') {
  214. var _results$, _results$2;
  215. results.shift();
  216. }
  217. // All runs were skipped.
  218. if (!results.length) return 'skipped';
  219. const failures = results.filter(result => result.status !== 'skipped' && result.status !== 'interrupted' && result.status !== this.expectedStatus);
  220. if (!failures.length)
  221. // all passed
  222. return 'expected';
  223. if (failures.length === results.length)
  224. // all failed
  225. return 'unexpected';
  226. return 'flaky'; // mixed bag
  227. }
  228. ok() {
  229. const status = this.outcome();
  230. return status === 'expected' || status === 'flaky' || status === 'skipped';
  231. }
  232. _serialize() {
  233. return {
  234. kind: 'test',
  235. id: this.id,
  236. title: this.title,
  237. retries: this.retries,
  238. timeout: this.timeout,
  239. expectedStatus: this.expectedStatus,
  240. location: this.location,
  241. only: this._only,
  242. requireFile: this._requireFile,
  243. poolDigest: this._poolDigest,
  244. workerHash: this._workerHash,
  245. staticAnnotations: this._staticAnnotations.slice(),
  246. annotations: this.annotations.slice(),
  247. projectId: this._projectId
  248. };
  249. }
  250. static _parse(data) {
  251. const test = new TestCase(data.title, () => {}, _testType.rootTestType, data.location);
  252. test.id = data.id;
  253. test.retries = data.retries;
  254. test.timeout = data.timeout;
  255. test.expectedStatus = data.expectedStatus;
  256. test._only = data.only;
  257. test._requireFile = data.requireFile;
  258. test._poolDigest = data.poolDigest;
  259. test._workerHash = data.workerHash;
  260. test._staticAnnotations = data.staticAnnotations;
  261. test.annotations = data.annotations;
  262. test._projectId = data.projectId;
  263. return test;
  264. }
  265. _clone() {
  266. const data = this._serialize();
  267. const test = TestCase._parse(data);
  268. test._testType = this._testType;
  269. test.fn = this.fn;
  270. return test;
  271. }
  272. _appendTestResult() {
  273. const result = {
  274. retry: this.results.length,
  275. parallelIndex: -1,
  276. workerIndex: -1,
  277. duration: 0,
  278. startTime: new Date(),
  279. stdout: [],
  280. stderr: [],
  281. attachments: [],
  282. status: 'skipped',
  283. steps: [],
  284. errors: []
  285. };
  286. this.results.push(result);
  287. return result;
  288. }
  289. }
  290. exports.TestCase = TestCase;