/* eslint global-require:0 */ import _ from 'underscore'; import ReactTestUtils from 'react-dom/test-utils'; import Config from '../../src/config' import N1SpecLoader from './n1-spec-loader' import TimeReporter from './time-reporter' import N1GuiReporter from './n1-gui-reporter'; import jasmineExports from './jasmine'; import ConsoleReporter from './console-reporter' import MasterAfterEach from './master-after-each' import MasterBeforeEach from './master-before-each' import nylasTestConstants from './nylas-test-constants' import * as jasmineExtensions from './jasmine-extensions' import * as reactTestUtilsExtensions from './react-test-utils-extensions' class N1SpecRunner { runSpecs(loadSettings) { this.loadSettings = loadSettings this._extendGlobalWindow(); this._setupJasmine(); this._setupNylasEnv(); this._setupWindow(); Object.assign(ReactTestUtils, reactTestUtilsExtensions) MasterBeforeEach.setup(this.loadSettings, window.beforeEach) MasterAfterEach.setup(this.loadSettings, window.afterEach) N1SpecLoader.loadSpecs(this.loadSettings, this.jasmineEnv); this.jasmineEnv.execute(); } /** * Put jasmine methods on the global scope so they can be used anywhere * without importing jasmine. */ _extendGlobalWindow() { Object.assign(window, { jasmine: jasmineExports.jasmine, it: this._makeItAsync(jasmineExports.it), // it: jasmineExports.it, fit: this._makeItAsync(jasmineExports.fit), xit: jasmineExports.xit, runs: jasmineExports.runs, waits: jasmineExports.waits, spyOn: jasmineExports.spyOn, expect: jasmineExports.expect, waitsFor: jasmineExports.waitsFor, describe: jasmineExports.describe, xdescribe: jasmineExports.xdescribe, afterEach: this._makeSurroundAsync(jasmineExports.afterEach), beforeEach: this._makeSurroundAsync(jasmineExports.beforeEach), testNowMoment: jasmineExtensions.testNowMoment, waitsForPromise: jasmineExtensions.waitsForPromise, }, nylasTestConstants) this.jasmineEnv = jasmineExports.jasmine.getEnv(); } _runAsync(userFn) { if (!userFn) return true const resp = userFn.apply(this); if (resp && resp.then) { return jasmineExtensions.waitsForPromise(() => { return resp }) } return resp } _makeItAsync(jasmineIt) { const self = this; return (desc, userFn) => { return jasmineIt(desc, function asyncIt() { self._runAsync.call(this, userFn) }) } } _makeSurroundAsync(jasmineBeforeAfter) { const self = this; return (userFn) => { return jasmineBeforeAfter(function asyncBeforeAfter() { self._runAsync.call(this, userFn) }) } } _setupJasmine() { this._addReporters() this._initializeDOM() this._extendJasmineMethods(); // On load, this will require "jasmine-focused" which looks up the // global `jasmine` object and extends onto it: // fdescribe, ffdescribe, fffdescribe, fit, ffit, fffit require('jasmine-tagged'); // On load this will extend jasmine's `beforeEach` require('jasmine-json'); } _setupNylasEnv() { // We need to mock the config even before `beforeEach` runs because it // gets accessed on module definitions const fakePersistedConfig = {env: 'production'}; NylasEnv.config = new Config(); NylasEnv.config.settings = fakePersistedConfig; NylasEnv.restoreWindowDimensions(); NylasEnv.themes.loadBaseStylesheets(); NylasEnv.themes.requireStylesheet('../../static/jasmine'); NylasEnv.themes.initialLoadComplete = true; NylasEnv.keymaps.loadKeymaps(); } _setupWindow() { window.addEventListener('core:close', () => window.close()); window.addEventListener('beforeunload', () => { NylasEnv.storeWindowDimensions(); return NylasEnv.saveSync(); }); } _addReporters() { const timeReporter = new TimeReporter(); const consoleReporter = new ConsoleReporter(); const loadSettings = NylasEnv.getLoadSettings(); if (loadSettings.jUnitXmlPath) { // jasmine-reporters extends the jasmine global with methods, so needs to // be `required` at runtime. The `jasmine` object has to be attached to the // global scope before it gets extended. This is done in // `_extendGlobalWindow` require('jasmine-reporters'); const jUnitXmlReporter = new jasmine.JUnitXmlReporter(loadSettings.jUnitXmlPath, true, true); this.jasmineEnv.addReporter(jUnitXmlReporter); } this.jasmineEnv.addReporter(timeReporter); this.jasmineEnv.addReporter(consoleReporter); if (loadSettings.showSpecsInWindow) { this.jasmineEnv.addReporter(N1GuiReporter); NylasEnv.show(); } else { // this package's dep `jasmine-focused` also adds methods to the // `jasmine` global // NOTE: this reporter MUST be added last as it exits the test process // when complete, which may result in e.g. your XML output not getting // written to disk if that reporter is added afterward. const N1TerminalReporter = require('./terminal-reporter').default const terminalReporter = new N1TerminalReporter(); this.jasmineEnv.addReporter(terminalReporter); } } _initializeDOM() { const div = document.createElement('div'); div.id = 'jasmine-content'; document.body.appendChild(div); document.querySelector('html').style.overflow = 'initial'; document.querySelector('body').style.overflow = 'initial'; } _extendJasmineMethods() { const jasmine = jasmineExports.jasmine; // Use underscore's definition of equality for toEqual assertions jasmine.getEnv().addEqualityTester(_.isEqual); jasmine.unspy = jasmineExtensions.unspy jasmine.attachToDOM = jasmineExtensions.attachToDOM const origEmitObject = jasmine.StringPrettyPrinter.prototype.emitObject; jasmine.StringPrettyPrinter.prototype.emitObject = function emitObject(obj) { if (obj.inspect) { return this.append(obj.inspect()); } return origEmitObject.call(this, obj); }; } } export default new N1SpecRunner()