| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237 | 'use strict';Object.defineProperty(exports, '__esModule', {  value: true});exports.default = void 0;function fs() {  const data = _interopRequireWildcard(require('graceful-fs'));  fs = function () {    return data;  };  return data;}function _jestHasteMap() {  const data = _interopRequireDefault(require('jest-haste-map'));  _jestHasteMap = function () {    return data;  };  return data;}function _interopRequireDefault(obj) {  return obj && obj.__esModule ? obj : {default: obj};}function _getRequireWildcardCache(nodeInterop) {  if (typeof WeakMap !== 'function') return null;  var cacheBabelInterop = new WeakMap();  var cacheNodeInterop = new WeakMap();  return (_getRequireWildcardCache = function (nodeInterop) {    return nodeInterop ? cacheNodeInterop : cacheBabelInterop;  })(nodeInterop);}function _interopRequireWildcard(obj, nodeInterop) {  if (!nodeInterop && obj && obj.__esModule) {    return obj;  }  if (obj === null || (typeof obj !== 'object' && typeof obj !== 'function')) {    return {default: obj};  }  var cache = _getRequireWildcardCache(nodeInterop);  if (cache && cache.has(obj)) {    return cache.get(obj);  }  var newObj = {};  var hasPropertyDescriptor =    Object.defineProperty && Object.getOwnPropertyDescriptor;  for (var key in obj) {    if (key !== 'default' && Object.prototype.hasOwnProperty.call(obj, key)) {      var desc = hasPropertyDescriptor        ? Object.getOwnPropertyDescriptor(obj, key)        : null;      if (desc && (desc.get || desc.set)) {        Object.defineProperty(newObj, key, desc);      } else {        newObj[key] = obj[key];      }    }  }  newObj.default = obj;  if (cache) {    cache.set(obj, newObj);  }  return newObj;}function _defineProperty(obj, key, value) {  if (key in obj) {    Object.defineProperty(obj, key, {      value: value,      enumerable: true,      configurable: true,      writable: true    });  } else {    obj[key] = value;  }  return obj;}const FAIL = 0;const SUCCESS = 1;/** * The TestSequencer will ultimately decide which tests should run first. * It is responsible for storing and reading from a local cache * map that stores context information for a given test, such as how long it * took to run during the last run and if it has failed or not. * Such information is used on: * TestSequencer.sort(tests: Array<Test>) * to sort the order of the provided tests. * * After the results are collected, * TestSequencer.cacheResults(tests: Array<Test>, results: AggregatedResult) * is called to store/update this information on the cache map. */class TestSequencer {  constructor() {    _defineProperty(this, '_cache', new Map());  }  _getCachePath(context) {    const {config} = context;    const HasteMapClass = _jestHasteMap().default.getStatic(config);    return HasteMapClass.getCacheFilePath(      config.cacheDirectory,      'perf-cache-' + config.name    );  }  _getCache(test) {    const {context} = test;    if (!this._cache.has(context) && context.config.cache) {      const cachePath = this._getCachePath(context);      if (fs().existsSync(cachePath)) {        try {          this._cache.set(            context,            JSON.parse(fs().readFileSync(cachePath, 'utf8'))          );        } catch {}      }    }    let cache = this._cache.get(context);    if (!cache) {      cache = {};      this._cache.set(context, cache);    }    return cache;  }  /**   * Sorting tests is very important because it has a great impact on the   * user-perceived responsiveness and speed of the test run.   *   * If such information is on cache, tests are sorted based on:   * -> Has it failed during the last run ?   * Since it's important to provide the most expected feedback as quickly   * as possible.   * -> How long it took to run ?   * Because running long tests first is an effort to minimize worker idle   * time at the end of a long test run.   * And if that information is not available they are sorted based on file size   * since big test files usually take longer to complete.   *   * Note that a possible improvement would be to analyse other information   * from the file other than its size.   *   */  sort(tests) {    const stats = {};    const fileSize = ({path, context: {hasteFS}}) =>      stats[path] || (stats[path] = hasteFS.getSize(path) || 0);    const hasFailed = (cache, test) =>      cache[test.path] && cache[test.path][0] === FAIL;    const time = (cache, test) => cache[test.path] && cache[test.path][1];    tests.forEach(test => (test.duration = time(this._getCache(test), test)));    return tests.sort((testA, testB) => {      const cacheA = this._getCache(testA);      const cacheB = this._getCache(testB);      const failedA = hasFailed(cacheA, testA);      const failedB = hasFailed(cacheB, testB);      const hasTimeA = testA.duration != null;      if (failedA !== failedB) {        return failedA ? -1 : 1;      } else if (hasTimeA != (testB.duration != null)) {        // If only one of two tests has timing information, run it last        return hasTimeA ? 1 : -1;      } else if (testA.duration != null && testB.duration != null) {        return testA.duration < testB.duration ? 1 : -1;      } else {        return fileSize(testA) < fileSize(testB) ? 1 : -1;      }    });  }  allFailedTests(tests) {    const hasFailed = (cache, test) => {      var _cache$test$path;      return (        ((_cache$test$path = cache[test.path]) === null ||        _cache$test$path === void 0          ? void 0          : _cache$test$path[0]) === FAIL      );    };    return this.sort(      tests.filter(test => hasFailed(this._getCache(test), test))    );  }  cacheResults(tests, results) {    const map = Object.create(null);    tests.forEach(test => (map[test.path] = test));    results.testResults.forEach(testResult => {      if (testResult && map[testResult.testFilePath] && !testResult.skipped) {        const cache = this._getCache(map[testResult.testFilePath]);        const perf = testResult.perfStats;        cache[testResult.testFilePath] = [          testResult.numFailingTests ? FAIL : SUCCESS,          perf.runtime || 0        ];      }    });    this._cache.forEach((cache, context) =>      fs().writeFileSync(this._getCachePath(context), JSON.stringify(cache))    );  }}exports.default = TestSequencer;
 |