Env.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801
  1. 'use strict';
  2. Object.defineProperty(exports, '__esModule', {
  3. value: true
  4. });
  5. exports.default = _default;
  6. var _assert = require('assert');
  7. var _chalk = _interopRequireDefault(require('chalk'));
  8. var _jestMessageUtil = require('jest-message-util');
  9. var _jestUtil = require('jest-util');
  10. var _queueRunner = _interopRequireDefault(require('../queueRunner'));
  11. var _treeProcessor = _interopRequireDefault(require('../treeProcessor'));
  12. var _isError = _interopRequireDefault(require('../isError'));
  13. var _assertionErrorMessage = _interopRequireDefault(
  14. require('../assertionErrorMessage')
  15. );
  16. function _interopRequireDefault(obj) {
  17. return obj && obj.__esModule ? obj : {default: obj};
  18. }
  19. var Symbol = global['jest-symbol-do-not-touch'] || global.Symbol;
  20. var Symbol = global['jest-symbol-do-not-touch'] || global.Symbol;
  21. var Promise = global[Symbol.for('jest-native-promise')] || global.Promise;
  22. function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
  23. try {
  24. var info = gen[key](arg);
  25. var value = info.value;
  26. } catch (error) {
  27. reject(error);
  28. return;
  29. }
  30. if (info.done) {
  31. resolve(value);
  32. } else {
  33. Promise.resolve(value).then(_next, _throw);
  34. }
  35. }
  36. function _asyncToGenerator(fn) {
  37. return function() {
  38. var self = this,
  39. args = arguments;
  40. return new Promise(function(resolve, reject) {
  41. var gen = fn.apply(self, args);
  42. function _next(value) {
  43. asyncGeneratorStep(gen, resolve, reject, _next, _throw, 'next', value);
  44. }
  45. function _throw(err) {
  46. asyncGeneratorStep(gen, resolve, reject, _next, _throw, 'throw', err);
  47. }
  48. _next(undefined);
  49. });
  50. };
  51. }
  52. function _defineProperty(obj, key, value) {
  53. if (key in obj) {
  54. Object.defineProperty(obj, key, {
  55. value: value,
  56. enumerable: true,
  57. configurable: true,
  58. writable: true
  59. });
  60. } else {
  61. obj[key] = value;
  62. }
  63. return obj;
  64. }
  65. function _default(j$) {
  66. var _temp;
  67. return (
  68. (_temp = class Env {
  69. constructor(_options) {
  70. _defineProperty(this, 'specFilter', void 0);
  71. _defineProperty(this, 'catchExceptions', void 0);
  72. _defineProperty(this, 'throwOnExpectationFailure', void 0);
  73. _defineProperty(this, 'catchingExceptions', void 0);
  74. _defineProperty(this, 'topSuite', void 0);
  75. _defineProperty(this, 'fail', void 0);
  76. _defineProperty(this, 'pending', void 0);
  77. _defineProperty(this, 'afterAll', void 0);
  78. _defineProperty(this, 'fit', void 0);
  79. _defineProperty(this, 'throwingExpectationFailures', void 0);
  80. _defineProperty(this, 'randomizeTests', void 0);
  81. _defineProperty(this, 'randomTests', void 0);
  82. _defineProperty(this, 'seed', void 0);
  83. _defineProperty(this, 'execute', void 0);
  84. _defineProperty(this, 'fdescribe', void 0);
  85. _defineProperty(this, 'spyOn', void 0);
  86. _defineProperty(this, 'beforeEach', void 0);
  87. _defineProperty(this, 'afterEach', void 0);
  88. _defineProperty(this, 'clearReporters', void 0);
  89. _defineProperty(this, 'addReporter', void 0);
  90. _defineProperty(this, 'it', void 0);
  91. _defineProperty(this, 'xdescribe', void 0);
  92. _defineProperty(this, 'xit', void 0);
  93. _defineProperty(this, 'beforeAll', void 0);
  94. _defineProperty(this, 'todo', void 0);
  95. _defineProperty(this, 'provideFallbackReporter', void 0);
  96. _defineProperty(this, 'allowRespy', void 0);
  97. _defineProperty(this, 'describe', void 0);
  98. let totalSpecsDefined = 0;
  99. let catchExceptions = true;
  100. const realSetTimeout = global.setTimeout;
  101. const realClearTimeout = global.clearTimeout;
  102. const runnableResources = {};
  103. const currentlyExecutingSuites = [];
  104. let currentSpec = null;
  105. let throwOnExpectationFailure = false;
  106. let random = false;
  107. let seed = null;
  108. let nextSpecId = 0;
  109. let nextSuiteId = 0;
  110. const getNextSpecId = function getNextSpecId() {
  111. return 'spec' + nextSpecId++;
  112. };
  113. const getNextSuiteId = function getNextSuiteId() {
  114. return 'suite' + nextSuiteId++;
  115. };
  116. const topSuite = new j$.Suite({
  117. id: getNextSuiteId(),
  118. description: '',
  119. getTestPath() {
  120. return j$.testPath;
  121. }
  122. });
  123. let currentDeclarationSuite = topSuite;
  124. const currentSuite = function currentSuite() {
  125. return currentlyExecutingSuites[currentlyExecutingSuites.length - 1];
  126. };
  127. const currentRunnable = function currentRunnable() {
  128. return currentSpec || currentSuite();
  129. };
  130. const reporter = new j$.ReportDispatcher([
  131. 'jasmineStarted',
  132. 'jasmineDone',
  133. 'suiteStarted',
  134. 'suiteDone',
  135. 'specStarted',
  136. 'specDone'
  137. ]);
  138. this.specFilter = function() {
  139. return true;
  140. };
  141. const defaultResourcesForRunnable = function defaultResourcesForRunnable(
  142. id,
  143. _parentRunnableId
  144. ) {
  145. const resources = {
  146. spies: []
  147. };
  148. runnableResources[id] = resources;
  149. };
  150. const clearResourcesForRunnable = function clearResourcesForRunnable(
  151. id
  152. ) {
  153. spyRegistry.clearSpies();
  154. delete runnableResources[id];
  155. };
  156. const beforeAndAfterFns = function beforeAndAfterFns(suite) {
  157. return function() {
  158. let afters = [];
  159. let befores = [];
  160. while (suite) {
  161. befores = befores.concat(suite.beforeFns);
  162. afters = afters.concat(suite.afterFns);
  163. suite = suite.parentSuite;
  164. }
  165. return {
  166. befores: befores.reverse(),
  167. afters
  168. };
  169. };
  170. };
  171. const getSpecName = function getSpecName(spec, suite) {
  172. const fullName = [spec.description];
  173. const suiteFullName = suite.getFullName();
  174. if (suiteFullName !== '') {
  175. fullName.unshift(suiteFullName);
  176. }
  177. return fullName.join(' ');
  178. };
  179. this.catchExceptions = function(value) {
  180. catchExceptions = !!value;
  181. return catchExceptions;
  182. };
  183. this.catchingExceptions = function() {
  184. return catchExceptions;
  185. };
  186. this.throwOnExpectationFailure = function(value) {
  187. throwOnExpectationFailure = !!value;
  188. };
  189. this.throwingExpectationFailures = function() {
  190. return throwOnExpectationFailure;
  191. };
  192. this.randomizeTests = function(value) {
  193. random = !!value;
  194. };
  195. this.randomTests = function() {
  196. return random;
  197. };
  198. this.seed = function(value) {
  199. if (value) {
  200. seed = value;
  201. }
  202. return seed;
  203. };
  204. const queueRunnerFactory = options => {
  205. options.clearTimeout = realClearTimeout;
  206. options.fail = this.fail;
  207. options.setTimeout = realSetTimeout;
  208. return (0, _queueRunner.default)(options);
  209. };
  210. this.topSuite = function() {
  211. return topSuite;
  212. };
  213. const uncaught = err => {
  214. if (currentSpec) {
  215. currentSpec.onException(err);
  216. currentSpec.cancel();
  217. } else {
  218. console.error('Unhandled error');
  219. console.error(err.stack);
  220. }
  221. };
  222. let oldListenersException;
  223. let oldListenersRejection;
  224. const executionSetup = function executionSetup() {
  225. // Need to ensure we are the only ones handling these exceptions.
  226. oldListenersException = process
  227. .listeners('uncaughtException')
  228. .slice();
  229. oldListenersRejection = process
  230. .listeners('unhandledRejection')
  231. .slice();
  232. j$.process.removeAllListeners('uncaughtException');
  233. j$.process.removeAllListeners('unhandledRejection');
  234. j$.process.on('uncaughtException', uncaught);
  235. j$.process.on('unhandledRejection', uncaught);
  236. };
  237. const executionTeardown = function executionTeardown() {
  238. j$.process.removeListener('uncaughtException', uncaught);
  239. j$.process.removeListener('unhandledRejection', uncaught); // restore previous exception handlers
  240. oldListenersException.forEach(listener => {
  241. j$.process.on('uncaughtException', listener);
  242. });
  243. oldListenersRejection.forEach(listener => {
  244. j$.process.on('unhandledRejection', listener);
  245. });
  246. };
  247. this.execute =
  248. /*#__PURE__*/
  249. (function() {
  250. var _ref = _asyncToGenerator(function*(
  251. runnablesToRun,
  252. suiteTree = topSuite
  253. ) {
  254. if (!runnablesToRun) {
  255. if (focusedRunnables.length) {
  256. runnablesToRun = focusedRunnables;
  257. } else {
  258. runnablesToRun = [suiteTree.id];
  259. }
  260. }
  261. if (currentlyExecutingSuites.length === 0) {
  262. executionSetup();
  263. }
  264. const lastDeclarationSuite = currentDeclarationSuite;
  265. yield (0, _treeProcessor.default)({
  266. nodeComplete(suite) {
  267. if (!suite.disabled) {
  268. clearResourcesForRunnable(suite.id);
  269. }
  270. currentlyExecutingSuites.pop();
  271. if (suite === topSuite) {
  272. reporter.jasmineDone({
  273. failedExpectations: topSuite.result.failedExpectations
  274. });
  275. } else {
  276. reporter.suiteDone(suite.getResult());
  277. }
  278. },
  279. nodeStart(suite) {
  280. currentlyExecutingSuites.push(suite);
  281. defaultResourcesForRunnable(
  282. suite.id,
  283. suite.parentSuite && suite.parentSuite.id
  284. );
  285. if (suite === topSuite) {
  286. reporter.jasmineStarted({
  287. totalSpecsDefined
  288. });
  289. } else {
  290. reporter.suiteStarted(suite.result);
  291. }
  292. },
  293. queueRunnerFactory,
  294. runnableIds: runnablesToRun,
  295. tree: suiteTree
  296. });
  297. currentDeclarationSuite = lastDeclarationSuite;
  298. if (currentlyExecutingSuites.length === 0) {
  299. executionTeardown();
  300. }
  301. });
  302. return function(_x) {
  303. return _ref.apply(this, arguments);
  304. };
  305. })();
  306. this.addReporter = function(reporterToAdd) {
  307. reporter.addReporter(reporterToAdd);
  308. };
  309. this.provideFallbackReporter = function(reporterToAdd) {
  310. reporter.provideFallbackReporter(reporterToAdd);
  311. };
  312. this.clearReporters = function() {
  313. reporter.clearReporters();
  314. };
  315. const spyRegistry = new j$.SpyRegistry({
  316. currentSpies() {
  317. if (!currentRunnable()) {
  318. throw new Error(
  319. 'Spies must be created in a before function or a spec'
  320. );
  321. }
  322. return runnableResources[currentRunnable().id].spies;
  323. }
  324. });
  325. this.allowRespy = function(allow) {
  326. spyRegistry.allowRespy(allow);
  327. };
  328. this.spyOn = function(...args) {
  329. return spyRegistry.spyOn.apply(spyRegistry, args);
  330. };
  331. const suiteFactory = function suiteFactory(description) {
  332. const suite = new j$.Suite({
  333. id: getNextSuiteId(),
  334. description,
  335. parentSuite: currentDeclarationSuite,
  336. throwOnExpectationFailure,
  337. getTestPath() {
  338. return j$.testPath;
  339. }
  340. });
  341. return suite;
  342. };
  343. this.describe = function(description, specDefinitions) {
  344. const suite = suiteFactory(description);
  345. if (specDefinitions === undefined) {
  346. throw new Error(
  347. `Missing second argument. It must be a callback function.`
  348. );
  349. }
  350. if (typeof specDefinitions !== 'function') {
  351. throw new Error(
  352. `Invalid second argument, ${specDefinitions}. It must be a callback function.`
  353. );
  354. }
  355. if (specDefinitions.length > 0) {
  356. throw new Error('describe does not expect any arguments');
  357. }
  358. if (currentDeclarationSuite.markedPending) {
  359. suite.pend();
  360. }
  361. if (currentDeclarationSuite.markedTodo) {
  362. // @ts-ignore TODO Possible error: Suite does not have todo method
  363. suite.todo();
  364. }
  365. addSpecsToSuite(suite, specDefinitions);
  366. return suite;
  367. };
  368. this.xdescribe = function(description, specDefinitions) {
  369. const suite = suiteFactory(description);
  370. suite.pend();
  371. addSpecsToSuite(suite, specDefinitions);
  372. return suite;
  373. };
  374. const focusedRunnables = [];
  375. this.fdescribe = function(description, specDefinitions) {
  376. const suite = suiteFactory(description);
  377. suite.isFocused = true;
  378. focusedRunnables.push(suite.id);
  379. unfocusAncestor();
  380. addSpecsToSuite(suite, specDefinitions);
  381. return suite;
  382. };
  383. const addSpecsToSuite = (suite, specDefinitions) => {
  384. const parentSuite = currentDeclarationSuite;
  385. parentSuite.addChild(suite);
  386. currentDeclarationSuite = suite;
  387. let declarationError = undefined;
  388. let describeReturnValue = undefined;
  389. try {
  390. describeReturnValue = specDefinitions.call(suite);
  391. } catch (e) {
  392. declarationError = e;
  393. } // TODO throw in Jest 25: declarationError = new Error
  394. if ((0, _jestUtil.isPromise)(describeReturnValue)) {
  395. console.log(
  396. (0, _jestMessageUtil.formatExecError)(
  397. new Error(
  398. _chalk.default.yellow(
  399. 'Returning a Promise from "describe" is not supported. Tests must be defined synchronously.\n' +
  400. 'Returning a value from "describe" will fail the test in a future version of Jest.'
  401. )
  402. ),
  403. {
  404. rootDir: '',
  405. testMatch: []
  406. },
  407. {
  408. noStackTrace: false
  409. }
  410. )
  411. );
  412. } else if (describeReturnValue !== undefined) {
  413. console.log(
  414. (0, _jestMessageUtil.formatExecError)(
  415. new Error(
  416. _chalk.default.yellow(
  417. 'A "describe" callback must not return a value.\n' +
  418. 'Returning a value from "describe" will fail the test in a future version of Jest.'
  419. )
  420. ),
  421. {
  422. rootDir: '',
  423. testMatch: []
  424. },
  425. {
  426. noStackTrace: false
  427. }
  428. )
  429. );
  430. }
  431. if (declarationError) {
  432. this.it('encountered a declaration exception', () => {
  433. throw declarationError;
  434. });
  435. }
  436. currentDeclarationSuite = parentSuite;
  437. };
  438. function findFocusedAncestor(suite) {
  439. while (suite) {
  440. if (suite.isFocused) {
  441. return suite.id;
  442. }
  443. suite = suite.parentSuite;
  444. }
  445. return null;
  446. }
  447. function unfocusAncestor() {
  448. const focusedAncestor = findFocusedAncestor(currentDeclarationSuite);
  449. if (focusedAncestor) {
  450. for (let i = 0; i < focusedRunnables.length; i++) {
  451. if (focusedRunnables[i] === focusedAncestor) {
  452. focusedRunnables.splice(i, 1);
  453. break;
  454. }
  455. }
  456. }
  457. }
  458. const specFactory = (description, fn, suite, timeout) => {
  459. totalSpecsDefined++;
  460. const spec = new j$.Spec({
  461. id: getNextSpecId(),
  462. beforeAndAfterFns: beforeAndAfterFns(suite),
  463. resultCallback: specResultCallback,
  464. getSpecName(spec) {
  465. return getSpecName(spec, suite);
  466. },
  467. getTestPath() {
  468. return j$.testPath;
  469. },
  470. onStart: specStarted,
  471. description,
  472. queueRunnerFactory,
  473. userContext() {
  474. return suite.clonedSharedUserContext();
  475. },
  476. queueableFn: {
  477. fn,
  478. timeout() {
  479. return timeout || j$._DEFAULT_TIMEOUT_INTERVAL;
  480. }
  481. },
  482. throwOnExpectationFailure
  483. });
  484. if (!this.specFilter(spec)) {
  485. spec.disable();
  486. }
  487. return spec;
  488. function specResultCallback(result) {
  489. clearResourcesForRunnable(spec.id);
  490. currentSpec = null;
  491. reporter.specDone(result);
  492. }
  493. function specStarted(spec) {
  494. currentSpec = spec;
  495. defaultResourcesForRunnable(spec.id, suite.id);
  496. reporter.specStarted(spec.result);
  497. }
  498. };
  499. this.it = function(description, fn, timeout) {
  500. if (typeof description !== 'string') {
  501. throw new Error(
  502. `Invalid first argument, ${description}. It must be a string.`
  503. );
  504. }
  505. if (fn === undefined) {
  506. throw new Error(
  507. 'Missing second argument. It must be a callback function. Perhaps you want to use `test.todo` for a test placeholder.'
  508. );
  509. }
  510. if (typeof fn !== 'function') {
  511. throw new Error(
  512. `Invalid second argument, ${fn}. It must be a callback function.`
  513. );
  514. }
  515. const spec = specFactory(
  516. description,
  517. fn,
  518. currentDeclarationSuite,
  519. timeout
  520. );
  521. if (currentDeclarationSuite.markedPending) {
  522. spec.pend();
  523. } // When a test is defined inside another, jasmine will not run it.
  524. // This check throws an error to warn the user about the edge-case.
  525. if (currentSpec !== null) {
  526. throw new Error(
  527. 'Tests cannot be nested. Test `' +
  528. spec.description +
  529. '` cannot run because it is nested within `' +
  530. currentSpec.description +
  531. '`.'
  532. );
  533. }
  534. currentDeclarationSuite.addChild(spec);
  535. return spec;
  536. };
  537. this.xit = function(...args) {
  538. const spec = this.it.apply(this, args);
  539. spec.pend('Temporarily disabled with xit');
  540. return spec;
  541. };
  542. this.todo = function() {
  543. const description = arguments[0];
  544. if (arguments.length !== 1 || typeof description !== 'string') {
  545. throw new _jestUtil.ErrorWithStack(
  546. 'Todo must be called with only a description.',
  547. test.todo
  548. );
  549. }
  550. const spec = specFactory(
  551. description,
  552. () => {},
  553. currentDeclarationSuite
  554. );
  555. spec.todo();
  556. currentDeclarationSuite.addChild(spec);
  557. return spec;
  558. };
  559. this.fit = function(description, fn, timeout) {
  560. const spec = specFactory(
  561. description,
  562. fn,
  563. currentDeclarationSuite,
  564. timeout
  565. );
  566. currentDeclarationSuite.addChild(spec);
  567. focusedRunnables.push(spec.id);
  568. unfocusAncestor();
  569. return spec;
  570. };
  571. this.beforeEach = function(beforeEachFunction, timeout) {
  572. currentDeclarationSuite.beforeEach({
  573. fn: beforeEachFunction,
  574. timeout() {
  575. return timeout || j$._DEFAULT_TIMEOUT_INTERVAL;
  576. }
  577. });
  578. };
  579. this.beforeAll = function(beforeAllFunction, timeout) {
  580. currentDeclarationSuite.beforeAll({
  581. fn: beforeAllFunction,
  582. timeout() {
  583. return timeout || j$._DEFAULT_TIMEOUT_INTERVAL;
  584. }
  585. });
  586. };
  587. this.afterEach = function(afterEachFunction, timeout) {
  588. currentDeclarationSuite.afterEach({
  589. fn: afterEachFunction,
  590. timeout() {
  591. return timeout || j$._DEFAULT_TIMEOUT_INTERVAL;
  592. }
  593. });
  594. };
  595. this.afterAll = function(afterAllFunction, timeout) {
  596. currentDeclarationSuite.afterAll({
  597. fn: afterAllFunction,
  598. timeout() {
  599. return timeout || j$._DEFAULT_TIMEOUT_INTERVAL;
  600. }
  601. });
  602. };
  603. this.pending = function(message) {
  604. let fullMessage = j$.Spec.pendingSpecExceptionMessage;
  605. if (message) {
  606. fullMessage += message;
  607. }
  608. throw fullMessage;
  609. };
  610. this.fail = function(error) {
  611. let checkIsError;
  612. let message;
  613. if (
  614. error instanceof _assert.AssertionError ||
  615. (error && error.name === _assert.AssertionError.name)
  616. ) {
  617. checkIsError = false; // @ts-ignore TODO Possible error: j$.Spec does not have expand property
  618. message = (0, _assertionErrorMessage.default)(error, {
  619. expand: j$.Spec.expand
  620. });
  621. } else {
  622. const check = (0, _isError.default)(error);
  623. checkIsError = check.isError;
  624. message = check.message;
  625. }
  626. const errorAsErrorObject = checkIsError ? error : new Error(message);
  627. const runnable = currentRunnable();
  628. if (!runnable) {
  629. errorAsErrorObject.message =
  630. 'Caught error after test environment was torn down\n\n' +
  631. errorAsErrorObject.message;
  632. throw errorAsErrorObject;
  633. }
  634. runnable.addExpectationResult(false, {
  635. matcherName: '',
  636. passed: false,
  637. expected: '',
  638. actual: '',
  639. message,
  640. error: errorAsErrorObject
  641. });
  642. };
  643. }
  644. }),
  645. _temp
  646. );
  647. }