pulsar/spec/spec-helper.coffee

374 lines
13 KiB
CoffeeScript
Raw Normal View History

2013-09-18 05:58:41 +04:00
require '../src/window'
atom.initialize()
atom.restoreWindowDimensions()
require 'jasmine-json'
require '../vendor/jasmine-jquery'
path = require 'path'
2014-02-24 05:09:05 +04:00
_ = require 'underscore-plus'
fs = require 'fs-plus'
Grim = require 'grim'
KeymapManager = require '../src/keymap-extensions'
{$, WorkspaceView, Workspace} = require 'atom'
2013-09-18 05:58:41 +04:00
Config = require '../src/config'
{Point} = require 'text-buffer'
2013-09-18 05:58:41 +04:00
Project = require '../src/project'
2014-09-23 01:35:13 +04:00
TextEditor = require '../src/text-editor'
TextEditorView = require '../src/text-editor-view'
2013-09-18 05:58:41 +04:00
TokenizedBuffer = require '../src/tokenized-buffer'
2014-09-23 01:35:13 +04:00
TextEditorComponent = require '../src/text-editor-component'
2013-04-07 12:18:08 +04:00
pathwatcher = require 'pathwatcher'
clipboard = require 'clipboard'
atom.themes.loadBaseStylesheets()
atom.themes.requireStylesheet '../static/jasmine'
atom.themes.initialLoadComplete = true
2013-09-18 01:54:33 +04:00
fixturePackagesPath = path.resolve(__dirname, './fixtures/packages')
atom.packages.packageDirPaths.unshift(fixturePackagesPath)
2014-04-01 02:28:55 +04:00
atom.keymaps.loadBundledKeymaps()
keyBindingsToRestore = atom.keymaps.getKeyBindings()
commandsToRestore = atom.commands.getSnapshot()
styleElementsToRestore = atom.styles.getSnapshot()
window.addEventListener 'core:close', -> window.close()
window.addEventListener 'beforeunload', ->
atom.storeWindowDimensions()
atom.saveSync()
2013-02-20 23:44:50 +04:00
$('html,body').css('overflow', 'auto')
# 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
2013-02-20 23:44:50 +04:00
jasmine.getEnv().addEqualityTester(_.isEqual) # Use underscore's definition of equality for toEqual assertions
2014-06-18 21:04:07 +04:00
2014-10-21 01:21:20 +04:00
if process.env.JANKY_SHA1 and process.platform is 'win32'
2014-07-07 21:14:38 +04:00
jasmine.getEnv().defaultTimeoutInterval = 60000
2014-06-18 21:04:07 +04:00
else
jasmine.getEnv().defaultTimeoutInterval = 5000
2013-02-20 23:44:50 +04:00
specPackageName = null
specPackagePath = null
specProjectPath = null
isCoreSpec = false
{specDirectory, resourcePath} = atom.getLoadSettings()
2013-11-22 02:55:25 +04:00
if specDirectory
specPackagePath = path.resolve(specDirectory, '..')
try
2014-02-18 03:25:51 +04:00
specPackageName = JSON.parse(fs.readFileSync(path.join(specPackagePath, 'package.json')))?.name
specProjectPath = path.join(specDirectory, 'fixtures')
isCoreSpec = specDirectory == fs.realpathSync(__dirname)
beforeEach ->
Grim.clearDeprecations() if isCoreSpec
2013-09-18 05:58:41 +04:00
$.fx.off = true
documentTitle = null
2013-11-13 05:34:13 +04:00
projectPath = specProjectPath ? path.join(@specDirectory, 'fixtures')
atom.project = new Project(paths: [projectPath])
2014-04-03 00:23:50 +04:00
atom.workspace = new Workspace()
2014-04-01 02:28:55 +04:00
atom.keymaps.keyBindings = _.clone(keyBindingsToRestore)
atom.commands.restoreSnapshot(commandsToRestore)
atom.styles.restoreSnapshot(styleElementsToRestore)
window.resetTimeouts()
atom.packages.packageStates = {}
serializedWindowState = null
spyOn(atom, 'saveSync')
2014-11-20 21:42:49 +03:00
atom.grammars.clearGrammarOverrides()
spy = spyOn(atom.packages, 'resolvePackagePath').andCallFake (packageName) ->
if specPackageName and packageName is specPackageName
resolvePackagePath(specPackagePath)
else
resolvePackagePath(packageName)
resolvePackagePath = _.bind(spy.originalValue, atom.packages)
2013-10-09 03:23:34 +04:00
# prevent specs from modifying Atom's menus
spyOn(atom.menu, 'sendToBrowserProcess')
# reset config before each spec; don't load or save from/to `config.json`
2013-11-22 03:25:51 +04:00
config = new Config({resourcePath, configDirPath: atom.getConfigDirPath()})
spyOn(config, 'load')
2012-12-13 03:46:30 +04:00
spyOn(config, 'save')
atom.config = config
atom.loadConfig()
2014-02-22 02:49:15 +04:00
config.set "core.destroyEmptyPanes", false
2013-11-11 21:29:29 +04:00
config.set "editor.fontFamily", "Courier"
config.set "editor.fontSize", 16
config.set "editor.autoIndent", false
config.set "core.disabledPackages", ["package-that-throws-an-exception",
"package-with-broken-package-json", "package-with-broken-keymap"]
config.set "editor.useShadowDOM", true
config.load.reset()
2013-11-11 21:29:29 +04:00
config.save.reset()
2012-12-13 03:23:36 +04:00
# make editor display updates synchronous
2014-09-23 01:35:13 +04:00
spyOn(TextEditorView.prototype, 'requestDisplayUpdate').andCallFake -> @updateDisplay()
TextEditorComponent.performSyncUpdates = true
spyOn(atom, "setRepresentedFilename")
spyOn(window, "setTimeout").andCallFake window.fakeSetTimeout
spyOn(window, "clearTimeout").andCallFake window.fakeClearTimeout
2014-02-19 22:01:56 +04:00
spyOn(pathwatcher.File.prototype, "detectResurrectionAfterDelay").andCallFake -> @detectResurrection()
2014-09-23 01:35:13 +04:00
spyOn(TextEditor.prototype, "shouldPromptToSave").andReturn false
# make tokenization synchronous
TokenizedBuffer.prototype.chunkSize = Infinity
spyOn(TokenizedBuffer.prototype, "tokenizeInBackground").andCallFake -> @tokenizeNextChunk()
clipboardContent = 'initial clipboard content'
spyOn(clipboard, 'writeText').andCallFake (text) -> clipboardContent = text
spyOn(clipboard, 'readText').andCallFake -> clipboardContent
addCustomMatchers(this)
afterEach ->
atom.packages.deactivatePackages()
atom.menu.template = []
2014-09-30 06:25:55 +04:00
atom.contextMenu.clear()
2014-11-20 03:51:00 +03:00
atom.workspace?.destroy()
atom.workspace = null
atom.__workspaceView = null
delete atom.state.workspace
2014-04-03 01:19:06 +04:00
atom.project?.destroy()
atom.project = null
atom.themes.removeStylesheet('global-editor-styles')
2014-01-04 04:42:11 +04:00
delete atom.state.packageStates
$('#jasmine-content').empty() unless window.debugContent
jasmine.unspy(atom, 'saveSync')
ensureNoPathSubscriptions()
2014-11-20 21:42:49 +03:00
atom.grammars.clearObservers()
waits(0) # yield to ui thread to make screen update more frequently
ensureNoPathSubscriptions = ->
2013-04-07 12:18:08 +04:00
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
2014-04-22 22:01:05 +04:00
output.push "#{deprecation.originName} is deprecated. #{deprecation.message}"
output.push _.multiplyString("-", 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)
2012-11-17 04:12:04 +04:00
jasmine.unspy = (object, methodName) ->
throw new Error("Not a spy") unless object[methodName].hasOwnProperty('originalValue')
2012-11-17 04:12:04 +04:00
object[methodName] = object[methodName].originalValue
2014-11-20 03:20:39 +03:00
jasmine.attachToDOM = (element) ->
jasmineContent = document.querySelector('#jasmine-content')
jasmineContent.appendChild(element) unless jasmineContent.contains(element)
addCustomMatchers = (spec) ->
spec.addMatchers
toBeInstanceOf: (expected) ->
notText = if @isNot then " not" else ""
this.message = => "Expected #{jasmine.pp(@actual)} to#{notText} be instance of #{expected.name} class"
@actual instanceof expected
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
toExistOnDisk: (expected) ->
notText = this.isNot and " not" or ""
@message = -> return "Expected path '" + @actual + "'" + notText + " to exist."
2013-11-01 00:43:44 +04:00
fs.existsSync(@actual)
2014-02-05 01:06:47 +04:00
toHaveFocus: ->
notText = this.isNot and " not" or ""
if not document.hasFocus()
console.error "Specs will fail because the Dev Tools have focus. To fix this close the Dev Tools or click the spec runner."
@message = -> return "Expected element '" + @actual + "' or its descendants" + notText + " to have focus."
element = @actual
element = element.get(0) if element.jquery
element is document.activeElement or element.contains(document.activeElement)
2014-02-05 01:06:47 +04:00
2014-08-14 00:41:56 +04:00
toShow: ->
notText = if @isNot then " not" else ""
element = @actual
element = element.get(0) if element.jquery
2014-10-17 04:31:30 +04:00
@message = -> return "Expected element '#{element}' or its descendants#{notText} to show."
2014-08-14 00:41:56 +04:00
element.style.display in ['block', 'inline-block', 'static', 'fixed']
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={}) ->
2014-03-15 01:08:36 +04:00
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)
$.Event("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}
$.Event type, properties
window.clickEvent = (properties={}) ->
window.mouseEvent("click", properties)
window.mousedownEvent = (properties={}) ->
window.mouseEvent('mousedown', properties)
window.mousemoveEvent = (properties={}) ->
window.mouseEvent('mousemove', properties)
window.waitsForPromise = (args...) ->
if args.length > 1
{ shouldReject, timeout } = args[0]
else
shouldReject = false
fn = _.last(args)
window.waitsFor timeout, (moveOn) ->
promise = fn()
if shouldReject
promise.fail(moveOn)
promise.done ->
jasmine.getEnv().currentSpec.fail("Expected promise to be rejected, but it was resolved")
moveOn()
else
promise.done(moveOn)
promise.fail (error) ->
jasmine.getEnv().currentSpec.fail("Expected promise to be resolved, but it was rejected with #{jasmine.pp(error)}")
moveOn()
window.resetTimeouts = ->
window.now = 0
window.timeoutCount = 0
2014-05-21 00:03:44 +04:00
window.intervalCount = 0
window.timeouts = []
2014-05-21 00:03:44 +04:00
window.intervalTimeouts = {}
window.fakeSetTimeout = (callback, ms) ->
id = ++window.timeoutCount
window.timeouts.push([id, window.now + ms, callback])
id
window.fakeClearTimeout = (idToClear) ->
window.timeouts = window.timeouts.filter ([id]) -> id != idToClear
window.fakeSetInterval = (callback, ms) ->
2014-05-21 00:03:44 +04:00
id = ++window.intervalCount
action = ->
callback()
2014-05-21 00:03:44 +04:00
window.intervalTimeouts[id] = window.fakeSetTimeout(action, ms)
window.intervalTimeouts[id] = window.fakeSetTimeout(action, ms)
id
window.fakeClearInterval = (idToClear) ->
2014-05-21 00:03:44 +04:00
window.fakeClearTimeout(@intervalTimeouts[idToClear])
window.advanceClock = (delta=1) ->
window.now += delta
callbacks = []
window.timeouts = window.timeouts.filter ([id, strikeTime, callback]) ->
if strikeTime <= window.now
callbacks.push(callback)
false
else
true
callback() for callback in callbacks
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 }
window.tokensText = (tokens) ->
_.pluck(tokens, 'value').join('')
window.setEditorWidthInChars = (editorView, widthInChars, charWidth=editorView.charWidth) ->
editorView.width(charWidth * widthInChars + editorView.gutter.outerWidth())
$(window).trigger 'resize' # update width of editor view's on-screen lines
window.setEditorHeightInLines = (editorView, heightInLines, lineHeight=editorView.lineHeight) ->
editorView.height(editorView.getEditor().getLineHeightInPixels() * heightInLines)
editorView.component?.measureHeightAndWidth()
$.fn.resultOfTrigger = (type) ->
event = $.Event(type)
this.trigger(event)
event.result
$.fn.enableKeymap = ->
2014-04-24 03:18:12 +04:00
@on 'keydown', (e) ->
originalEvent = e.originalEvent ? e
Object.defineProperty(originalEvent, 'target', get: -> e.target) unless originalEvent.target?
atom.keymaps.handleKeyboardEvent(originalEvent)
not e.originalEvent.defaultPrevented
$.fn.attachToDom = ->
@appendTo($('#jasmine-content')) unless @isOnDom()
$.fn.simulateDomAttachment = ->
$('<html>').append(this)
$.fn.textInput = (data) ->
this.each ->
event = document.createEvent('TextEvent')
event.initTextEvent('textInput', true, true, window, data)
2013-09-18 05:58:41 +04:00
event = $.event.fix(event)
$(this).trigger(event)