Convert spec-helper to es6

This commit is contained in:
Evan Morikawa 2016-10-16 17:41:15 -04:00
parent f1f7952f64
commit 27ccc3cd78
3 changed files with 343 additions and 425 deletions

View file

@ -10,7 +10,7 @@ class N1SpecRunner {
this.loadSettings = loadSettings
this._extendGlobalWindow();
this._setupJasmine();
N1SpecLoader.loadSpecs(loadSettings, this.jasmineEnv);
N1SpecLoader.loadSpecs(this.loadSettings, this.jasmineEnv);
this.jasmineEnv.execute();
}

View file

@ -1,424 +0,0 @@
_ = require 'underscore'
_str = require 'underscore.string'
_ = _.extend(_, require('../src/config-utils'))
fs = require 'fs-plus'
path = require 'path'
require '../src/window'
NylasEnv.restoreWindowDimensions()
require 'jasmine-json'
Grim = require 'grim'
TimeOverride = require './time-override'
KeymapManager = require('../src/keymap-manager').default
Config = require '../src/config'
pathwatcher = require 'pathwatcher'
{clipboard} = require 'electron'
{Account,
Contact,
TaskQueue,
AccountStore,
DatabaseStore,
MailboxPerspective,
FocusedPerspectiveStore,
ComponentRegistry} = require "nylas-exports"
NylasEnv.themes.loadBaseStylesheets()
NylasEnv.themes.requireStylesheet '../static/jasmine'
NylasEnv.themes.initialLoadComplete = true
NylasEnv.keymaps.loadKeymaps()
styleElementsToRestore = NylasEnv.styles.getSnapshot()
window.addEventListener 'core:close', -> window.close()
window.addEventListener 'beforeunload', ->
NylasEnv.storeWindowDimensions()
NylasEnv.saveSync()
document.querySelector('html').style.overflow = 'initial'
document.querySelector('body').style.overflow = 'initial'
# Allow document.title to be assigned in specs without screwing up spec window title
documentTitle = null
Object.defineProperty document, 'title',
get: -> documentTitle
set: (title) -> documentTitle = title
jasmine.getEnv().addEqualityTester(_.isEqual) # Use underscore's definition of equality for toEqual assertions
# ----------------------------------------------------
# Custom log reporter to pointpoint console statements
# ----------------------------------------------------
# util = require('util')
# console.inspect = (args...) ->
# arg = args
# if (args.length is 1)
# arg = args[0]
# console.log(util.inspect(arg))
#
# original_log = console.log
# original_warn = console.warn
# original_error = console.error
#
# class JasmineConsoleReporter
# reportSpecStarting: (spec) ->
# withContext = (log) ->
# return ->
# if arguments[0] is '.'
# log(arguments...)
# else
# log("[#{spec.getFullName()}] #{arguments[0]}", Array(arguments)[1..-1]...)
# console.log = withContext(original_log)
# console.warn = withContext(original_warn)
# console.error = withContext(original_error)
#
# reportSpecResults: (result) ->
# if console.log isnt original_log
# console.log = original_log
# if console.warn isnt original_warn
# console.warn = original_warn
# if console.error isnt original_error
# console.error = original_error
#
# jasmine.getEnv().addReporter(new JasmineConsoleReporter())
#
#
if process.env.JANKY_SHA1 and process.platform is 'win32'
jasmine.getEnv().defaultTimeoutInterval = 60000
else
jasmine.getEnv().defaultTimeoutInterval = 250
specPackageName = null
specPackagePath = null
isCoreSpec = false
{specDirectory, resourcePath} = NylasEnv.getLoadSettings()
if specDirectory
specPackagePath = path.resolve(specDirectory, '..')
try
specPackageName = JSON.parse(fs.readFileSync(path.join(specPackagePath, 'package.json')))?.name
isCoreSpec = specDirectory == fs.realpathSync(__dirname)
# Override ReactTestUtils.renderIntoDocument so that
# we can remove all the created elements after the test completes.
React = require "react"
ReactDOM = require "react-dom"
ReactTestUtils = require('react-addons-test-utils')
ReactTestUtils.scryRenderedComponentsWithTypeAndProps = (root, type, props) ->
if not root then throw new Error("Must supply a root to scryRenderedComponentsWithTypeAndProps")
_.compact _.map ReactTestUtils.scryRenderedComponentsWithType(root, type), (el) ->
if _.isEqual(_.pick(el.props, Object.keys(props)), props)
return el
else
return false
ReactTestUtils.scryRenderedDOMComponentsWithAttr = (root, attrName, attrValue) ->
ReactTestUtils.findAllInRenderedTree root, (inst) ->
inst[attrName] and (!attrValue or inst[attrName] is attrValue)
ReactTestUtils.findRenderedDOMComponentWithAttr = (root, attrName, attrValue) ->
all = ReactTestUtils.scryRenderedDOMComponentsWithAttr(root, attrName, attrValue)
if all.length is not 1
throw new Error("Did not find exactly one match for data attribute: #{attrName} with value: #{attrValue}")
all[0]
ReactElementContainers = []
ReactTestUtils.renderIntoDocument = (element) ->
container = document.createElement('div')
ReactElementContainers.push(container)
ReactDOM.render(element, container)
ReactTestUtils.unmountAll = ->
for container in ReactElementContainers
ReactDOM.unmountComponentAtNode(container)
ReactElementContainers = []
# So it passes the Utils.isTempId test
window.TEST_ACCOUNT_CLIENT_ID = "local-test-account-client-id"
window.TEST_ACCOUNT_ID = "test-account-server-id"
window.TEST_ACCOUNT_EMAIL = "tester@nylas.com"
window.TEST_ACCOUNT_NAME = "Nylas Test"
window.TEST_PLUGIN_ID = "test-plugin-id-123"
window.TEST_ACCOUNT_ALIAS_EMAIL = "tester+alternative@nylas.com"
window.TEST_TIME_ZONE = "America/Los_Angeles"
moment = require('moment-timezone')
# moment-round upon require patches `moment` with new functions.
require('moment-round')
# This date was chosen because it's close to a DST boundary
window.testNowMoment = ->
moment.tz("2016-03-15 12:00", TEST_TIME_ZONE)
# We need to mock the config even before `beforeEach` runs because it gets
# accessed on module definitions
fakePersistedConfig = {env: 'production'}
NylasEnv.config = new Config()
NylasEnv.config.settings = fakePersistedConfig
beforeEach ->
NylasEnv.testOrganizationUnit = null
Grim.clearDeprecations() if isCoreSpec
ComponentRegistry._clear()
global.localStorage.clear()
DatabaseStore._transactionQueue = undefined
## If we don't spy on DatabaseStore._query, then
#`DatabaseStore.inTransaction` will never complete and cause all tests
#that depend on transactions to hang.
#
# @_query("BEGIN IMMEDIATE TRANSACTION") never resolves because
# DatabaseStore._query never runs because the @_open flag is always
# false because we never setup the DB when `NylasEnv.inSpecMode` is
# true.
spyOn(DatabaseStore, '_query').andCallFake => Promise.resolve([])
TaskQueue._queue = []
TaskQueue._completed = []
TaskQueue._onlineStatus = true
documentTitle = null
NylasEnv.styles.restoreSnapshot(styleElementsToRestore)
NylasEnv.workspaceViewParentSelector = '#jasmine-content'
NylasEnv.packages.packageStates = {}
serializedWindowState = null
spyOn(NylasEnv, 'saveSync')
TimeOverride.resetTime()
TimeOverride.enableSpies()
spy = spyOn(NylasEnv.packages, 'resolvePackagePath').andCallFake (packageName) ->
if specPackageName and packageName is specPackageName
resolvePackagePath(specPackagePath)
else
resolvePackagePath(packageName)
resolvePackagePath = _.bind(spy.originalValue, NylasEnv.packages)
# prevent specs from modifying N1's menus
spyOn(NylasEnv.menu, 'sendToBrowserProcess')
# Log in a fake user, and ensure that accountForId, etc. work
AccountStore._accounts = [
new Account({
provider: "gmail"
name: TEST_ACCOUNT_NAME
emailAddress: TEST_ACCOUNT_EMAIL
organizationUnit: NylasEnv.testOrganizationUnit || 'label'
clientId: TEST_ACCOUNT_CLIENT_ID
serverId: TEST_ACCOUNT_ID,
aliases: [
"#{TEST_ACCOUNT_NAME} Alternate <#{TEST_ACCOUNT_ALIAS_EMAIL}>"
]
}),
new Account({
provider: "gmail"
name: 'Second'
emailAddress: 'second@gmail.com'
organizationUnit: NylasEnv.testOrganizationUnit || 'label'
clientId: 'second-test-account-id'
serverId: 'second-test-account-id'
aliases: [
'Second Support <second@gmail.com>'
'Second Alternate <second+alternate@gmail.com>'
'Second <second+third@gmail.com>'
]
})
]
FocusedPerspectiveStore._current = MailboxPerspective.forNothing()
# reset config before each spec; don't load or save from/to `config.json`
fakePersistedConfig = {env: 'production'}
spyOn(Config::, 'getRawValues').andCallFake =>
fakePersistedConfig
spyOn(Config::, 'setRawValue').andCallFake (keyPath, value) ->
if (keyPath)
_.setValueForKeyPath(fakePersistedConfig, keyPath, value)
else
fakePersistedConfig = value
this.load()
NylasEnv.config = new Config()
NylasEnv.loadConfig()
spyOn(pathwatcher.File.prototype, "detectResurrectionAfterDelay").andCallFake ->
@detectResurrection()
clipboardContent = 'initial clipboard content'
spyOn(clipboard, 'writeText').andCallFake (text) -> clipboardContent = text
spyOn(clipboard, 'readText').andCallFake -> clipboardContent
advanceClock(1000)
addCustomMatchers(this)
TimeOverride.resetSpyData()
afterEach ->
NylasEnv.packages.deactivatePackages()
NylasEnv.menu.template = []
NylasEnv.themes.removeStylesheet('global-editor-styles')
if NylasEnv.state
delete NylasEnv.state.packageStates
unless window.debugContent
document.getElementById('jasmine-content').innerHTML = ''
ReactTestUtils.unmountAll()
jasmine.unspy(NylasEnv, 'saveSync')
ensureNoPathSubscriptions()
waits(0) # yield to ui thread to make screen update more frequently
ensureNoPathSubscriptions = ->
watchedPaths = pathwatcher.getWatchedPaths()
pathwatcher.closeAllWatchers()
if watchedPaths.length > 0
throw new Error("Leaking subscriptions for paths: " + watchedPaths.join(", "))
ensureNoDeprecatedFunctionsCalled = ->
deprecations = Grim.getDeprecations()
if deprecations.length > 0
originalPrepareStackTrace = Error.prepareStackTrace
Error.prepareStackTrace = (error, stack) ->
output = []
for deprecation in deprecations
output.push "#{deprecation.originName} is deprecated. #{deprecation.message}"
output.push _str.repeat("-", output[output.length - 1].length)
for stack in deprecation.getStacks()
for {functionName, location} in stack
output.push "#{functionName} -- #{location}"
output.push ""
output.join("\n")
error = new Error("Deprecated function(s) #{deprecations.map(({originName}) -> originName).join ', '}) were called.")
error.stack
Error.prepareStackTrace = originalPrepareStackTrace
throw error
emitObject = jasmine.StringPrettyPrinter.prototype.emitObject
jasmine.StringPrettyPrinter.prototype.emitObject = (obj) ->
if obj.inspect
@append obj.inspect()
else
emitObject.call(this, obj)
jasmine.unspy = (object, methodName) ->
throw new Error("Not a spy") unless object[methodName].hasOwnProperty('originalValue')
object[methodName] = object[methodName].originalValue
jasmine.attachToDOM = (element) ->
jasmineContent = document.querySelector('#jasmine-content')
jasmineContent.appendChild(element) unless jasmineContent.contains(element)
deprecationsSnapshot = null
jasmine.snapshotDeprecations = ->
deprecationsSnapshot = _.clone(Grim.deprecations)
jasmine.restoreDeprecationsSnapshot = ->
Grim.deprecations = deprecationsSnapshot
addCustomMatchers = (spec) ->
spec.addMatchers
toHaveLength: (expected) ->
if not @actual?
this.message = => "Expected object #{@actual} has no length method"
false
else
notText = if @isNot then " not" else ""
this.message = => "Expected object with length #{@actual.length} to#{notText} have length #{expected}"
@actual.length == expected
# -------------------------
# Stubs for Window methods
# -------------------------
window.keyIdentifierForKey = (key) ->
if key.length > 1 # named key
key
else
charCode = key.toUpperCase().charCodeAt(0)
"U+00" + charCode.toString(16)
window.keydownEvent = (key, properties={}) ->
originalEventProperties = {}
originalEventProperties.ctrl = properties.ctrlKey
originalEventProperties.alt = properties.altKey
originalEventProperties.shift = properties.shiftKey
originalEventProperties.cmd = properties.metaKey
originalEventProperties.target = properties.target?[0] ? properties.target
originalEventProperties.which = properties.which
originalEvent = KeymapManager.keydownEvent(key, originalEventProperties)
properties = _.extend({originalEvent}, properties)
new CustomEvent('keydown', properties)
window.mouseEvent = (type, properties) ->
if properties.point
{point, editorView} = properties
{top, left} = @pagePixelPositionForPoint(editorView, point)
properties.pageX = left + 1
properties.pageY = top + 1
properties.originalEvent ?= {detail: 1}
new CustomEvent(type, properties)
window.clickEvent = (properties={}) ->
window.mouseEvent("click", properties)
window.mousedownEvent = (properties={}) ->
window.mouseEvent('mousedown', properties)
window.mousemoveEvent = (properties={}) ->
window.mouseEvent('mousemove', properties)
# See docs/writing-specs.md
window.waitsForPromise = (args...) ->
if args.length > 1
{ shouldReject, timeout } = args[0]
else
shouldReject = false
fn = _.last(args)
window.waitsFor timeout, (moveOn) ->
promise = fn()
# Keep in mind we can't check `promise instanceof Promise` because parts of
# the app still use other Promise libraries Just see if it looks
# promise-like.
if not promise or not promise.then
jasmine.getEnv().currentSpec.fail("Expected callback to return a promise-like object, but it returned #{promise}")
moveOn()
else if shouldReject
promise.catch(moveOn)
promise.then ->
jasmine.getEnv().currentSpec.fail("Expected promise to be rejected, but it was resolved")
moveOn()
else
promise.then(moveOn)
promise.catch (error) ->
# I don't know what `pp` does, but for standard `new Error` objects,
# it sometimes returns "{ }". Catch this case and fall through to toString()
msg = jasmine.pp(error)
msg = error.toString() if msg is "{ }"
jasmine.getEnv().currentSpec.fail("Expected promise to be resolved, but it was rejected with #{msg}")
moveOn()
window.pagePixelPositionForPoint = (editorView, point) ->
point = Point.fromObject point
top = editorView.renderedLines.offset().top + point.row * editorView.lineHeight
left = editorView.renderedLines.offset().left + point.column * editorView.charWidth - editorView.renderedLines.scrollLeft()
{ top, left }

