mirror of
https://github.com/atom/atom.git
synced 2026-02-12 15:45:23 -05:00
Merge branch 'master' into as-double-reflow-measurements
This commit is contained in:
@@ -1,15 +1,9 @@
|
||||
{$} = require '../src/space-pen-extensions'
|
||||
|
||||
describe '"atom" protocol URL', ->
|
||||
it 'sends the file relative in the package as response', ->
|
||||
called = false
|
||||
callback = -> called = true
|
||||
$.ajax
|
||||
url: 'atom://async/package.json'
|
||||
success: callback
|
||||
# In old versions of jQuery, ajax calls to custom protocol would always
|
||||
# be treated as error eventhough the browser thinks it's a success
|
||||
# request.
|
||||
error: callback
|
||||
request = new XMLHttpRequest()
|
||||
request.addEventListener('load', -> called = true)
|
||||
request.open('GET', 'atom://async/package.json', true)
|
||||
request.send()
|
||||
|
||||
waitsFor 'request to be done', -> called is true
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
path = require 'path'
|
||||
_ = require 'underscore-plus'
|
||||
{View, $, $$} = require '../src/space-pen-extensions'
|
||||
grim = require 'grim'
|
||||
marked = require 'marked'
|
||||
|
||||
listen = require '../src/delegated-listener'
|
||||
|
||||
formatStackTrace = (spec, message='', stackTrace) ->
|
||||
return stackTrace unless stackTrace
|
||||
|
||||
@@ -30,30 +31,43 @@ formatStackTrace = (spec, message='', stackTrace) ->
|
||||
lines.join('\n').trim()
|
||||
|
||||
module.exports =
|
||||
class AtomReporter extends View
|
||||
@content: ->
|
||||
@div class: 'spec-reporter', =>
|
||||
@div class: 'padded pull-right', =>
|
||||
@button outlet: 'reloadButton', class: 'btn btn-small reload-button', 'Reload Specs'
|
||||
@div outlet: 'coreArea', class: 'symbol-area', =>
|
||||
@div outlet: 'coreHeader', class: 'symbol-header'
|
||||
@ul outlet: 'coreSummary', class: 'symbol-summary list-unstyled'
|
||||
@div outlet: 'bundledArea', class: 'symbol-area', =>
|
||||
@div outlet: 'bundledHeader', class: 'symbol-header'
|
||||
@ul outlet: 'bundledSummary', class: 'symbol-summary list-unstyled'
|
||||
@div outlet: 'userArea', class: 'symbol-area', =>
|
||||
@div outlet: 'userHeader', class: 'symbol-header'
|
||||
@ul outlet: 'userSummary', class: 'symbol-summary list-unstyled'
|
||||
@div outlet: "status", class: 'status alert alert-info', =>
|
||||
@div outlet: "time", class: 'time'
|
||||
@div outlet: "specCount", class: 'spec-count'
|
||||
@div outlet: "message", class: 'message'
|
||||
@div outlet: "results", class: 'results'
|
||||
class AtomReporter
|
||||
|
||||
@div outlet: "deprecations", class: 'status alert alert-warning', style: 'display: none', =>
|
||||
@span outlet: 'deprecationStatus', '0 deprecations'
|
||||
@div class: 'deprecation-toggle'
|
||||
@div outlet: 'deprecationList', class: 'deprecation-list'
|
||||
constructor: ->
|
||||
@element = document.createElement('div')
|
||||
@element.innerHTML = """
|
||||
<div class="spec-reporter">
|
||||
<div class="padded pull-right">
|
||||
<button outlet="reloadButton" class="btn btn-small reload-button">Reload Specs</button>
|
||||
</div>
|
||||
<div outlet="coreArea" class="symbol-area">
|
||||
<div outlet="coreHeader" class="symbol-header"></div>
|
||||
<ul outlet="coreSummary"class="symbol-summary list-unstyled"></ul>
|
||||
</div>
|
||||
<div outlet="bundledArea" class="symbol-area">
|
||||
<div outlet="bundledHeader" class="symbol-header"></div>
|
||||
<ul outlet="bundledSummary"class="symbol-summary list-unstyled"></ul>
|
||||
</div>
|
||||
<div outlet="userArea" class="symbol-area">
|
||||
<div outlet="userHeader" class="symbol-header"></div>
|
||||
<ul outlet="userSummary"class="symbol-summary list-unstyled"></ul>
|
||||
</div>
|
||||
<div outlet="status" class="status alert alert-info">
|
||||
<div outlet="time" class="time"></div>
|
||||
<div outlet="specCount" class="spec-count"></div>
|
||||
<div outlet="message" class="message"></div>
|
||||
</div>
|
||||
<div outlet="results" class="results"></div>
|
||||
<div outlet="deprecations" class="status alert alert-warning" style="display: none">
|
||||
<span outlet="deprecationStatus">0 deprecations</span>
|
||||
<div class="deprecation-toggle"></div>
|
||||
</div>
|
||||
<div outlet="deprecationList" class="deprecation-list"></div>
|
||||
</div>
|
||||
"""
|
||||
|
||||
for element in @element.querySelectorAll('[outlet]')
|
||||
this[element.getAttribute('outlet')] = element
|
||||
|
||||
startedAt: null
|
||||
runningSpecCount: 0
|
||||
@@ -71,20 +85,18 @@ class AtomReporter extends View
|
||||
specs = runner.specs()
|
||||
@totalSpecCount = specs.length
|
||||
@addSpecs(specs)
|
||||
$(document.body).append this
|
||||
|
||||
@on 'click', '.stack-trace', ->
|
||||
$(this).toggleClass('expanded')
|
||||
|
||||
@reloadButton.on 'click', -> require('ipc').send('call-window-method', 'restart')
|
||||
document.body.appendChild(@element)
|
||||
|
||||
reportRunnerResults: (runner) ->
|
||||
@updateSpecCounts()
|
||||
@status.addClass('alert-success').removeClass('alert-info') if @failedCount is 0
|
||||
if @failedCount is 0
|
||||
@status.classList.add('alert-success')
|
||||
@status.classList.remove('alert-info')
|
||||
|
||||
if @failedCount is 1
|
||||
@message.text "#{@failedCount} failure"
|
||||
@message.textContent = "#{@failedCount} failure"
|
||||
else
|
||||
@message.text "#{@failedCount} failures"
|
||||
@message.textConent = "#{@failedCount} failures"
|
||||
|
||||
reportSuiteResults: (suite) ->
|
||||
|
||||
@@ -100,170 +112,214 @@ class AtomReporter extends View
|
||||
addDeprecations: (spec) ->
|
||||
deprecations = grim.getDeprecations()
|
||||
@deprecationCount += deprecations.length
|
||||
@deprecations.show() if @deprecationCount > 0
|
||||
@deprecations.style.display = '' if @deprecationCount > 0
|
||||
if @deprecationCount is 1
|
||||
@deprecationStatus.text("1 deprecation")
|
||||
@deprecationStatus.textContent = "1 deprecation"
|
||||
else
|
||||
@deprecationStatus.text("#{@deprecationCount} deprecations")
|
||||
@deprecationStatus.textContent = "#{@deprecationCount} deprecations"
|
||||
|
||||
for deprecation in deprecations
|
||||
@deprecationList.append $$ ->
|
||||
@div class: 'padded', =>
|
||||
@div class: 'result-message fail deprecation-message', =>
|
||||
@raw marked(deprecation.message)
|
||||
@deprecationList.appendChild(@buildDeprecationElement(spec, deprecation))
|
||||
|
||||
for stack in deprecation.getStacks()
|
||||
fullStack = stack.map ({functionName, location}) ->
|
||||
if functionName is '<unknown>'
|
||||
" at #{location}"
|
||||
else
|
||||
" at #{functionName} (#{location})"
|
||||
@pre class: 'stack-trace padded', formatStackTrace(spec, deprecation.message, fullStack.join('\n'))
|
||||
grim.clearDeprecations()
|
||||
|
||||
handleEvents: ->
|
||||
$(document).on "click", ".spec-toggle", ({currentTarget}) ->
|
||||
element = $(currentTarget)
|
||||
specFailures = element.parent().find('.spec-failures')
|
||||
specFailures.toggle()
|
||||
element.toggleClass('folded')
|
||||
false
|
||||
buildDeprecationElement: (spec, deprecation) ->
|
||||
div = document.createElement('div')
|
||||
div.className = 'padded'
|
||||
div.innerHTML = """
|
||||
<div class="result-message fail deprecation-message">
|
||||
#{marked(deprecation.message)}
|
||||
</div>
|
||||
"""
|
||||
|
||||
$(document).on "click", ".deprecation-toggle", ({currentTarget}) ->
|
||||
element = $(currentTarget)
|
||||
deprecationList = $(document).find('.deprecation-list')
|
||||
deprecationList.toggle()
|
||||
element.toggleClass('folded')
|
||||
false
|
||||
for stack in deprecation.getStacks()
|
||||
fullStack = stack.map ({functionName, location}) ->
|
||||
if functionName is '<unknown>'
|
||||
" at #{location}"
|
||||
else
|
||||
" at #{functionName} (#{location})"
|
||||
pre = document.createElement('pre')
|
||||
pre.className = 'stack-trace padded'
|
||||
pre.textContent = formatStackTrace(spec, deprecation.message, fullStack.join('\n'))
|
||||
div.appendChild(pre)
|
||||
|
||||
div
|
||||
|
||||
handleEvents: ->
|
||||
listen document, 'click', '.spec-toggle', (event) ->
|
||||
specFailures = event.currentTarget.parentElement.querySelector('.spec-failures')
|
||||
|
||||
if specFailures.style.display is 'none'
|
||||
specFailures.style.display = ''
|
||||
event.currentTarget.classList.remove('folded')
|
||||
else
|
||||
specFailures.style.display = 'none'
|
||||
event.currentTarget.classList.add('folded')
|
||||
|
||||
event.preventDefault()
|
||||
|
||||
listen document, 'click', '.deprecation-list', (event) ->
|
||||
deprecationList = event.currentTarget.parentElement.querySelector('.deprecation-list')
|
||||
|
||||
if deprecationList.style.display is 'none'
|
||||
deprecationList.style.display = ''
|
||||
event.currentTarget.classList.remove('folded')
|
||||
else
|
||||
deprecationList.style.display = 'none'
|
||||
event.currentTarget.classList.add('folded')
|
||||
|
||||
event.preventDefault()
|
||||
|
||||
listen document, 'click', '.stack-trace', (event) ->
|
||||
event.currentTarget.classList.toggle('expanded')
|
||||
|
||||
@reloadButton.addEventListener('click', -> require('ipc').send('call-window-method', 'restart'))
|
||||
|
||||
updateSpecCounts: ->
|
||||
if @skippedCount
|
||||
specCount = "#{@completeSpecCount - @skippedCount}/#{@totalSpecCount - @skippedCount} (#{@skippedCount} skipped)"
|
||||
else
|
||||
specCount = "#{@completeSpecCount}/#{@totalSpecCount}"
|
||||
@specCount[0].textContent = specCount
|
||||
@specCount.textContent = specCount
|
||||
|
||||
updateStatusView: (spec) ->
|
||||
if @failedCount > 0
|
||||
@status.addClass('alert-danger').removeClass('alert-info')
|
||||
@status.classList.add('alert-danger')
|
||||
@status.classList.remove('alert-info')
|
||||
|
||||
@updateSpecCounts()
|
||||
|
||||
rootSuite = spec.suite
|
||||
rootSuite = rootSuite.parentSuite while rootSuite.parentSuite
|
||||
@message.text rootSuite.description
|
||||
@message.textContent = rootSuite.description
|
||||
|
||||
time = "#{Math.round((spec.endedAt - @startedAt) / 10)}"
|
||||
time = "0#{time}" if time.length < 3
|
||||
@time[0].textContent = "#{time[0...-2]}.#{time[-2..]}s"
|
||||
@time.textContent = "#{time[0...-2]}.#{time[-2..]}s"
|
||||
|
||||
addSpecs: (specs) ->
|
||||
coreSpecs = 0
|
||||
bundledPackageSpecs = 0
|
||||
userPackageSpecs = 0
|
||||
for spec in specs
|
||||
symbol = $$ -> @li id: "spec-summary-#{spec.id}", class: "spec-summary pending"
|
||||
symbol = document.createElement('li')
|
||||
symbol.setAttribute('id', "spec-summary-#{spec.id}")
|
||||
symbol.className = "spec-summary pending"
|
||||
switch spec.specType
|
||||
when 'core'
|
||||
coreSpecs++
|
||||
@coreSummary.append symbol
|
||||
@coreSummary.appendChild symbol
|
||||
when 'bundled'
|
||||
bundledPackageSpecs++
|
||||
@bundledSummary.append symbol
|
||||
@bundledSummary.appendChild symbol
|
||||
when 'user'
|
||||
userPackageSpecs++
|
||||
@userSummary.append symbol
|
||||
@userSummary.appendChild symbol
|
||||
|
||||
if coreSpecs > 0
|
||||
@coreHeader.text("Core Specs (#{coreSpecs})")
|
||||
@coreHeader.textContent = "Core Specs (#{coreSpecs})"
|
||||
else
|
||||
@coreArea.hide()
|
||||
@coreArea.style.display = 'none'
|
||||
if bundledPackageSpecs > 0
|
||||
@bundledHeader.text("Bundled Package Specs (#{bundledPackageSpecs})")
|
||||
@bundledHeader.textContent = "Bundled Package Specs (#{bundledPackageSpecs})"
|
||||
else
|
||||
@bundledArea.hide()
|
||||
@bundledArea.style.display = 'none'
|
||||
if userPackageSpecs > 0
|
||||
if coreSpecs is 0 and bundledPackageSpecs is 0
|
||||
# Package specs being run, show a more descriptive label
|
||||
{specDirectory} = specs[0]
|
||||
packageFolderName = path.basename(path.dirname(specDirectory))
|
||||
packageName = _.undasherize(_.uncamelcase(packageFolderName))
|
||||
@userHeader.text("#{packageName} Specs")
|
||||
@userHeader.textContent = "#{packageName} Specs"
|
||||
else
|
||||
@userHeader.text("User Package Specs (#{userPackageSpecs})")
|
||||
@userHeader.textContent = "User Package Specs (#{userPackageSpecs})"
|
||||
else
|
||||
@userArea.hide()
|
||||
@userArea.style.display = 'none'
|
||||
|
||||
specStarted: (spec) ->
|
||||
@runningSpecCount++
|
||||
|
||||
specComplete: (spec) ->
|
||||
specSummaryElement = $("#spec-summary-#{spec.id}")
|
||||
specSummaryElement.removeClass('pending')
|
||||
specSummaryElement.setTooltip(title: spec.getFullName(), container: '.spec-reporter')
|
||||
specSummaryElement = document.getElementById("spec-summary-#{spec.id}")
|
||||
specSummaryElement.classList.remove('pending')
|
||||
|
||||
results = spec.results()
|
||||
if results.skipped
|
||||
specSummaryElement.addClass("skipped")
|
||||
specSummaryElement.classList.add("skipped")
|
||||
@skippedCount++
|
||||
else if results.passed()
|
||||
specSummaryElement.addClass("passed")
|
||||
specSummaryElement.classList.add("passed")
|
||||
@passedCount++
|
||||
else
|
||||
specSummaryElement.addClass("failed")
|
||||
specSummaryElement.classList.add("failed")
|
||||
|
||||
specView = new SpecResultView(spec)
|
||||
specView.attach()
|
||||
@failedCount++
|
||||
@addDeprecations(spec)
|
||||
|
||||
class SuiteResultView extends View
|
||||
@content: ->
|
||||
@div class: 'suite', =>
|
||||
@div outlet: 'description', class: 'description'
|
||||
|
||||
initialize: (@suite) ->
|
||||
@attr('id', "suite-view-#{@suite.id}")
|
||||
@description.text(@suite.description)
|
||||
class SuiteResultView
|
||||
constructor: (@suite) ->
|
||||
@element = document.createElement('div')
|
||||
@element.className = 'suite'
|
||||
@element.setAttribute('id', "suite-view-#{@suite.id}")
|
||||
@description = document.createElement('div')
|
||||
@description.className = 'description'
|
||||
@description.textContent = @suite.description
|
||||
@element.appendChild(@description)
|
||||
|
||||
attach: ->
|
||||
(@parentSuiteView() or $('.results')).append this
|
||||
(@parentSuiteView() or document.querySelector('.results')).appendChild(@element)
|
||||
|
||||
parentSuiteView: ->
|
||||
return unless @suite.parentSuite
|
||||
|
||||
if not suiteView = $("#suite-view-#{@suite.parentSuite.id}").view()
|
||||
unless suiteViewElement = document.querySelector("#suite-view-#{@suite.parentSuite.id}")
|
||||
suiteView = new SuiteResultView(@suite.parentSuite)
|
||||
suiteView.attach()
|
||||
suiteViewElement = suiteView.element
|
||||
|
||||
suiteView
|
||||
suiteViewElement
|
||||
|
||||
class SpecResultView extends View
|
||||
@content: ->
|
||||
@div class: 'spec', =>
|
||||
@div class: 'spec-toggle'
|
||||
@div outlet: 'description', class: 'description'
|
||||
@div outlet: 'specFailures', class: 'spec-failures'
|
||||
class SpecResultView
|
||||
constructor: (@spec) ->
|
||||
@element = document.createElement('div')
|
||||
@element.className = 'spec'
|
||||
@element.innerHTML = """
|
||||
<div class='spec-toggle'></div>
|
||||
<div outlet='description' class='description'></div>
|
||||
<div outlet='specFailures' class='spec-failures'></div>
|
||||
"""
|
||||
@description = @element.querySelector('[outlet="description"]')
|
||||
@specFailures = @element.querySelector('[outlet="specFailures"]')
|
||||
|
||||
initialize: (@spec) ->
|
||||
@addClass("spec-view-#{@spec.id}")
|
||||
@element.classList.add("spec-view-#{@spec.id}")
|
||||
|
||||
description = @spec.description
|
||||
description = "it #{description}" if description.indexOf('it ') isnt 0
|
||||
@description.text(description)
|
||||
@description.textContent = description
|
||||
|
||||
for result in @spec.results().getItems() when not result.passed()
|
||||
stackTrace = formatStackTrace(@spec, result.message, result.trace.stack)
|
||||
@specFailures.append $$ ->
|
||||
@div result.message, class: 'result-message fail'
|
||||
@pre stackTrace, class: 'stack-trace padded' if stackTrace
|
||||
|
||||
resultElement = document.createElement('div')
|
||||
resultElement.className = 'result-message fail'
|
||||
resultElement.textContent = result.message
|
||||
@specFailures.appendChild(resultElement)
|
||||
|
||||
if stackTrace
|
||||
traceElement = document.createElement('pre')
|
||||
traceElement.className = 'stack-trace padded'
|
||||
traceElement.textContent = stackTrace
|
||||
@specFailures.appendChild(traceElement)
|
||||
|
||||
attach: ->
|
||||
@parentSuiteView().append this
|
||||
@parentSuiteView().appendChild(@element)
|
||||
|
||||
parentSuiteView: ->
|
||||
if not suiteView = $("#suite-view-#{@spec.suite.id}").view()
|
||||
unless suiteViewElement = document.querySelector("#suite-view-#{@spec.suite.id}")
|
||||
suiteView = new SuiteResultView(@spec.suite)
|
||||
suiteView.attach()
|
||||
suiteViewElement = suiteView.element
|
||||
|
||||
suiteView
|
||||
suiteViewElement
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
{$, $$} = require '../src/space-pen-extensions'
|
||||
Exec = require('child_process').exec
|
||||
path = require 'path'
|
||||
Package = require '../src/package'
|
||||
@@ -223,3 +222,31 @@ describe "the `atom` global", ->
|
||||
spyOn(atom, "pickFolder").andCallFake (callback) -> callback(null)
|
||||
atom.addProjectFolder()
|
||||
expect(atom.project.getPaths()).toEqual(initialPaths)
|
||||
|
||||
describe "::unloadEditorWindow()", ->
|
||||
it "saves the serialized state of the window so it can be deserialized after reload", ->
|
||||
workspaceState = atom.workspace.serialize()
|
||||
syntaxState = atom.grammars.serialize()
|
||||
projectState = atom.project.serialize()
|
||||
|
||||
atom.unloadEditorWindow()
|
||||
|
||||
expect(atom.state.workspace).toEqual workspaceState
|
||||
expect(atom.state.grammars).toEqual syntaxState
|
||||
expect(atom.state.project).toEqual projectState
|
||||
expect(atom.saveSync).toHaveBeenCalled()
|
||||
|
||||
describe "::removeEditorWindow()", ->
|
||||
it "unsubscribes from all buffers", ->
|
||||
waitsForPromise ->
|
||||
atom.workspace.open("sample.js")
|
||||
|
||||
runs ->
|
||||
buffer = atom.workspace.getActivePaneItem().buffer
|
||||
pane = atom.workspace.getActivePane()
|
||||
pane.splitRight(copyActiveItem: true)
|
||||
expect(atom.workspace.getTextEditors().length).toBe 2
|
||||
|
||||
atom.removeEditorWindow()
|
||||
|
||||
expect(buffer.getSubscriptionCount()).toBe 0
|
||||
|
||||
@@ -115,6 +115,15 @@ describe "CommandRegistry", ->
|
||||
grandchild.dispatchEvent(dispatchedEvent)
|
||||
expect(dispatchedEvent.abortKeyBinding).toHaveBeenCalled()
|
||||
|
||||
it "copies non-standard properties from the original event to the synthetic event", ->
|
||||
syntheticEvent = null
|
||||
registry.add '.child', 'command', (event) -> syntheticEvent = event
|
||||
|
||||
dispatchedEvent = new CustomEvent('command', bubbles: true)
|
||||
dispatchedEvent.nonStandardProperty = 'testing'
|
||||
grandchild.dispatchEvent(dispatchedEvent)
|
||||
expect(syntheticEvent.nonStandardProperty).toBe 'testing'
|
||||
|
||||
it "allows listeners to be removed via a disposable returned by ::add", ->
|
||||
calls = []
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
{$$} = require '../src/space-pen-extensions'
|
||||
|
||||
ContextMenuManager = require '../src/context-menu-manager'
|
||||
|
||||
describe "ContextMenuManager", ->
|
||||
|
||||
@@ -281,6 +281,9 @@ describe "DisplayBuffer", ->
|
||||
|
||||
describe ".setEditorWidthInChars(length)", ->
|
||||
it "changes the length at which lines are wrapped and emits a change event for all screen lines", ->
|
||||
tokensText = (tokens) ->
|
||||
_.pluck(tokens, 'value').join('')
|
||||
|
||||
displayBuffer.setEditorWidthInChars(40)
|
||||
expect(tokensText displayBuffer.tokenizedLineForScreenRow(4).tokens).toBe ' left = [], right = [];'
|
||||
expect(tokensText displayBuffer.tokenizedLineForScreenRow(5).tokens).toBe ' while(items.length > 0) {'
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
fs = require 'fs'
|
||||
|
||||
module.exports.runSpecSuite = (specSuite, logFile, logErrors=true) ->
|
||||
{$, $$} = require '../src/space-pen-extensions'
|
||||
|
||||
window[key] = value for key, value of require '../vendor/jasmine'
|
||||
|
||||
{TerminalReporter} = require 'jasmine-tagged'
|
||||
@@ -47,7 +45,9 @@ module.exports.runSpecSuite = (specSuite, logFile, logErrors=true) ->
|
||||
jasmineEnv.addReporter(timeReporter)
|
||||
jasmineEnv.setIncludedTags([process.platform])
|
||||
|
||||
$('body').append $$ -> @div id: 'jasmine-content'
|
||||
jasmineContent = document.createElement('div')
|
||||
jasmineContent.setAttribute('id', 'jasmine-content')
|
||||
document.body.appendChild(jasmineContent)
|
||||
|
||||
jasmineEnv.execute()
|
||||
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
path = require 'path'
|
||||
{$, $$} = require '../src/space-pen-extensions'
|
||||
Package = require '../src/package'
|
||||
{Disposable} = require 'atom'
|
||||
|
||||
describe "PackageManager", ->
|
||||
workspaceElement = null
|
||||
|
||||
createTestElement = (className) ->
|
||||
element = document.createElement('div')
|
||||
element.className = className
|
||||
element
|
||||
|
||||
beforeEach ->
|
||||
workspaceElement = atom.views.getView(atom.workspace)
|
||||
|
||||
@@ -209,33 +213,31 @@ describe "PackageManager", ->
|
||||
mainModule = null
|
||||
|
||||
it "defers requiring/activating the main module until an activation event bubbles to the root view", ->
|
||||
expect(promise.isFulfilled()).not.toBeTruthy()
|
||||
expect(Package.prototype.requireMainModule.callCount).toBe 0
|
||||
|
||||
workspaceElement.dispatchEvent(new CustomEvent('activation-command', bubbles: true))
|
||||
|
||||
waitsForPromise ->
|
||||
promise
|
||||
|
||||
runs ->
|
||||
expect(Package.prototype.requireMainModule.callCount).toBe 1
|
||||
|
||||
it "triggers the activation event on all handlers registered during activation", ->
|
||||
waitsForPromise ->
|
||||
atom.workspace.open()
|
||||
|
||||
runs ->
|
||||
editorView = atom.views.getView(atom.workspace.getActiveTextEditor()).__spacePenView
|
||||
legacyCommandListener = jasmine.createSpy("legacyCommandListener")
|
||||
editorView.command 'activation-command', legacyCommandListener
|
||||
editorElement = atom.views.getView(atom.workspace.getActiveTextEditor())
|
||||
editorCommandListener = jasmine.createSpy("editorCommandListener")
|
||||
atom.commands.add 'atom-text-editor', 'activation-command', editorCommandListener
|
||||
atom.commands.dispatch(editorView[0], 'activation-command')
|
||||
atom.commands.dispatch(editorElement, 'activation-command')
|
||||
expect(mainModule.activate.callCount).toBe 1
|
||||
expect(mainModule.legacyActivationCommandCallCount).toBe 1
|
||||
expect(mainModule.activationCommandCallCount).toBe 1
|
||||
expect(legacyCommandListener.callCount).toBe 1
|
||||
expect(editorCommandListener.callCount).toBe 1
|
||||
expect(workspaceCommandListener.callCount).toBe 1
|
||||
atom.commands.dispatch(editorView[0], 'activation-command')
|
||||
expect(mainModule.legacyActivationCommandCallCount).toBe 2
|
||||
atom.commands.dispatch(editorElement, 'activation-command')
|
||||
expect(mainModule.activationCommandCallCount).toBe 2
|
||||
expect(legacyCommandListener.callCount).toBe 2
|
||||
expect(editorCommandListener.callCount).toBe 2
|
||||
expect(workspaceCommandListener.callCount).toBe 2
|
||||
expect(mainModule.activate.callCount).toBe 1
|
||||
@@ -301,8 +303,8 @@ describe "PackageManager", ->
|
||||
promise = atom.packages.activatePackage('package-with-activation-hooks')
|
||||
|
||||
it "defers requiring/activating the main module until an triggering of an activation hook occurs", ->
|
||||
expect(promise.isFulfilled()).not.toBeTruthy()
|
||||
expect(Package.prototype.requireMainModule.callCount).toBe 0
|
||||
|
||||
atom.packages.triggerActivationHook('language-fictitious:grammar-used')
|
||||
|
||||
waitsForPromise ->
|
||||
@@ -399,36 +401,36 @@ describe "PackageManager", ->
|
||||
describe "keymap loading", ->
|
||||
describe "when the metadata does not contain a 'keymaps' manifest", ->
|
||||
it "loads all the .cson/.json files in the keymaps directory", ->
|
||||
element1 = $$ -> @div class: 'test-1'
|
||||
element2 = $$ -> @div class: 'test-2'
|
||||
element3 = $$ -> @div class: 'test-3'
|
||||
element1 = createTestElement('test-1')
|
||||
element2 = createTestElement('test-2')
|
||||
element3 = createTestElement('test-3')
|
||||
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes: 'ctrl-z', target: element1[0])).toHaveLength 0
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes: 'ctrl-z', target: element2[0])).toHaveLength 0
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes: 'ctrl-z', target: element3[0])).toHaveLength 0
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes: 'ctrl-z', target: element1)).toHaveLength 0
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes: 'ctrl-z', target: element2)).toHaveLength 0
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes: 'ctrl-z', target: element3)).toHaveLength 0
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage("package-with-keymaps")
|
||||
|
||||
runs ->
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes: 'ctrl-z', target: element1[0])[0].command).toBe "test-1"
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes: 'ctrl-z', target: element2[0])[0].command).toBe "test-2"
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes: 'ctrl-z', target: element3[0])).toHaveLength 0
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes: 'ctrl-z', target: element1)[0].command).toBe "test-1"
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes: 'ctrl-z', target: element2)[0].command).toBe "test-2"
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes: 'ctrl-z', target: element3)).toHaveLength 0
|
||||
|
||||
describe "when the metadata contains a 'keymaps' manifest", ->
|
||||
it "loads only the keymaps specified by the manifest, in the specified order", ->
|
||||
element1 = $$ -> @div class: 'test-1'
|
||||
element3 = $$ -> @div class: 'test-3'
|
||||
element1 = createTestElement('test-1')
|
||||
element3 = createTestElement('test-3')
|
||||
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes: 'ctrl-z', target: element1[0])).toHaveLength 0
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes: 'ctrl-z', target: element1)).toHaveLength 0
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage("package-with-keymaps-manifest")
|
||||
|
||||
runs ->
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes: 'ctrl-z', target: element1[0])[0].command).toBe 'keymap-1'
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes: 'ctrl-n', target: element1[0])[0].command).toBe 'keymap-2'
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes: 'ctrl-y', target: element3[0])).toHaveLength 0
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes: 'ctrl-z', target: element1)[0].command).toBe 'keymap-1'
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes: 'ctrl-n', target: element1)[0].command).toBe 'keymap-2'
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes: 'ctrl-y', target: element3)).toHaveLength 0
|
||||
|
||||
describe "when the keymap file is empty", ->
|
||||
it "does not throw an error on activation", ->
|
||||
@@ -440,9 +442,9 @@ describe "PackageManager", ->
|
||||
|
||||
describe "when the package's keymaps have been disabled", ->
|
||||
it "does not add the keymaps", ->
|
||||
element1 = $$ -> @div class: 'test-1'
|
||||
element1 = createTestElement('test-1')
|
||||
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes: 'ctrl-z', target: element1[0])).toHaveLength 0
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes: 'ctrl-z', target: element1)).toHaveLength 0
|
||||
|
||||
atom.config.set("core.packagesWithKeymapsDisabled", ["package-with-keymaps-manifest"])
|
||||
|
||||
@@ -450,11 +452,11 @@ describe "PackageManager", ->
|
||||
atom.packages.activatePackage("package-with-keymaps-manifest")
|
||||
|
||||
runs ->
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes: 'ctrl-z', target: element1[0])).toHaveLength 0
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes: 'ctrl-z', target: element1)).toHaveLength 0
|
||||
|
||||
describe "when the package's keymaps are disabled and re-enabled after it is activated", ->
|
||||
it "removes and re-adds the keymaps", ->
|
||||
element1 = $$ -> @div class: 'test-1'
|
||||
element1 = createTestElement('test-1')
|
||||
atom.packages.observePackagesWithKeymapsDisabled()
|
||||
|
||||
waitsForPromise ->
|
||||
@@ -462,10 +464,10 @@ describe "PackageManager", ->
|
||||
|
||||
runs ->
|
||||
atom.config.set("core.packagesWithKeymapsDisabled", ['package-with-keymaps-manifest'])
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes: 'ctrl-z', target: element1[0])).toHaveLength 0
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes: 'ctrl-z', target: element1)).toHaveLength 0
|
||||
|
||||
atom.config.set("core.packagesWithKeymapsDisabled", [])
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes: 'ctrl-z', target: element1[0])[0].command).toBe 'keymap-1'
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes: 'ctrl-z', target: element1)[0].command).toBe 'keymap-1'
|
||||
|
||||
describe "menu loading", ->
|
||||
beforeEach ->
|
||||
@@ -474,7 +476,7 @@ describe "PackageManager", ->
|
||||
|
||||
describe "when the metadata does not contain a 'menus' manifest", ->
|
||||
it "loads all the .cson/.json files in the menus directory", ->
|
||||
element = ($$ -> @div class: 'test-1')[0]
|
||||
element = createTestElement('test-1')
|
||||
|
||||
expect(atom.contextMenu.templateForElement(element)).toEqual []
|
||||
|
||||
@@ -491,7 +493,7 @@ describe "PackageManager", ->
|
||||
|
||||
describe "when the metadata contains a 'menus' manifest", ->
|
||||
it "loads only the menus specified by the manifest, in the specified order", ->
|
||||
element = ($$ -> @div class: 'test-1')[0]
|
||||
element = createTestElement('test-1')
|
||||
|
||||
expect(atom.contextMenu.templateForElement(element)).toEqual []
|
||||
|
||||
@@ -535,7 +537,8 @@ describe "PackageManager", ->
|
||||
expect(atom.themes.stylesheetElementForId(one)).not.toBeNull()
|
||||
expect(atom.themes.stylesheetElementForId(two)).not.toBeNull()
|
||||
expect(atom.themes.stylesheetElementForId(three)).toBeNull()
|
||||
expect($('#jasmine-content').css('font-size')).toBe '1px'
|
||||
|
||||
expect(getComputedStyle(document.querySelector('#jasmine-content')).fontSize).toBe '1px'
|
||||
|
||||
describe "when the metadata does not contain a 'styleSheets' manifest", ->
|
||||
it "loads all style sheets from the styles directory", ->
|
||||
@@ -562,7 +565,7 @@ describe "PackageManager", ->
|
||||
expect(atom.themes.stylesheetElementForId(two)).not.toBeNull()
|
||||
expect(atom.themes.stylesheetElementForId(three)).not.toBeNull()
|
||||
expect(atom.themes.stylesheetElementForId(four)).not.toBeNull()
|
||||
expect($('#jasmine-content').css('font-size')).toBe '3px'
|
||||
expect(getComputedStyle(document.querySelector('#jasmine-content')).fontSize).toBe '3px'
|
||||
|
||||
it "assigns the stylesheet's context based on the filename", ->
|
||||
waitsForPromise ->
|
||||
@@ -747,8 +750,8 @@ describe "PackageManager", ->
|
||||
|
||||
runs ->
|
||||
atom.packages.deactivatePackage('package-with-keymaps')
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes: 'ctrl-z', target: ($$ -> @div class: 'test-1')[0])).toHaveLength 0
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes: 'ctrl-z', target: ($$ -> @div class: 'test-2')[0])).toHaveLength 0
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes: 'ctrl-z', target: createTestElement('test-1'))).toHaveLength 0
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes: 'ctrl-z', target: createTestElement('test-2'))).toHaveLength 0
|
||||
|
||||
it "removes the package's stylesheets", ->
|
||||
waitsForPromise ->
|
||||
@@ -890,7 +893,7 @@ describe "PackageManager", ->
|
||||
# enabling of theme
|
||||
pack = atom.packages.enablePackage(packageName)
|
||||
|
||||
waitsFor ->
|
||||
waitsFor 'theme to enable', 500, ->
|
||||
pack in atom.packages.getActivePackages()
|
||||
|
||||
runs ->
|
||||
@@ -903,7 +906,7 @@ describe "PackageManager", ->
|
||||
|
||||
pack = atom.packages.disablePackage(packageName)
|
||||
|
||||
waitsFor ->
|
||||
waitsFor 'did-change-active-themes event to fire', 500, ->
|
||||
didChangeActiveThemesHandler.callCount is 1
|
||||
|
||||
runs ->
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
{$} = require '../src/space-pen-extensions'
|
||||
path = require 'path'
|
||||
Package = require '../src/package'
|
||||
ThemePackage = require '../src/theme-package'
|
||||
@@ -106,54 +105,55 @@ describe "Package", ->
|
||||
expect(pack.getIncompatibleNativeModules().length).toBe(0)
|
||||
|
||||
describe "theme", ->
|
||||
theme = null
|
||||
[editorElement, theme] = []
|
||||
|
||||
beforeEach ->
|
||||
$("#jasmine-content").append $("<atom-text-editor></atom-text-editor>")
|
||||
editorElement = document.createElement('atom-text-editor')
|
||||
jasmine.attachToDOM(editorElement)
|
||||
|
||||
afterEach ->
|
||||
theme.deactivate() if theme?
|
||||
|
||||
describe "when the theme contains a single style file", ->
|
||||
it "loads and applies css", ->
|
||||
expect($("atom-text-editor").css("padding-bottom")).not.toBe "1234px"
|
||||
expect(getComputedStyle(editorElement).paddingBottom).not.toBe "1234px"
|
||||
themePath = atom.project.getDirectories()[0]?.resolve('packages/theme-with-index-css')
|
||||
theme = new ThemePackage(themePath)
|
||||
theme.activate()
|
||||
expect($("atom-text-editor").css("padding-top")).toBe "1234px"
|
||||
expect(getComputedStyle(editorElement).paddingTop).toBe "1234px"
|
||||
|
||||
it "parses, loads and applies less", ->
|
||||
expect($("atom-text-editor").css("padding-bottom")).not.toBe "1234px"
|
||||
expect(getComputedStyle(editorElement).paddingBottom).not.toBe "1234px"
|
||||
themePath = atom.project.getDirectories()[0]?.resolve('packages/theme-with-index-less')
|
||||
theme = new ThemePackage(themePath)
|
||||
theme.activate()
|
||||
expect($("atom-text-editor").css("padding-top")).toBe "4321px"
|
||||
expect(getComputedStyle(editorElement).paddingTop).toBe "4321px"
|
||||
|
||||
describe "when the theme contains a package.json file", ->
|
||||
it "loads and applies stylesheets from package.json in the correct order", ->
|
||||
expect($("atom-text-editor").css("padding-top")).not.toBe("101px")
|
||||
expect($("atom-text-editor").css("padding-right")).not.toBe("102px")
|
||||
expect($("atom-text-editor").css("padding-bottom")).not.toBe("103px")
|
||||
expect(getComputedStyle(editorElement).paddingTop).not.toBe("101px")
|
||||
expect(getComputedStyle(editorElement).paddingRight).not.toBe("102px")
|
||||
expect(getComputedStyle(editorElement).paddingBottom).not.toBe("103px")
|
||||
|
||||
themePath = atom.project.getDirectories()[0]?.resolve('packages/theme-with-package-file')
|
||||
theme = new ThemePackage(themePath)
|
||||
theme.activate()
|
||||
expect($("atom-text-editor").css("padding-top")).toBe("101px")
|
||||
expect($("atom-text-editor").css("padding-right")).toBe("102px")
|
||||
expect($("atom-text-editor").css("padding-bottom")).toBe("103px")
|
||||
expect(getComputedStyle(editorElement).paddingTop).toBe("101px")
|
||||
expect(getComputedStyle(editorElement).paddingRight).toBe("102px")
|
||||
expect(getComputedStyle(editorElement).paddingBottom).toBe("103px")
|
||||
|
||||
describe "when the theme does not contain a package.json file and is a directory", ->
|
||||
it "loads all stylesheet files in the directory", ->
|
||||
expect($("atom-text-editor").css("padding-top")).not.toBe "10px"
|
||||
expect($("atom-text-editor").css("padding-right")).not.toBe "20px"
|
||||
expect($("atom-text-editor").css("padding-bottom")).not.toBe "30px"
|
||||
expect(getComputedStyle(editorElement).paddingTop).not.toBe "10px"
|
||||
expect(getComputedStyle(editorElement).paddingRight).not.toBe "20px"
|
||||
expect(getComputedStyle(editorElement).paddingBottom).not.toBe "30px"
|
||||
|
||||
themePath = atom.project.getDirectories()[0]?.resolve('packages/theme-without-package-file')
|
||||
theme = new ThemePackage(themePath)
|
||||
theme.activate()
|
||||
expect($("atom-text-editor").css("padding-top")).toBe "10px"
|
||||
expect($("atom-text-editor").css("padding-right")).toBe "20px"
|
||||
expect($("atom-text-editor").css("padding-bottom")).toBe "30px"
|
||||
expect(getComputedStyle(editorElement).paddingTop).toBe "10px"
|
||||
expect(getComputedStyle(editorElement).paddingRight).toBe "20px"
|
||||
expect(getComputedStyle(editorElement).paddingBottom).toBe "30px"
|
||||
|
||||
describe "reloading a theme", ->
|
||||
beforeEach ->
|
||||
|
||||
@@ -4,16 +4,13 @@ PaneAxis = require '../src/pane-axis'
|
||||
|
||||
describe "PaneContainerElement", ->
|
||||
describe "when panes are added or removed", ->
|
||||
[paneAxisElement, paneAxis] = []
|
||||
it "inserts or removes resize elements", ->
|
||||
childTagNames = ->
|
||||
child.nodeName.toLowerCase() for child in paneAxisElement.children
|
||||
|
||||
beforeEach ->
|
||||
paneAxis = new PaneAxis
|
||||
paneAxisElement = new PaneAxisElement().initialize(paneAxis)
|
||||
|
||||
childTagNames = ->
|
||||
child.nodeName.toLowerCase() for child in paneAxisElement.children
|
||||
|
||||
it "inserts or removes resize elements", ->
|
||||
expect(childTagNames()).toEqual []
|
||||
|
||||
paneAxis.addChild(new PaneAxis)
|
||||
@@ -44,6 +41,45 @@ describe "PaneContainerElement", ->
|
||||
'atom-pane-axis'
|
||||
]
|
||||
|
||||
it "transfers focus to the next pane if a focused pane is removed", ->
|
||||
container = new PaneContainer
|
||||
containerElement = atom.views.getView(container)
|
||||
leftPane = container.getActivePane()
|
||||
leftPaneElement = atom.views.getView(leftPane)
|
||||
rightPane = leftPane.splitRight()
|
||||
rightPaneElement = atom.views.getView(rightPane)
|
||||
|
||||
jasmine.attachToDOM(containerElement)
|
||||
rightPaneElement.focus()
|
||||
expect(document.activeElement).toBe rightPaneElement
|
||||
|
||||
rightPane.destroy()
|
||||
expect(document.activeElement).toBe leftPaneElement
|
||||
|
||||
describe "when a pane is split", ->
|
||||
it "builds appropriately-oriented atom-pane-axis elements", ->
|
||||
container = new PaneContainer
|
||||
containerElement = atom.views.getView(container)
|
||||
|
||||
pane1 = container.getRoot()
|
||||
pane2 = pane1.splitRight()
|
||||
pane3 = pane2.splitDown()
|
||||
|
||||
horizontalPanes = containerElement.querySelectorAll('atom-pane-container > atom-pane-axis.horizontal > atom-pane')
|
||||
expect(horizontalPanes.length).toBe 1
|
||||
expect(horizontalPanes[0]).toBe atom.views.getView(pane1)
|
||||
|
||||
verticalPanes = containerElement.querySelectorAll('atom-pane-container > atom-pane-axis.horizontal > atom-pane-axis.vertical > atom-pane')
|
||||
expect(verticalPanes.length).toBe 2
|
||||
expect(verticalPanes[0]).toBe atom.views.getView(pane2)
|
||||
expect(verticalPanes[1]).toBe atom.views.getView(pane3)
|
||||
|
||||
pane1.destroy()
|
||||
verticalPanes = containerElement.querySelectorAll('atom-pane-container > atom-pane-axis.vertical > atom-pane')
|
||||
expect(verticalPanes.length).toBe 2
|
||||
expect(verticalPanes[0]).toBe atom.views.getView(pane2)
|
||||
expect(verticalPanes[1]).toBe atom.views.getView(pane3)
|
||||
|
||||
describe "when the resize element is dragged ", ->
|
||||
[container, containerElement] = []
|
||||
|
||||
@@ -194,3 +230,96 @@ describe "PaneContainerElement", ->
|
||||
atom.commands.dispatch(atom.views.getView(rightPane), 'pane:decrease-size')
|
||||
expect(leftPane.getFlexScale()).toBe 1/1.1
|
||||
expect(rightPane.getFlexScale()).toBe 1/1.1
|
||||
|
||||
describe "changing focus directionally between panes", ->
|
||||
[containerElement, pane1, pane2, pane3, pane4, pane5, pane6, pane7, pane8, pane9] = []
|
||||
|
||||
beforeEach ->
|
||||
# Set up a grid of 9 panes, in the following arrangement, where the
|
||||
# numbers correspond to the variable names below.
|
||||
#
|
||||
# -------
|
||||
# |1|2|3|
|
||||
# -------
|
||||
# |4|5|6|
|
||||
# -------
|
||||
# |7|8|9|
|
||||
# -------
|
||||
|
||||
buildElement = (id) ->
|
||||
element = document.createElement('div')
|
||||
element.textContent = id
|
||||
element.tabIndex = -1
|
||||
element
|
||||
|
||||
container = new PaneContainer
|
||||
pane1 = container.getRoot()
|
||||
pane1.activateItem(buildElement('1'))
|
||||
pane4 = pane1.splitDown(items: [buildElement('4')])
|
||||
pane7 = pane4.splitDown(items: [buildElement('7')])
|
||||
|
||||
pane2 = pane1.splitRight(items: [buildElement('2')])
|
||||
pane3 = pane2.splitRight(items: [buildElement('3')])
|
||||
|
||||
pane5 = pane4.splitRight(items: [buildElement('5')])
|
||||
pane6 = pane5.splitRight(items: [buildElement('6')])
|
||||
|
||||
pane8 = pane7.splitRight(items: [buildElement('8')])
|
||||
pane9 = pane8.splitRight(items: [buildElement('9')])
|
||||
|
||||
containerElement = atom.views.getView(container)
|
||||
containerElement.style.height = '400px'
|
||||
containerElement.style.width = '400px'
|
||||
jasmine.attachToDOM(containerElement)
|
||||
|
||||
describe "::focusPaneViewAbove()", ->
|
||||
describe "when there are multiple rows above the focused pane", ->
|
||||
it "focuses up to the adjacent row", ->
|
||||
pane8.activate()
|
||||
containerElement.focusPaneViewAbove()
|
||||
expect(document.activeElement).toBe pane5.getActiveItem()
|
||||
|
||||
describe "when there are no rows above the focused pane", ->
|
||||
it "keeps the current pane focused", ->
|
||||
pane2.activate()
|
||||
containerElement.focusPaneViewAbove()
|
||||
expect(document.activeElement).toBe pane2.getActiveItem()
|
||||
|
||||
describe "::focusPaneViewBelow()", ->
|
||||
describe "when there are multiple rows below the focused pane", ->
|
||||
it "focuses down to the adjacent row", ->
|
||||
pane2.activate()
|
||||
containerElement.focusPaneViewBelow()
|
||||
expect(document.activeElement).toBe pane5.getActiveItem()
|
||||
|
||||
describe "when there are no rows below the focused pane", ->
|
||||
it "keeps the current pane focused", ->
|
||||
pane8.activate()
|
||||
containerElement.focusPaneViewBelow()
|
||||
expect(document.activeElement).toBe pane8.getActiveItem()
|
||||
|
||||
describe "::focusPaneViewOnLeft()", ->
|
||||
describe "when there are multiple columns to the left of the focused pane", ->
|
||||
it "focuses left to the adjacent column", ->
|
||||
pane6.activate()
|
||||
containerElement.focusPaneViewOnLeft()
|
||||
expect(document.activeElement).toBe pane5.getActiveItem()
|
||||
|
||||
describe "when there are no columns to the left of the focused pane", ->
|
||||
it "keeps the current pane focused", ->
|
||||
pane4.activate()
|
||||
containerElement.focusPaneViewOnLeft()
|
||||
expect(document.activeElement).toBe pane4.getActiveItem()
|
||||
|
||||
describe "::focusPaneViewOnRight()", ->
|
||||
describe "when there are multiple columns to the right of the focused pane", ->
|
||||
it "focuses right to the adjacent column", ->
|
||||
pane4.activate()
|
||||
containerElement.focusPaneViewOnRight()
|
||||
expect(document.activeElement).toBe pane5.getActiveItem()
|
||||
|
||||
describe "when there are no columns to the right of the focused pane", ->
|
||||
it "keeps the current pane focused", ->
|
||||
pane6.activate()
|
||||
containerElement.focusPaneViewOnRight()
|
||||
expect(document.activeElement).toBe pane6.getActiveItem()
|
||||
|
||||
@@ -40,6 +40,32 @@ describe "PaneContainer", ->
|
||||
containerB = atom.deserializers.deserialize(state)
|
||||
expect(containerB.getActivePane()).toBe containerB.getPanes()[0]
|
||||
|
||||
describe "if there are empty panes after deserialization", ->
|
||||
beforeEach ->
|
||||
pane3A.getItems()[0].serialize = -> deserializer: 'Bogus'
|
||||
|
||||
describe "if the 'core.destroyEmptyPanes' config option is false (the default)", ->
|
||||
it "leaves the empty panes intact", ->
|
||||
state = containerA.serialize()
|
||||
containerB = atom.deserializers.deserialize(state)
|
||||
[leftPane, column] = containerB.getRoot().getChildren()
|
||||
[topPane, bottomPane] = column.getChildren()
|
||||
|
||||
expect(leftPane.getItems().length).toBe 1
|
||||
expect(topPane.getItems().length).toBe 1
|
||||
expect(bottomPane.getItems().length).toBe 0
|
||||
|
||||
describe "if the 'core.destroyEmptyPanes' config option is true", ->
|
||||
it "removes empty panes on deserialization", ->
|
||||
atom.config.set('core.destroyEmptyPanes', true)
|
||||
|
||||
state = containerA.serialize()
|
||||
containerB = atom.deserializers.deserialize(state)
|
||||
[leftPane, rightPane] = containerB.getRoot().getChildren()
|
||||
|
||||
expect(leftPane.getItems().length).toBe 1
|
||||
expect(rightPane.getItems().length).toBe 1
|
||||
|
||||
it "does not allow the root pane to be destroyed", ->
|
||||
container = new PaneContainer
|
||||
container.getRoot().destroy()
|
||||
@@ -223,3 +249,19 @@ describe "PaneContainer", ->
|
||||
['will', {item: item2, pane: pane2, index: 0}]
|
||||
['did', {item: item2, pane: pane2, index: 0}]
|
||||
]
|
||||
|
||||
describe "::saveAll()", ->
|
||||
it "saves all open pane items", ->
|
||||
container = new PaneContainer
|
||||
pane1 = container.getRoot()
|
||||
pane2 = pane1.splitRight()
|
||||
|
||||
pane1.addItem(item1 = {getURI: (-> ''), save: -> @saved = true})
|
||||
pane1.addItem(item2 = {getURI: (-> ''), save: -> @saved = true})
|
||||
pane2.addItem(item3 = {getURI: (-> ''), save: -> @saved = true})
|
||||
|
||||
container.saveAll()
|
||||
|
||||
expect(item1.saved).toBe true
|
||||
expect(item2.saved).toBe true
|
||||
expect(item3.saved).toBe true
|
||||
|
||||
@@ -1,334 +0,0 @@
|
||||
path = require 'path'
|
||||
temp = require 'temp'
|
||||
PaneContainer = require '../src/pane-container'
|
||||
PaneContainerView = require '../src/pane-container-view'
|
||||
PaneView = require '../src/pane-view'
|
||||
{Disposable} = require 'event-kit'
|
||||
{$, View, $$} = require '../src/space-pen-extensions'
|
||||
|
||||
describe "PaneContainerView", ->
|
||||
[TestView, container, pane1, pane2, pane3, deserializerDisposable] = []
|
||||
|
||||
beforeEach ->
|
||||
class TestView extends View
|
||||
deserializerDisposable = atom.deserializers.add(this)
|
||||
@deserialize: ({name}) -> new TestView(name)
|
||||
@content: -> @div tabindex: -1
|
||||
initialize: (@name) -> @text(@name)
|
||||
serialize: -> {deserializer: 'TestView', @name}
|
||||
getURI: -> path.join(temp.dir, @name)
|
||||
save: -> @saved = true
|
||||
isEqual: (other) -> @name is other?.name
|
||||
onDidChangeTitle: -> new Disposable(->)
|
||||
onDidChangeModified: -> new Disposable(->)
|
||||
|
||||
container = atom.views.getView(atom.workspace.paneContainer).__spacePenView
|
||||
pane1 = container.getRoot()
|
||||
pane1.activateItem(new TestView('1'))
|
||||
pane2 = pane1.splitRight(new TestView('2'))
|
||||
pane3 = pane2.splitDown(new TestView('3'))
|
||||
|
||||
afterEach ->
|
||||
deserializerDisposable.dispose()
|
||||
|
||||
describe ".getActivePaneView()", ->
|
||||
it "returns the most-recently focused pane", ->
|
||||
focusStealer = $$ -> @div tabindex: -1, "focus stealer"
|
||||
focusStealer.attachToDom()
|
||||
container.attachToDom()
|
||||
|
||||
pane2.focus()
|
||||
expect(container.getFocusedPane()).toBe pane2
|
||||
expect(container.getActivePaneView()).toBe pane2
|
||||
|
||||
focusStealer.focus()
|
||||
expect(container.getFocusedPane()).toBeUndefined()
|
||||
expect(container.getActivePaneView()).toBe pane2
|
||||
|
||||
pane3.focus()
|
||||
expect(container.getFocusedPane()).toBe pane3
|
||||
expect(container.getActivePaneView()).toBe pane3
|
||||
|
||||
describe ".eachPaneView(callback)", ->
|
||||
it "runs the callback with all current and future panes until the subscription is cancelled", ->
|
||||
panes = []
|
||||
subscription = container.eachPaneView (pane) -> panes.push(pane)
|
||||
expect(panes).toEqual [pane1, pane2, pane3]
|
||||
|
||||
panes = []
|
||||
pane4 = pane3.splitRight(pane3.copyActiveItem())
|
||||
expect(panes).toEqual [pane4]
|
||||
|
||||
panes = []
|
||||
subscription.off()
|
||||
pane4.splitDown()
|
||||
expect(panes).toEqual []
|
||||
|
||||
describe ".saveAll()", ->
|
||||
it "saves all open pane items", ->
|
||||
pane1.activateItem(new TestView('4'))
|
||||
|
||||
container.saveAll()
|
||||
|
||||
for pane in container.getPaneViews()
|
||||
for item in pane.getItems()
|
||||
expect(item.saved).toBeTruthy()
|
||||
|
||||
describe "serialization", ->
|
||||
it "can be serialized and deserialized, and correctly adjusts dimensions of deserialized panes after attach", ->
|
||||
newContainer = atom.views.getView(container.model.testSerialization()).__spacePenView
|
||||
expect(newContainer.find('atom-pane-axis.horizontal > :contains(1)')).toExist()
|
||||
expect(newContainer.find('atom-pane-axis.horizontal > atom-pane-axis.vertical > :contains(2)')).toExist()
|
||||
expect(newContainer.find('atom-pane-axis.horizontal > atom-pane-axis.vertical > :contains(3)')).toExist()
|
||||
|
||||
newContainer.height(200).width(300).attachToDom()
|
||||
expect(newContainer.find('atom-pane-axis.horizontal > :contains(1)').width()).toBe 150
|
||||
expect(newContainer.find('atom-pane-axis.horizontal > atom-pane-axis.vertical > :contains(2)').height()).toBe 100
|
||||
|
||||
describe "if there are empty panes after deserialization", ->
|
||||
beforeEach ->
|
||||
# only deserialize pane 1's view successfully
|
||||
TestView.deserialize = ({name}) -> new TestView(name) if name is '1'
|
||||
|
||||
describe "if the 'core.destroyEmptyPanes' config option is false (the default)", ->
|
||||
it "leaves the empty panes intact", ->
|
||||
newContainer = atom.views.getView(container.model.testSerialization()).__spacePenView
|
||||
expect(newContainer.find('atom-pane-axis.horizontal > :contains(1)')).toExist()
|
||||
expect(newContainer.find('atom-pane-axis.horizontal > atom-pane-axis.vertical > atom-pane').length).toBe 2
|
||||
|
||||
describe "if the 'core.destroyEmptyPanes' config option is true", ->
|
||||
it "removes empty panes on deserialization", ->
|
||||
atom.config.set('core.destroyEmptyPanes', true)
|
||||
newContainer = atom.views.getView(container.model.testSerialization()).__spacePenView
|
||||
expect(newContainer.find('atom-pane-axis.horizontal, atom-pane-axis.vertical')).not.toExist()
|
||||
expect(newContainer.find('> :contains(1)')).toExist()
|
||||
|
||||
describe "pane-container:active-pane-item-changed", ->
|
||||
[pane1, item1a, item1b, item2a, item2b, item3a, container, activeItemChangedHandler] = []
|
||||
beforeEach ->
|
||||
item1a = new TestView('1a')
|
||||
item1b = new TestView('1b')
|
||||
item2a = new TestView('2a')
|
||||
item2b = new TestView('2b')
|
||||
item3a = new TestView('3a')
|
||||
|
||||
container = atom.views.getView(new PaneContainer).__spacePenView
|
||||
pane1 = container.getRoot()
|
||||
pane1.activateItem(item1a)
|
||||
container.attachToDom()
|
||||
|
||||
activeItemChangedHandler = jasmine.createSpy("activeItemChangedHandler")
|
||||
container.on 'pane-container:active-pane-item-changed', activeItemChangedHandler
|
||||
|
||||
describe "when there is one pane", ->
|
||||
it "is triggered when a new pane item is added", ->
|
||||
pane1.activateItem(item1b)
|
||||
expect(activeItemChangedHandler.callCount).toBe 1
|
||||
expect(activeItemChangedHandler.argsForCall[0][1]).toEqual item1b
|
||||
|
||||
it "is not triggered when the active pane item is shown again", ->
|
||||
pane1.activateItem(item1a)
|
||||
expect(activeItemChangedHandler).not.toHaveBeenCalled()
|
||||
|
||||
it "is triggered when switching to an existing pane item", ->
|
||||
pane1.activateItem(item1b)
|
||||
activeItemChangedHandler.reset()
|
||||
|
||||
pane1.activateItem(item1a)
|
||||
expect(activeItemChangedHandler.callCount).toBe 1
|
||||
expect(activeItemChangedHandler.argsForCall[0][1]).toEqual item1a
|
||||
|
||||
it "is triggered when the active pane item is destroyed", ->
|
||||
pane1.activateItem(item1b)
|
||||
activeItemChangedHandler.reset()
|
||||
|
||||
pane1.destroyItem(item1b)
|
||||
expect(activeItemChangedHandler.callCount).toBe 1
|
||||
expect(activeItemChangedHandler.argsForCall[0][1]).toEqual item1a
|
||||
|
||||
it "is not triggered when an inactive pane item is destroyed", ->
|
||||
pane1.activateItem(item1b)
|
||||
activeItemChangedHandler.reset()
|
||||
|
||||
pane1.destroyItem(item1a)
|
||||
expect(activeItemChangedHandler).not.toHaveBeenCalled()
|
||||
|
||||
it "is triggered when all pane items are destroyed", ->
|
||||
pane1.destroyItem(item1a)
|
||||
expect(activeItemChangedHandler.callCount).toBe 1
|
||||
expect(activeItemChangedHandler.argsForCall[0][1]).toBe undefined
|
||||
|
||||
describe "when there are two panes", ->
|
||||
[pane2] = []
|
||||
|
||||
beforeEach ->
|
||||
pane2 = pane1.splitLeft(item2a)
|
||||
activeItemChangedHandler.reset()
|
||||
|
||||
it "is triggered when a new pane item is added to the active pane", ->
|
||||
pane2.activateItem(item2b)
|
||||
expect(activeItemChangedHandler.callCount).toBe 1
|
||||
expect(activeItemChangedHandler.argsForCall[0][1]).toEqual item2b
|
||||
|
||||
it "is not triggered when a new pane item is added to an inactive pane", ->
|
||||
pane1.activateItem(item1b)
|
||||
expect(activeItemChangedHandler).not.toHaveBeenCalled()
|
||||
|
||||
it "is triggered when the active pane's active item is destroyed", ->
|
||||
pane2.activateItem(item2b)
|
||||
activeItemChangedHandler.reset()
|
||||
|
||||
pane2.destroyItem(item2b)
|
||||
expect(activeItemChangedHandler.callCount).toBe 1
|
||||
expect(activeItemChangedHandler.argsForCall[0][1]).toEqual item2a
|
||||
|
||||
it "is not triggered when an inactive pane's active item is destroyed", ->
|
||||
pane1.activateItem(item1b)
|
||||
activeItemChangedHandler.reset()
|
||||
|
||||
pane1.destroyItem(item1b)
|
||||
expect(activeItemChangedHandler).not.toHaveBeenCalled()
|
||||
|
||||
it "is triggered when the active pane is destroyed", ->
|
||||
pane2.remove()
|
||||
expect(activeItemChangedHandler.callCount).toBe 1
|
||||
expect(activeItemChangedHandler.argsForCall[0][1]).toEqual item1a
|
||||
|
||||
it "is not triggered when an inactive pane is destroyed", ->
|
||||
pane1.remove()
|
||||
expect(activeItemChangedHandler).not.toHaveBeenCalled()
|
||||
|
||||
it "is triggered when the active pane is changed", ->
|
||||
pane1.activate()
|
||||
expect(activeItemChangedHandler.callCount).toBe 1
|
||||
expect(activeItemChangedHandler.argsForCall[0][1]).toEqual item1a
|
||||
|
||||
describe "when there are multiple panes", ->
|
||||
beforeEach ->
|
||||
pane2 = pane1.splitRight(item2a)
|
||||
activeItemChangedHandler.reset()
|
||||
|
||||
it "is triggered when a new pane is added", ->
|
||||
pane2.splitDown(item3a)
|
||||
expect(activeItemChangedHandler.callCount).toBe 1
|
||||
expect(activeItemChangedHandler.argsForCall[0][1]).toEqual item3a
|
||||
|
||||
it "is not triggered when an inactive pane is destroyed", ->
|
||||
pane3 = pane2.splitDown(item3a)
|
||||
activeItemChangedHandler.reset()
|
||||
|
||||
pane1.remove()
|
||||
pane2.remove()
|
||||
expect(activeItemChangedHandler).not.toHaveBeenCalled()
|
||||
|
||||
describe ".focusNextPaneView()", ->
|
||||
it "focuses the pane following the focused pane or the first pane if no pane has focus", ->
|
||||
container.attachToDom()
|
||||
container.focusNextPaneView()
|
||||
expect(pane1.activeItem).toMatchSelector ':focus'
|
||||
container.focusNextPaneView()
|
||||
expect(pane2.activeItem).toMatchSelector ':focus'
|
||||
container.focusNextPaneView()
|
||||
expect(pane3.activeItem).toMatchSelector ':focus'
|
||||
container.focusNextPaneView()
|
||||
expect(pane1.activeItem).toMatchSelector ':focus'
|
||||
|
||||
describe ".focusPreviousPaneView()", ->
|
||||
it "focuses the pane preceding the focused pane or the last pane if no pane has focus", ->
|
||||
container.attachToDom()
|
||||
container.getPaneViews()[0].focus() # activate first pane
|
||||
|
||||
container.focusPreviousPaneView()
|
||||
expect(pane3.activeItem).toMatchSelector ':focus'
|
||||
container.focusPreviousPaneView()
|
||||
expect(pane2.activeItem).toMatchSelector ':focus'
|
||||
container.focusPreviousPaneView()
|
||||
expect(pane1.activeItem).toMatchSelector ':focus'
|
||||
container.focusPreviousPaneView()
|
||||
expect(pane3.activeItem).toMatchSelector ':focus'
|
||||
|
||||
describe "changing focus directionally between panes", ->
|
||||
[pane1, pane2, pane3, pane4, pane5, pane6, pane7, pane8, pane9] = []
|
||||
|
||||
beforeEach ->
|
||||
# Set up a grid of 9 panes, in the following arrangement, where the
|
||||
# numbers correspond to the variable names below.
|
||||
#
|
||||
# -------
|
||||
# |1|2|3|
|
||||
# -------
|
||||
# |4|5|6|
|
||||
# -------
|
||||
# |7|8|9|
|
||||
# -------
|
||||
|
||||
container = atom.views.getView(new PaneContainer).__spacePenView
|
||||
pane1 = container.getRoot()
|
||||
pane1.activateItem(new TestView('1'))
|
||||
pane4 = pane1.splitDown(new TestView('4'))
|
||||
pane7 = pane4.splitDown(new TestView('7'))
|
||||
|
||||
pane2 = pane1.splitRight(new TestView('2'))
|
||||
pane3 = pane2.splitRight(new TestView('3'))
|
||||
|
||||
pane5 = pane4.splitRight(new TestView('5'))
|
||||
pane6 = pane5.splitRight(new TestView('6'))
|
||||
|
||||
pane8 = pane7.splitRight(new TestView('8'))
|
||||
pane9 = pane8.splitRight(new TestView('9'))
|
||||
|
||||
container.height(400)
|
||||
container.width(400)
|
||||
container.attachToDom()
|
||||
|
||||
describe ".focusPaneViewAbove()", ->
|
||||
describe "when there are multiple rows above the focused pane", ->
|
||||
it "focuses up to the adjacent row", ->
|
||||
pane8.focus()
|
||||
container.focusPaneViewAbove()
|
||||
expect(pane5.activeItem).toMatchSelector ':focus'
|
||||
|
||||
describe "when there are no rows above the focused pane", ->
|
||||
it "keeps the current pane focused", ->
|
||||
pane2.focus()
|
||||
container.focusPaneViewAbove()
|
||||
expect(pane2.activeItem).toMatchSelector ':focus'
|
||||
|
||||
describe ".focusPaneViewBelow()", ->
|
||||
describe "when there are multiple rows below the focused pane", ->
|
||||
it "focuses down to the adjacent row", ->
|
||||
pane2.focus()
|
||||
container.focusPaneViewBelow()
|
||||
expect(pane5.activeItem).toMatchSelector ':focus'
|
||||
|
||||
describe "when there are no rows below the focused pane", ->
|
||||
it "keeps the current pane focused", ->
|
||||
pane8.focus()
|
||||
container.focusPaneViewBelow()
|
||||
expect(pane8.activeItem).toMatchSelector ':focus'
|
||||
|
||||
describe ".focusPaneViewOnLeft()", ->
|
||||
describe "when there are multiple columns to the left of the focused pane", ->
|
||||
it "focuses left to the adjacent column", ->
|
||||
pane6.focus()
|
||||
container.focusPaneViewOnLeft()
|
||||
expect(pane5.activeItem).toMatchSelector ':focus'
|
||||
|
||||
describe "when there are no columns to the left of the focused pane", ->
|
||||
it "keeps the current pane focused", ->
|
||||
pane4.focus()
|
||||
container.focusPaneViewOnLeft()
|
||||
expect(pane4.activeItem).toMatchSelector ':focus'
|
||||
|
||||
describe ".focusPaneViewOnRight()", ->
|
||||
describe "when there are multiple columns to the right of the focused pane", ->
|
||||
it "focuses right to the adjacent column", ->
|
||||
pane4.focus()
|
||||
container.focusPaneViewOnRight()
|
||||
expect(pane5.activeItem).toMatchSelector ':focus'
|
||||
|
||||
describe "when there are no columns to the right of the focused pane", ->
|
||||
it "keeps the current pane focused", ->
|
||||
pane6.focus()
|
||||
container.focusPaneViewOnRight()
|
||||
expect(pane6.activeItem).toMatchSelector ':focus'
|
||||
197
spec/pane-element-spec.coffee
Normal file
197
spec/pane-element-spec.coffee
Normal file
@@ -0,0 +1,197 @@
|
||||
PaneContainer = require '../src/pane-container'
|
||||
|
||||
describe "PaneElement", ->
|
||||
[paneElement, container, pane] = []
|
||||
|
||||
beforeEach ->
|
||||
container = new PaneContainer
|
||||
pane = container.getRoot()
|
||||
paneElement = atom.views.getView(pane)
|
||||
|
||||
describe "when the pane's active status changes", ->
|
||||
it "adds or removes the .active class as appropriate", ->
|
||||
pane2 = pane.splitRight()
|
||||
expect(pane2.isActive()).toBe true
|
||||
|
||||
expect(paneElement.className).not.toMatch /active/
|
||||
pane.activate()
|
||||
expect(paneElement.className).toMatch /active/
|
||||
pane2.activate()
|
||||
expect(paneElement.className).not.toMatch /active/
|
||||
|
||||
describe "when the active item changes", ->
|
||||
it "hides all item elements except the active one", ->
|
||||
item1 = document.createElement('div')
|
||||
item2 = document.createElement('div')
|
||||
item3 = document.createElement('div')
|
||||
pane.addItem(item1)
|
||||
pane.addItem(item2)
|
||||
pane.addItem(item3)
|
||||
|
||||
expect(pane.getActiveItem()).toBe item1
|
||||
expect(item1.parentElement).toBeDefined()
|
||||
expect(item1.style.display).toBe ''
|
||||
expect(item2.parentElement).toBeNull()
|
||||
expect(item3.parentElement).toBeNull()
|
||||
|
||||
pane.activateItem(item2)
|
||||
expect(item2.parentElement).toBeDefined()
|
||||
expect(item1.style.display).toBe 'none'
|
||||
expect(item2.style.display).toBe ''
|
||||
expect(item3.parentElement).toBeNull()
|
||||
|
||||
pane.activateItem(item3)
|
||||
expect(item3.parentElement).toBeDefined()
|
||||
expect(item1.style.display).toBe 'none'
|
||||
expect(item2.style.display).toBe 'none'
|
||||
expect(item3.style.display).toBe ''
|
||||
|
||||
it "transfers focus to the new item if the previous item was focused", ->
|
||||
item1 = document.createElement('div')
|
||||
item1.tabIndex = -1
|
||||
item2 = document.createElement('div')
|
||||
item2.tabIndex = -1
|
||||
pane.addItem(item1)
|
||||
pane.addItem(item2)
|
||||
jasmine.attachToDOM(paneElement)
|
||||
paneElement.focus()
|
||||
|
||||
expect(document.activeElement).toBe item1
|
||||
pane.activateItem(item2)
|
||||
expect(document.activeElement).toBe item2
|
||||
|
||||
describe "if the active item is a model object", ->
|
||||
it "retrieves the associated view from atom.views and appends it to the itemViews div", ->
|
||||
class TestModel
|
||||
|
||||
atom.views.addViewProvider TestModel, (model) ->
|
||||
view = document.createElement('div')
|
||||
view.model = model
|
||||
view
|
||||
|
||||
item1 = new TestModel
|
||||
item2 = new TestModel
|
||||
pane.addItem(item1)
|
||||
pane.addItem(item2)
|
||||
|
||||
expect(paneElement.itemViews.children[0].model).toBe item1
|
||||
expect(paneElement.itemViews.children[0].style.display).toBe ''
|
||||
pane.activateItem(item2)
|
||||
expect(paneElement.itemViews.children[1].model).toBe item2
|
||||
expect(paneElement.itemViews.children[0].style.display).toBe 'none'
|
||||
expect(paneElement.itemViews.children[1].style.display).toBe ''
|
||||
|
||||
describe "when the new active implements .getPath()", ->
|
||||
it "adds the file path and file name as a data attribute on the pane", ->
|
||||
item1 = document.createElement('div')
|
||||
item1.getPath = -> '/foo/bar.txt'
|
||||
item2 = document.createElement('div')
|
||||
pane.addItem(item1)
|
||||
pane.addItem(item2)
|
||||
|
||||
expect(paneElement.dataset.activeItemPath).toBe '/foo/bar.txt'
|
||||
expect(paneElement.dataset.activeItemName).toBe 'bar.txt'
|
||||
|
||||
pane.activateItem(item2)
|
||||
|
||||
expect(paneElement.dataset.activeItemPath).toBeUndefined()
|
||||
expect(paneElement.dataset.activeItemName).toBeUndefined()
|
||||
|
||||
pane.activateItem(item1)
|
||||
expect(paneElement.dataset.activeItemPath).toBe '/foo/bar.txt'
|
||||
expect(paneElement.dataset.activeItemName).toBe 'bar.txt'
|
||||
|
||||
pane.destroyItems()
|
||||
expect(paneElement.dataset.activeItemPath).toBeUndefined()
|
||||
expect(paneElement.dataset.activeItemName).toBeUndefined()
|
||||
|
||||
describe "when an item is removed from the pane", ->
|
||||
describe "when the destroyed item is an element", ->
|
||||
it "removes the item from the itemViews div", ->
|
||||
item1 = document.createElement('div')
|
||||
item2 = document.createElement('div')
|
||||
pane.addItem(item1)
|
||||
pane.addItem(item2)
|
||||
paneElement = atom.views.getView(pane)
|
||||
|
||||
expect(item1.parentElement).toBe paneElement.itemViews
|
||||
pane.destroyItem(item1)
|
||||
expect(item1.parentElement).toBeNull()
|
||||
expect(item2.parentElement).toBe paneElement.itemViews
|
||||
pane.destroyItem(item2)
|
||||
expect(item2.parentElement).toBeNull()
|
||||
|
||||
describe "when the destroyed item is a model", ->
|
||||
it "removes the model's associated view", ->
|
||||
class TestModel
|
||||
|
||||
atom.views.addViewProvider TestModel, (model) ->
|
||||
view = document.createElement('div')
|
||||
model.element = view
|
||||
view.model = model
|
||||
view
|
||||
|
||||
item1 = new TestModel
|
||||
item2 = new TestModel
|
||||
pane.addItem(item1)
|
||||
pane.addItem(item2)
|
||||
|
||||
expect(item1.element.parentElement).toBe paneElement.itemViews
|
||||
pane.destroyItem(item1)
|
||||
expect(item1.element.parentElement).toBeNull()
|
||||
expect(item2.element.parentElement).toBe paneElement.itemViews
|
||||
pane.destroyItem(item2)
|
||||
expect(item2.element.parentElement).toBeNull()
|
||||
|
||||
describe "when the pane element is focused", ->
|
||||
it "transfers focus to the active view", ->
|
||||
item = document.createElement('div')
|
||||
item.tabIndex = -1
|
||||
pane.activateItem(item)
|
||||
jasmine.attachToDOM(paneElement)
|
||||
|
||||
expect(document.activeElement).toBe document.body
|
||||
paneElement.focus()
|
||||
expect(document.activeElement).toBe item
|
||||
|
||||
it "makes the pane active", ->
|
||||
pane.splitRight()
|
||||
expect(pane.isActive()).toBe false
|
||||
|
||||
jasmine.attachToDOM(paneElement)
|
||||
paneElement.focus()
|
||||
|
||||
expect(pane.isActive()).toBe true
|
||||
|
||||
describe "when the pane element is attached", ->
|
||||
it "focuses the pane element if isFocused() returns true on its model", ->
|
||||
pane.focus()
|
||||
jasmine.attachToDOM(paneElement)
|
||||
expect(document.activeElement).toBe paneElement
|
||||
|
||||
describe "drag and drop", ->
|
||||
buildDragEvent = (type, files) ->
|
||||
dataTransfer =
|
||||
files: files
|
||||
data: {}
|
||||
setData: (key, value) -> @data[key] = value
|
||||
getData: (key) -> @data[key]
|
||||
|
||||
event = new CustomEvent("drop")
|
||||
event.dataTransfer = dataTransfer
|
||||
event
|
||||
|
||||
describe "when a file is dragged to the pane", ->
|
||||
it "opens it", ->
|
||||
spyOn(atom, "open")
|
||||
event = buildDragEvent("drop", [{path: "/fake1"}, {path: "/fake2"}])
|
||||
paneElement.dispatchEvent(event)
|
||||
expect(atom.open.callCount).toBe 1
|
||||
expect(atom.open.argsForCall[0][0]).toEqual pathsToOpen: ['/fake1', '/fake2']
|
||||
|
||||
describe "when a non-file is dragged to the pane", ->
|
||||
it "does nothing", ->
|
||||
spyOn(atom, "open")
|
||||
event = buildDragEvent("drop", [])
|
||||
paneElement.dispatchEvent(event)
|
||||
expect(atom.open).not.toHaveBeenCalled()
|
||||
@@ -1,389 +0,0 @@
|
||||
PaneContainer = require '../src/pane-container'
|
||||
PaneView = require '../src/pane-view'
|
||||
fs = require 'fs-plus'
|
||||
{Emitter, Disposable} = require 'event-kit'
|
||||
{$, View} = require '../src/space-pen-extensions'
|
||||
path = require 'path'
|
||||
temp = require 'temp'
|
||||
|
||||
describe "PaneView", ->
|
||||
[container, containerModel, view1, view2, editor1, editor2, pane, paneModel, deserializerDisposable] = []
|
||||
|
||||
class TestView extends View
|
||||
@deserialize: ({id, text}) -> new TestView({id, text})
|
||||
@content: ({id, text}) -> @div class: 'test-view', id: id, tabindex: -1, text
|
||||
initialize: ({@id, @text}) ->
|
||||
@emitter = new Emitter
|
||||
serialize: -> {deserializer: 'TestView', @id, @text}
|
||||
getURI: -> @id
|
||||
isEqual: (other) -> other? and @id is other.id and @text is other.text
|
||||
changeTitle: ->
|
||||
@emitter.emit 'did-change-title', 'title'
|
||||
onDidChangeTitle: (callback) ->
|
||||
@emitter.on 'did-change-title', callback
|
||||
onDidChangeModified: -> new Disposable(->)
|
||||
|
||||
beforeEach ->
|
||||
jasmine.snapshotDeprecations()
|
||||
|
||||
deserializerDisposable = atom.deserializers.add(TestView)
|
||||
container = atom.views.getView(new PaneContainer).__spacePenView
|
||||
containerModel = container.model
|
||||
view1 = new TestView(id: 'view-1', text: 'View 1')
|
||||
view2 = new TestView(id: 'view-2', text: 'View 2')
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('sample.js').then (o) -> editor1 = o
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('sample.txt').then (o) -> editor2 = o
|
||||
|
||||
runs ->
|
||||
pane = container.getRoot()
|
||||
paneModel = pane.getModel()
|
||||
paneModel.addItems([view1, editor1, view2, editor2])
|
||||
|
||||
afterEach ->
|
||||
deserializerDisposable.dispose()
|
||||
jasmine.restoreDeprecationsSnapshot()
|
||||
|
||||
describe "when the active pane item changes", ->
|
||||
it "hides all item views except the active one", ->
|
||||
expect(pane.getActiveItem()).toBe view1
|
||||
expect(view1.css('display')).not.toBe 'none'
|
||||
|
||||
pane.activateItem(view2)
|
||||
expect(view1.css('display')).toBe 'none'
|
||||
expect(view2.css('display')).not.toBe 'none'
|
||||
|
||||
it "triggers 'pane:active-item-changed'", ->
|
||||
itemChangedHandler = jasmine.createSpy("itemChangedHandler")
|
||||
container.on 'pane:active-item-changed', itemChangedHandler
|
||||
|
||||
expect(pane.getActiveItem()).toBe view1
|
||||
paneModel.activateItem(view2)
|
||||
paneModel.activateItem(view2)
|
||||
|
||||
expect(itemChangedHandler.callCount).toBe 1
|
||||
expect(itemChangedHandler.argsForCall[0][1]).toBe view2
|
||||
itemChangedHandler.reset()
|
||||
|
||||
paneModel.activateItem(editor1)
|
||||
expect(itemChangedHandler).toHaveBeenCalled()
|
||||
expect(itemChangedHandler.argsForCall[0][1]).toBe editor1
|
||||
itemChangedHandler.reset()
|
||||
|
||||
it "transfers focus to the new active view if the previous view was focused", ->
|
||||
container.attachToDom()
|
||||
pane.focus()
|
||||
expect(pane.activeView).not.toBe view2
|
||||
expect(pane.activeView).toMatchSelector ':focus'
|
||||
paneModel.activateItem(view2)
|
||||
expect(view2).toMatchSelector ':focus'
|
||||
|
||||
describe "when the new activeItem is a model", ->
|
||||
it "shows the item's view or creates and shows a new view for the item if none exists", ->
|
||||
initialViewCount = pane.itemViews.find('.test-view').length
|
||||
|
||||
model1 =
|
||||
id: 'test-model-1'
|
||||
text: 'Test Model 1'
|
||||
serialize: -> {@id, @text}
|
||||
getViewClass: -> TestView
|
||||
|
||||
model2 =
|
||||
id: 'test-model-2'
|
||||
text: 'Test Model 2'
|
||||
serialize: -> {@id, @text}
|
||||
getViewClass: -> TestView
|
||||
|
||||
paneModel.activateItem(model1)
|
||||
paneModel.activateItem(model2)
|
||||
expect(pane.itemViews.find('.test-view').length).toBe initialViewCount + 2
|
||||
|
||||
paneModel.activatePreviousItem()
|
||||
expect(pane.itemViews.find('.test-view').length).toBe initialViewCount + 2
|
||||
|
||||
paneModel.destroyItem(model2)
|
||||
expect(pane.itemViews.find('.test-view').length).toBe initialViewCount + 1
|
||||
|
||||
paneModel.destroyItem(model1)
|
||||
expect(pane.itemViews.find('.test-view').length).toBe initialViewCount
|
||||
|
||||
describe "when the new activeItem is a view", ->
|
||||
it "appends it to the itemViews div if it hasn't already been appended and shows it", ->
|
||||
expect(pane.itemViews.find('#view-2')).not.toExist()
|
||||
paneModel.activateItem(view2)
|
||||
expect(pane.itemViews.find('#view-2')).toExist()
|
||||
paneModel.activateItem(view1)
|
||||
paneModel.activateItem(view2)
|
||||
expect(pane.itemViews.find('#view-2').length).toBe 1
|
||||
|
||||
describe "when the new activeItem implements ::getPath", ->
|
||||
beforeEach ->
|
||||
paneModel.activateItem(editor1)
|
||||
|
||||
it "adds the file path as a data attribute to the pane", ->
|
||||
expect(pane).toHaveAttr('data-active-item-path')
|
||||
|
||||
it "adds the file name as a data attribute to the pane", ->
|
||||
expect(pane).toHaveAttr('data-active-item-name')
|
||||
|
||||
describe "when the activeItem is destroyed", ->
|
||||
it "removes the data attributes", ->
|
||||
pane.destroyItems()
|
||||
expect(pane).not.toHaveAttr('data-active-item-path')
|
||||
expect(pane).not.toHaveAttr('data-active-item-name')
|
||||
|
||||
describe "when the new activeItem does not implement ::getPath", ->
|
||||
beforeEach ->
|
||||
paneModel.activateItem(editor1)
|
||||
paneModel.activateItem(document.createElement('div'))
|
||||
|
||||
it "does not add the file path as a data attribute to the pane", ->
|
||||
expect(pane).not.toHaveAttr('data-active-item-path')
|
||||
|
||||
it "does not add the file name as data attribute to the pane", ->
|
||||
expect(pane).not.toHaveAttr('data-active-item-name')
|
||||
|
||||
describe "when an item is destroyed", ->
|
||||
it "triggers the 'pane:item-removed' event with the item and its former index", ->
|
||||
itemRemovedHandler = jasmine.createSpy("itemRemovedHandler")
|
||||
pane.on 'pane:item-removed', itemRemovedHandler
|
||||
paneModel.destroyItem(editor1)
|
||||
expect(itemRemovedHandler).toHaveBeenCalled()
|
||||
expect(itemRemovedHandler.argsForCall[0][1..2]).toEqual [editor1, 1]
|
||||
|
||||
describe "when the destroyed item is a view", ->
|
||||
it "removes the item from the 'item-views' div", ->
|
||||
expect(view1.parent()).toMatchSelector pane.itemViews
|
||||
paneModel.destroyItem(view1)
|
||||
expect(view1.parent()).not.toMatchSelector pane.itemViews
|
||||
|
||||
describe "when the destroyed item is a model", ->
|
||||
it "removes the associated view", ->
|
||||
paneModel.activateItem(editor1)
|
||||
expect(pane.itemViews.find('atom-text-editor').length).toBe 1
|
||||
pane.destroyItem(editor1)
|
||||
expect(pane.itemViews.find('atom-text-editor').length).toBe 0
|
||||
|
||||
describe "when an item is moved within the same pane", ->
|
||||
it "emits a 'pane:item-moved' event with the item and the new index", ->
|
||||
pane.on 'pane:item-moved', itemMovedHandler = jasmine.createSpy("itemMovedHandler")
|
||||
paneModel.moveItem(view1, 2)
|
||||
expect(itemMovedHandler).toHaveBeenCalled()
|
||||
expect(itemMovedHandler.argsForCall[0][1..2]).toEqual [view1, 2]
|
||||
|
||||
describe "when an item is moved to another pane", ->
|
||||
it "detaches the item's view rather than removing it", ->
|
||||
container.attachToDom()
|
||||
expect(view1.is(':visible')).toBe true
|
||||
paneModel2 = paneModel.splitRight()
|
||||
view1.data('preservative', 1234)
|
||||
paneModel.moveItemToPane(view1, paneModel2, 1)
|
||||
expect(view1.data('preservative')).toBe 1234
|
||||
paneModel2.activateItemAtIndex(1)
|
||||
expect(view1.data('preservative')).toBe 1234
|
||||
expect(view1.is(':visible')).toBe true
|
||||
|
||||
describe "when the title of the active item changes", ->
|
||||
describe 'when there is no onDidChangeTitle method (deprecated)', ->
|
||||
beforeEach ->
|
||||
jasmine.snapshotDeprecations()
|
||||
|
||||
view1.onDidChangeTitle = null
|
||||
view2.onDidChangeTitle = null
|
||||
|
||||
pane.activateItem(view2)
|
||||
pane.activateItem(view1)
|
||||
|
||||
afterEach ->
|
||||
jasmine.restoreDeprecationsSnapshot()
|
||||
|
||||
it "emits pane:active-item-title-changed", ->
|
||||
activeItemTitleChangedHandler = jasmine.createSpy("activeItemTitleChangedHandler")
|
||||
pane.on 'pane:active-item-title-changed', activeItemTitleChangedHandler
|
||||
|
||||
expect(pane.getActiveItem()).toBe view1
|
||||
|
||||
view2.trigger 'title-changed'
|
||||
expect(activeItemTitleChangedHandler).not.toHaveBeenCalled()
|
||||
|
||||
view1.trigger 'title-changed'
|
||||
expect(activeItemTitleChangedHandler).toHaveBeenCalled()
|
||||
activeItemTitleChangedHandler.reset()
|
||||
|
||||
pane.activateItem(view2)
|
||||
view2.trigger 'title-changed'
|
||||
expect(activeItemTitleChangedHandler).toHaveBeenCalled()
|
||||
|
||||
describe 'when there is a onDidChangeTitle method', ->
|
||||
it "emits pane:active-item-title-changed", ->
|
||||
activeItemTitleChangedHandler = jasmine.createSpy("activeItemTitleChangedHandler")
|
||||
pane.on 'pane:active-item-title-changed', activeItemTitleChangedHandler
|
||||
|
||||
expect(pane.getActiveItem()).toBe view1
|
||||
view2.changeTitle()
|
||||
expect(activeItemTitleChangedHandler).not.toHaveBeenCalled()
|
||||
|
||||
view1.changeTitle()
|
||||
expect(activeItemTitleChangedHandler).toHaveBeenCalled()
|
||||
activeItemTitleChangedHandler.reset()
|
||||
|
||||
pane.activateItem(view2)
|
||||
view2.changeTitle()
|
||||
expect(activeItemTitleChangedHandler).toHaveBeenCalled()
|
||||
|
||||
describe "when an unmodifed buffer's path is deleted", ->
|
||||
it "removes the pane item", ->
|
||||
editor = null
|
||||
jasmine.unspy(window, 'setTimeout')
|
||||
filePath = path.join(temp.mkdirSync(), 'file.txt')
|
||||
fs.writeFileSync(filePath, '')
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.open(filePath).then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
pane.activateItem(editor)
|
||||
expect(pane.items).toHaveLength(5)
|
||||
fs.removeSync(filePath)
|
||||
|
||||
waitsFor ->
|
||||
pane.items.length is 4
|
||||
|
||||
describe "when a pane is destroyed", ->
|
||||
[pane2, pane2Model] = []
|
||||
|
||||
beforeEach ->
|
||||
pane2Model = paneModel.splitRight() # Can't destroy the last pane, so we add another
|
||||
pane2 = atom.views.getView(pane2Model).__spacePenView
|
||||
|
||||
it "triggers a 'pane:removed' event with the pane", ->
|
||||
removedHandler = jasmine.createSpy("removedHandler")
|
||||
container.on 'pane:removed', removedHandler
|
||||
paneModel.destroy()
|
||||
expect(removedHandler).toHaveBeenCalled()
|
||||
expect(removedHandler.argsForCall[0][1]).toBe pane
|
||||
|
||||
describe "if the destroyed pane has focus", ->
|
||||
[paneToLeft, paneToRight] = []
|
||||
|
||||
it "focuses the next pane", ->
|
||||
container.attachToDom()
|
||||
pane2.activate()
|
||||
expect(pane.hasFocus()).toBe false
|
||||
expect(pane2.hasFocus()).toBe true
|
||||
pane2Model.destroy()
|
||||
expect(pane.hasFocus()).toBe true
|
||||
|
||||
describe "::getNextPane()", ->
|
||||
it "returns the next pane if one exists, wrapping around from the last pane to the first", ->
|
||||
pane.activateItem(editor1)
|
||||
expect(pane.getNextPane()).toBeUndefined
|
||||
pane2 = pane.splitRight(pane.copyActiveItem())
|
||||
expect(pane.getNextPane()).toBe pane2
|
||||
expect(pane2.getNextPane()).toBe pane
|
||||
|
||||
describe "when the pane's active status changes", ->
|
||||
[pane2, pane2Model] = []
|
||||
|
||||
beforeEach ->
|
||||
pane2Model = paneModel.splitRight(items: [pane.copyActiveItem()])
|
||||
pane2 = atom.views.getView(pane2Model).__spacePenView
|
||||
expect(pane2Model.isActive()).toBe true
|
||||
|
||||
it "adds or removes the .active class as appropriate", ->
|
||||
expect(pane).not.toHaveClass('active')
|
||||
paneModel.activate()
|
||||
expect(pane).toHaveClass('active')
|
||||
pane2Model.activate()
|
||||
expect(pane).not.toHaveClass('active')
|
||||
|
||||
it "triggers 'pane:became-active' or 'pane:became-inactive' according to the current status", ->
|
||||
pane.on 'pane:became-active', becameActiveHandler = jasmine.createSpy("becameActiveHandler")
|
||||
pane.on 'pane:became-inactive', becameInactiveHandler = jasmine.createSpy("becameInactiveHandler")
|
||||
paneModel.activate()
|
||||
|
||||
expect(becameActiveHandler.callCount).toBe 1
|
||||
expect(becameInactiveHandler.callCount).toBe 0
|
||||
|
||||
pane2Model.activate()
|
||||
expect(becameActiveHandler.callCount).toBe 1
|
||||
expect(becameInactiveHandler.callCount).toBe 1
|
||||
|
||||
describe "when the pane is focused", ->
|
||||
beforeEach ->
|
||||
container.attachToDom()
|
||||
|
||||
it "transfers focus to the active view", ->
|
||||
focusHandler = jasmine.createSpy("focusHandler")
|
||||
pane.getActiveItem().on 'focus', focusHandler
|
||||
pane.focus()
|
||||
expect(focusHandler).toHaveBeenCalled()
|
||||
|
||||
it "makes the pane active", ->
|
||||
paneModel.splitRight(items: [pane.copyActiveItem()])
|
||||
expect(paneModel.isActive()).toBe false
|
||||
pane.focus()
|
||||
expect(paneModel.isActive()).toBe true
|
||||
|
||||
describe "when a pane is split", ->
|
||||
it "builds the appropriateatom-pane-axis.horizontal and pane-column views", ->
|
||||
pane1 = pane
|
||||
pane1Model = pane.getModel()
|
||||
pane.activateItem(editor1)
|
||||
|
||||
pane2Model = pane1Model.splitRight(items: [pane1Model.copyActiveItem()])
|
||||
pane3Model = pane2Model.splitDown(items: [pane2Model.copyActiveItem()])
|
||||
pane2 = pane2Model._view
|
||||
pane2 = atom.views.getView(pane2Model).__spacePenView
|
||||
pane3 = atom.views.getView(pane3Model).__spacePenView
|
||||
|
||||
expect(container.find('> atom-pane-axis.horizontal > atom-pane').toArray()).toEqual [pane1[0]]
|
||||
expect(container.find('> atom-pane-axis.horizontal > atom-pane-axis.vertical > atom-pane').toArray()).toEqual [pane2[0], pane3[0]]
|
||||
|
||||
pane1Model.destroy()
|
||||
expect(container.find('> atom-pane-axis.vertical > atom-pane').toArray()).toEqual [pane2[0], pane3[0]]
|
||||
|
||||
describe "serialization", ->
|
||||
it "focuses the pane after attach only if had focus when serialized", ->
|
||||
container.attachToDom()
|
||||
pane.focus()
|
||||
|
||||
container2 = atom.views.getView(container.model.testSerialization()).__spacePenView
|
||||
pane2 = container2.getRoot()
|
||||
container2.attachToDom()
|
||||
expect(pane2).toMatchSelector(':has(:focus)')
|
||||
|
||||
$(document.activeElement).blur()
|
||||
container3 = atom.views.getView(container.model.testSerialization()).__spacePenView
|
||||
pane3 = container3.getRoot()
|
||||
container3.attachToDom()
|
||||
expect(pane3).not.toMatchSelector(':has(:focus)')
|
||||
|
||||
describe "drag and drop", ->
|
||||
buildDragEvent = (type, files) ->
|
||||
dataTransfer =
|
||||
files: files
|
||||
data: {}
|
||||
setData: (key, value) -> @data[key] = value
|
||||
getData: (key) -> @data[key]
|
||||
|
||||
event = new CustomEvent("drop")
|
||||
event.dataTransfer = dataTransfer
|
||||
event
|
||||
|
||||
describe "when a file is dragged to window", ->
|
||||
it "opens it", ->
|
||||
spyOn(atom, "open")
|
||||
event = buildDragEvent("drop", [ {path: "/fake1"}, {path: "/fake2"} ])
|
||||
pane[0].dispatchEvent(event)
|
||||
expect(atom.open.callCount).toBe 1
|
||||
expect(atom.open.argsForCall[0][0]).toEqual pathsToOpen: ['/fake1', '/fake2']
|
||||
|
||||
describe "when a non-file is dragged to window", ->
|
||||
it "does nothing", ->
|
||||
spyOn(atom, "open")
|
||||
event = buildDragEvent("drop", [])
|
||||
pane[0].dispatchEvent(event)
|
||||
expect(atom.open).not.toHaveBeenCalled()
|
||||
@@ -201,18 +201,6 @@ describe "Project", ->
|
||||
expect(editor.buffer.getPath()).toBeUndefined()
|
||||
expect(newBufferHandler).toHaveBeenCalledWith(editor.buffer)
|
||||
|
||||
it "returns number of read bytes as progress indicator", ->
|
||||
filePath = atom.project.getDirectories()[0]?.resolve 'a'
|
||||
totalBytes = 0
|
||||
promise = atom.project.open(filePath)
|
||||
promise.progress (bytesRead) -> totalBytes = bytesRead
|
||||
|
||||
waitsForPromise ->
|
||||
promise
|
||||
|
||||
runs ->
|
||||
expect(totalBytes).toBe fs.statSync(filePath).size
|
||||
|
||||
describe ".bufferForPath(path)", ->
|
||||
[buffer] = []
|
||||
beforeEach ->
|
||||
|
||||
@@ -1,212 +0,0 @@
|
||||
SelectListView = require '../src/select-list-view'
|
||||
{$, $$} = require '../src/space-pen-extensions'
|
||||
|
||||
describe "SelectListView", ->
|
||||
[selectList, items, list, filterEditorView] = []
|
||||
|
||||
beforeEach ->
|
||||
items = [
|
||||
["A", "Alpha"], ["B", "Bravo"], ["C", "Charlie"],
|
||||
["D", "Delta"], ["E", "Echo"], ["F", "Foxtrot"]
|
||||
]
|
||||
|
||||
selectList = new SelectListView
|
||||
selectList.setMaxItems(4)
|
||||
selectList.getFilterKey = -> 1
|
||||
selectList.viewForItem = (item) ->
|
||||
$$ -> @li item[1], class: item[0]
|
||||
|
||||
selectList.confirmed = jasmine.createSpy('confirmed hook')
|
||||
selectList.cancelled = jasmine.createSpy('cancelled hook')
|
||||
|
||||
selectList.setItems(items)
|
||||
{list, filterEditorView} = selectList
|
||||
|
||||
describe "when an array is assigned", ->
|
||||
it "populates the list with up to maxItems items, based on the liForElement function", ->
|
||||
expect(list.find('li').length).toBe selectList.maxItems
|
||||
expect(list.find('li:eq(0)')).toHaveText 'Alpha'
|
||||
expect(list.find('li:eq(0)')).toHaveClass 'A'
|
||||
|
||||
describe "viewForItem(item)", ->
|
||||
it "allows raw DOM elements to be returned", ->
|
||||
selectList.viewForItem = (item) ->
|
||||
li = document.createElement('li')
|
||||
li.classList.add(item[0])
|
||||
li.innerText = item[1]
|
||||
li
|
||||
|
||||
selectList.setItems(items)
|
||||
|
||||
expect(list.find('li').length).toBe selectList.maxItems
|
||||
expect(list.find('li:eq(0)')).toHaveText 'Alpha'
|
||||
expect(list.find('li:eq(0)')).toHaveClass 'A'
|
||||
expect(selectList.getSelectedItem()).toBe items[0]
|
||||
|
||||
it "allows raw HTML to be returned", ->
|
||||
selectList.viewForItem = (item) ->
|
||||
"<li>#{item}</li>"
|
||||
|
||||
selectList.setItems(['Bermuda', 'Bahama'])
|
||||
|
||||
expect(list.find('li:eq(0)')).toHaveText 'Bermuda'
|
||||
expect(selectList.getSelectedItem()).toBe 'Bermuda'
|
||||
|
||||
describe "when the text of the mini editor changes", ->
|
||||
beforeEach ->
|
||||
selectList.attachToDom()
|
||||
|
||||
it "filters the elements in the list based on the scoreElement function and selects the first item", ->
|
||||
filterEditorView.getEditor().insertText('la')
|
||||
window.advanceClock(selectList.inputThrottle)
|
||||
|
||||
expect(list.find('li').length).toBe 2
|
||||
expect(list.find('li:contains(Alpha)')).toExist()
|
||||
expect(list.find('li:contains(Delta)')).toExist()
|
||||
expect(list.find('li:first')).toHaveClass 'selected'
|
||||
expect(selectList.error).not.toBeVisible()
|
||||
|
||||
it "displays an error if there are no matches, removes error when there are matches", ->
|
||||
filterEditorView.getEditor().insertText('nothing will match this')
|
||||
window.advanceClock(selectList.inputThrottle)
|
||||
|
||||
expect(list.find('li').length).toBe 0
|
||||
expect(selectList.error).not.toBeHidden()
|
||||
|
||||
filterEditorView.getEditor().setText('la')
|
||||
window.advanceClock(selectList.inputThrottle)
|
||||
|
||||
expect(list.find('li').length).toBe 2
|
||||
expect(selectList.error).not.toBeVisible()
|
||||
|
||||
it "displays no elements until the array has been set on the list", ->
|
||||
selectList.items = null
|
||||
selectList.list.empty()
|
||||
filterEditorView.getEditor().insertText('la')
|
||||
window.advanceClock(selectList.inputThrottle)
|
||||
|
||||
expect(list.find('li').length).toBe 0
|
||||
expect(selectList.error).toBeHidden()
|
||||
selectList.setItems(items)
|
||||
expect(list.find('li').length).toBe 2
|
||||
|
||||
describe "when core:move-up / core:move-down are triggered on the filterEditorView", ->
|
||||
it "selects the previous / next item in the list, or wraps around to the other side", ->
|
||||
expect(list.find('li:first')).toHaveClass 'selected'
|
||||
|
||||
filterEditorView.trigger 'core:move-up'
|
||||
|
||||
expect(list.find('li:first')).not.toHaveClass 'selected'
|
||||
expect(list.find('li:last')).toHaveClass 'selected'
|
||||
|
||||
filterEditorView.trigger 'core:move-down'
|
||||
|
||||
expect(list.find('li:first')).toHaveClass 'selected'
|
||||
expect(list.find('li:last')).not.toHaveClass 'selected'
|
||||
|
||||
filterEditorView.trigger 'core:move-down'
|
||||
|
||||
expect(list.find('li:eq(0)')).not.toHaveClass 'selected'
|
||||
expect(list.find('li:eq(1)')).toHaveClass 'selected'
|
||||
|
||||
filterEditorView.trigger 'core:move-down'
|
||||
|
||||
expect(list.find('li:eq(1)')).not.toHaveClass 'selected'
|
||||
expect(list.find('li:eq(2)')).toHaveClass 'selected'
|
||||
|
||||
filterEditorView.trigger 'core:move-up'
|
||||
|
||||
expect(list.find('li:eq(2)')).not.toHaveClass 'selected'
|
||||
expect(list.find('li:eq(1)')).toHaveClass 'selected'
|
||||
|
||||
it "scrolls to keep the selected item in view", ->
|
||||
selectList.attachToDom()
|
||||
itemHeight = list.find('li').outerHeight()
|
||||
list.height(itemHeight * 2)
|
||||
|
||||
filterEditorView.trigger 'core:move-down'
|
||||
filterEditorView.trigger 'core:move-down'
|
||||
expect(list.scrollBottom()).toBe itemHeight * 3
|
||||
|
||||
filterEditorView.trigger 'core:move-down'
|
||||
expect(list.scrollBottom()).toBe itemHeight * 4
|
||||
|
||||
filterEditorView.trigger 'core:move-up'
|
||||
filterEditorView.trigger 'core:move-up'
|
||||
expect(list.scrollTop()).toBe itemHeight
|
||||
|
||||
describe "the core:confirm event", ->
|
||||
describe "when there is an item selected (because the list in not empty)", ->
|
||||
it "triggers the selected hook with the selected array element", ->
|
||||
filterEditorView.trigger 'core:move-down'
|
||||
filterEditorView.trigger 'core:move-down'
|
||||
filterEditorView.trigger 'core:confirm'
|
||||
expect(selectList.confirmed).toHaveBeenCalledWith(items[2])
|
||||
|
||||
describe "when there is no item selected (because the list is empty)", ->
|
||||
beforeEach ->
|
||||
selectList.attachToDom()
|
||||
|
||||
it "does not trigger the confirmed hook", ->
|
||||
filterEditorView.getEditor().insertText("i will never match anything")
|
||||
window.advanceClock(selectList.inputThrottle)
|
||||
|
||||
expect(list.find('li')).not.toExist()
|
||||
filterEditorView.trigger 'core:confirm'
|
||||
expect(selectList.confirmed).not.toHaveBeenCalled()
|
||||
|
||||
it "does trigger the cancelled hook", ->
|
||||
filterEditorView.getEditor().insertText("i will never match anything")
|
||||
window.advanceClock(selectList.inputThrottle)
|
||||
|
||||
expect(list.find('li')).not.toExist()
|
||||
filterEditorView.trigger 'core:confirm'
|
||||
expect(selectList.cancelled).toHaveBeenCalled()
|
||||
|
||||
describe "when a list item is clicked", ->
|
||||
it "selects the item on mousedown and confirms it on mouseup", ->
|
||||
item = list.find('li:eq(1)')
|
||||
|
||||
item.mousedown()
|
||||
expect(item).toHaveClass 'selected'
|
||||
item.mouseup()
|
||||
|
||||
expect(selectList.confirmed).toHaveBeenCalledWith(items[1])
|
||||
|
||||
describe "the core:cancel event", ->
|
||||
it "triggers the cancelled hook and detaches and empties the select list", ->
|
||||
spyOn(selectList, 'detach')
|
||||
filterEditorView.trigger 'core:cancel'
|
||||
expect(selectList.cancelled).toHaveBeenCalled()
|
||||
expect(selectList.detach).toHaveBeenCalled()
|
||||
expect(selectList.list).toBeEmpty()
|
||||
|
||||
describe "when the mini editor loses focus", ->
|
||||
it "triggers the cancelled hook and detaches the select list", ->
|
||||
spyOn(selectList, 'detach')
|
||||
filterEditorView.trigger 'blur'
|
||||
expect(selectList.cancelled).toHaveBeenCalled()
|
||||
expect(selectList.detach).toHaveBeenCalled()
|
||||
|
||||
describe "the core:move-to-top event", ->
|
||||
it "scrolls to the top, selects the first element, and does not bubble the event", ->
|
||||
selectList.attachToDom()
|
||||
moveToTopHandler = jasmine.createSpy("moveToTopHandler")
|
||||
selectList.parent().on 'core:move-to-top', moveToTopHandler
|
||||
|
||||
selectList.trigger 'core:move-down'
|
||||
expect(list.find('li:eq(1)')).toHaveClass 'selected'
|
||||
selectList.trigger 'core:move-to-top'
|
||||
expect(list.find('li:first')).toHaveClass 'selected'
|
||||
expect(moveToTopHandler).not.toHaveBeenCalled()
|
||||
|
||||
describe "the core:move-to-bottom event", ->
|
||||
it "scrolls to the bottom, selects the last element, and does not bubble the event", ->
|
||||
selectList.attachToDom()
|
||||
moveToBottomHandler = jasmine.createSpy("moveToBottomHandler")
|
||||
selectList.parent().on 'core:move-to-bottom', moveToBottomHandler
|
||||
|
||||
expect(list.find('li:first')).toHaveClass 'selected'
|
||||
selectList.trigger 'core:move-to-bottom'
|
||||
expect(list.find('li:last')).toHaveClass 'selected'
|
||||
expect(moveToBottomHandler).not.toHaveBeenCalled()
|
||||
@@ -1,41 +0,0 @@
|
||||
{View, $, $$} = require '../src/space-pen-extensions'
|
||||
|
||||
describe "SpacePen extensions", ->
|
||||
class TestView extends View
|
||||
@content: -> @div()
|
||||
|
||||
[view, parent] = []
|
||||
|
||||
beforeEach ->
|
||||
view = new TestView
|
||||
parent = $$ -> @div()
|
||||
parent.append(view)
|
||||
|
||||
describe "View.subscribe(eventEmitter, eventName, callback)", ->
|
||||
[emitter, eventHandler] = []
|
||||
|
||||
beforeEach ->
|
||||
eventHandler = jasmine.createSpy 'eventHandler'
|
||||
emitter = $$ -> @div()
|
||||
view.subscribe emitter, 'foo', eventHandler
|
||||
|
||||
it "subscribes to the given event emitter and unsubscribes when unsubscribe is called", ->
|
||||
emitter.trigger "foo"
|
||||
expect(eventHandler).toHaveBeenCalled()
|
||||
|
||||
describe "tooltips", ->
|
||||
describe "when the window is resized", ->
|
||||
it "hides the tooltips", ->
|
||||
class TooltipView extends View
|
||||
@content: ->
|
||||
@div()
|
||||
|
||||
view = new TooltipView()
|
||||
view.attachToDom()
|
||||
view.setTooltip('this is a tip')
|
||||
|
||||
view.tooltip('show')
|
||||
expect($(document.body).find('.tooltip')).toBeVisible()
|
||||
|
||||
$(window).trigger('resize')
|
||||
expect($(document.body).find('.tooltip')).not.toExist()
|
||||
@@ -10,16 +10,12 @@ fs = require 'fs-plus'
|
||||
Grim = require 'grim'
|
||||
KeymapManager = require '../src/keymap-extensions'
|
||||
|
||||
# FIXME: Remove jquery from this
|
||||
{$} = require '../src/space-pen-extensions'
|
||||
|
||||
Config = require '../src/config'
|
||||
{Point} = require 'text-buffer'
|
||||
Project = require '../src/project'
|
||||
Workspace = require '../src/workspace'
|
||||
ServiceHub = require 'service-hub'
|
||||
TextEditor = require '../src/text-editor'
|
||||
TextEditorView = require '../src/text-editor-view'
|
||||
TextEditorElement = require '../src/text-editor-element'
|
||||
TokenizedBuffer = require '../src/tokenized-buffer'
|
||||
TextEditorComponent = require '../src/text-editor-component'
|
||||
@@ -41,7 +37,9 @@ window.addEventListener 'core:close', -> window.close()
|
||||
window.addEventListener 'beforeunload', ->
|
||||
atom.storeWindowDimensions()
|
||||
atom.saveSync()
|
||||
$('html,body').css('overflow', 'auto')
|
||||
|
||||
document.querySelector('html').style.overflow = 'auto'
|
||||
document.body.style.overflow = 'auto'
|
||||
|
||||
# Allow document.title to be assigned in specs without screwing up spec window title
|
||||
documentTitle = null
|
||||
@@ -91,7 +89,6 @@ if specDirectory
|
||||
isCoreSpec = specDirectory is fs.realpathSync(__dirname)
|
||||
|
||||
beforeEach ->
|
||||
$.fx.off = true
|
||||
documentTitle = null
|
||||
projectPath = specProjectPath ? path.join(@specDirectory, 'fixtures')
|
||||
atom.packages.serviceHub = new ServiceHub
|
||||
@@ -102,7 +99,7 @@ beforeEach ->
|
||||
atom.styles.restoreSnapshot(styleElementsToRestore)
|
||||
atom.views.clearDocumentRequests()
|
||||
|
||||
atom.workspaceViewParentSelector = '#jasmine-content'
|
||||
atom.workspaceParentSelectorctor = '#jasmine-content'
|
||||
|
||||
window.resetTimeouts()
|
||||
spyOn(_._, "now").andCallFake -> window.now
|
||||
@@ -171,7 +168,6 @@ afterEach ->
|
||||
|
||||
atom.workspace?.destroy()
|
||||
atom.workspace = null
|
||||
atom.__workspaceView = null
|
||||
delete atom.state.workspace
|
||||
|
||||
atom.project?.destroy()
|
||||
@@ -181,7 +177,7 @@ afterEach ->
|
||||
|
||||
delete atom.state.packageStates
|
||||
|
||||
$('#jasmine-content').empty() unless window.debugContent
|
||||
document.getElementById('jasmine-content').innerHTML = '' unless window.debugContent
|
||||
|
||||
jasmine.unspy(atom, 'saveSync')
|
||||
ensureNoPathSubscriptions()
|
||||
@@ -279,43 +275,6 @@ addCustomMatchers = (spec) ->
|
||||
@message = -> return "Expected element '#{element}' or its descendants#{notText} to show."
|
||||
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={}) ->
|
||||
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.buildKeydownEvent(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]
|
||||
@@ -374,45 +333,3 @@ window.advanceClock = (delta=1) ->
|
||||
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?.measureDimensions()
|
||||
|
||||
$.fn.resultOfTrigger = (type) ->
|
||||
event = $.Event(type)
|
||||
this.trigger(event)
|
||||
event.result
|
||||
|
||||
$.fn.enableKeymap = ->
|
||||
@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)
|
||||
event = $.event.fix(event)
|
||||
$(this).trigger(event)
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
_ = require 'underscore-plus'
|
||||
{extend, flatten, toArray, last} = _
|
||||
|
||||
TextEditorView = require '../src/text-editor-view'
|
||||
TextEditorComponent = require '../src/text-editor-component'
|
||||
TextEditorElement = require '../src/text-editor-element'
|
||||
nbsp = String.fromCharCode(160)
|
||||
|
||||
describe "TextEditorComponent", ->
|
||||
[contentNode, editor, wrapperView, wrapperNode, component, componentNode, verticalScrollbarNode, horizontalScrollbarNode] = []
|
||||
[contentNode, editor, wrapperNode, component, componentNode, verticalScrollbarNode, horizontalScrollbarNode] = []
|
||||
[lineHeightInPixels, charWidth, nextAnimationFrame, noAnimationFrame, tileSize, tileHeightInPixels] = []
|
||||
|
||||
beforeEach ->
|
||||
@@ -34,12 +33,13 @@ describe "TextEditorComponent", ->
|
||||
contentNode = document.querySelector('#jasmine-content')
|
||||
contentNode.style.width = '1000px'
|
||||
|
||||
wrapperView = new TextEditorView(editor, {tileSize})
|
||||
wrapperView.attachToDom()
|
||||
wrapperNode = wrapperView.element
|
||||
wrapperNode = new TextEditorElement()
|
||||
wrapperNode.tileSize = tileSize
|
||||
wrapperNode.initialize(editor)
|
||||
wrapperNode.setUpdatedSynchronously(false)
|
||||
jasmine.attachToDOM(wrapperNode)
|
||||
|
||||
{component} = wrapperView
|
||||
{component} = wrapperNode
|
||||
component.setFontFamily('monospace')
|
||||
component.setLineHeight(1.3)
|
||||
component.setFontSize(20)
|
||||
@@ -2384,11 +2384,11 @@ describe "TextEditorComponent", ->
|
||||
inputNode.focus()
|
||||
nextAnimationFrame()
|
||||
expect(componentNode.classList.contains('is-focused')).toBe true
|
||||
expect(wrapperView.hasClass('is-focused')).toBe true
|
||||
expect(wrapperNode.classList.contains('is-focused')).toBe true
|
||||
inputNode.blur()
|
||||
nextAnimationFrame()
|
||||
expect(componentNode.classList.contains('is-focused')).toBe false
|
||||
expect(wrapperView.hasClass('is-focused')).toBe false
|
||||
expect(wrapperNode.classList.contains('is-focused')).toBe false
|
||||
|
||||
describe "selection handling", ->
|
||||
cursor = null
|
||||
@@ -2896,17 +2896,18 @@ describe "TextEditorComponent", ->
|
||||
describe "hiding and showing the editor", ->
|
||||
describe "when the editor is hidden when it is mounted", ->
|
||||
it "defers measurement and rendering until the editor becomes visible", ->
|
||||
wrapperView.remove()
|
||||
wrapperNode.remove()
|
||||
|
||||
hiddenParent = document.createElement('div')
|
||||
hiddenParent.style.display = 'none'
|
||||
contentNode.appendChild(hiddenParent)
|
||||
|
||||
wrapperView = new TextEditorView(editor, {tileSize})
|
||||
wrapperNode = wrapperView.element
|
||||
wrapperView.appendTo(hiddenParent)
|
||||
wrapperNode = new TextEditorElement()
|
||||
wrapperNode.tileSize = tileSize
|
||||
wrapperNode.initialize(editor)
|
||||
hiddenParent.appendChild(wrapperNode)
|
||||
|
||||
{component} = wrapperView
|
||||
{component} = wrapperNode
|
||||
componentNode = component.getDomNode()
|
||||
expect(componentNode.querySelectorAll('.line').length).toBe 0
|
||||
|
||||
@@ -2917,18 +2918,25 @@ describe "TextEditorComponent", ->
|
||||
|
||||
describe "when the lineHeight changes while the editor is hidden", ->
|
||||
it "does not attempt to measure the lineHeightInPixels until the editor becomes visible again", ->
|
||||
wrapperView.hide()
|
||||
initialLineHeightInPixels = null
|
||||
wrapperNode.style.display = 'none'
|
||||
component.checkForVisibilityChange()
|
||||
|
||||
initialLineHeightInPixels = editor.getLineHeightInPixels()
|
||||
|
||||
component.setLineHeight(2)
|
||||
expect(editor.getLineHeightInPixels()).toBe initialLineHeightInPixels
|
||||
|
||||
wrapperView.show()
|
||||
wrapperNode.style.display = ''
|
||||
component.checkForVisibilityChange()
|
||||
|
||||
expect(editor.getLineHeightInPixels()).not.toBe initialLineHeightInPixels
|
||||
|
||||
describe "when the fontSize changes while the editor is hidden", ->
|
||||
it "does not attempt to measure the lineHeightInPixels or defaultCharWidth until the editor becomes visible again", ->
|
||||
wrapperView.hide()
|
||||
wrapperNode.style.display = 'none'
|
||||
component.checkForVisibilityChange()
|
||||
|
||||
initialLineHeightInPixels = editor.getLineHeightInPixels()
|
||||
initialCharWidth = editor.getDefaultCharWidth()
|
||||
|
||||
@@ -2936,17 +2944,22 @@ describe "TextEditorComponent", ->
|
||||
expect(editor.getLineHeightInPixels()).toBe initialLineHeightInPixels
|
||||
expect(editor.getDefaultCharWidth()).toBe initialCharWidth
|
||||
|
||||
wrapperView.show()
|
||||
wrapperNode.style.display = ''
|
||||
component.checkForVisibilityChange()
|
||||
|
||||
expect(editor.getLineHeightInPixels()).not.toBe initialLineHeightInPixels
|
||||
expect(editor.getDefaultCharWidth()).not.toBe initialCharWidth
|
||||
|
||||
it "does not re-measure character widths until the editor is shown again", ->
|
||||
wrapperView.hide()
|
||||
wrapperNode.style.display = 'none'
|
||||
component.checkForVisibilityChange()
|
||||
|
||||
component.setFontSize(22)
|
||||
editor.getBuffer().insert([0, 0], 'a') # regression test against atom/atom#3318
|
||||
|
||||
wrapperView.show()
|
||||
wrapperNode.style.display = ''
|
||||
component.checkForVisibilityChange()
|
||||
|
||||
editor.setCursorBufferPosition([0, Infinity])
|
||||
nextAnimationFrame()
|
||||
|
||||
@@ -2956,22 +2969,29 @@ describe "TextEditorComponent", ->
|
||||
|
||||
describe "when the fontFamily changes while the editor is hidden", ->
|
||||
it "does not attempt to measure the defaultCharWidth until the editor becomes visible again", ->
|
||||
wrapperView.hide()
|
||||
wrapperNode.style.display = 'none'
|
||||
component.checkForVisibilityChange()
|
||||
|
||||
initialLineHeightInPixels = editor.getLineHeightInPixels()
|
||||
initialCharWidth = editor.getDefaultCharWidth()
|
||||
|
||||
component.setFontFamily('serif')
|
||||
expect(editor.getDefaultCharWidth()).toBe initialCharWidth
|
||||
|
||||
wrapperView.show()
|
||||
wrapperNode.style.display = ''
|
||||
component.checkForVisibilityChange()
|
||||
|
||||
expect(editor.getDefaultCharWidth()).not.toBe initialCharWidth
|
||||
|
||||
it "does not re-measure character widths until the editor is shown again", ->
|
||||
wrapperView.hide()
|
||||
wrapperNode.style.display = 'none'
|
||||
component.checkForVisibilityChange()
|
||||
|
||||
component.setFontFamily('serif')
|
||||
|
||||
wrapperView.show()
|
||||
wrapperNode.style.display = ''
|
||||
component.checkForVisibilityChange()
|
||||
|
||||
editor.setCursorBufferPosition([0, Infinity])
|
||||
nextAnimationFrame()
|
||||
|
||||
@@ -2986,14 +3006,18 @@ describe "TextEditorComponent", ->
|
||||
it "does not re-measure character widths until the editor is shown again", ->
|
||||
atom.config.set('editor.fontFamily', 'sans-serif')
|
||||
|
||||
wrapperView.hide()
|
||||
wrapperNode.style.display = 'none'
|
||||
component.checkForVisibilityChange()
|
||||
|
||||
atom.themes.applyStylesheet 'test', """
|
||||
.function.js {
|
||||
font-weight: bold;
|
||||
}
|
||||
"""
|
||||
|
||||
wrapperView.show()
|
||||
wrapperNode.style.display = ''
|
||||
component.checkForVisibilityChange()
|
||||
|
||||
editor.setCursorBufferPosition([0, Infinity])
|
||||
nextAnimationFrame()
|
||||
|
||||
@@ -3004,11 +3028,17 @@ describe "TextEditorComponent", ->
|
||||
describe "when lines are changed while the editor is hidden", ->
|
||||
it "does not measure new characters until the editor is shown again", ->
|
||||
editor.setText('')
|
||||
wrapperView.hide()
|
||||
|
||||
wrapperNode.style.display = 'none'
|
||||
component.checkForVisibilityChange()
|
||||
|
||||
editor.setText('var z = 1')
|
||||
editor.setCursorBufferPosition([0, Infinity])
|
||||
nextAnimationFrame()
|
||||
wrapperView.show()
|
||||
|
||||
wrapperNode.style.display = 'none'
|
||||
component.checkForVisibilityChange()
|
||||
|
||||
expect(componentNode.querySelector('.cursor').style['-webkit-transform']).toBe "translate(#{9 * charWidth}px, 0px)"
|
||||
|
||||
describe "soft wrapping", ->
|
||||
@@ -3138,26 +3168,6 @@ describe "TextEditorComponent", ->
|
||||
nextAnimationFrame()
|
||||
expect(componentNode.querySelector('.placeholder-text')).toBeNull()
|
||||
|
||||
describe "legacy editor compatibility", ->
|
||||
it "triggers the screen-lines-changed event before the editor:display-updated event", ->
|
||||
editor.setSoftWrapped(true)
|
||||
|
||||
callingOrder = []
|
||||
editor.onDidChange -> callingOrder.push 'screen-lines-changed'
|
||||
wrapperView.on 'editor:display-updated', -> callingOrder.push 'editor:display-updated'
|
||||
editor.insertText("HELLO! HELLO!\n HELLO! HELLO! HELLO! HELLO! HELLO! HELLO! HELLO! HELLO! HELLO! HELLO! HELLO! HELLO! HELLO! HELLO! HELLO! HELLO! HELLO! HELLO! ")
|
||||
nextAnimationFrame()
|
||||
|
||||
expect(callingOrder).toEqual ['screen-lines-changed', 'editor:display-updated', 'editor:display-updated']
|
||||
|
||||
it "works with the ::setEditorHeightInLines and ::setEditorWidthInChars helpers", ->
|
||||
setEditorHeightInLines(wrapperView, 7)
|
||||
nextAnimationFrame()
|
||||
expect(componentNode.offsetHeight).toBe lineHeightInPixels * 7
|
||||
|
||||
setEditorWidthInChars(wrapperView, 10)
|
||||
expect(componentNode.querySelector('.scroll-view').offsetWidth).toBe charWidth * 10
|
||||
|
||||
describe "grammar data attributes", ->
|
||||
it "adds and updates the grammar data attribute based on the current grammar", ->
|
||||
expect(wrapperNode.dataset.grammar).toBe 'source js'
|
||||
@@ -3172,10 +3182,10 @@ describe "TextEditorComponent", ->
|
||||
|
||||
describe "detaching and reattaching the editor (regression)", ->
|
||||
it "does not throw an exception", ->
|
||||
wrapperView.detach()
|
||||
wrapperView.attachToDom()
|
||||
wrapperNode.remove()
|
||||
jasmine.attachToDOM(wrapperNode)
|
||||
|
||||
wrapperView.trigger('core:move-right')
|
||||
atom.commands.dispatch(wrapperNode, 'core:move-right')
|
||||
|
||||
expect(editor.getCursorBufferPosition()).toEqual [0, 1]
|
||||
|
||||
|
||||
@@ -2899,6 +2899,32 @@ describe "TextEditor", ->
|
||||
expect(buffer.lineForRow(3)).toBe ' var pivot = item'
|
||||
expect(atom.clipboard.read()).toBe ' <= 1) ret\ns.shift(), current, left = [], right = [];'
|
||||
|
||||
describe ".cutToEndOfBufferLine()", ->
|
||||
beforeEach ->
|
||||
editor.setSoftWrapped(true)
|
||||
editor.setEditorWidthInChars(10)
|
||||
|
||||
describe "when nothing is selected", ->
|
||||
it "cuts up to the end of the buffer line", ->
|
||||
editor.setCursorBufferPosition([2, 20])
|
||||
editor.addCursorAtBufferPosition([3, 20])
|
||||
|
||||
editor.cutToEndOfBufferLine()
|
||||
|
||||
expect(buffer.lineForRow(2)).toBe ' if (items.length'
|
||||
expect(buffer.lineForRow(3)).toBe ' var pivot = item'
|
||||
expect(atom.clipboard.read()).toBe ' <= 1) return items;\ns.shift(), current, left = [], right = [];'
|
||||
|
||||
describe "when text is selected", ->
|
||||
it "only cuts the selected text, not to the end of the buffer line", ->
|
||||
editor.setSelectedBufferRanges([[[2, 20], [2, 30]], [[3, 20], [3, 20]]])
|
||||
|
||||
editor.cutToEndOfBufferLine()
|
||||
|
||||
expect(buffer.lineForRow(2)).toBe ' if (items.lengthurn items;'
|
||||
expect(buffer.lineForRow(3)).toBe ' var pivot = item'
|
||||
expect(atom.clipboard.read()).toBe ' <= 1) ret\ns.shift(), current, left = [], right = [];'
|
||||
|
||||
describe ".copySelectedText()", ->
|
||||
it "copies selected text onto the clipboard", ->
|
||||
editor.setSelectedBufferRanges([[[0, 4], [0, 13]], [[1, 6], [1, 10]], [[2, 8], [2, 13]]])
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
path = require 'path'
|
||||
|
||||
{$, $$} = require '../src/space-pen-extensions'
|
||||
fs = require 'fs-plus'
|
||||
temp = require 'temp'
|
||||
|
||||
@@ -26,19 +24,20 @@ describe "ThemeManager", ->
|
||||
afterEach ->
|
||||
jasmine.restoreDeprecationsSnapshot()
|
||||
|
||||
it 'getLoadedThemes get all the loaded themes', ->
|
||||
themes = themeManager.getLoadedThemes()
|
||||
expect(themes.length).toBeGreaterThan(2)
|
||||
describe 'getLoadedThemes', ->
|
||||
it 'gets all the loaded themes', ->
|
||||
themes = themeManager.getLoadedThemes()
|
||||
expect(themes.length).toBeGreaterThan(2)
|
||||
|
||||
it 'getActiveThemes get all the active themes', ->
|
||||
waitsForPromise ->
|
||||
themeManager.activateThemes()
|
||||
describe "getActiveThemes", ->
|
||||
it 'gets all the active themes', ->
|
||||
waitsForPromise -> themeManager.activateThemes()
|
||||
|
||||
runs ->
|
||||
names = atom.config.get('core.themes')
|
||||
expect(names.length).toBeGreaterThan(0)
|
||||
themes = themeManager.getActiveThemes()
|
||||
expect(themes).toHaveLength(names.length)
|
||||
runs ->
|
||||
names = atom.config.get('core.themes')
|
||||
expect(names.length).toBeGreaterThan(0)
|
||||
themes = themeManager.getActiveThemes()
|
||||
expect(themes).toHaveLength(names.length)
|
||||
|
||||
describe "when the core.themes config value contains invalid entry", ->
|
||||
it "ignores theme", ->
|
||||
@@ -88,7 +87,7 @@ describe "ThemeManager", ->
|
||||
|
||||
runs ->
|
||||
didChangeActiveThemesHandler.reset()
|
||||
expect($('style.theme')).toHaveLength 0
|
||||
expect(document.querySelectorAll('style.theme')).toHaveLength 0
|
||||
atom.config.set('core.themes', ['atom-dark-ui'])
|
||||
|
||||
waitsFor ->
|
||||
@@ -96,8 +95,8 @@ describe "ThemeManager", ->
|
||||
|
||||
runs ->
|
||||
didChangeActiveThemesHandler.reset()
|
||||
expect($('style[priority=1]')).toHaveLength 2
|
||||
expect($('style[priority=1]:eq(0)').attr('source-path')).toMatch /atom-dark-ui/
|
||||
expect(document.querySelectorAll('style[priority="1"]')).toHaveLength 2
|
||||
expect(document.querySelector('style[priority="1"]').getAttribute('source-path')).toMatch /atom-dark-ui/
|
||||
atom.config.set('core.themes', ['atom-light-ui', 'atom-dark-ui'])
|
||||
|
||||
waitsFor ->
|
||||
@@ -105,9 +104,9 @@ describe "ThemeManager", ->
|
||||
|
||||
runs ->
|
||||
didChangeActiveThemesHandler.reset()
|
||||
expect($('style[priority=1]')).toHaveLength 2
|
||||
expect($('style[priority=1]:eq(0)').attr('source-path')).toMatch /atom-dark-ui/
|
||||
expect($('style[priority=1]:eq(1)').attr('source-path')).toMatch /atom-light-ui/
|
||||
expect(document.querySelectorAll('style[priority="1"]')).toHaveLength 2
|
||||
expect(document.querySelectorAll('style[priority="1"]')[0].getAttribute('source-path')).toMatch /atom-dark-ui/
|
||||
expect(document.querySelectorAll('style[priority="1"]')[1].getAttribute('source-path')).toMatch /atom-light-ui/
|
||||
atom.config.set('core.themes', [])
|
||||
|
||||
waitsFor ->
|
||||
@@ -115,7 +114,7 @@ describe "ThemeManager", ->
|
||||
|
||||
runs ->
|
||||
didChangeActiveThemesHandler.reset()
|
||||
expect($('style[priority=1]')).toHaveLength 2
|
||||
expect(document.querySelectorAll('style[priority="1"]')).toHaveLength 2
|
||||
# atom-dark-ui has an directory path, the syntax one doesn't
|
||||
atom.config.set('core.themes', ['theme-with-index-less', 'atom-dark-ui'])
|
||||
|
||||
@@ -123,7 +122,7 @@ describe "ThemeManager", ->
|
||||
didChangeActiveThemesHandler.callCount is 1
|
||||
|
||||
runs ->
|
||||
expect($('style[priority=1]')).toHaveLength 2
|
||||
expect(document.querySelectorAll('style[priority="1"]')).toHaveLength 2
|
||||
importPaths = themeManager.getImportPaths()
|
||||
expect(importPaths.length).toBe 1
|
||||
expect(importPaths[0]).toContain 'atom-dark-ui'
|
||||
@@ -172,37 +171,38 @@ describe "ThemeManager", ->
|
||||
themeManager.onDidAddStylesheet stylesheetAddedHandler = jasmine.createSpy("stylesheetAddedHandler")
|
||||
|
||||
cssPath = atom.project.getDirectories()[0]?.resolve('css.css')
|
||||
lengthBefore = $('head style').length
|
||||
lengthBefore = document.querySelectorAll('head style').length
|
||||
|
||||
themeManager.requireStylesheet(cssPath)
|
||||
expect($('head style').length).toBe lengthBefore + 1
|
||||
expect(document.querySelectorAll('head style').length).toBe lengthBefore + 1
|
||||
|
||||
expect(styleElementAddedHandler).toHaveBeenCalled()
|
||||
expect(stylesheetAddedHandler).toHaveBeenCalled()
|
||||
expect(stylesheetsChangedHandler).toHaveBeenCalled()
|
||||
|
||||
element = $('head style[source-path*="css.css"]')
|
||||
expect(element.attr('source-path')).toBe themeManager.stringToId(cssPath)
|
||||
expect(element.text()).toBe fs.readFileSync(cssPath, 'utf8')
|
||||
expect(element[0].sheet).toBe stylesheetAddedHandler.argsForCall[0][0]
|
||||
element = document.querySelector('head style[source-path*="css.css"]')
|
||||
expect(element.getAttribute('source-path')).toBe themeManager.stringToId(cssPath)
|
||||
expect(element.textContent).toBe fs.readFileSync(cssPath, 'utf8')
|
||||
expect(element.sheet).toBe stylesheetAddedHandler.argsForCall[0][0]
|
||||
|
||||
# doesn't append twice
|
||||
styleElementAddedHandler.reset()
|
||||
themeManager.requireStylesheet(cssPath)
|
||||
expect($('head style').length).toBe lengthBefore + 1
|
||||
expect(document.querySelectorAll('head style').length).toBe lengthBefore + 1
|
||||
expect(styleElementAddedHandler).not.toHaveBeenCalled()
|
||||
|
||||
$('head style[id*="css.css"]').remove()
|
||||
for styleElement in document.querySelectorAll('head style[id*="css.css"]')
|
||||
styleElement.remove()
|
||||
|
||||
it "synchronously loads and parses less files at the given path and installs a style tag for it in the head", ->
|
||||
lessPath = atom.project.getDirectories()[0]?.resolve('sample.less')
|
||||
lengthBefore = $('head style').length
|
||||
lengthBefore = document.querySelectorAll('head style').length
|
||||
themeManager.requireStylesheet(lessPath)
|
||||
expect($('head style').length).toBe lengthBefore + 1
|
||||
expect(document.querySelectorAll('head style').length).toBe lengthBefore + 1
|
||||
|
||||
element = $('head style[source-path*="sample.less"]')
|
||||
expect(element.attr('source-path')).toBe themeManager.stringToId(lessPath)
|
||||
expect(element.text()).toBe """
|
||||
element = document.querySelector('head style[source-path*="sample.less"]')
|
||||
expect(element.getAttribute('source-path')).toBe themeManager.stringToId(lessPath)
|
||||
expect(element.textContent).toBe """
|
||||
#header {
|
||||
color: #4d926f;
|
||||
}
|
||||
@@ -214,24 +214,25 @@ describe "ThemeManager", ->
|
||||
|
||||
# doesn't append twice
|
||||
themeManager.requireStylesheet(lessPath)
|
||||
expect($('head style').length).toBe lengthBefore + 1
|
||||
$('head style[id*="sample.less"]').remove()
|
||||
expect(document.querySelectorAll('head style').length).toBe lengthBefore + 1
|
||||
for styleElement in document.querySelectorAll('head style[id*="sample.less"]')
|
||||
styleElement.remove()
|
||||
|
||||
it "supports requiring css and less stylesheets without an explicit extension", ->
|
||||
themeManager.requireStylesheet path.join(__dirname, 'fixtures', 'css')
|
||||
expect($('head style[source-path*="css.css"]').attr('source-path')).toBe themeManager.stringToId(atom.project.getDirectories()[0]?.resolve('css.css'))
|
||||
expect(document.querySelector('head style[source-path*="css.css"]').getAttribute('source-path')).toBe themeManager.stringToId(atom.project.getDirectories()[0]?.resolve('css.css'))
|
||||
themeManager.requireStylesheet path.join(__dirname, 'fixtures', 'sample')
|
||||
expect($('head style[source-path*="sample.less"]').attr('source-path')).toBe themeManager.stringToId(atom.project.getDirectories()[0]?.resolve('sample.less'))
|
||||
expect(document.querySelector('head style[source-path*="sample.less"]').getAttribute('source-path')).toBe themeManager.stringToId(atom.project.getDirectories()[0]?.resolve('sample.less'))
|
||||
|
||||
$('head style[id*="css.css"]').remove()
|
||||
$('head style[id*="sample.less"]').remove()
|
||||
document.querySelector('head style[source-path*="css.css"]').remove()
|
||||
document.querySelector('head style[source-path*="sample.less"]').remove()
|
||||
|
||||
it "returns a disposable allowing styles applied by the given path to be removed", ->
|
||||
cssPath = require.resolve('./fixtures/css.css')
|
||||
|
||||
expect($(document.body).css('font-weight')).not.toBe("bold")
|
||||
expect(getComputedStyle(document.body).fontWeight).not.toBe("bold")
|
||||
disposable = themeManager.requireStylesheet(cssPath)
|
||||
expect($(document.body).css('font-weight')).toBe("bold")
|
||||
expect(getComputedStyle(document.body).fontWeight).toBe("bold")
|
||||
|
||||
atom.styles.onDidRemoveStyleElement styleElementRemovedHandler = jasmine.createSpy("styleElementRemovedHandler")
|
||||
themeManager.onDidRemoveStylesheet stylesheetRemovedHandler = jasmine.createSpy("stylesheetRemovedHandler")
|
||||
@@ -239,7 +240,7 @@ describe "ThemeManager", ->
|
||||
|
||||
disposable.dispose()
|
||||
|
||||
expect($(document.body).css('font-weight')).not.toBe("bold")
|
||||
expect(getComputedStyle(document.body).fontWeight).not.toBe("bold")
|
||||
|
||||
expect(styleElementRemovedHandler).toHaveBeenCalled()
|
||||
expect(stylesheetRemovedHandler).toHaveBeenCalled()
|
||||
@@ -271,9 +272,9 @@ describe "ThemeManager", ->
|
||||
expect(getComputedStyle(workspaceElement)["background-color"]).toBe "rgb(0, 0, 255)"
|
||||
|
||||
# from within the theme itself
|
||||
expect($("atom-text-editor").css("padding-top")).toBe "150px"
|
||||
expect($("atom-text-editor").css("padding-right")).toBe "150px"
|
||||
expect($("atom-text-editor").css("padding-bottom")).toBe "150px"
|
||||
expect(getComputedStyle(document.querySelector("atom-text-editor")).paddingTop).toBe "150px"
|
||||
expect(getComputedStyle(document.querySelector("atom-text-editor")).paddingRight).toBe "150px"
|
||||
expect(getComputedStyle(document.querySelector("atom-text-editor")).paddingBottom).toBe "150px"
|
||||
|
||||
describe "when there is a theme with incomplete variables", ->
|
||||
it "loads the correct values from the fallback ui-variables", ->
|
||||
@@ -288,7 +289,7 @@ describe "ThemeManager", ->
|
||||
expect(getComputedStyle(workspaceElement)["background-color"]).toBe "rgb(0, 0, 255)"
|
||||
|
||||
# from within the theme itself
|
||||
expect($("atom-text-editor").css("background-color")).toBe "rgb(0, 152, 255)"
|
||||
expect(getComputedStyle(document.querySelector("atom-text-editor")).backgroundColor).toBe "rgb(0, 152, 255)"
|
||||
|
||||
describe "user stylesheet", ->
|
||||
userStylesheetPath = null
|
||||
@@ -320,14 +321,14 @@ describe "ThemeManager", ->
|
||||
themeManager.onDidAddStylesheet stylesheetAddedHandler = jasmine.createSpy("stylesheetAddedHandler")
|
||||
spyOn(themeManager, 'loadUserStylesheet').andCallThrough()
|
||||
|
||||
expect($(document.body).css('border-style')).toBe 'dotted'
|
||||
expect(getComputedStyle(document.body).borderStyle).toBe 'dotted'
|
||||
fs.writeFileSync(userStylesheetPath, 'body {border-style: dashed}')
|
||||
|
||||
waitsFor ->
|
||||
themeManager.loadUserStylesheet.callCount is 1
|
||||
|
||||
runs ->
|
||||
expect($(document.body).css('border-style')).toBe 'dashed'
|
||||
expect(getComputedStyle(document.body).borderStyle).toBe 'dashed'
|
||||
|
||||
expect(styleElementRemovedHandler).toHaveBeenCalled()
|
||||
expect(styleElementRemovedHandler.argsForCall[0][0].textContent).toContain 'dotted'
|
||||
@@ -354,7 +355,7 @@ describe "ThemeManager", ->
|
||||
expect(styleElementRemovedHandler.argsForCall[0][0].textContent).toContain 'dashed'
|
||||
expect(stylesheetRemovedHandler).toHaveBeenCalled()
|
||||
expect(stylesheetRemovedHandler.argsForCall[0][0].cssRules[0].style.border).toBe 'dashed'
|
||||
expect($(document.body).css('border-style')).toBe 'none'
|
||||
expect(getComputedStyle(document.body).borderStyle).toBe 'none'
|
||||
expect(stylesheetsChangedHandler).toHaveBeenCalled()
|
||||
|
||||
describe "when there is an error reading the stylesheet", ->
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
TooltipManager = require '../src/tooltip-manager'
|
||||
{$} = require '../src/space-pen-extensions'
|
||||
_ = require "underscore-plus"
|
||||
|
||||
describe "TooltipManager", ->
|
||||
@@ -15,18 +14,51 @@ describe "TooltipManager", ->
|
||||
jasmine.attachToDOM(element)
|
||||
|
||||
hover = (element, fn) ->
|
||||
$(element).trigger 'mouseenter'
|
||||
element.dispatchEvent(new CustomEvent('mouseenter', bubbles: false))
|
||||
element.dispatchEvent(new CustomEvent('mouseover', bubbles: true))
|
||||
advanceClock(manager.defaults.delay.show)
|
||||
fn()
|
||||
$(element).trigger 'mouseleave'
|
||||
element.dispatchEvent(new CustomEvent('mouseleave', bubbles: false))
|
||||
element.dispatchEvent(new CustomEvent('mouseout', bubbles: true))
|
||||
advanceClock(manager.defaults.delay.hide)
|
||||
|
||||
describe "::add(target, options)", ->
|
||||
describe "when the target is an element", ->
|
||||
it "creates a tooltip based on the given options when hovering over the target element", ->
|
||||
manager.add element, title: "Title"
|
||||
hover element, ->
|
||||
expect(document.body.querySelector(".tooltip")).toHaveText("Title")
|
||||
it "creates a tooltip based on the given options when hovering over the target element", ->
|
||||
manager.add element, title: "Title"
|
||||
hover element, ->
|
||||
expect(document.body.querySelector(".tooltip")).toHaveText("Title")
|
||||
|
||||
it "allows jQuery elements to be passed as the target", ->
|
||||
element2 = document.createElement('div')
|
||||
jasmine.attachToDOM(element2)
|
||||
|
||||
fakeJqueryWrapper = [element, element2]
|
||||
fakeJqueryWrapper.jquery = 'any-version'
|
||||
disposable = manager.add fakeJqueryWrapper, title: "Title"
|
||||
|
||||
hover element, -> expect(document.body.querySelector(".tooltip")).toHaveText("Title")
|
||||
expect(document.body.querySelector(".tooltip")).toBeNull()
|
||||
hover element2, -> expect(document.body.querySelector(".tooltip")).toHaveText("Title")
|
||||
expect(document.body.querySelector(".tooltip")).toBeNull()
|
||||
|
||||
disposable.dispose()
|
||||
|
||||
hover element, -> expect(document.body.querySelector(".tooltip")).toBeNull()
|
||||
hover element2, -> expect(document.body.querySelector(".tooltip")).toBeNull()
|
||||
|
||||
describe "when a selector is specified", ->
|
||||
it "creates a tooltip when hovering over a descendant of the target that matches the selector", ->
|
||||
child = document.createElement('div')
|
||||
child.classList.add('bar')
|
||||
grandchild = document.createElement('div')
|
||||
element.appendChild(child)
|
||||
child.appendChild(grandchild)
|
||||
|
||||
manager.add element, selector: '.bar', title: 'Bar'
|
||||
|
||||
hover grandchild, ->
|
||||
expect(document.body.querySelector('.tooltip')).toHaveText('Bar')
|
||||
expect(document.body.querySelector('.tooltip')).toBeNull()
|
||||
|
||||
describe "when a keyBindingCommand is specified", ->
|
||||
describe "when a title is specified", ->
|
||||
@@ -81,3 +113,11 @@ describe "TooltipManager", ->
|
||||
|
||||
hover element, ->
|
||||
expect(document.body.querySelector(".tooltip")).toBeNull()
|
||||
|
||||
describe "when the window is resized", ->
|
||||
it "hides the tooltips", ->
|
||||
manager.add element, title: "Title"
|
||||
hover element, ->
|
||||
expect(document.body.querySelector(".tooltip")).toBeDefined()
|
||||
window.dispatchEvent(new CustomEvent('resize'))
|
||||
expect(document.body.querySelector(".tooltip")).toBeNull()
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
ViewRegistry = require '../src/view-registry'
|
||||
{View} = require '../src/space-pen-extensions'
|
||||
|
||||
describe "ViewRegistry", ->
|
||||
registry = null
|
||||
@@ -16,16 +15,6 @@ describe "ViewRegistry", ->
|
||||
node = document.createElement('div')
|
||||
expect(registry.getView(node)).toBe node
|
||||
|
||||
describe "when passed a SpacePen view", ->
|
||||
it "returns the root node of the view with a .spacePenView property pointing at the SpacePen view", ->
|
||||
class TestView extends View
|
||||
@content: -> @div "Hello"
|
||||
|
||||
view = new TestView
|
||||
node = registry.getView(view)
|
||||
expect(node.textContent).toBe "Hello"
|
||||
expect(node.spacePenView).toBe view
|
||||
|
||||
describe "when passed an object with an element property", ->
|
||||
it "returns the element property if it's an instance of HTMLElement", ->
|
||||
class TestComponent
|
||||
@@ -59,30 +48,8 @@ describe "ViewRegistry", ->
|
||||
expect(view2.model).toBe subclassModel
|
||||
|
||||
describe "when no view provider is registered for the object's constructor", ->
|
||||
describe "when the object has a .getViewClass() method", ->
|
||||
it "builds an instance of the view class with the model, then returns its root node with a __spacePenView property pointing at the view", ->
|
||||
class TestView extends View
|
||||
@content: (model) -> @div model.name
|
||||
initialize: (@model) ->
|
||||
|
||||
class TestModel
|
||||
constructor: (@name) ->
|
||||
getViewClass: -> TestView
|
||||
|
||||
model = new TestModel("hello")
|
||||
node = registry.getView(model)
|
||||
|
||||
expect(node.textContent).toBe "hello"
|
||||
view = node.spacePenView
|
||||
expect(view instanceof TestView).toBe true
|
||||
expect(view.model).toBe model
|
||||
|
||||
# returns the same DOM node for repeated calls
|
||||
expect(registry.getView(model)).toBe node
|
||||
|
||||
describe "when the object has no .getViewClass() method", ->
|
||||
it "throws an exception", ->
|
||||
expect(-> registry.getView(new Object)).toThrow()
|
||||
it "throws an exception", ->
|
||||
expect(-> registry.getView(new Object)).toThrow()
|
||||
|
||||
describe "::addViewProvider(providerSpec)", ->
|
||||
it "returns a disposable that can be used to remove the provider", ->
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{$, $$} = require '../src/space-pen-extensions'
|
||||
KeymapManager = require 'atom-keymap'
|
||||
path = require 'path'
|
||||
fs = require 'fs-plus'
|
||||
temp = require 'temp'
|
||||
@@ -16,45 +16,41 @@ describe "Window", ->
|
||||
loadSettings.initialPath = initialPath
|
||||
loadSettings
|
||||
atom.project.destroy()
|
||||
windowEventHandler = new WindowEventHandler()
|
||||
atom.deserializeEditorWindow()
|
||||
atom.windowEventHandler.unsubscribe()
|
||||
windowEventHandler = new WindowEventHandler
|
||||
projectPath = atom.project.getPaths()[0]
|
||||
|
||||
afterEach ->
|
||||
windowEventHandler.unsubscribe()
|
||||
$(window).off 'beforeunload'
|
||||
|
||||
describe "when the window is loaded", ->
|
||||
it "doesn't have .is-blurred on the body tag", ->
|
||||
expect($("body")).not.toHaveClass("is-blurred")
|
||||
expect(document.body.className).not.toMatch("is-blurred")
|
||||
|
||||
describe "when the window is blurred", ->
|
||||
beforeEach ->
|
||||
$(window).triggerHandler 'blur'
|
||||
window.dispatchEvent(new CustomEvent('blur'))
|
||||
|
||||
afterEach ->
|
||||
$('body').removeClass('is-blurred')
|
||||
document.body.classList.remove('is-blurred')
|
||||
|
||||
it "adds the .is-blurred class on the body", ->
|
||||
expect($("body")).toHaveClass("is-blurred")
|
||||
expect(document.body.className).toMatch("is-blurred")
|
||||
|
||||
describe "when the window is focused again", ->
|
||||
it "removes the .is-blurred class from the body", ->
|
||||
$(window).triggerHandler 'focus'
|
||||
expect($("body")).not.toHaveClass("is-blurred")
|
||||
window.dispatchEvent(new CustomEvent('focus'))
|
||||
expect(document.body.className).not.toMatch("is-blurred")
|
||||
|
||||
describe "window:close event", ->
|
||||
it "closes the window", ->
|
||||
spyOn(atom, 'close')
|
||||
$(window).trigger 'window:close'
|
||||
window.dispatchEvent(new CustomEvent('window:close'))
|
||||
expect(atom.close).toHaveBeenCalled()
|
||||
|
||||
describe "beforeunload event", ->
|
||||
[beforeUnloadEvent] = []
|
||||
|
||||
beforeEach ->
|
||||
jasmine.unspy(TextEditor.prototype, "shouldPromptToSave")
|
||||
beforeUnloadEvent = $.Event(new Event('beforeunload'))
|
||||
|
||||
describe "when pane items are modified", ->
|
||||
it "prompts user to save and calls atom.workspace.confirmClose", ->
|
||||
@@ -67,7 +63,7 @@ describe "Window", ->
|
||||
|
||||
runs ->
|
||||
editor.insertText("I look different, I feel different.")
|
||||
$(window).trigger(beforeUnloadEvent)
|
||||
window.dispatchEvent(new CustomEvent('beforeunload'))
|
||||
expect(atom.workspace.confirmClose).toHaveBeenCalled()
|
||||
expect(atom.confirm).toHaveBeenCalled()
|
||||
|
||||
@@ -80,7 +76,7 @@ describe "Window", ->
|
||||
|
||||
runs ->
|
||||
editor.insertText("I look different, I feel different.")
|
||||
$(window).trigger(beforeUnloadEvent)
|
||||
window.dispatchEvent(new CustomEvent('beforeunload'))
|
||||
expect(atom.confirm).toHaveBeenCalled()
|
||||
|
||||
it "prompts user to save and handler returns false if dialog is canceled", ->
|
||||
@@ -91,11 +87,12 @@ describe "Window", ->
|
||||
|
||||
runs ->
|
||||
editor.insertText("I look different, I feel different.")
|
||||
$(window).trigger(beforeUnloadEvent)
|
||||
window.dispatchEvent(new CustomEvent('beforeunload'))
|
||||
expect(atom.confirm).toHaveBeenCalled()
|
||||
|
||||
describe "when the same path is modified in multiple panes", ->
|
||||
it "prompts to save the item", ->
|
||||
return
|
||||
editor = null
|
||||
filePath = path.join(temp.mkdirSync('atom-file'), 'file.txt')
|
||||
fs.writeFileSync(filePath, 'hello')
|
||||
@@ -108,146 +105,125 @@ describe "Window", ->
|
||||
runs ->
|
||||
atom.workspace.getActivePane().splitRight(copyActiveItem: true)
|
||||
editor.setText('world')
|
||||
$(window).trigger(beforeUnloadEvent)
|
||||
window.dispatchEvent(new CustomEvent('beforeunload'))
|
||||
expect(atom.workspace.confirmClose).toHaveBeenCalled()
|
||||
expect(atom.confirm.callCount).toBe 1
|
||||
expect(fs.readFileSync(filePath, 'utf8')).toBe 'world'
|
||||
|
||||
describe ".unloadEditorWindow()", ->
|
||||
it "saves the serialized state of the window so it can be deserialized after reload", ->
|
||||
workspaceState = atom.workspace.serialize()
|
||||
syntaxState = atom.grammars.serialize()
|
||||
projectState = atom.project.serialize()
|
||||
|
||||
atom.unloadEditorWindow()
|
||||
|
||||
expect(atom.state.workspace).toEqual workspaceState
|
||||
expect(atom.state.grammars).toEqual syntaxState
|
||||
expect(atom.state.project).toEqual projectState
|
||||
expect(atom.saveSync).toHaveBeenCalled()
|
||||
|
||||
describe ".removeEditorWindow()", ->
|
||||
it "unsubscribes from all buffers", ->
|
||||
waitsForPromise ->
|
||||
atom.workspace.open("sample.js")
|
||||
|
||||
runs ->
|
||||
buffer = atom.workspace.getActivePaneItem().buffer
|
||||
pane = atom.workspace.getActivePane()
|
||||
pane.splitRight(copyActiveItem: true)
|
||||
expect(atom.workspace.getTextEditors().length).toBe 2
|
||||
|
||||
atom.removeEditorWindow()
|
||||
|
||||
expect(buffer.getSubscriptionCount()).toBe 0
|
||||
|
||||
describe "when a link is clicked", ->
|
||||
it "opens the http/https links in an external application", ->
|
||||
shell = require 'shell'
|
||||
spyOn(shell, 'openExternal')
|
||||
|
||||
$("<a href='http://github.com'>the website</a>").appendTo(document.body).click().remove()
|
||||
link = document.createElement('a')
|
||||
linkChild = document.createElement('span')
|
||||
link.appendChild(linkChild)
|
||||
link.href = 'http://github.com'
|
||||
jasmine.attachToDOM(link)
|
||||
fakeEvent = {target: linkChild, currentTarget: link, preventDefault: (->)}
|
||||
|
||||
windowEventHandler.handleLinkClick(fakeEvent)
|
||||
expect(shell.openExternal).toHaveBeenCalled()
|
||||
expect(shell.openExternal.argsForCall[0][0]).toBe "http://github.com"
|
||||
|
||||
shell.openExternal.reset()
|
||||
$("<a href='https://github.com'>the website</a>").appendTo(document.body).click().remove()
|
||||
|
||||
link.href = 'https://github.com'
|
||||
windowEventHandler.handleLinkClick(fakeEvent)
|
||||
expect(shell.openExternal).toHaveBeenCalled()
|
||||
expect(shell.openExternal.argsForCall[0][0]).toBe "https://github.com"
|
||||
|
||||
shell.openExternal.reset()
|
||||
$("<a href=''>the website</a>").appendTo(document.body).click().remove()
|
||||
|
||||
link.href = ''
|
||||
windowEventHandler.handleLinkClick(fakeEvent)
|
||||
expect(shell.openExternal).not.toHaveBeenCalled()
|
||||
|
||||
shell.openExternal.reset()
|
||||
$("<a href='#scroll-me'>link</a>").appendTo(document.body).click().remove()
|
||||
|
||||
link.href = '#scroll-me'
|
||||
windowEventHandler.handleLinkClick(fakeEvent)
|
||||
expect(shell.openExternal).not.toHaveBeenCalled()
|
||||
|
||||
describe "when a form is submitted", ->
|
||||
it "prevents the default so that the window's URL isn't changed", ->
|
||||
submitSpy = jasmine.createSpy('submit')
|
||||
$(document).on('submit', 'form', submitSpy)
|
||||
$("<form>foo</form>").appendTo(document.body).submit().remove()
|
||||
expect(submitSpy.callCount).toBe 1
|
||||
expect(submitSpy.argsForCall[0][0].isDefaultPrevented()).toBe true
|
||||
form = document.createElement('form')
|
||||
jasmine.attachToDOM(form)
|
||||
|
||||
defaultPrevented = false
|
||||
event = new CustomEvent('submit', bubbles: true)
|
||||
event.preventDefault = -> defaultPrevented = true
|
||||
form.dispatchEvent(event)
|
||||
expect(defaultPrevented).toBe(true)
|
||||
|
||||
describe "core:focus-next and core:focus-previous", ->
|
||||
describe "when there is no currently focused element", ->
|
||||
it "focuses the element with the lowest/highest tabindex", ->
|
||||
elements = $$ ->
|
||||
@div =>
|
||||
@button tabindex: 2
|
||||
@input tabindex: 1
|
||||
wrapperDiv = document.createElement('div')
|
||||
wrapperDiv.innerHTML = """
|
||||
<div>
|
||||
<button tabindex="2"></button>
|
||||
<input tabindex="1">
|
||||
</div>
|
||||
"""
|
||||
elements = wrapperDiv.firstChild
|
||||
jasmine.attachToDOM(elements)
|
||||
|
||||
elements.attachToDom()
|
||||
elements.dispatchEvent(new CustomEvent("core:focus-next", bubbles: true))
|
||||
expect(document.activeElement.tabIndex).toBe 1
|
||||
|
||||
elements.trigger "core:focus-next"
|
||||
expect(elements.find("[tabindex=1]:focus")).toExist()
|
||||
|
||||
$(":focus").blur()
|
||||
|
||||
elements.trigger "core:focus-previous"
|
||||
expect(elements.find("[tabindex=2]:focus")).toExist()
|
||||
document.body.focus()
|
||||
elements.dispatchEvent(new CustomEvent("core:focus-previous", bubbles: true))
|
||||
expect(document.activeElement.tabIndex).toBe 2
|
||||
|
||||
describe "when a tabindex is set on the currently focused element", ->
|
||||
it "focuses the element with the next highest tabindex", ->
|
||||
elements = $$ ->
|
||||
@div =>
|
||||
@input tabindex: 1
|
||||
@button tabindex: 2
|
||||
@button tabindex: 5
|
||||
@input tabindex: -1
|
||||
@input tabindex: 3
|
||||
@button tabindex: 7
|
||||
it "focuses the element with the next highest/lowest tabindex, skipping disabled elements", ->
|
||||
wrapperDiv = document.createElement('div')
|
||||
wrapperDiv.innerHTML = """
|
||||
<div>
|
||||
<input tabindex="1">
|
||||
<button tabindex="2"></button>
|
||||
<button tabindex="5"></button>
|
||||
<input tabindex="-1">
|
||||
<input tabindex="3">
|
||||
<button tabindex="7"></button>
|
||||
<input tabindex="9" disabled>
|
||||
</div>
|
||||
"""
|
||||
elements = wrapperDiv.firstChild
|
||||
jasmine.attachToDOM(elements)
|
||||
|
||||
elements.attachToDom()
|
||||
elements.find("[tabindex=1]").focus()
|
||||
elements.querySelector('[tabindex="1"]').focus()
|
||||
|
||||
elements.trigger "core:focus-next"
|
||||
expect(elements.find("[tabindex=2]:focus")).toExist()
|
||||
elements.dispatchEvent(new CustomEvent("core:focus-next", bubbles: true))
|
||||
expect(document.activeElement.tabIndex).toBe 2
|
||||
|
||||
elements.trigger "core:focus-next"
|
||||
expect(elements.find("[tabindex=3]:focus")).toExist()
|
||||
elements.dispatchEvent(new CustomEvent("core:focus-next", bubbles: true))
|
||||
expect(document.activeElement.tabIndex).toBe 3
|
||||
|
||||
elements.focus().trigger "core:focus-next"
|
||||
expect(elements.find("[tabindex=5]:focus")).toExist()
|
||||
elements.dispatchEvent(new CustomEvent("core:focus-next", bubbles: true))
|
||||
expect(document.activeElement.tabIndex).toBe 5
|
||||
|
||||
elements.focus().trigger "core:focus-next"
|
||||
expect(elements.find("[tabindex=7]:focus")).toExist()
|
||||
elements.dispatchEvent(new CustomEvent("core:focus-next", bubbles: true))
|
||||
expect(document.activeElement.tabIndex).toBe 7
|
||||
|
||||
elements.focus().trigger "core:focus-next"
|
||||
expect(elements.find("[tabindex=1]:focus")).toExist()
|
||||
elements.dispatchEvent(new CustomEvent("core:focus-next", bubbles: true))
|
||||
expect(document.activeElement.tabIndex).toBe 1
|
||||
|
||||
elements.trigger "core:focus-previous"
|
||||
expect(elements.find("[tabindex=7]:focus")).toExist()
|
||||
elements.dispatchEvent(new CustomEvent("core:focus-previous", bubbles: true))
|
||||
expect(document.activeElement.tabIndex).toBe 7
|
||||
|
||||
elements.trigger "core:focus-previous"
|
||||
expect(elements.find("[tabindex=5]:focus")).toExist()
|
||||
elements.dispatchEvent(new CustomEvent("core:focus-previous", bubbles: true))
|
||||
expect(document.activeElement.tabIndex).toBe 5
|
||||
|
||||
elements.focus().trigger "core:focus-previous"
|
||||
expect(elements.find("[tabindex=3]:focus")).toExist()
|
||||
elements.dispatchEvent(new CustomEvent("core:focus-previous", bubbles: true))
|
||||
expect(document.activeElement.tabIndex).toBe 3
|
||||
|
||||
elements.focus().trigger "core:focus-previous"
|
||||
expect(elements.find("[tabindex=2]:focus")).toExist()
|
||||
elements.dispatchEvent(new CustomEvent("core:focus-previous", bubbles: true))
|
||||
expect(document.activeElement.tabIndex).toBe 2
|
||||
|
||||
elements.focus().trigger "core:focus-previous"
|
||||
expect(elements.find("[tabindex=1]:focus")).toExist()
|
||||
elements.dispatchEvent(new CustomEvent("core:focus-previous", bubbles: true))
|
||||
expect(document.activeElement.tabIndex).toBe 1
|
||||
|
||||
it "skips disabled elements", ->
|
||||
elements = $$ ->
|
||||
@div =>
|
||||
@input tabindex: 1
|
||||
@button tabindex: 2, disabled: 'disabled'
|
||||
@input tabindex: 3
|
||||
|
||||
elements.attachToDom()
|
||||
elements.find("[tabindex=1]").focus()
|
||||
|
||||
elements.trigger "core:focus-next"
|
||||
expect(elements.find("[tabindex=3]:focus")).toExist()
|
||||
|
||||
elements.trigger "core:focus-previous"
|
||||
expect(elements.find("[tabindex=1]:focus")).toExist()
|
||||
elements.dispatchEvent(new CustomEvent("core:focus-previous", bubbles: true))
|
||||
expect(document.activeElement.tabIndex).toBe 7
|
||||
|
||||
describe "the window:open-locations event", ->
|
||||
beforeEach ->
|
||||
@@ -304,3 +280,16 @@ describe "Window", ->
|
||||
|
||||
runs ->
|
||||
expect(atom.project.getPaths()[0]).toBe pathToOpen
|
||||
|
||||
describe "when keydown events occur on the document", ->
|
||||
it "dispatches the event via the KeymapManager and CommandRegistry", ->
|
||||
dispatchedCommands = []
|
||||
atom.commands.onWillDispatch (command) -> dispatchedCommands.push(command)
|
||||
atom.commands.add '*', 'foo-command': ->
|
||||
atom.keymaps.add 'source-name', '*': {'x': 'foo-command'}
|
||||
|
||||
event = KeymapManager.buildKeydownEvent('x', target: document.createElement('div'))
|
||||
document.dispatchEvent(event)
|
||||
|
||||
expect(dispatchedCommands.length).toBe 1
|
||||
expect(dispatchedCommands[0].type).toBe 'foo-command'
|
||||
@@ -3,13 +3,90 @@ path = require 'path'
|
||||
temp = require('temp').track()
|
||||
|
||||
describe "WorkspaceElement", ->
|
||||
workspaceElement = null
|
||||
describe "when the workspace element is focused", ->
|
||||
it "transfers focus to the active pane", ->
|
||||
workspaceElement = atom.views.getView(atom.workspace)
|
||||
jasmine.attachToDOM(workspaceElement)
|
||||
activePaneElement = atom.views.getView(atom.workspace.getActivePane())
|
||||
document.body.focus()
|
||||
expect(document.activeElement).not.toBe(activePaneElement)
|
||||
workspaceElement.focus()
|
||||
expect(document.activeElement).toBe(activePaneElement)
|
||||
|
||||
beforeEach ->
|
||||
workspaceElement = atom.views.getView(atom.workspace)
|
||||
describe "the scrollbar visibility class", ->
|
||||
it "has a class based on the style of the scrollbar", ->
|
||||
observeCallback = null
|
||||
scrollbarStyle = require 'scrollbar-style'
|
||||
spyOn(scrollbarStyle, 'observePreferredScrollbarStyle').andCallFake (cb) -> observeCallback = cb
|
||||
workspaceElement = atom.views.getView(atom.workspace)
|
||||
|
||||
observeCallback('legacy')
|
||||
expect(workspaceElement.className).toMatch 'scrollbars-visible-always'
|
||||
|
||||
observeCallback('overlay')
|
||||
expect(workspaceElement).toHaveClass 'scrollbars-visible-when-scrolling'
|
||||
|
||||
describe "editor font styling", ->
|
||||
[editor, editorElement] = []
|
||||
|
||||
beforeEach ->
|
||||
waitsForPromise -> atom.workspace.open('sample.js')
|
||||
|
||||
runs ->
|
||||
workspaceElement = atom.views.getView(atom.workspace)
|
||||
jasmine.attachToDOM(workspaceElement)
|
||||
editor = atom.workspace.getActiveTextEditor()
|
||||
editorElement = atom.views.getView(editor)
|
||||
|
||||
it "updates the font-size based on the 'editor.fontSize' config value", ->
|
||||
initialCharWidth = editor.getDefaultCharWidth()
|
||||
expect(getComputedStyle(editorElement).fontSize).toBe atom.config.get('editor.fontSize') + 'px'
|
||||
atom.config.set('editor.fontSize', atom.config.get('editor.fontSize') + 5)
|
||||
expect(getComputedStyle(editorElement).fontSize).toBe atom.config.get('editor.fontSize') + 'px'
|
||||
expect(editor.getDefaultCharWidth()).toBeGreaterThan initialCharWidth
|
||||
|
||||
it "updates the font-family based on the 'editor.fontFamily' config value", ->
|
||||
initialCharWidth = editor.getDefaultCharWidth()
|
||||
expect(getComputedStyle(editorElement).fontFamily).toBe atom.config.get('editor.fontFamily')
|
||||
atom.config.set('editor.fontFamily', 'sans-serif')
|
||||
expect(getComputedStyle(editorElement).fontFamily).toBe atom.config.get('editor.fontFamily')
|
||||
expect(editor.getDefaultCharWidth()).not.toBe initialCharWidth
|
||||
|
||||
it "updates the line-height based on the 'editor.lineHeight' config value", ->
|
||||
initialLineHeight = editor.getLineHeightInPixels()
|
||||
atom.config.set('editor.lineHeight', '30px')
|
||||
expect(getComputedStyle(editorElement).lineHeight).toBe atom.config.get('editor.lineHeight')
|
||||
expect(editor.getLineHeightInPixels()).not.toBe initialLineHeight
|
||||
|
||||
describe 'panel containers', ->
|
||||
it 'inserts panel container elements in the correct places in the DOM', ->
|
||||
workspaceElement = atom.views.getView(atom.workspace)
|
||||
|
||||
leftContainer = workspaceElement.querySelector('atom-panel-container.left')
|
||||
rightContainer = workspaceElement.querySelector('atom-panel-container.right')
|
||||
expect(leftContainer.nextSibling).toBe workspaceElement.verticalAxis
|
||||
expect(rightContainer.previousSibling).toBe workspaceElement.verticalAxis
|
||||
|
||||
topContainer = workspaceElement.querySelector('atom-panel-container.top')
|
||||
bottomContainer = workspaceElement.querySelector('atom-panel-container.bottom')
|
||||
expect(topContainer.nextSibling).toBe workspaceElement.paneContainer
|
||||
expect(bottomContainer.previousSibling).toBe workspaceElement.paneContainer
|
||||
|
||||
modalContainer = workspaceElement.querySelector('atom-panel-container.modal')
|
||||
expect(modalContainer.parentNode).toBe workspaceElement
|
||||
|
||||
describe "the 'window:toggle-invisibles' command", ->
|
||||
it "shows/hides invisibles in all open and future editors", ->
|
||||
workspaceElement = atom.views.getView(atom.workspace)
|
||||
expect(atom.config.get('editor.showInvisibles')).toBe false
|
||||
atom.commands.dispatch(workspaceElement, 'window:toggle-invisibles')
|
||||
expect(atom.config.get('editor.showInvisibles')).toBe true
|
||||
atom.commands.dispatch(workspaceElement, 'window:toggle-invisibles')
|
||||
expect(atom.config.get('editor.showInvisibles')).toBe false
|
||||
|
||||
describe "the 'window:run-package-specs' command", ->
|
||||
it "runs the package specs for the active item's project path, or the first project path", ->
|
||||
workspaceElement = atom.views.getView(atom.workspace)
|
||||
spyOn(ipc, 'send')
|
||||
|
||||
# No project paths. Don't try to run specs.
|
||||
|
||||
@@ -2,7 +2,6 @@ path = require 'path'
|
||||
temp = require 'temp'
|
||||
Workspace = require '../src/workspace'
|
||||
Pane = require '../src/pane'
|
||||
{View} = require '../src/space-pen-extensions'
|
||||
platform = require './spec-helper-platform'
|
||||
_ = require 'underscore-plus'
|
||||
fstream = require 'fstream'
|
||||
@@ -17,6 +16,64 @@ describe "Workspace", ->
|
||||
atom.workspace = workspace = new Workspace
|
||||
waits(1)
|
||||
|
||||
describe "serialization", ->
|
||||
simulateReload = ->
|
||||
workspaceState = atom.workspace.serialize()
|
||||
projectState = atom.project.serialize()
|
||||
atom.workspace.destroy()
|
||||
atom.project.destroy()
|
||||
atom.project = atom.deserializers.deserialize(projectState)
|
||||
atom.workspace = Workspace.deserialize(workspaceState)
|
||||
|
||||
describe "when the workspace contains text editors", ->
|
||||
it "constructs the view with the same panes", ->
|
||||
pane1 = atom.workspace.getActivePane()
|
||||
pane2 = pane1.splitRight(copyActiveItem: true)
|
||||
pane3 = pane2.splitRight(copyActiveItem: true)
|
||||
pane4 = null
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('b').then (editor) ->
|
||||
pane2.activateItem(editor.copy())
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('../sample.js').then (editor) ->
|
||||
pane3.activateItem(editor)
|
||||
|
||||
runs ->
|
||||
pane3.activeItem.setCursorScreenPosition([2, 4])
|
||||
pane4 = pane2.splitDown()
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('../sample.txt').then (editor) ->
|
||||
pane4.activateItem(editor)
|
||||
|
||||
runs ->
|
||||
pane4.getActiveItem().setCursorScreenPosition([0, 2])
|
||||
pane2.activate()
|
||||
|
||||
simulateReload()
|
||||
|
||||
expect(atom.workspace.getTextEditors().length).toBe 4
|
||||
[editor1, editor2, editor3, editor4] = atom.workspace.getTextEditors()
|
||||
|
||||
expect(editor1.getPath()).toBe atom.project.getDirectories()[0]?.resolve('b')
|
||||
expect(editor2.getPath()).toBe atom.project.getDirectories()[0]?.resolve('../sample.txt')
|
||||
expect(editor2.getCursorScreenPosition()).toEqual [0, 2]
|
||||
expect(editor3.getPath()).toBe atom.project.getDirectories()[0]?.resolve('b')
|
||||
expect(editor4.getPath()).toBe atom.project.getDirectories()[0]?.resolve('../sample.js')
|
||||
expect(editor4.getCursorScreenPosition()).toEqual [2, 4]
|
||||
|
||||
expect(atom.workspace.getActiveTextEditor().getPath()).toBe editor3.getPath()
|
||||
expect(document.title).toBe "#{path.basename(editor3.getPath())} - #{atom.project.getPaths()[0]} - Atom"
|
||||
|
||||
describe "where there are no open panes or editors", ->
|
||||
it "constructs the view with no open editors", ->
|
||||
atom.workspace.getActivePane().destroy()
|
||||
expect(atom.workspace.getTextEditors().length).toBe 0
|
||||
simulateReload()
|
||||
expect(atom.workspace.getTextEditors().length).toBe 0
|
||||
|
||||
describe "::open(uri, options)", ->
|
||||
openEvents = null
|
||||
|
||||
@@ -1065,11 +1122,16 @@ describe "Workspace", ->
|
||||
|
||||
it "can be cancelled when the object returned by scan() has its cancel() method invoked", ->
|
||||
thenable = atom.workspace.scan /aaaa/, ->
|
||||
expect(fakeSearch.cancelled).toBe(undefined)
|
||||
thenable.cancel()
|
||||
expect(fakeSearch.cancelled).toBe(true)
|
||||
|
||||
resultOfPromiseSearch = null
|
||||
|
||||
waitsFor 'fakeSearch to be defined', -> fakeSearch?
|
||||
|
||||
runs ->
|
||||
expect(fakeSearch.cancelled).toBe(undefined)
|
||||
thenable.cancel()
|
||||
expect(fakeSearch.cancelled).toBe(true)
|
||||
|
||||
|
||||
waitsForPromise ->
|
||||
thenable.then (promiseResult) -> resultOfPromiseSearch = promiseResult
|
||||
|
||||
@@ -1077,15 +1139,28 @@ describe "Workspace", ->
|
||||
expect(resultOfPromiseSearch).toBe('cancelled')
|
||||
|
||||
it "will have the side-effect of failing the overall search if it fails", ->
|
||||
cancelableSearch = atom.workspace.scan /aaaa/, ->
|
||||
fakeSearch.hoistedReject()
|
||||
# This provider's search should be cancelled when the first provider fails
|
||||
fakeSearch2 = null
|
||||
atom.packages.serviceHub.provide('atom.directory-searcher', '0.1.0', {
|
||||
canSearchDirectory: (directory) -> directory.getPath() is dir2
|
||||
search: (directory, regex, options) -> fakeSearch2 = new FakeSearch(options)
|
||||
})
|
||||
|
||||
didReject = false
|
||||
promise = cancelableSearch = atom.workspace.scan /aaaa/, ->
|
||||
waitsFor 'fakeSearch to be defined', -> fakeSearch?
|
||||
|
||||
runs ->
|
||||
fakeSearch.hoistedReject()
|
||||
|
||||
waitsForPromise ->
|
||||
cancelableSearch.catch -> didReject = true
|
||||
|
||||
waitsFor (done) -> promise.then(null, done)
|
||||
|
||||
runs ->
|
||||
expect(didReject).toBe(true)
|
||||
expect(fakeSearch2.cancelled).toBe true # Cancels other ongoing searches
|
||||
|
||||
describe "::replace(regex, replacementText, paths, iterator)", ->
|
||||
[filePath, commentFilePath, sampleContent, sampleCommentContent] = []
|
||||
@@ -1267,3 +1342,32 @@ describe "Workspace", ->
|
||||
|
||||
save = -> atom.workspace.saveActivePaneItem()
|
||||
expect(save).toThrow()
|
||||
|
||||
describe "::destroyActivePaneItemOrEmptyPane", ->
|
||||
beforeEach ->
|
||||
waitsForPromise -> atom.workspace.open()
|
||||
|
||||
it "closes the active pane item until all that remains is a single empty pane", ->
|
||||
atom.config.set('core.destroyEmptyPanes', false)
|
||||
|
||||
pane1 = atom.workspace.getActivePane()
|
||||
pane2 = pane1.splitRight(copyActiveItem: true)
|
||||
|
||||
expect(atom.workspace.getPanes().length).toBe 2
|
||||
expect(pane2.getItems().length).toBe 1
|
||||
atom.workspace.destroyActivePaneItemOrEmptyPane()
|
||||
|
||||
expect(atom.workspace.getPanes().length).toBe 2
|
||||
expect(pane2.getItems().length).toBe 0
|
||||
|
||||
atom.workspace.destroyActivePaneItemOrEmptyPane()
|
||||
|
||||
expect(atom.workspace.getPanes().length).toBe 1
|
||||
expect(pane1.getItems().length).toBe 1
|
||||
|
||||
atom.workspace.destroyActivePaneItemOrEmptyPane()
|
||||
expect(atom.workspace.getPanes().length).toBe 1
|
||||
expect(pane1.getItems().length).toBe 0
|
||||
|
||||
atom.workspace.destroyActivePaneItemOrEmptyPane()
|
||||
expect(atom.workspace.getPanes().length).toBe 1
|
||||
|
||||
@@ -1,301 +0,0 @@
|
||||
{$, $$, View} = require '../src/space-pen-extensions'
|
||||
Q = require 'q'
|
||||
path = require 'path'
|
||||
temp = require 'temp'
|
||||
TextEditorView = require '../src/text-editor-view'
|
||||
PaneView = require '../src/pane-view'
|
||||
Workspace = require '../src/workspace'
|
||||
|
||||
describe "WorkspaceView", ->
|
||||
pathToOpen = null
|
||||
|
||||
beforeEach ->
|
||||
jasmine.snapshotDeprecations()
|
||||
|
||||
atom.project.setPaths([atom.project.getDirectories()[0]?.resolve('dir')])
|
||||
pathToOpen = atom.project.getDirectories()[0]?.resolve('a')
|
||||
atom.workspace = new Workspace
|
||||
atom.workspaceView = atom.views.getView(atom.workspace).__spacePenView
|
||||
atom.workspaceView.enableKeymap()
|
||||
atom.workspaceView.focus()
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.open(pathToOpen)
|
||||
|
||||
afterEach ->
|
||||
jasmine.restoreDeprecationsSnapshot()
|
||||
|
||||
describe "@deserialize()", ->
|
||||
viewState = null
|
||||
|
||||
simulateReload = ->
|
||||
workspaceState = atom.workspace.serialize()
|
||||
projectState = atom.project.serialize()
|
||||
atom.workspaceView.remove()
|
||||
atom.project = atom.deserializers.deserialize(projectState)
|
||||
atom.workspace = Workspace.deserialize(workspaceState)
|
||||
atom.workspaceView = atom.views.getView(atom.workspace).__spacePenView
|
||||
atom.workspaceView.attachToDom()
|
||||
|
||||
describe "when the serialized WorkspaceView has an unsaved buffer", ->
|
||||
it "constructs the view with the same panes", ->
|
||||
atom.workspaceView.attachToDom()
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.open()
|
||||
|
||||
runs ->
|
||||
editorView1 = atom.workspaceView.getActiveView()
|
||||
buffer = editorView1.getEditor().getBuffer()
|
||||
editorView1.getPaneView().getModel().splitRight(copyActiveItem: true)
|
||||
expect(atom.workspaceView.getActivePaneView()).toBe atom.workspaceView.getPaneViews()[1]
|
||||
|
||||
simulateReload()
|
||||
|
||||
expect(atom.workspaceView.getEditorViews().length).toBe 2
|
||||
expect(atom.workspaceView.getActivePaneView()).toBe atom.workspaceView.getPaneViews()[1]
|
||||
expect(document.title).toBe "untitled - #{atom.project.getPaths()[0]} - Atom"
|
||||
|
||||
describe "when there are open editors", ->
|
||||
it "constructs the view with the same panes", ->
|
||||
atom.workspaceView.attachToDom()
|
||||
pane1 = atom.workspaceView.getActivePaneView()
|
||||
pane2 = pane1.splitRight()
|
||||
pane3 = pane2.splitRight()
|
||||
pane4 = null
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('b').then (editor) ->
|
||||
pane2.activateItem(editor.copy())
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('../sample.js').then (editor) ->
|
||||
pane3.activateItem(editor)
|
||||
|
||||
runs ->
|
||||
pane3.activeItem.setCursorScreenPosition([2, 4])
|
||||
pane4 = pane2.splitDown()
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('../sample.txt').then (editor) ->
|
||||
pane4.activateItem(editor)
|
||||
|
||||
runs ->
|
||||
pane4.activeItem.setCursorScreenPosition([0, 2])
|
||||
pane2.focus()
|
||||
|
||||
simulateReload()
|
||||
|
||||
expect(atom.workspaceView.getEditorViews().length).toBe 4
|
||||
editorView1 = atom.workspaceView.panes.find('atom-pane-axis.horizontal > atom-pane atom-text-editor:eq(0)').view()
|
||||
editorView3 = atom.workspaceView.panes.find('atom-pane-axis.horizontal > atom-pane atom-text-editor:eq(1)').view()
|
||||
editorView2 = atom.workspaceView.panes.find('atom-pane-axis.horizontal > atom-pane-axis.vertical > atom-pane atom-text-editor:eq(0)').view()
|
||||
editorView4 = atom.workspaceView.panes.find('atom-pane-axis.horizontal > atom-pane-axis.vertical > atom-pane atom-text-editor:eq(1)').view()
|
||||
|
||||
expect(editorView1.getEditor().getPath()).toBe atom.project.getDirectories()[0]?.resolve('a')
|
||||
expect(editorView2.getEditor().getPath()).toBe atom.project.getDirectories()[0]?.resolve('b')
|
||||
expect(editorView3.getEditor().getPath()).toBe atom.project.getDirectories()[0]?.resolve('../sample.js')
|
||||
expect(editorView3.getEditor().getCursorScreenPosition()).toEqual [2, 4]
|
||||
expect(editorView4.getEditor().getPath()).toBe atom.project.getDirectories()[0]?.resolve('../sample.txt')
|
||||
expect(editorView4.getEditor().getCursorScreenPosition()).toEqual [0, 2]
|
||||
|
||||
# ensure adjust pane dimensions is called
|
||||
expect(editorView1.width()).toBeGreaterThan 0
|
||||
expect(editorView2.width()).toBeGreaterThan 0
|
||||
expect(editorView3.width()).toBeGreaterThan 0
|
||||
expect(editorView4.width()).toBeGreaterThan 0
|
||||
|
||||
# ensure correct editorView is focused again
|
||||
expect(editorView2).toHaveFocus()
|
||||
expect(editorView1).not.toHaveFocus()
|
||||
expect(editorView3).not.toHaveFocus()
|
||||
expect(editorView4).not.toHaveFocus()
|
||||
|
||||
expect(document.title).toBe "#{path.basename(editorView2.getEditor().getPath())} - #{atom.project.getPaths()[0]} - Atom"
|
||||
|
||||
describe "where there are no open editors", ->
|
||||
it "constructs the view with no open editors", ->
|
||||
atom.workspaceView.getActivePaneView().remove()
|
||||
expect(atom.workspaceView.getEditorViews().length).toBe 0
|
||||
simulateReload()
|
||||
expect(atom.workspaceView.getEditorViews().length).toBe 0
|
||||
|
||||
describe "focus", ->
|
||||
beforeEach ->
|
||||
atom.workspaceView.attachToDom()
|
||||
|
||||
it "hands off focus to the active pane", ->
|
||||
activePane = atom.workspaceView.getActivePaneView()
|
||||
$('body').focus()
|
||||
expect(activePane).not.toHaveFocus()
|
||||
atom.workspaceView.focus()
|
||||
expect(activePane).toHaveFocus()
|
||||
|
||||
describe "keymap wiring", ->
|
||||
describe "when a keydown event is triggered in the WorkspaceView", ->
|
||||
it "triggers matching keybindings for that event", ->
|
||||
commandHandler = jasmine.createSpy('commandHandler')
|
||||
atom.workspaceView.on('foo-command', commandHandler)
|
||||
atom.keymaps.add('name', '*': {'x': 'foo-command'})
|
||||
event = keydownEvent 'x', target: atom.workspaceView[0]
|
||||
|
||||
atom.workspaceView.trigger(event)
|
||||
expect(commandHandler).toHaveBeenCalled()
|
||||
|
||||
describe "window:toggle-invisibles event", ->
|
||||
it "shows/hides invisibles in all open and future editors", ->
|
||||
atom.workspaceView.height(200)
|
||||
atom.workspaceView.attachToDom()
|
||||
rightEditorView = atom.workspaceView.getActiveView()
|
||||
rightEditorView.getEditor().setText("\t \n")
|
||||
rightEditorView.getPaneView().getModel().splitLeft(copyActiveItem: true)
|
||||
leftEditorView = atom.workspaceView.getActiveView()
|
||||
expect(rightEditorView.find(".line:first").text()).toBe " "
|
||||
expect(leftEditorView.find(".line:first").text()).toBe " "
|
||||
|
||||
{space, tab, eol} = atom.config.get('editor.invisibles')
|
||||
withInvisiblesShowing = "#{tab} #{space}#{space}#{eol}"
|
||||
|
||||
atom.workspaceView.trigger "window:toggle-invisibles"
|
||||
expect(rightEditorView.find(".line:first").text()).toBe withInvisiblesShowing
|
||||
expect(leftEditorView.find(".line:first").text()).toBe withInvisiblesShowing
|
||||
|
||||
leftEditorView.getPaneView().getModel().splitDown(copyActiveItem: true)
|
||||
lowerLeftEditorView = atom.workspaceView.getActiveView()
|
||||
expect(lowerLeftEditorView.find(".line:first").text()).toBe withInvisiblesShowing
|
||||
|
||||
atom.workspaceView.trigger "window:toggle-invisibles"
|
||||
expect(rightEditorView.find(".line:first").text()).toBe " "
|
||||
expect(leftEditorView.find(".line:first").text()).toBe " "
|
||||
|
||||
rightEditorView.getPaneView().getModel().splitDown(copyActiveItem: true)
|
||||
lowerRightEditorView = atom.workspaceView.getActiveView()
|
||||
expect(lowerRightEditorView.find(".line:first").text()).toBe " "
|
||||
|
||||
describe ".eachEditorView(callback)", ->
|
||||
beforeEach ->
|
||||
atom.workspaceView.attachToDom()
|
||||
|
||||
it "invokes the callback for existing editor", ->
|
||||
count = 0
|
||||
callbackEditor = null
|
||||
callback = (editor) ->
|
||||
callbackEditor = editor
|
||||
count++
|
||||
atom.workspaceView.eachEditorView(callback)
|
||||
expect(count).toBe 1
|
||||
expect(callbackEditor).toBe atom.workspaceView.getActiveView()
|
||||
|
||||
it "invokes the callback for new editor", ->
|
||||
count = 0
|
||||
callbackEditor = null
|
||||
callback = (editor) ->
|
||||
callbackEditor = editor
|
||||
count++
|
||||
|
||||
atom.workspaceView.eachEditorView(callback)
|
||||
count = 0
|
||||
callbackEditor = null
|
||||
atom.workspaceView.getActiveView().getPaneView().getModel().splitRight(copyActiveItem: true)
|
||||
expect(count).toBe 1
|
||||
expect(callbackEditor).toBe atom.workspaceView.getActiveView()
|
||||
|
||||
it "does not invoke the callback for mini editors", ->
|
||||
editorViewCreatedHandler = jasmine.createSpy('editorViewCreatedHandler')
|
||||
atom.workspaceView.eachEditorView(editorViewCreatedHandler)
|
||||
editorViewCreatedHandler.reset()
|
||||
miniEditor = new TextEditorView(mini: true)
|
||||
atom.workspaceView.append(miniEditor)
|
||||
expect(editorViewCreatedHandler).not.toHaveBeenCalled()
|
||||
|
||||
it "returns a subscription that can be disabled", ->
|
||||
count = 0
|
||||
callback = (editor) -> count++
|
||||
|
||||
subscription = atom.workspaceView.eachEditorView(callback)
|
||||
expect(count).toBe 1
|
||||
atom.workspaceView.getActiveView().getPaneView().getModel().splitRight(copyActiveItem: true)
|
||||
expect(count).toBe 2
|
||||
subscription.off()
|
||||
atom.workspaceView.getActiveView().getPaneView().getModel().splitRight(copyActiveItem: true)
|
||||
expect(count).toBe 2
|
||||
|
||||
describe "core:close", ->
|
||||
it "closes the active pane item until all that remains is a single empty pane", ->
|
||||
atom.config.set('core.destroyEmptyPanes', true)
|
||||
|
||||
paneView1 = atom.workspaceView.getActivePaneView()
|
||||
editorView = atom.workspaceView.getActiveView()
|
||||
editorView.getPaneView().getModel().splitRight(copyActiveItem: true)
|
||||
paneView2 = atom.workspaceView.getActivePaneView()
|
||||
|
||||
expect(paneView1).not.toBe paneView2
|
||||
expect(atom.workspaceView.getPaneViews()).toHaveLength 2
|
||||
atom.workspaceView.trigger('core:close')
|
||||
|
||||
expect(atom.workspaceView.getActivePaneView().getItems()).toHaveLength 1
|
||||
expect(atom.workspaceView.getPaneViews()).toHaveLength 1
|
||||
atom.workspaceView.trigger('core:close')
|
||||
|
||||
expect(atom.workspaceView.getActivePaneView().getItems()).toHaveLength 0
|
||||
expect(atom.workspaceView.getPaneViews()).toHaveLength 1
|
||||
|
||||
describe "the scrollbar visibility class", ->
|
||||
it "has a class based on the style of the scrollbar", ->
|
||||
style = 'legacy'
|
||||
scrollbarStyle = require 'scrollbar-style'
|
||||
spyOn(scrollbarStyle, 'getPreferredScrollbarStyle').andCallFake -> style
|
||||
|
||||
atom.workspaceView.element.observeScrollbarStyle()
|
||||
expect(atom.workspaceView).toHaveClass 'scrollbars-visible-always'
|
||||
|
||||
style = 'overlay'
|
||||
atom.workspaceView.element.observeScrollbarStyle()
|
||||
expect(atom.workspaceView).toHaveClass 'scrollbars-visible-when-scrolling'
|
||||
|
||||
describe "editor font styling", ->
|
||||
[editorNode, editor] = []
|
||||
|
||||
beforeEach ->
|
||||
atom.workspaceView.attachToDom()
|
||||
editorNode = atom.workspaceView.find('atom-text-editor')[0]
|
||||
editor = atom.workspaceView.find('atom-text-editor').view().getEditor()
|
||||
|
||||
it "updates the font-size based on the 'editor.fontSize' config value", ->
|
||||
initialCharWidth = editor.getDefaultCharWidth()
|
||||
expect(getComputedStyle(editorNode).fontSize).toBe atom.config.get('editor.fontSize') + 'px'
|
||||
atom.config.set('editor.fontSize', atom.config.get('editor.fontSize') + 5)
|
||||
expect(getComputedStyle(editorNode).fontSize).toBe atom.config.get('editor.fontSize') + 'px'
|
||||
expect(editor.getDefaultCharWidth()).toBeGreaterThan initialCharWidth
|
||||
|
||||
it "updates the font-family based on the 'editor.fontFamily' config value", ->
|
||||
initialCharWidth = editor.getDefaultCharWidth()
|
||||
expect(getComputedStyle(editorNode).fontFamily).toBe atom.config.get('editor.fontFamily')
|
||||
atom.config.set('editor.fontFamily', 'sans-serif')
|
||||
expect(getComputedStyle(editorNode).fontFamily).toBe atom.config.get('editor.fontFamily')
|
||||
expect(editor.getDefaultCharWidth()).not.toBe initialCharWidth
|
||||
|
||||
it "updates the line-height based on the 'editor.lineHeight' config value", ->
|
||||
initialLineHeight = editor.getLineHeightInPixels()
|
||||
atom.config.set('editor.lineHeight', '30px')
|
||||
expect(getComputedStyle(editorNode).lineHeight).toBe atom.config.get('editor.lineHeight')
|
||||
expect(editor.getLineHeightInPixels()).not.toBe initialLineHeight
|
||||
|
||||
describe 'panel containers', ->
|
||||
workspaceElement = null
|
||||
beforeEach ->
|
||||
workspaceElement = atom.views.getView(atom.workspace)
|
||||
|
||||
it 'inserts panel container elements in the correct places in the DOM', ->
|
||||
leftContainer = workspaceElement.querySelector('atom-panel-container.left')
|
||||
rightContainer = workspaceElement.querySelector('atom-panel-container.right')
|
||||
expect(leftContainer.nextSibling).toBe workspaceElement.verticalAxis
|
||||
expect(rightContainer.previousSibling).toBe workspaceElement.verticalAxis
|
||||
|
||||
topContainer = workspaceElement.querySelector('atom-panel-container.top')
|
||||
bottomContainer = workspaceElement.querySelector('atom-panel-container.bottom')
|
||||
expect(topContainer.nextSibling).toBe workspaceElement.paneContainer
|
||||
expect(bottomContainer.previousSibling).toBe workspaceElement.paneContainer
|
||||
|
||||
modalContainer = workspaceElement.querySelector('atom-panel-container.modal')
|
||||
expect(modalContainer.parentNode).toBe workspaceElement
|
||||
Reference in New Issue
Block a user