jasmine-test-runner.js 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. /*
  2. * decaffeinate suggestions:
  3. * DS101: Remove unnecessary use of Array.from
  4. * DS102: Remove unnecessary code created because of implicit returns
  5. * DS202: Simplify dynamic range loops
  6. * DS205: Consider reworking code to avoid use of IIFEs
  7. * DS207: Consider shorter variations of null checks
  8. * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md
  9. */
  10. const Grim = require('grim');
  11. const fs = require('fs-plus');
  12. const temp = require('temp');
  13. const path = require('path');
  14. const {ipcRenderer} = require('electron');
  15. temp.track();
  16. module.exports = function({logFile, headless, testPaths, buildAtomEnvironment}) {
  17. const object = require('../vendor/jasmine');
  18. for (let key in object) { const value = object[key]; window[key] = value; }
  19. require('jasmine-tagged');
  20. // Rewrite global jasmine functions to have support for async tests.
  21. // This way packages can create async specs without having to import these from the
  22. // async-spec-helpers file.
  23. global.it = asyncifyJasmineFn(global.it, 1);
  24. global.fit = asyncifyJasmineFn(global.fit, 1);
  25. global.ffit = asyncifyJasmineFn(global.ffit, 1);
  26. global.fffit = asyncifyJasmineFn(global.fffit, 1);
  27. global.beforeEach = asyncifyJasmineFn(global.beforeEach, 0);
  28. global.afterEach = asyncifyJasmineFn(global.afterEach, 0);
  29. // Allow document.title to be assigned in specs without screwing up spec window title
  30. let documentTitle = null;
  31. Object.defineProperty(document, 'title', {
  32. get() { return documentTitle; },
  33. set(title) { return documentTitle = title; }
  34. }
  35. );
  36. const userHome = process.env.ATOM_HOME || path.join(fs.getHomeDirectory(), '.atom');
  37. const atomHome = temp.mkdirSync({prefix: 'atom-test-home-'});
  38. if (process.env.APM_TEST_PACKAGES) {
  39. const testPackages = process.env.APM_TEST_PACKAGES.split(/\s+/);
  40. fs.makeTreeSync(path.join(atomHome, 'packages'));
  41. for (let packName of Array.from(testPackages)) {
  42. const userPack = path.join(userHome, 'packages', packName);
  43. const loadablePack = path.join(atomHome, 'packages', packName);
  44. try {
  45. fs.symlinkSync(userPack, loadablePack, 'dir');
  46. } catch (error) {
  47. fs.copySync(userPack, loadablePack);
  48. }
  49. }
  50. }
  51. const ApplicationDelegate = require('../src/application-delegate');
  52. const applicationDelegate = new ApplicationDelegate();
  53. applicationDelegate.setRepresentedFilename = function() {};
  54. applicationDelegate.setWindowDocumentEdited = function() {};
  55. window.atom = buildAtomEnvironment({
  56. applicationDelegate, window, document,
  57. configDirPath: atomHome,
  58. enablePersistence: false
  59. });
  60. require('./spec-helper');
  61. if (process.env.JANKY_SHA1 || process.env.CI) { disableFocusMethods(); }
  62. for (let testPath of Array.from(testPaths)) { requireSpecs(testPath); }
  63. setSpecType('user');
  64. let resolveWithExitCode = null;
  65. const promise = new Promise((resolve, reject) => resolveWithExitCode = resolve);
  66. const jasmineEnv = jasmine.getEnv();
  67. jasmineEnv.addReporter(buildReporter({logFile, headless, resolveWithExitCode}));
  68. if(process.env.SPEC_FILTER) {
  69. const {getFullDescription} = require('./jasmine-list-reporter');
  70. const regex = new RegExp(process.env.SPEC_FILTER)
  71. jasmineEnv.specFilter = (spec) => getFullDescription(spec, false).match(regex)
  72. }
  73. if (process.env.TEST_JUNIT_XML_PATH) {
  74. const {JasmineJUnitReporter} = require('./jasmine-junit-reporter');
  75. process.stdout.write(`Outputting JUnit XML to <${process.env.TEST_JUNIT_XML_PATH}>\n`);
  76. const outputDir = path.dirname(process.env.TEST_JUNIT_XML_PATH);
  77. const fileBase = path.basename(process.env.TEST_JUNIT_XML_PATH, '.xml');
  78. jasmineEnv.addReporter(new JasmineJUnitReporter(outputDir, true, false, fileBase, true));
  79. }
  80. jasmineEnv.setIncludedTags([process.platform]);
  81. const jasmineContent = document.createElement('div');
  82. jasmineContent.setAttribute('id', 'jasmine-content');
  83. document.body.appendChild(jasmineContent);
  84. jasmineEnv.execute();
  85. return promise;
  86. };
  87. var asyncifyJasmineFn = (fn, callbackPosition) => (function(...args) {
  88. if (typeof args[callbackPosition] === 'function') {
  89. const callback = args[callbackPosition];
  90. args[callbackPosition] = function(...args) {
  91. const result = callback.apply(this, args);
  92. if (result instanceof Promise) {
  93. return waitsForPromise(() => result);
  94. }
  95. };
  96. }
  97. return fn.apply(this, args);
  98. });
  99. var waitsForPromise = function(fn) {
  100. const promise = fn();
  101. return global.waitsFor('spec promise to resolve', done => promise.then(done, function(error) {
  102. jasmine.getEnv().currentSpec.fail(error);
  103. return done();
  104. }));
  105. };
  106. var disableFocusMethods = () => ['fdescribe', 'ffdescribe', 'fffdescribe', 'fit', 'ffit', 'fffit'].forEach(function(methodName) {
  107. const focusMethod = window[methodName];
  108. return window[methodName] = function(description) {
  109. const error = new Error('Focused spec is running on CI');
  110. return focusMethod(description, function() { throw error; });
  111. };
  112. });
  113. var requireSpecs = function(testPath, specType) {
  114. if (fs.isDirectorySync(testPath)) {
  115. return (() => {
  116. const result = [];
  117. for (let testFilePath of Array.from(fs.listTreeSync(testPath))) {
  118. if (/-spec\.(coffee|js)$/.test(testFilePath)) {
  119. require(testFilePath);
  120. // Set spec directory on spec for setting up the project in spec-helper
  121. result.push(setSpecDirectory(testPath));
  122. }
  123. }
  124. return result;
  125. })();
  126. } else {
  127. require(testPath);
  128. return setSpecDirectory(path.dirname(testPath));
  129. }
  130. };
  131. const setSpecField = function(name, value) {
  132. const specs = jasmine.getEnv().currentRunner().specs();
  133. if (specs.length === 0) { return; }
  134. return (() => {
  135. const result = [];
  136. for (let start = specs.length-1, index = start, asc = start <= 0; asc ? index <= 0 : index >= 0; asc ? index++ : index--) {
  137. if (specs[index][name] != null) { break; }
  138. result.push(specs[index][name] = value);
  139. }
  140. return result;
  141. })();
  142. };
  143. var setSpecType = specType => setSpecField('specType', specType);
  144. var setSpecDirectory = specDirectory => setSpecField('specDirectory', specDirectory);
  145. var buildReporter = function({logFile, headless, resolveWithExitCode}) {
  146. if (headless) {
  147. return buildTerminalReporter(logFile, resolveWithExitCode);
  148. } else {
  149. let reporter;
  150. const AtomReporter = require('./atom-reporter.js');
  151. return reporter = new AtomReporter();
  152. }
  153. };
  154. var buildTerminalReporter = function(logFile, resolveWithExitCode) {
  155. let logStream;
  156. if (logFile != null) { logStream = fs.openSync(logFile, 'w'); }
  157. const log = function(str) {
  158. if (logStream != null) {
  159. return fs.writeSync(logStream, str);
  160. } else {
  161. return ipcRenderer.send('write-to-stderr', str);
  162. }
  163. };
  164. const options = {
  165. print(str) {
  166. return log(str);
  167. },
  168. onComplete(runner) {
  169. if (logStream != null) { fs.closeSync(logStream); }
  170. if (Grim.getDeprecationsLength() > 0) {
  171. Grim.logDeprecations();
  172. resolveWithExitCode(1);
  173. return;
  174. }
  175. if (runner.results().failedCount > 0) {
  176. return resolveWithExitCode(1);
  177. } else {
  178. return resolveWithExitCode(0);
  179. }
  180. }
  181. };
  182. if (process.env.ATOM_JASMINE_REPORTER === 'list') {
  183. const {JasmineListReporter} = require('./jasmine-list-reporter');
  184. return new JasmineListReporter(options);
  185. } else {
  186. const {TerminalReporter} = require('jasmine-tagged');
  187. return new TerminalReporter(options);
  188. }
  189. };