342
spec/spec-helper.es6 Normal file
View file

@ -0,0 +1,342 @@
import _ from 'underscore';
import fs from 'fs-plus';
import path from 'path';
import '../src/window';
NylasEnv.restoreWindowDimensions();
import 'jasmine-json';
import Grim from 'grim';
import TimeOverride from './time-override';
import Config from '../src/config';
import pathwatcher from 'pathwatcher';
import { clipboard } from 'electron';
import { Account, TaskQueue, AccountStore, DatabaseStore, MailboxPerspective, FocusedPerspectiveStore, ComponentRegistry } from "nylas-exports";
NylasEnv.themes.loadBaseStylesheets();
NylasEnv.themes.requireStylesheet('../static/jasmine');
NylasEnv.themes.initialLoadComplete = true;
NylasEnv.keymaps.loadKeymaps();
let styleElementsToRestore = NylasEnv.styles.getSnapshot();
window.addEventListener('core:close', () => window.close());
window.addEventListener('beforeunload', function() {
NylasEnv.storeWindowDimensions();
return NylasEnv.saveSync();
}
);
document.querySelector('html').style.overflow = 'initial';
document.querySelector('body').style.overflow = 'initial';
// Allow document.title to be assigned in specs without screwing up spec window title
let documentTitle = null;
Object.defineProperty(document, 'title', {
get() { return documentTitle; },
set(title) { return documentTitle = title; }
}
);
jasmine.getEnv().addEqualityTester(_.isEqual); // Use underscore's definition of equality for toEqual assertions
//
//
if (process.env.JANKY_SHA1 && process.platform === 'win32') {
jasmine.getEnv().defaultTimeoutInterval = 60000;
} else {
jasmine.getEnv().defaultTimeoutInterval = 250;
}
let specPackageName = null;
let specPackagePath = null;
let isCoreSpec = false;
let {specDirectory, resourcePath} = NylasEnv.getLoadSettings();
if (specDirectory) {
specPackagePath = path.resolve(specDirectory, '..');
try {
specPackageName = __guard__(JSON.parse(fs.readFileSync(path.join(specPackagePath, 'package.json'))), x => x.name);
} catch (error) {}
}
isCoreSpec = specDirectory === fs.realpathSync(__dirname);
// Override ReactTestUtils.renderIntoDocument so that
// we can remove all the created elements after the test completes.
import React from "react";
import ReactDOM from "react-dom";
import ReactTestUtils from 'react-addons-test-utils';
ReactTestUtils.scryRenderedComponentsWithTypeAndProps = function(root, type, props) {
if (!root) { throw new Error("Must supply a root to scryRenderedComponentsWithTypeAndProps"); }
return _.compact(_.map(ReactTestUtils.scryRenderedComponentsWithType(root, type), function(el) {
if (_.isEqual(_.pick(el.props, Object.keys(props)), props)) {
return el;
} else {
return false;
}
}
)
);
};
let ReactElementContainers = [];
ReactTestUtils.renderIntoDocument = function(element) {
let container = document.createElement('div');
ReactElementContainers.push(container);
return ReactDOM.render(element, container);
};
ReactTestUtils.unmountAll = function() {
for (let i = 0; i < ReactElementContainers.length; i++) {
let container = ReactElementContainers[i];
ReactDOM.unmountComponentAtNode(container);
}
return ReactElementContainers = [];
};
// So it passes the Utils.isTempId test
window.TEST_ACCOUNT_CLIENT_ID = "local-test-account-client-id";
window.TEST_ACCOUNT_ID = "test-account-server-id";
window.TEST_ACCOUNT_EMAIL = "tester@nylas.com";
window.TEST_ACCOUNT_NAME = "Nylas Test";
window.TEST_PLUGIN_ID = "test-plugin-id-123";
window.TEST_ACCOUNT_ALIAS_EMAIL = "tester+alternative@nylas.com";
window.TEST_TIME_ZONE = "America/Los_Angeles";
import moment from 'moment-timezone';
// moment-round upon require patches `moment` with new functions.
import 'moment-round';
// This date was chosen because it's close to a DST boundary
window.testNowMoment = () => moment.tz("2016-03-15 12:00", TEST_TIME_ZONE);
// We need to mock the config even before `beforeEach` runs because it gets
// accessed on module definitions
let fakePersistedConfig = {env: 'production'};
NylasEnv.config = new Config();
NylasEnv.config.settings = fakePersistedConfig;
beforeEach(function() {
NylasEnv.testOrganizationUnit = null;
if (isCoreSpec) { Grim.clearDeprecations(); }
ComponentRegistry._clear();
global.localStorage.clear();
DatabaseStore._transactionQueue = undefined;
//# If we don't spy on DatabaseStore._query, then
//`DatabaseStore.inTransaction` will never complete and cause all tests
//that depend on transactions to hang.
//
// @_query("BEGIN IMMEDIATE TRANSACTION") never resolves because
// DatabaseStore._query never runs because the @_open flag is always
// false because we never setup the DB when `NylasEnv.inSpecMode` is
// true.
spyOn(DatabaseStore, '_query').andCallFake(() => Promise.resolve([]));
TaskQueue._queue = [];
TaskQueue._completed = [];
TaskQueue._onlineStatus = true;
documentTitle = null;
NylasEnv.styles.restoreSnapshot(styleElementsToRestore);
NylasEnv.workspaceViewParentSelector = '#jasmine-content';
NylasEnv.packages.packageStates = {};
let serializedWindowState = null;
spyOn(NylasEnv, 'saveSync');
TimeOverride.resetTime();
TimeOverride.enableSpies();
let spy = spyOn(NylasEnv.packages, 'resolvePackagePath').andCallFake(function(packageName) {
if (specPackageName && packageName === specPackageName) {
return resolvePackagePath(specPackagePath);
} else {
return resolvePackagePath(packageName);
}
});
var resolvePackagePath = _.bind(spy.originalValue, NylasEnv.packages);
// prevent specs from modifying N1's menus
spyOn(NylasEnv.menu, 'sendToBrowserProcess');
// Log in a fake user, and ensure that accountForId, etc. work
AccountStore._accounts = [
new Account({
provider: "gmail",
name: TEST_ACCOUNT_NAME,
emailAddress: TEST_ACCOUNT_EMAIL,
organizationUnit: NylasEnv.testOrganizationUnit || 'label',
clientId: TEST_ACCOUNT_CLIENT_ID,
serverId: TEST_ACCOUNT_ID,
aliases: [
`${TEST_ACCOUNT_NAME} Alternate <${TEST_ACCOUNT_ALIAS_EMAIL}>`
]
}),
new Account({
provider: "gmail",
name: 'Second',
emailAddress: 'second@gmail.com',
organizationUnit: NylasEnv.testOrganizationUnit || 'label',
clientId: 'second-test-account-id',
serverId: 'second-test-account-id',
aliases: [
'Second Support <second@gmail.com>',
'Second Alternate <second+alternate@gmail.com>',
'Second <second+third@gmail.com>'
]
})
];
FocusedPerspectiveStore._current = MailboxPerspective.forNothing();
// reset config before each spec; don't load or save from/to `config.json`
fakePersistedConfig = {env: 'production'};
spyOn(Config.prototype, 'getRawValues').andCallFake(() => {
return fakePersistedConfig;
}
);
spyOn(Config.prototype, 'setRawValue').andCallFake(function(keyPath, value) {
if (keyPath) {
_.setValueForKeyPath(fakePersistedConfig, keyPath, value);
} else {
fakePersistedConfig = value;
}
return this.load();
});
NylasEnv.config = new Config();
NylasEnv.loadConfig();
spyOn(pathwatcher.File.prototype, "detectResurrectionAfterDelay").andCallFake(function() {
return this.detectResurrection();
});
let clipboardContent = 'initial clipboard content';
spyOn(clipboard, 'writeText').andCallFake(text => clipboardContent = text);
spyOn(clipboard, 'readText').andCallFake(() => clipboardContent);
advanceClock(1000);
addCustomMatchers(this);
return TimeOverride.resetSpyData();
});
afterEach(function() {
NylasEnv.packages.deactivatePackages();
NylasEnv.menu.template = [];
NylasEnv.themes.removeStylesheet('global-editor-styles');
if (NylasEnv.state) {
delete NylasEnv.state.packageStates;
}
if (!window.debugContent) {
document.getElementById('jasmine-content').innerHTML = '';
}
ReactTestUtils.unmountAll();
jasmine.unspy(NylasEnv, 'saveSync');
ensureNoPathSubscriptions();
return waits(0);
}); // yield to ui thread to make screen update more frequently
var ensureNoPathSubscriptions = function() {
let watchedPaths = pathwatcher.getWatchedPaths();
pathwatcher.closeAllWatchers();
if (watchedPaths.length > 0) {
throw new Error(`Leaking subscriptions for paths: ${watchedPaths.join(", ")}`);
}
};
let { emitObject } = jasmine.StringPrettyPrinter.prototype;
jasmine.StringPrettyPrinter.prototype.emitObject = function(obj) {
if (obj.inspect) {
return this.append(obj.inspect());
} else {
return emitObject.call(this, obj);
}
};
jasmine.unspy = function(object, methodName) {
if (!object[methodName].hasOwnProperty('originalValue')) { throw new Error("Not a spy"); }
return object[methodName] = object[methodName].originalValue;
};
jasmine.attachToDOM = function(element) {
let jasmineContent = document.querySelector('#jasmine-content');
if (!jasmineContent.contains(element)) { return jasmineContent.appendChild(element); }
};
let deprecationsSnapshot = null;
jasmine.snapshotDeprecations = () => deprecationsSnapshot = _.clone(Grim.deprecations);
jasmine.restoreDeprecationsSnapshot = () => Grim.deprecations = deprecationsSnapshot;
var addCustomMatchers = spec =>
spec.addMatchers({
toHaveLength(expected) {
if (this.actual == null) {
this.message = () => `Expected object ${this.actual} has no length method`;
return false;
} else {
let notText = this.isNot ? " not" : "";
this.message = () => `Expected object with length ${this.actual.length} to${notText} have length ${expected}`;
return this.actual.length === expected;
}
}
})
;
// See docs/writing-specs.md
window.waitsForPromise = function(...args) {
if (args.length > 1) {
var { shouldReject, timeout } = args[0];
} else {
var shouldReject = false;
}
let fn = _.last(args);
return window.waitsFor(timeout, function(moveOn) {
let promise = fn();
// Keep in mind we can't check `promise instanceof Promise` because parts of
// the app still use other Promise libraries Just see if it looks
// promise-like.
if (!promise || !promise.then) {
jasmine.getEnv().currentSpec.fail(`Expected callback to return a promise-like object, but it returned ${promise}`);
return moveOn();
} else if (shouldReject) {
promise.catch(moveOn);
return promise.then(function() {
jasmine.getEnv().currentSpec.fail("Expected promise to be rejected, but it was resolved");
return moveOn();
});
} else {
promise.then(moveOn);
return promise.catch(function(error) {
// I don't know what `pp` does, but for standard `new Error` objects,
// it sometimes returns "{ }". Catch this case and fall through to toString()
let msg = jasmine.pp(error);
if (msg === "{ }") { msg = error.toString(); }
jasmine.getEnv().currentSpec.fail(`Expected promise to be resolved, but it was rejected with ${msg}`);
return moveOn();
});
}
}
);
};
function __guard__(value, transform) {
return (typeof value !== 'undefined' && value !== null) ? transform(value) : undefined;
}