mirror of
https://github.com/atom/atom.git
synced 2026-02-16 01:25:13 -05:00
Merge pull request #18896 from rafeca/add-linting-to-specs
Add linter to spec/ folder
This commit is contained in:
@@ -6,29 +6,46 @@ const path = require('path')
|
||||
|
||||
const CONFIG = require('../config')
|
||||
|
||||
module.exports = function () {
|
||||
module.exports = async function () {
|
||||
const globPathsToLint = [
|
||||
path.join(CONFIG.repositoryRootPath, 'exports', '**', '*.js'),
|
||||
path.join(CONFIG.repositoryRootPath, 'packages', '**', '*.js'),
|
||||
path.join(CONFIG.repositoryRootPath, 'script', '**', '*.js'),
|
||||
path.join(CONFIG.repositoryRootPath, 'spec', '**', '*.js'),
|
||||
path.join(CONFIG.repositoryRootPath, 'src', '**', '*.js'),
|
||||
path.join(CONFIG.repositoryRootPath, 'static', '*.js')
|
||||
]
|
||||
return expandGlobPaths(globPathsToLint).then((paths) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
standard.lintFiles(paths, (error, lintOutput) => {
|
||||
if (error) {
|
||||
reject(error)
|
||||
} else {
|
||||
const errors = []
|
||||
for (let result of lintOutput.results) {
|
||||
for (let message of result.messages) {
|
||||
errors.push({path: result.filePath, lineNumber: message.line, message: message.message, rule: message.ruleId})
|
||||
}
|
||||
const globPathsToIgnore = [
|
||||
path.join(CONFIG.repositoryRootPath, 'spec', 'fixtures', '**', '*.js')
|
||||
]
|
||||
|
||||
const [includePaths, excludePaths] = await Promise.all([
|
||||
expandGlobPaths(globPathsToLint),
|
||||
expandGlobPaths(globPathsToIgnore)
|
||||
])
|
||||
|
||||
const paths = includePaths.filter(
|
||||
myPath => !excludePaths.includes(myPath)
|
||||
)
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
standard.lintFiles(paths, (error, lintOutput) => {
|
||||
if (error) {
|
||||
reject(error)
|
||||
} else {
|
||||
const errors = []
|
||||
for (let result of lintOutput.results) {
|
||||
for (let message of result.messages) {
|
||||
errors.push({
|
||||
path: result.filePath,
|
||||
lineNumber: message.line,
|
||||
message: message.message,
|
||||
rule: message.ruleId
|
||||
})
|
||||
}
|
||||
resolve(errors)
|
||||
}
|
||||
})
|
||||
resolve(errors)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
/** @babel */
|
||||
|
||||
import {it, fit, ffit, fffit, beforeEach, afterEach} from './async-spec-helpers'
|
||||
import { it } from './async-spec-helpers'
|
||||
import ApplicationDelegate from '../src/application-delegate'
|
||||
|
||||
describe('ApplicationDelegate', function () {
|
||||
describe('set/getTemporaryWindowState', function () {
|
||||
it('can serialize object trees containing redundant child object references', async function () {
|
||||
const applicationDelegate = new ApplicationDelegate()
|
||||
const childObject = {c: 1}
|
||||
const sentObject = {a: childObject, b: childObject}
|
||||
const childObject = { c: 1 }
|
||||
const sentObject = { a: childObject, b: childObject }
|
||||
|
||||
await applicationDelegate.setTemporaryWindowState(sentObject)
|
||||
const receivedObject = await applicationDelegate.getTemporaryWindowState()
|
||||
|
||||
@@ -32,7 +32,10 @@ function afterEach (fn) {
|
||||
}
|
||||
})
|
||||
|
||||
async function conditionPromise (condition, description = 'anonymous condition') {
|
||||
async function conditionPromise (
|
||||
condition,
|
||||
description = 'anonymous condition'
|
||||
) {
|
||||
const startTime = Date.now()
|
||||
|
||||
while (true) {
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
const {it, fit, ffit, beforeEach, afterEach, conditionPromise} = require('./async-spec-helpers')
|
||||
const _ = require('underscore-plus')
|
||||
const {
|
||||
it,
|
||||
beforeEach,
|
||||
afterEach,
|
||||
conditionPromise
|
||||
} = require('./async-spec-helpers')
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const temp = require('temp').track()
|
||||
@@ -15,26 +19,26 @@ describe('AtomEnvironment', () => {
|
||||
describe('window sizing methods', () => {
|
||||
describe('::getPosition and ::setPosition', () => {
|
||||
let originalPosition = null
|
||||
beforeEach(() => originalPosition = atom.getPosition())
|
||||
beforeEach(() => (originalPosition = atom.getPosition()))
|
||||
|
||||
afterEach(() => atom.setPosition(originalPosition.x, originalPosition.y))
|
||||
|
||||
it('sets the position of the window, and can retrieve the position just set', () => {
|
||||
atom.setPosition(22, 45)
|
||||
expect(atom.getPosition()).toEqual({x: 22, y: 45})
|
||||
expect(atom.getPosition()).toEqual({ x: 22, y: 45 })
|
||||
})
|
||||
})
|
||||
|
||||
describe('::getSize and ::setSize', () => {
|
||||
let originalSize = null
|
||||
beforeEach(() => originalSize = atom.getSize())
|
||||
beforeEach(() => (originalSize = atom.getSize()))
|
||||
afterEach(() => atom.setSize(originalSize.width, originalSize.height))
|
||||
|
||||
it('sets the size of the window, and can retrieve the size just set', async () => {
|
||||
const newWidth = originalSize.width - 12
|
||||
const newHeight = originalSize.height - 23
|
||||
await atom.setSize(newWidth, newHeight)
|
||||
expect(atom.getSize()).toEqual({width: newWidth, height: newHeight})
|
||||
expect(atom.getSize()).toEqual({ width: newWidth, height: newHeight })
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -67,9 +71,9 @@ describe('AtomEnvironment', () => {
|
||||
|
||||
it('will open the dev tools when an error is triggered', async () => {
|
||||
try {
|
||||
a + 1
|
||||
a + 1 // eslint-disable-line no-undef
|
||||
} catch (e) {
|
||||
window.onerror.call(window, e.toString(), 'abc', 2, 3, e)
|
||||
window.onerror(e.toString(), 'abc', 2, 3, e)
|
||||
}
|
||||
|
||||
await devToolsPromise
|
||||
@@ -88,10 +92,10 @@ describe('AtomEnvironment', () => {
|
||||
let error = null
|
||||
atom.onWillThrowError(willThrowSpy)
|
||||
try {
|
||||
a + 1
|
||||
a + 1 // eslint-disable-line no-undef
|
||||
} catch (e) {
|
||||
error = e
|
||||
window.onerror.call(window, e.toString(), 'abc', 2, 3, e)
|
||||
window.onerror(e.toString(), 'abc', 2, 3, e)
|
||||
}
|
||||
|
||||
delete willThrowSpy.mostRecentCall.args[0].preventDefault
|
||||
@@ -109,9 +113,9 @@ describe('AtomEnvironment', () => {
|
||||
atom.onWillThrowError(willThrowSpy)
|
||||
|
||||
try {
|
||||
a + 1
|
||||
a + 1 // eslint-disable-line no-undef
|
||||
} catch (e) {
|
||||
window.onerror.call(window, e.toString(), 'abc', 2, 3, e)
|
||||
window.onerror(e.toString(), 'abc', 2, 3, e)
|
||||
}
|
||||
|
||||
expect(willThrowSpy).toHaveBeenCalled()
|
||||
@@ -122,16 +126,16 @@ describe('AtomEnvironment', () => {
|
||||
|
||||
describe('::onDidThrowError', () => {
|
||||
let didThrowSpy = null
|
||||
beforeEach(() => didThrowSpy = jasmine.createSpy())
|
||||
beforeEach(() => (didThrowSpy = jasmine.createSpy()))
|
||||
|
||||
it('is called when there is an error', () => {
|
||||
let error = null
|
||||
atom.onDidThrowError(didThrowSpy)
|
||||
try {
|
||||
a + 1
|
||||
a + 1 // eslint-disable-line no-undef
|
||||
} catch (e) {
|
||||
error = e
|
||||
window.onerror.call(window, e.toString(), 'abc', 2, 3, e)
|
||||
window.onerror(e.toString(), 'abc', 2, 3, e)
|
||||
}
|
||||
expect(didThrowSpy).toHaveBeenCalledWith({
|
||||
message: error.toString(),
|
||||
@@ -165,22 +169,24 @@ describe('AtomEnvironment', () => {
|
||||
describe('if passed a callback function', () => {
|
||||
it("calls the callback with the assertion failure's error object", () => {
|
||||
let error = null
|
||||
atom.assert(false, 'a == b', e => error = e)
|
||||
atom.assert(false, 'a == b', e => (error = e))
|
||||
expect(error).toBe(errors[0])
|
||||
})
|
||||
})
|
||||
|
||||
describe('if passed metadata', () => {
|
||||
it("assigns the metadata on the assertion failure's error object", () => {
|
||||
atom.assert(false, 'a == b', {foo: 'bar'})
|
||||
expect(errors[0].metadata).toEqual({foo: 'bar'})
|
||||
atom.assert(false, 'a == b', { foo: 'bar' })
|
||||
expect(errors[0].metadata).toEqual({ foo: 'bar' })
|
||||
})
|
||||
})
|
||||
|
||||
describe('when Atom has been built from source', () => {
|
||||
it('throws an error', () => {
|
||||
atom.isReleasedVersion.andReturn(false)
|
||||
expect(() => atom.assert(false, 'testing')).toThrow('Assertion failed: testing')
|
||||
expect(() => atom.assert(false, 'testing')).toThrow(
|
||||
'Assertion failed: testing'
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -195,9 +201,9 @@ describe('AtomEnvironment', () => {
|
||||
})
|
||||
|
||||
describe('saving and loading', () => {
|
||||
beforeEach(() => atom.enablePersistence = true)
|
||||
beforeEach(() => (atom.enablePersistence = true))
|
||||
|
||||
afterEach(() => atom.enablePersistence = false)
|
||||
afterEach(() => (atom.enablePersistence = false))
|
||||
|
||||
it('selects the state based on the current project paths', async () => {
|
||||
jasmine.useRealClock()
|
||||
@@ -210,7 +216,7 @@ describe('AtomEnvironment', () => {
|
||||
})
|
||||
|
||||
spyOn(atom, 'getLoadSettings').andCallFake(() => loadSettings)
|
||||
spyOn(atom, 'serialize').andReturn({stuff: 'cool'})
|
||||
spyOn(atom, 'serialize').andReturn({ stuff: 'cool' })
|
||||
|
||||
atom.project.setPaths([dir1, dir2])
|
||||
|
||||
@@ -221,7 +227,7 @@ describe('AtomEnvironment', () => {
|
||||
expect(await atom.loadState()).toBeFalsy()
|
||||
|
||||
loadSettings.initialPaths = [dir2, dir1]
|
||||
expect(await atom.loadState()).toEqual({stuff: 'cool'})
|
||||
expect(await atom.loadState()).toEqual({ stuff: 'cool' })
|
||||
})
|
||||
|
||||
it('saves state when the CPU is idle after a keydown or mousedown event', () => {
|
||||
@@ -231,7 +237,9 @@ describe('AtomEnvironment', () => {
|
||||
const idleCallbacks = []
|
||||
atomEnv.initialize({
|
||||
window: {
|
||||
requestIdleCallback (callback) { idleCallbacks.push(callback) },
|
||||
requestIdleCallback (callback) {
|
||||
idleCallbacks.push(callback)
|
||||
},
|
||||
addEventListener () {},
|
||||
removeEventListener () {}
|
||||
},
|
||||
@@ -244,16 +252,16 @@ describe('AtomEnvironment', () => {
|
||||
atomEnv.document.dispatchEvent(keydown)
|
||||
advanceClock(atomEnv.saveStateDebounceInterval)
|
||||
idleCallbacks.shift()()
|
||||
expect(atomEnv.saveState).toHaveBeenCalledWith({isUnloading: false})
|
||||
expect(atomEnv.saveState).not.toHaveBeenCalledWith({isUnloading: true})
|
||||
expect(atomEnv.saveState).toHaveBeenCalledWith({ isUnloading: false })
|
||||
expect(atomEnv.saveState).not.toHaveBeenCalledWith({ isUnloading: true })
|
||||
|
||||
atomEnv.saveState.reset()
|
||||
const mousedown = new MouseEvent('mousedown')
|
||||
atomEnv.document.dispatchEvent(mousedown)
|
||||
advanceClock(atomEnv.saveStateDebounceInterval)
|
||||
idleCallbacks.shift()()
|
||||
expect(atomEnv.saveState).toHaveBeenCalledWith({isUnloading: false})
|
||||
expect(atomEnv.saveState).not.toHaveBeenCalledWith({isUnloading: true})
|
||||
expect(atomEnv.saveState).toHaveBeenCalledWith({ isUnloading: false })
|
||||
expect(atomEnv.saveState).not.toHaveBeenCalledWith({ isUnloading: true })
|
||||
|
||||
atomEnv.destroy()
|
||||
})
|
||||
@@ -265,7 +273,9 @@ describe('AtomEnvironment', () => {
|
||||
const idleCallbacks = []
|
||||
atomEnv.initialize({
|
||||
window: {
|
||||
requestIdleCallback (callback) { idleCallbacks.push(callback) },
|
||||
requestIdleCallback (callback) {
|
||||
idleCallbacks.push(callback)
|
||||
},
|
||||
addEventListener () {},
|
||||
removeEventListener () {}
|
||||
},
|
||||
@@ -278,7 +288,7 @@ describe('AtomEnvironment', () => {
|
||||
atomEnv.document.dispatchEvent(mousedown)
|
||||
expect(atomEnv.saveState).not.toHaveBeenCalled()
|
||||
await atomEnv.prepareToUnloadEditorWindow()
|
||||
expect(atomEnv.saveState).toHaveBeenCalledWith({isUnloading: true})
|
||||
expect(atomEnv.saveState).toHaveBeenCalledWith({ isUnloading: true })
|
||||
|
||||
advanceClock(atomEnv.saveStateDebounceInterval)
|
||||
idleCallbacks.shift()()
|
||||
@@ -294,11 +304,13 @@ describe('AtomEnvironment', () => {
|
||||
})
|
||||
|
||||
it('serializes the project state with all the options supplied in saveState', async () => {
|
||||
spyOn(atom.project, 'serialize').andReturn({foo: 42})
|
||||
spyOn(atom.project, 'serialize').andReturn({ foo: 42 })
|
||||
|
||||
await atom.saveState({anyOption: 'any option'})
|
||||
await atom.saveState({ anyOption: 'any option' })
|
||||
expect(atom.project.serialize.calls.length).toBe(1)
|
||||
expect(atom.project.serialize.mostRecentCall.args[0]).toEqual({anyOption: 'any option'})
|
||||
expect(atom.project.serialize.mostRecentCall.args[0]).toEqual({
|
||||
anyOption: 'any option'
|
||||
})
|
||||
})
|
||||
|
||||
it('serializes the text editor registry', async () => {
|
||||
@@ -309,20 +321,22 @@ describe('AtomEnvironment', () => {
|
||||
const atom2 = new AtomEnvironment({
|
||||
applicationDelegate: atom.applicationDelegate,
|
||||
window: document.createElement('div'),
|
||||
document: Object.assign(
|
||||
document.createElement('div'),
|
||||
{
|
||||
body: document.createElement('div'),
|
||||
head: document.createElement('div')
|
||||
}
|
||||
)
|
||||
document: Object.assign(document.createElement('div'), {
|
||||
body: document.createElement('div'),
|
||||
head: document.createElement('div')
|
||||
})
|
||||
})
|
||||
atom2.initialize({document, window})
|
||||
atom2.initialize({ document, window })
|
||||
|
||||
await atom2.deserialize(atom.serialize())
|
||||
await atom2.packages.activatePackage('language-text')
|
||||
const editor2 = atom2.workspace.getActiveTextEditor()
|
||||
expect(editor2.getBuffer().getLanguageMode().getLanguageId()).toBe('text.plain')
|
||||
expect(
|
||||
editor2
|
||||
.getBuffer()
|
||||
.getLanguageMode()
|
||||
.getLanguageId()
|
||||
).toBe('text.plain')
|
||||
atom2.destroy()
|
||||
})
|
||||
|
||||
@@ -335,10 +349,13 @@ describe('AtomEnvironment', () => {
|
||||
})
|
||||
spyOn(atom.notifications, 'addError')
|
||||
|
||||
await atom.deserialize({project: 'should work'})
|
||||
expect(atom.notifications.addError).toHaveBeenCalledWith('Unable to open project directory', {
|
||||
description: 'Project directory `/foo` is no longer on disk.'
|
||||
})
|
||||
await atom.deserialize({ project: 'should work' })
|
||||
expect(atom.notifications.addError).toHaveBeenCalledWith(
|
||||
'Unable to open project directory',
|
||||
{
|
||||
description: 'Project directory `/foo` is no longer on disk.'
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
it('accumulates and reports two errors with one notification', async () => {
|
||||
@@ -349,10 +366,14 @@ describe('AtomEnvironment', () => {
|
||||
})
|
||||
spyOn(atom.notifications, 'addError')
|
||||
|
||||
await atom.deserialize({project: 'should work'})
|
||||
expect(atom.notifications.addError).toHaveBeenCalledWith('Unable to open 2 project directories', {
|
||||
description: 'Project directories `/foo` and `/wat` are no longer on disk.'
|
||||
})
|
||||
await atom.deserialize({ project: 'should work' })
|
||||
expect(atom.notifications.addError).toHaveBeenCalledWith(
|
||||
'Unable to open 2 project directories',
|
||||
{
|
||||
description:
|
||||
'Project directories `/foo` and `/wat` are no longer on disk.'
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
it('accumulates and reports three+ errors with one notification', async () => {
|
||||
@@ -363,17 +384,23 @@ describe('AtomEnvironment', () => {
|
||||
})
|
||||
spyOn(atom.notifications, 'addError')
|
||||
|
||||
await atom.deserialize({project: 'should work'})
|
||||
expect(atom.notifications.addError).toHaveBeenCalledWith('Unable to open 4 project directories', {
|
||||
description: 'Project directories `/foo`, `/wat`, `/stuff`, and `/things` are no longer on disk.'
|
||||
})
|
||||
await atom.deserialize({ project: 'should work' })
|
||||
expect(atom.notifications.addError).toHaveBeenCalledWith(
|
||||
'Unable to open 4 project directories',
|
||||
{
|
||||
description:
|
||||
'Project directories `/foo`, `/wat`, `/stuff`, and `/things` are no longer on disk.'
|
||||
}
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('openInitialEmptyEditorIfNecessary', () => {
|
||||
describe('when there are no paths set', () => {
|
||||
beforeEach(() => spyOn(atom, 'getLoadSettings').andReturn({initialPaths: []}))
|
||||
beforeEach(() =>
|
||||
spyOn(atom, 'getLoadSettings').andReturn({ initialPaths: [] })
|
||||
)
|
||||
|
||||
it('opens an empty buffer', () => {
|
||||
spyOn(atom.workspace, 'open')
|
||||
@@ -396,7 +423,9 @@ describe('AtomEnvironment', () => {
|
||||
|
||||
describe('when the project has a path', () => {
|
||||
beforeEach(() => {
|
||||
spyOn(atom, 'getLoadSettings').andReturn({initialPaths: ['something']})
|
||||
spyOn(atom, 'getLoadSettings').andReturn({
|
||||
initialPaths: ['something']
|
||||
})
|
||||
spyOn(atom.workspace, 'open')
|
||||
})
|
||||
|
||||
@@ -410,7 +439,6 @@ describe('AtomEnvironment', () => {
|
||||
describe('adding a project folder', () => {
|
||||
it('does nothing if the user dismisses the file picker', () => {
|
||||
const initialPaths = atom.project.getPaths()
|
||||
const tempDirectory = temp.mkdirSync('a-new-directory')
|
||||
spyOn(atom, 'pickFolder').andCallFake(callback => callback(null))
|
||||
atom.addProjectFolder()
|
||||
expect(atom.project.getPaths()).toEqual(initialPaths)
|
||||
@@ -423,9 +451,11 @@ describe('AtomEnvironment', () => {
|
||||
})
|
||||
|
||||
it('adds the selected folder to the project', async () => {
|
||||
const initialPaths = atom.project.setPaths([])
|
||||
atom.project.setPaths([])
|
||||
const tempDirectory = temp.mkdirSync('a-new-directory')
|
||||
spyOn(atom, 'pickFolder').andCallFake(callback => callback([tempDirectory]))
|
||||
spyOn(atom, 'pickFolder').andCallFake(callback =>
|
||||
callback([tempDirectory])
|
||||
)
|
||||
await atom.addProjectFolder()
|
||||
expect(atom.project.getPaths()).toEqual([tempDirectory])
|
||||
expect(atom.attemptRestoreProjectStateForPaths).not.toHaveBeenCalled()
|
||||
@@ -437,7 +467,9 @@ describe('AtomEnvironment', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
spyOn(atom, 'getStateKey').andCallFake(dirs => dirs.join(':'))
|
||||
spyOn(atom, 'loadState').andCallFake(async (key) => key === __dirname ? state : null)
|
||||
spyOn(atom, 'loadState').andCallFake(async key =>
|
||||
key === __dirname ? state : null
|
||||
)
|
||||
spyOn(atom, 'attemptRestoreProjectStateForPaths')
|
||||
spyOn(atom, 'pickFolder').andCallFake(callback => callback([__dirname]))
|
||||
atom.project.setPaths([])
|
||||
@@ -446,7 +478,10 @@ describe('AtomEnvironment', () => {
|
||||
describe('when there are no project folders', () => {
|
||||
it('attempts to restore the project state', async () => {
|
||||
await atom.addProjectFolder()
|
||||
expect(atom.attemptRestoreProjectStateForPaths).toHaveBeenCalledWith(state, [__dirname])
|
||||
expect(atom.attemptRestoreProjectStateForPaths).toHaveBeenCalledWith(
|
||||
state,
|
||||
[__dirname]
|
||||
)
|
||||
expect(atom.project.getPaths()).toEqual([])
|
||||
})
|
||||
})
|
||||
@@ -481,7 +516,9 @@ describe('AtomEnvironment', () => {
|
||||
fs.writeFileSync(filePath2, 'def')
|
||||
fs.writeFileSync(filePath3, 'ghi')
|
||||
|
||||
const env1 = new AtomEnvironment({applicationDelegate: atom.applicationDelegate})
|
||||
const env1 = new AtomEnvironment({
|
||||
applicationDelegate: atom.applicationDelegate
|
||||
})
|
||||
env1.project.setPaths([projectPath])
|
||||
await env1.workspace.open(filePath1)
|
||||
await env1.workspace.open(filePath2)
|
||||
@@ -489,8 +526,14 @@ describe('AtomEnvironment', () => {
|
||||
const env1State = env1.serialize()
|
||||
env1.destroy()
|
||||
|
||||
const env2 = new AtomEnvironment({applicationDelegate: atom.applicationDelegate})
|
||||
await env2.attemptRestoreProjectStateForPaths(env1State, [projectPath], [filePath2])
|
||||
const env2 = new AtomEnvironment({
|
||||
applicationDelegate: atom.applicationDelegate
|
||||
})
|
||||
await env2.attemptRestoreProjectStateForPaths(
|
||||
env1State,
|
||||
[projectPath],
|
||||
[filePath2]
|
||||
)
|
||||
const restoredURIs = env2.workspace.getPaneItems().map(p => p.getURI())
|
||||
expect(restoredURIs).toEqual([filePath1, filePath2, filePath3])
|
||||
env2.destroy()
|
||||
@@ -500,12 +543,18 @@ describe('AtomEnvironment', () => {
|
||||
it("doesn't prompt the user to restore state", () => {
|
||||
const dock = atom.workspace.getLeftDock()
|
||||
dock.getActivePane().addItem({
|
||||
getTitle () { return 'title' },
|
||||
getTitle () {
|
||||
return 'title'
|
||||
},
|
||||
element: document.createElement('div')
|
||||
})
|
||||
const state = {}
|
||||
spyOn(atom, 'confirm')
|
||||
atom.attemptRestoreProjectStateForPaths(state, [__dirname], [__filename])
|
||||
atom.attemptRestoreProjectStateForPaths(
|
||||
state,
|
||||
[__dirname],
|
||||
[__filename]
|
||||
)
|
||||
expect(atom.confirm).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
@@ -527,7 +576,11 @@ describe('AtomEnvironment', () => {
|
||||
spyOn(atom.project, 'addPath')
|
||||
spyOn(atom.workspace, 'open')
|
||||
const state = Symbol()
|
||||
atom.attemptRestoreProjectStateForPaths(state, [__dirname], [__filename])
|
||||
atom.attemptRestoreProjectStateForPaths(
|
||||
state,
|
||||
[__dirname],
|
||||
[__filename]
|
||||
)
|
||||
expect(atom.confirm).toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
@@ -539,7 +592,11 @@ describe('AtomEnvironment', () => {
|
||||
spyOn(atom.workspace, 'open')
|
||||
const state = Symbol()
|
||||
|
||||
atom.attemptRestoreProjectStateForPaths(state, [__dirname], [__filename])
|
||||
atom.attemptRestoreProjectStateForPaths(
|
||||
state,
|
||||
[__dirname],
|
||||
[__filename]
|
||||
)
|
||||
expect(atom.confirm).toHaveBeenCalled()
|
||||
await conditionPromise(() => atom.project.addPath.callCount === 1)
|
||||
|
||||
@@ -554,7 +611,11 @@ describe('AtomEnvironment', () => {
|
||||
spyOn(atom, 'open')
|
||||
const state = Symbol()
|
||||
|
||||
atom.attemptRestoreProjectStateForPaths(state, [__dirname], [__filename])
|
||||
atom.attemptRestoreProjectStateForPaths(
|
||||
state,
|
||||
[__dirname],
|
||||
[__filename]
|
||||
)
|
||||
expect(atom.confirm).toHaveBeenCalled()
|
||||
await conditionPromise(() => atom.open.callCount === 1)
|
||||
expect(atom.open).toHaveBeenCalledWith({
|
||||
@@ -571,8 +632,16 @@ describe('AtomEnvironment', () => {
|
||||
it('saves the BlobStore so it can be loaded after reload', () => {
|
||||
const configDirPath = temp.mkdirSync('atom-spec-environment')
|
||||
const fakeBlobStore = jasmine.createSpyObj('blob store', ['save'])
|
||||
const atomEnvironment = new AtomEnvironment({applicationDelegate: atom.applicationDelegate, enablePersistence: true})
|
||||
atomEnvironment.initialize({configDirPath, blobStore: fakeBlobStore, window, document})
|
||||
const atomEnvironment = new AtomEnvironment({
|
||||
applicationDelegate: atom.applicationDelegate,
|
||||
enablePersistence: true
|
||||
})
|
||||
atomEnvironment.initialize({
|
||||
configDirPath,
|
||||
blobStore: fakeBlobStore,
|
||||
window,
|
||||
document
|
||||
})
|
||||
|
||||
atomEnvironment.unloadEditorWindow()
|
||||
|
||||
@@ -584,16 +653,19 @@ describe('AtomEnvironment', () => {
|
||||
|
||||
describe('::destroy()', () => {
|
||||
it('does not throw exceptions when unsubscribing from ipc events (regression)', async () => {
|
||||
const configDirPath = temp.mkdirSync('atom-spec-environment')
|
||||
const fakeDocument = {
|
||||
addEventListener () {},
|
||||
removeEventListener () {},
|
||||
head: document.createElement('head'),
|
||||
body: document.createElement('body')
|
||||
}
|
||||
const atomEnvironment = new AtomEnvironment({applicationDelegate: atom.applicationDelegate})
|
||||
atomEnvironment.initialize({window, document: fakeDocument})
|
||||
spyOn(atomEnvironment.packages, 'loadPackages').andReturn(Promise.resolve())
|
||||
const atomEnvironment = new AtomEnvironment({
|
||||
applicationDelegate: atom.applicationDelegate
|
||||
})
|
||||
atomEnvironment.initialize({ window, document: fakeDocument })
|
||||
spyOn(atomEnvironment.packages, 'loadPackages').andReturn(
|
||||
Promise.resolve()
|
||||
)
|
||||
spyOn(atomEnvironment.packages, 'activate').andReturn(Promise.resolve())
|
||||
spyOn(atomEnvironment, 'displayWindow').andReturn(Promise.resolve())
|
||||
await atomEnvironment.startEditorWindow()
|
||||
@@ -606,17 +678,21 @@ describe('AtomEnvironment', () => {
|
||||
let atomEnvironment, envLoaded, spy
|
||||
|
||||
beforeEach(() => {
|
||||
let resolve = null
|
||||
const promise = new Promise((r) => { resolve = r })
|
||||
let resolvePromise = null
|
||||
const promise = new Promise(resolve => {
|
||||
resolvePromise = resolve
|
||||
})
|
||||
envLoaded = () => {
|
||||
resolve()
|
||||
resolvePromise()
|
||||
return promise
|
||||
}
|
||||
atomEnvironment = new AtomEnvironment({
|
||||
applicationDelegate: atom.applicationDelegate,
|
||||
updateProcessEnv () { return promise }
|
||||
updateProcessEnv () {
|
||||
return promise
|
||||
}
|
||||
})
|
||||
atomEnvironment.initialize({window, document})
|
||||
atomEnvironment.initialize({ window, document })
|
||||
spy = jasmine.createSpy()
|
||||
})
|
||||
|
||||
@@ -650,23 +726,30 @@ describe('AtomEnvironment', () => {
|
||||
describe('when the opened path exists', () => {
|
||||
it('opens a file', async () => {
|
||||
const pathToOpen = __filename
|
||||
await atom.openLocations([{pathToOpen}])
|
||||
await atom.openLocations([{ pathToOpen }])
|
||||
expect(atom.project.getPaths()).toEqual([])
|
||||
})
|
||||
|
||||
it('opens a directory as a project folder', async () => {
|
||||
const pathToOpen = __dirname
|
||||
await atom.openLocations([{pathToOpen}])
|
||||
expect(atom.workspace.getTextEditors().map(e => e.getPath())).toEqual([])
|
||||
await atom.openLocations([{ pathToOpen }])
|
||||
expect(atom.workspace.getTextEditors().map(e => e.getPath())).toEqual(
|
||||
[]
|
||||
)
|
||||
expect(atom.project.getPaths()).toEqual([pathToOpen])
|
||||
})
|
||||
})
|
||||
|
||||
describe('when the opened path does not exist', () => {
|
||||
it('opens it as a new file', async () => {
|
||||
const pathToOpen = path.join(__dirname, 'this-path-does-not-exist.txt')
|
||||
await atom.openLocations([{pathToOpen}])
|
||||
expect(atom.workspace.getTextEditors().map(e => e.getPath())).toEqual([pathToOpen])
|
||||
const pathToOpen = path.join(
|
||||
__dirname,
|
||||
'this-path-does-not-exist.txt'
|
||||
)
|
||||
await atom.openLocations([{ pathToOpen }])
|
||||
expect(atom.workspace.getTextEditors().map(e => e.getPath())).toEqual(
|
||||
[pathToOpen]
|
||||
)
|
||||
expect(atom.project.getPaths()).toEqual([])
|
||||
})
|
||||
|
||||
@@ -678,9 +761,9 @@ describe('AtomEnvironment', () => {
|
||||
const existingDir = path.join(__dirname, 'fixtures')
|
||||
|
||||
await atom.openLocations([
|
||||
{pathToOpen: nonExistent, mustBeDirectory: true},
|
||||
{pathToOpen: existingFile, mustBeDirectory: true},
|
||||
{pathToOpen: existingDir, mustBeDirectory: true}
|
||||
{ pathToOpen: nonExistent, mustBeDirectory: true },
|
||||
{ pathToOpen: existingFile, mustBeDirectory: true },
|
||||
{ pathToOpen: existingDir, mustBeDirectory: true }
|
||||
])
|
||||
|
||||
expect(atom.workspace.getTextEditors()).toEqual([])
|
||||
@@ -688,7 +771,9 @@ describe('AtomEnvironment', () => {
|
||||
|
||||
expect(atom.notifications.addWarning).toHaveBeenCalledWith(
|
||||
'Unable to open project folders',
|
||||
{description: `The directories \`${nonExistent}\` and \`${existingFile}\` do not exist.`}
|
||||
{
|
||||
description: `The directories \`${nonExistent}\` and \`${existingFile}\` do not exist.`
|
||||
}
|
||||
)
|
||||
})
|
||||
})
|
||||
@@ -697,15 +782,23 @@ describe('AtomEnvironment', () => {
|
||||
let serviceDisposable
|
||||
|
||||
beforeEach(() => {
|
||||
serviceDisposable = atom.packages.serviceHub.provide('atom.directory-provider', '0.1.0', {
|
||||
directoryForURISync (uri) {
|
||||
if (uri.startsWith('remote://')) {
|
||||
return { getPath() { return uri } }
|
||||
} else {
|
||||
return null
|
||||
serviceDisposable = atom.packages.serviceHub.provide(
|
||||
'atom.directory-provider',
|
||||
'0.1.0',
|
||||
{
|
||||
directoryForURISync (uri) {
|
||||
if (uri.startsWith('remote://')) {
|
||||
return {
|
||||
getPath () {
|
||||
return uri
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
waitsFor(() => atom.project.directoryProviders.length > 0)
|
||||
})
|
||||
@@ -717,7 +810,7 @@ describe('AtomEnvironment', () => {
|
||||
it("adds it to the project's paths as is", async () => {
|
||||
const pathToOpen = 'remote://server:7644/some/dir/path'
|
||||
spyOn(atom.project, 'addPath')
|
||||
await atom.openLocations([{pathToOpen}])
|
||||
await atom.openLocations([{ pathToOpen }])
|
||||
expect(atom.project.addPath).toHaveBeenCalledWith(pathToOpen)
|
||||
})
|
||||
})
|
||||
@@ -729,7 +822,11 @@ describe('AtomEnvironment', () => {
|
||||
beforeEach(() => {
|
||||
spyOn(atom, 'getStateKey').andCallFake(dirs => dirs.join(':'))
|
||||
spyOn(atom, 'loadState').andCallFake(function (key) {
|
||||
if (key === __dirname) { return Promise.resolve(state) } else { return Promise.resolve(null) }
|
||||
if (key === __dirname) {
|
||||
return Promise.resolve(state)
|
||||
} else {
|
||||
return Promise.resolve(null)
|
||||
}
|
||||
})
|
||||
spyOn(atom, 'attemptRestoreProjectStateForPaths')
|
||||
})
|
||||
@@ -737,8 +834,12 @@ describe('AtomEnvironment', () => {
|
||||
describe('when there are no project folders', () => {
|
||||
it('attempts to restore the project state', async () => {
|
||||
const pathToOpen = __dirname
|
||||
await atom.openLocations([{pathToOpen}])
|
||||
expect(atom.attemptRestoreProjectStateForPaths).toHaveBeenCalledWith(state, [pathToOpen], [])
|
||||
await atom.openLocations([{ pathToOpen }])
|
||||
expect(atom.attemptRestoreProjectStateForPaths).toHaveBeenCalledWith(
|
||||
state,
|
||||
[pathToOpen],
|
||||
[]
|
||||
)
|
||||
expect(atom.project.getPaths()).toEqual([])
|
||||
})
|
||||
|
||||
@@ -755,17 +856,28 @@ describe('AtomEnvironment', () => {
|
||||
})
|
||||
|
||||
await atom.openLocations([
|
||||
{pathToOpen: existingDir},
|
||||
{pathToOpen: missingDir, mustBeDirectory: true}
|
||||
{ pathToOpen: existingDir },
|
||||
{ pathToOpen: missingDir, mustBeDirectory: true }
|
||||
])
|
||||
|
||||
expect(atom.attemptRestoreProjectStateForPaths).toHaveBeenCalledWith(state, [existingDir], [])
|
||||
expect(atom.attemptRestoreProjectStateForPaths).toHaveBeenCalledWith(
|
||||
state,
|
||||
[existingDir],
|
||||
[]
|
||||
)
|
||||
expect(atom.project.getPaths(), [existingDir])
|
||||
})
|
||||
|
||||
it('opens the specified files', async () => {
|
||||
await atom.openLocations([{pathToOpen: __dirname}, {pathToOpen: __filename}])
|
||||
expect(atom.attemptRestoreProjectStateForPaths).toHaveBeenCalledWith(state, [__dirname], [__filename])
|
||||
await atom.openLocations([
|
||||
{ pathToOpen: __dirname },
|
||||
{ pathToOpen: __filename }
|
||||
])
|
||||
expect(atom.attemptRestoreProjectStateForPaths).toHaveBeenCalledWith(
|
||||
state,
|
||||
[__dirname],
|
||||
[__filename]
|
||||
)
|
||||
expect(atom.project.getPaths()).toEqual([])
|
||||
})
|
||||
})
|
||||
@@ -775,7 +887,7 @@ describe('AtomEnvironment', () => {
|
||||
|
||||
it('does not attempt to restore the project state, instead adding the project paths', async () => {
|
||||
const pathToOpen = path.join(__dirname, 'fixtures')
|
||||
await atom.openLocations([{pathToOpen, forceAddToWindow: true}])
|
||||
await atom.openLocations([{ pathToOpen, forceAddToWindow: true }])
|
||||
expect(atom.attemptRestoreProjectStateForPaths).not.toHaveBeenCalled()
|
||||
expect(atom.project.getPaths()).toEqual([__dirname, pathToOpen])
|
||||
})
|
||||
@@ -783,8 +895,10 @@ describe('AtomEnvironment', () => {
|
||||
it('opens the specified files', async () => {
|
||||
const pathToOpen = path.join(__dirname, 'fixtures')
|
||||
const fileToOpen = path.join(pathToOpen, 'michelle-is-awesome.txt')
|
||||
await atom.openLocations([{pathToOpen}, {pathToOpen: fileToOpen}])
|
||||
expect(atom.attemptRestoreProjectStateForPaths).not.toHaveBeenCalledWith(state, [pathToOpen], [fileToOpen])
|
||||
await atom.openLocations([{ pathToOpen }, { pathToOpen: fileToOpen }])
|
||||
expect(
|
||||
atom.attemptRestoreProjectStateForPaths
|
||||
).not.toHaveBeenCalledWith(state, [pathToOpen], [fileToOpen])
|
||||
expect(atom.project.getPaths()).toEqual([__dirname, pathToOpen])
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
/** @babel */
|
||||
|
||||
import {it, fit, ffit, fffit, beforeEach, afterEach} from './async-spec-helpers'
|
||||
import {app} from 'remote'
|
||||
import { it, beforeEach, afterEach } from './async-spec-helpers'
|
||||
import { app } from 'remote'
|
||||
import atomPaths from '../src/atom-paths'
|
||||
import fs from 'fs-plus'
|
||||
import path from 'path'
|
||||
const temp = require('temp').track()
|
||||
|
||||
describe("AtomPaths", () => {
|
||||
const portableAtomHomePath = path.join(atomPaths.getAppDirectory(), '..', '.atom')
|
||||
describe('AtomPaths', () => {
|
||||
const portableAtomHomePath = path.join(
|
||||
atomPaths.getAppDirectory(),
|
||||
'..',
|
||||
'.atom'
|
||||
)
|
||||
|
||||
afterEach(() => {
|
||||
atomPaths.setAtomHome(app.getPath('home'))
|
||||
@@ -18,8 +22,9 @@ describe("AtomPaths", () => {
|
||||
describe('when a portable .atom folder exists', () => {
|
||||
beforeEach(() => {
|
||||
delete process.env.ATOM_HOME
|
||||
if (!fs.existsSync(portableAtomHomePath))
|
||||
if (!fs.existsSync(portableAtomHomePath)) {
|
||||
fs.mkdirSync(portableAtomHomePath)
|
||||
}
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
@@ -69,6 +74,7 @@ describe("AtomPaths", () => {
|
||||
})
|
||||
|
||||
describe('setUserData', () => {
|
||||
let tempAtomConfigPath = null
|
||||
let tempAtomHomePath = null
|
||||
let electronUserDataPath = null
|
||||
let defaultElectronUserDataPath = null
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
const AutoUpdateManager = require('../src/auto-update-manager')
|
||||
const {remote} = require('electron')
|
||||
const { remote } = require('electron')
|
||||
const electronAutoUpdater = remote.require('electron').autoUpdater
|
||||
|
||||
describe('AutoUpdateManager (renderer)', () => {
|
||||
@@ -8,7 +8,9 @@ describe('AutoUpdateManager (renderer)', () => {
|
||||
let autoUpdateManager
|
||||
|
||||
beforeEach(() => {
|
||||
autoUpdateManager = new AutoUpdateManager({applicationDelegate: atom.applicationDelegate})
|
||||
autoUpdateManager = new AutoUpdateManager({
|
||||
applicationDelegate: atom.applicationDelegate
|
||||
})
|
||||
autoUpdateManager.initialize()
|
||||
})
|
||||
|
||||
@@ -69,14 +71,16 @@ describe('AutoUpdateManager (renderer)', () => {
|
||||
autoUpdateManager.onUpdateError(spy)
|
||||
electronAutoUpdater.emit('error', {}, 'an error message')
|
||||
waitsFor(() => spy.callCount === 1)
|
||||
runs(() => expect(autoUpdateManager.getErrorMessage()).toBe('an error message'))
|
||||
runs(() =>
|
||||
expect(autoUpdateManager.getErrorMessage()).toBe('an error message')
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('::platformSupportsUpdates', () => {
|
||||
let state, releaseChannel
|
||||
it('returns true on macOS and Windows when in stable', () => {
|
||||
spyOn(autoUpdateManager, 'getState').andCallFake(() => state)
|
||||
spyOn(autoUpdateManager, 'getState').andCallFake(() => state)
|
||||
spyOn(atom, 'getReleaseChannel').andCallFake(() => releaseChannel)
|
||||
|
||||
state = 'idle'
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
const path = require('path')
|
||||
const fs = require('fs-plus')
|
||||
const temp = require('temp').track()
|
||||
const {it, fit, ffit, fffit, beforeEach, afterEach} = require('./async-spec-helpers');
|
||||
const {
|
||||
it,
|
||||
beforeEach,
|
||||
afterEach
|
||||
} = require('./async-spec-helpers')
|
||||
const CommandInstaller = require('../src/command-installer')
|
||||
|
||||
describe('CommandInstaller on #darwin', () => {
|
||||
@@ -12,14 +16,25 @@ describe('CommandInstaller on #darwin', () => {
|
||||
|
||||
resourcesPath = temp.mkdirSync('atom-app')
|
||||
atomBinPath = path.join(resourcesPath, 'app', 'atom.sh')
|
||||
apmBinPath = path.join(resourcesPath, 'app', 'apm', 'node_modules', '.bin', 'apm')
|
||||
apmBinPath = path.join(
|
||||
resourcesPath,
|
||||
'app',
|
||||
'apm',
|
||||
'node_modules',
|
||||
'.bin',
|
||||
'apm'
|
||||
)
|
||||
fs.writeFileSync(atomBinPath, '')
|
||||
fs.writeFileSync(apmBinPath, '')
|
||||
fs.chmodSync(atomBinPath, '755')
|
||||
fs.chmodSync(apmBinPath, '755')
|
||||
|
||||
spyOn(CommandInstaller.prototype, 'getResourcesDirectory').andReturn(resourcesPath)
|
||||
spyOn(CommandInstaller.prototype, 'getInstallDirectory').andReturn(installationPath)
|
||||
spyOn(CommandInstaller.prototype, 'getResourcesDirectory').andReturn(
|
||||
resourcesPath
|
||||
)
|
||||
spyOn(CommandInstaller.prototype, 'getInstallDirectory').andReturn(
|
||||
installationPath
|
||||
)
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
@@ -32,7 +47,9 @@ describe('CommandInstaller on #darwin', () => {
|
||||
const appDelegate = jasmine.createSpyObj('appDelegate', ['confirm'])
|
||||
installer = new CommandInstaller(appDelegate)
|
||||
installer.initialize('2.0.2')
|
||||
spyOn(installer, 'installAtomCommand').andCallFake((__, callback) => callback(new Error('an error')))
|
||||
spyOn(installer, 'installAtomCommand').andCallFake((__, callback) =>
|
||||
callback(new Error('an error'))
|
||||
)
|
||||
|
||||
installer.installShellCommandsInteractively()
|
||||
|
||||
@@ -43,7 +60,9 @@ describe('CommandInstaller on #darwin', () => {
|
||||
|
||||
appDelegate.confirm.reset()
|
||||
installer.installAtomCommand.andCallFake((__, callback) => callback())
|
||||
spyOn(installer, 'installApmCommand').andCallFake((__, callback) => callback(new Error('another error')))
|
||||
spyOn(installer, 'installApmCommand').andCallFake((__, callback) =>
|
||||
callback(new Error('another error'))
|
||||
)
|
||||
|
||||
installer.installShellCommandsInteractively()
|
||||
|
||||
@@ -57,8 +76,12 @@ describe('CommandInstaller on #darwin', () => {
|
||||
const appDelegate = jasmine.createSpyObj('appDelegate', ['confirm'])
|
||||
installer = new CommandInstaller(appDelegate)
|
||||
installer.initialize('2.0.2')
|
||||
spyOn(installer, 'installAtomCommand').andCallFake((__, callback) => callback(undefined, 'atom'))
|
||||
spyOn(installer, 'installApmCommand').andCallFake((__, callback) => callback(undefined, 'apm'))
|
||||
spyOn(installer, 'installAtomCommand').andCallFake((__, callback) =>
|
||||
callback(undefined, 'atom')
|
||||
)
|
||||
spyOn(installer, 'installApmCommand').andCallFake((__, callback) =>
|
||||
callback(undefined, 'apm')
|
||||
)
|
||||
|
||||
installer.installShellCommandsInteractively()
|
||||
|
||||
@@ -81,9 +104,13 @@ describe('CommandInstaller on #darwin', () => {
|
||||
waitsFor(done => {
|
||||
installer.installAtomCommand(false, error => {
|
||||
expect(error).toBeNull()
|
||||
expect(fs.realpathSync(installedAtomPath)).toBe(fs.realpathSync(atomBinPath))
|
||||
expect(fs.realpathSync(installedAtomPath)).toBe(
|
||||
fs.realpathSync(atomBinPath)
|
||||
)
|
||||
expect(fs.isExecutableSync(installedAtomPath)).toBe(true)
|
||||
expect(fs.isFileSync(path.join(installationPath, 'atom-beta'))).toBe(false)
|
||||
expect(fs.isFileSync(path.join(installationPath, 'atom-beta'))).toBe(
|
||||
false
|
||||
)
|
||||
done()
|
||||
})
|
||||
})
|
||||
@@ -96,9 +123,13 @@ describe('CommandInstaller on #darwin', () => {
|
||||
waitsFor(done => {
|
||||
installer.installApmCommand(false, error => {
|
||||
expect(error).toBeNull()
|
||||
expect(fs.realpathSync(installedApmPath)).toBe(fs.realpathSync(apmBinPath))
|
||||
expect(fs.realpathSync(installedApmPath)).toBe(
|
||||
fs.realpathSync(apmBinPath)
|
||||
)
|
||||
expect(fs.isExecutableSync(installedApmPath)).toBeTruthy()
|
||||
expect(fs.isFileSync(path.join(installationPath, 'apm-beta'))).toBe(false)
|
||||
expect(fs.isFileSync(path.join(installationPath, 'apm-beta'))).toBe(
|
||||
false
|
||||
)
|
||||
done()
|
||||
})
|
||||
})
|
||||
@@ -118,7 +149,9 @@ describe('CommandInstaller on #darwin', () => {
|
||||
waitsFor(done => {
|
||||
installer.installAtomCommand(false, error => {
|
||||
expect(error).toBeNull()
|
||||
expect(fs.realpathSync(installedAtomPath)).toBe(fs.realpathSync(atomBinPath))
|
||||
expect(fs.realpathSync(installedAtomPath)).toBe(
|
||||
fs.realpathSync(atomBinPath)
|
||||
)
|
||||
expect(fs.isExecutableSync(installedAtomPath)).toBe(true)
|
||||
expect(fs.isFileSync(path.join(installationPath, 'atom'))).toBe(false)
|
||||
done()
|
||||
@@ -133,7 +166,9 @@ describe('CommandInstaller on #darwin', () => {
|
||||
waitsFor(done => {
|
||||
installer.installApmCommand(false, error => {
|
||||
expect(error).toBeNull()
|
||||
expect(fs.realpathSync(installedApmPath)).toBe(fs.realpathSync(apmBinPath))
|
||||
expect(fs.realpathSync(installedApmPath)).toBe(
|
||||
fs.realpathSync(apmBinPath)
|
||||
)
|
||||
expect(fs.isExecutableSync(installedApmPath)).toBeTruthy()
|
||||
expect(fs.isFileSync(path.join(installationPath, 'apm'))).toBe(false)
|
||||
done()
|
||||
@@ -155,7 +190,9 @@ describe('CommandInstaller on #darwin', () => {
|
||||
waitsFor(done => {
|
||||
installer.installAtomCommand(false, error => {
|
||||
expect(error).toBeNull()
|
||||
expect(fs.realpathSync(installedAtomPath)).toBe(fs.realpathSync(atomBinPath))
|
||||
expect(fs.realpathSync(installedAtomPath)).toBe(
|
||||
fs.realpathSync(atomBinPath)
|
||||
)
|
||||
expect(fs.isExecutableSync(installedAtomPath)).toBe(true)
|
||||
expect(fs.isFileSync(path.join(installationPath, 'atom'))).toBe(false)
|
||||
done()
|
||||
@@ -170,9 +207,13 @@ describe('CommandInstaller on #darwin', () => {
|
||||
waitsFor(done => {
|
||||
installer.installApmCommand(false, error => {
|
||||
expect(error).toBeNull()
|
||||
expect(fs.realpathSync(installedApmPath)).toBe(fs.realpathSync(apmBinPath))
|
||||
expect(fs.realpathSync(installedApmPath)).toBe(
|
||||
fs.realpathSync(apmBinPath)
|
||||
)
|
||||
expect(fs.isExecutableSync(installedApmPath)).toBeTruthy()
|
||||
expect(fs.isFileSync(path.join(installationPath, 'nightly'))).toBe(false)
|
||||
expect(fs.isFileSync(path.join(installationPath, 'nightly'))).toBe(
|
||||
false
|
||||
)
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,289 +1,307 @@
|
||||
const CommandRegistry = require('../src/command-registry');
|
||||
const _ = require('underscore-plus');
|
||||
const {it, fit, ffit, fffit, beforeEach, afterEach} = require('./async-spec-helpers');
|
||||
const CommandRegistry = require('../src/command-registry')
|
||||
const _ = require('underscore-plus')
|
||||
const { it, beforeEach, afterEach } = require('./async-spec-helpers')
|
||||
|
||||
describe("CommandRegistry", () => {
|
||||
let registry, parent, child, grandchild;
|
||||
describe('CommandRegistry', () => {
|
||||
let registry, parent, child, grandchild
|
||||
|
||||
beforeEach(() => {
|
||||
parent = document.createElement("div");
|
||||
child = document.createElement("div");
|
||||
grandchild = document.createElement("div");
|
||||
parent.classList.add('parent');
|
||||
child.classList.add('child');
|
||||
grandchild.classList.add('grandchild');
|
||||
child.appendChild(grandchild);
|
||||
parent.appendChild(child);
|
||||
document.querySelector('#jasmine-content').appendChild(parent);
|
||||
parent = document.createElement('div')
|
||||
child = document.createElement('div')
|
||||
grandchild = document.createElement('div')
|
||||
parent.classList.add('parent')
|
||||
child.classList.add('child')
|
||||
grandchild.classList.add('grandchild')
|
||||
child.appendChild(grandchild)
|
||||
parent.appendChild(child)
|
||||
document.querySelector('#jasmine-content').appendChild(parent)
|
||||
|
||||
registry = new CommandRegistry;
|
||||
registry.attach(parent);
|
||||
});
|
||||
registry = new CommandRegistry()
|
||||
registry.attach(parent)
|
||||
})
|
||||
|
||||
afterEach(() => registry.destroy());
|
||||
afterEach(() => registry.destroy())
|
||||
|
||||
describe("when a command event is dispatched on an element", () => {
|
||||
it("invokes callbacks with selectors matching the target", () => {
|
||||
let called = false;
|
||||
describe('when a command event is dispatched on an element', () => {
|
||||
it('invokes callbacks with selectors matching the target', () => {
|
||||
let called = false
|
||||
registry.add('.grandchild', 'command', function (event) {
|
||||
expect(this).toBe(grandchild);
|
||||
expect(event.type).toBe('command');
|
||||
expect(event.eventPhase).toBe(Event.BUBBLING_PHASE);
|
||||
expect(event.target).toBe(grandchild);
|
||||
expect(event.currentTarget).toBe(grandchild);
|
||||
called = true;
|
||||
});
|
||||
expect(this).toBe(grandchild)
|
||||
expect(event.type).toBe('command')
|
||||
expect(event.eventPhase).toBe(Event.BUBBLING_PHASE)
|
||||
expect(event.target).toBe(grandchild)
|
||||
expect(event.currentTarget).toBe(grandchild)
|
||||
called = true
|
||||
})
|
||||
|
||||
grandchild.dispatchEvent(new CustomEvent('command', {bubbles: true}));
|
||||
expect(called).toBe(true);
|
||||
});
|
||||
grandchild.dispatchEvent(new CustomEvent('command', { bubbles: true }))
|
||||
expect(called).toBe(true)
|
||||
})
|
||||
|
||||
it("invokes callbacks with selectors matching ancestors of the target", () => {
|
||||
const calls = [];
|
||||
it('invokes callbacks with selectors matching ancestors of the target', () => {
|
||||
const calls = []
|
||||
|
||||
registry.add('.child', 'command', function (event) {
|
||||
expect(this).toBe(child);
|
||||
expect(event.target).toBe(grandchild);
|
||||
expect(event.currentTarget).toBe(child);
|
||||
calls.push('child');
|
||||
});
|
||||
expect(this).toBe(child)
|
||||
expect(event.target).toBe(grandchild)
|
||||
expect(event.currentTarget).toBe(child)
|
||||
calls.push('child')
|
||||
})
|
||||
|
||||
registry.add('.parent', 'command', function (event) {
|
||||
expect(this).toBe(parent);
|
||||
expect(event.target).toBe(grandchild);
|
||||
expect(event.currentTarget).toBe(parent);
|
||||
calls.push('parent');
|
||||
});
|
||||
registry.add('.parent', 'command', function (event) {
|
||||
expect(this).toBe(parent)
|
||||
expect(event.target).toBe(grandchild)
|
||||
expect(event.currentTarget).toBe(parent)
|
||||
calls.push('parent')
|
||||
})
|
||||
|
||||
grandchild.dispatchEvent(new CustomEvent('command', {bubbles: true}));
|
||||
expect(calls).toEqual(['child', 'parent']);
|
||||
});
|
||||
grandchild.dispatchEvent(new CustomEvent('command', { bubbles: true }))
|
||||
expect(calls).toEqual(['child', 'parent'])
|
||||
})
|
||||
|
||||
it("invokes inline listeners prior to listeners applied via selectors", () => {
|
||||
const calls = [];
|
||||
registry.add('.grandchild', 'command', () => calls.push('grandchild'));
|
||||
registry.add(child, 'command', () => calls.push('child-inline'));
|
||||
registry.add('.child', 'command', () => calls.push('child'));
|
||||
registry.add('.parent', 'command', () => calls.push('parent'));
|
||||
it('invokes inline listeners prior to listeners applied via selectors', () => {
|
||||
const calls = []
|
||||
registry.add('.grandchild', 'command', () => calls.push('grandchild'))
|
||||
registry.add(child, 'command', () => calls.push('child-inline'))
|
||||
registry.add('.child', 'command', () => calls.push('child'))
|
||||
registry.add('.parent', 'command', () => calls.push('parent'))
|
||||
|
||||
grandchild.dispatchEvent(new CustomEvent('command', {bubbles: true}));
|
||||
expect(calls).toEqual(['grandchild', 'child-inline', 'child', 'parent']);
|
||||
});
|
||||
grandchild.dispatchEvent(new CustomEvent('command', { bubbles: true }))
|
||||
expect(calls).toEqual(['grandchild', 'child-inline', 'child', 'parent'])
|
||||
})
|
||||
|
||||
it("orders multiple matching listeners for an element by selector specificity", () => {
|
||||
child.classList.add('foo', 'bar');
|
||||
const calls = [];
|
||||
it('orders multiple matching listeners for an element by selector specificity', () => {
|
||||
child.classList.add('foo', 'bar')
|
||||
const calls = []
|
||||
|
||||
registry.add('.foo.bar', 'command', () => calls.push('.foo.bar'));
|
||||
registry.add('.foo', 'command', () => calls.push('.foo'));
|
||||
registry.add('.bar', 'command', () => calls.push('.bar')); // specificity ties favor commands added later, like CSS
|
||||
registry.add('.foo.bar', 'command', () => calls.push('.foo.bar'))
|
||||
registry.add('.foo', 'command', () => calls.push('.foo'))
|
||||
registry.add('.bar', 'command', () => calls.push('.bar')) // specificity ties favor commands added later, like CSS
|
||||
|
||||
grandchild.dispatchEvent(new CustomEvent('command', {bubbles: true}));
|
||||
expect(calls).toEqual(['.foo.bar', '.bar', '.foo']);
|
||||
});
|
||||
grandchild.dispatchEvent(new CustomEvent('command', { bubbles: true }))
|
||||
expect(calls).toEqual(['.foo.bar', '.bar', '.foo'])
|
||||
})
|
||||
|
||||
it("orders inline listeners by reverse registration order", () => {
|
||||
const calls = [];
|
||||
registry.add(child, 'command', () => calls.push('child1'));
|
||||
registry.add(child, 'command', () => calls.push('child2'));
|
||||
child.dispatchEvent(new CustomEvent('command', {bubbles: true}));
|
||||
expect(calls).toEqual(['child2', 'child1']);
|
||||
});
|
||||
it('orders inline listeners by reverse registration order', () => {
|
||||
const calls = []
|
||||
registry.add(child, 'command', () => calls.push('child1'))
|
||||
registry.add(child, 'command', () => calls.push('child2'))
|
||||
child.dispatchEvent(new CustomEvent('command', { bubbles: true }))
|
||||
expect(calls).toEqual(['child2', 'child1'])
|
||||
})
|
||||
|
||||
it("stops bubbling through ancestors when .stopPropagation() is called on the event", () => {
|
||||
const calls = [];
|
||||
it('stops bubbling through ancestors when .stopPropagation() is called on the event', () => {
|
||||
const calls = []
|
||||
|
||||
registry.add('.parent', 'command', () => calls.push('parent'));
|
||||
registry.add('.child', 'command', () => calls.push('child-2'));
|
||||
registry.add('.child', 'command', (event) => {
|
||||
calls.push('child-1');
|
||||
event.stopPropagation();
|
||||
});
|
||||
registry.add('.parent', 'command', () => calls.push('parent'))
|
||||
registry.add('.child', 'command', () => calls.push('child-2'))
|
||||
registry.add('.child', 'command', event => {
|
||||
calls.push('child-1')
|
||||
event.stopPropagation()
|
||||
})
|
||||
|
||||
const dispatchedEvent = new CustomEvent('command', {bubbles: true});
|
||||
spyOn(dispatchedEvent, 'stopPropagation');
|
||||
grandchild.dispatchEvent(dispatchedEvent);
|
||||
expect(calls).toEqual(['child-1', 'child-2']);
|
||||
expect(dispatchedEvent.stopPropagation).toHaveBeenCalled();
|
||||
});
|
||||
const dispatchedEvent = new CustomEvent('command', { bubbles: true })
|
||||
spyOn(dispatchedEvent, 'stopPropagation')
|
||||
grandchild.dispatchEvent(dispatchedEvent)
|
||||
expect(calls).toEqual(['child-1', 'child-2'])
|
||||
expect(dispatchedEvent.stopPropagation).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it("stops invoking callbacks when .stopImmediatePropagation() is called on the event", () => {
|
||||
const calls = [];
|
||||
it('stops invoking callbacks when .stopImmediatePropagation() is called on the event', () => {
|
||||
const calls = []
|
||||
|
||||
registry.add('.parent', 'command', () => calls.push('parent'));
|
||||
registry.add('.child', 'command', () => calls.push('child-2'));
|
||||
registry.add('.child', 'command', (event) => {
|
||||
calls.push('child-1');
|
||||
event.stopImmediatePropagation();
|
||||
});
|
||||
registry.add('.parent', 'command', () => calls.push('parent'))
|
||||
registry.add('.child', 'command', () => calls.push('child-2'))
|
||||
registry.add('.child', 'command', event => {
|
||||
calls.push('child-1')
|
||||
event.stopImmediatePropagation()
|
||||
})
|
||||
|
||||
const dispatchedEvent = new CustomEvent('command', {bubbles: true});
|
||||
spyOn(dispatchedEvent, 'stopImmediatePropagation');
|
||||
grandchild.dispatchEvent(dispatchedEvent);
|
||||
expect(calls).toEqual(['child-1']);
|
||||
expect(dispatchedEvent.stopImmediatePropagation).toHaveBeenCalled();
|
||||
});
|
||||
const dispatchedEvent = new CustomEvent('command', { bubbles: true })
|
||||
spyOn(dispatchedEvent, 'stopImmediatePropagation')
|
||||
grandchild.dispatchEvent(dispatchedEvent)
|
||||
expect(calls).toEqual(['child-1'])
|
||||
expect(dispatchedEvent.stopImmediatePropagation).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it("forwards .preventDefault() calls from the synthetic event to the original", () => {
|
||||
registry.add('.child', 'command', event => event.preventDefault());
|
||||
it('forwards .preventDefault() calls from the synthetic event to the original', () => {
|
||||
registry.add('.child', 'command', event => event.preventDefault())
|
||||
|
||||
const dispatchedEvent = new CustomEvent('command', {bubbles: true});
|
||||
spyOn(dispatchedEvent, 'preventDefault');
|
||||
grandchild.dispatchEvent(dispatchedEvent);
|
||||
expect(dispatchedEvent.preventDefault).toHaveBeenCalled();
|
||||
});
|
||||
const dispatchedEvent = new CustomEvent('command', { bubbles: true })
|
||||
spyOn(dispatchedEvent, 'preventDefault')
|
||||
grandchild.dispatchEvent(dispatchedEvent)
|
||||
expect(dispatchedEvent.preventDefault).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it("forwards .abortKeyBinding() calls from the synthetic event to the original", () => {
|
||||
registry.add('.child', 'command', event => event.abortKeyBinding());
|
||||
it('forwards .abortKeyBinding() calls from the synthetic event to the original', () => {
|
||||
registry.add('.child', 'command', event => event.abortKeyBinding())
|
||||
|
||||
const dispatchedEvent = new CustomEvent('command', {bubbles: true});
|
||||
dispatchedEvent.abortKeyBinding = jasmine.createSpy('abortKeyBinding');
|
||||
grandchild.dispatchEvent(dispatchedEvent);
|
||||
expect(dispatchedEvent.abortKeyBinding).toHaveBeenCalled();
|
||||
});
|
||||
const dispatchedEvent = new CustomEvent('command', { bubbles: true })
|
||||
dispatchedEvent.abortKeyBinding = jasmine.createSpy('abortKeyBinding')
|
||||
grandchild.dispatchEvent(dispatchedEvent)
|
||||
expect(dispatchedEvent.abortKeyBinding).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it("copies non-standard properties from the original event to the synthetic event", () => {
|
||||
let syntheticEvent = null;
|
||||
registry.add('.child', 'command', event => syntheticEvent = event);
|
||||
it('copies non-standard properties from the original event to the synthetic event', () => {
|
||||
let syntheticEvent = null
|
||||
registry.add('.child', 'command', event => (syntheticEvent = event))
|
||||
|
||||
const dispatchedEvent = new CustomEvent('command', {bubbles: true});
|
||||
dispatchedEvent.nonStandardProperty = 'testing';
|
||||
grandchild.dispatchEvent(dispatchedEvent);
|
||||
expect(syntheticEvent.nonStandardProperty).toBe('testing');
|
||||
});
|
||||
const 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", () => {
|
||||
let calls = [];
|
||||
it('allows listeners to be removed via a disposable returned by ::add', () => {
|
||||
let calls = []
|
||||
|
||||
const disposable1 = registry.add('.parent', 'command', () => calls.push('parent'));
|
||||
const disposable2 = registry.add('.child', 'command', () => calls.push('child'));
|
||||
const disposable1 = registry.add('.parent', 'command', () =>
|
||||
calls.push('parent')
|
||||
)
|
||||
const disposable2 = registry.add('.child', 'command', () =>
|
||||
calls.push('child')
|
||||
)
|
||||
|
||||
disposable1.dispose();
|
||||
grandchild.dispatchEvent(new CustomEvent('command', {bubbles: true}));
|
||||
expect(calls).toEqual(['child']);
|
||||
disposable1.dispose()
|
||||
grandchild.dispatchEvent(new CustomEvent('command', { bubbles: true }))
|
||||
expect(calls).toEqual(['child'])
|
||||
|
||||
calls = [];
|
||||
disposable2.dispose();
|
||||
grandchild.dispatchEvent(new CustomEvent('command', {bubbles: true}));
|
||||
expect(calls).toEqual([]);
|
||||
});
|
||||
calls = []
|
||||
disposable2.dispose()
|
||||
grandchild.dispatchEvent(new CustomEvent('command', { bubbles: true }))
|
||||
expect(calls).toEqual([])
|
||||
})
|
||||
|
||||
it("allows multiple commands to be registered under one selector when called with an object", () => {
|
||||
let calls = [];
|
||||
it('allows multiple commands to be registered under one selector when called with an object', () => {
|
||||
let calls = []
|
||||
|
||||
const disposable = registry.add('.child', {
|
||||
'command-1'() {
|
||||
calls.push('command-1');
|
||||
'command-1' () {
|
||||
calls.push('command-1')
|
||||
},
|
||||
'command-2'() {
|
||||
calls.push('command-2');
|
||||
'command-2' () {
|
||||
calls.push('command-2')
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
grandchild.dispatchEvent(new CustomEvent('command-1', {bubbles: true}));
|
||||
grandchild.dispatchEvent(new CustomEvent('command-2', {bubbles: true}));
|
||||
grandchild.dispatchEvent(new CustomEvent('command-1', { bubbles: true }))
|
||||
grandchild.dispatchEvent(new CustomEvent('command-2', { bubbles: true }))
|
||||
|
||||
expect(calls).toEqual(['command-1', 'command-2']);
|
||||
expect(calls).toEqual(['command-1', 'command-2'])
|
||||
|
||||
calls = [];
|
||||
disposable.dispose();
|
||||
grandchild.dispatchEvent(new CustomEvent('command-1', {bubbles: true}));
|
||||
grandchild.dispatchEvent(new CustomEvent('command-2', {bubbles: true}));
|
||||
expect(calls).toEqual([]);
|
||||
});
|
||||
calls = []
|
||||
disposable.dispose()
|
||||
grandchild.dispatchEvent(new CustomEvent('command-1', { bubbles: true }))
|
||||
grandchild.dispatchEvent(new CustomEvent('command-2', { bubbles: true }))
|
||||
expect(calls).toEqual([])
|
||||
})
|
||||
|
||||
it("invokes callbacks registered with ::onWillDispatch and ::onDidDispatch", () => {
|
||||
const sequence = [];
|
||||
it('invokes callbacks registered with ::onWillDispatch and ::onDidDispatch', () => {
|
||||
const sequence = []
|
||||
|
||||
registry.onDidDispatch(event => sequence.push(['onDidDispatch', event]));
|
||||
registry.onDidDispatch(event => sequence.push(['onDidDispatch', event]))
|
||||
|
||||
registry.add('.grandchild', 'command', event => sequence.push(['listener', event]));
|
||||
registry.add('.grandchild', 'command', event =>
|
||||
sequence.push(['listener', event])
|
||||
)
|
||||
|
||||
registry.onWillDispatch(event => sequence.push(['onWillDispatch', event]));
|
||||
registry.onWillDispatch(event => sequence.push(['onWillDispatch', event]))
|
||||
|
||||
grandchild.dispatchEvent(new CustomEvent('command', {bubbles: true}));
|
||||
grandchild.dispatchEvent(new CustomEvent('command', { bubbles: true }))
|
||||
|
||||
expect(sequence[0][0]).toBe('onWillDispatch');
|
||||
expect(sequence[1][0]).toBe('listener');
|
||||
expect(sequence[2][0]).toBe('onDidDispatch');
|
||||
expect(sequence[0][0]).toBe('onWillDispatch')
|
||||
expect(sequence[1][0]).toBe('listener')
|
||||
expect(sequence[2][0]).toBe('onDidDispatch')
|
||||
|
||||
expect(sequence[0][1] === sequence[1][1] && sequence[1][1] === sequence[2][1]).toBe(true);
|
||||
expect(sequence[0][1].constructor).toBe(CustomEvent);
|
||||
expect(sequence[0][1].target).toBe(grandchild);
|
||||
});
|
||||
});
|
||||
expect(
|
||||
sequence[0][1] === sequence[1][1] && sequence[1][1] === sequence[2][1]
|
||||
).toBe(true)
|
||||
expect(sequence[0][1].constructor).toBe(CustomEvent)
|
||||
expect(sequence[0][1].target).toBe(grandchild)
|
||||
})
|
||||
})
|
||||
|
||||
describe("::add(selector, commandName, callback)", () => {
|
||||
it("throws an error when called with an invalid selector", () => {
|
||||
const badSelector = '<>';
|
||||
let addError = null;
|
||||
describe('::add(selector, commandName, callback)', () => {
|
||||
it('throws an error when called with an invalid selector', () => {
|
||||
const badSelector = '<>'
|
||||
let addError = null
|
||||
try {
|
||||
registry.add(badSelector, 'foo:bar', () => {});
|
||||
registry.add(badSelector, 'foo:bar', () => {})
|
||||
} catch (error) {
|
||||
addError = error;
|
||||
addError = error
|
||||
}
|
||||
expect(addError.message).toContain(badSelector);
|
||||
});
|
||||
expect(addError.message).toContain(badSelector)
|
||||
})
|
||||
|
||||
it("throws an error when called with a null callback and selector target", () => {
|
||||
const badCallback = null;
|
||||
it('throws an error when called with a null callback and selector target', () => {
|
||||
const badCallback = null
|
||||
|
||||
expect(() => {
|
||||
registry.add('.selector', 'foo:bar', badCallback);
|
||||
}).toThrow(new Error('Cannot register a command with a null listener.'));
|
||||
});
|
||||
registry.add('.selector', 'foo:bar', badCallback)
|
||||
}).toThrow(new Error('Cannot register a command with a null listener.'))
|
||||
})
|
||||
|
||||
it("throws an error when called with a null callback and object target", () => {
|
||||
const badCallback = null;
|
||||
it('throws an error when called with a null callback and object target', () => {
|
||||
const badCallback = null
|
||||
|
||||
expect(() => {
|
||||
registry.add(document.body, 'foo:bar', badCallback);
|
||||
}).toThrow(new Error('Cannot register a command with a null listener.'));
|
||||
});
|
||||
registry.add(document.body, 'foo:bar', badCallback)
|
||||
}).toThrow(new Error('Cannot register a command with a null listener.'))
|
||||
})
|
||||
|
||||
it("throws an error when called with an object listener without a didDispatch method", () => {
|
||||
it('throws an error when called with an object listener without a didDispatch method', () => {
|
||||
const badListener = {
|
||||
title: 'a listener without a didDispatch callback',
|
||||
description: 'this should throw an error'
|
||||
};
|
||||
}
|
||||
|
||||
expect(() => {
|
||||
registry.add(document.body, 'foo:bar', badListener);
|
||||
}).toThrow(new Error('Listener must be a callback function or an object with a didDispatch method.'));
|
||||
});
|
||||
});
|
||||
registry.add(document.body, 'foo:bar', badListener)
|
||||
}).toThrow(
|
||||
new Error(
|
||||
'Listener must be a callback function or an object with a didDispatch method.'
|
||||
)
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe("::findCommands({target})", () => {
|
||||
it("returns command descriptors that can be invoked on the target or its ancestors", () => {
|
||||
registry.add('.parent', 'namespace:command-1', () => {});
|
||||
registry.add('.child', 'namespace:command-2', () => {});
|
||||
registry.add('.grandchild', 'namespace:command-3', () => {});
|
||||
registry.add('.grandchild.no-match', 'namespace:command-4', () => {});
|
||||
describe('::findCommands({target})', () => {
|
||||
it('returns command descriptors that can be invoked on the target or its ancestors', () => {
|
||||
registry.add('.parent', 'namespace:command-1', () => {})
|
||||
registry.add('.child', 'namespace:command-2', () => {})
|
||||
registry.add('.grandchild', 'namespace:command-3', () => {})
|
||||
registry.add('.grandchild.no-match', 'namespace:command-4', () => {})
|
||||
|
||||
registry.add(grandchild, 'namespace:inline-command-1', () => {});
|
||||
registry.add(child, 'namespace:inline-command-2', () => {});
|
||||
registry.add(grandchild, 'namespace:inline-command-1', () => {})
|
||||
registry.add(child, 'namespace:inline-command-2', () => {})
|
||||
|
||||
const commands = registry.findCommands({target: grandchild});
|
||||
const nonJqueryCommands = _.reject(commands, cmd => cmd.jQuery);
|
||||
const commands = registry.findCommands({ target: grandchild })
|
||||
const nonJqueryCommands = _.reject(commands, cmd => cmd.jQuery)
|
||||
expect(nonJqueryCommands).toEqual([
|
||||
{name: 'namespace:inline-command-1', displayName: 'Namespace: Inline Command 1'},
|
||||
{name: 'namespace:command-3', displayName: 'Namespace: Command 3'},
|
||||
{name: 'namespace:inline-command-2', displayName: 'Namespace: Inline Command 2'},
|
||||
{name: 'namespace:command-2', displayName: 'Namespace: Command 2'},
|
||||
{name: 'namespace:command-1', displayName: 'Namespace: Command 1'}
|
||||
]);
|
||||
});
|
||||
{
|
||||
name: 'namespace:inline-command-1',
|
||||
displayName: 'Namespace: Inline Command 1'
|
||||
},
|
||||
{ name: 'namespace:command-3', displayName: 'Namespace: Command 3' },
|
||||
{
|
||||
name: 'namespace:inline-command-2',
|
||||
displayName: 'Namespace: Inline Command 2'
|
||||
},
|
||||
{ name: 'namespace:command-2', displayName: 'Namespace: Command 2' },
|
||||
{ name: 'namespace:command-1', displayName: 'Namespace: Command 1' }
|
||||
])
|
||||
})
|
||||
|
||||
it("returns command descriptors with arbitrary metadata if set in a listener object", () => {
|
||||
registry.add('.grandchild', 'namespace:command-1', () => {});
|
||||
it('returns command descriptors with arbitrary metadata if set in a listener object', () => {
|
||||
registry.add('.grandchild', 'namespace:command-1', () => {})
|
||||
registry.add('.grandchild', 'namespace:command-2', {
|
||||
displayName: 'Custom Command 2',
|
||||
metadata: {
|
||||
some: 'other',
|
||||
object: 'data'
|
||||
},
|
||||
didDispatch() {}
|
||||
});
|
||||
didDispatch () {}
|
||||
})
|
||||
registry.add('.grandchild', 'namespace:command-3', {
|
||||
name: 'some:other:incorrect:commandname',
|
||||
displayName: 'Custom Command 3',
|
||||
@@ -291,10 +309,10 @@ describe("CommandRegistry", () => {
|
||||
some: 'other',
|
||||
object: 'data'
|
||||
},
|
||||
didDispatch() {}
|
||||
});
|
||||
didDispatch () {}
|
||||
})
|
||||
|
||||
const commands = registry.findCommands({target: grandchild});
|
||||
const commands = registry.findCommands({ target: grandchild })
|
||||
expect(commands).toEqual([
|
||||
{
|
||||
displayName: 'Namespace: Command 1',
|
||||
@@ -303,143 +321,163 @@ describe("CommandRegistry", () => {
|
||||
{
|
||||
displayName: 'Custom Command 2',
|
||||
metadata: {
|
||||
some : 'other',
|
||||
object : 'data'
|
||||
some: 'other',
|
||||
object: 'data'
|
||||
},
|
||||
name: 'namespace:command-2'
|
||||
},
|
||||
{
|
||||
displayName: 'Custom Command 3',
|
||||
metadata: {
|
||||
some : 'other',
|
||||
object : 'data'
|
||||
some: 'other',
|
||||
object: 'data'
|
||||
},
|
||||
name: 'namespace:command-3'
|
||||
}
|
||||
]);
|
||||
});
|
||||
])
|
||||
})
|
||||
|
||||
it("returns command descriptors with arbitrary metadata if set on a listener function", () => {
|
||||
it('returns command descriptors with arbitrary metadata if set on a listener function', () => {
|
||||
function listener () {}
|
||||
listener.displayName = 'Custom Command 2'
|
||||
listener.metadata = {
|
||||
some: 'other',
|
||||
object: 'data'
|
||||
};
|
||||
}
|
||||
|
||||
registry.add('.grandchild', 'namespace:command-2', listener);
|
||||
const commands = registry.findCommands({target: grandchild});
|
||||
registry.add('.grandchild', 'namespace:command-2', listener)
|
||||
const commands = registry.findCommands({ target: grandchild })
|
||||
expect(commands).toEqual([
|
||||
{
|
||||
displayName : 'Custom Command 2',
|
||||
displayName: 'Custom Command 2',
|
||||
metadata: {
|
||||
some: 'other',
|
||||
object: 'data'
|
||||
},
|
||||
name: 'namespace:command-2'
|
||||
}
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("::dispatch(target, commandName)", () => {
|
||||
it("simulates invocation of the given command ", () => {
|
||||
let called = false;
|
||||
registry.add('.grandchild', 'command', function (event) {
|
||||
expect(this).toBe(grandchild);
|
||||
expect(event.type).toBe('command');
|
||||
expect(event.eventPhase).toBe(Event.BUBBLING_PHASE);
|
||||
expect(event.target).toBe(grandchild);
|
||||
expect(event.currentTarget).toBe(grandchild);
|
||||
called = true;
|
||||
});
|
||||
|
||||
registry.dispatch(grandchild, 'command');
|
||||
expect(called).toBe(true);
|
||||
});
|
||||
|
||||
it("returns a promise if any listeners matched the command", () => {
|
||||
registry.add('.grandchild', 'command', () => {});
|
||||
|
||||
expect(registry.dispatch(grandchild, 'command').constructor.name).toBe("Promise");
|
||||
expect(registry.dispatch(grandchild, 'bogus')).toBe(null);
|
||||
expect(registry.dispatch(parent, 'command')).toBe(null);
|
||||
});
|
||||
|
||||
it("returns a promise that resolves when the listeners resolve", async () => {
|
||||
jasmine.useRealClock();
|
||||
registry.add('.grandchild', 'command', () => 1);
|
||||
registry.add('.grandchild', 'command', () => Promise.resolve(2));
|
||||
registry.add('.grandchild', 'command', () => new Promise((resolve) => {
|
||||
setTimeout(() => { resolve(3); }, 1);
|
||||
}));
|
||||
|
||||
const values = await registry.dispatch(grandchild, 'command');
|
||||
expect(values).toEqual([3, 2, 1]);
|
||||
});
|
||||
|
||||
it("returns a promise that rejects when a listener is rejected", async () => {
|
||||
jasmine.useRealClock();
|
||||
registry.add('.grandchild', 'command', () => 1);
|
||||
registry.add('.grandchild', 'command', () => Promise.resolve(2));
|
||||
registry.add('.grandchild', 'command', () => new Promise((resolve, reject) => {
|
||||
setTimeout(() => { reject(3); }, 1);
|
||||
}));
|
||||
|
||||
let value;
|
||||
try {
|
||||
value = await registry.dispatch(grandchild, 'command');
|
||||
} catch (err) {
|
||||
value = err;
|
||||
}
|
||||
expect(value).toBe(3);
|
||||
});
|
||||
});
|
||||
|
||||
describe("::getSnapshot and ::restoreSnapshot", () =>
|
||||
it("removes all command handlers except for those in the snapshot", () => {
|
||||
registry.add('.parent', 'namespace:command-1', () => {});
|
||||
registry.add('.child', 'namespace:command-2', () => {});
|
||||
const snapshot = registry.getSnapshot();
|
||||
registry.add('.grandchild', 'namespace:command-3', () => {});
|
||||
|
||||
expect(registry.findCommands({target: grandchild}).slice(0, 3)).toEqual([
|
||||
{name: 'namespace:command-3', displayName: 'Namespace: Command 3'},
|
||||
{name: 'namespace:command-2', displayName: 'Namespace: Command 2'},
|
||||
{name: 'namespace:command-1', displayName: 'Namespace: Command 1'}
|
||||
]);
|
||||
|
||||
registry.restoreSnapshot(snapshot);
|
||||
|
||||
expect(registry.findCommands({target: grandchild}).slice(0, 2)).toEqual([
|
||||
{name: 'namespace:command-2', displayName: 'Namespace: Command 2'},
|
||||
{name: 'namespace:command-1', displayName: 'Namespace: Command 1'}
|
||||
]);
|
||||
|
||||
registry.add('.grandchild', 'namespace:command-3', () => {});
|
||||
registry.restoreSnapshot(snapshot);
|
||||
|
||||
expect(registry.findCommands({target: grandchild}).slice(0, 2)).toEqual([
|
||||
{name: 'namespace:command-2', displayName: 'Namespace: Command 2'},
|
||||
{name: 'namespace:command-1', displayName: 'Namespace: Command 1'}
|
||||
]);
|
||||
})
|
||||
);
|
||||
|
||||
describe("::attach(rootNode)", () =>
|
||||
it("adds event listeners for any previously-added commands", () => {
|
||||
const registry2 = new CommandRegistry;
|
||||
|
||||
const commandSpy = jasmine.createSpy('command-callback');
|
||||
registry2.add('.grandchild', 'command-1', commandSpy);
|
||||
|
||||
grandchild.dispatchEvent(new CustomEvent('command-1', {bubbles: true}));
|
||||
expect(commandSpy).not.toHaveBeenCalled();
|
||||
|
||||
registry2.attach(parent);
|
||||
|
||||
grandchild.dispatchEvent(new CustomEvent('command-1', {bubbles: true}));
|
||||
expect(commandSpy).toHaveBeenCalled();
|
||||
])
|
||||
})
|
||||
);
|
||||
});
|
||||
})
|
||||
|
||||
describe('::dispatch(target, commandName)', () => {
|
||||
it('simulates invocation of the given command ', () => {
|
||||
let called = false
|
||||
registry.add('.grandchild', 'command', function (event) {
|
||||
expect(this).toBe(grandchild)
|
||||
expect(event.type).toBe('command')
|
||||
expect(event.eventPhase).toBe(Event.BUBBLING_PHASE)
|
||||
expect(event.target).toBe(grandchild)
|
||||
expect(event.currentTarget).toBe(grandchild)
|
||||
called = true
|
||||
})
|
||||
|
||||
registry.dispatch(grandchild, 'command')
|
||||
expect(called).toBe(true)
|
||||
})
|
||||
|
||||
it('returns a promise if any listeners matched the command', () => {
|
||||
registry.add('.grandchild', 'command', () => {})
|
||||
|
||||
expect(registry.dispatch(grandchild, 'command').constructor.name).toBe(
|
||||
'Promise'
|
||||
)
|
||||
expect(registry.dispatch(grandchild, 'bogus')).toBe(null)
|
||||
expect(registry.dispatch(parent, 'command')).toBe(null)
|
||||
})
|
||||
|
||||
it('returns a promise that resolves when the listeners resolve', async () => {
|
||||
jasmine.useRealClock()
|
||||
registry.add('.grandchild', 'command', () => 1)
|
||||
registry.add('.grandchild', 'command', () => Promise.resolve(2))
|
||||
registry.add(
|
||||
'.grandchild',
|
||||
'command',
|
||||
() =>
|
||||
new Promise(resolve => {
|
||||
setTimeout(() => {
|
||||
resolve(3)
|
||||
}, 1)
|
||||
})
|
||||
)
|
||||
|
||||
const values = await registry.dispatch(grandchild, 'command')
|
||||
expect(values).toEqual([3, 2, 1])
|
||||
})
|
||||
|
||||
it('returns a promise that rejects when a listener is rejected', async () => {
|
||||
jasmine.useRealClock()
|
||||
registry.add('.grandchild', 'command', () => 1)
|
||||
registry.add('.grandchild', 'command', () => Promise.resolve(2))
|
||||
registry.add(
|
||||
'.grandchild',
|
||||
'command',
|
||||
() =>
|
||||
new Promise((resolve, reject) => {
|
||||
setTimeout(() => {
|
||||
reject(3)
|
||||
}, 1)
|
||||
})
|
||||
)
|
||||
|
||||
let value
|
||||
try {
|
||||
value = await registry.dispatch(grandchild, 'command')
|
||||
} catch (err) {
|
||||
value = err
|
||||
}
|
||||
expect(value).toBe(3)
|
||||
})
|
||||
})
|
||||
|
||||
describe('::getSnapshot and ::restoreSnapshot', () =>
|
||||
it('removes all command handlers except for those in the snapshot', () => {
|
||||
registry.add('.parent', 'namespace:command-1', () => {})
|
||||
registry.add('.child', 'namespace:command-2', () => {})
|
||||
const snapshot = registry.getSnapshot()
|
||||
registry.add('.grandchild', 'namespace:command-3', () => {})
|
||||
|
||||
expect(registry.findCommands({ target: grandchild }).slice(0, 3)).toEqual(
|
||||
[
|
||||
{ name: 'namespace:command-3', displayName: 'Namespace: Command 3' },
|
||||
{ name: 'namespace:command-2', displayName: 'Namespace: Command 2' },
|
||||
{ name: 'namespace:command-1', displayName: 'Namespace: Command 1' }
|
||||
]
|
||||
)
|
||||
|
||||
registry.restoreSnapshot(snapshot)
|
||||
|
||||
expect(registry.findCommands({ target: grandchild }).slice(0, 2)).toEqual(
|
||||
[
|
||||
{ name: 'namespace:command-2', displayName: 'Namespace: Command 2' },
|
||||
{ name: 'namespace:command-1', displayName: 'Namespace: Command 1' }
|
||||
]
|
||||
)
|
||||
|
||||
registry.add('.grandchild', 'namespace:command-3', () => {})
|
||||
registry.restoreSnapshot(snapshot)
|
||||
|
||||
expect(registry.findCommands({ target: grandchild }).slice(0, 2)).toEqual(
|
||||
[
|
||||
{ name: 'namespace:command-2', displayName: 'Namespace: Command 2' },
|
||||
{ name: 'namespace:command-1', displayName: 'Namespace: Command 1' }
|
||||
]
|
||||
)
|
||||
}))
|
||||
|
||||
describe('::attach(rootNode)', () =>
|
||||
it('adds event listeners for any previously-added commands', () => {
|
||||
const registry2 = new CommandRegistry()
|
||||
|
||||
const commandSpy = jasmine.createSpy('command-callback')
|
||||
registry2.add('.grandchild', 'command-1', commandSpy)
|
||||
|
||||
grandchild.dispatchEvent(new CustomEvent('command-1', { bubbles: true }))
|
||||
expect(commandSpy).not.toHaveBeenCalled()
|
||||
|
||||
registry2.attach(parent)
|
||||
|
||||
grandchild.dispatchEvent(new CustomEvent('command-1', { bubbles: true }))
|
||||
expect(commandSpy).toHaveBeenCalled()
|
||||
}))
|
||||
})
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
const {it, fit, ffit, beforeEach, afterEach, conditionPromise} = require('./async-spec-helpers')
|
||||
const {
|
||||
it,
|
||||
|
||||
beforeEach,
|
||||
afterEach
|
||||
} = require('./async-spec-helpers')
|
||||
const fs = require('fs-plus')
|
||||
const path = require('path')
|
||||
const temp = require('temp').track()
|
||||
@@ -42,22 +47,25 @@ describe('ConfigFile', () => {
|
||||
|
||||
const event = new Promise(resolve => configFile.onDidChange(resolve))
|
||||
|
||||
writeFileSync(filePath, dedent `
|
||||
writeFileSync(
|
||||
filePath,
|
||||
dedent`
|
||||
'*':
|
||||
foo: 'bar'
|
||||
|
||||
'javascript':
|
||||
foo: 'baz'
|
||||
`)
|
||||
`
|
||||
)
|
||||
|
||||
expect(await event).toEqual({
|
||||
'*': {foo: 'bar'},
|
||||
'javascript': {foo: 'baz'}
|
||||
'*': { foo: 'bar' },
|
||||
javascript: { foo: 'baz' }
|
||||
})
|
||||
|
||||
expect(configFile.get()).toEqual({
|
||||
'*': {foo: 'bar'},
|
||||
'javascript': {foo: 'baz'}
|
||||
'*': { foo: 'bar' },
|
||||
javascript: { foo: 'baz' }
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -69,25 +77,33 @@ describe('ConfigFile', () => {
|
||||
|
||||
const message = new Promise(resolve => configFile.onDidError(resolve))
|
||||
|
||||
writeFileSync(filePath, dedent `
|
||||
writeFileSync(
|
||||
filePath,
|
||||
dedent`
|
||||
um what?
|
||||
`, 2)
|
||||
`,
|
||||
2
|
||||
)
|
||||
|
||||
expect(await message).toContain('Failed to load `the-config.cson`')
|
||||
|
||||
const event = new Promise(resolve => configFile.onDidChange(resolve))
|
||||
|
||||
writeFileSync(filePath, dedent `
|
||||
writeFileSync(
|
||||
filePath,
|
||||
dedent`
|
||||
'*':
|
||||
foo: 'bar'
|
||||
|
||||
'javascript':
|
||||
foo: 'baz'
|
||||
`, 4)
|
||||
`,
|
||||
4
|
||||
)
|
||||
|
||||
expect(await event).toEqual({
|
||||
'*': {foo: 'bar'},
|
||||
'javascript': {foo: 'baz'}
|
||||
'*': { foo: 'bar' },
|
||||
javascript: { foo: 'baz' }
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -115,7 +131,7 @@ describe('ConfigFile', () => {
|
||||
})
|
||||
|
||||
function writeFileSync (filePath, content, seconds = 2) {
|
||||
const utime = (Date.now() / 1000) + seconds
|
||||
const utime = Date.now() / 1000 + seconds
|
||||
fs.writeFileSync(filePath, content)
|
||||
fs.utimesSync(filePath, utime, utime)
|
||||
}
|
||||
|
||||
1107
spec/config-spec.js
1107
spec/config-spec.js
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,7 @@
|
||||
|
||||
const Grim = require('grim')
|
||||
|
||||
import {it, fit, ffit, fffit, beforeEach, afterEach} from './async-spec-helpers'
|
||||
import { it } from './async-spec-helpers'
|
||||
import etch from 'etch'
|
||||
|
||||
const getNextUpdatePromise = () => etch.getScheduler().nextUpdatePromise
|
||||
@@ -16,7 +16,12 @@ describe('Dock', () => {
|
||||
dock.onDidChangeVisible(didChangeVisibleSpy)
|
||||
|
||||
expect(dock.isVisible()).toBe(false)
|
||||
expect(document.activeElement).toBe(atom.workspace.getCenter().getActivePane().getElement())
|
||||
expect(document.activeElement).toBe(
|
||||
atom.workspace
|
||||
.getCenter()
|
||||
.getActivePane()
|
||||
.getElement()
|
||||
)
|
||||
dock.activate()
|
||||
expect(dock.isVisible()).toBe(true)
|
||||
expect(document.activeElement).toBe(dock.getActivePane().getElement())
|
||||
@@ -36,7 +41,12 @@ describe('Dock', () => {
|
||||
expect(didChangeVisibleSpy.mostRecentCall.args[0]).toBe(true)
|
||||
|
||||
dock.hide()
|
||||
expect(document.activeElement).toBe(atom.workspace.getCenter().getActivePane().getElement())
|
||||
expect(document.activeElement).toBe(
|
||||
atom.workspace
|
||||
.getCenter()
|
||||
.getActivePane()
|
||||
.getElement()
|
||||
)
|
||||
expect(didChangeVisibleSpy.mostRecentCall.args[0]).toBe(false)
|
||||
|
||||
dock.activate()
|
||||
@@ -44,13 +54,18 @@ describe('Dock', () => {
|
||||
expect(didChangeVisibleSpy.mostRecentCall.args[0]).toBe(true)
|
||||
|
||||
dock.toggle()
|
||||
expect(document.activeElement).toBe(atom.workspace.getCenter().getActivePane().getElement())
|
||||
expect(document.activeElement).toBe(
|
||||
atom.workspace
|
||||
.getCenter()
|
||||
.getActivePane()
|
||||
.getElement()
|
||||
)
|
||||
expect(didChangeVisibleSpy.mostRecentCall.args[0]).toBe(false)
|
||||
|
||||
// Don't change focus if the dock was not focused in the first place
|
||||
const modalElement = document.createElement('div')
|
||||
modalElement.setAttribute('tabindex', -1)
|
||||
atom.workspace.addModalPanel({item: modalElement})
|
||||
atom.workspace.addModalPanel({ item: modalElement })
|
||||
modalElement.focus()
|
||||
expect(document.activeElement).toBe(modalElement)
|
||||
|
||||
@@ -68,13 +83,18 @@ describe('Dock', () => {
|
||||
it('opens the dock', async () => {
|
||||
const item = {
|
||||
element: document.createElement('div'),
|
||||
getDefaultLocation() { return 'left' }
|
||||
getDefaultLocation () {
|
||||
return 'left'
|
||||
}
|
||||
}
|
||||
|
||||
await atom.workspace.open(item, {activatePane: false})
|
||||
await atom.workspace.open(item, { activatePane: false })
|
||||
expect(atom.workspace.getLeftDock().isVisible()).toBe(false)
|
||||
|
||||
atom.workspace.getLeftDock().getPanes()[0].activate()
|
||||
atom.workspace
|
||||
.getLeftDock()
|
||||
.getPanes()[0]
|
||||
.activate()
|
||||
expect(atom.workspace.getLeftDock().isVisible()).toBe(true)
|
||||
})
|
||||
})
|
||||
@@ -145,47 +165,63 @@ describe('Dock', () => {
|
||||
|
||||
describe('when the dock resize handle is double-clicked', () => {
|
||||
describe('when the dock is open', () => {
|
||||
it('resizes a vertically-oriented dock to the current item\'s preferred width', async () => {
|
||||
it("resizes a vertically-oriented dock to the current item's preferred width", async () => {
|
||||
jasmine.attachToDOM(atom.workspace.getElement())
|
||||
|
||||
const item = {
|
||||
element: document.createElement('div'),
|
||||
getDefaultLocation() { return 'left' },
|
||||
getPreferredWidth() { return 142 },
|
||||
getPreferredHeight() { return 122 }
|
||||
getDefaultLocation () {
|
||||
return 'left'
|
||||
},
|
||||
getPreferredWidth () {
|
||||
return 142
|
||||
},
|
||||
getPreferredHeight () {
|
||||
return 122
|
||||
}
|
||||
}
|
||||
|
||||
await atom.workspace.open(item)
|
||||
const dock = atom.workspace.getLeftDock()
|
||||
const dockElement = dock.getElement()
|
||||
|
||||
dock.setState({size: 300})
|
||||
dock.setState({ size: 300 })
|
||||
await getNextUpdatePromise()
|
||||
expect(dockElement.offsetWidth).toBe(300)
|
||||
dockElement.querySelector('.atom-dock-resize-handle').dispatchEvent(new MouseEvent('mousedown', {detail: 2}))
|
||||
dockElement
|
||||
.querySelector('.atom-dock-resize-handle')
|
||||
.dispatchEvent(new MouseEvent('mousedown', { detail: 2 }))
|
||||
await getNextUpdatePromise()
|
||||
|
||||
expect(dockElement.offsetWidth).toBe(item.getPreferredWidth())
|
||||
})
|
||||
|
||||
it('resizes a horizontally-oriented dock to the current item\'s preferred width', async () => {
|
||||
it("resizes a horizontally-oriented dock to the current item's preferred width", async () => {
|
||||
jasmine.attachToDOM(atom.workspace.getElement())
|
||||
|
||||
const item = {
|
||||
element: document.createElement('div'),
|
||||
getDefaultLocation() { return 'bottom' },
|
||||
getPreferredWidth() { return 122 },
|
||||
getPreferredHeight() { return 142 }
|
||||
getDefaultLocation () {
|
||||
return 'bottom'
|
||||
},
|
||||
getPreferredWidth () {
|
||||
return 122
|
||||
},
|
||||
getPreferredHeight () {
|
||||
return 142
|
||||
}
|
||||
}
|
||||
|
||||
await atom.workspace.open(item)
|
||||
const dock = atom.workspace.getBottomDock()
|
||||
const dockElement = dock.getElement()
|
||||
|
||||
dock.setState({size: 300})
|
||||
dock.setState({ size: 300 })
|
||||
await getNextUpdatePromise()
|
||||
expect(dockElement.offsetHeight).toBe(300)
|
||||
dockElement.querySelector('.atom-dock-resize-handle').dispatchEvent(new MouseEvent('mousedown', {detail: 2}))
|
||||
dockElement
|
||||
.querySelector('.atom-dock-resize-handle')
|
||||
.dispatchEvent(new MouseEvent('mousedown', { detail: 2 }))
|
||||
await getNextUpdatePromise()
|
||||
|
||||
expect(dockElement.offsetHeight).toBe(item.getPreferredHeight())
|
||||
@@ -198,19 +234,31 @@ describe('Dock', () => {
|
||||
|
||||
const item = {
|
||||
element: document.createElement('div'),
|
||||
getDefaultLocation() { return 'bottom' },
|
||||
getPreferredWidth() { return 122 },
|
||||
getPreferredHeight() { return 142 }
|
||||
getDefaultLocation () {
|
||||
return 'bottom'
|
||||
},
|
||||
getPreferredWidth () {
|
||||
return 122
|
||||
},
|
||||
getPreferredHeight () {
|
||||
return 142
|
||||
}
|
||||
}
|
||||
|
||||
await atom.workspace.open(item, {activatePane: false})
|
||||
await atom.workspace.open(item, { activatePane: false })
|
||||
|
||||
const dockElement = atom.workspace.getBottomDock().getElement()
|
||||
dockElement.querySelector('.atom-dock-resize-handle').dispatchEvent(new MouseEvent('mousedown', {detail: 2}))
|
||||
dockElement
|
||||
.querySelector('.atom-dock-resize-handle')
|
||||
.dispatchEvent(new MouseEvent('mousedown', { detail: 2 }))
|
||||
expect(dockElement.offsetHeight).toBe(0)
|
||||
expect(dockElement.querySelector('.atom-dock-inner').offsetHeight).toBe(0)
|
||||
expect(dockElement.querySelector('.atom-dock-inner').offsetHeight).toBe(
|
||||
0
|
||||
)
|
||||
// The content should be masked away.
|
||||
expect(dockElement.querySelector('.atom-dock-mask').offsetHeight).toBe(0)
|
||||
expect(dockElement.querySelector('.atom-dock-mask').offsetHeight).toBe(
|
||||
0
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -222,8 +270,12 @@ describe('Dock', () => {
|
||||
|
||||
const createItem = preferredWidth => ({
|
||||
element: document.createElement('div'),
|
||||
getDefaultLocation() { return 'left' },
|
||||
getPreferredWidth() { return preferredWidth }
|
||||
getDefaultLocation () {
|
||||
return 'left'
|
||||
},
|
||||
getPreferredWidth () {
|
||||
return preferredWidth
|
||||
}
|
||||
})
|
||||
|
||||
const dock = atom.workspace.getLeftDock()
|
||||
@@ -257,7 +309,9 @@ describe('Dock', () => {
|
||||
|
||||
const item = {
|
||||
element: document.createElement('div'),
|
||||
getDefaultLocation() { return 'left' }
|
||||
getDefaultLocation () {
|
||||
return 'left'
|
||||
}
|
||||
}
|
||||
const dock = atom.workspace.getLeftDock()
|
||||
expect(dock.getPaneItems()).toHaveLength(0)
|
||||
@@ -275,11 +329,15 @@ describe('Dock', () => {
|
||||
|
||||
const item = {
|
||||
element: document.createElement('div'),
|
||||
getDefaultLocation() { return 'left' },
|
||||
getPreferredWidth() { return 122 },
|
||||
serialize: () => ({deserializer: 'DockTestItem'})
|
||||
getDefaultLocation () {
|
||||
return 'left'
|
||||
},
|
||||
getPreferredWidth () {
|
||||
return 122
|
||||
},
|
||||
serialize: () => ({ deserializer: 'DockTestItem' })
|
||||
}
|
||||
const itemDeserializer = atom.deserializers.add({
|
||||
atom.deserializers.add({
|
||||
name: 'DockTestItem',
|
||||
deserialize: () => item
|
||||
})
|
||||
@@ -287,10 +345,10 @@ describe('Dock', () => {
|
||||
const dockElement = dock.getElement()
|
||||
|
||||
await atom.workspace.open(item)
|
||||
dock.setState({size: 150})
|
||||
dock.setState({ size: 150 })
|
||||
expect(dockElement.offsetWidth).toBe(150)
|
||||
const serialized = dock.serialize()
|
||||
dock.setState({size: 122})
|
||||
dock.setState({ size: 122 })
|
||||
expect(dockElement.offsetWidth).toBe(122)
|
||||
dock.destroyActivePane()
|
||||
dock.deserialize(serialized, atom.deserializers)
|
||||
@@ -302,8 +360,12 @@ describe('Dock', () => {
|
||||
|
||||
const item = {
|
||||
element: document.createElement('div'),
|
||||
getDefaultLocation() { return 'left' },
|
||||
getPreferredWidth() { return 122 }
|
||||
getDefaultLocation () {
|
||||
return 'left'
|
||||
},
|
||||
getPreferredWidth () {
|
||||
return 122
|
||||
}
|
||||
}
|
||||
const dock = atom.workspace.getLeftDock()
|
||||
|
||||
@@ -324,16 +386,22 @@ describe('Dock', () => {
|
||||
element.setAttribute('is', 'tabs-tab')
|
||||
element.item = {
|
||||
element,
|
||||
getDefaultLocation() { return 'left' },
|
||||
getPreferredWidth() { return 144 }
|
||||
getDefaultLocation () {
|
||||
return 'left'
|
||||
},
|
||||
getPreferredWidth () {
|
||||
return 144
|
||||
}
|
||||
}
|
||||
|
||||
const dragEvent = new DragEvent('dragstart')
|
||||
Object.defineProperty(dragEvent, 'target', {value: element})
|
||||
Object.defineProperty(dragEvent, 'target', { value: element })
|
||||
|
||||
atom.workspace.getElement().handleDragStart(dragEvent)
|
||||
await getNextUpdatePromise()
|
||||
expect(atom.workspace.getLeftDock().refs.wrapperElement.offsetWidth).toBe(144)
|
||||
expect(atom.workspace.getLeftDock().refs.wrapperElement.offsetWidth).toBe(
|
||||
144
|
||||
)
|
||||
})
|
||||
|
||||
it('does nothing when text nodes are dragged', () => {
|
||||
@@ -342,9 +410,11 @@ describe('Dock', () => {
|
||||
const textNode = document.createTextNode('hello')
|
||||
|
||||
const dragEvent = new DragEvent('dragstart')
|
||||
Object.defineProperty(dragEvent, 'target', {value: textNode})
|
||||
Object.defineProperty(dragEvent, 'target', { value: textNode })
|
||||
|
||||
expect(() => atom.workspace.getElement().handleDragStart(dragEvent)).not.toThrow()
|
||||
expect(() =>
|
||||
atom.workspace.getElement().handleDragStart(dragEvent)
|
||||
).not.toThrow()
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -1,16 +1,20 @@
|
||||
const path = require('path')
|
||||
const fs = require('fs-plus')
|
||||
const temp = require('temp').track()
|
||||
const {Directory} = require('pathwatcher')
|
||||
const { Directory } = require('pathwatcher')
|
||||
const GitRepository = require('../src/git-repository')
|
||||
const GitRepositoryProvider = require('../src/git-repository-provider')
|
||||
const {it, fit, ffit, fffit, beforeEach} = require('./async-spec-helpers')
|
||||
const { it, beforeEach } = require('./async-spec-helpers')
|
||||
|
||||
describe('GitRepositoryProvider', () => {
|
||||
let provider
|
||||
|
||||
beforeEach(() => {
|
||||
provider = new GitRepositoryProvider(atom.project, atom.config, atom.confirm)
|
||||
provider = new GitRepositoryProvider(
|
||||
atom.project,
|
||||
atom.config,
|
||||
atom.confirm
|
||||
)
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
@@ -24,7 +28,9 @@ describe('GitRepositoryProvider', () => {
|
||||
describe('.repositoryForDirectory(directory)', () => {
|
||||
describe('when specified a Directory with a Git repository', () => {
|
||||
it('resolves with a GitRepository', async () => {
|
||||
const directory = new Directory(path.join(__dirname, 'fixtures', 'git', 'master.git'))
|
||||
const directory = new Directory(
|
||||
path.join(__dirname, 'fixtures', 'git', 'master.git')
|
||||
)
|
||||
const result = await provider.repositoryForDirectory(directory)
|
||||
expect(result).toBeInstanceOf(GitRepository)
|
||||
expect(provider.pathToRepository[result.getPath()]).toBeTruthy()
|
||||
@@ -39,7 +45,9 @@ describe('GitRepositoryProvider', () => {
|
||||
new Directory(path.join(__dirname, 'fixtures', 'git', 'master.git'))
|
||||
)
|
||||
const secondRepo = await provider.repositoryForDirectory(
|
||||
new Directory(path.join(__dirname, 'fixtures', 'git', 'master.git', 'objects'))
|
||||
new Directory(
|
||||
path.join(__dirname, 'fixtures', 'git', 'master.git', 'objects')
|
||||
)
|
||||
)
|
||||
|
||||
expect(firstRepo).toBeInstanceOf(GitRepository)
|
||||
@@ -72,7 +80,10 @@ describe('GitRepositoryProvider', () => {
|
||||
it('returns a Promise that resolves to a GitRepository', async () => {
|
||||
const gitDirPath = path.join(__dirname, 'fixtures', 'git', 'master.git')
|
||||
const workDirPath = temp.mkdirSync('git-workdir')
|
||||
fs.writeFileSync(path.join(workDirPath, '.git'), `gitdir: ${gitDirPath}\n`)
|
||||
fs.writeFileSync(
|
||||
path.join(workDirPath, '.git'),
|
||||
`gitdir: ${gitDirPath}\n`
|
||||
)
|
||||
|
||||
const directory = new Directory(workDirPath)
|
||||
const result = await provider.repositoryForDirectory(directory)
|
||||
@@ -90,7 +101,9 @@ describe('GitRepositoryProvider', () => {
|
||||
const subdirectory = {}
|
||||
directory = {
|
||||
getSubdirectory () {},
|
||||
isRoot () { return true }
|
||||
isRoot () {
|
||||
return true
|
||||
}
|
||||
}
|
||||
spyOn(directory, 'getSubdirectory').andReturn(subdirectory)
|
||||
})
|
||||
@@ -145,7 +158,7 @@ describe('GitRepositoryProvider', () => {
|
||||
fs.writeFileSync(path.join(dirPath, '.git', 'refs'), '')
|
||||
|
||||
const directory = new Directory(dirPath)
|
||||
const repo = provider.repositoryForDirectorySync(directory)
|
||||
const repo = provider.repositoryForDirectorySync(directory)
|
||||
expect(repo).toBe(null)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const {it, fit, ffit, fffit, beforeEach, afterEach} = require('./async-spec-helpers')
|
||||
const { it, beforeEach, afterEach } = require('./async-spec-helpers')
|
||||
const path = require('path')
|
||||
const fs = require('fs-plus')
|
||||
const temp = require('temp').track()
|
||||
@@ -25,30 +25,44 @@ describe('GitRepository', () => {
|
||||
|
||||
describe('new GitRepository(path)', () => {
|
||||
it('throws an exception when no repository is found', () => {
|
||||
expect(() => new GitRepository(path.join(temp.dir, 'nogit.txt'))).toThrow()
|
||||
expect(
|
||||
() => new GitRepository(path.join(temp.dir, 'nogit.txt'))
|
||||
).toThrow()
|
||||
})
|
||||
})
|
||||
|
||||
describe('.getPath()', () => {
|
||||
it('returns the repository path for a .git directory path with a directory', () => {
|
||||
repo = new GitRepository(path.join(__dirname, 'fixtures', 'git', 'master.git', 'objects'))
|
||||
expect(repo.getPath()).toBe(path.join(__dirname, 'fixtures', 'git', 'master.git'))
|
||||
repo = new GitRepository(
|
||||
path.join(__dirname, 'fixtures', 'git', 'master.git', 'objects')
|
||||
)
|
||||
expect(repo.getPath()).toBe(
|
||||
path.join(__dirname, 'fixtures', 'git', 'master.git')
|
||||
)
|
||||
})
|
||||
|
||||
it('returns the repository path for a repository path', () => {
|
||||
repo = new GitRepository(path.join(__dirname, 'fixtures', 'git', 'master.git'))
|
||||
expect(repo.getPath()).toBe(path.join(__dirname, 'fixtures', 'git', 'master.git'))
|
||||
repo = new GitRepository(
|
||||
path.join(__dirname, 'fixtures', 'git', 'master.git')
|
||||
)
|
||||
expect(repo.getPath()).toBe(
|
||||
path.join(__dirname, 'fixtures', 'git', 'master.git')
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('.isPathIgnored(path)', () => {
|
||||
it('returns true for an ignored path', () => {
|
||||
repo = new GitRepository(path.join(__dirname, 'fixtures', 'git', 'ignore.git'))
|
||||
repo = new GitRepository(
|
||||
path.join(__dirname, 'fixtures', 'git', 'ignore.git')
|
||||
)
|
||||
expect(repo.isPathIgnored('a.txt')).toBeTruthy()
|
||||
})
|
||||
|
||||
it('returns false for a non-ignored path', () => {
|
||||
repo = new GitRepository(path.join(__dirname, 'fixtures', 'git', 'ignore.git'))
|
||||
repo = new GitRepository(
|
||||
path.join(__dirname, 'fixtures', 'git', 'ignore.git')
|
||||
)
|
||||
expect(repo.isPathIgnored('b.txt')).toBeFalsy()
|
||||
})
|
||||
})
|
||||
@@ -136,7 +150,10 @@ describe('GitRepository', () => {
|
||||
repo.onDidChangeStatus(statusHandler)
|
||||
repo.checkoutHead(filePath)
|
||||
expect(statusHandler.callCount).toBe(1)
|
||||
expect(statusHandler.argsForCall[0][0]).toEqual({path: filePath, pathStatus: 0})
|
||||
expect(statusHandler.argsForCall[0][0]).toEqual({
|
||||
path: filePath,
|
||||
pathStatus: 0
|
||||
})
|
||||
|
||||
repo.checkoutHead(filePath)
|
||||
expect(statusHandler.callCount).toBe(1)
|
||||
@@ -150,7 +167,11 @@ describe('GitRepository', () => {
|
||||
spyOn(atom, 'confirm')
|
||||
|
||||
const workingDirPath = copyRepository()
|
||||
repo = new GitRepository(workingDirPath, {project: atom.project, config: atom.config, confirm: atom.confirm})
|
||||
repo = new GitRepository(workingDirPath, {
|
||||
project: atom.project,
|
||||
config: atom.config,
|
||||
confirm: atom.confirm
|
||||
})
|
||||
filePath = path.join(workingDirPath, 'a.txt')
|
||||
fs.writeFileSync(filePath, 'ch ch changes')
|
||||
|
||||
@@ -161,7 +182,7 @@ describe('GitRepository', () => {
|
||||
// Permissions issues with this test on Windows
|
||||
if (process.platform === 'win32') return
|
||||
|
||||
atom.confirm.andCallFake(({buttons}) => buttons.OK())
|
||||
atom.confirm.andCallFake(({ buttons }) => buttons.OK())
|
||||
atom.config.set('editor.confirmCheckoutHeadRevision', true)
|
||||
|
||||
repo.checkoutHeadForEditor(editor)
|
||||
@@ -183,7 +204,9 @@ describe('GitRepository', () => {
|
||||
|
||||
describe('.destroy()', () => {
|
||||
it('throws an exception when any method is called after it is called', () => {
|
||||
repo = new GitRepository(path.join(__dirname, 'fixtures', 'git', 'master.git'))
|
||||
repo = new GitRepository(
|
||||
path.join(__dirname, 'fixtures', 'git', 'master.git')
|
||||
)
|
||||
repo.destroy()
|
||||
expect(() => repo.getShortHead()).toThrow()
|
||||
})
|
||||
@@ -204,7 +227,10 @@ describe('GitRepository', () => {
|
||||
fs.writeFileSync(filePath, '')
|
||||
let status = repo.getPathStatus(filePath)
|
||||
expect(statusHandler.callCount).toBe(1)
|
||||
expect(statusHandler.argsForCall[0][0]).toEqual({path: filePath, pathStatus: status})
|
||||
expect(statusHandler.argsForCall[0][0]).toEqual({
|
||||
path: filePath,
|
||||
pathStatus: status
|
||||
})
|
||||
|
||||
fs.writeFileSync(filePath, 'abc')
|
||||
status = repo.getPathStatus(filePath)
|
||||
@@ -223,10 +249,14 @@ describe('GitRepository', () => {
|
||||
})
|
||||
|
||||
it('gets the status based on the files inside the directory', () => {
|
||||
expect(repo.isStatusModified(repo.getDirectoryStatus(directoryPath))).toBe(false)
|
||||
expect(
|
||||
repo.isStatusModified(repo.getDirectoryStatus(directoryPath))
|
||||
).toBe(false)
|
||||
fs.writeFileSync(filePath, 'abc')
|
||||
repo.getPathStatus(filePath)
|
||||
expect(repo.isStatusModified(repo.getDirectoryStatus(directoryPath))).toBe(true)
|
||||
expect(
|
||||
repo.isStatusModified(repo.getDirectoryStatus(directoryPath))
|
||||
).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -235,7 +265,10 @@ describe('GitRepository', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
workingDirectory = copyRepository()
|
||||
repo = new GitRepository(workingDirectory, {project: atom.project, config: atom.config})
|
||||
repo = new GitRepository(workingDirectory, {
|
||||
project: atom.project,
|
||||
config: atom.config
|
||||
})
|
||||
modifiedPath = path.join(workingDirectory, 'file.txt')
|
||||
newPath = path.join(workingDirectory, 'untracked.txt')
|
||||
cleanPath = path.join(workingDirectory, 'other.txt')
|
||||
@@ -252,8 +285,10 @@ describe('GitRepository', () => {
|
||||
await repo.refreshStatus()
|
||||
expect(statusHandler.callCount).toBe(1)
|
||||
expect(repo.getCachedPathStatus(cleanPath)).toBeUndefined()
|
||||
expect(repo.isStatusNew(repo.getCachedPathStatus(newPath) )).toBeTruthy()
|
||||
expect(repo.isStatusModified(repo.getCachedPathStatus(modifiedPath))).toBeTruthy()
|
||||
expect(repo.isStatusNew(repo.getCachedPathStatus(newPath))).toBeTruthy()
|
||||
expect(
|
||||
repo.isStatusModified(repo.getCachedPathStatus(modifiedPath))
|
||||
).toBeTruthy()
|
||||
})
|
||||
|
||||
it('caches the proper statuses when a subdir is open', async () => {
|
||||
@@ -278,7 +313,9 @@ describe('GitRepository', () => {
|
||||
await repo.refreshStatus()
|
||||
expect(repo.getCachedPathStatus(cleanPath)).toBeUndefined()
|
||||
expect(repo.isStatusNew(repo.getCachedPathStatus(newPath))).toBeTruthy()
|
||||
expect(repo.isStatusModified(repo.getCachedPathStatus(modifiedPath))).toBeTruthy()
|
||||
expect(
|
||||
repo.isStatusModified(repo.getCachedPathStatus(modifiedPath))
|
||||
).toBeTruthy()
|
||||
})
|
||||
|
||||
it('caches statuses that were looked up synchronously', async () => {
|
||||
@@ -288,7 +325,9 @@ describe('GitRepository', () => {
|
||||
|
||||
fs.writeFileSync(modifiedPath, originalContent)
|
||||
await repo.refreshStatus()
|
||||
expect(repo.isStatusModified(repo.getCachedPathStatus(modifiedPath))).toBeFalsy()
|
||||
expect(
|
||||
repo.isStatusModified(repo.getCachedPathStatus(modifiedPath))
|
||||
).toBeFalsy()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -297,7 +336,9 @@ describe('GitRepository', () => {
|
||||
|
||||
beforeEach(async () => {
|
||||
atom.project.setPaths([copyRepository()])
|
||||
const refreshPromise = new Promise(resolve => atom.project.getRepositories()[0].onDidChangeStatuses(resolve))
|
||||
const refreshPromise = new Promise(resolve =>
|
||||
atom.project.getRepositories()[0].onDidChangeStatuses(resolve)
|
||||
)
|
||||
editor = await atom.workspace.open('other.txt')
|
||||
await refreshPromise
|
||||
})
|
||||
@@ -310,7 +351,10 @@ describe('GitRepository', () => {
|
||||
|
||||
await editor.save()
|
||||
expect(statusHandler.callCount).toBe(1)
|
||||
expect(statusHandler).toHaveBeenCalledWith({path: editor.getPath(), pathStatus: 256})
|
||||
expect(statusHandler).toHaveBeenCalledWith({
|
||||
path: editor.getPath(),
|
||||
pathStatus: 256
|
||||
})
|
||||
})
|
||||
|
||||
it('emits a status-changed event when a buffer is reloaded', async () => {
|
||||
@@ -321,7 +365,10 @@ describe('GitRepository', () => {
|
||||
|
||||
await editor.getBuffer().reload()
|
||||
expect(statusHandler.callCount).toBe(1)
|
||||
expect(statusHandler).toHaveBeenCalledWith({path: editor.getPath(), pathStatus: 256})
|
||||
expect(statusHandler).toHaveBeenCalledWith({
|
||||
path: editor.getPath(),
|
||||
pathStatus: 256
|
||||
})
|
||||
|
||||
await editor.getBuffer().reload()
|
||||
expect(statusHandler.callCount).toBe(1)
|
||||
@@ -334,7 +381,10 @@ describe('GitRepository', () => {
|
||||
atom.project.getRepositories()[0].onDidChangeStatus(statusHandler)
|
||||
editor.getBuffer().emitter.emit('did-change-path')
|
||||
expect(statusHandler.callCount).toBe(1)
|
||||
expect(statusHandler).toHaveBeenCalledWith({path: editor.getPath(), pathStatus: 256})
|
||||
expect(statusHandler).toHaveBeenCalledWith({
|
||||
path: editor.getPath(),
|
||||
pathStatus: 256
|
||||
})
|
||||
editor.getBuffer().emitter.emit('did-change-path')
|
||||
expect(statusHandler.callCount).toBe(1)
|
||||
})
|
||||
@@ -364,11 +414,9 @@ describe('GitRepository', () => {
|
||||
grammarRegistry: atom.grammars,
|
||||
applicationDelegate: atom.applicationDelegate
|
||||
})
|
||||
await project2.deserialize(atom.project.serialize({isUnloading: false}))
|
||||
await project2.deserialize(atom.project.serialize({ isUnloading: false }))
|
||||
|
||||
buffer = project2.getBuffers()[0]
|
||||
|
||||
const originalContent = buffer.getText()
|
||||
buffer.append('changes')
|
||||
|
||||
statusHandler = jasmine.createSpy('statusHandler')
|
||||
@@ -376,14 +424,23 @@ describe('GitRepository', () => {
|
||||
await buffer.save()
|
||||
|
||||
expect(statusHandler.callCount).toBe(1)
|
||||
expect(statusHandler).toHaveBeenCalledWith({path: buffer.getPath(), pathStatus: 256})
|
||||
expect(statusHandler).toHaveBeenCalledWith({
|
||||
path: buffer.getPath(),
|
||||
pathStatus: 256
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
function copyRepository () {
|
||||
const workingDirPath = temp.mkdirSync('atom-spec-git')
|
||||
fs.copySync(path.join(__dirname, 'fixtures', 'git', 'working-dir'), workingDirPath)
|
||||
fs.renameSync(path.join(workingDirPath, 'git.git'), path.join(workingDirPath, '.git'))
|
||||
fs.copySync(
|
||||
path.join(__dirname, 'fixtures', 'git', 'working-dir'),
|
||||
workingDirPath
|
||||
)
|
||||
fs.renameSync(
|
||||
path.join(workingDirPath, 'git.git'),
|
||||
path.join(workingDirPath, '.git')
|
||||
)
|
||||
return workingDirPath
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const {it, fit, ffit, fffit, beforeEach, afterEach} = require('./async-spec-helpers')
|
||||
const { it, beforeEach, afterEach } = require('./async-spec-helpers')
|
||||
|
||||
const dedent = require('dedent')
|
||||
const path = require('path')
|
||||
@@ -13,14 +13,18 @@ describe('GrammarRegistry', () => {
|
||||
let grammarRegistry
|
||||
|
||||
beforeEach(() => {
|
||||
grammarRegistry = new GrammarRegistry({config: atom.config})
|
||||
grammarRegistry = new GrammarRegistry({ config: atom.config })
|
||||
expect(subscriptionCount(grammarRegistry)).toBe(1)
|
||||
})
|
||||
|
||||
describe('.assignLanguageMode(buffer, languageId)', () => {
|
||||
it('assigns to the buffer a language mode with the given language id', async () => {
|
||||
grammarRegistry.loadGrammarSync(require.resolve('language-javascript/grammars/javascript.cson'))
|
||||
grammarRegistry.loadGrammarSync(require.resolve('language-css/grammars/css.cson'))
|
||||
grammarRegistry.loadGrammarSync(
|
||||
require.resolve('language-javascript/grammars/javascript.cson')
|
||||
)
|
||||
grammarRegistry.loadGrammarSync(
|
||||
require.resolve('language-css/grammars/css.cson')
|
||||
)
|
||||
|
||||
const buffer = new TextBuffer()
|
||||
expect(grammarRegistry.assignLanguageMode(buffer, 'source.js')).toBe(true)
|
||||
@@ -31,7 +35,9 @@ describe('GrammarRegistry', () => {
|
||||
expect(grammarRegistry.assignLanguageMode(buffer, 'source.js')).toBe(true)
|
||||
|
||||
// Language names are not case-sensitive
|
||||
expect(grammarRegistry.assignLanguageMode(buffer, 'source.css')).toBe(true)
|
||||
expect(grammarRegistry.assignLanguageMode(buffer, 'source.css')).toBe(
|
||||
true
|
||||
)
|
||||
expect(buffer.getLanguageMode().getLanguageId()).toBe('source.css')
|
||||
|
||||
// Returns false if no language is found
|
||||
@@ -41,14 +47,20 @@ describe('GrammarRegistry', () => {
|
||||
|
||||
describe('when no languageId is passed', () => {
|
||||
it('makes the buffer use the null grammar', () => {
|
||||
grammarRegistry.loadGrammarSync(require.resolve('language-css/grammars/css.cson'))
|
||||
grammarRegistry.loadGrammarSync(
|
||||
require.resolve('language-css/grammars/css.cson')
|
||||
)
|
||||
|
||||
const buffer = new TextBuffer()
|
||||
expect(grammarRegistry.assignLanguageMode(buffer, 'source.css')).toBe(true)
|
||||
expect(grammarRegistry.assignLanguageMode(buffer, 'source.css')).toBe(
|
||||
true
|
||||
)
|
||||
expect(buffer.getLanguageMode().getLanguageId()).toBe('source.css')
|
||||
|
||||
expect(grammarRegistry.assignLanguageMode(buffer, null)).toBe(true)
|
||||
expect(buffer.getLanguageMode().getLanguageId()).toBe('text.plain.null-grammar')
|
||||
expect(buffer.getLanguageMode().getLanguageId()).toBe(
|
||||
'text.plain.null-grammar'
|
||||
)
|
||||
expect(grammarRegistry.getAssignedLanguageId(buffer)).toBe(null)
|
||||
})
|
||||
})
|
||||
@@ -56,10 +68,18 @@ describe('GrammarRegistry', () => {
|
||||
|
||||
describe('.grammarForId(languageId)', () => {
|
||||
it('returns a text-mate grammar when `core.useTreeSitterParsers` is false', () => {
|
||||
atom.config.set('core.useTreeSitterParsers', false, {scopeSelector: '.source.js'})
|
||||
atom.config.set('core.useTreeSitterParsers', false, {
|
||||
scopeSelector: '.source.js'
|
||||
})
|
||||
|
||||
grammarRegistry.loadGrammarSync(require.resolve('language-javascript/grammars/javascript.cson'))
|
||||
grammarRegistry.loadGrammarSync(require.resolve('language-javascript/grammars/tree-sitter-javascript.cson'))
|
||||
grammarRegistry.loadGrammarSync(
|
||||
require.resolve('language-javascript/grammars/javascript.cson')
|
||||
)
|
||||
grammarRegistry.loadGrammarSync(
|
||||
require.resolve(
|
||||
'language-javascript/grammars/tree-sitter-javascript.cson'
|
||||
)
|
||||
)
|
||||
|
||||
const grammar = grammarRegistry.grammarForId('source.js')
|
||||
expect(grammar instanceof FirstMate.Grammar).toBe(true)
|
||||
@@ -72,26 +92,40 @@ describe('GrammarRegistry', () => {
|
||||
it('returns a tree-sitter grammar when `core.useTreeSitterParsers` is true', () => {
|
||||
atom.config.set('core.useTreeSitterParsers', true)
|
||||
|
||||
grammarRegistry.loadGrammarSync(require.resolve('language-javascript/grammars/javascript.cson'))
|
||||
grammarRegistry.loadGrammarSync(require.resolve('language-javascript/grammars/tree-sitter-javascript.cson'))
|
||||
grammarRegistry.loadGrammarSync(
|
||||
require.resolve('language-javascript/grammars/javascript.cson')
|
||||
)
|
||||
grammarRegistry.loadGrammarSync(
|
||||
require.resolve(
|
||||
'language-javascript/grammars/tree-sitter-javascript.cson'
|
||||
)
|
||||
)
|
||||
|
||||
const grammar = grammarRegistry.grammarForId('source.js')
|
||||
expect(grammar instanceof TreeSitterGrammar).toBe(true)
|
||||
expect(grammar.scopeName).toBe('source.js')
|
||||
|
||||
grammarRegistry.removeGrammar(grammar)
|
||||
expect(grammarRegistry.grammarForId('source.js') instanceof FirstMate.Grammar).toBe(true)
|
||||
expect(
|
||||
grammarRegistry.grammarForId('source.js') instanceof FirstMate.Grammar
|
||||
).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('.autoAssignLanguageMode(buffer)', () => {
|
||||
it('assigns to the buffer a language mode based on the best available grammar', () => {
|
||||
grammarRegistry.loadGrammarSync(require.resolve('language-javascript/grammars/javascript.cson'))
|
||||
grammarRegistry.loadGrammarSync(require.resolve('language-css/grammars/css.cson'))
|
||||
grammarRegistry.loadGrammarSync(
|
||||
require.resolve('language-javascript/grammars/javascript.cson')
|
||||
)
|
||||
grammarRegistry.loadGrammarSync(
|
||||
require.resolve('language-css/grammars/css.cson')
|
||||
)
|
||||
|
||||
const buffer = new TextBuffer()
|
||||
buffer.setPath('foo.js')
|
||||
expect(grammarRegistry.assignLanguageMode(buffer, 'source.css')).toBe(true)
|
||||
expect(grammarRegistry.assignLanguageMode(buffer, 'source.css')).toBe(
|
||||
true
|
||||
)
|
||||
expect(buffer.getLanguageMode().getLanguageId()).toBe('source.css')
|
||||
|
||||
grammarRegistry.autoAssignLanguageMode(buffer)
|
||||
@@ -103,8 +137,12 @@ describe('GrammarRegistry', () => {
|
||||
it('assigns a grammar to the buffer based on its path', async () => {
|
||||
const buffer = new TextBuffer()
|
||||
|
||||
grammarRegistry.loadGrammarSync(require.resolve('language-javascript/grammars/javascript.cson'))
|
||||
grammarRegistry.loadGrammarSync(require.resolve('language-c/grammars/c.cson'))
|
||||
grammarRegistry.loadGrammarSync(
|
||||
require.resolve('language-javascript/grammars/javascript.cson')
|
||||
)
|
||||
grammarRegistry.loadGrammarSync(
|
||||
require.resolve('language-c/grammars/c.cson')
|
||||
)
|
||||
|
||||
buffer.setPath('test.js')
|
||||
grammarRegistry.maintainLanguageMode(buffer)
|
||||
@@ -114,7 +152,7 @@ describe('GrammarRegistry', () => {
|
||||
expect(buffer.getLanguageMode().getLanguageId()).toBe('source.c')
|
||||
})
|
||||
|
||||
it('updates the buffer\'s grammar when a more appropriate text-mate grammar is added for its path', async () => {
|
||||
it("updates the buffer's grammar when a more appropriate text-mate grammar is added for its path", async () => {
|
||||
atom.config.set('core.useTreeSitterParsers', false)
|
||||
|
||||
const buffer = new TextBuffer()
|
||||
@@ -123,14 +161,20 @@ describe('GrammarRegistry', () => {
|
||||
buffer.setPath('test.js')
|
||||
grammarRegistry.maintainLanguageMode(buffer)
|
||||
|
||||
const textMateGrammar = grammarRegistry.loadGrammarSync(require.resolve('language-javascript/grammars/javascript.cson'))
|
||||
const textMateGrammar = grammarRegistry.loadGrammarSync(
|
||||
require.resolve('language-javascript/grammars/javascript.cson')
|
||||
)
|
||||
expect(buffer.getLanguageMode().grammar).toBe(textMateGrammar)
|
||||
|
||||
grammarRegistry.loadGrammarSync(require.resolve('language-javascript/grammars/tree-sitter-javascript.cson'))
|
||||
grammarRegistry.loadGrammarSync(
|
||||
require.resolve(
|
||||
'language-javascript/grammars/tree-sitter-javascript.cson'
|
||||
)
|
||||
)
|
||||
expect(buffer.getLanguageMode().grammar).toBe(textMateGrammar)
|
||||
})
|
||||
|
||||
it('updates the buffer\'s grammar when a more appropriate tree-sitter grammar is added for its path', async () => {
|
||||
it("updates the buffer's grammar when a more appropriate tree-sitter grammar is added for its path", async () => {
|
||||
atom.config.set('core.useTreeSitterParsers', true)
|
||||
|
||||
const buffer = new TextBuffer()
|
||||
@@ -139,10 +183,16 @@ describe('GrammarRegistry', () => {
|
||||
buffer.setPath('test.js')
|
||||
grammarRegistry.maintainLanguageMode(buffer)
|
||||
|
||||
const treeSitterGrammar = grammarRegistry.loadGrammarSync(require.resolve('language-javascript/grammars/tree-sitter-javascript.cson'))
|
||||
const treeSitterGrammar = grammarRegistry.loadGrammarSync(
|
||||
require.resolve(
|
||||
'language-javascript/grammars/tree-sitter-javascript.cson'
|
||||
)
|
||||
)
|
||||
expect(buffer.getLanguageMode().grammar).toBe(treeSitterGrammar)
|
||||
|
||||
grammarRegistry.loadGrammarSync(require.resolve('language-javascript/grammars/javascript.cson'))
|
||||
grammarRegistry.loadGrammarSync(
|
||||
require.resolve('language-javascript/grammars/javascript.cson')
|
||||
)
|
||||
expect(buffer.getLanguageMode().grammar).toBe(treeSitterGrammar)
|
||||
})
|
||||
|
||||
@@ -152,41 +202,59 @@ describe('GrammarRegistry', () => {
|
||||
buffer.setPath('test.js')
|
||||
grammarRegistry.maintainLanguageMode(buffer)
|
||||
|
||||
grammarRegistry.loadGrammarSync(require.resolve('language-css/grammars/css.cson'))
|
||||
expect(grammarRegistry.assignLanguageMode(buffer, 'source.css')).toBe(true)
|
||||
grammarRegistry.loadGrammarSync(
|
||||
require.resolve('language-css/grammars/css.cson')
|
||||
)
|
||||
expect(grammarRegistry.assignLanguageMode(buffer, 'source.css')).toBe(
|
||||
true
|
||||
)
|
||||
expect(buffer.getLanguageMode().getLanguageId()).toBe('source.css')
|
||||
|
||||
grammarRegistry.loadGrammarSync(require.resolve('language-javascript/grammars/javascript.cson'))
|
||||
grammarRegistry.loadGrammarSync(
|
||||
require.resolve('language-javascript/grammars/javascript.cson')
|
||||
)
|
||||
expect(buffer.getLanguageMode().getLanguageId()).toBe('source.css')
|
||||
})
|
||||
|
||||
it('returns a disposable that can be used to stop the registry from updating the buffer', async () => {
|
||||
const buffer = new TextBuffer()
|
||||
grammarRegistry.loadGrammarSync(require.resolve('language-javascript/grammars/javascript.cson'))
|
||||
grammarRegistry.loadGrammarSync(
|
||||
require.resolve('language-javascript/grammars/javascript.cson')
|
||||
)
|
||||
|
||||
const previousSubscriptionCount = buffer.emitter.getTotalListenerCount()
|
||||
const disposable = grammarRegistry.maintainLanguageMode(buffer)
|
||||
expect(buffer.emitter.getTotalListenerCount()).toBeGreaterThan(previousSubscriptionCount)
|
||||
expect(buffer.emitter.getTotalListenerCount()).toBeGreaterThan(
|
||||
previousSubscriptionCount
|
||||
)
|
||||
expect(retainedBufferCount(grammarRegistry)).toBe(1)
|
||||
|
||||
buffer.setPath('test.js')
|
||||
expect(buffer.getLanguageMode().getLanguageId()).toBe('source.js')
|
||||
|
||||
buffer.setPath('test.txt')
|
||||
expect(buffer.getLanguageMode().getLanguageId()).toBe('text.plain.null-grammar')
|
||||
expect(buffer.getLanguageMode().getLanguageId()).toBe(
|
||||
'text.plain.null-grammar'
|
||||
)
|
||||
|
||||
disposable.dispose()
|
||||
expect(buffer.emitter.getTotalListenerCount()).toBe(previousSubscriptionCount)
|
||||
expect(buffer.emitter.getTotalListenerCount()).toBe(
|
||||
previousSubscriptionCount
|
||||
)
|
||||
expect(retainedBufferCount(grammarRegistry)).toBe(0)
|
||||
|
||||
buffer.setPath('test.js')
|
||||
expect(buffer.getLanguageMode().getLanguageId()).toBe('text.plain.null-grammar')
|
||||
expect(buffer.getLanguageMode().getLanguageId()).toBe(
|
||||
'text.plain.null-grammar'
|
||||
)
|
||||
expect(retainedBufferCount(grammarRegistry)).toBe(0)
|
||||
})
|
||||
|
||||
it('doesn\'t do anything when called a second time with the same buffer', async () => {
|
||||
it("doesn't do anything when called a second time with the same buffer", async () => {
|
||||
const buffer = new TextBuffer()
|
||||
grammarRegistry.loadGrammarSync(require.resolve('language-javascript/grammars/javascript.cson'))
|
||||
grammarRegistry.loadGrammarSync(
|
||||
require.resolve('language-javascript/grammars/javascript.cson')
|
||||
)
|
||||
const disposable1 = grammarRegistry.maintainLanguageMode(buffer)
|
||||
const disposable2 = grammarRegistry.maintainLanguageMode(buffer)
|
||||
|
||||
@@ -195,16 +263,22 @@ describe('GrammarRegistry', () => {
|
||||
|
||||
disposable2.dispose()
|
||||
buffer.setPath('test.txt')
|
||||
expect(buffer.getLanguageMode().getLanguageId()).toBe('text.plain.null-grammar')
|
||||
expect(buffer.getLanguageMode().getLanguageId()).toBe(
|
||||
'text.plain.null-grammar'
|
||||
)
|
||||
|
||||
disposable1.dispose()
|
||||
buffer.setPath('test.js')
|
||||
expect(buffer.getLanguageMode().getLanguageId()).toBe('text.plain.null-grammar')
|
||||
expect(buffer.getLanguageMode().getLanguageId()).toBe(
|
||||
'text.plain.null-grammar'
|
||||
)
|
||||
})
|
||||
|
||||
it('does not retain the buffer after the buffer is destroyed', () => {
|
||||
const buffer = new TextBuffer()
|
||||
grammarRegistry.loadGrammarSync(require.resolve('language-javascript/grammars/javascript.cson'))
|
||||
grammarRegistry.loadGrammarSync(
|
||||
require.resolve('language-javascript/grammars/javascript.cson')
|
||||
)
|
||||
|
||||
const disposable = grammarRegistry.maintainLanguageMode(buffer)
|
||||
expect(retainedBufferCount(grammarRegistry)).toBe(1)
|
||||
@@ -222,9 +296,11 @@ describe('GrammarRegistry', () => {
|
||||
|
||||
it('does not retain the buffer when the grammar registry is destroyed', () => {
|
||||
const buffer = new TextBuffer()
|
||||
grammarRegistry.loadGrammarSync(require.resolve('language-javascript/grammars/javascript.cson'))
|
||||
grammarRegistry.loadGrammarSync(
|
||||
require.resolve('language-javascript/grammars/javascript.cson')
|
||||
)
|
||||
|
||||
const disposable = grammarRegistry.maintainLanguageMode(buffer)
|
||||
grammarRegistry.maintainLanguageMode(buffer)
|
||||
expect(retainedBufferCount(grammarRegistry)).toBe(1)
|
||||
expect(subscriptionCount(grammarRegistry)).toBe(3)
|
||||
|
||||
@@ -238,19 +314,25 @@ describe('GrammarRegistry', () => {
|
||||
|
||||
describe('.selectGrammar(filePath)', () => {
|
||||
it('always returns a grammar', () => {
|
||||
const registry = new GrammarRegistry({config: atom.config})
|
||||
const registry = new GrammarRegistry({ config: atom.config })
|
||||
expect(registry.selectGrammar().scopeName).toBe('text.plain.null-grammar')
|
||||
})
|
||||
|
||||
it('selects the text.plain grammar over the null grammar', async () => {
|
||||
await atom.packages.activatePackage('language-text')
|
||||
expect(atom.grammars.selectGrammar('test.txt').scopeName).toBe('text.plain')
|
||||
expect(atom.grammars.selectGrammar('test.txt').scopeName).toBe(
|
||||
'text.plain'
|
||||
)
|
||||
})
|
||||
|
||||
it('selects a grammar based on the file path case insensitively', async () => {
|
||||
await atom.packages.activatePackage('language-coffee-script')
|
||||
expect(atom.grammars.selectGrammar('/tmp/source.coffee').scopeName).toBe('source.coffee')
|
||||
expect(atom.grammars.selectGrammar('/tmp/source.COFFEE').scopeName).toBe('source.coffee')
|
||||
expect(atom.grammars.selectGrammar('/tmp/source.coffee').scopeName).toBe(
|
||||
'source.coffee'
|
||||
)
|
||||
expect(atom.grammars.selectGrammar('/tmp/source.COFFEE').scopeName).toBe(
|
||||
'source.coffee'
|
||||
)
|
||||
})
|
||||
|
||||
describe('on Windows', () => {
|
||||
@@ -258,16 +340,18 @@ describe('GrammarRegistry', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
originalPlatform = process.platform
|
||||
Object.defineProperty(process, 'platform', {value: 'win32'})
|
||||
Object.defineProperty(process, 'platform', { value: 'win32' })
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
Object.defineProperty(process, 'platform', {value: originalPlatform})
|
||||
Object.defineProperty(process, 'platform', { value: originalPlatform })
|
||||
})
|
||||
|
||||
it('normalizes back slashes to forward slashes when matching the fileTypes', async () => {
|
||||
await atom.packages.activatePackage('language-git')
|
||||
expect(atom.grammars.selectGrammar('something\\.git\\config').scopeName).toBe('source.git-config')
|
||||
expect(
|
||||
atom.grammars.selectGrammar('something\\.git\\config').scopeName
|
||||
).toBe('source.git-config')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -277,10 +361,14 @@ describe('GrammarRegistry', () => {
|
||||
await atom.packages.activatePackage('language-ruby')
|
||||
|
||||
expect(atom.grammars.selectGrammar('file.js').name).toBe('JavaScript') // based on extension (.js)
|
||||
expect(atom.grammars.selectGrammar(path.join(temp.dir, '.git', 'config')).name).toBe('Git Config') // based on end of the path (.git/config)
|
||||
expect(
|
||||
atom.grammars.selectGrammar(path.join(temp.dir, '.git', 'config')).name
|
||||
).toBe('Git Config') // based on end of the path (.git/config)
|
||||
expect(atom.grammars.selectGrammar('Rakefile').name).toBe('Ruby') // based on the file's basename (Rakefile)
|
||||
expect(atom.grammars.selectGrammar('curb').name).toBe('Null Grammar')
|
||||
expect(atom.grammars.selectGrammar('/hu.git/config').name).toBe('Null Grammar')
|
||||
expect(atom.grammars.selectGrammar('/hu.git/config').name).toBe(
|
||||
'Null Grammar'
|
||||
)
|
||||
})
|
||||
|
||||
it("uses the filePath's shebang line if the grammar cannot be determined by the extension or basename", async () => {
|
||||
@@ -296,13 +384,20 @@ describe('GrammarRegistry', () => {
|
||||
await atom.packages.activatePackage('language-coffee-script')
|
||||
|
||||
let fileContent = 'first-line\n<html>'
|
||||
expect(atom.grammars.selectGrammar('dummy.coffee', fileContent).name).toBe('CoffeeScript')
|
||||
expect(
|
||||
atom.grammars.selectGrammar('dummy.coffee', fileContent).name
|
||||
).toBe('CoffeeScript')
|
||||
|
||||
fileContent = '<?xml version="1.0" encoding="UTF-8"?>'
|
||||
expect(atom.grammars.selectGrammar('grammar.tmLanguage', fileContent).name).toBe('Null Grammar')
|
||||
expect(
|
||||
atom.grammars.selectGrammar('grammar.tmLanguage', fileContent).name
|
||||
).toBe('Null Grammar')
|
||||
|
||||
fileContent += '\n<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">'
|
||||
expect(atom.grammars.selectGrammar('grammar.tmLanguage', fileContent).name).toBe('Property List (XML)')
|
||||
fileContent +=
|
||||
'\n<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">'
|
||||
expect(
|
||||
atom.grammars.selectGrammar('grammar.tmLanguage', fileContent).name
|
||||
).toBe('Property List (XML)')
|
||||
})
|
||||
|
||||
it("doesn't read the file when the file contents are specified", async () => {
|
||||
@@ -311,28 +406,36 @@ describe('GrammarRegistry', () => {
|
||||
const filePath = require.resolve('./fixtures/shebang')
|
||||
const filePathContents = fs.readFileSync(filePath, 'utf8')
|
||||
spyOn(fs, 'read').andCallThrough()
|
||||
expect(atom.grammars.selectGrammar(filePath, filePathContents).name).toBe('Ruby')
|
||||
expect(atom.grammars.selectGrammar(filePath, filePathContents).name).toBe(
|
||||
'Ruby'
|
||||
)
|
||||
expect(fs.read).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
describe('when multiple grammars have matching fileTypes', () => {
|
||||
it('selects the grammar with the longest fileType match', () => {
|
||||
const grammarPath1 = temp.path({suffix: '.json'})
|
||||
fs.writeFileSync(grammarPath1, JSON.stringify({
|
||||
name: 'test1',
|
||||
scopeName: 'source1',
|
||||
fileTypes: ['test']
|
||||
}))
|
||||
const grammarPath1 = temp.path({ suffix: '.json' })
|
||||
fs.writeFileSync(
|
||||
grammarPath1,
|
||||
JSON.stringify({
|
||||
name: 'test1',
|
||||
scopeName: 'source1',
|
||||
fileTypes: ['test']
|
||||
})
|
||||
)
|
||||
const grammar1 = atom.grammars.loadGrammarSync(grammarPath1)
|
||||
expect(atom.grammars.selectGrammar('more.test', '')).toBe(grammar1)
|
||||
fs.removeSync(grammarPath1)
|
||||
|
||||
const grammarPath2 = temp.path({suffix: '.json'})
|
||||
fs.writeFileSync(grammarPath2, JSON.stringify({
|
||||
name: 'test2',
|
||||
scopeName: 'source2',
|
||||
fileTypes: ['test', 'more.test']
|
||||
}))
|
||||
const grammarPath2 = temp.path({ suffix: '.json' })
|
||||
fs.writeFileSync(
|
||||
grammarPath2,
|
||||
JSON.stringify({
|
||||
name: 'test2',
|
||||
scopeName: 'source2',
|
||||
fileTypes: ['test', 'more.test']
|
||||
})
|
||||
)
|
||||
const grammar2 = atom.grammars.loadGrammarSync(grammarPath2)
|
||||
expect(atom.grammars.selectGrammar('more.test', '')).toBe(grammar2)
|
||||
return fs.removeSync(grammarPath2)
|
||||
@@ -341,19 +444,28 @@ describe('GrammarRegistry', () => {
|
||||
|
||||
it('favors non-bundled packages when breaking scoring ties', async () => {
|
||||
await atom.packages.activatePackage('language-ruby')
|
||||
await atom.packages.activatePackage(path.join(__dirname, 'fixtures', 'packages', 'package-with-rb-filetype'))
|
||||
await atom.packages.activatePackage(
|
||||
path.join(__dirname, 'fixtures', 'packages', 'package-with-rb-filetype')
|
||||
)
|
||||
|
||||
atom.grammars.grammarForScopeName('source.ruby').bundledPackage = true
|
||||
atom.grammars.grammarForScopeName('test.rb').bundledPackage = false
|
||||
|
||||
expect(atom.grammars.selectGrammar('test.rb', '#!/usr/bin/env ruby').scopeName).toBe('source.ruby')
|
||||
expect(atom.grammars.selectGrammar('test.rb', '#!/usr/bin/env testruby').scopeName).toBe('test.rb')
|
||||
expect(
|
||||
atom.grammars.selectGrammar('test.rb', '#!/usr/bin/env ruby').scopeName
|
||||
).toBe('source.ruby')
|
||||
expect(
|
||||
atom.grammars.selectGrammar('test.rb', '#!/usr/bin/env testruby')
|
||||
.scopeName
|
||||
).toBe('test.rb')
|
||||
expect(atom.grammars.selectGrammar('test.rb').scopeName).toBe('test.rb')
|
||||
})
|
||||
|
||||
describe('when there is no file path', () => {
|
||||
it('does not throw an exception (regression)', () => {
|
||||
expect(() => atom.grammars.selectGrammar(null, '#!/usr/bin/ruby')).not.toThrow()
|
||||
expect(() =>
|
||||
atom.grammars.selectGrammar(null, '#!/usr/bin/ruby')
|
||||
).not.toThrow()
|
||||
expect(() => atom.grammars.selectGrammar(null, '')).not.toThrow()
|
||||
expect(() => atom.grammars.selectGrammar(null, null)).not.toThrow()
|
||||
})
|
||||
@@ -362,8 +474,11 @@ describe('GrammarRegistry', () => {
|
||||
describe('when the user has custom grammar file types', () => {
|
||||
it('considers the custom file types as well as those defined in the grammar', async () => {
|
||||
await atom.packages.activatePackage('language-ruby')
|
||||
atom.config.set('core.customFileTypes', {'source.ruby': ['Cheffile']})
|
||||
expect(atom.grammars.selectGrammar('build/Cheffile', 'cookbook "postgres"').scopeName).toBe('source.ruby')
|
||||
atom.config.set('core.customFileTypes', { 'source.ruby': ['Cheffile'] })
|
||||
expect(
|
||||
atom.grammars.selectGrammar('build/Cheffile', 'cookbook "postgres"')
|
||||
.scopeName
|
||||
).toBe('source.ruby')
|
||||
})
|
||||
|
||||
it('favors user-defined file types over built-in ones of equal length', async () => {
|
||||
@@ -374,31 +489,50 @@ describe('GrammarRegistry', () => {
|
||||
'source.coffee': ['Rakefile'],
|
||||
'source.ruby': ['Cakefile']
|
||||
})
|
||||
expect(atom.grammars.selectGrammar('Rakefile', '').scopeName).toBe('source.coffee')
|
||||
expect(atom.grammars.selectGrammar('Cakefile', '').scopeName).toBe('source.ruby')
|
||||
expect(atom.grammars.selectGrammar('Rakefile', '').scopeName).toBe(
|
||||
'source.coffee'
|
||||
)
|
||||
expect(atom.grammars.selectGrammar('Cakefile', '').scopeName).toBe(
|
||||
'source.ruby'
|
||||
)
|
||||
})
|
||||
|
||||
it('favors user-defined file types over grammars with matching first-line-regexps', async () => {
|
||||
await atom.packages.activatePackage('language-ruby')
|
||||
await atom.packages.activatePackage('language-javascript')
|
||||
|
||||
atom.config.set('core.customFileTypes', {'source.ruby': ['bootstrap']})
|
||||
expect(atom.grammars.selectGrammar('bootstrap', '#!/usr/bin/env node').scopeName).toBe('source.ruby')
|
||||
atom.config.set('core.customFileTypes', {
|
||||
'source.ruby': ['bootstrap']
|
||||
})
|
||||
expect(
|
||||
atom.grammars.selectGrammar('bootstrap', '#!/usr/bin/env node')
|
||||
.scopeName
|
||||
).toBe('source.ruby')
|
||||
})
|
||||
})
|
||||
|
||||
it('favors a grammar with a matching file type over one with m matching first line pattern', async () => {
|
||||
await atom.packages.activatePackage('language-ruby')
|
||||
await atom.packages.activatePackage('language-javascript')
|
||||
expect(atom.grammars.selectGrammar('foo.rb', '#!/usr/bin/env node').scopeName).toBe('source.ruby')
|
||||
expect(
|
||||
atom.grammars.selectGrammar('foo.rb', '#!/usr/bin/env node').scopeName
|
||||
).toBe('source.ruby')
|
||||
})
|
||||
|
||||
describe('tree-sitter vs text-mate', () => {
|
||||
it('favors a text-mate grammar over a tree-sitter grammar when `core.useTreeSitterParsers` is false', () => {
|
||||
atom.config.set('core.useTreeSitterParsers', false, {scopeSelector: '.source.js'})
|
||||
atom.config.set('core.useTreeSitterParsers', false, {
|
||||
scopeSelector: '.source.js'
|
||||
})
|
||||
|
||||
grammarRegistry.loadGrammarSync(require.resolve('language-javascript/grammars/javascript.cson'))
|
||||
grammarRegistry.loadGrammarSync(require.resolve('language-javascript/grammars/tree-sitter-javascript.cson'))
|
||||
grammarRegistry.loadGrammarSync(
|
||||
require.resolve('language-javascript/grammars/javascript.cson')
|
||||
)
|
||||
grammarRegistry.loadGrammarSync(
|
||||
require.resolve(
|
||||
'language-javascript/grammars/tree-sitter-javascript.cson'
|
||||
)
|
||||
)
|
||||
|
||||
const grammar = grammarRegistry.selectGrammar('test.js')
|
||||
expect(grammar.scopeName).toBe('source.js')
|
||||
@@ -408,8 +542,14 @@ describe('GrammarRegistry', () => {
|
||||
it('favors a tree-sitter grammar over a text-mate grammar when `core.useTreeSitterParsers` is true', () => {
|
||||
atom.config.set('core.useTreeSitterParsers', true)
|
||||
|
||||
grammarRegistry.loadGrammarSync(require.resolve('language-javascript/grammars/javascript.cson'))
|
||||
grammarRegistry.loadGrammarSync(require.resolve('language-javascript/grammars/tree-sitter-javascript.cson'))
|
||||
grammarRegistry.loadGrammarSync(
|
||||
require.resolve('language-javascript/grammars/javascript.cson')
|
||||
)
|
||||
grammarRegistry.loadGrammarSync(
|
||||
require.resolve(
|
||||
'language-javascript/grammars/tree-sitter-javascript.cson'
|
||||
)
|
||||
)
|
||||
|
||||
const grammar = grammarRegistry.selectGrammar('test.js')
|
||||
expect(grammar instanceof TreeSitterGrammar).toBe(true)
|
||||
@@ -417,7 +557,11 @@ describe('GrammarRegistry', () => {
|
||||
|
||||
it('only favors a tree-sitter grammar if it actually matches in some way (regression)', () => {
|
||||
atom.config.set('core.useTreeSitterParsers', true)
|
||||
grammarRegistry.loadGrammarSync(require.resolve('language-javascript/grammars/tree-sitter-javascript.cson'))
|
||||
grammarRegistry.loadGrammarSync(
|
||||
require.resolve(
|
||||
'language-javascript/grammars/tree-sitter-javascript.cson'
|
||||
)
|
||||
)
|
||||
|
||||
const grammar = grammarRegistry.selectGrammar('test', '')
|
||||
expect(grammar.name).toBe('Null Grammar')
|
||||
@@ -427,110 +571,164 @@ describe('GrammarRegistry', () => {
|
||||
describe('tree-sitter grammars with content regexes', () => {
|
||||
it('recognizes C++ header files', () => {
|
||||
atom.config.set('core.useTreeSitterParsers', true)
|
||||
grammarRegistry.loadGrammarSync(require.resolve('language-c/grammars/tree-sitter-c.cson'))
|
||||
grammarRegistry.loadGrammarSync(require.resolve('language-c/grammars/tree-sitter-cpp.cson'))
|
||||
grammarRegistry.loadGrammarSync(require.resolve('language-coffee-script/grammars/coffeescript.cson'))
|
||||
grammarRegistry.loadGrammarSync(
|
||||
require.resolve('language-c/grammars/tree-sitter-c.cson')
|
||||
)
|
||||
grammarRegistry.loadGrammarSync(
|
||||
require.resolve('language-c/grammars/tree-sitter-cpp.cson')
|
||||
)
|
||||
grammarRegistry.loadGrammarSync(
|
||||
require.resolve('language-coffee-script/grammars/coffeescript.cson')
|
||||
)
|
||||
|
||||
let grammar = grammarRegistry.selectGrammar('test.h', dedent `
|
||||
let grammar = grammarRegistry.selectGrammar(
|
||||
'test.h',
|
||||
dedent`
|
||||
#include <string.h>
|
||||
|
||||
typedef struct {
|
||||
void verb();
|
||||
} Noun;
|
||||
`)
|
||||
`
|
||||
)
|
||||
expect(grammar.name).toBe('C')
|
||||
|
||||
grammar = grammarRegistry.selectGrammar('test.h', dedent `
|
||||
grammar = grammarRegistry.selectGrammar(
|
||||
'test.h',
|
||||
dedent`
|
||||
#include <string>
|
||||
|
||||
class Noun {
|
||||
public:
|
||||
void verb();
|
||||
};
|
||||
`)
|
||||
`
|
||||
)
|
||||
expect(grammar.name).toBe('C++')
|
||||
|
||||
// The word `class` only indicates C++ in `.h` files, not in all files.
|
||||
grammar = grammarRegistry.selectGrammar('test.coffee', dedent `
|
||||
grammar = grammarRegistry.selectGrammar(
|
||||
'test.coffee',
|
||||
dedent`
|
||||
module.exports =
|
||||
class Noun
|
||||
verb: -> true
|
||||
`)
|
||||
`
|
||||
)
|
||||
expect(grammar.name).toBe('CoffeeScript')
|
||||
})
|
||||
|
||||
it('recognizes C++ files that do not match the content regex (regression)', () => {
|
||||
atom.config.set('core.useTreeSitterParsers', true)
|
||||
grammarRegistry.loadGrammarSync(require.resolve('language-c/grammars/tree-sitter-c.cson'))
|
||||
grammarRegistry.loadGrammarSync(require.resolve('language-c/grammars/c++.cson'))
|
||||
grammarRegistry.loadGrammarSync(require.resolve('language-c/grammars/tree-sitter-cpp.cson'))
|
||||
grammarRegistry.loadGrammarSync(
|
||||
require.resolve('language-c/grammars/tree-sitter-c.cson')
|
||||
)
|
||||
grammarRegistry.loadGrammarSync(
|
||||
require.resolve('language-c/grammars/c++.cson')
|
||||
)
|
||||
grammarRegistry.loadGrammarSync(
|
||||
require.resolve('language-c/grammars/tree-sitter-cpp.cson')
|
||||
)
|
||||
|
||||
let grammar = grammarRegistry.selectGrammar('test.cc', dedent `
|
||||
let grammar = grammarRegistry.selectGrammar(
|
||||
'test.cc',
|
||||
dedent`
|
||||
int a();
|
||||
`)
|
||||
`
|
||||
)
|
||||
expect(grammar.name).toBe('C++')
|
||||
})
|
||||
|
||||
it('does not apply content regexes from grammars without filetype or first line matches', () => {
|
||||
atom.config.set('core.useTreeSitterParsers', true)
|
||||
grammarRegistry.loadGrammarSync(require.resolve('language-c/grammars/tree-sitter-cpp.cson'))
|
||||
grammarRegistry.loadGrammarSync(
|
||||
require.resolve('language-c/grammars/tree-sitter-cpp.cson')
|
||||
)
|
||||
|
||||
let grammar = grammarRegistry.selectGrammar('', dedent `
|
||||
let grammar = grammarRegistry.selectGrammar(
|
||||
'',
|
||||
dedent`
|
||||
class Foo
|
||||
# this is ruby, not C++
|
||||
end
|
||||
`)
|
||||
`
|
||||
)
|
||||
|
||||
expect(grammar.name).toBe('Null Grammar')
|
||||
})
|
||||
|
||||
it('recognizes shell scripts with shebang lines', () => {
|
||||
atom.config.set('core.useTreeSitterParsers', true)
|
||||
grammarRegistry.loadGrammarSync(require.resolve('language-shellscript/grammars/shell-unix-bash.cson'))
|
||||
grammarRegistry.loadGrammarSync(require.resolve('language-shellscript/grammars/tree-sitter-bash.cson'))
|
||||
grammarRegistry.loadGrammarSync(
|
||||
require.resolve('language-shellscript/grammars/shell-unix-bash.cson')
|
||||
)
|
||||
grammarRegistry.loadGrammarSync(
|
||||
require.resolve('language-shellscript/grammars/tree-sitter-bash.cson')
|
||||
)
|
||||
|
||||
let grammar = grammarRegistry.selectGrammar('test.h', dedent `
|
||||
let grammar = grammarRegistry.selectGrammar(
|
||||
'test.h',
|
||||
dedent`
|
||||
#!/bin/bash
|
||||
|
||||
echo "hi"
|
||||
`)
|
||||
`
|
||||
)
|
||||
expect(grammar.name).toBe('Shell Script')
|
||||
expect(grammar instanceof TreeSitterGrammar).toBeTruthy()
|
||||
|
||||
grammar = grammarRegistry.selectGrammar('test.h', dedent `
|
||||
grammar = grammarRegistry.selectGrammar(
|
||||
'test.h',
|
||||
dedent`
|
||||
# vim: set ft=bash
|
||||
|
||||
echo "hi"
|
||||
`)
|
||||
`
|
||||
)
|
||||
expect(grammar.name).toBe('Shell Script')
|
||||
expect(grammar instanceof TreeSitterGrammar).toBeTruthy()
|
||||
|
||||
atom.config.set('core.useTreeSitterParsers', false)
|
||||
grammar = grammarRegistry.selectGrammar('test.h', dedent `
|
||||
grammar = grammarRegistry.selectGrammar(
|
||||
'test.h',
|
||||
dedent`
|
||||
#!/bin/bash
|
||||
|
||||
echo "hi"
|
||||
`)
|
||||
`
|
||||
)
|
||||
expect(grammar.name).toBe('Shell Script')
|
||||
expect(grammar instanceof TreeSitterGrammar).toBeFalsy()
|
||||
})
|
||||
|
||||
it('recognizes JavaScript files that use Flow', () => {
|
||||
atom.config.set('core.useTreeSitterParsers', true)
|
||||
grammarRegistry.loadGrammarSync(require.resolve('language-javascript/grammars/tree-sitter-javascript.cson'))
|
||||
grammarRegistry.loadGrammarSync(require.resolve('language-typescript/grammars/tree-sitter-flow.cson'))
|
||||
grammarRegistry.loadGrammarSync(
|
||||
require.resolve(
|
||||
'language-javascript/grammars/tree-sitter-javascript.cson'
|
||||
)
|
||||
)
|
||||
grammarRegistry.loadGrammarSync(
|
||||
require.resolve('language-typescript/grammars/tree-sitter-flow.cson')
|
||||
)
|
||||
|
||||
let grammar = grammarRegistry.selectGrammar('test.js', dedent`
|
||||
let grammar = grammarRegistry.selectGrammar(
|
||||
'test.js',
|
||||
dedent`
|
||||
// Copyright something
|
||||
// @flow
|
||||
|
||||
module.exports = function () { return 1 + 1 }
|
||||
`)
|
||||
`
|
||||
)
|
||||
expect(grammar.name).toBe('Flow JavaScript')
|
||||
|
||||
grammar = grammarRegistry.selectGrammar('test.js', dedent`
|
||||
grammar = grammarRegistry.selectGrammar(
|
||||
'test.js',
|
||||
dedent`
|
||||
module.exports = function () { return 1 + 1 }
|
||||
`)
|
||||
`
|
||||
)
|
||||
expect(grammar.name).toBe('JavaScript')
|
||||
})
|
||||
})
|
||||
@@ -548,8 +746,12 @@ describe('GrammarRegistry', () => {
|
||||
describe('.addInjectionPoint(languageId, {type, language, content})', () => {
|
||||
const injectionPoint = {
|
||||
type: 'some_node_type',
|
||||
language() { return 'some_language_name' },
|
||||
content(node) { return node }
|
||||
language () {
|
||||
return 'some_language_name'
|
||||
},
|
||||
content (node) {
|
||||
return node
|
||||
}
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
@@ -574,13 +776,19 @@ describe('GrammarRegistry', () => {
|
||||
})
|
||||
|
||||
describe('serialization', () => {
|
||||
it('persists editors\' grammar overrides', async () => {
|
||||
it("persists editors' grammar overrides", async () => {
|
||||
const buffer1 = new TextBuffer()
|
||||
const buffer2 = new TextBuffer()
|
||||
|
||||
grammarRegistry.loadGrammarSync(require.resolve('language-c/grammars/c.cson'))
|
||||
grammarRegistry.loadGrammarSync(require.resolve('language-html/grammars/html.cson'))
|
||||
grammarRegistry.loadGrammarSync(require.resolve('language-javascript/grammars/javascript.cson'))
|
||||
grammarRegistry.loadGrammarSync(
|
||||
require.resolve('language-c/grammars/c.cson')
|
||||
)
|
||||
grammarRegistry.loadGrammarSync(
|
||||
require.resolve('language-html/grammars/html.cson')
|
||||
)
|
||||
grammarRegistry.loadGrammarSync(
|
||||
require.resolve('language-javascript/grammars/javascript.cson')
|
||||
)
|
||||
|
||||
grammarRegistry.maintainLanguageMode(buffer1)
|
||||
grammarRegistry.maintainLanguageMode(buffer2)
|
||||
@@ -590,11 +798,17 @@ describe('GrammarRegistry', () => {
|
||||
const buffer1Copy = await TextBuffer.deserialize(buffer1.serialize())
|
||||
const buffer2Copy = await TextBuffer.deserialize(buffer2.serialize())
|
||||
|
||||
const grammarRegistryCopy = new GrammarRegistry({config: atom.config})
|
||||
grammarRegistryCopy.deserialize(JSON.parse(JSON.stringify(grammarRegistry.serialize())))
|
||||
const grammarRegistryCopy = new GrammarRegistry({ config: atom.config })
|
||||
grammarRegistryCopy.deserialize(
|
||||
JSON.parse(JSON.stringify(grammarRegistry.serialize()))
|
||||
)
|
||||
|
||||
grammarRegistryCopy.loadGrammarSync(require.resolve('language-c/grammars/c.cson'))
|
||||
grammarRegistryCopy.loadGrammarSync(require.resolve('language-html/grammars/html.cson'))
|
||||
grammarRegistryCopy.loadGrammarSync(
|
||||
require.resolve('language-c/grammars/c.cson')
|
||||
)
|
||||
grammarRegistryCopy.loadGrammarSync(
|
||||
require.resolve('language-html/grammars/html.cson')
|
||||
)
|
||||
|
||||
expect(buffer1Copy.getLanguageMode().getLanguageId()).toBe(null)
|
||||
expect(buffer2Copy.getLanguageMode().getLanguageId()).toBe(null)
|
||||
@@ -604,7 +818,9 @@ describe('GrammarRegistry', () => {
|
||||
expect(buffer1Copy.getLanguageMode().getLanguageId()).toBe('source.c')
|
||||
expect(buffer2Copy.getLanguageMode().getLanguageId()).toBe(null)
|
||||
|
||||
grammarRegistryCopy.loadGrammarSync(require.resolve('language-javascript/grammars/javascript.cson'))
|
||||
grammarRegistryCopy.loadGrammarSync(
|
||||
require.resolve('language-javascript/grammars/javascript.cson')
|
||||
)
|
||||
expect(buffer1Copy.getLanguageMode().getLanguageId()).toBe('source.c')
|
||||
expect(buffer2Copy.getLanguageMode().getLanguageId()).toBe('source.js')
|
||||
})
|
||||
|
||||
@@ -14,26 +14,28 @@ describe('GutterContainer', () => {
|
||||
describe('when initialized', () =>
|
||||
it('it has no gutters', () => {
|
||||
expect(gutterContainer.getGutters().length).toBe(0)
|
||||
})
|
||||
)
|
||||
}))
|
||||
|
||||
describe('::addGutter', () => {
|
||||
it('creates a new gutter', () => {
|
||||
const newGutter = gutterContainer.addGutter({'test-gutter': 'test-gutter', priority: 1})
|
||||
const newGutter = gutterContainer.addGutter({
|
||||
'test-gutter': 'test-gutter',
|
||||
priority: 1
|
||||
})
|
||||
expect(gutterContainer.getGutters()).toEqual([newGutter])
|
||||
expect(newGutter.priority).toBe(1)
|
||||
})
|
||||
|
||||
it('throws an error if the provided gutter name is already in use', () => {
|
||||
const name = 'test-gutter'
|
||||
gutterContainer.addGutter({name})
|
||||
expect(gutterContainer.addGutter.bind(null, {name})).toThrow()
|
||||
gutterContainer.addGutter({ name })
|
||||
expect(gutterContainer.addGutter.bind(null, { name })).toThrow()
|
||||
})
|
||||
|
||||
it('keeps added gutters sorted by ascending priority', () => {
|
||||
const gutter1 = gutterContainer.addGutter({name: 'first', priority: 1})
|
||||
const gutter3 = gutterContainer.addGutter({name: 'third', priority: 3})
|
||||
const gutter2 = gutterContainer.addGutter({name: 'second', priority: 2})
|
||||
const gutter1 = gutterContainer.addGutter({ name: 'first', priority: 1 })
|
||||
const gutter3 = gutterContainer.addGutter({ name: 'third', priority: 3 })
|
||||
const gutter2 = gutterContainer.addGutter({ name: 'second', priority: 2 })
|
||||
expect(gutterContainer.getGutters()).toEqual([gutter1, gutter2, gutter3])
|
||||
})
|
||||
})
|
||||
@@ -44,11 +46,13 @@ describe('GutterContainer', () => {
|
||||
beforeEach(function () {
|
||||
gutterContainer = new GutterContainer(fakeTextEditor)
|
||||
removedGutters = []
|
||||
gutterContainer.onDidRemoveGutter(gutterName => removedGutters.push(gutterName))
|
||||
gutterContainer.onDidRemoveGutter(gutterName =>
|
||||
removedGutters.push(gutterName)
|
||||
)
|
||||
})
|
||||
|
||||
it('removes the gutter if it is contained by this GutterContainer', () => {
|
||||
const gutter = gutterContainer.addGutter({'test-gutter': 'test-gutter'})
|
||||
const gutter = gutterContainer.addGutter({ 'test-gutter': 'test-gutter' })
|
||||
expect(gutterContainer.getGutters()).toEqual([gutter])
|
||||
gutterContainer.removeGutter(gutter)
|
||||
expect(gutterContainer.getGutters().length).toBe(0)
|
||||
@@ -65,13 +69,15 @@ describe('GutterContainer', () => {
|
||||
|
||||
describe('::destroy', () =>
|
||||
it('clears its array of gutters and destroys custom gutters', () => {
|
||||
const newGutter = gutterContainer.addGutter({'test-gutter': 'test-gutter', priority: 1})
|
||||
const newGutter = gutterContainer.addGutter({
|
||||
'test-gutter': 'test-gutter',
|
||||
priority: 1
|
||||
})
|
||||
const newGutterSpy = jasmine.createSpy()
|
||||
newGutter.onDidDestroy(newGutterSpy)
|
||||
|
||||
gutterContainer.destroy()
|
||||
expect(newGutterSpy).toHaveBeenCalled()
|
||||
expect(gutterContainer.getGutters()).toEqual([])
|
||||
})
|
||||
)
|
||||
}))
|
||||
})
|
||||
|
||||
@@ -24,8 +24,7 @@ describe('Gutter', () => {
|
||||
expect(gutter.isVisible()).toBe(false)
|
||||
// An event should only be emitted when the visibility changes.
|
||||
expect(events.length).toBe(1)
|
||||
})
|
||||
)
|
||||
}))
|
||||
|
||||
describe('::show', () =>
|
||||
it('shows the gutter if it is hidden.', () => {
|
||||
@@ -45,8 +44,7 @@ describe('Gutter', () => {
|
||||
expect(gutter.isVisible()).toBe(true)
|
||||
// An event should only be emitted when the visibility changes.
|
||||
expect(events.length).toBe(1)
|
||||
})
|
||||
)
|
||||
}))
|
||||
|
||||
describe('::destroy', () => {
|
||||
let mockGutterContainer, mockGutterContainerRemovedGutters
|
||||
@@ -61,21 +59,23 @@ describe('Gutter', () => {
|
||||
})
|
||||
|
||||
it('removes the gutter from its container.', () => {
|
||||
const gutter = new Gutter(mockGutterContainer, {name})
|
||||
const gutter = new Gutter(mockGutterContainer, { name })
|
||||
gutter.destroy()
|
||||
expect(mockGutterContainerRemovedGutters).toEqual([gutter])
|
||||
})
|
||||
|
||||
it('calls all callbacks registered on ::onDidDestroy.', () => {
|
||||
const gutter = new Gutter(mockGutterContainer, {name})
|
||||
const gutter = new Gutter(mockGutterContainer, { name })
|
||||
let didDestroy = false
|
||||
gutter.onDidDestroy(() => { didDestroy = true })
|
||||
gutter.onDidDestroy(() => {
|
||||
didDestroy = true
|
||||
})
|
||||
gutter.destroy()
|
||||
expect(didDestroy).toBe(true)
|
||||
})
|
||||
|
||||
it('does not allow destroying the line-number gutter', () => {
|
||||
const gutter = new Gutter(mockGutterContainer, {name: 'line-number'})
|
||||
const gutter = new Gutter(mockGutterContainer, { name: 'line-number' })
|
||||
expect(gutter.destroy).toThrow()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
const WORDS = require('./words')
|
||||
const {Point, Range} = require('text-buffer')
|
||||
const { Point, Range } = require('text-buffer')
|
||||
|
||||
exports.getRandomBufferRange = function getRandomBufferRange (random, buffer) {
|
||||
const endRow = random(buffer.getLineCount())
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
const {it, fit, ffit, fffit, beforeEach, afterEach} = require('./async-spec-helpers')
|
||||
const {Emitter, Disposable, CompositeDisposable} = require('event-kit')
|
||||
const { it, beforeEach, afterEach } = require('./async-spec-helpers')
|
||||
|
||||
const {HistoryManager, HistoryProject} = require('../src/history-manager')
|
||||
const { HistoryManager, HistoryProject } = require('../src/history-manager')
|
||||
const StateStore = require('../src/state-store')
|
||||
|
||||
describe("HistoryManager", () => {
|
||||
describe('HistoryManager', () => {
|
||||
let historyManager, commandRegistry, project, stateStore
|
||||
let commandDisposable, projectDisposable
|
||||
|
||||
@@ -16,19 +15,26 @@ describe("HistoryManager", () => {
|
||||
stateStore = new StateStore('history-manager-test', 1)
|
||||
await stateStore.save('history-manager', {
|
||||
projects: [
|
||||
{paths: ['/1', 'c:\\2'], lastOpened: new Date(2016, 9, 17, 17, 16, 23)},
|
||||
{paths: ['/test'], lastOpened: new Date(2016, 9, 17, 11, 12, 13)}
|
||||
{
|
||||
paths: ['/1', 'c:\\2'],
|
||||
lastOpened: new Date(2016, 9, 17, 17, 16, 23)
|
||||
},
|
||||
{ paths: ['/test'], lastOpened: new Date(2016, 9, 17, 11, 12, 13) }
|
||||
]
|
||||
})
|
||||
|
||||
projectDisposable = jasmine.createSpyObj('Disposable', ['dispose'])
|
||||
project = jasmine.createSpyObj('Project', ['onDidChangePaths'])
|
||||
project.onDidChangePaths.andCallFake((f) => {
|
||||
project.onDidChangePaths.andCallFake(f => {
|
||||
project.didChangePathsListener = f
|
||||
return projectDisposable
|
||||
})
|
||||
|
||||
historyManager = new HistoryManager({stateStore, project, commands: commandRegistry})
|
||||
historyManager = new HistoryManager({
|
||||
stateStore,
|
||||
project,
|
||||
commands: commandRegistry
|
||||
})
|
||||
await historyManager.loadState()
|
||||
})
|
||||
|
||||
@@ -36,24 +42,29 @@ describe("HistoryManager", () => {
|
||||
await stateStore.clear()
|
||||
})
|
||||
|
||||
describe("constructor", () => {
|
||||
describe('constructor', () => {
|
||||
it("registers the 'clear-project-history' command function", () => {
|
||||
expect(commandRegistry.add).toHaveBeenCalled()
|
||||
const cmdCall = commandRegistry.add.calls[0]
|
||||
expect(cmdCall.args.length).toBe(3)
|
||||
expect(cmdCall.args[0]).toBe('atom-workspace')
|
||||
expect(typeof cmdCall.args[1]['application:clear-project-history']).toBe('function')
|
||||
expect(typeof cmdCall.args[1]['application:clear-project-history']).toBe(
|
||||
'function'
|
||||
)
|
||||
})
|
||||
|
||||
describe("getProjects", () => {
|
||||
it("returns an array of HistoryProjects", () => {
|
||||
describe('getProjects', () => {
|
||||
it('returns an array of HistoryProjects', () => {
|
||||
expect(historyManager.getProjects()).toEqual([
|
||||
new HistoryProject(['/1', 'c:\\2'], new Date(2016, 9, 17, 17, 16, 23)),
|
||||
new HistoryProject(
|
||||
['/1', 'c:\\2'],
|
||||
new Date(2016, 9, 17, 17, 16, 23)
|
||||
),
|
||||
new HistoryProject(['/test'], new Date(2016, 9, 17, 11, 12, 13))
|
||||
])
|
||||
})
|
||||
|
||||
it("returns an array of HistoryProjects that is not mutable state", () => {
|
||||
it('returns an array of HistoryProjects that is not mutable state', () => {
|
||||
const firstProjects = historyManager.getProjects()
|
||||
firstProjects.pop()
|
||||
firstProjects[0].path = 'modified'
|
||||
@@ -64,21 +75,25 @@ describe("HistoryManager", () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe("clearProjects", () => {
|
||||
it("clears the list of projects", async () => {
|
||||
describe('clearProjects', () => {
|
||||
it('clears the list of projects', async () => {
|
||||
expect(historyManager.getProjects().length).not.toBe(0)
|
||||
await historyManager.clearProjects()
|
||||
expect(historyManager.getProjects().length).toBe(0)
|
||||
})
|
||||
|
||||
it("saves the state", async () => {
|
||||
it('saves the state', async () => {
|
||||
await historyManager.clearProjects()
|
||||
const historyManager2 = new HistoryManager({stateStore, project, commands: commandRegistry})
|
||||
const historyManager2 = new HistoryManager({
|
||||
stateStore,
|
||||
project,
|
||||
commands: commandRegistry
|
||||
})
|
||||
await historyManager2.loadState()
|
||||
expect(historyManager.getProjects().length).toBe(0)
|
||||
})
|
||||
|
||||
it("fires the onDidChangeProjects event", async () => {
|
||||
it('fires the onDidChangeProjects event', async () => {
|
||||
const didChangeSpy = jasmine.createSpy()
|
||||
historyManager.onDidChangeProjects(didChangeSpy)
|
||||
await historyManager.clearProjects()
|
||||
@@ -87,7 +102,7 @@ describe("HistoryManager", () => {
|
||||
})
|
||||
})
|
||||
|
||||
it("listens to project.onDidChangePaths adding a new project", () => {
|
||||
it('listens to project.onDidChangePaths adding a new project', () => {
|
||||
const start = new Date()
|
||||
project.didChangePathsListener(['/a/new', '/path/or/two'])
|
||||
const projects = historyManager.getProjects()
|
||||
@@ -96,7 +111,7 @@ describe("HistoryManager", () => {
|
||||
expect(projects[0].lastOpened).not.toBeLessThan(start)
|
||||
})
|
||||
|
||||
it("listens to project.onDidChangePaths updating an existing project", () => {
|
||||
it('listens to project.onDidChangePaths updating an existing project', () => {
|
||||
const start = new Date()
|
||||
project.didChangePathsListener(['/test'])
|
||||
const projects = historyManager.getProjects()
|
||||
@@ -106,22 +121,22 @@ describe("HistoryManager", () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe("loadState", () => {
|
||||
it("defaults to an empty array if no state", async () => {
|
||||
describe('loadState', () => {
|
||||
it('defaults to an empty array if no state', async () => {
|
||||
await stateStore.clear()
|
||||
await historyManager.loadState()
|
||||
expect(historyManager.getProjects()).toEqual([])
|
||||
})
|
||||
|
||||
it("defaults to an empty array if no projects", async () => {
|
||||
it('defaults to an empty array if no projects', async () => {
|
||||
await stateStore.save('history-manager', {})
|
||||
await historyManager.loadState()
|
||||
expect(historyManager.getProjects()).toEqual([])
|
||||
})
|
||||
})
|
||||
|
||||
describe("addProject", () => {
|
||||
it("adds a new project to the end", async () => {
|
||||
describe('addProject', () => {
|
||||
it('adds a new project to the end', async () => {
|
||||
const date = new Date(2010, 10, 9, 8, 7, 6)
|
||||
await historyManager.addProject(['/a/b'], date)
|
||||
const projects = historyManager.getProjects()
|
||||
@@ -130,7 +145,7 @@ describe("HistoryManager", () => {
|
||||
expect(projects[2].lastOpened).toBe(date)
|
||||
})
|
||||
|
||||
it("adds a new project to the start", async () => {
|
||||
it('adds a new project to the start', async () => {
|
||||
const date = new Date()
|
||||
await historyManager.addProject(['/so/new'], date)
|
||||
const projects = historyManager.getProjects()
|
||||
@@ -139,7 +154,7 @@ describe("HistoryManager", () => {
|
||||
expect(projects[0].lastOpened).toBe(date)
|
||||
})
|
||||
|
||||
it("updates an existing project and moves it to the start", async () => {
|
||||
it('updates an existing project and moves it to the start', async () => {
|
||||
const date = new Date()
|
||||
await historyManager.addProject(['/test'], date)
|
||||
const projects = historyManager.getProjects()
|
||||
@@ -148,7 +163,7 @@ describe("HistoryManager", () => {
|
||||
expect(projects[0].lastOpened).toBe(date)
|
||||
})
|
||||
|
||||
it("fires the onDidChangeProjects event when adding a project", async () => {
|
||||
it('fires the onDidChangeProjects event when adding a project', async () => {
|
||||
const didChangeSpy = jasmine.createSpy()
|
||||
const beforeCount = historyManager.getProjects().length
|
||||
historyManager.onDidChangeProjects(didChangeSpy)
|
||||
@@ -157,7 +172,7 @@ describe("HistoryManager", () => {
|
||||
expect(historyManager.getProjects().length).toBe(beforeCount + 1)
|
||||
})
|
||||
|
||||
it("fires the onDidChangeProjects event when updating a project", async () => {
|
||||
it('fires the onDidChangeProjects event when updating a project', async () => {
|
||||
const didChangeSpy = jasmine.createSpy()
|
||||
const beforeCount = historyManager.getProjects().length
|
||||
historyManager.onDidChangeProjects(didChangeSpy)
|
||||
@@ -167,8 +182,8 @@ describe("HistoryManager", () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe("getProject", () => {
|
||||
it("returns a project that matches the paths", () => {
|
||||
describe('getProject', () => {
|
||||
it('returns a project that matches the paths', () => {
|
||||
const project = historyManager.getProject(['/1', 'c:\\2'])
|
||||
expect(project).not.toBeNull()
|
||||
expect(project.paths).toEqual(['/1', 'c:\\2'])
|
||||
@@ -180,7 +195,7 @@ describe("HistoryManager", () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe("saveState", () => {
|
||||
describe('saveState', () => {
|
||||
let savedHistory
|
||||
beforeEach(() => {
|
||||
// historyManager.saveState is spied on globally to prevent specs from
|
||||
@@ -195,11 +210,17 @@ describe("HistoryManager", () => {
|
||||
})
|
||||
})
|
||||
|
||||
it("saves the state", async () => {
|
||||
await historyManager.addProject(["/save/state"])
|
||||
it('saves the state', async () => {
|
||||
await historyManager.addProject(['/save/state'])
|
||||
await historyManager.saveState()
|
||||
const historyManager2 = new HistoryManager({stateStore, project, commands: commandRegistry})
|
||||
spyOn(historyManager2.stateStore, 'load').andCallFake(name => Promise.resolve(savedHistory))
|
||||
const historyManager2 = new HistoryManager({
|
||||
stateStore,
|
||||
project,
|
||||
commands: commandRegistry
|
||||
})
|
||||
spyOn(historyManager2.stateStore, 'load').andCallFake(name =>
|
||||
Promise.resolve(savedHistory)
|
||||
)
|
||||
await historyManager2.loadState()
|
||||
expect(historyManager2.getProjects()[0].paths).toEqual(['/save/state'])
|
||||
})
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const {TerminalReporter} = require('jasmine-tagged')
|
||||
const { TerminalReporter } = require('jasmine-tagged')
|
||||
|
||||
class JasmineListReporter extends TerminalReporter {
|
||||
fullDescription (spec) {
|
||||
|
||||
@@ -9,14 +9,21 @@ const path = require('path')
|
||||
const sinon = require('sinon')
|
||||
const AtomApplication = require('../../src/main-process/atom-application')
|
||||
const parseCommandLine = require('../../src/main-process/parse-command-line')
|
||||
const {timeoutPromise, conditionPromise, emitterEventPromise} = require('../async-spec-helpers')
|
||||
const {
|
||||
timeoutPromise,
|
||||
conditionPromise,
|
||||
emitterEventPromise
|
||||
} = require('../async-spec-helpers')
|
||||
|
||||
const ATOM_RESOURCE_PATH = path.resolve(__dirname, '..', '..')
|
||||
|
||||
describe('AtomApplication', function () {
|
||||
this.timeout(60 * 1000)
|
||||
|
||||
let originalAppQuit, originalShowMessageBox, originalAtomHome, atomApplicationsToDestroy
|
||||
let originalAppQuit,
|
||||
originalShowMessageBox,
|
||||
originalAtomHome,
|
||||
atomApplicationsToDestroy
|
||||
|
||||
beforeEach(() => {
|
||||
originalAppQuit = electron.app.quit
|
||||
@@ -25,11 +32,15 @@ describe('AtomApplication', function () {
|
||||
originalAtomHome = process.env.ATOM_HOME
|
||||
process.env.ATOM_HOME = makeTempDir('atom-home')
|
||||
// Symlinking the compile cache into the temporary home dir makes the windows load much faster
|
||||
fs.symlinkSync(path.join(originalAtomHome, 'compile-cache'), path.join(process.env.ATOM_HOME, 'compile-cache'), 'junction')
|
||||
fs.symlinkSync(
|
||||
path.join(originalAtomHome, 'compile-cache'),
|
||||
path.join(process.env.ATOM_HOME, 'compile-cache'),
|
||||
'junction'
|
||||
)
|
||||
season.writeFileSync(path.join(process.env.ATOM_HOME, 'config.cson'), {
|
||||
'*': {
|
||||
welcome: {showOnStartup: false},
|
||||
core: {telemetryConsent: 'no'}
|
||||
welcome: { showOnStartup: false },
|
||||
core: { telemetryConsent: 'no' }
|
||||
}
|
||||
})
|
||||
atomApplicationsToDestroy = []
|
||||
@@ -54,10 +65,14 @@ describe('AtomApplication', function () {
|
||||
const tempDirPath2 = makeTempDir()
|
||||
|
||||
const atomApplication1 = buildAtomApplication()
|
||||
const [app1Window1] = await atomApplication1.launch(parseCommandLine([tempDirPath1]))
|
||||
const [app1Window1] = await atomApplication1.launch(
|
||||
parseCommandLine([tempDirPath1])
|
||||
)
|
||||
await emitterEventPromise(app1Window1, 'window:locations-opened')
|
||||
|
||||
const [app1Window2] = await atomApplication1.launch(parseCommandLine([tempDirPath2]))
|
||||
const [app1Window2] = await atomApplication1.launch(
|
||||
parseCommandLine([tempDirPath2])
|
||||
)
|
||||
await emitterEventPromise(app1Window2, 'window:locations-opened')
|
||||
|
||||
await Promise.all([
|
||||
@@ -66,30 +81,46 @@ describe('AtomApplication', function () {
|
||||
])
|
||||
|
||||
const atomApplication2 = buildAtomApplication()
|
||||
const [app2Window1, app2Window2] = await atomApplication2.launch(parseCommandLine([]))
|
||||
const [app2Window1, app2Window2] = await atomApplication2.launch(
|
||||
parseCommandLine([])
|
||||
)
|
||||
await Promise.all([
|
||||
emitterEventPromise(app2Window1, 'window:locations-opened'),
|
||||
emitterEventPromise(app2Window2, 'window:locations-opened')
|
||||
])
|
||||
|
||||
assert.deepEqual(await getTreeViewRootDirectories(app2Window1), [tempDirPath1])
|
||||
assert.deepEqual(await getTreeViewRootDirectories(app2Window2), [tempDirPath2])
|
||||
assert.deepEqual(await getTreeViewRootDirectories(app2Window1), [
|
||||
tempDirPath1
|
||||
])
|
||||
assert.deepEqual(await getTreeViewRootDirectories(app2Window2), [
|
||||
tempDirPath2
|
||||
])
|
||||
})
|
||||
|
||||
it('when windows already exist, opens a new window with a single untitled buffer', async () => {
|
||||
const atomApplication = buildAtomApplication()
|
||||
const [window1] = await atomApplication.launch(parseCommandLine([]))
|
||||
await focusWindow(window1)
|
||||
const window1EditorTitle = await evalInWebContents(window1.browserWindow.webContents, sendBackToMainProcess => {
|
||||
sendBackToMainProcess(atom.workspace.getActiveTextEditor().getTitle())
|
||||
})
|
||||
const window1EditorTitle = await evalInWebContents(
|
||||
window1.browserWindow.webContents,
|
||||
sendBackToMainProcess => {
|
||||
sendBackToMainProcess(
|
||||
atom.workspace.getActiveTextEditor().getTitle()
|
||||
)
|
||||
}
|
||||
)
|
||||
assert.equal(window1EditorTitle, 'untitled')
|
||||
|
||||
const window2 = atomApplication.openWithOptions(parseCommandLine([]))
|
||||
await window2.loadedPromise
|
||||
const window2EditorTitle = await evalInWebContents(window1.browserWindow.webContents, sendBackToMainProcess => {
|
||||
sendBackToMainProcess(atom.workspace.getActiveTextEditor().getTitle())
|
||||
})
|
||||
const window2EditorTitle = await evalInWebContents(
|
||||
window1.browserWindow.webContents,
|
||||
sendBackToMainProcess => {
|
||||
sendBackToMainProcess(
|
||||
atom.workspace.getActiveTextEditor().getTitle()
|
||||
)
|
||||
}
|
||||
)
|
||||
assert.equal(window2EditorTitle, 'untitled')
|
||||
|
||||
assert.deepEqual(atomApplication.getAllWindows(), [window2, window1])
|
||||
@@ -101,10 +132,14 @@ describe('AtomApplication', function () {
|
||||
const tempDirPath2 = makeTempDir()
|
||||
|
||||
const atomApplication1 = buildAtomApplication()
|
||||
const [app1Window1] = await atomApplication1.launch(parseCommandLine([tempDirPath1]))
|
||||
const [app1Window1] = await atomApplication1.launch(
|
||||
parseCommandLine([tempDirPath1])
|
||||
)
|
||||
await emitterEventPromise(app1Window1, 'window:locations-opened')
|
||||
|
||||
const [app1Window2] = await atomApplication1.launch(parseCommandLine([tempDirPath2]))
|
||||
const [app1Window2] = await atomApplication1.launch(
|
||||
parseCommandLine([tempDirPath2])
|
||||
)
|
||||
await emitterEventPromise(app1Window2, 'window:locations-opened')
|
||||
|
||||
await Promise.all([
|
||||
@@ -114,13 +149,20 @@ describe('AtomApplication', function () {
|
||||
|
||||
// Launch with --new-window
|
||||
const atomApplication2 = buildAtomApplication()
|
||||
const appWindows2 = await atomApplication2.launch(parseCommandLine(['--new-window']))
|
||||
const appWindows2 = await atomApplication2.launch(
|
||||
parseCommandLine(['--new-window'])
|
||||
)
|
||||
assert.lengthOf(appWindows2, 1)
|
||||
const [appWindow2] = appWindows2
|
||||
await appWindow2.loadedPromise
|
||||
const window2EditorTitle = await evalInWebContents(appWindow2.browserWindow.webContents, sendBackToMainProcess => {
|
||||
sendBackToMainProcess(atom.workspace.getActiveTextEditor().getTitle())
|
||||
})
|
||||
const window2EditorTitle = await evalInWebContents(
|
||||
appWindow2.browserWindow.webContents,
|
||||
sendBackToMainProcess => {
|
||||
sendBackToMainProcess(
|
||||
atom.workspace.getActiveTextEditor().getTitle()
|
||||
)
|
||||
}
|
||||
)
|
||||
assert.equal(window2EditorTitle, 'untitled')
|
||||
})
|
||||
|
||||
@@ -135,12 +177,17 @@ describe('AtomApplication', function () {
|
||||
const [window1] = await atomApplication.launch(parseCommandLine([]))
|
||||
await focusWindow(window1)
|
||||
|
||||
// wait a bit just to make sure we don't pass due to querying the render process before it loads
|
||||
// wait a bit just to make sure we don't pass due to querying the render process before it loads
|
||||
await timeoutPromise(1000)
|
||||
|
||||
const itemCount = await evalInWebContents(window1.browserWindow.webContents, sendBackToMainProcess => {
|
||||
sendBackToMainProcess(atom.workspace.getActivePane().getItems().length)
|
||||
})
|
||||
const itemCount = await evalInWebContents(
|
||||
window1.browserWindow.webContents,
|
||||
sendBackToMainProcess => {
|
||||
sendBackToMainProcess(
|
||||
atom.workspace.getActivePane().getItems().length
|
||||
)
|
||||
}
|
||||
)
|
||||
assert.equal(itemCount, 0)
|
||||
})
|
||||
})
|
||||
@@ -153,11 +200,18 @@ describe('AtomApplication', function () {
|
||||
fs.mkdirSync(dirBSubdirPath)
|
||||
|
||||
const atomApplication = buildAtomApplication()
|
||||
const [window1] = await atomApplication.launch(parseCommandLine([dirAPath, dirBPath]))
|
||||
const [window1] = await atomApplication.launch(
|
||||
parseCommandLine([dirAPath, dirBPath])
|
||||
)
|
||||
await focusWindow(window1)
|
||||
|
||||
await conditionPromise(async () => (await getTreeViewRootDirectories(window1)).length === 2)
|
||||
assert.deepEqual(await getTreeViewRootDirectories(window1), [dirAPath, dirBPath])
|
||||
await conditionPromise(
|
||||
async () => (await getTreeViewRootDirectories(window1)).length === 2
|
||||
)
|
||||
assert.deepEqual(await getTreeViewRootDirectories(window1), [
|
||||
dirAPath,
|
||||
dirBPath
|
||||
])
|
||||
})
|
||||
|
||||
it('can open to a specific line number of a file', async () => {
|
||||
@@ -165,14 +219,19 @@ describe('AtomApplication', function () {
|
||||
fs.writeFileSync(filePath, '1\n2\n3\n4\n')
|
||||
const atomApplication = buildAtomApplication()
|
||||
|
||||
const [window] = await atomApplication.launch(parseCommandLine([filePath + ':3']))
|
||||
const [window] = await atomApplication.launch(
|
||||
parseCommandLine([filePath + ':3'])
|
||||
)
|
||||
await focusWindow(window)
|
||||
|
||||
const cursorRow = await evalInWebContents(window.browserWindow.webContents, sendBackToMainProcess => {
|
||||
atom.workspace.observeTextEditors(textEditor => {
|
||||
sendBackToMainProcess(textEditor.getCursorBufferPosition().row)
|
||||
})
|
||||
})
|
||||
const cursorRow = await evalInWebContents(
|
||||
window.browserWindow.webContents,
|
||||
sendBackToMainProcess => {
|
||||
atom.workspace.observeTextEditors(textEditor => {
|
||||
sendBackToMainProcess(textEditor.getCursorBufferPosition().row)
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
assert.equal(cursorRow, 2)
|
||||
})
|
||||
@@ -182,16 +241,21 @@ describe('AtomApplication', function () {
|
||||
fs.writeFileSync(filePath, '1\n2\n3\n4\n')
|
||||
const atomApplication = buildAtomApplication()
|
||||
|
||||
const [window] = await atomApplication.launch(parseCommandLine([filePath + ':2:2']))
|
||||
const [window] = await atomApplication.launch(
|
||||
parseCommandLine([filePath + ':2:2'])
|
||||
)
|
||||
await focusWindow(window)
|
||||
|
||||
const cursorPosition = await evalInWebContents(window.browserWindow.webContents, sendBackToMainProcess => {
|
||||
atom.workspace.observeTextEditors(textEditor => {
|
||||
sendBackToMainProcess(textEditor.getCursorBufferPosition())
|
||||
})
|
||||
})
|
||||
const cursorPosition = await evalInWebContents(
|
||||
window.browserWindow.webContents,
|
||||
sendBackToMainProcess => {
|
||||
atom.workspace.observeTextEditors(textEditor => {
|
||||
sendBackToMainProcess(textEditor.getCursorBufferPosition())
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
assert.deepEqual(cursorPosition, {row: 1, column: 1})
|
||||
assert.deepEqual(cursorPosition, { row: 1, column: 1 })
|
||||
})
|
||||
|
||||
it('removes all trailing whitespace and colons from the specified path', async () => {
|
||||
@@ -199,31 +263,44 @@ describe('AtomApplication', function () {
|
||||
fs.writeFileSync(filePath, '1\n2\n3\n4\n')
|
||||
const atomApplication = buildAtomApplication()
|
||||
|
||||
const [window] = await atomApplication.launch(parseCommandLine([filePath + ':: ']))
|
||||
const [window] = await atomApplication.launch(
|
||||
parseCommandLine([filePath + ':: '])
|
||||
)
|
||||
await focusWindow(window)
|
||||
|
||||
const openedPath = await evalInWebContents(window.browserWindow.webContents, sendBackToMainProcess => {
|
||||
atom.workspace.observeTextEditors(textEditor => {
|
||||
sendBackToMainProcess(textEditor.getPath())
|
||||
})
|
||||
})
|
||||
const openedPath = await evalInWebContents(
|
||||
window.browserWindow.webContents,
|
||||
sendBackToMainProcess => {
|
||||
atom.workspace.observeTextEditors(textEditor => {
|
||||
sendBackToMainProcess(textEditor.getPath())
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
assert.equal(openedPath, filePath)
|
||||
})
|
||||
|
||||
it('opens an empty text editor when launched with a new file path', async () => {
|
||||
// Choosing "Don't save"
|
||||
mockElectronShowMessageBox({response: 2})
|
||||
mockElectronShowMessageBox({ response: 2 })
|
||||
|
||||
const atomApplication = buildAtomApplication()
|
||||
const newFilePath = path.join(makeTempDir(), 'new-file')
|
||||
const [window] = await atomApplication.launch(parseCommandLine([newFilePath]))
|
||||
const [window] = await atomApplication.launch(
|
||||
parseCommandLine([newFilePath])
|
||||
)
|
||||
await focusWindow(window)
|
||||
const {editorTitle, editorText} = await evalInWebContents(window.browserWindow.webContents, sendBackToMainProcess => {
|
||||
atom.workspace.observeTextEditors(editor => {
|
||||
sendBackToMainProcess({editorTitle: editor.getTitle(), editorText: editor.getText()})
|
||||
})
|
||||
})
|
||||
const { editorTitle, editorText } = await evalInWebContents(
|
||||
window.browserWindow.webContents,
|
||||
sendBackToMainProcess => {
|
||||
atom.workspace.observeTextEditors(editor => {
|
||||
sendBackToMainProcess({
|
||||
editorTitle: editor.getTitle(),
|
||||
editorText: editor.getText()
|
||||
})
|
||||
})
|
||||
}
|
||||
)
|
||||
assert.equal(editorTitle, path.basename(newFilePath))
|
||||
assert.equal(editorText, '')
|
||||
assert.deepEqual(await getTreeViewRootDirectories(window), [])
|
||||
@@ -239,32 +316,51 @@ describe('AtomApplication', function () {
|
||||
fs.writeFileSync(existingDirCFilePath, 'this is an existing file')
|
||||
|
||||
const atomApplication = buildAtomApplication()
|
||||
const [window1] = await atomApplication.launch(parseCommandLine([dirAPath]))
|
||||
const [window1] = await atomApplication.launch(
|
||||
parseCommandLine([dirAPath])
|
||||
)
|
||||
await focusWindow(window1)
|
||||
|
||||
await conditionPromise(async () => (await getTreeViewRootDirectories(window1)).length === 1)
|
||||
await conditionPromise(
|
||||
async () => (await getTreeViewRootDirectories(window1)).length === 1
|
||||
)
|
||||
assert.deepEqual(await getTreeViewRootDirectories(window1), [dirAPath])
|
||||
|
||||
// When opening *files* with --add, reuses an existing window
|
||||
let [reusedWindow] = await atomApplication.launch(parseCommandLine([existingDirCFilePath, '--add']))
|
||||
let [reusedWindow] = await atomApplication.launch(
|
||||
parseCommandLine([existingDirCFilePath, '--add'])
|
||||
)
|
||||
assert.equal(reusedWindow, window1)
|
||||
assert.deepEqual(atomApplication.getAllWindows(), [window1])
|
||||
let activeEditorPath = await evalInWebContents(window1.browserWindow.webContents, sendBackToMainProcess => {
|
||||
const subscription = atom.workspace.onDidChangeActivePaneItem(textEditor => {
|
||||
sendBackToMainProcess(textEditor.getPath())
|
||||
subscription.dispose()
|
||||
})
|
||||
})
|
||||
let activeEditorPath = await evalInWebContents(
|
||||
window1.browserWindow.webContents,
|
||||
sendBackToMainProcess => {
|
||||
const subscription = atom.workspace.onDidChangeActivePaneItem(
|
||||
textEditor => {
|
||||
sendBackToMainProcess(textEditor.getPath())
|
||||
subscription.dispose()
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
assert.equal(activeEditorPath, existingDirCFilePath)
|
||||
assert.deepEqual(await getTreeViewRootDirectories(window1), [dirAPath])
|
||||
|
||||
// When opening *directories* with --add, reuses an existing window and adds the directory to the project
|
||||
reusedWindow = (await atomApplication.launch(parseCommandLine([dirBPath, '-a'])))[0]
|
||||
reusedWindow = (await atomApplication.launch(
|
||||
parseCommandLine([dirBPath, '-a'])
|
||||
))[0]
|
||||
assert.equal(reusedWindow, window1)
|
||||
assert.deepEqual(atomApplication.getAllWindows(), [window1])
|
||||
|
||||
await conditionPromise(async () => (await getTreeViewRootDirectories(reusedWindow)).length === 2)
|
||||
assert.deepEqual(await getTreeViewRootDirectories(window1), [dirAPath, dirBPath])
|
||||
await conditionPromise(
|
||||
async () =>
|
||||
(await getTreeViewRootDirectories(reusedWindow)).length === 2
|
||||
)
|
||||
assert.deepEqual(await getTreeViewRootDirectories(window1), [
|
||||
dirAPath,
|
||||
dirBPath
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
@@ -272,11 +368,15 @@ describe('AtomApplication', function () {
|
||||
it('positions new windows at an offset distance from the previous window', async () => {
|
||||
const atomApplication = buildAtomApplication()
|
||||
|
||||
const [window1] = await atomApplication.launch(parseCommandLine([makeTempDir()]))
|
||||
const [window1] = await atomApplication.launch(
|
||||
parseCommandLine([makeTempDir()])
|
||||
)
|
||||
await focusWindow(window1)
|
||||
window1.browserWindow.setBounds({width: 400, height: 400, x: 0, y: 0})
|
||||
window1.browserWindow.setBounds({ width: 400, height: 400, x: 0, y: 0 })
|
||||
|
||||
const [window2] = await atomApplication.launch(parseCommandLine([makeTempDir()]))
|
||||
const [window2] = await atomApplication.launch(
|
||||
parseCommandLine([makeTempDir()])
|
||||
)
|
||||
await focusWindow(window2)
|
||||
|
||||
assert.notEqual(window1, window2)
|
||||
@@ -289,70 +389,109 @@ describe('AtomApplication', function () {
|
||||
|
||||
it('persists window state based on the project directories', async () => {
|
||||
// Choosing "Don't save"
|
||||
mockElectronShowMessageBox({response: 2})
|
||||
mockElectronShowMessageBox({ response: 2 })
|
||||
|
||||
const tempDirPath = makeTempDir()
|
||||
const atomApplication = buildAtomApplication()
|
||||
const nonExistentFilePath = path.join(tempDirPath, 'new-file')
|
||||
|
||||
const [window1] = await atomApplication.launch(parseCommandLine([tempDirPath, nonExistentFilePath]))
|
||||
await evalInWebContents(window1.browserWindow.webContents, sendBackToMainProcess => {
|
||||
atom.workspace.observeTextEditors(textEditor => {
|
||||
textEditor.insertText('Hello World!')
|
||||
sendBackToMainProcess(null)
|
||||
})
|
||||
})
|
||||
const [window1] = await atomApplication.launch(
|
||||
parseCommandLine([tempDirPath, nonExistentFilePath])
|
||||
)
|
||||
await evalInWebContents(
|
||||
window1.browserWindow.webContents,
|
||||
sendBackToMainProcess => {
|
||||
atom.workspace.observeTextEditors(textEditor => {
|
||||
textEditor.insertText('Hello World!')
|
||||
sendBackToMainProcess(null)
|
||||
})
|
||||
}
|
||||
)
|
||||
await window1.prepareToUnload()
|
||||
window1.close()
|
||||
await window1.closedPromise
|
||||
|
||||
// Restore unsaved state when opening the same project directory
|
||||
const [window2] = await atomApplication.launch(parseCommandLine([tempDirPath]))
|
||||
const [window2] = await atomApplication.launch(
|
||||
parseCommandLine([tempDirPath])
|
||||
)
|
||||
await window2.loadedPromise
|
||||
const window2Text = await evalInWebContents(window2.browserWindow.webContents, sendBackToMainProcess => {
|
||||
const textEditor = atom.workspace.getActiveTextEditor()
|
||||
textEditor.moveToBottom()
|
||||
textEditor.insertText(' How are you?')
|
||||
sendBackToMainProcess(textEditor.getText())
|
||||
})
|
||||
const window2Text = await evalInWebContents(
|
||||
window2.browserWindow.webContents,
|
||||
sendBackToMainProcess => {
|
||||
const textEditor = atom.workspace.getActiveTextEditor()
|
||||
textEditor.moveToBottom()
|
||||
textEditor.insertText(' How are you?')
|
||||
sendBackToMainProcess(textEditor.getText())
|
||||
}
|
||||
)
|
||||
assert.equal(window2Text, 'Hello World! How are you?')
|
||||
})
|
||||
|
||||
it('adds a remote directory to the project when launched with a remote directory', async () => {
|
||||
const packagePath = path.join(__dirname, '..', 'fixtures', 'packages', 'package-with-directory-provider')
|
||||
const packagePath = path.join(
|
||||
__dirname,
|
||||
'..',
|
||||
'fixtures',
|
||||
'packages',
|
||||
'package-with-directory-provider'
|
||||
)
|
||||
const packagesDirPath = path.join(process.env.ATOM_HOME, 'packages')
|
||||
fs.mkdirSync(packagesDirPath)
|
||||
fs.symlinkSync(packagePath, path.join(packagesDirPath, 'package-with-directory-provider'), 'junction')
|
||||
fs.symlinkSync(
|
||||
packagePath,
|
||||
path.join(packagesDirPath, 'package-with-directory-provider'),
|
||||
'junction'
|
||||
)
|
||||
|
||||
const atomApplication = buildAtomApplication()
|
||||
atomApplication.config.set('core.disabledPackages', ['fuzzy-finder'])
|
||||
|
||||
const remotePath = 'remote://server:3437/some/directory/path'
|
||||
let [window] = await atomApplication.launch(parseCommandLine([remotePath]))
|
||||
let [window] = await atomApplication.launch(
|
||||
parseCommandLine([remotePath])
|
||||
)
|
||||
|
||||
await focusWindow(window)
|
||||
await conditionPromise(async () => (await getProjectDirectories()).length > 0)
|
||||
await conditionPromise(
|
||||
async () => (await getProjectDirectories()).length > 0
|
||||
)
|
||||
let directories = await getProjectDirectories()
|
||||
assert.deepEqual(directories, [{type: 'FakeRemoteDirectory', path: remotePath}])
|
||||
assert.deepEqual(directories, [
|
||||
{ type: 'FakeRemoteDirectory', path: remotePath }
|
||||
])
|
||||
|
||||
await window.reload()
|
||||
await focusWindow(window)
|
||||
directories = await getProjectDirectories()
|
||||
assert.deepEqual(directories, [{type: 'FakeRemoteDirectory', path: remotePath}])
|
||||
assert.deepEqual(directories, [
|
||||
{ type: 'FakeRemoteDirectory', path: remotePath }
|
||||
])
|
||||
|
||||
function getProjectDirectories () {
|
||||
return evalInWebContents(window.browserWindow.webContents, sendBackToMainProcess => {
|
||||
sendBackToMainProcess(atom.project.getDirectories().map(d => ({ type: d.constructor.name, path: d.getPath() })))
|
||||
})
|
||||
return evalInWebContents(
|
||||
window.browserWindow.webContents,
|
||||
sendBackToMainProcess => {
|
||||
sendBackToMainProcess(
|
||||
atom.project
|
||||
.getDirectories()
|
||||
.map(d => ({ type: d.constructor.name, path: d.getPath() }))
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
it('does not reopen any previously opened windows when launched with no path and `core.restorePreviousWindowsOnStart` is no', async () => {
|
||||
const atomApplication1 = buildAtomApplication()
|
||||
const [app1Window1] = await atomApplication1.launch(parseCommandLine([makeTempDir()]))
|
||||
const [app1Window1] = await atomApplication1.launch(
|
||||
parseCommandLine([makeTempDir()])
|
||||
)
|
||||
await focusWindow(app1Window1)
|
||||
|
||||
const [app1Window2] = await atomApplication1.launch(parseCommandLine([makeTempDir()]))
|
||||
const [app1Window2] = await atomApplication1.launch(
|
||||
parseCommandLine([makeTempDir()])
|
||||
)
|
||||
await focusWindow(app1Window2)
|
||||
|
||||
const configPath = path.join(process.env.ATOM_HOME, 'config.cson')
|
||||
@@ -382,19 +521,27 @@ describe('AtomApplication', function () {
|
||||
})
|
||||
|
||||
it('kills the specified pid after a newly-opened window is closed', async () => {
|
||||
const [window1] = await atomApplication.launch(parseCommandLine(['--wait', '--pid', '101']))
|
||||
const [window1] = await atomApplication.launch(
|
||||
parseCommandLine(['--wait', '--pid', '101'])
|
||||
)
|
||||
await focusWindow(window1)
|
||||
|
||||
const [window2] = await atomApplication.launch(parseCommandLine(['--new-window', '--wait', '--pid', '102']))
|
||||
const [window2] = await atomApplication.launch(
|
||||
parseCommandLine(['--new-window', '--wait', '--pid', '102'])
|
||||
)
|
||||
await focusWindow(window2)
|
||||
assert.deepEqual(killedPids, [])
|
||||
|
||||
let processKillPromise = new Promise(resolve => { onDidKillProcess = resolve })
|
||||
let processKillPromise = new Promise(resolve => {
|
||||
onDidKillProcess = resolve
|
||||
})
|
||||
window1.close()
|
||||
await processKillPromise
|
||||
assert.deepEqual(killedPids, [101])
|
||||
|
||||
processKillPromise = new Promise(resolve => { onDidKillProcess = resolve })
|
||||
processKillPromise = new Promise(resolve => {
|
||||
onDidKillProcess = resolve
|
||||
})
|
||||
window2.close()
|
||||
await processKillPromise
|
||||
assert.deepEqual(killedPids, [101, 102])
|
||||
@@ -407,18 +554,34 @@ describe('AtomApplication', function () {
|
||||
fs.writeFileSync(filePath1, 'File 1')
|
||||
fs.writeFileSync(filePath2, 'File 2')
|
||||
|
||||
const [window] = await atomApplication.launch(parseCommandLine(['--wait', '--pid', '101', projectDir]))
|
||||
const [window] = await atomApplication.launch(
|
||||
parseCommandLine(['--wait', '--pid', '101', projectDir])
|
||||
)
|
||||
await focusWindow(window)
|
||||
|
||||
const [reusedWindow] = await atomApplication.launch(parseCommandLine(['--add', '--wait', '--pid', '102', filePath1, filePath2]))
|
||||
const [reusedWindow] = await atomApplication.launch(
|
||||
parseCommandLine([
|
||||
'--add',
|
||||
'--wait',
|
||||
'--pid',
|
||||
'102',
|
||||
filePath1,
|
||||
filePath2
|
||||
])
|
||||
)
|
||||
assert.equal(reusedWindow, window)
|
||||
|
||||
const activeEditorPath = await evalInWebContents(window.browserWindow.webContents, send => {
|
||||
const subscription = atom.workspace.onDidChangeActivePaneItem(editor => {
|
||||
send(editor.getPath())
|
||||
subscription.dispose()
|
||||
})
|
||||
})
|
||||
const activeEditorPath = await evalInWebContents(
|
||||
window.browserWindow.webContents,
|
||||
send => {
|
||||
const subscription = atom.workspace.onDidChangeActivePaneItem(
|
||||
editor => {
|
||||
send(editor.getPath())
|
||||
subscription.dispose()
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
assert([filePath1, filePath2].includes(activeEditorPath))
|
||||
assert.deepEqual(killedPids, [])
|
||||
@@ -430,7 +593,9 @@ describe('AtomApplication', function () {
|
||||
await timeoutPromise(100)
|
||||
assert.deepEqual(killedPids, [])
|
||||
|
||||
let processKillPromise = new Promise(resolve => { onDidKillProcess = resolve })
|
||||
let processKillPromise = new Promise(resolve => {
|
||||
onDidKillProcess = resolve
|
||||
})
|
||||
await evalInWebContents(window.browserWindow.webContents, send => {
|
||||
atom.workspace.getActivePaneItem().destroy()
|
||||
send()
|
||||
@@ -438,7 +603,9 @@ describe('AtomApplication', function () {
|
||||
await processKillPromise
|
||||
assert.deepEqual(killedPids, [102])
|
||||
|
||||
processKillPromise = new Promise(resolve => { onDidKillProcess = resolve })
|
||||
processKillPromise = new Promise(resolve => {
|
||||
onDidKillProcess = resolve
|
||||
})
|
||||
window.close()
|
||||
await processKillPromise
|
||||
assert.deepEqual(killedPids, [102, 101])
|
||||
@@ -449,25 +616,40 @@ describe('AtomApplication', function () {
|
||||
await focusWindow(window)
|
||||
|
||||
const dirPath1 = makeTempDir()
|
||||
const [reusedWindow] = await atomApplication.launch(parseCommandLine(['--add', '--wait', '--pid', '101', dirPath1]))
|
||||
const [reusedWindow] = await atomApplication.launch(
|
||||
parseCommandLine(['--add', '--wait', '--pid', '101', dirPath1])
|
||||
)
|
||||
assert.equal(reusedWindow, window)
|
||||
await conditionPromise(async () => (await getTreeViewRootDirectories(window)).length === 1)
|
||||
await conditionPromise(
|
||||
async () => (await getTreeViewRootDirectories(window)).length === 1
|
||||
)
|
||||
assert.deepEqual(await getTreeViewRootDirectories(window), [dirPath1])
|
||||
assert.deepEqual(killedPids, [])
|
||||
|
||||
const dirPath2 = makeTempDir()
|
||||
await evalInWebContents(window.browserWindow.webContents, (send, dirPath1, dirPath2) => {
|
||||
atom.project.setPaths([dirPath1, dirPath2])
|
||||
send()
|
||||
}, dirPath1, dirPath2)
|
||||
await evalInWebContents(
|
||||
window.browserWindow.webContents,
|
||||
(send, dirPath1, dirPath2) => {
|
||||
atom.project.setPaths([dirPath1, dirPath2])
|
||||
send()
|
||||
},
|
||||
dirPath1,
|
||||
dirPath2
|
||||
)
|
||||
await timeoutPromise(100)
|
||||
assert.deepEqual(killedPids, [])
|
||||
|
||||
let processKillPromise = new Promise(resolve => { onDidKillProcess = resolve })
|
||||
await evalInWebContents(window.browserWindow.webContents, (send, dirPath2) => {
|
||||
atom.project.setPaths([dirPath2])
|
||||
send()
|
||||
}, dirPath2)
|
||||
let processKillPromise = new Promise(resolve => {
|
||||
onDidKillProcess = resolve
|
||||
})
|
||||
await evalInWebContents(
|
||||
window.browserWindow.webContents,
|
||||
(send, dirPath2) => {
|
||||
atom.project.setPaths([dirPath2])
|
||||
send()
|
||||
},
|
||||
dirPath2
|
||||
)
|
||||
await processKillPromise
|
||||
assert.deepEqual(killedPids, [101])
|
||||
})
|
||||
@@ -477,7 +659,9 @@ describe('AtomApplication', function () {
|
||||
if (process.platform === 'linux' || process.platform === 'win32') {
|
||||
it('quits the application', async () => {
|
||||
const atomApplication = buildAtomApplication()
|
||||
const [window] = await atomApplication.launch(parseCommandLine([path.join(makeTempDir('a'), 'file-a')]))
|
||||
const [window] = await atomApplication.launch(
|
||||
parseCommandLine([path.join(makeTempDir('a'), 'file-a')])
|
||||
)
|
||||
await focusWindow(window)
|
||||
window.close()
|
||||
await window.closedPromise
|
||||
@@ -487,7 +671,9 @@ describe('AtomApplication', function () {
|
||||
} else if (process.platform === 'darwin') {
|
||||
it('leaves the application open', async () => {
|
||||
const atomApplication = buildAtomApplication()
|
||||
const [window] = await atomApplication.launch(parseCommandLine([path.join(makeTempDir('a'), 'file-a')]))
|
||||
const [window] = await atomApplication.launch(
|
||||
parseCommandLine([path.join(makeTempDir('a'), 'file-a')])
|
||||
)
|
||||
await focusWindow(window)
|
||||
window.close()
|
||||
await window.closedPromise
|
||||
@@ -503,16 +689,29 @@ describe('AtomApplication', function () {
|
||||
const dirB = makeTempDir()
|
||||
|
||||
const atomApplication = buildAtomApplication()
|
||||
const [window0] = await atomApplication.launch(parseCommandLine([dirA, dirB]))
|
||||
const [window0] = await atomApplication.launch(
|
||||
parseCommandLine([dirA, dirB])
|
||||
)
|
||||
await focusWindow(window0)
|
||||
await conditionPromise(async () => (await getTreeViewRootDirectories(window0)).length === 2)
|
||||
assert.deepEqual(await getTreeViewRootDirectories(window0), [dirA, dirB])
|
||||
await conditionPromise(
|
||||
async () => (await getTreeViewRootDirectories(window0)).length === 2
|
||||
)
|
||||
assert.deepEqual(await getTreeViewRootDirectories(window0), [
|
||||
dirA,
|
||||
dirB
|
||||
])
|
||||
|
||||
const saveStatePromise = emitterEventPromise(atomApplication, 'application:did-save-state')
|
||||
await evalInWebContents(window0.browserWindow.webContents, (sendBackToMainProcess) => {
|
||||
atom.project.removePath(atom.project.getPaths()[0])
|
||||
sendBackToMainProcess(null)
|
||||
})
|
||||
const saveStatePromise = emitterEventPromise(
|
||||
atomApplication,
|
||||
'application:did-save-state'
|
||||
)
|
||||
await evalInWebContents(
|
||||
window0.browserWindow.webContents,
|
||||
sendBackToMainProcess => {
|
||||
atom.project.removePath(atom.project.getPaths()[0])
|
||||
sendBackToMainProcess(null)
|
||||
}
|
||||
)
|
||||
assert.deepEqual(await getTreeViewRootDirectories(window0), [dirB])
|
||||
await saveStatePromise
|
||||
|
||||
@@ -520,17 +719,29 @@ describe('AtomApplication', function () {
|
||||
const atomApplication2 = buildAtomApplication()
|
||||
const [window2] = await atomApplication2.launch(parseCommandLine([]))
|
||||
await focusWindow(window2)
|
||||
await conditionPromise(async () => (await getTreeViewRootDirectories(window2)).length === 1)
|
||||
await conditionPromise(
|
||||
async () => (await getTreeViewRootDirectories(window2)).length === 1
|
||||
)
|
||||
assert.deepEqual(await getTreeViewRootDirectories(window2), [dirB])
|
||||
})
|
||||
})
|
||||
|
||||
describe('when opening atom:// URLs', () => {
|
||||
it('loads the urlMain file in a new window', async () => {
|
||||
const packagePath = path.join(__dirname, '..', 'fixtures', 'packages', 'package-with-url-main')
|
||||
const packagePath = path.join(
|
||||
__dirname,
|
||||
'..',
|
||||
'fixtures',
|
||||
'packages',
|
||||
'package-with-url-main'
|
||||
)
|
||||
const packagesDirPath = path.join(process.env.ATOM_HOME, 'packages')
|
||||
fs.mkdirSync(packagesDirPath)
|
||||
fs.symlinkSync(packagePath, path.join(packagesDirPath, 'package-with-url-main'), 'junction')
|
||||
fs.symlinkSync(
|
||||
packagePath,
|
||||
path.join(packagesDirPath, 'package-with-url-main'),
|
||||
'junction'
|
||||
)
|
||||
|
||||
const atomApplication = buildAtomApplication()
|
||||
const launchOptions = parseCommandLine([])
|
||||
@@ -538,9 +749,12 @@ describe('AtomApplication', function () {
|
||||
let [windows] = await atomApplication.launch(launchOptions)
|
||||
await windows[0].loadedPromise
|
||||
|
||||
let reached = await evalInWebContents(windows[0].browserWindow.webContents, sendBackToMainProcess => {
|
||||
sendBackToMainProcess(global.reachedUrlMain)
|
||||
})
|
||||
let reached = await evalInWebContents(
|
||||
windows[0].browserWindow.webContents,
|
||||
sendBackToMainProcess => {
|
||||
sendBackToMainProcess(global.reachedUrlMain)
|
||||
}
|
||||
)
|
||||
assert.isTrue(reached)
|
||||
windows[0].close()
|
||||
})
|
||||
@@ -550,9 +764,13 @@ describe('AtomApplication', function () {
|
||||
const dirBPath = makeTempDir('b')
|
||||
|
||||
const atomApplication = buildAtomApplication()
|
||||
const [window1] = await atomApplication.launch(parseCommandLine([path.join(dirAPath)]))
|
||||
const [window1] = await atomApplication.launch(
|
||||
parseCommandLine([path.join(dirAPath)])
|
||||
)
|
||||
await focusWindow(window1)
|
||||
const [window2] = await atomApplication.launch(parseCommandLine([path.join(dirBPath)]))
|
||||
const [window2] = await atomApplication.launch(
|
||||
parseCommandLine([path.join(dirBPath)])
|
||||
)
|
||||
await focusWindow(window2)
|
||||
|
||||
const fileA = path.join(dirAPath, 'file-a')
|
||||
@@ -564,10 +782,16 @@ describe('AtomApplication', function () {
|
||||
sinon.spy(window2, 'sendURIMessage')
|
||||
|
||||
atomApplication.launch(parseCommandLine(['--uri-handler', uriA]))
|
||||
await conditionPromise(() => window1.sendURIMessage.calledWith(uriA), `window1 to be focused from ${fileA}`)
|
||||
await conditionPromise(
|
||||
() => window1.sendURIMessage.calledWith(uriA),
|
||||
`window1 to be focused from ${fileA}`
|
||||
)
|
||||
|
||||
atomApplication.launch(parseCommandLine(['--uri-handler', uriB]))
|
||||
await conditionPromise(() => window2.sendURIMessage.calledWith(uriB), `window2 to be focused from ${fileB}`)
|
||||
await conditionPromise(
|
||||
() => window2.sendURIMessage.calledWith(uriB),
|
||||
`window2 to be focused from ${fileB}`
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -584,7 +808,10 @@ describe('AtomApplication', function () {
|
||||
await new Promise(process.nextTick)
|
||||
assert(!electron.app.didQuit())
|
||||
|
||||
await Promise.all([window1.lastPrepareToUnloadPromise, window2.lastPrepareToUnloadPromise])
|
||||
await Promise.all([
|
||||
window1.lastPrepareToUnloadPromise,
|
||||
window2.lastPrepareToUnloadPromise
|
||||
])
|
||||
assert(!electron.app.didQuit())
|
||||
await atomApplication.lastBeforeQuitPromise
|
||||
await new Promise(process.nextTick)
|
||||
@@ -596,20 +823,23 @@ describe('AtomApplication', function () {
|
||||
const [window1] = await atomApplication.launch(parseCommandLine([]))
|
||||
const [window2] = await atomApplication.launch(parseCommandLine([]))
|
||||
await Promise.all([window1.loadedPromise, window2.loadedPromise])
|
||||
await evalInWebContents(window1.browserWindow.webContents, sendBackToMainProcess => {
|
||||
atom.workspace.getActiveTextEditor().insertText('unsaved text')
|
||||
sendBackToMainProcess()
|
||||
})
|
||||
await evalInWebContents(
|
||||
window1.browserWindow.webContents,
|
||||
sendBackToMainProcess => {
|
||||
atom.workspace.getActiveTextEditor().insertText('unsaved text')
|
||||
sendBackToMainProcess()
|
||||
}
|
||||
)
|
||||
|
||||
// Choosing "Cancel"
|
||||
mockElectronShowMessageBox({response: 1})
|
||||
mockElectronShowMessageBox({ response: 1 })
|
||||
electron.app.quit()
|
||||
await atomApplication.lastBeforeQuitPromise
|
||||
assert(!electron.app.didQuit())
|
||||
assert.equal(electron.app.quit.callCount, 1) // Ensure choosing "Cancel" doesn't try to quit the electron app more than once (regression)
|
||||
|
||||
// Choosing "Don't save"
|
||||
mockElectronShowMessageBox({response: 2})
|
||||
mockElectronShowMessageBox({ response: 2 })
|
||||
electron.app.quit()
|
||||
await atomApplication.lastBeforeQuitPromise
|
||||
assert(electron.app.didQuit())
|
||||
@@ -620,19 +850,22 @@ describe('AtomApplication', function () {
|
||||
const [window1] = await atomApplication.launch(parseCommandLine([]))
|
||||
const [window2] = await atomApplication.launch(parseCommandLine([]))
|
||||
await Promise.all([window1.loadedPromise, window2.loadedPromise])
|
||||
await evalInWebContents(window1.browserWindow.webContents, sendBackToMainProcess => {
|
||||
atom.workspace.getActiveTextEditor().insertText('unsaved text')
|
||||
sendBackToMainProcess()
|
||||
})
|
||||
await evalInWebContents(
|
||||
window1.browserWindow.webContents,
|
||||
sendBackToMainProcess => {
|
||||
atom.workspace.getActiveTextEditor().insertText('unsaved text')
|
||||
sendBackToMainProcess()
|
||||
}
|
||||
)
|
||||
|
||||
// Choosing "Cancel"
|
||||
mockElectronShowMessageBox({response: 1})
|
||||
mockElectronShowMessageBox({ response: 1 })
|
||||
electron.app.quit()
|
||||
await atomApplication.lastBeforeQuitPromise
|
||||
assert(atomApplication.getAllWindows().length === 1)
|
||||
|
||||
// Choosing "Don't save"
|
||||
mockElectronShowMessageBox({response: 2})
|
||||
mockElectronShowMessageBox({ response: 2 })
|
||||
electron.app.quit()
|
||||
await atomApplication.lastBeforeQuitPromise
|
||||
assert(atomApplication.getAllWindows().length === 0)
|
||||
@@ -650,24 +883,35 @@ describe('AtomApplication', function () {
|
||||
await window.closedPromise
|
||||
|
||||
atomApplication.emit('application:open')
|
||||
await conditionPromise(() => atomApplication.promptForPathToOpen.calledWith('all'))
|
||||
await conditionPromise(() =>
|
||||
atomApplication.promptForPathToOpen.calledWith('all')
|
||||
)
|
||||
atomApplication.promptForPathToOpen.reset()
|
||||
|
||||
atomApplication.emit('application:open-file')
|
||||
await conditionPromise(() => atomApplication.promptForPathToOpen.calledWith('file'))
|
||||
await conditionPromise(() =>
|
||||
atomApplication.promptForPathToOpen.calledWith('file')
|
||||
)
|
||||
atomApplication.promptForPathToOpen.reset()
|
||||
|
||||
atomApplication.emit('application:open-folder')
|
||||
await conditionPromise(() => atomApplication.promptForPathToOpen.calledWith('folder'))
|
||||
await conditionPromise(() =>
|
||||
atomApplication.promptForPathToOpen.calledWith('folder')
|
||||
)
|
||||
atomApplication.promptForPathToOpen.reset()
|
||||
})
|
||||
}
|
||||
|
||||
function buildAtomApplication (params = {}) {
|
||||
const atomApplication = new AtomApplication(Object.assign({
|
||||
resourcePath: ATOM_RESOURCE_PATH,
|
||||
atomHomeDirPath: process.env.ATOM_HOME
|
||||
}, params))
|
||||
const atomApplication = new AtomApplication(
|
||||
Object.assign(
|
||||
{
|
||||
resourcePath: ATOM_RESOURCE_PATH,
|
||||
atomHomeDirPath: process.env.ATOM_HOME
|
||||
},
|
||||
params
|
||||
)
|
||||
)
|
||||
atomApplicationsToDestroy.push(atomApplication)
|
||||
return atomApplication
|
||||
}
|
||||
@@ -675,7 +919,9 @@ describe('AtomApplication', function () {
|
||||
async function focusWindow (window) {
|
||||
window.focus()
|
||||
await window.loadedPromise
|
||||
await conditionPromise(() => window.atomApplication.getLastFocusedWindow() === window)
|
||||
await conditionPromise(
|
||||
() => window.atomApplication.getLastFocusedWindow() === window
|
||||
)
|
||||
}
|
||||
|
||||
function mockElectronAppQuit () {
|
||||
@@ -684,7 +930,11 @@ describe('AtomApplication', function () {
|
||||
electron.app.quit = function () {
|
||||
this.quit.callCount++
|
||||
let defaultPrevented = false
|
||||
this.emit('before-quit', {preventDefault () { defaultPrevented = true }})
|
||||
this.emit('before-quit', {
|
||||
preventDefault () {
|
||||
defaultPrevented = true
|
||||
}
|
||||
})
|
||||
if (!defaultPrevented) didQuit = true
|
||||
}
|
||||
|
||||
@@ -693,7 +943,7 @@ describe('AtomApplication', function () {
|
||||
electron.app.didQuit = () => didQuit
|
||||
}
|
||||
|
||||
function mockElectronShowMessageBox ({response}) {
|
||||
function mockElectronShowMessageBox ({ response }) {
|
||||
electron.dialog.showMessageBox = (window, options, callback) => {
|
||||
callback(response)
|
||||
}
|
||||
@@ -718,7 +968,9 @@ describe('AtomApplication', function () {
|
||||
function sendBackToMainProcess (result) {
|
||||
require('electron').ipcRenderer.send('${channelId}', result)
|
||||
}
|
||||
(${source})(sendBackToMainProcess, ${args.map(JSON.stringify).join(', ')})
|
||||
(${source})(sendBackToMainProcess, ${args
|
||||
.map(JSON.stringify)
|
||||
.join(', ')})
|
||||
`
|
||||
// console.log(`about to execute:\n${js}`)
|
||||
|
||||
@@ -727,19 +979,24 @@ describe('AtomApplication', function () {
|
||||
}
|
||||
|
||||
function getTreeViewRootDirectories (atomWindow) {
|
||||
return evalInWebContents(atomWindow.browserWindow.webContents, sendBackToMainProcess => {
|
||||
atom.workspace.getLeftDock().observeActivePaneItem((treeView) => {
|
||||
if (treeView) {
|
||||
sendBackToMainProcess(
|
||||
Array
|
||||
.from(treeView.element.querySelectorAll('.project-root > .header .name'))
|
||||
.map(element => element.dataset.path)
|
||||
)
|
||||
} else {
|
||||
sendBackToMainProcess([])
|
||||
}
|
||||
})
|
||||
})
|
||||
return evalInWebContents(
|
||||
atomWindow.browserWindow.webContents,
|
||||
sendBackToMainProcess => {
|
||||
atom.workspace.getLeftDock().observeActivePaneItem(treeView => {
|
||||
if (treeView) {
|
||||
sendBackToMainProcess(
|
||||
Array.from(
|
||||
treeView.element.querySelectorAll(
|
||||
'.project-root > .header .name'
|
||||
)
|
||||
).map(element => element.dataset.path)
|
||||
)
|
||||
} else {
|
||||
sendBackToMainProcess([])
|
||||
}
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
function clearElectronSession () {
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
const {dialog} = require('electron')
|
||||
const { dialog } = require('electron')
|
||||
const FileRecoveryService = require('../../src/main-process/file-recovery-service')
|
||||
const fs = require('fs-plus')
|
||||
const fsreal = require('fs')
|
||||
const EventEmitter = require('events').EventEmitter
|
||||
const { assert } = require('chai')
|
||||
const sinon = require('sinon')
|
||||
const {escapeRegExp} = require('underscore-plus')
|
||||
const { escapeRegExp } = require('underscore-plus')
|
||||
const temp = require('temp').track()
|
||||
|
||||
describe("FileRecoveryService", () => {
|
||||
describe('FileRecoveryService', () => {
|
||||
let recoveryService, recoveryDirectory, spies
|
||||
|
||||
beforeEach(() => {
|
||||
@@ -25,90 +26,90 @@ describe("FileRecoveryService", () => {
|
||||
}
|
||||
})
|
||||
|
||||
describe("when no crash happens during a save", () => {
|
||||
it("creates a recovery file and deletes it after saving", async () => {
|
||||
describe('when no crash happens during a save', () => {
|
||||
it('creates a recovery file and deletes it after saving', async () => {
|
||||
const mockWindow = {}
|
||||
const filePath = temp.path()
|
||||
|
||||
fs.writeFileSync(filePath, "some content")
|
||||
fs.writeFileSync(filePath, 'some content')
|
||||
await recoveryService.willSavePath(mockWindow, filePath)
|
||||
assert.equal(fs.listTreeSync(recoveryDirectory).length, 1)
|
||||
|
||||
fs.writeFileSync(filePath, "changed")
|
||||
fs.writeFileSync(filePath, 'changed')
|
||||
await recoveryService.didSavePath(mockWindow, filePath)
|
||||
assert.equal(fs.listTreeSync(recoveryDirectory).length, 0)
|
||||
assert.equal(fs.readFileSync(filePath, 'utf8'), "changed")
|
||||
assert.equal(fs.readFileSync(filePath, 'utf8'), 'changed')
|
||||
|
||||
fs.removeSync(filePath)
|
||||
})
|
||||
|
||||
it("creates only one recovery file when many windows attempt to save the same file, deleting it when the last one finishes saving it", async () => {
|
||||
it('creates only one recovery file when many windows attempt to save the same file, deleting it when the last one finishes saving it', async () => {
|
||||
const mockWindow = {}
|
||||
const anotherMockWindow = {}
|
||||
const filePath = temp.path()
|
||||
|
||||
fs.writeFileSync(filePath, "some content")
|
||||
fs.writeFileSync(filePath, 'some content')
|
||||
await recoveryService.willSavePath(mockWindow, filePath)
|
||||
await recoveryService.willSavePath(anotherMockWindow, filePath)
|
||||
assert.equal(fs.listTreeSync(recoveryDirectory).length, 1)
|
||||
|
||||
fs.writeFileSync(filePath, "changed")
|
||||
fs.writeFileSync(filePath, 'changed')
|
||||
await recoveryService.didSavePath(mockWindow, filePath)
|
||||
assert.equal(fs.listTreeSync(recoveryDirectory).length, 1)
|
||||
assert.equal(fs.readFileSync(filePath, 'utf8'), "changed")
|
||||
assert.equal(fs.readFileSync(filePath, 'utf8'), 'changed')
|
||||
|
||||
await recoveryService.didSavePath(anotherMockWindow, filePath)
|
||||
assert.equal(fs.listTreeSync(recoveryDirectory).length, 0)
|
||||
assert.equal(fs.readFileSync(filePath, 'utf8'), "changed")
|
||||
assert.equal(fs.readFileSync(filePath, 'utf8'), 'changed')
|
||||
|
||||
fs.removeSync(filePath)
|
||||
})
|
||||
})
|
||||
|
||||
describe("when a crash happens during a save", () => {
|
||||
it("restores the created recovery file and deletes it", async () => {
|
||||
describe('when a crash happens during a save', () => {
|
||||
it('restores the created recovery file and deletes it', async () => {
|
||||
const mockWindow = {}
|
||||
const filePath = temp.path()
|
||||
|
||||
fs.writeFileSync(filePath, "some content")
|
||||
fs.writeFileSync(filePath, 'some content')
|
||||
await recoveryService.willSavePath(mockWindow, filePath)
|
||||
assert.equal(fs.listTreeSync(recoveryDirectory).length, 1)
|
||||
|
||||
fs.writeFileSync(filePath, "changed")
|
||||
fs.writeFileSync(filePath, 'changed')
|
||||
await recoveryService.didCrashWindow(mockWindow)
|
||||
assert.equal(fs.listTreeSync(recoveryDirectory).length, 0)
|
||||
assert.equal(fs.readFileSync(filePath, 'utf8'), "some content")
|
||||
assert.equal(fs.readFileSync(filePath, 'utf8'), 'some content')
|
||||
|
||||
fs.removeSync(filePath)
|
||||
})
|
||||
|
||||
it("restores the created recovery file when many windows attempt to save the same file and one of them crashes", async () => {
|
||||
it('restores the created recovery file when many windows attempt to save the same file and one of them crashes', async () => {
|
||||
const mockWindow = {}
|
||||
const anotherMockWindow = {}
|
||||
const filePath = temp.path()
|
||||
|
||||
fs.writeFileSync(filePath, "A")
|
||||
fs.writeFileSync(filePath, 'A')
|
||||
await recoveryService.willSavePath(mockWindow, filePath)
|
||||
fs.writeFileSync(filePath, "B")
|
||||
fs.writeFileSync(filePath, 'B')
|
||||
await recoveryService.willSavePath(anotherMockWindow, filePath)
|
||||
assert.equal(fs.listTreeSync(recoveryDirectory).length, 1)
|
||||
|
||||
fs.writeFileSync(filePath, "C")
|
||||
fs.writeFileSync(filePath, 'C')
|
||||
|
||||
await recoveryService.didCrashWindow(mockWindow)
|
||||
assert.equal(fs.readFileSync(filePath, 'utf8'), "A")
|
||||
assert.equal(fs.readFileSync(filePath, 'utf8'), 'A')
|
||||
assert.equal(fs.listTreeSync(recoveryDirectory).length, 0)
|
||||
|
||||
fs.writeFileSync(filePath, "D")
|
||||
fs.writeFileSync(filePath, 'D')
|
||||
await recoveryService.willSavePath(mockWindow, filePath)
|
||||
fs.writeFileSync(filePath, "E")
|
||||
fs.writeFileSync(filePath, 'E')
|
||||
await recoveryService.willSavePath(anotherMockWindow, filePath)
|
||||
assert.equal(fs.listTreeSync(recoveryDirectory).length, 1)
|
||||
|
||||
fs.writeFileSync(filePath, "F")
|
||||
fs.writeFileSync(filePath, 'F')
|
||||
|
||||
await recoveryService.didCrashWindow(anotherMockWindow)
|
||||
assert.equal(fs.readFileSync(filePath, 'utf8'), "D")
|
||||
assert.equal(fs.readFileSync(filePath, 'utf8'), 'D')
|
||||
assert.equal(fs.listTreeSync(recoveryDirectory).length, 0)
|
||||
|
||||
fs.removeSync(filePath)
|
||||
@@ -117,10 +118,10 @@ describe("FileRecoveryService", () => {
|
||||
it("emits a warning when a file can't be recovered", async () => {
|
||||
const mockWindow = {}
|
||||
const filePath = temp.path()
|
||||
fs.writeFileSync(filePath, "content")
|
||||
fs.writeFileSync(filePath, 'content')
|
||||
|
||||
let logs = []
|
||||
spies.stub(console, 'log', (message) => logs.push(message))
|
||||
spies.stub(console, 'log', message => logs.push(message))
|
||||
spies.stub(dialog, 'showMessageBox')
|
||||
|
||||
// Copy files to be recovered before mocking fs.createWriteStream
|
||||
@@ -130,9 +131,15 @@ describe("FileRecoveryService", () => {
|
||||
// attempting to copy the recovered file to its original location
|
||||
var fakeEmitter = new EventEmitter()
|
||||
var onStub = spies.stub(fakeEmitter, 'on')
|
||||
onStub.withArgs('error').yields(new Error('Nope')).returns(fakeEmitter)
|
||||
onStub
|
||||
.withArgs('error')
|
||||
.yields(new Error('Nope'))
|
||||
.returns(fakeEmitter)
|
||||
onStub.withArgs('open').returns(fakeEmitter)
|
||||
spies.stub(fsreal, 'createWriteStream').withArgs(filePath).returns(fakeEmitter)
|
||||
spies
|
||||
.stub(fsreal, 'createWriteStream')
|
||||
.withArgs(filePath)
|
||||
.returns(fakeEmitter)
|
||||
|
||||
await recoveryService.didCrashWindow(mockWindow)
|
||||
let recoveryFiles = fs.listTreeSync(recoveryDirectory)
|
||||
@@ -148,10 +155,10 @@ describe("FileRecoveryService", () => {
|
||||
it("doesn't create a recovery file when the file that's being saved doesn't exist yet", async () => {
|
||||
const mockWindow = {}
|
||||
|
||||
await recoveryService.willSavePath(mockWindow, "a-file-that-doesnt-exist")
|
||||
await recoveryService.willSavePath(mockWindow, 'a-file-that-doesnt-exist')
|
||||
assert.equal(fs.listTreeSync(recoveryDirectory).length, 0)
|
||||
|
||||
await recoveryService.didSavePath(mockWindow, "a-file-that-doesnt-exist")
|
||||
await recoveryService.didSavePath(mockWindow, 'a-file-that-doesnt-exist')
|
||||
assert.equal(fs.listTreeSync(recoveryDirectory).length, 0)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
const Mocha = require('mocha')
|
||||
const fs = require('fs-plus')
|
||||
const {assert} = require('chai')
|
||||
const { assert } = require('chai')
|
||||
|
||||
module.exports =
|
||||
function (testPaths) {
|
||||
module.exports = function (testPaths) {
|
||||
global.assert = assert
|
||||
|
||||
let reporterOptions = {
|
||||
|
||||
@@ -1,9 +1,17 @@
|
||||
const { assert } = require('chai')
|
||||
const parseCommandLine = require('../../src/main-process/parse-command-line')
|
||||
|
||||
describe('parseCommandLine', () => {
|
||||
describe('when --uri-handler is not passed', () => {
|
||||
it('parses arguments as normal', () => {
|
||||
const args = parseCommandLine(['-d', '--safe', '--test', '/some/path', 'atom://test/url', 'atom://other/url'])
|
||||
const args = parseCommandLine([
|
||||
'-d',
|
||||
'--safe',
|
||||
'--test',
|
||||
'/some/path',
|
||||
'atom://test/url',
|
||||
'atom://other/url'
|
||||
])
|
||||
assert.isTrue(args.devMode)
|
||||
assert.isTrue(args.safeMode)
|
||||
assert.isTrue(args.test)
|
||||
@@ -14,7 +22,15 @@ describe('parseCommandLine', () => {
|
||||
|
||||
describe('when --uri-handler is passed', () => {
|
||||
it('ignores other arguments and limits to one URL', () => {
|
||||
const args = parseCommandLine(['-d', '--uri-handler', '--safe', '--test', '/some/path', 'atom://test/url', 'atom://other/url'])
|
||||
const args = parseCommandLine([
|
||||
'-d',
|
||||
'--uri-handler',
|
||||
'--safe',
|
||||
'--test',
|
||||
'/some/path',
|
||||
'atom://test/url',
|
||||
'atom://other/url'
|
||||
])
|
||||
assert.isUndefined(args.devMode)
|
||||
assert.isUndefined(args.safeMode)
|
||||
assert.isUndefined(args.test)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const {sortMenuItems} = require('../src/menu-sort-helpers')
|
||||
const { sortMenuItems } = require('../src/menu-sort-helpers')
|
||||
|
||||
describe('contextMenu', () => {
|
||||
describe('dedupes separators', () => {
|
||||
@@ -18,7 +18,8 @@ describe('contextMenu', () => {
|
||||
it('preserves separators at the begining of set two', () => {
|
||||
const items = [
|
||||
{ command: 'core:one' },
|
||||
{ type: 'separator' }, { command: 'core:two' }
|
||||
{ type: 'separator' },
|
||||
{ command: 'core:two' }
|
||||
]
|
||||
const expected = [
|
||||
{ command: 'core:one' },
|
||||
@@ -36,8 +37,10 @@ describe('contextMenu', () => {
|
||||
|
||||
it('removes duplicate separators across sets', () => {
|
||||
const items = [
|
||||
{ command: 'core:one' }, { type: 'separator' },
|
||||
{ type: 'separator' }, { command: 'core:two' }
|
||||
{ command: 'core:one' },
|
||||
{ type: 'separator' },
|
||||
{ type: 'separator' },
|
||||
{ command: 'core:two' }
|
||||
]
|
||||
const expected = [
|
||||
{ command: 'core:one' },
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
/** @babel */
|
||||
|
||||
import {it, beforeEach} from './async-spec-helpers'
|
||||
import { it, beforeEach } from './async-spec-helpers'
|
||||
|
||||
import path from 'path'
|
||||
import {Emitter} from 'event-kit'
|
||||
import { Emitter } from 'event-kit'
|
||||
|
||||
import {NativeWatcherRegistry} from '../src/native-watcher-registry'
|
||||
import { NativeWatcherRegistry } from '../src/native-watcher-registry'
|
||||
|
||||
function findRootDirectory () {
|
||||
let current = process.cwd()
|
||||
@@ -42,7 +42,9 @@ class MockWatcher {
|
||||
attachToNative (native, nativePath) {
|
||||
if (this.normalizedPath.startsWith(nativePath)) {
|
||||
if (this.native) {
|
||||
this.native.attached = this.native.attached.filter(each => each !== this)
|
||||
this.native.attached = this.native.attached.filter(
|
||||
each => each !== this
|
||||
)
|
||||
}
|
||||
this.native = native
|
||||
this.native.attached.push(this)
|
||||
@@ -84,7 +86,9 @@ describe('NativeWatcherRegistry', function () {
|
||||
let createNative, registry
|
||||
|
||||
beforeEach(function () {
|
||||
registry = new NativeWatcherRegistry(normalizedPath => createNative(normalizedPath))
|
||||
registry = new NativeWatcherRegistry(normalizedPath =>
|
||||
createNative(normalizedPath)
|
||||
)
|
||||
})
|
||||
|
||||
it('attaches a Watcher to a newly created NativeWatcher for a new directory', async function () {
|
||||
@@ -201,9 +205,20 @@ describe('NativeWatcherRegistry', function () {
|
||||
const RUNNING = new MockNative('running')
|
||||
|
||||
const stoppedPath = absolute('watcher', 'that', 'will', 'be', 'stopped')
|
||||
const stoppedPathParts = stoppedPath.split(path.sep).filter(part => part.length > 0)
|
||||
const runningPath = absolute('watcher', 'that', 'will', 'continue', 'to', 'exist')
|
||||
const runningPathParts = runningPath.split(path.sep).filter(part => part.length > 0)
|
||||
const stoppedPathParts = stoppedPath
|
||||
.split(path.sep)
|
||||
.filter(part => part.length > 0)
|
||||
const runningPath = absolute(
|
||||
'watcher',
|
||||
'that',
|
||||
'will',
|
||||
'continue',
|
||||
'to',
|
||||
'exist'
|
||||
)
|
||||
const runningPathParts = runningPath
|
||||
.split(path.sep)
|
||||
.filter(part => part.length > 0)
|
||||
|
||||
createNative = dir => {
|
||||
if (dir === stoppedPath) {
|
||||
@@ -281,23 +296,29 @@ describe('NativeWatcherRegistry', function () {
|
||||
expect(childWatcher0.native).toBe(CHILD0)
|
||||
expect(childWatcher1.native).toBe(CHILD1)
|
||||
|
||||
expect(registry.tree.root.lookup(parts(parentDir)).when({
|
||||
parent: () => false,
|
||||
missing: () => false,
|
||||
children: () => true
|
||||
})).toBe(true)
|
||||
expect(
|
||||
registry.tree.root.lookup(parts(parentDir)).when({
|
||||
parent: () => false,
|
||||
missing: () => false,
|
||||
children: () => true
|
||||
})
|
||||
).toBe(true)
|
||||
|
||||
expect(registry.tree.root.lookup(parts(childDir0)).when({
|
||||
parent: () => true,
|
||||
missing: () => false,
|
||||
children: () => false
|
||||
})).toBe(true)
|
||||
expect(
|
||||
registry.tree.root.lookup(parts(childDir0)).when({
|
||||
parent: () => true,
|
||||
missing: () => false,
|
||||
children: () => false
|
||||
})
|
||||
).toBe(true)
|
||||
|
||||
expect(registry.tree.root.lookup(parts(childDir1)).when({
|
||||
parent: () => true,
|
||||
missing: () => false,
|
||||
children: () => false
|
||||
})).toBe(true)
|
||||
expect(
|
||||
registry.tree.root.lookup(parts(childDir1)).when({
|
||||
parent: () => true,
|
||||
missing: () => false,
|
||||
children: () => false
|
||||
})
|
||||
).toBe(true)
|
||||
})
|
||||
|
||||
it('consolidates children when splitting a parent watcher', async function () {
|
||||
@@ -340,23 +361,29 @@ describe('NativeWatcherRegistry', function () {
|
||||
expect(childWatcher0.native).toBe(CHILD0)
|
||||
expect(childWatcher1.native).toBe(CHILD0)
|
||||
|
||||
expect(registry.tree.root.lookup(parts(parentDir)).when({
|
||||
parent: () => false,
|
||||
missing: () => false,
|
||||
children: () => true
|
||||
})).toBe(true)
|
||||
expect(
|
||||
registry.tree.root.lookup(parts(parentDir)).when({
|
||||
parent: () => false,
|
||||
missing: () => false,
|
||||
children: () => true
|
||||
})
|
||||
).toBe(true)
|
||||
|
||||
expect(registry.tree.root.lookup(parts(childDir0)).when({
|
||||
parent: () => true,
|
||||
missing: () => false,
|
||||
children: () => false
|
||||
})).toBe(true)
|
||||
expect(
|
||||
registry.tree.root.lookup(parts(childDir0)).when({
|
||||
parent: () => true,
|
||||
missing: () => false,
|
||||
children: () => false
|
||||
})
|
||||
).toBe(true)
|
||||
|
||||
expect(registry.tree.root.lookup(parts(childDir1)).when({
|
||||
parent: () => true,
|
||||
missing: () => false,
|
||||
children: () => false
|
||||
})).toBe(true)
|
||||
expect(
|
||||
registry.tree.root.lookup(parts(childDir1)).when({
|
||||
parent: () => true,
|
||||
missing: () => false,
|
||||
children: () => false
|
||||
})
|
||||
).toBe(true)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -10,8 +10,7 @@ describe('NotificationManager', () => {
|
||||
describe('the atom global', () =>
|
||||
it('has a notifications instance', () => {
|
||||
expect(atom.notifications instanceof NotificationManager).toBe(true)
|
||||
})
|
||||
)
|
||||
}))
|
||||
|
||||
describe('adding events', () => {
|
||||
let addSpy
|
||||
@@ -22,7 +21,7 @@ describe('NotificationManager', () => {
|
||||
})
|
||||
|
||||
it('emits an event when a notification has been added', () => {
|
||||
manager.add('error', 'Some error!', {icon: 'someIcon'})
|
||||
manager.add('error', 'Some error!', { icon: 'someIcon' })
|
||||
expect(addSpy).toHaveBeenCalled()
|
||||
|
||||
const notification = addSpy.mostRecentCall.args[0]
|
||||
@@ -32,35 +31,35 @@ describe('NotificationManager', () => {
|
||||
})
|
||||
|
||||
it('emits a fatal error when ::addFatalError has been called', () => {
|
||||
manager.addFatalError('Some error!', {icon: 'someIcon'})
|
||||
manager.addFatalError('Some error!', { icon: 'someIcon' })
|
||||
expect(addSpy).toHaveBeenCalled()
|
||||
const notification = addSpy.mostRecentCall.args[0]
|
||||
expect(notification.getType()).toBe('fatal')
|
||||
})
|
||||
|
||||
it('emits an error when ::addError has been called', () => {
|
||||
manager.addError('Some error!', {icon: 'someIcon'})
|
||||
manager.addError('Some error!', { icon: 'someIcon' })
|
||||
expect(addSpy).toHaveBeenCalled()
|
||||
const notification = addSpy.mostRecentCall.args[0]
|
||||
expect(notification.getType()).toBe('error')
|
||||
})
|
||||
|
||||
it('emits a warning notification when ::addWarning has been called', () => {
|
||||
manager.addWarning('Something!', {icon: 'someIcon'})
|
||||
manager.addWarning('Something!', { icon: 'someIcon' })
|
||||
expect(addSpy).toHaveBeenCalled()
|
||||
const notification = addSpy.mostRecentCall.args[0]
|
||||
expect(notification.getType()).toBe('warning')
|
||||
})
|
||||
|
||||
it('emits an info notification when ::addInfo has been called', () => {
|
||||
manager.addInfo('Something!', {icon: 'someIcon'})
|
||||
manager.addInfo('Something!', { icon: 'someIcon' })
|
||||
expect(addSpy).toHaveBeenCalled()
|
||||
const notification = addSpy.mostRecentCall.args[0]
|
||||
expect(notification.getType()).toBe('info')
|
||||
})
|
||||
|
||||
it('emits a success notification when ::addSuccess has been called', () => {
|
||||
manager.addSuccess('Something!', {icon: 'someIcon'})
|
||||
manager.addSuccess('Something!', { icon: 'someIcon' })
|
||||
expect(addSpy).toHaveBeenCalled()
|
||||
const notification = addSpy.mostRecentCall.args[0]
|
||||
expect(notification.getType()).toBe('success')
|
||||
|
||||
@@ -20,8 +20,7 @@ describe('Notification', () => {
|
||||
it('returns a Date object', () => {
|
||||
const notification = new Notification('error', 'message!')
|
||||
expect(notification.getTimestamp() instanceof Date).toBe(true)
|
||||
})
|
||||
)
|
||||
}))
|
||||
|
||||
describe('::getIcon()', () => {
|
||||
it('returns a default when no icon specified', () => {
|
||||
@@ -30,7 +29,9 @@ describe('Notification', () => {
|
||||
})
|
||||
|
||||
it('returns the icon specified', () => {
|
||||
const notification = new Notification('error', 'message!', {icon: 'my-icon'})
|
||||
const notification = new Notification('error', 'message!', {
|
||||
icon: 'my-icon'
|
||||
})
|
||||
expect(notification.getIcon()).toBe('my-icon')
|
||||
})
|
||||
})
|
||||
@@ -39,7 +40,9 @@ describe('Notification', () => {
|
||||
describe('when the notfication is dismissable', () =>
|
||||
it('calls a callback when the notification is dismissed', () => {
|
||||
const dismissedSpy = jasmine.createSpy()
|
||||
const notification = new Notification('error', 'message', {dismissable: true})
|
||||
const notification = new Notification('error', 'message', {
|
||||
dismissable: true
|
||||
})
|
||||
notification.onDidDismiss(dismissedSpy)
|
||||
|
||||
expect(notification.isDismissable()).toBe(true)
|
||||
@@ -49,8 +52,7 @@ describe('Notification', () => {
|
||||
|
||||
expect(dismissedSpy).toHaveBeenCalled()
|
||||
expect(notification.isDismissed()).toBe(true)
|
||||
})
|
||||
)
|
||||
}))
|
||||
|
||||
describe('when the notfication is not dismissable', () =>
|
||||
it('does nothing when ::dismiss() is called', () => {
|
||||
@@ -65,7 +67,6 @@ describe('Notification', () => {
|
||||
|
||||
expect(dismissedSpy).not.toHaveBeenCalled()
|
||||
expect(notification.isDismissed()).toBe(true)
|
||||
})
|
||||
)
|
||||
}))
|
||||
})
|
||||
})
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,18 +1,17 @@
|
||||
/** @babel */
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
|
||||
import {it, fit, ffit, fffit, beforeEach, afterEach} from './async-spec-helpers'
|
||||
import { it, beforeEach } from './async-spec-helpers'
|
||||
|
||||
import PackageTranspilationRegistry from '../src/package-transpilation-registry'
|
||||
|
||||
const originalCompiler = {
|
||||
getCachePath: (sourceCode, filePath) => {
|
||||
return "orig-cache-path"
|
||||
return 'orig-cache-path'
|
||||
},
|
||||
|
||||
compile: (sourceCode, filePath) => {
|
||||
return sourceCode + "-original-compiler"
|
||||
return sourceCode + '-original-compiler'
|
||||
},
|
||||
|
||||
shouldCompile: (sourceCode, filePath) => {
|
||||
@@ -20,7 +19,7 @@ const originalCompiler = {
|
||||
}
|
||||
}
|
||||
|
||||
describe("PackageTranspilationRegistry", () => {
|
||||
describe('PackageTranspilationRegistry', () => {
|
||||
let registry
|
||||
let wrappedCompiler
|
||||
|
||||
@@ -47,20 +46,36 @@ describe("PackageTranspilationRegistry", () => {
|
||||
const hitPath = path.join('/path/to/lib/file.js')
|
||||
const hitPathCoffee = path.join('/path/to/file2.coffee')
|
||||
const missPath = path.join('/path/other/file3.js')
|
||||
const hitPathMissSubdir =path.join('/path/to/file4.js')
|
||||
const hitPathMissSubdir = path.join('/path/to/file4.js')
|
||||
const hitPathMissExt = path.join('/path/to/file5.ts')
|
||||
const nodeModulesFolder = path.join('/path/to/lib/node_modules/file6.js')
|
||||
const hitNonStandardExt = path.join('/path/to/file7.omgwhatisthis')
|
||||
|
||||
const jsSpec = { glob: "lib/**/*.js", transpiler: './transpiler-js', options: { type: 'js' } }
|
||||
const coffeeSpec = { glob: "*.coffee", transpiler: './transpiler-coffee', options: { type: 'coffee' } }
|
||||
const omgSpec = { glob: "*.omgwhatisthis", transpiler: './transpiler-omg', options: { type: 'omg' } }
|
||||
const jsSpec = {
|
||||
glob: 'lib/**/*.js',
|
||||
transpiler: './transpiler-js',
|
||||
options: { type: 'js' }
|
||||
}
|
||||
const coffeeSpec = {
|
||||
glob: '*.coffee',
|
||||
transpiler: './transpiler-coffee',
|
||||
options: { type: 'coffee' }
|
||||
}
|
||||
const omgSpec = {
|
||||
glob: '*.omgwhatisthis',
|
||||
transpiler: './transpiler-omg',
|
||||
options: { type: 'omg' }
|
||||
}
|
||||
|
||||
const expectedMeta = { name: 'my-package', path: path.join('/path/to'), meta: { some: 'metadata' } }
|
||||
const expectedMeta = {
|
||||
name: 'my-package',
|
||||
path: path.join('/path/to'),
|
||||
meta: { some: 'metadata' }
|
||||
}
|
||||
|
||||
const jsTranspiler = {
|
||||
transpile: (sourceCode, filePath, options) => {
|
||||
return {code: sourceCode + "-transpiler-js"}
|
||||
return { code: sourceCode + '-transpiler-js' }
|
||||
},
|
||||
|
||||
getCacheKeyData: (sourceCode, filePath, options) => {
|
||||
@@ -70,7 +85,7 @@ describe("PackageTranspilationRegistry", () => {
|
||||
|
||||
const coffeeTranspiler = {
|
||||
transpile: (sourceCode, filePath, options) => {
|
||||
return {code: sourceCode + "-transpiler-coffee"}
|
||||
return { code: sourceCode + '-transpiler-coffee' }
|
||||
},
|
||||
|
||||
getCacheKeyData: (sourceCode, filePath, options) => {
|
||||
@@ -80,7 +95,7 @@ describe("PackageTranspilationRegistry", () => {
|
||||
|
||||
const omgTranspiler = {
|
||||
transpile: (sourceCode, filePath, options) => {
|
||||
return {code: sourceCode + "-transpiler-omg"}
|
||||
return { code: sourceCode + '-transpiler-omg' }
|
||||
},
|
||||
|
||||
getCacheKeyData: (sourceCode, filePath, options) => {
|
||||
@@ -89,72 +104,135 @@ describe("PackageTranspilationRegistry", () => {
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
jsSpec._transpilerSource = "js-transpiler-source"
|
||||
coffeeSpec._transpilerSource = "coffee-transpiler-source"
|
||||
omgTranspiler._transpilerSource = "omg-transpiler-source"
|
||||
jsSpec._transpilerSource = 'js-transpiler-source'
|
||||
coffeeSpec._transpilerSource = 'coffee-transpiler-source'
|
||||
omgTranspiler._transpilerSource = 'omg-transpiler-source'
|
||||
|
||||
spyOn(registry, "getTranspiler").andCallFake(spec => {
|
||||
spyOn(registry, 'getTranspiler').andCallFake(spec => {
|
||||
if (spec.transpiler === './transpiler-js') return jsTranspiler
|
||||
if (spec.transpiler === './transpiler-coffee') return coffeeTranspiler
|
||||
if (spec.transpiler === './transpiler-omg') return omgTranspiler
|
||||
throw new Error('bad transpiler path ' + spec.transpiler)
|
||||
})
|
||||
|
||||
registry.addTranspilerConfigForPath(path.join('/path/to'), 'my-package', { some: 'metadata' }, [
|
||||
jsSpec, coffeeSpec, omgSpec
|
||||
])
|
||||
registry.addTranspilerConfigForPath(
|
||||
path.join('/path/to'),
|
||||
'my-package',
|
||||
{ some: 'metadata' },
|
||||
[jsSpec, coffeeSpec, omgSpec]
|
||||
)
|
||||
})
|
||||
|
||||
it('always returns true from shouldCompile for a file in that dir that match a glob', () => {
|
||||
spyOn(originalCompiler, 'shouldCompile').andReturn(false)
|
||||
expect(wrappedCompiler.shouldCompile('source', hitPath)).toBe(true)
|
||||
expect(wrappedCompiler.shouldCompile('source', hitPathCoffee)).toBe(true)
|
||||
expect(wrappedCompiler.shouldCompile('source', hitNonStandardExt)).toBe(true)
|
||||
expect(wrappedCompiler.shouldCompile('source', hitPathMissExt)).toBe(false)
|
||||
expect(wrappedCompiler.shouldCompile('source', hitPathMissSubdir)).toBe(false)
|
||||
expect(wrappedCompiler.shouldCompile('source', hitNonStandardExt)).toBe(
|
||||
true
|
||||
)
|
||||
expect(wrappedCompiler.shouldCompile('source', hitPathMissExt)).toBe(
|
||||
false
|
||||
)
|
||||
expect(wrappedCompiler.shouldCompile('source', hitPathMissSubdir)).toBe(
|
||||
false
|
||||
)
|
||||
expect(wrappedCompiler.shouldCompile('source', missPath)).toBe(false)
|
||||
expect(wrappedCompiler.shouldCompile('source', nodeModulesFolder)).toBe(false)
|
||||
expect(wrappedCompiler.shouldCompile('source', nodeModulesFolder)).toBe(
|
||||
false
|
||||
)
|
||||
})
|
||||
|
||||
it('calls getCacheKeyData on the transpiler to get additional cache key data', () => {
|
||||
spyOn(registry, "getTranspilerPath").andReturn("./transpiler-js")
|
||||
spyOn(registry, 'getTranspilerPath').andReturn('./transpiler-js')
|
||||
spyOn(jsTranspiler, 'getCacheKeyData').andCallThrough()
|
||||
|
||||
wrappedCompiler.getCachePath('source', missPath, jsSpec)
|
||||
expect(jsTranspiler.getCacheKeyData).not.toHaveBeenCalledWith('source', missPath, jsSpec.options, expectedMeta)
|
||||
expect(jsTranspiler.getCacheKeyData).not.toHaveBeenCalledWith(
|
||||
'source',
|
||||
missPath,
|
||||
jsSpec.options,
|
||||
expectedMeta
|
||||
)
|
||||
wrappedCompiler.getCachePath('source', hitPath, jsSpec)
|
||||
expect(jsTranspiler.getCacheKeyData).toHaveBeenCalledWith('source', hitPath, jsSpec.options, expectedMeta)
|
||||
expect(jsTranspiler.getCacheKeyData).toHaveBeenCalledWith(
|
||||
'source',
|
||||
hitPath,
|
||||
jsSpec.options,
|
||||
expectedMeta
|
||||
)
|
||||
})
|
||||
|
||||
it('compiles files matching a glob with the associated transpiler, and the old one otherwise', () => {
|
||||
spyOn(jsTranspiler, "transpile").andCallThrough()
|
||||
spyOn(coffeeTranspiler, "transpile").andCallThrough()
|
||||
spyOn(omgTranspiler, "transpile").andCallThrough()
|
||||
spyOn(jsTranspiler, 'transpile').andCallThrough()
|
||||
spyOn(coffeeTranspiler, 'transpile').andCallThrough()
|
||||
spyOn(omgTranspiler, 'transpile').andCallThrough()
|
||||
|
||||
expect(wrappedCompiler.compile('source', hitPath)).toEqual('source-transpiler-js')
|
||||
expect(jsTranspiler.transpile).toHaveBeenCalledWith('source', hitPath, jsSpec.options, expectedMeta)
|
||||
expect(wrappedCompiler.compile('source', hitPathCoffee)).toEqual('source-transpiler-coffee')
|
||||
expect(coffeeTranspiler.transpile).toHaveBeenCalledWith('source', hitPathCoffee, coffeeSpec.options, expectedMeta)
|
||||
expect(wrappedCompiler.compile('source', hitNonStandardExt)).toEqual('source-transpiler-omg')
|
||||
expect(omgTranspiler.transpile).toHaveBeenCalledWith('source', hitNonStandardExt, omgSpec.options, expectedMeta)
|
||||
expect(wrappedCompiler.compile('source', hitPath)).toEqual(
|
||||
'source-transpiler-js'
|
||||
)
|
||||
expect(jsTranspiler.transpile).toHaveBeenCalledWith(
|
||||
'source',
|
||||
hitPath,
|
||||
jsSpec.options,
|
||||
expectedMeta
|
||||
)
|
||||
expect(wrappedCompiler.compile('source', hitPathCoffee)).toEqual(
|
||||
'source-transpiler-coffee'
|
||||
)
|
||||
expect(coffeeTranspiler.transpile).toHaveBeenCalledWith(
|
||||
'source',
|
||||
hitPathCoffee,
|
||||
coffeeSpec.options,
|
||||
expectedMeta
|
||||
)
|
||||
expect(wrappedCompiler.compile('source', hitNonStandardExt)).toEqual(
|
||||
'source-transpiler-omg'
|
||||
)
|
||||
expect(omgTranspiler.transpile).toHaveBeenCalledWith(
|
||||
'source',
|
||||
hitNonStandardExt,
|
||||
omgSpec.options,
|
||||
expectedMeta
|
||||
)
|
||||
|
||||
expect(wrappedCompiler.compile('source', missPath)).toEqual('source-original-compiler')
|
||||
expect(wrappedCompiler.compile('source', hitPathMissExt)).toEqual('source-original-compiler')
|
||||
expect(wrappedCompiler.compile('source', hitPathMissSubdir)).toEqual('source-original-compiler')
|
||||
expect(wrappedCompiler.compile('source', nodeModulesFolder)).toEqual('source-original-compiler')
|
||||
expect(wrappedCompiler.compile('source', missPath)).toEqual(
|
||||
'source-original-compiler'
|
||||
)
|
||||
expect(wrappedCompiler.compile('source', hitPathMissExt)).toEqual(
|
||||
'source-original-compiler'
|
||||
)
|
||||
expect(wrappedCompiler.compile('source', hitPathMissSubdir)).toEqual(
|
||||
'source-original-compiler'
|
||||
)
|
||||
expect(wrappedCompiler.compile('source', nodeModulesFolder)).toEqual(
|
||||
'source-original-compiler'
|
||||
)
|
||||
})
|
||||
|
||||
describe('when the packages root path contains node_modules', () =>{
|
||||
describe('when the packages root path contains node_modules', () => {
|
||||
beforeEach(() => {
|
||||
registry.addTranspilerConfigForPath(path.join('/path/with/node_modules/in/root'), 'my-other-package', { some: 'metadata' }, [
|
||||
jsSpec
|
||||
])
|
||||
registry.addTranspilerConfigForPath(
|
||||
path.join('/path/with/node_modules/in/root'),
|
||||
'my-other-package',
|
||||
{ some: 'metadata' },
|
||||
[jsSpec]
|
||||
)
|
||||
})
|
||||
|
||||
it('returns appropriate values from shouldCompile', () => {
|
||||
spyOn(originalCompiler, 'shouldCompile').andReturn(false)
|
||||
expect(wrappedCompiler.shouldCompile('source', '/path/with/node_modules/in/root/lib/test.js')).toBe(true)
|
||||
expect(wrappedCompiler.shouldCompile('source', '/path/with/node_modules/in/root/lib/node_modules/test.js')).toBe(false)
|
||||
expect(
|
||||
wrappedCompiler.shouldCompile(
|
||||
'source',
|
||||
'/path/with/node_modules/in/root/lib/test.js'
|
||||
)
|
||||
).toBe(true)
|
||||
expect(
|
||||
wrappedCompiler.shouldCompile(
|
||||
'source',
|
||||
'/path/with/node_modules/in/root/lib/node_modules/test.js'
|
||||
)
|
||||
).toBe(false)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
const PaneContainer = require('../src/pane-container')
|
||||
const {it, fit, ffit, fffit, beforeEach, afterEach} = require('./async-spec-helpers')
|
||||
const {
|
||||
it,
|
||||
|
||||
beforeEach
|
||||
} = require('./async-spec-helpers')
|
||||
|
||||
describe('PaneContainer', () => {
|
||||
let confirm, params
|
||||
|
||||
beforeEach(() => {
|
||||
confirm = spyOn(atom.applicationDelegate, 'confirm').andCallFake((options, callback) => callback(0))
|
||||
confirm = spyOn(atom.applicationDelegate, 'confirm').andCallFake(
|
||||
(options, callback) => callback(0)
|
||||
)
|
||||
params = {
|
||||
location: 'center',
|
||||
config: atom.config,
|
||||
@@ -21,16 +27,20 @@ describe('PaneContainer', () => {
|
||||
beforeEach(() => {
|
||||
// This is a dummy item to prevent panes from being empty on deserialization
|
||||
class Item {
|
||||
static deserialize () { return new (this)() }
|
||||
serialize () { return {deserializer: 'Item'} }
|
||||
static deserialize () {
|
||||
return new this()
|
||||
}
|
||||
serialize () {
|
||||
return { deserializer: 'Item' }
|
||||
}
|
||||
}
|
||||
atom.deserializers.add(Item)
|
||||
|
||||
containerA = new PaneContainer(params)
|
||||
pane1A = containerA.getActivePane()
|
||||
pane1A.addItem(new Item())
|
||||
pane2A = pane1A.splitRight({items: [new Item()]})
|
||||
pane3A = pane2A.splitDown({items: [new Item()]})
|
||||
pane2A = pane1A.splitRight({ items: [new Item()] })
|
||||
pane3A = pane2A.splitDown({ items: [new Item()] })
|
||||
pane3A.focus()
|
||||
})
|
||||
|
||||
@@ -64,7 +74,7 @@ describe('PaneContainer', () => {
|
||||
|
||||
describe('if there are empty panes after deserialization', () => {
|
||||
beforeEach(() => {
|
||||
pane3A.getItems()[0].serialize = () => ({deserializer: 'Bogus'})
|
||||
pane3A.getItems()[0].serialize = () => ({ deserializer: 'Bogus' })
|
||||
})
|
||||
|
||||
describe("if the 'core.destroyEmptyPanes' config option is false (the default)", () =>
|
||||
@@ -78,8 +88,7 @@ describe('PaneContainer', () => {
|
||||
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', () => {
|
||||
@@ -92,8 +101,7 @@ describe('PaneContainer', () => {
|
||||
|
||||
expect(leftPane.getItems().length).toBe(1)
|
||||
expect(rightPane.getItems().length).toBe(1)
|
||||
})
|
||||
)
|
||||
}))
|
||||
})
|
||||
})
|
||||
|
||||
@@ -144,8 +152,8 @@ describe('PaneContainer', () => {
|
||||
beforeEach(() => {
|
||||
container = new PaneContainer(params)
|
||||
container.getRoot().addItems([{}, {}])
|
||||
container.getRoot().splitRight({items: [{}, {}]});
|
||||
[pane1, pane2] = container.getPanes()
|
||||
container.getRoot().splitRight({ items: [{}, {}] })
|
||||
;[pane1, pane2] = container.getPanes()
|
||||
|
||||
observed = []
|
||||
container.onDidChangeActivePane(pane => observed.push(pane))
|
||||
@@ -164,8 +172,8 @@ describe('PaneContainer', () => {
|
||||
beforeEach(() => {
|
||||
container = new PaneContainer(params)
|
||||
container.getRoot().addItems([{}, {}])
|
||||
container.getRoot().splitRight({items: [{}, {}]});
|
||||
[pane1, pane2] = container.getPanes()
|
||||
container.getRoot().splitRight({ items: [{}, {}] })
|
||||
;[pane1, pane2] = container.getPanes()
|
||||
|
||||
observed = []
|
||||
container.onDidChangeActivePaneItem(item => observed.push(item))
|
||||
@@ -190,8 +198,8 @@ describe('PaneContainer', () => {
|
||||
beforeEach(() => {
|
||||
container = new PaneContainer(params)
|
||||
container.getRoot().addItems([{}, {}])
|
||||
container.getRoot().splitRight({items: [{}, {}]});
|
||||
[pane1, pane2] = container.getPanes()
|
||||
container.getRoot().splitRight({ items: [{}, {}] })
|
||||
;[pane1, pane2] = container.getPanes()
|
||||
|
||||
observed = []
|
||||
container.onDidStopChangingActivePaneItem(item => observed.push(item))
|
||||
@@ -251,30 +259,33 @@ describe('PaneContainer', () => {
|
||||
it('invokes observers with all current and future pane items', () => {
|
||||
const container = new PaneContainer(params)
|
||||
container.getRoot().addItems([{}, {}])
|
||||
container.getRoot().splitRight({items: [{}]})
|
||||
container.getRoot().splitRight({ items: [{}] })
|
||||
const pane2 = container.getPanes()[1]
|
||||
const observed = []
|
||||
container.observePaneItems(pane => observed.push(pane))
|
||||
|
||||
const pane3 = pane2.splitDown({items: [{}]})
|
||||
const pane3 = pane2.splitDown({ items: [{}] })
|
||||
pane3.addItems([{}, {}])
|
||||
|
||||
expect(observed).toEqual(container.getPaneItems())
|
||||
})
|
||||
)
|
||||
}))
|
||||
|
||||
describe('::confirmClose()', () => {
|
||||
let container, pane1, pane2
|
||||
|
||||
beforeEach(() => {
|
||||
class TestItem {
|
||||
shouldPromptToSave () { return true }
|
||||
getURI () { return 'test' }
|
||||
shouldPromptToSave () {
|
||||
return true
|
||||
}
|
||||
getURI () {
|
||||
return 'test'
|
||||
}
|
||||
}
|
||||
|
||||
container = new PaneContainer(params)
|
||||
container.getRoot().splitRight();
|
||||
[pane1, pane2] = container.getPanes()
|
||||
container.getRoot().splitRight()
|
||||
;[pane1, pane2] = container.getPanes()
|
||||
pane1.addItem(new TestItem())
|
||||
pane2.addItem(new TestItem())
|
||||
})
|
||||
@@ -298,7 +309,7 @@ describe('PaneContainer', () => {
|
||||
it('invokes the given callback when panes are added', () => {
|
||||
const container = new PaneContainer(params)
|
||||
const events = []
|
||||
container.onDidAddPane((event) => {
|
||||
container.onDidAddPane(event => {
|
||||
expect(container.getPanes().includes(event.pane)).toBe(true)
|
||||
events.push(event)
|
||||
})
|
||||
@@ -307,23 +318,31 @@ describe('PaneContainer', () => {
|
||||
const pane2 = pane1.splitRight()
|
||||
const pane3 = pane2.splitDown()
|
||||
|
||||
expect(events).toEqual([{pane: pane2}, {pane: pane3}])
|
||||
expect(events).toEqual([{ pane: pane2 }, { pane: pane3 }])
|
||||
})
|
||||
})
|
||||
|
||||
describe('::onWillDestroyPane(callback)', () => {
|
||||
it('invokes the given callback before panes or their items are destroyed', () => {
|
||||
class TestItem {
|
||||
constructor () { this._isDestroyed = false }
|
||||
destroy () { this._isDestroyed = true }
|
||||
isDestroyed () { return this._isDestroyed }
|
||||
constructor () {
|
||||
this._isDestroyed = false
|
||||
}
|
||||
destroy () {
|
||||
this._isDestroyed = true
|
||||
}
|
||||
isDestroyed () {
|
||||
return this._isDestroyed
|
||||
}
|
||||
}
|
||||
|
||||
const container = new PaneContainer(params)
|
||||
const events = []
|
||||
container.onWillDestroyPane((event) => {
|
||||
const itemsDestroyed = event.pane.getItems().map((item) => item.isDestroyed())
|
||||
events.push([event, {itemsDestroyed}])
|
||||
container.onWillDestroyPane(event => {
|
||||
const itemsDestroyed = event.pane
|
||||
.getItems()
|
||||
.map(item => item.isDestroyed())
|
||||
events.push([event, { itemsDestroyed }])
|
||||
})
|
||||
|
||||
const pane1 = container.getActivePane()
|
||||
@@ -332,7 +351,7 @@ describe('PaneContainer', () => {
|
||||
|
||||
pane2.destroy()
|
||||
|
||||
expect(events).toEqual([[{pane: pane2}, {itemsDestroyed: [false]}]])
|
||||
expect(events).toEqual([[{ pane: pane2 }, { itemsDestroyed: [false] }]])
|
||||
})
|
||||
})
|
||||
|
||||
@@ -340,7 +359,7 @@ describe('PaneContainer', () => {
|
||||
it('invokes the given callback when panes are destroyed', () => {
|
||||
const container = new PaneContainer(params)
|
||||
const events = []
|
||||
container.onDidDestroyPane((event) => {
|
||||
container.onDidDestroyPane(event => {
|
||||
expect(container.getPanes().includes(event.pane)).toBe(false)
|
||||
events.push(event)
|
||||
})
|
||||
@@ -352,13 +371,13 @@ describe('PaneContainer', () => {
|
||||
pane2.destroy()
|
||||
pane3.destroy()
|
||||
|
||||
expect(events).toEqual([{pane: pane2}, {pane: pane3}])
|
||||
expect(events).toEqual([{ pane: pane2 }, { pane: pane3 }])
|
||||
})
|
||||
|
||||
it('invokes the given callback when the container is destroyed', () => {
|
||||
const container = new PaneContainer(params)
|
||||
const events = []
|
||||
container.onDidDestroyPane((event) => {
|
||||
container.onDidDestroyPane(event => {
|
||||
expect(container.getPanes().includes(event.pane)).toBe(false)
|
||||
events.push(event)
|
||||
})
|
||||
@@ -369,7 +388,11 @@ describe('PaneContainer', () => {
|
||||
|
||||
container.destroy()
|
||||
|
||||
expect(events).toEqual([{pane: pane1}, {pane: pane2}, {pane: pane3}])
|
||||
expect(events).toEqual([
|
||||
{ pane: pane1 },
|
||||
{ pane: pane2 },
|
||||
{ pane: pane3 }
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
@@ -385,19 +408,19 @@ describe('PaneContainer', () => {
|
||||
const events = []
|
||||
container.onWillDestroyPaneItem(event => events.push(['will', event]))
|
||||
container.onDidDestroyPaneItem(event => events.push(['did', event]))
|
||||
const pane2 = pane1.splitRight({items: [item2, item3]})
|
||||
const pane2 = pane1.splitRight({ items: [item2, item3] })
|
||||
|
||||
await pane1.destroyItem(item1)
|
||||
await pane2.destroyItem(item3)
|
||||
await pane2.destroyItem(item2)
|
||||
|
||||
expect(events).toEqual([
|
||||
['will', {item: item1, pane: pane1, index: 0}],
|
||||
['did', {item: item1, pane: pane1, index: 0}],
|
||||
['will', {item: item3, pane: pane2, index: 1}],
|
||||
['did', {item: item3, pane: pane2, index: 1}],
|
||||
['will', {item: item2, pane: pane2, index: 0}],
|
||||
['did', {item: item2, pane: pane2, index: 0}]
|
||||
['will', { item: item1, pane: pane1, index: 0 }],
|
||||
['did', { item: item1, pane: pane1, index: 0 }],
|
||||
['will', { item: item3, pane: pane2, index: 1 }],
|
||||
['did', { item: item3, pane: pane2, index: 1 }],
|
||||
['will', { item: item2, pane: pane2, index: 0 }],
|
||||
['did', { item: item2, pane: pane2, index: 0 }]
|
||||
])
|
||||
})
|
||||
})
|
||||
@@ -410,21 +433,39 @@ describe('PaneContainer', () => {
|
||||
|
||||
const item1 = {
|
||||
saved: false,
|
||||
getURI () { return '' },
|
||||
isModified () { return true },
|
||||
save () { this.saved = true }
|
||||
getURI () {
|
||||
return ''
|
||||
},
|
||||
isModified () {
|
||||
return true
|
||||
},
|
||||
save () {
|
||||
this.saved = true
|
||||
}
|
||||
}
|
||||
const item2 = {
|
||||
saved: false,
|
||||
getURI () { return '' },
|
||||
isModified () { return false },
|
||||
save () { this.saved = true }
|
||||
getURI () {
|
||||
return ''
|
||||
},
|
||||
isModified () {
|
||||
return false
|
||||
},
|
||||
save () {
|
||||
this.saved = true
|
||||
}
|
||||
}
|
||||
const item3 = {
|
||||
saved: false,
|
||||
getURI () { return '' },
|
||||
isModified () { return true },
|
||||
save () { this.saved = true }
|
||||
getURI () {
|
||||
return ''
|
||||
},
|
||||
isModified () {
|
||||
return true
|
||||
},
|
||||
save () {
|
||||
this.saved = true
|
||||
}
|
||||
}
|
||||
|
||||
pane1.addItem(item1)
|
||||
@@ -436,37 +477,38 @@ describe('PaneContainer', () => {
|
||||
expect(item1.saved).toBe(true)
|
||||
expect(item2.saved).toBe(false)
|
||||
expect(item3.saved).toBe(true)
|
||||
})
|
||||
)
|
||||
}))
|
||||
|
||||
describe('::moveActiveItemToPane(destPane) and ::copyActiveItemToPane(destPane)', () => {
|
||||
let container, pane1, pane2, item1
|
||||
|
||||
beforeEach(() => {
|
||||
class TestItem {
|
||||
constructor (id) { this.id = id }
|
||||
copy () { return new TestItem(this.id) }
|
||||
constructor (id) {
|
||||
this.id = id
|
||||
}
|
||||
copy () {
|
||||
return new TestItem(this.id)
|
||||
}
|
||||
}
|
||||
|
||||
container = new PaneContainer(params)
|
||||
pane1 = container.getRoot()
|
||||
item1 = new TestItem('1')
|
||||
pane2 = pane1.splitRight({items: [item1]})
|
||||
pane2 = pane1.splitRight({ items: [item1] })
|
||||
})
|
||||
|
||||
describe('::::moveActiveItemToPane(destPane)', () =>
|
||||
it('moves active item to given pane and focuses it', () => {
|
||||
container.moveActiveItemToPane(pane1)
|
||||
expect(pane1.getActiveItem()).toBe(item1)
|
||||
})
|
||||
)
|
||||
}))
|
||||
|
||||
describe('::::copyActiveItemToPane(destPane)', () =>
|
||||
it('copies active item to given pane and focuses it', () => {
|
||||
container.copyActiveItemToPane(pane1)
|
||||
expect(container.paneForItem(item1)).toBe(pane2)
|
||||
expect(pane1.getActiveItem().id).toBe(item1.id)
|
||||
})
|
||||
)
|
||||
}))
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,15 +1,20 @@
|
||||
const {extend} = require('underscore-plus')
|
||||
const {Emitter} = require('event-kit')
|
||||
const { extend } = require('underscore-plus')
|
||||
const { Emitter } = require('event-kit')
|
||||
const Grim = require('grim')
|
||||
const Pane = require('../src/pane')
|
||||
const PaneContainer = require('../src/pane-container')
|
||||
const {it, fit, ffit, fffit, beforeEach, conditionPromise, timeoutPromise} = require('./async-spec-helpers')
|
||||
const {
|
||||
it,
|
||||
beforeEach,
|
||||
conditionPromise,
|
||||
timeoutPromise
|
||||
} = require('./async-spec-helpers')
|
||||
|
||||
describe('Pane', () => {
|
||||
let confirm, showSaveDialog, deserializerDisposable
|
||||
|
||||
class Item {
|
||||
static deserialize ({name, uri}) {
|
||||
static deserialize ({ name, uri }) {
|
||||
return new Item(name, uri)
|
||||
}
|
||||
|
||||
@@ -20,14 +25,24 @@ describe('Pane', () => {
|
||||
this.destroyed = false
|
||||
}
|
||||
|
||||
getURI () { return this.uri }
|
||||
getPath () { return this.path }
|
||||
isEqual (other) { return this.name === (other && other.name) }
|
||||
isPermanentDockItem () { return false }
|
||||
isDestroyed () { return this.destroyed }
|
||||
getURI () {
|
||||
return this.uri
|
||||
}
|
||||
getPath () {
|
||||
return this.path
|
||||
}
|
||||
isEqual (other) {
|
||||
return this.name === (other && other.name)
|
||||
}
|
||||
isPermanentDockItem () {
|
||||
return false
|
||||
}
|
||||
isDestroyed () {
|
||||
return this.destroyed
|
||||
}
|
||||
|
||||
serialize () {
|
||||
return {deserializer: 'Item', name: this.name, uri: this.uri}
|
||||
return { deserializer: 'Item', name: this.name, uri: this.uri }
|
||||
}
|
||||
|
||||
copy () {
|
||||
@@ -63,22 +78,29 @@ describe('Pane', () => {
|
||||
})
|
||||
|
||||
function paneParams (params) {
|
||||
return extend({
|
||||
applicationDelegate: atom.applicationDelegate,
|
||||
config: atom.config,
|
||||
deserializerManager: atom.deserializers,
|
||||
notificationManager: atom.notifications
|
||||
}, params)
|
||||
return extend(
|
||||
{
|
||||
applicationDelegate: atom.applicationDelegate,
|
||||
config: atom.config,
|
||||
deserializerManager: atom.deserializers,
|
||||
notificationManager: atom.notifications
|
||||
},
|
||||
params
|
||||
)
|
||||
}
|
||||
|
||||
describe('construction', () => {
|
||||
it('sets the active item to the first item', () => {
|
||||
const pane = new Pane(paneParams({items: [new Item('A'), new Item('B')]}))
|
||||
const pane = new Pane(
|
||||
paneParams({ items: [new Item('A'), new Item('B')] })
|
||||
)
|
||||
expect(pane.getActiveItem()).toBe(pane.itemAtIndex(0))
|
||||
})
|
||||
|
||||
it('compacts the items array', () => {
|
||||
const pane = new Pane(paneParams({items: [undefined, new Item('A'), null, new Item('B')]}))
|
||||
const pane = new Pane(
|
||||
paneParams({ items: [undefined, new Item('A'), null, new Item('B')] })
|
||||
)
|
||||
expect(pane.getItems().length).toBe(2)
|
||||
expect(pane.getActiveItem()).toBe(pane.itemAtIndex(0))
|
||||
})
|
||||
@@ -136,15 +158,19 @@ describe('Pane', () => {
|
||||
|
||||
describe('::addItem(item, index)', () => {
|
||||
it('adds the item at the given index', () => {
|
||||
const pane = new Pane(paneParams({items: [new Item('A'), new Item('B')]}))
|
||||
const pane = new Pane(
|
||||
paneParams({ items: [new Item('A'), new Item('B')] })
|
||||
)
|
||||
const [item1, item2] = pane.getItems()
|
||||
const item3 = new Item('C')
|
||||
pane.addItem(item3, {index: 1})
|
||||
pane.addItem(item3, { index: 1 })
|
||||
expect(pane.getItems()).toEqual([item1, item3, item2])
|
||||
})
|
||||
|
||||
it('adds the item after the active item if no index is provided', () => {
|
||||
const pane = new Pane(paneParams({items: [new Item('A'), new Item('B'), new Item('C')]}))
|
||||
const pane = new Pane(
|
||||
paneParams({ items: [new Item('A'), new Item('B'), new Item('C')] })
|
||||
)
|
||||
const [item1, item2, item3] = pane.getItems()
|
||||
pane.activateItem(item2)
|
||||
const item4 = new Item('D')
|
||||
@@ -160,18 +186,23 @@ describe('Pane', () => {
|
||||
})
|
||||
|
||||
it('invokes ::onDidAddItem() observers', () => {
|
||||
const pane = new Pane(paneParams({items: [new Item('A'), new Item('B')]}))
|
||||
const pane = new Pane(
|
||||
paneParams({ items: [new Item('A'), new Item('B')] })
|
||||
)
|
||||
const events = []
|
||||
pane.onDidAddItem(event => events.push(event))
|
||||
|
||||
const item = new Item('C')
|
||||
pane.addItem(item, {index: 1})
|
||||
expect(events).toEqual([{item, index: 1, moved: false}])
|
||||
pane.addItem(item, { index: 1 })
|
||||
expect(events).toEqual([{ item, index: 1, moved: false }])
|
||||
})
|
||||
|
||||
it('throws an exception if the item is already present on a pane', () => {
|
||||
const item = new Item('A')
|
||||
const container = new PaneContainer({config: atom.config, applicationDelegate: atom.applicationDelegate})
|
||||
const container = new PaneContainer({
|
||||
config: atom.config,
|
||||
applicationDelegate: atom.applicationDelegate
|
||||
})
|
||||
const pane1 = container.getActivePane()
|
||||
pane1.addItem(item)
|
||||
const pane2 = pane1.splitRight()
|
||||
@@ -179,36 +210,36 @@ describe('Pane', () => {
|
||||
})
|
||||
|
||||
it("throws an exception if the item isn't an object", () => {
|
||||
const pane = new Pane(paneParams({items: []}))
|
||||
const pane = new Pane(paneParams({ items: [] }))
|
||||
expect(() => pane.addItem(null)).toThrow()
|
||||
expect(() => pane.addItem('foo')).toThrow()
|
||||
expect(() => pane.addItem(1)).toThrow()
|
||||
})
|
||||
|
||||
it('destroys any existing pending item', () => {
|
||||
const pane = new Pane(paneParams({items: []}))
|
||||
const pane = new Pane(paneParams({ items: [] }))
|
||||
const itemA = new Item('A')
|
||||
const itemB = new Item('B')
|
||||
const itemC = new Item('C')
|
||||
pane.addItem(itemA, {pending: false})
|
||||
pane.addItem(itemB, {pending: true})
|
||||
pane.addItem(itemC, {pending: false})
|
||||
pane.addItem(itemA, { pending: false })
|
||||
pane.addItem(itemB, { pending: true })
|
||||
pane.addItem(itemC, { pending: false })
|
||||
expect(itemB.isDestroyed()).toBe(true)
|
||||
})
|
||||
|
||||
it('adds the new item before destroying any existing pending item', () => {
|
||||
const eventOrder = []
|
||||
|
||||
const pane = new Pane(paneParams({items: []}))
|
||||
const pane = new Pane(paneParams({ items: [] }))
|
||||
const itemA = new Item('A')
|
||||
const itemB = new Item('B')
|
||||
pane.addItem(itemA, {pending: true})
|
||||
pane.addItem(itemA, { pending: true })
|
||||
|
||||
pane.onDidAddItem(function ({item}) {
|
||||
pane.onDidAddItem(function ({ item }) {
|
||||
if (item === itemB) eventOrder.push('add')
|
||||
})
|
||||
|
||||
pane.onDidRemoveItem(function ({item}) {
|
||||
pane.onDidRemoveItem(function ({ item }) {
|
||||
if (item === itemA) eventOrder.push('remove')
|
||||
})
|
||||
|
||||
@@ -221,9 +252,11 @@ describe('Pane', () => {
|
||||
|
||||
it('subscribes to be notified when item terminates its pending state', () => {
|
||||
const fakeDisposable = { dispose: () => {} }
|
||||
const spy = jasmine.createSpy('onDidTerminatePendingState').andReturn((fakeDisposable))
|
||||
const spy = jasmine
|
||||
.createSpy('onDidTerminatePendingState')
|
||||
.andReturn(fakeDisposable)
|
||||
|
||||
const pane = new Pane(paneParams({items: []}))
|
||||
const pane = new Pane(paneParams({ items: [] }))
|
||||
const item = {
|
||||
getTitle: () => '',
|
||||
onDidTerminatePendingState: spy
|
||||
@@ -235,9 +268,9 @@ describe('Pane', () => {
|
||||
|
||||
it('subscribes to be notified when item is destroyed', () => {
|
||||
const fakeDisposable = { dispose: () => {} }
|
||||
const spy = jasmine.createSpy('onDidDestroy').andReturn((fakeDisposable))
|
||||
const spy = jasmine.createSpy('onDidDestroy').andReturn(fakeDisposable)
|
||||
|
||||
const pane = new Pane(paneParams({items: []}))
|
||||
const pane = new Pane(paneParams({ items: [] }))
|
||||
const item = {
|
||||
getTitle: () => '',
|
||||
onDidDestroy: spy
|
||||
@@ -251,7 +284,7 @@ describe('Pane', () => {
|
||||
beforeEach(() => spyOn(Grim, 'deprecate'))
|
||||
|
||||
it('supports the older public API', () => {
|
||||
const pane = new Pane(paneParams({items: []}))
|
||||
const pane = new Pane(paneParams({ items: [] }))
|
||||
const itemA = new Item('A')
|
||||
const itemB = new Item('B')
|
||||
const itemC = new Item('C')
|
||||
@@ -262,9 +295,11 @@ describe('Pane', () => {
|
||||
})
|
||||
|
||||
it('shows a deprecation warning', () => {
|
||||
const pane = new Pane(paneParams({items: []}))
|
||||
const pane = new Pane(paneParams({ items: [] }))
|
||||
pane.addItem(new Item(), 2)
|
||||
expect(Grim.deprecate).toHaveBeenCalledWith('Pane::addItem(item, 2) is deprecated in favor of Pane::addItem(item, {index: 2})')
|
||||
expect(Grim.deprecate).toHaveBeenCalledWith(
|
||||
'Pane::addItem(item, 2) is deprecated in favor of Pane::addItem(item, {index: 2})'
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -273,7 +308,7 @@ describe('Pane', () => {
|
||||
let pane = null
|
||||
|
||||
beforeEach(() => {
|
||||
pane = new Pane(paneParams({items: [new Item('A'), new Item('B')]}))
|
||||
pane = new Pane(paneParams({ items: [new Item('A'), new Item('B')] }))
|
||||
})
|
||||
|
||||
it('changes the active item to the current item', () => {
|
||||
@@ -306,16 +341,16 @@ describe('Pane', () => {
|
||||
})
|
||||
|
||||
it('replaces the active item if it is pending', () => {
|
||||
pane.activateItem(itemC, {pending: true})
|
||||
pane.activateItem(itemC, { pending: true })
|
||||
expect(pane.getItems().map(item => item.name)).toEqual(['A', 'C', 'B'])
|
||||
pane.activateItem(itemD, {pending: true})
|
||||
pane.activateItem(itemD, { pending: true })
|
||||
expect(pane.getItems().map(item => item.name)).toEqual(['A', 'D', 'B'])
|
||||
})
|
||||
|
||||
it('adds the item after the active item if it is not pending', () => {
|
||||
pane.activateItem(itemC, {pending: true})
|
||||
pane.activateItem(itemC, { pending: true })
|
||||
pane.activateItemAtIndex(2)
|
||||
pane.activateItem(itemD, {pending: true})
|
||||
pane.activateItem(itemD, { pending: true })
|
||||
expect(pane.getItems().map(item => item.name)).toEqual(['A', 'B', 'D'])
|
||||
})
|
||||
})
|
||||
@@ -369,14 +404,14 @@ describe('Pane', () => {
|
||||
const pendingSpy = jasmine.createSpy('onItemDidTerminatePendingState')
|
||||
const destroySpy = jasmine.createSpy('onWillDestroyItem')
|
||||
|
||||
await atom.workspace.open('sample.txt', {pending: true}).then(() => {
|
||||
await atom.workspace.open('sample.txt', { pending: true }).then(() => {
|
||||
pane = atom.workspace.getActivePane()
|
||||
})
|
||||
|
||||
pane.onItemDidTerminatePendingState(pendingSpy)
|
||||
pane.onWillDestroyItem(destroySpy)
|
||||
|
||||
await atom.workspace.open('sample.js', {pending: true})
|
||||
await atom.workspace.open('sample.js', { pending: true })
|
||||
|
||||
expect(destroySpy).toHaveBeenCalled()
|
||||
expect(pendingSpy).not.toHaveBeenCalled()
|
||||
@@ -385,7 +420,17 @@ describe('Pane', () => {
|
||||
|
||||
describe('::activateNextRecentlyUsedItem() and ::activatePreviousRecentlyUsedItem()', () => {
|
||||
it('sets the active item to the next/previous item in the itemStack, looping around at either end', () => {
|
||||
const pane = new Pane(paneParams({items: [new Item('A'), new Item('B'), new Item('C'), new Item('D'), new Item('E')]}))
|
||||
const pane = new Pane(
|
||||
paneParams({
|
||||
items: [
|
||||
new Item('A'),
|
||||
new Item('B'),
|
||||
new Item('C'),
|
||||
new Item('D'),
|
||||
new Item('E')
|
||||
]
|
||||
})
|
||||
)
|
||||
const [item1, item2, item3, item4, item5] = pane.getItems()
|
||||
pane.itemStack = [item3, item1, item2, item5, item4]
|
||||
|
||||
@@ -416,7 +461,9 @@ describe('Pane', () => {
|
||||
|
||||
describe('::activateNextItem() and ::activatePreviousItem()', () => {
|
||||
it('sets the active item to the next/previous item, looping around at either end', () => {
|
||||
const pane = new Pane(paneParams({items: [new Item('A'), new Item('B'), new Item('C')]}))
|
||||
const pane = new Pane(
|
||||
paneParams({ items: [new Item('A'), new Item('B'), new Item('C')] })
|
||||
)
|
||||
const [item1, item2, item3] = pane.getItems()
|
||||
|
||||
expect(pane.getActiveItem()).toBe(item1)
|
||||
@@ -433,8 +480,10 @@ describe('Pane', () => {
|
||||
|
||||
describe('::activateLastItem()', () => {
|
||||
it('sets the active item to the last item', () => {
|
||||
const pane = new Pane(paneParams({items: [new Item('A'), new Item('B'), new Item('C')]}))
|
||||
const [item1,, item3] = pane.getItems()
|
||||
const pane = new Pane(
|
||||
paneParams({ items: [new Item('A'), new Item('B'), new Item('C')] })
|
||||
)
|
||||
const [item1, , item3] = pane.getItems()
|
||||
|
||||
expect(pane.getActiveItem()).toBe(item1)
|
||||
pane.activateLastItem()
|
||||
@@ -444,7 +493,9 @@ describe('Pane', () => {
|
||||
|
||||
describe('::moveItemRight() and ::moveItemLeft()', () => {
|
||||
it('moves the active item to the right and left, without looping around at either end', () => {
|
||||
const pane = new Pane(paneParams({items: [new Item('A'), new Item('B'), new Item('C')]}))
|
||||
const pane = new Pane(
|
||||
paneParams({ items: [new Item('A'), new Item('B'), new Item('C')] })
|
||||
)
|
||||
const [item1, item2, item3] = pane.getItems()
|
||||
|
||||
pane.activateItemAtIndex(0)
|
||||
@@ -464,7 +515,9 @@ describe('Pane', () => {
|
||||
|
||||
describe('::activateItemAtIndex(index)', () => {
|
||||
it('activates the item at the given index', () => {
|
||||
const pane = new Pane(paneParams({items: [new Item('A'), new Item('B'), new Item('C')]}))
|
||||
const pane = new Pane(
|
||||
paneParams({ items: [new Item('A'), new Item('B'), new Item('C')] })
|
||||
)
|
||||
const [item1, item2, item3] = pane.getItems()
|
||||
pane.activateItemAtIndex(2)
|
||||
expect(pane.getActiveItem()).toBe(item3)
|
||||
@@ -485,7 +538,9 @@ describe('Pane', () => {
|
||||
let pane, item1, item2, item3
|
||||
|
||||
beforeEach(() => {
|
||||
pane = new Pane(paneParams({items: [new Item('A'), new Item('B'), new Item('C')]}))
|
||||
pane = new Pane(
|
||||
paneParams({ items: [new Item('A'), new Item('B'), new Item('C')] })
|
||||
)
|
||||
;[item1, item2, item3] = pane.getItems()
|
||||
})
|
||||
|
||||
@@ -521,17 +576,17 @@ describe('Pane', () => {
|
||||
|
||||
it('invokes ::onWillDestroyItem() and PaneContainer::onWillDestroyPaneItem observers before destroying the item', async () => {
|
||||
jasmine.useRealClock()
|
||||
pane.container = new PaneContainer({config: atom.config, confirm})
|
||||
pane.container = new PaneContainer({ config: atom.config, confirm })
|
||||
const events = []
|
||||
|
||||
pane.onWillDestroyItem(async (event) => {
|
||||
pane.onWillDestroyItem(async event => {
|
||||
expect(item2.isDestroyed()).toBe(false)
|
||||
await timeoutPromise(50)
|
||||
expect(item2.isDestroyed()).toBe(false)
|
||||
events.push(['will-destroy-item', event])
|
||||
})
|
||||
|
||||
pane.container.onWillDestroyPaneItem(async (event) => {
|
||||
pane.container.onWillDestroyPaneItem(async event => {
|
||||
expect(item2.isDestroyed()).toBe(false)
|
||||
await timeoutPromise(50)
|
||||
expect(item2.isDestroyed()).toBe(false)
|
||||
@@ -541,8 +596,8 @@ describe('Pane', () => {
|
||||
await pane.destroyItem(item2)
|
||||
expect(item2.isDestroyed()).toBe(true)
|
||||
expect(events).toEqual([
|
||||
['will-destroy-item', {item: item2, index: 1}],
|
||||
['will-destroy-pane-item', {item: item2, index: 1, pane}]
|
||||
['will-destroy-item', { item: item2, index: 1 }],
|
||||
['will-destroy-pane-item', { item: item2, index: 1, pane }]
|
||||
])
|
||||
})
|
||||
|
||||
@@ -550,14 +605,18 @@ describe('Pane', () => {
|
||||
const events = []
|
||||
pane.onWillRemoveItem(event => events.push(event))
|
||||
pane.destroyItem(item2)
|
||||
expect(events).toEqual([{item: item2, index: 1, moved: false, destroyed: true}])
|
||||
expect(events).toEqual([
|
||||
{ item: item2, index: 1, moved: false, destroyed: true }
|
||||
])
|
||||
})
|
||||
|
||||
it('invokes ::onDidRemoveItem() observers', () => {
|
||||
const events = []
|
||||
pane.onDidRemoveItem(event => events.push(event))
|
||||
pane.destroyItem(item2)
|
||||
expect(events).toEqual([{item: item2, index: 1, moved: false, destroyed: true}])
|
||||
expect(events).toEqual([
|
||||
{ item: item2, index: 1, moved: false, destroyed: true }
|
||||
])
|
||||
})
|
||||
|
||||
describe('when the destroyed item is the active item and is the first item', () => {
|
||||
@@ -608,7 +667,9 @@ describe('Pane', () => {
|
||||
|
||||
itemURI = null
|
||||
|
||||
showSaveDialog.andCallFake((options, callback) => callback('/selected/path'))
|
||||
showSaveDialog.andCallFake((options, callback) =>
|
||||
callback('/selected/path')
|
||||
)
|
||||
confirm.andCallFake((options, callback) => callback(0))
|
||||
|
||||
const success = await pane.destroyItem(item1)
|
||||
@@ -631,7 +692,7 @@ describe('Pane', () => {
|
||||
expect(item1.save).not.toHaveBeenCalled()
|
||||
expect(pane.getItems().includes(item1)).toBe(false)
|
||||
expect(item1.isDestroyed()).toBe(true)
|
||||
expect(success).toBe(true);
|
||||
expect(success).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -662,7 +723,9 @@ describe('Pane', () => {
|
||||
describe("when the 'core.destroyEmptyPanes' config option is false (the default)", () => {
|
||||
it('does not destroy the pane, but leaves it in place with empty items', () => {
|
||||
expect(atom.config.get('core.destroyEmptyPanes')).toBe(false)
|
||||
for (let item of pane.getItems()) { pane.destroyItem(item) }
|
||||
for (let item of pane.getItems()) {
|
||||
pane.destroyItem(item)
|
||||
}
|
||||
expect(pane.isDestroyed()).toBe(false)
|
||||
expect(pane.getActiveItem()).toBeUndefined()
|
||||
expect(() => pane.saveActiveItem()).not.toThrow()
|
||||
@@ -687,7 +750,7 @@ describe('Pane', () => {
|
||||
const success = await pane.destroyItem(item1)
|
||||
expect(pane.getItems().includes(item1)).toBe(true)
|
||||
expect(item1.isDestroyed()).toBe(false)
|
||||
expect(success).toBe(false);
|
||||
expect(success).toBe(false)
|
||||
})
|
||||
|
||||
it('destroy the item if force=true', async () => {
|
||||
@@ -702,7 +765,9 @@ describe('Pane', () => {
|
||||
|
||||
describe('::destroyActiveItem()', () => {
|
||||
it('destroys the active item', () => {
|
||||
const pane = new Pane(paneParams({items: [new Item('A'), new Item('B')]}))
|
||||
const pane = new Pane(
|
||||
paneParams({ items: [new Item('A'), new Item('B')] })
|
||||
)
|
||||
const activeItem = pane.getActiveItem()
|
||||
pane.destroyActiveItem()
|
||||
expect(activeItem.isDestroyed()).toBe(true)
|
||||
@@ -717,7 +782,9 @@ describe('Pane', () => {
|
||||
|
||||
describe('::destroyItems()', () => {
|
||||
it('destroys all items', async () => {
|
||||
const pane = new Pane(paneParams({items: [new Item('A'), new Item('B'), new Item('C')]}))
|
||||
const pane = new Pane(
|
||||
paneParams({ items: [new Item('A'), new Item('B'), new Item('C')] })
|
||||
)
|
||||
const [item1, item2, item3] = pane.getItems()
|
||||
|
||||
await pane.destroyItems()
|
||||
@@ -730,7 +797,7 @@ describe('Pane', () => {
|
||||
|
||||
describe('::observeItems()', () => {
|
||||
it('invokes the observer with all current and future items', () => {
|
||||
const pane = new Pane(paneParams({items: [new Item(), new Item()]}))
|
||||
const pane = new Pane(paneParams({ items: [new Item(), new Item()] }))
|
||||
const [item1, item2] = pane.getItems()
|
||||
|
||||
const observed = []
|
||||
@@ -745,8 +812,10 @@ describe('Pane', () => {
|
||||
|
||||
describe('when an item emits a destroyed event', () => {
|
||||
it('removes it from the list of items', () => {
|
||||
const pane = new Pane(paneParams({items: [new Item('A'), new Item('B'), new Item('C')]}))
|
||||
const [item1,, item3] = pane.getItems()
|
||||
const pane = new Pane(
|
||||
paneParams({ items: [new Item('A'), new Item('B'), new Item('C')] })
|
||||
)
|
||||
const [item1, , item3] = pane.getItems()
|
||||
pane.itemAtIndex(1).destroy()
|
||||
expect(pane.getItems()).toEqual([item1, item3])
|
||||
})
|
||||
@@ -754,7 +823,9 @@ describe('Pane', () => {
|
||||
|
||||
describe('::destroyInactiveItems()', () => {
|
||||
it('destroys all items but the active item', () => {
|
||||
const pane = new Pane(paneParams({items: [new Item('A'), new Item('B'), new Item('C')]}))
|
||||
const pane = new Pane(
|
||||
paneParams({ items: [new Item('A'), new Item('B'), new Item('C')] })
|
||||
)
|
||||
const [, item2] = pane.getItems()
|
||||
pane.activateItem(item2)
|
||||
pane.destroyInactiveItems()
|
||||
@@ -766,8 +837,10 @@ describe('Pane', () => {
|
||||
let pane
|
||||
|
||||
beforeEach(() => {
|
||||
pane = new Pane(paneParams({items: [new Item('A')]}))
|
||||
showSaveDialog.andCallFake((options, callback) => callback('/selected/path'))
|
||||
pane = new Pane(paneParams({ items: [new Item('A')] }))
|
||||
showSaveDialog.andCallFake((options, callback) =>
|
||||
callback('/selected/path')
|
||||
)
|
||||
})
|
||||
|
||||
describe('when the active item has a uri', () => {
|
||||
@@ -797,7 +870,9 @@ describe('Pane', () => {
|
||||
pane.getActiveItem().saveAs = jasmine.createSpy('saveAs')
|
||||
await pane.saveActiveItem()
|
||||
expect(showSaveDialog.mostRecentCall.args[0]).toEqual({})
|
||||
expect(pane.getActiveItem().saveAs).toHaveBeenCalledWith('/selected/path')
|
||||
expect(pane.getActiveItem().saveAs).toHaveBeenCalledWith(
|
||||
'/selected/path'
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -826,14 +901,16 @@ describe('Pane', () => {
|
||||
return Promise.reject(error)
|
||||
}
|
||||
|
||||
waitsFor((done) => {
|
||||
const subscription = atom.notifications.onDidAddNotification(function (notification) {
|
||||
expect(notification.getType()).toBe('warning')
|
||||
expect(notification.getMessage()).toContain('Permission denied')
|
||||
expect(notification.getMessage()).toContain('/foo')
|
||||
subscription.dispose()
|
||||
done()
|
||||
})
|
||||
waitsFor(done => {
|
||||
const subscription = atom.notifications.onDidAddNotification(
|
||||
function (notification) {
|
||||
expect(notification.getType()).toBe('warning')
|
||||
expect(notification.getMessage()).toContain('Permission denied')
|
||||
expect(notification.getMessage()).toContain('/foo')
|
||||
subscription.dispose()
|
||||
done()
|
||||
}
|
||||
)
|
||||
pane.saveActiveItem()
|
||||
})
|
||||
})
|
||||
@@ -848,14 +925,16 @@ describe('Pane', () => {
|
||||
throw error
|
||||
}
|
||||
|
||||
waitsFor((done) => {
|
||||
const subscription = atom.notifications.onDidAddNotification(function (notification) {
|
||||
expect(notification.getType()).toBe('warning')
|
||||
expect(notification.getMessage()).toContain('Permission denied')
|
||||
expect(notification.getMessage()).toContain('/foo')
|
||||
subscription.dispose()
|
||||
done()
|
||||
})
|
||||
waitsFor(done => {
|
||||
const subscription = atom.notifications.onDidAddNotification(
|
||||
function (notification) {
|
||||
expect(notification.getType()).toBe('warning')
|
||||
expect(notification.getMessage()).toContain('Permission denied')
|
||||
expect(notification.getMessage()).toContain('/foo')
|
||||
subscription.dispose()
|
||||
done()
|
||||
}
|
||||
)
|
||||
pane.saveActiveItem()
|
||||
})
|
||||
})
|
||||
@@ -866,8 +945,10 @@ describe('Pane', () => {
|
||||
let pane = null
|
||||
|
||||
beforeEach(() => {
|
||||
pane = new Pane(paneParams({items: [new Item('A')]}))
|
||||
showSaveDialog.andCallFake((options, callback) => callback('/selected/path'))
|
||||
pane = new Pane(paneParams({ items: [new Item('A')] }))
|
||||
showSaveDialog.andCallFake((options, callback) =>
|
||||
callback('/selected/path')
|
||||
)
|
||||
})
|
||||
|
||||
describe('when the current item has a saveAs method', () => {
|
||||
@@ -877,10 +958,16 @@ describe('Pane', () => {
|
||||
pane.getActiveItem().path = __filename
|
||||
pane.getActiveItem().saveAs = jasmine.createSpy('saveAs')
|
||||
pane.saveActiveItemAs()
|
||||
expect(showSaveDialog.mostRecentCall.args[0]).toEqual({defaultPath: __filename})
|
||||
expect(showSaveDialog.mostRecentCall.args[0]).toEqual({
|
||||
defaultPath: __filename
|
||||
})
|
||||
|
||||
await conditionPromise(() => pane.getActiveItem().saveAs.callCount === 1)
|
||||
expect(pane.getActiveItem().saveAs).toHaveBeenCalledWith('/selected/path')
|
||||
await conditionPromise(
|
||||
() => pane.getActiveItem().saveAs.callCount === 1
|
||||
)
|
||||
expect(pane.getActiveItem().saveAs).toHaveBeenCalledWith(
|
||||
'/selected/path'
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -901,14 +988,16 @@ describe('Pane', () => {
|
||||
return Promise.reject(error)
|
||||
}
|
||||
|
||||
waitsFor((done) => {
|
||||
const subscription = atom.notifications.onDidAddNotification(function (notification) {
|
||||
expect(notification.getType()).toBe('warning')
|
||||
expect(notification.getMessage()).toContain('Permission denied')
|
||||
expect(notification.getMessage()).toContain('/foo')
|
||||
subscription.dispose()
|
||||
done()
|
||||
})
|
||||
waitsFor(done => {
|
||||
const subscription = atom.notifications.onDidAddNotification(
|
||||
function (notification) {
|
||||
expect(notification.getType()).toBe('warning')
|
||||
expect(notification.getMessage()).toContain('Permission denied')
|
||||
expect(notification.getMessage()).toContain('/foo')
|
||||
subscription.dispose()
|
||||
done()
|
||||
}
|
||||
)
|
||||
pane.saveActiveItemAs()
|
||||
})
|
||||
})
|
||||
@@ -917,7 +1006,11 @@ describe('Pane', () => {
|
||||
|
||||
describe('::itemForURI(uri)', () => {
|
||||
it('returns the item for which a call to .getURI() returns the given uri', () => {
|
||||
const pane = new Pane(paneParams({items: [new Item('A'), new Item('B'), new Item('C'), new Item('D')]}))
|
||||
const pane = new Pane(
|
||||
paneParams({
|
||||
items: [new Item('A'), new Item('B'), new Item('C'), new Item('D')]
|
||||
})
|
||||
)
|
||||
const [item1, item2] = pane.getItems()
|
||||
item1.uri = 'a'
|
||||
item2.uri = 'b'
|
||||
@@ -931,7 +1024,11 @@ describe('Pane', () => {
|
||||
let pane, item1, item2, item3, item4
|
||||
|
||||
beforeEach(() => {
|
||||
pane = new Pane(paneParams({items: [new Item('A'), new Item('B'), new Item('C'), new Item('D')]}))
|
||||
pane = new Pane(
|
||||
paneParams({
|
||||
items: [new Item('A'), new Item('B'), new Item('C'), new Item('D')]
|
||||
})
|
||||
)
|
||||
;[item1, item2, item3, item4] = pane.getItems()
|
||||
})
|
||||
|
||||
@@ -953,8 +1050,8 @@ describe('Pane', () => {
|
||||
pane.moveItem(item1, 2)
|
||||
pane.moveItem(item2, 3)
|
||||
expect(events).toEqual([
|
||||
{item: item1, oldIndex: 0, newIndex: 2},
|
||||
{item: item2, oldIndex: 0, newIndex: 3}
|
||||
{ item: item1, oldIndex: 0, newIndex: 2 },
|
||||
{ item: item2, oldIndex: 0, newIndex: 3 }
|
||||
])
|
||||
})
|
||||
})
|
||||
@@ -964,12 +1061,12 @@ describe('Pane', () => {
|
||||
let item1, item2, item3, item4, item5
|
||||
|
||||
beforeEach(() => {
|
||||
container = new PaneContainer({config: atom.config, confirm})
|
||||
container = new PaneContainer({ config: atom.config, confirm })
|
||||
pane1 = container.getActivePane()
|
||||
pane1.addItems([new Item('A'), new Item('B'), new Item('C')])
|
||||
pane2 = pane1.splitRight({items: [new Item('D'), new Item('E')]});
|
||||
[item1, item2, item3] = pane1.getItems();
|
||||
[item4, item5] = pane2.getItems()
|
||||
pane2 = pane1.splitRight({ items: [new Item('D'), new Item('E')] })
|
||||
;[item1, item2, item3] = pane1.getItems()
|
||||
;[item4, item5] = pane2.getItems()
|
||||
})
|
||||
|
||||
it('moves the item to the given pane at the given index', () => {
|
||||
@@ -983,7 +1080,9 @@ describe('Pane', () => {
|
||||
pane1.onWillRemoveItem(event => events.push(event))
|
||||
pane1.moveItemToPane(item2, pane2, 1)
|
||||
|
||||
expect(events).toEqual([{item: item2, index: 1, moved: true, destroyed: false}])
|
||||
expect(events).toEqual([
|
||||
{ item: item2, index: 1, moved: true, destroyed: false }
|
||||
])
|
||||
})
|
||||
|
||||
it('invokes ::onDidRemoveItem() observers', () => {
|
||||
@@ -991,7 +1090,9 @@ describe('Pane', () => {
|
||||
pane1.onDidRemoveItem(event => events.push(event))
|
||||
pane1.moveItemToPane(item2, pane2, 1)
|
||||
|
||||
expect(events).toEqual([{item: item2, index: 1, moved: true, destroyed: false}])
|
||||
expect(events).toEqual([
|
||||
{ item: item2, index: 1, moved: true, destroyed: false }
|
||||
])
|
||||
})
|
||||
|
||||
it('does not invoke ::onDidAddPaneItem observers on the container', () => {
|
||||
@@ -1025,7 +1126,7 @@ describe('Pane', () => {
|
||||
describe('when the item being moved is pending', () => {
|
||||
it('is made permanent in the new pane', () => {
|
||||
const item6 = new Item('F')
|
||||
pane1.addItem(item6, {pending: true})
|
||||
pane1.addItem(item6, { pending: true })
|
||||
expect(pane1.getPendingItem()).toEqual(item6)
|
||||
pane1.moveItemToPane(item6, pane2, 0)
|
||||
expect(pane2.getPendingItem()).not.toEqual(item6)
|
||||
@@ -1035,7 +1136,7 @@ describe('Pane', () => {
|
||||
describe('when the target pane has a pending item', () => {
|
||||
it('does not destroy the pending item', () => {
|
||||
const item6 = new Item('F')
|
||||
pane1.addItem(item6, {pending: true})
|
||||
pane1.addItem(item6, { pending: true })
|
||||
expect(pane1.getPendingItem()).toEqual(item6)
|
||||
pane2.moveItemToPane(item5, pane1, 0)
|
||||
expect(pane1.getPendingItem()).toEqual(item6)
|
||||
@@ -1047,7 +1148,11 @@ describe('Pane', () => {
|
||||
let pane1, item1, container
|
||||
|
||||
beforeEach(() => {
|
||||
container = new PaneContainer({config: atom.config, confirm, deserializerManager: atom.deserializers})
|
||||
container = new PaneContainer({
|
||||
config: atom.config,
|
||||
confirm,
|
||||
deserializerManager: atom.deserializers
|
||||
})
|
||||
pane1 = container.getActivePane()
|
||||
item1 = new Item('A')
|
||||
pane1.addItem(item1)
|
||||
@@ -1056,8 +1161,8 @@ describe('Pane', () => {
|
||||
describe('::splitLeft(params)', () => {
|
||||
describe('when the parent is the container root', () => {
|
||||
it('replaces itself with a row and inserts a new pane to the left of itself', () => {
|
||||
const pane2 = pane1.splitLeft({items: [new Item('B')]})
|
||||
const pane3 = pane1.splitLeft({items: [new Item('C')]})
|
||||
const pane2 = pane1.splitLeft({ items: [new Item('B')] })
|
||||
const pane3 = pane1.splitLeft({ items: [new Item('C')] })
|
||||
expect(container.root.orientation).toBe('horizontal')
|
||||
expect(container.root.children).toEqual([pane2, pane3, pane1])
|
||||
})
|
||||
@@ -1065,20 +1170,20 @@ describe('Pane', () => {
|
||||
|
||||
describe('when `moveActiveItem: true` is passed in the params', () => {
|
||||
it('moves the active item', () => {
|
||||
const pane2 = pane1.splitLeft({moveActiveItem: true})
|
||||
const pane2 = pane1.splitLeft({ moveActiveItem: true })
|
||||
expect(pane2.getActiveItem()).toBe(item1)
|
||||
})
|
||||
})
|
||||
|
||||
describe('when `copyActiveItem: true` is passed in the params', () => {
|
||||
it('duplicates the active item', () => {
|
||||
const pane2 = pane1.splitLeft({copyActiveItem: true})
|
||||
const pane2 = pane1.splitLeft({ copyActiveItem: true })
|
||||
expect(pane2.getActiveItem()).toEqual(pane1.getActiveItem())
|
||||
})
|
||||
|
||||
it("does nothing if the active item doesn't implement .copy()", () => {
|
||||
item1.copy = null
|
||||
const pane2 = pane1.splitLeft({copyActiveItem: true})
|
||||
const pane2 = pane1.splitLeft({ copyActiveItem: true })
|
||||
expect(pane2.getActiveItem()).toBeUndefined()
|
||||
})
|
||||
})
|
||||
@@ -1086,8 +1191,8 @@ describe('Pane', () => {
|
||||
describe('when the parent is a column', () => {
|
||||
it('replaces itself with a row and inserts a new pane to the left of itself', () => {
|
||||
pane1.splitDown()
|
||||
const pane2 = pane1.splitLeft({items: [new Item('B')]})
|
||||
const pane3 = pane1.splitLeft({items: [new Item('C')]})
|
||||
const pane2 = pane1.splitLeft({ items: [new Item('B')] })
|
||||
const pane3 = pane1.splitLeft({ items: [new Item('C')] })
|
||||
const row = container.root.children[0]
|
||||
expect(row.orientation).toBe('horizontal')
|
||||
expect(row.children).toEqual([pane2, pane3, pane1])
|
||||
@@ -1098,8 +1203,8 @@ describe('Pane', () => {
|
||||
describe('::splitRight(params)', () => {
|
||||
describe('when the parent is the container root', () => {
|
||||
it('replaces itself with a row and inserts a new pane to the right of itself', () => {
|
||||
const pane2 = pane1.splitRight({items: [new Item('B')]})
|
||||
const pane3 = pane1.splitRight({items: [new Item('C')]})
|
||||
const pane2 = pane1.splitRight({ items: [new Item('B')] })
|
||||
const pane3 = pane1.splitRight({ items: [new Item('C')] })
|
||||
expect(container.root.orientation).toBe('horizontal')
|
||||
expect(container.root.children).toEqual([pane1, pane3, pane2])
|
||||
})
|
||||
@@ -1107,14 +1212,14 @@ describe('Pane', () => {
|
||||
|
||||
describe('when `moveActiveItem: true` is passed in the params', () => {
|
||||
it('moves the active item', () => {
|
||||
const pane2 = pane1.splitRight({moveActiveItem: true})
|
||||
const pane2 = pane1.splitRight({ moveActiveItem: true })
|
||||
expect(pane2.getActiveItem()).toBe(item1)
|
||||
})
|
||||
})
|
||||
|
||||
describe('when `copyActiveItem: true` is passed in the params', () => {
|
||||
it('duplicates the active item', () => {
|
||||
const pane2 = pane1.splitRight({copyActiveItem: true})
|
||||
const pane2 = pane1.splitRight({ copyActiveItem: true })
|
||||
expect(pane2.getActiveItem()).toEqual(pane1.getActiveItem())
|
||||
})
|
||||
})
|
||||
@@ -1122,8 +1227,8 @@ describe('Pane', () => {
|
||||
describe('when the parent is a column', () => {
|
||||
it('replaces itself with a row and inserts a new pane to the right of itself', () => {
|
||||
pane1.splitDown()
|
||||
const pane2 = pane1.splitRight({items: [new Item('B')]})
|
||||
const pane3 = pane1.splitRight({items: [new Item('C')]})
|
||||
const pane2 = pane1.splitRight({ items: [new Item('B')] })
|
||||
const pane3 = pane1.splitRight({ items: [new Item('C')] })
|
||||
const row = container.root.children[0]
|
||||
expect(row.orientation).toBe('horizontal')
|
||||
expect(row.children).toEqual([pane1, pane3, pane2])
|
||||
@@ -1134,8 +1239,8 @@ describe('Pane', () => {
|
||||
describe('::splitUp(params)', () => {
|
||||
describe('when the parent is the container root', () => {
|
||||
it('replaces itself with a column and inserts a new pane above itself', () => {
|
||||
const pane2 = pane1.splitUp({items: [new Item('B')]})
|
||||
const pane3 = pane1.splitUp({items: [new Item('C')]})
|
||||
const pane2 = pane1.splitUp({ items: [new Item('B')] })
|
||||
const pane3 = pane1.splitUp({ items: [new Item('C')] })
|
||||
expect(container.root.orientation).toBe('vertical')
|
||||
expect(container.root.children).toEqual([pane2, pane3, pane1])
|
||||
})
|
||||
@@ -1143,14 +1248,14 @@ describe('Pane', () => {
|
||||
|
||||
describe('when `moveActiveItem: true` is passed in the params', () => {
|
||||
it('moves the active item', () => {
|
||||
const pane2 = pane1.splitUp({moveActiveItem: true})
|
||||
const pane2 = pane1.splitUp({ moveActiveItem: true })
|
||||
expect(pane2.getActiveItem()).toBe(item1)
|
||||
})
|
||||
})
|
||||
|
||||
describe('when `copyActiveItem: true` is passed in the params', () => {
|
||||
it('duplicates the active item', () => {
|
||||
const pane2 = pane1.splitUp({copyActiveItem: true})
|
||||
const pane2 = pane1.splitUp({ copyActiveItem: true })
|
||||
expect(pane2.getActiveItem()).toEqual(pane1.getActiveItem())
|
||||
})
|
||||
})
|
||||
@@ -1158,8 +1263,8 @@ describe('Pane', () => {
|
||||
describe('when the parent is a row', () => {
|
||||
it('replaces itself with a column and inserts a new pane above itself', () => {
|
||||
pane1.splitRight()
|
||||
const pane2 = pane1.splitUp({items: [new Item('B')]})
|
||||
const pane3 = pane1.splitUp({items: [new Item('C')]})
|
||||
const pane2 = pane1.splitUp({ items: [new Item('B')] })
|
||||
const pane3 = pane1.splitUp({ items: [new Item('C')] })
|
||||
const column = container.root.children[0]
|
||||
expect(column.orientation).toBe('vertical')
|
||||
expect(column.children).toEqual([pane2, pane3, pane1])
|
||||
@@ -1170,8 +1275,8 @@ describe('Pane', () => {
|
||||
describe('::splitDown(params)', () => {
|
||||
describe('when the parent is the container root', () => {
|
||||
it('replaces itself with a column and inserts a new pane below itself', () => {
|
||||
const pane2 = pane1.splitDown({items: [new Item('B')]})
|
||||
const pane3 = pane1.splitDown({items: [new Item('C')]})
|
||||
const pane2 = pane1.splitDown({ items: [new Item('B')] })
|
||||
const pane3 = pane1.splitDown({ items: [new Item('C')] })
|
||||
expect(container.root.orientation).toBe('vertical')
|
||||
expect(container.root.children).toEqual([pane1, pane3, pane2])
|
||||
})
|
||||
@@ -1179,14 +1284,14 @@ describe('Pane', () => {
|
||||
|
||||
describe('when `moveActiveItem: true` is passed in the params', () => {
|
||||
it('moves the active item', () => {
|
||||
const pane2 = pane1.splitDown({moveActiveItem: true})
|
||||
const pane2 = pane1.splitDown({ moveActiveItem: true })
|
||||
expect(pane2.getActiveItem()).toBe(item1)
|
||||
})
|
||||
})
|
||||
|
||||
describe('when `copyActiveItem: true` is passed in the params', () => {
|
||||
it('duplicates the active item', () => {
|
||||
const pane2 = pane1.splitDown({copyActiveItem: true})
|
||||
const pane2 = pane1.splitDown({ copyActiveItem: true })
|
||||
expect(pane2.getActiveItem()).toEqual(pane1.getActiveItem())
|
||||
})
|
||||
})
|
||||
@@ -1194,8 +1299,8 @@ describe('Pane', () => {
|
||||
describe('when the parent is a row', () => {
|
||||
it('replaces itself with a column and inserts a new pane below itself', () => {
|
||||
pane1.splitRight()
|
||||
const pane2 = pane1.splitDown({items: [new Item('B')]})
|
||||
const pane3 = pane1.splitDown({items: [new Item('C')]})
|
||||
const pane2 = pane1.splitDown({ items: [new Item('B')] })
|
||||
const pane3 = pane1.splitDown({ items: [new Item('C')] })
|
||||
const column = container.root.children[0]
|
||||
expect(column.orientation).toBe('vertical')
|
||||
expect(column.children).toEqual([pane1, pane3, pane2])
|
||||
@@ -1209,7 +1314,9 @@ describe('Pane', () => {
|
||||
pane1.destroyItem(item1)
|
||||
expect(pane1.getActiveItem()).toBe(undefined)
|
||||
|
||||
const pane2 = pane1.split('horizontal', 'before', {moveActiveItem: true})
|
||||
const pane2 = pane1.split('horizontal', 'before', {
|
||||
moveActiveItem: true
|
||||
})
|
||||
expect(container.root.children).toEqual([pane2, pane1])
|
||||
|
||||
expect(pane2.getActiveItem()).toBe(undefined)
|
||||
@@ -1221,7 +1328,9 @@ describe('Pane', () => {
|
||||
pane1.destroyItem(item1)
|
||||
expect(pane1.getActiveItem()).toBe(undefined)
|
||||
|
||||
const pane2 = pane1.split('horizontal', 'before', {copyActiveItem: true})
|
||||
const pane2 = pane1.split('horizontal', 'before', {
|
||||
copyActiveItem: true
|
||||
})
|
||||
expect(container.root.children).toEqual([pane2, pane1])
|
||||
|
||||
expect(pane2.getActiveItem()).toBe(undefined)
|
||||
@@ -1239,7 +1348,9 @@ describe('Pane', () => {
|
||||
|
||||
describe('::close()', () => {
|
||||
it('prompts to save unsaved items before destroying the pane', async () => {
|
||||
const pane = new Pane(paneParams({items: [new Item('A'), new Item('B')]}))
|
||||
const pane = new Pane(
|
||||
paneParams({ items: [new Item('A'), new Item('B')] })
|
||||
)
|
||||
const [item1] = pane.getItems()
|
||||
|
||||
item1.shouldPromptToSave = () => true
|
||||
@@ -1254,7 +1365,9 @@ describe('Pane', () => {
|
||||
})
|
||||
|
||||
it('does not destroy the pane if the user clicks cancel', async () => {
|
||||
const pane = new Pane(paneParams({items: [new Item('A'), new Item('B')]}))
|
||||
const pane = new Pane(
|
||||
paneParams({ items: [new Item('A'), new Item('B')] })
|
||||
)
|
||||
const [item1] = pane.getItems()
|
||||
|
||||
item1.shouldPromptToSave = () => true
|
||||
@@ -1270,7 +1383,9 @@ describe('Pane', () => {
|
||||
})
|
||||
|
||||
it('does not destroy the pane if the user starts to save but then does not choose a path', async () => {
|
||||
const pane = new Pane(paneParams({items: [new Item('A'), new Item('B')]}))
|
||||
const pane = new Pane(
|
||||
paneParams({ items: [new Item('A'), new Item('B')] })
|
||||
)
|
||||
const [item1] = pane.getItems()
|
||||
|
||||
item1.shouldPromptToSave = () => true
|
||||
@@ -1290,8 +1405,12 @@ describe('Pane', () => {
|
||||
let pane, item1
|
||||
|
||||
beforeEach(() => {
|
||||
pane = new Pane({items: [new Item('A'), new Item('B')], applicationDelegate: atom.applicationDelegate, config: atom.config});
|
||||
[item1] = pane.getItems()
|
||||
pane = new Pane({
|
||||
items: [new Item('A'), new Item('B')],
|
||||
applicationDelegate: atom.applicationDelegate,
|
||||
config: atom.config
|
||||
})
|
||||
;[item1] = pane.getItems()
|
||||
|
||||
item1.shouldPromptToSave = () => true
|
||||
item1.getURI = () => '/test/path'
|
||||
@@ -1336,7 +1455,9 @@ describe('Pane', () => {
|
||||
await pane.close()
|
||||
expect(atom.applicationDelegate.confirm).toHaveBeenCalled()
|
||||
expect(confirmations).toBe(2)
|
||||
expect(atom.applicationDelegate.showSaveDialog.mostRecentCall.args[0]).toEqual({})
|
||||
expect(
|
||||
atom.applicationDelegate.showSaveDialog.mostRecentCall.args[0]
|
||||
).toEqual({})
|
||||
expect(item1.save).toHaveBeenCalled()
|
||||
expect(item1.saveAs).toHaveBeenCalled()
|
||||
expect(pane.isDestroyed()).toBe(true)
|
||||
@@ -1365,7 +1486,9 @@ describe('Pane', () => {
|
||||
await pane.close()
|
||||
expect(atom.applicationDelegate.confirm).toHaveBeenCalled()
|
||||
expect(confirmations).toBe(3)
|
||||
expect(atom.applicationDelegate.showSaveDialog.mostRecentCall.args[0]).toEqual({})
|
||||
expect(
|
||||
atom.applicationDelegate.showSaveDialog.mostRecentCall.args[0]
|
||||
).toEqual({})
|
||||
expect(item1.save).toHaveBeenCalled()
|
||||
expect(item1.saveAs).toHaveBeenCalled()
|
||||
expect(pane.isDestroyed()).toBe(true)
|
||||
@@ -1377,7 +1500,7 @@ describe('Pane', () => {
|
||||
let container, pane1, pane2
|
||||
|
||||
beforeEach(() => {
|
||||
container = new PaneContainer({config: atom.config, confirm})
|
||||
container = new PaneContainer({ config: atom.config, confirm })
|
||||
pane1 = container.root
|
||||
pane1.addItems([new Item('A'), new Item('B')])
|
||||
pane2 = pane1.splitRight()
|
||||
@@ -1386,7 +1509,7 @@ describe('Pane', () => {
|
||||
it('invokes ::onWillDestroy observers before destroying items', () => {
|
||||
let itemsDestroyed = null
|
||||
pane1.onWillDestroy(() => {
|
||||
itemsDestroyed = (pane1.getItems().map((item) => item.isDestroyed()))
|
||||
itemsDestroyed = pane1.getItems().map(item => item.isDestroyed())
|
||||
})
|
||||
pane1.destroy()
|
||||
expect(itemsDestroyed).toEqual([false, false])
|
||||
@@ -1435,7 +1558,7 @@ describe('Pane', () => {
|
||||
let editor1, pane, eventCount
|
||||
|
||||
beforeEach(async () => {
|
||||
editor1 = await atom.workspace.open('sample.txt', {pending: true})
|
||||
editor1 = await atom.workspace.open('sample.txt', { pending: true })
|
||||
pane = atom.workspace.getActivePane()
|
||||
eventCount = 0
|
||||
editor1.onDidTerminatePendingState(() => eventCount++)
|
||||
@@ -1458,7 +1581,7 @@ describe('Pane', () => {
|
||||
})
|
||||
|
||||
it('terminates pending state when buffer is changed', () => {
|
||||
editor1.insertText('I\'ll be back!')
|
||||
editor1.insertText("I'll be back!")
|
||||
advanceClock(editor1.getBuffer().stoppedChangingDelay)
|
||||
|
||||
expect(pane.getPendingItem()).toBeNull()
|
||||
@@ -1498,10 +1621,12 @@ describe('Pane', () => {
|
||||
let pane = null
|
||||
|
||||
beforeEach(() => {
|
||||
pane = new Pane(paneParams({
|
||||
items: [new Item('A', 'a'), new Item('B', 'b'), new Item('C', 'c')],
|
||||
flexScale: 2
|
||||
}))
|
||||
pane = new Pane(
|
||||
paneParams({
|
||||
items: [new Item('A', 'a'), new Item('B', 'b'), new Item('C', 'c')],
|
||||
flexScale: 2
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
it('can serialize and deserialize the pane and all its items', () => {
|
||||
@@ -1524,7 +1649,7 @@ describe('Pane', () => {
|
||||
|
||||
it("restores the correct item when it doesn't implement getURI() and some items weren't deserialized", () => {
|
||||
const unserializable = {}
|
||||
pane.addItem(unserializable, {index: 0})
|
||||
pane.addItem(unserializable, { index: 0 })
|
||||
pane.items[2].getURI = null
|
||||
pane.activateItemAtIndex(2)
|
||||
const newPane = Pane.deserialize(pane.serialize(), atom)
|
||||
|
||||
@@ -6,8 +6,7 @@ const PanelContainer = require('../src/panel-container')
|
||||
describe('PanelContainerElement', () => {
|
||||
let jasmineContent, element, container
|
||||
|
||||
class TestPanelContainerItem {
|
||||
}
|
||||
class TestPanelContainerItem {}
|
||||
|
||||
class TestPanelContainerItemElement_ extends HTMLElement {
|
||||
createdCallback () {
|
||||
@@ -17,23 +16,25 @@ describe('PanelContainerElement', () => {
|
||||
this.model = model
|
||||
return this
|
||||
}
|
||||
focus() {}
|
||||
focus () {}
|
||||
}
|
||||
|
||||
const TestPanelContainerItemElement = document.registerElement(
|
||||
'atom-test-container-item-element',
|
||||
{prototype: TestPanelContainerItemElement_.prototype}
|
||||
{ prototype: TestPanelContainerItemElement_.prototype }
|
||||
)
|
||||
|
||||
beforeEach(() => {
|
||||
jasmineContent = document.body.querySelector('#jasmine-content')
|
||||
|
||||
atom.views.addViewProvider(
|
||||
TestPanelContainerItem,
|
||||
model => new TestPanelContainerItemElement().initialize(model)
|
||||
atom.views.addViewProvider(TestPanelContainerItem, model =>
|
||||
new TestPanelContainerItemElement().initialize(model)
|
||||
)
|
||||
|
||||
container = new PanelContainer({viewRegistry: atom.views, location: 'left'})
|
||||
container = new PanelContainer({
|
||||
viewRegistry: atom.views,
|
||||
location: 'left'
|
||||
})
|
||||
element = container.getElement()
|
||||
jasmineContent.appendChild(element)
|
||||
})
|
||||
@@ -50,9 +51,18 @@ describe('PanelContainerElement', () => {
|
||||
|
||||
describe('adding and removing panels', () => {
|
||||
it('allows panels to be inserted at any position', () => {
|
||||
const panel1 = new Panel({item: new TestPanelContainerItem(), priority: 10}, atom.views)
|
||||
const panel2 = new Panel({item: new TestPanelContainerItem(), priority: 5}, atom.views)
|
||||
const panel3 = new Panel({item: new TestPanelContainerItem(), priority: 8}, atom.views)
|
||||
const panel1 = new Panel(
|
||||
{ item: new TestPanelContainerItem(), priority: 10 },
|
||||
atom.views
|
||||
)
|
||||
const panel2 = new Panel(
|
||||
{ item: new TestPanelContainerItem(), priority: 5 },
|
||||
atom.views
|
||||
)
|
||||
const panel3 = new Panel(
|
||||
{ item: new TestPanelContainerItem(), priority: 8 },
|
||||
atom.views
|
||||
)
|
||||
|
||||
container.addPanel(panel1)
|
||||
container.addPanel(panel2)
|
||||
@@ -67,7 +77,10 @@ describe('PanelContainerElement', () => {
|
||||
it('adds atom-panel elements when a new panel is added to the container; removes them when the panels are destroyed', () => {
|
||||
expect(element.childNodes.length).toBe(0)
|
||||
|
||||
const panel1 = new Panel({item: new TestPanelContainerItem()}, atom.views)
|
||||
const panel1 = new Panel(
|
||||
{ item: new TestPanelContainerItem() },
|
||||
atom.views
|
||||
)
|
||||
container.addPanel(panel1)
|
||||
expect(element.childNodes.length).toBe(1)
|
||||
expect(element.childNodes[0]).toHaveClass('left')
|
||||
@@ -76,7 +89,10 @@ describe('PanelContainerElement', () => {
|
||||
|
||||
expect(element.childNodes[0].tagName).toBe('ATOM-PANEL')
|
||||
|
||||
const panel2 = new Panel({item: new TestPanelContainerItem()}, atom.views)
|
||||
const panel2 = new Panel(
|
||||
{ item: new TestPanelContainerItem() },
|
||||
atom.views
|
||||
)
|
||||
container.addPanel(panel2)
|
||||
expect(element.childNodes.length).toBe(2)
|
||||
|
||||
@@ -88,12 +104,14 @@ describe('PanelContainerElement', () => {
|
||||
|
||||
panel2.destroy()
|
||||
expect(element.childNodes.length).toBe(0)
|
||||
})
|
||||
)
|
||||
}))
|
||||
|
||||
describe('when the container is at the bottom location', () => {
|
||||
beforeEach(() => {
|
||||
container = new PanelContainer({viewRegistry: atom.views, location: 'bottom'})
|
||||
container = new PanelContainer({
|
||||
viewRegistry: atom.views,
|
||||
location: 'bottom'
|
||||
})
|
||||
element = container.getElement()
|
||||
jasmineContent.appendChild(element)
|
||||
})
|
||||
@@ -101,7 +119,10 @@ describe('PanelContainerElement', () => {
|
||||
it('adds atom-panel elements when a new panel is added to the container; removes them when the panels are destroyed', () => {
|
||||
expect(element.childNodes.length).toBe(0)
|
||||
|
||||
const panel1 = new Panel({item: new TestPanelContainerItem(), className: 'one'}, atom.views)
|
||||
const panel1 = new Panel(
|
||||
{ item: new TestPanelContainerItem(), className: 'one' },
|
||||
atom.views
|
||||
)
|
||||
container.addPanel(panel1)
|
||||
expect(element.childNodes.length).toBe(1)
|
||||
expect(element.childNodes[0]).toHaveClass('bottom')
|
||||
@@ -110,7 +131,10 @@ describe('PanelContainerElement', () => {
|
||||
expect(element.childNodes[0].tagName).toBe('ATOM-PANEL')
|
||||
expect(panel1.getElement()).toHaveClass('one')
|
||||
|
||||
const panel2 = new Panel({item: new TestPanelContainerItem(), className: 'two'}, atom.views)
|
||||
const panel2 = new Panel(
|
||||
{ item: new TestPanelContainerItem(), className: 'two' },
|
||||
atom.views
|
||||
)
|
||||
container.addPanel(panel2)
|
||||
expect(element.childNodes.length).toBe(2)
|
||||
expect(panel2.getElement()).toHaveClass('two')
|
||||
@@ -126,18 +150,27 @@ describe('PanelContainerElement', () => {
|
||||
|
||||
describe('when the container is modal', () => {
|
||||
beforeEach(() => {
|
||||
container = new PanelContainer({viewRegistry: atom.views, location: 'modal'})
|
||||
container = new PanelContainer({
|
||||
viewRegistry: atom.views,
|
||||
location: 'modal'
|
||||
})
|
||||
element = container.getElement()
|
||||
jasmineContent.appendChild(element)
|
||||
})
|
||||
|
||||
it('allows only one panel to be visible at a time', () => {
|
||||
const panel1 = new Panel({item: new TestPanelContainerItem()}, atom.views)
|
||||
const panel1 = new Panel(
|
||||
{ item: new TestPanelContainerItem() },
|
||||
atom.views
|
||||
)
|
||||
container.addPanel(panel1)
|
||||
|
||||
expect(panel1.getElement().style.display).not.toBe('none')
|
||||
|
||||
const panel2 = new Panel({item: new TestPanelContainerItem()}, atom.views)
|
||||
const panel2 = new Panel(
|
||||
{ item: new TestPanelContainerItem() },
|
||||
atom.views
|
||||
)
|
||||
container.addPanel(panel2)
|
||||
|
||||
expect(panel1.getElement().style.display).toBe('none')
|
||||
@@ -150,7 +183,10 @@ describe('PanelContainerElement', () => {
|
||||
})
|
||||
|
||||
it("adds the 'modal' class to panels", () => {
|
||||
const panel1 = new Panel({item: new TestPanelContainerItem()}, atom.views)
|
||||
const panel1 = new Panel(
|
||||
{ item: new TestPanelContainerItem() },
|
||||
atom.views
|
||||
)
|
||||
container.addPanel(panel1)
|
||||
|
||||
expect(panel1.getElement()).toHaveClass('modal')
|
||||
@@ -161,8 +197,8 @@ describe('PanelContainerElement', () => {
|
||||
expect(panel1.getElement()).toHaveClass('from-top')
|
||||
})
|
||||
|
||||
describe("autoFocus", () => {
|
||||
function createPanel() {
|
||||
describe('autoFocus', () => {
|
||||
function createPanel () {
|
||||
const panel = new Panel(
|
||||
{
|
||||
item: new TestPanelContainerItem(),
|
||||
@@ -176,7 +212,7 @@ describe('PanelContainerElement', () => {
|
||||
return panel
|
||||
}
|
||||
|
||||
it("focuses the first tabbable item if available", () => {
|
||||
it('focuses the first tabbable item if available', () => {
|
||||
const panel = createPanel()
|
||||
const panelEl = panel.getElement()
|
||||
const inputEl = document.createElement('input')
|
||||
@@ -188,7 +224,7 @@ describe('PanelContainerElement', () => {
|
||||
expect(document.activeElement).toBe(inputEl)
|
||||
})
|
||||
|
||||
it("focuses the entire panel item when no tabbable item is available and the panel is focusable", () => {
|
||||
it('focuses the entire panel item when no tabbable item is available and the panel is focusable', () => {
|
||||
const panel = createPanel()
|
||||
const panelEl = panel.getElement()
|
||||
|
||||
@@ -197,7 +233,7 @@ describe('PanelContainerElement', () => {
|
||||
expect(panelEl.focus).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it("returns focus to the original activeElement", () => {
|
||||
it('returns focus to the original activeElement', () => {
|
||||
const panel = createPanel()
|
||||
const previousActiveElement = document.activeElement
|
||||
const panelEl = panel.getElement()
|
||||
|
||||
@@ -6,11 +6,10 @@ const PanelContainer = require('../src/panel-container')
|
||||
describe('PanelContainer', () => {
|
||||
let container
|
||||
|
||||
class TestPanelItem {
|
||||
}
|
||||
class TestPanelItem {}
|
||||
|
||||
beforeEach(() => {
|
||||
container = new PanelContainer({viewRegistry: atom.views})
|
||||
container = new PanelContainer({ viewRegistry: atom.views })
|
||||
})
|
||||
|
||||
describe('::addPanel(panel)', () => {
|
||||
@@ -18,13 +17,13 @@ describe('PanelContainer', () => {
|
||||
const addPanelSpy = jasmine.createSpy()
|
||||
container.onDidAddPanel(addPanelSpy)
|
||||
|
||||
const panel1 = new Panel({item: new TestPanelItem()}, atom.views)
|
||||
const panel1 = new Panel({ item: new TestPanelItem() }, atom.views)
|
||||
container.addPanel(panel1)
|
||||
expect(addPanelSpy).toHaveBeenCalledWith({panel: panel1, index: 0})
|
||||
expect(addPanelSpy).toHaveBeenCalledWith({ panel: panel1, index: 0 })
|
||||
|
||||
const panel2 = new Panel({item: new TestPanelItem()}, atom.views)
|
||||
const panel2 = new Panel({ item: new TestPanelItem() }, atom.views)
|
||||
container.addPanel(panel2)
|
||||
expect(addPanelSpy).toHaveBeenCalledWith({panel: panel2, index: 1})
|
||||
expect(addPanelSpy).toHaveBeenCalledWith({ panel: panel2, index: 1 })
|
||||
})
|
||||
})
|
||||
|
||||
@@ -33,18 +32,18 @@ describe('PanelContainer', () => {
|
||||
const removePanelSpy = jasmine.createSpy()
|
||||
container.onDidRemovePanel(removePanelSpy)
|
||||
|
||||
const panel1 = new Panel({item: new TestPanelItem()}, atom.views)
|
||||
const panel1 = new Panel({ item: new TestPanelItem() }, atom.views)
|
||||
container.addPanel(panel1)
|
||||
const panel2 = new Panel({item: new TestPanelItem()}, atom.views)
|
||||
const panel2 = new Panel({ item: new TestPanelItem() }, atom.views)
|
||||
container.addPanel(panel2)
|
||||
|
||||
expect(removePanelSpy).not.toHaveBeenCalled()
|
||||
|
||||
panel2.destroy()
|
||||
expect(removePanelSpy).toHaveBeenCalledWith({panel: panel2, index: 1})
|
||||
expect(removePanelSpy).toHaveBeenCalledWith({ panel: panel2, index: 1 })
|
||||
|
||||
panel1.destroy()
|
||||
expect(removePanelSpy).toHaveBeenCalledWith({panel: panel1, index: 0})
|
||||
expect(removePanelSpy).toHaveBeenCalledWith({ panel: panel1, index: 0 })
|
||||
})
|
||||
})
|
||||
|
||||
@@ -52,12 +51,16 @@ describe('PanelContainer', () => {
|
||||
it('destroys the container and all of its panels', () => {
|
||||
const destroyedPanels = []
|
||||
|
||||
const panel1 = new Panel({item: new TestPanelItem()}, atom.views)
|
||||
panel1.onDidDestroy(() => { destroyedPanels.push(panel1) })
|
||||
const panel1 = new Panel({ item: new TestPanelItem() }, atom.views)
|
||||
panel1.onDidDestroy(() => {
|
||||
destroyedPanels.push(panel1)
|
||||
})
|
||||
container.addPanel(panel1)
|
||||
|
||||
const panel2 = new Panel({item: new TestPanelItem()}, atom.views)
|
||||
panel2.onDidDestroy(() => { destroyedPanels.push(panel2) })
|
||||
const panel2 = new Panel({ item: new TestPanelItem() }, atom.views)
|
||||
panel2.onDidDestroy(() => {
|
||||
destroyedPanels.push(panel2)
|
||||
})
|
||||
container.addPanel(panel2)
|
||||
|
||||
container.destroy()
|
||||
@@ -72,8 +75,8 @@ describe('PanelContainer', () => {
|
||||
let initialPanel
|
||||
beforeEach(() => {
|
||||
// 'left' logic is the same as 'top'
|
||||
container = new PanelContainer({location: 'left'})
|
||||
initialPanel = new Panel({item: new TestPanelItem()}, atom.views)
|
||||
container = new PanelContainer({ location: 'left' })
|
||||
initialPanel = new Panel({ item: new TestPanelItem() }, atom.views)
|
||||
container.addPanel(initialPanel)
|
||||
})
|
||||
|
||||
@@ -81,10 +84,13 @@ describe('PanelContainer', () => {
|
||||
it('is inserted at the beginning of the list', () => {
|
||||
const addPanelSpy = jasmine.createSpy()
|
||||
container.onDidAddPanel(addPanelSpy)
|
||||
const panel = new Panel({item: new TestPanelItem(), priority: 0}, atom.views)
|
||||
const panel = new Panel(
|
||||
{ item: new TestPanelItem(), priority: 0 },
|
||||
atom.views
|
||||
)
|
||||
container.addPanel(panel)
|
||||
|
||||
expect(addPanelSpy).toHaveBeenCalledWith({panel, index: 0})
|
||||
expect(addPanelSpy).toHaveBeenCalledWith({ panel, index: 0 })
|
||||
expect(container.getPanels()[0]).toBe(panel)
|
||||
})
|
||||
})
|
||||
@@ -92,14 +98,20 @@ describe('PanelContainer', () => {
|
||||
describe('when a panel with priority between two other panels is added', () => {
|
||||
it('is inserted at the between the two panels', () => {
|
||||
const addPanelSpy = jasmine.createSpy()
|
||||
let panel = new Panel({item: new TestPanelItem(), priority: 1000}, atom.views)
|
||||
let panel = new Panel(
|
||||
{ item: new TestPanelItem(), priority: 1000 },
|
||||
atom.views
|
||||
)
|
||||
container.addPanel(panel)
|
||||
|
||||
container.onDidAddPanel(addPanelSpy)
|
||||
panel = new Panel({item: new TestPanelItem(), priority: 101}, atom.views)
|
||||
panel = new Panel(
|
||||
{ item: new TestPanelItem(), priority: 101 },
|
||||
atom.views
|
||||
)
|
||||
container.addPanel(panel)
|
||||
|
||||
expect(addPanelSpy).toHaveBeenCalledWith({panel, index: 1})
|
||||
expect(addPanelSpy).toHaveBeenCalledWith({ panel, index: 1 })
|
||||
expect(container.getPanels()[1]).toBe(panel)
|
||||
})
|
||||
})
|
||||
@@ -109,8 +121,8 @@ describe('PanelContainer', () => {
|
||||
let initialPanel
|
||||
beforeEach(() => {
|
||||
// 'bottom' logic is the same as 'right'
|
||||
container = new PanelContainer({location: 'right'})
|
||||
initialPanel = new Panel({item: new TestPanelItem()}, atom.views)
|
||||
container = new PanelContainer({ location: 'right' })
|
||||
initialPanel = new Panel({ item: new TestPanelItem() }, atom.views)
|
||||
container.addPanel(initialPanel)
|
||||
})
|
||||
|
||||
@@ -118,10 +130,13 @@ describe('PanelContainer', () => {
|
||||
it('is inserted at the beginning of the list', () => {
|
||||
const addPanelSpy = jasmine.createSpy()
|
||||
container.onDidAddPanel(addPanelSpy)
|
||||
const panel = new Panel({item: new TestPanelItem(), priority: 1000}, atom.views)
|
||||
const panel = new Panel(
|
||||
{ item: new TestPanelItem(), priority: 1000 },
|
||||
atom.views
|
||||
)
|
||||
container.addPanel(panel)
|
||||
|
||||
expect(addPanelSpy).toHaveBeenCalledWith({panel, index: 0})
|
||||
expect(addPanelSpy).toHaveBeenCalledWith({ panel, index: 0 })
|
||||
expect(container.getPanels()[0]).toBe(panel)
|
||||
})
|
||||
})
|
||||
@@ -130,10 +145,13 @@ describe('PanelContainer', () => {
|
||||
it('is inserted at the end of the list', () => {
|
||||
const addPanelSpy = jasmine.createSpy()
|
||||
container.onDidAddPanel(addPanelSpy)
|
||||
const panel = new Panel({item: new TestPanelItem(), priority: 0}, atom.views)
|
||||
const panel = new Panel(
|
||||
{ item: new TestPanelItem(), priority: 0 },
|
||||
atom.views
|
||||
)
|
||||
container.addPanel(panel)
|
||||
|
||||
expect(addPanelSpy).toHaveBeenCalledWith({panel, index: 1})
|
||||
expect(addPanelSpy).toHaveBeenCalledWith({ panel, index: 1 })
|
||||
expect(container.getPanels()[1]).toBe(panel)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -12,8 +12,8 @@ describe('Panel', () => {
|
||||
}
|
||||
}
|
||||
|
||||
it('adds the item\'s element as a child of the panel', () => {
|
||||
const panel = new Panel({item: new TestPanelItem()}, atom.views)
|
||||
it("adds the item's element as a child of the panel", () => {
|
||||
const panel = new Panel({ item: new TestPanelItem() }, atom.views)
|
||||
const element = panel.getElement()
|
||||
expect(element.tagName.toLowerCase()).toBe('atom-panel')
|
||||
expect(element.firstChild).toBe(panel.getItem().getElement())
|
||||
@@ -21,7 +21,7 @@ describe('Panel', () => {
|
||||
|
||||
describe('destroying the panel', () => {
|
||||
it('removes the element when the panel is destroyed', () => {
|
||||
const panel = new Panel({item: new TestPanelItem()}, atom.views)
|
||||
const panel = new Panel({ item: new TestPanelItem() }, atom.views)
|
||||
const element = panel.getElement()
|
||||
const jasmineContent = document.getElementById('jasmine-content')
|
||||
jasmineContent.appendChild(element)
|
||||
@@ -33,7 +33,7 @@ describe('Panel', () => {
|
||||
|
||||
it('does not try to remove the element twice', () => {
|
||||
const item = new TestPanelItem()
|
||||
const panel = new Panel({item}, atom.views)
|
||||
const panel = new Panel({ item }, atom.views)
|
||||
const element = panel.getElement()
|
||||
const jasmineContent = document.getElementById('jasmine-content')
|
||||
jasmineContent.appendChild(element)
|
||||
@@ -52,7 +52,7 @@ describe('Panel', () => {
|
||||
|
||||
describe('changing panel visibility', () => {
|
||||
it('notifies observers added with onDidChangeVisible', () => {
|
||||
const panel = new Panel({item: new TestPanelItem()}, atom.views)
|
||||
const panel = new Panel({ item: new TestPanelItem() }, atom.views)
|
||||
|
||||
const spy = jasmine.createSpy()
|
||||
panel.onDidChangeVisible(spy)
|
||||
@@ -72,13 +72,16 @@ describe('Panel', () => {
|
||||
})
|
||||
|
||||
it('initially renders panel created with visible: false', () => {
|
||||
const panel = new Panel({visible: false, item: new TestPanelItem()}, atom.views)
|
||||
const panel = new Panel(
|
||||
{ visible: false, item: new TestPanelItem() },
|
||||
atom.views
|
||||
)
|
||||
const element = panel.getElement()
|
||||
expect(element.style.display).toBe('none')
|
||||
})
|
||||
|
||||
it('hides and shows the panel element when Panel::hide() and Panel::show() are called', () => {
|
||||
const panel = new Panel({item: new TestPanelItem()}, atom.views)
|
||||
const panel = new Panel({ item: new TestPanelItem() }, atom.views)
|
||||
const element = panel.getElement()
|
||||
expect(element.style.display).not.toBe('none')
|
||||
|
||||
@@ -92,7 +95,10 @@ describe('Panel', () => {
|
||||
|
||||
describe('when a class name is specified', () => {
|
||||
it('initially renders panel created with visible: false', () => {
|
||||
const panel = new Panel({className: 'some classes', item: new TestPanelItem()}, atom.views)
|
||||
const panel = new Panel(
|
||||
{ className: 'some classes', item: new TestPanelItem() },
|
||||
atom.views
|
||||
)
|
||||
const element = panel.getElement()
|
||||
|
||||
expect(element).toHaveClass('some')
|
||||
@@ -102,7 +108,7 @@ describe('Panel', () => {
|
||||
|
||||
describe('creating an atom-panel via markup', () => {
|
||||
it('does not throw an error', () => {
|
||||
const element = document.createElement('atom-panel')
|
||||
document.createElement('atom-panel')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,16 +1,22 @@
|
||||
/** @babel */
|
||||
|
||||
import {it, beforeEach, afterEach, promisifySome} from './async-spec-helpers'
|
||||
import { it, beforeEach, afterEach, promisifySome } from './async-spec-helpers'
|
||||
import tempCb from 'temp'
|
||||
import fsCb from 'fs-plus'
|
||||
import path from 'path'
|
||||
|
||||
import {CompositeDisposable} from 'event-kit'
|
||||
import {watchPath, stopAllWatchers} from '../src/path-watcher'
|
||||
import { CompositeDisposable } from 'event-kit'
|
||||
import { watchPath, stopAllWatchers } from '../src/path-watcher'
|
||||
|
||||
tempCb.track()
|
||||
|
||||
const fs = promisifySome(fsCb, ['writeFile', 'mkdir', 'symlink', 'appendFile', 'realpath'])
|
||||
const fs = promisifySome(fsCb, [
|
||||
'writeFile',
|
||||
'mkdir',
|
||||
'symlink',
|
||||
'appendFile',
|
||||
'realpath'
|
||||
])
|
||||
const temp = promisifySome(tempCb, ['mkdir'])
|
||||
|
||||
describe('watchPath', function () {
|
||||
@@ -105,16 +111,18 @@ describe('watchPath', function () {
|
||||
waitForChanges(rootWatcher, subFile),
|
||||
waitForChanges(childWatcher, subFile)
|
||||
])
|
||||
await fs.writeFile(subFile, 'subfile\n', {encoding: 'utf8'})
|
||||
await fs.writeFile(subFile, 'subfile\n', { encoding: 'utf8' })
|
||||
await firstChanges
|
||||
|
||||
const nextRootEvent = waitForChanges(rootWatcher, rootFile)
|
||||
await fs.writeFile(rootFile, 'rootfile\n', {encoding: 'utf8'})
|
||||
await fs.writeFile(rootFile, 'rootfile\n', { encoding: 'utf8' })
|
||||
await nextRootEvent
|
||||
})
|
||||
|
||||
it('adopts existing child watchers and filters events appropriately to them', async function () {
|
||||
const parentDir = await temp.mkdir('atom-fsmanager-test-').then(fs.realpath)
|
||||
const parentDir = await temp
|
||||
.mkdir('atom-fsmanager-test-')
|
||||
.then(fs.realpath)
|
||||
|
||||
// Create the directory tree
|
||||
const rootFile = path.join(parentDir, 'rootfile.txt')
|
||||
@@ -126,9 +134,9 @@ describe('watchPath', function () {
|
||||
await fs.mkdir(subDir0)
|
||||
await fs.mkdir(subDir1)
|
||||
await Promise.all([
|
||||
fs.writeFile(rootFile, 'rootfile\n', {encoding: 'utf8'}),
|
||||
fs.writeFile(subFile0, 'subfile 0\n', {encoding: 'utf8'}),
|
||||
fs.writeFile(subFile1, 'subfile 1\n', {encoding: 'utf8'})
|
||||
fs.writeFile(rootFile, 'rootfile\n', { encoding: 'utf8' }),
|
||||
fs.writeFile(subFile0, 'subfile 0\n', { encoding: 'utf8' }),
|
||||
fs.writeFile(subFile1, 'subfile 1\n', { encoding: 'utf8' })
|
||||
])
|
||||
|
||||
// Begin the child watchers and keep them alive
|
||||
@@ -142,16 +150,21 @@ describe('watchPath', function () {
|
||||
|
||||
// Create the parent watcher
|
||||
const parentWatcher = await watchPath(parentDir, {}, () => {})
|
||||
const parentWatcherChanges = waitForChanges(parentWatcher, rootFile, subFile0, subFile1)
|
||||
const parentWatcherChanges = waitForChanges(
|
||||
parentWatcher,
|
||||
rootFile,
|
||||
subFile0,
|
||||
subFile1
|
||||
)
|
||||
|
||||
expect(subWatcher0.native).toBe(parentWatcher.native)
|
||||
expect(subWatcher1.native).toBe(parentWatcher.native)
|
||||
|
||||
// Ensure events are filtered correctly
|
||||
await Promise.all([
|
||||
fs.appendFile(rootFile, 'change\n', {encoding: 'utf8'}),
|
||||
fs.appendFile(subFile0, 'change\n', {encoding: 'utf8'}),
|
||||
fs.appendFile(subFile1, 'change\n', {encoding: 'utf8'})
|
||||
fs.appendFile(rootFile, 'change\n', { encoding: 'utf8' }),
|
||||
fs.appendFile(subFile0, 'change\n', { encoding: 'utf8' }),
|
||||
fs.appendFile(subFile1, 'change\n', { encoding: 'utf8' })
|
||||
])
|
||||
|
||||
await Promise.all([
|
||||
|
||||
@@ -3,8 +3,8 @@ const TextBuffer = require('text-buffer')
|
||||
const Project = require('../src/project')
|
||||
const fs = require('fs-plus')
|
||||
const path = require('path')
|
||||
const {Directory} = require('pathwatcher')
|
||||
const {stopAllWatchers} = require('../src/path-watcher')
|
||||
const { Directory } = require('pathwatcher')
|
||||
const { stopAllWatchers } = require('../src/path-watcher')
|
||||
const GitRepository = require('../src/git-repository')
|
||||
|
||||
describe('Project', () => {
|
||||
@@ -46,13 +46,16 @@ describe('Project', () => {
|
||||
|
||||
let err = null
|
||||
waitsForPromise(() =>
|
||||
deserializedProject.deserialize(state, atom.deserializers)
|
||||
.catch(e => { err = e })
|
||||
deserializedProject.deserialize(state, atom.deserializers).catch(e => {
|
||||
err = e
|
||||
})
|
||||
)
|
||||
|
||||
runs(() => {
|
||||
expect(deserializedProject.getPaths()).toEqual(atom.project.getPaths())
|
||||
expect(err.missingProjectPaths).toEqual(['/directory/that/does/not/exist'])
|
||||
expect(err.missingProjectPaths).toEqual([
|
||||
'/directory/that/does/not/exist'
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
@@ -74,8 +77,9 @@ describe('Project', () => {
|
||||
|
||||
let err = null
|
||||
waitsForPromise(() =>
|
||||
deserializedProject.deserialize(state, atom.deserializers)
|
||||
.catch(e => { err = e })
|
||||
deserializedProject.deserialize(state, atom.deserializers).catch(e => {
|
||||
err = e
|
||||
})
|
||||
)
|
||||
|
||||
runs(() => {
|
||||
@@ -98,7 +102,11 @@ describe('Project', () => {
|
||||
})
|
||||
})
|
||||
|
||||
waitsForPromise(() => deserializedProject.deserialize(atom.project.serialize({isUnloading: false})))
|
||||
waitsForPromise(() =>
|
||||
deserializedProject.deserialize(
|
||||
atom.project.serialize({ isUnloading: false })
|
||||
)
|
||||
)
|
||||
|
||||
runs(() => expect(deserializedProject.getBuffers().length).toBe(0))
|
||||
})
|
||||
@@ -116,7 +124,11 @@ describe('Project', () => {
|
||||
})
|
||||
})
|
||||
|
||||
waitsForPromise(() => deserializedProject.deserialize(atom.project.serialize({isUnloading: false})))
|
||||
waitsForPromise(() =>
|
||||
deserializedProject.deserialize(
|
||||
atom.project.serialize({ isUnloading: false })
|
||||
)
|
||||
)
|
||||
|
||||
runs(() => {
|
||||
expect(deserializedProject.getBuffers().length).toBe(1)
|
||||
@@ -126,7 +138,10 @@ describe('Project', () => {
|
||||
})
|
||||
|
||||
it('does not deserialize buffers when their path is now a directory', () => {
|
||||
const pathToOpen = path.join(temp.mkdirSync('atom-spec-project'), 'file.txt')
|
||||
const pathToOpen = path.join(
|
||||
temp.mkdirSync('atom-spec-project'),
|
||||
'file.txt'
|
||||
)
|
||||
|
||||
waitsForPromise(() => atom.workspace.open(pathToOpen))
|
||||
|
||||
@@ -141,14 +156,23 @@ describe('Project', () => {
|
||||
})
|
||||
})
|
||||
|
||||
waitsForPromise(() => deserializedProject.deserialize(atom.project.serialize({isUnloading: false})))
|
||||
waitsForPromise(() =>
|
||||
deserializedProject.deserialize(
|
||||
atom.project.serialize({ isUnloading: false })
|
||||
)
|
||||
)
|
||||
|
||||
runs(() => expect(deserializedProject.getBuffers().length).toBe(0))
|
||||
})
|
||||
|
||||
it('does not deserialize buffers when their path is inaccessible', () => {
|
||||
if (process.platform === 'win32') { return } // chmod not supported on win32
|
||||
const pathToOpen = path.join(temp.mkdirSync('atom-spec-project'), 'file.txt')
|
||||
if (process.platform === 'win32') {
|
||||
return
|
||||
} // chmod not supported on win32
|
||||
const pathToOpen = path.join(
|
||||
temp.mkdirSync('atom-spec-project'),
|
||||
'file.txt'
|
||||
)
|
||||
fs.writeFileSync(pathToOpen, '')
|
||||
|
||||
waitsForPromise(() => atom.workspace.open(pathToOpen))
|
||||
@@ -164,13 +188,20 @@ describe('Project', () => {
|
||||
})
|
||||
})
|
||||
|
||||
waitsForPromise(() => deserializedProject.deserialize(atom.project.serialize({isUnloading: false})))
|
||||
waitsForPromise(() =>
|
||||
deserializedProject.deserialize(
|
||||
atom.project.serialize({ isUnloading: false })
|
||||
)
|
||||
)
|
||||
|
||||
runs(() => expect(deserializedProject.getBuffers().length).toBe(0))
|
||||
})
|
||||
|
||||
it('does not deserialize buffers with their path is no longer present', () => {
|
||||
const pathToOpen = path.join(temp.mkdirSync('atom-spec-project'), 'file.txt')
|
||||
const pathToOpen = path.join(
|
||||
temp.mkdirSync('atom-spec-project'),
|
||||
'file.txt'
|
||||
)
|
||||
fs.writeFileSync(pathToOpen, '')
|
||||
|
||||
waitsForPromise(() => atom.workspace.open(pathToOpen))
|
||||
@@ -186,13 +217,20 @@ describe('Project', () => {
|
||||
})
|
||||
})
|
||||
|
||||
waitsForPromise(() => deserializedProject.deserialize(atom.project.serialize({isUnloading: false})))
|
||||
waitsForPromise(() =>
|
||||
deserializedProject.deserialize(
|
||||
atom.project.serialize({ isUnloading: false })
|
||||
)
|
||||
)
|
||||
|
||||
runs(() => expect(deserializedProject.getBuffers().length).toBe(0))
|
||||
})
|
||||
|
||||
it('deserializes buffers that have never been saved before', () => {
|
||||
const pathToOpen = path.join(temp.mkdirSync('atom-spec-project'), 'file.txt')
|
||||
const pathToOpen = path.join(
|
||||
temp.mkdirSync('atom-spec-project'),
|
||||
'file.txt'
|
||||
)
|
||||
|
||||
waitsForPromise(() => atom.workspace.open(pathToOpen))
|
||||
|
||||
@@ -208,7 +246,11 @@ describe('Project', () => {
|
||||
})
|
||||
})
|
||||
|
||||
waitsForPromise(() => deserializedProject.deserialize(atom.project.serialize({isUnloading: false})))
|
||||
waitsForPromise(() =>
|
||||
deserializedProject.deserialize(
|
||||
atom.project.serialize({ isUnloading: false })
|
||||
)
|
||||
)
|
||||
|
||||
runs(() => {
|
||||
expect(deserializedProject.getBuffers().length).toBe(1)
|
||||
@@ -226,7 +268,7 @@ describe('Project', () => {
|
||||
|
||||
runs(() => {
|
||||
bufferA = atom.project.getBuffers()[0]
|
||||
layerA = bufferA.addMarkerLayer({persistent: true})
|
||||
layerA = bufferA.addMarkerLayer({ persistent: true })
|
||||
markerA = layerA.markPosition([0, 3])
|
||||
bufferA.append('!')
|
||||
notQuittingProject = new Project({
|
||||
@@ -237,10 +279,17 @@ describe('Project', () => {
|
||||
})
|
||||
})
|
||||
|
||||
waitsForPromise(() => notQuittingProject.deserialize(atom.project.serialize({isUnloading: false})))
|
||||
waitsForPromise(() =>
|
||||
notQuittingProject.deserialize(
|
||||
atom.project.serialize({ isUnloading: false })
|
||||
)
|
||||
)
|
||||
|
||||
runs(() => {
|
||||
expect(notQuittingProject.getBuffers()[0].getMarkerLayer(layerA.id), x => x.getMarker(markerA.id)).toBeUndefined()
|
||||
expect(
|
||||
notQuittingProject.getBuffers()[0].getMarkerLayer(layerA.id),
|
||||
x => x.getMarker(markerA.id)
|
||||
).toBeUndefined()
|
||||
expect(notQuittingProject.getBuffers()[0].undo()).toBe(false)
|
||||
quittingProject = new Project({
|
||||
notificationManager: atom.notifications,
|
||||
@@ -250,10 +299,16 @@ describe('Project', () => {
|
||||
})
|
||||
})
|
||||
|
||||
waitsForPromise(() => quittingProject.deserialize(atom.project.serialize({isUnloading: true})))
|
||||
waitsForPromise(() =>
|
||||
quittingProject.deserialize(
|
||||
atom.project.serialize({ isUnloading: true })
|
||||
)
|
||||
)
|
||||
|
||||
runs(() => {
|
||||
expect(quittingProject.getBuffers()[0].getMarkerLayer(layerA.id), x => x.getMarker(markerA.id)).not.toBeUndefined()
|
||||
expect(quittingProject.getBuffers()[0].getMarkerLayer(layerA.id), x =>
|
||||
x.getMarker(markerA.id)
|
||||
).not.toBeUndefined()
|
||||
expect(quittingProject.getBuffers()[0].undo()).toBe(true)
|
||||
})
|
||||
})
|
||||
@@ -266,11 +321,17 @@ describe('Project', () => {
|
||||
expect(atom.project.getPaths()[0]).toBeUndefined()
|
||||
let editor = null
|
||||
|
||||
waitsForPromise(() => atom.workspace.open().then(o => { editor = o }))
|
||||
waitsForPromise(() =>
|
||||
atom.workspace.open().then(o => {
|
||||
editor = o
|
||||
})
|
||||
)
|
||||
|
||||
waitsForPromise(() => editor.saveAs(tempFile))
|
||||
|
||||
runs(() => expect(atom.project.getPaths()[0]).toBe(path.dirname(tempFile)))
|
||||
runs(() =>
|
||||
expect(atom.project.getPaths()[0]).toBe(path.dirname(tempFile))
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -284,7 +345,7 @@ describe('Project', () => {
|
||||
paths: [projectPath1, projectPath2],
|
||||
originPath: 'originPath',
|
||||
config: {
|
||||
'baz': 'buzz'
|
||||
baz: 'buzz'
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -323,10 +384,12 @@ describe('Project', () => {
|
||||
let buffer
|
||||
beforeEach(() =>
|
||||
waitsForPromise(() =>
|
||||
atom.project.bufferForPath(path.join(__dirname, 'fixtures', 'sample.js')).then((o) => {
|
||||
buffer = o
|
||||
buffer.retain()
|
||||
})
|
||||
atom.project
|
||||
.bufferForPath(path.join(__dirname, 'fixtures', 'sample.js'))
|
||||
.then(o => {
|
||||
buffer = o
|
||||
buffer.retain()
|
||||
})
|
||||
)
|
||||
)
|
||||
|
||||
@@ -339,10 +402,18 @@ describe('Project', () => {
|
||||
waitsForPromise(() => buffer.save())
|
||||
|
||||
runs(() => {
|
||||
expect(atom.project.applicationDelegate.emitDidSavePath.calls.length).toBe(1)
|
||||
expect(atom.project.applicationDelegate.emitDidSavePath).toHaveBeenCalledWith(buffer.getPath())
|
||||
expect(atom.project.applicationDelegate.emitWillSavePath.calls.length).toBe(1)
|
||||
expect(atom.project.applicationDelegate.emitWillSavePath).toHaveBeenCalledWith(buffer.getPath())
|
||||
expect(
|
||||
atom.project.applicationDelegate.emitDidSavePath.calls.length
|
||||
).toBe(1)
|
||||
expect(
|
||||
atom.project.applicationDelegate.emitDidSavePath
|
||||
).toHaveBeenCalledWith(buffer.getPath())
|
||||
expect(
|
||||
atom.project.applicationDelegate.emitWillSavePath.calls.length
|
||||
).toBe(1)
|
||||
expect(
|
||||
atom.project.applicationDelegate.emitWillSavePath
|
||||
).toHaveBeenCalledWith(buffer.getPath())
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -350,20 +421,23 @@ describe('Project', () => {
|
||||
describe('when a watch error is thrown from the TextBuffer', () => {
|
||||
let editor = null
|
||||
beforeEach(() =>
|
||||
waitsForPromise(() => atom.workspace.open(require.resolve('./fixtures/dir/a')).then(o => { editor = o }))
|
||||
waitsForPromise(() =>
|
||||
atom.workspace.open(require.resolve('./fixtures/dir/a')).then(o => {
|
||||
editor = o
|
||||
})
|
||||
)
|
||||
)
|
||||
|
||||
it('creates a warning notification', () => {
|
||||
let noteSpy
|
||||
atom.notifications.onDidAddNotification(noteSpy = jasmine.createSpy())
|
||||
atom.notifications.onDidAddNotification((noteSpy = jasmine.createSpy()))
|
||||
|
||||
const error = new Error('SomeError')
|
||||
error.eventType = 'resurrect'
|
||||
editor.buffer.emitter.emit('will-throw-watch-error', {
|
||||
handle: jasmine.createSpy(),
|
||||
error
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
expect(noteSpy).toHaveBeenCalled()
|
||||
|
||||
@@ -371,7 +445,9 @@ describe('Project', () => {
|
||||
expect(notification.getType()).toBe('warning')
|
||||
expect(notification.getDetail()).toBe('SomeError')
|
||||
expect(notification.getMessage()).toContain('`resurrect`')
|
||||
expect(notification.getMessage()).toContain(path.join('fixtures', 'dir', 'a'))
|
||||
expect(notification.getMessage()).toContain(
|
||||
path.join('fixtures', 'dir', 'a')
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -379,10 +455,18 @@ describe('Project', () => {
|
||||
let fakeRepositoryProvider, fakeRepository
|
||||
|
||||
beforeEach(() => {
|
||||
fakeRepository = {destroy () { return null }}
|
||||
fakeRepository = {
|
||||
destroy () {
|
||||
return null
|
||||
}
|
||||
}
|
||||
fakeRepositoryProvider = {
|
||||
repositoryForDirectory (directory) { return Promise.resolve(fakeRepository) },
|
||||
repositoryForDirectorySync (directory) { return fakeRepository }
|
||||
repositoryForDirectory (directory) {
|
||||
return Promise.resolve(fakeRepository)
|
||||
},
|
||||
repositoryForDirectorySync (directory) {
|
||||
return fakeRepository
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -391,7 +475,11 @@ describe('Project', () => {
|
||||
atom.project.setPaths([projectPath])
|
||||
expect(atom.project.getRepositories()).toEqual([null])
|
||||
|
||||
atom.packages.serviceHub.provide('atom.repository-provider', '0.1.0', fakeRepositoryProvider)
|
||||
atom.packages.serviceHub.provide(
|
||||
'atom.repository-provider',
|
||||
'0.1.0',
|
||||
fakeRepositoryProvider
|
||||
)
|
||||
waitsFor(() => atom.project.repositoryProviders.length > 1)
|
||||
runs(() => atom.project.getRepositories()[0] === fakeRepository)
|
||||
})
|
||||
@@ -401,7 +489,11 @@ describe('Project', () => {
|
||||
expect(repositories.length).toEqual(1)
|
||||
expect(repositories[0]).toBeTruthy()
|
||||
|
||||
atom.packages.serviceHub.provide('atom.repository-provider', '0.1.0', fakeRepositoryProvider)
|
||||
atom.packages.serviceHub.provide(
|
||||
'atom.repository-provider',
|
||||
'0.1.0',
|
||||
fakeRepositoryProvider
|
||||
)
|
||||
waitsFor(() => atom.project.repositoryProviders.length > 1)
|
||||
runs(() => expect(atom.project.getRepositories()).toBe(repositories))
|
||||
})
|
||||
@@ -409,7 +501,11 @@ describe('Project', () => {
|
||||
it('stops using it to create repositories when the service is removed', () => {
|
||||
atom.project.setPaths([])
|
||||
|
||||
const disposable = atom.packages.serviceHub.provide('atom.repository-provider', '0.1.0', fakeRepositoryProvider)
|
||||
const disposable = atom.packages.serviceHub.provide(
|
||||
'atom.repository-provider',
|
||||
'0.1.0',
|
||||
fakeRepositoryProvider
|
||||
)
|
||||
waitsFor(() => atom.project.repositoryProviders.length > 1)
|
||||
runs(() => {
|
||||
disposable.dispose()
|
||||
@@ -424,15 +520,35 @@ describe('Project', () => {
|
||||
constructor (aPath) {
|
||||
this.path = aPath
|
||||
}
|
||||
getPath () { return this.path }
|
||||
getFile () { return {existsSync () { return false }} }
|
||||
getSubdirectory () { return {existsSync () { return false }} }
|
||||
isRoot () { return true }
|
||||
existsSync () { return this.path.endsWith('does-exist') }
|
||||
contains (filePath) { return filePath.startsWith(this.path) }
|
||||
getPath () {
|
||||
return this.path
|
||||
}
|
||||
getFile () {
|
||||
return {
|
||||
existsSync () {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
getSubdirectory () {
|
||||
return {
|
||||
existsSync () {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
isRoot () {
|
||||
return true
|
||||
}
|
||||
existsSync () {
|
||||
return this.path.endsWith('does-exist')
|
||||
}
|
||||
contains (filePath) {
|
||||
return filePath.startsWith(this.path)
|
||||
}
|
||||
onDidChangeFiles (callback) {
|
||||
onDidChangeFilesCallback = callback
|
||||
return {dispose: () => {}}
|
||||
return { dispose: () => {} }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -440,15 +556,19 @@ describe('Project', () => {
|
||||
let onDidChangeFilesCallback = null
|
||||
|
||||
beforeEach(() => {
|
||||
serviceDisposable = atom.packages.serviceHub.provide('atom.directory-provider', '0.1.0', {
|
||||
directoryForURISync (uri) {
|
||||
if (uri.startsWith('ssh://')) {
|
||||
return new DummyDirectory(uri)
|
||||
} else {
|
||||
return null
|
||||
serviceDisposable = atom.packages.serviceHub.provide(
|
||||
'atom.directory-provider',
|
||||
'0.1.0',
|
||||
{
|
||||
directoryForURISync (uri) {
|
||||
if (uri.startsWith('ssh://')) {
|
||||
return new DummyDirectory(uri)
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
onDidChangeFilesCallback = null
|
||||
|
||||
waitsFor(() => atom.project.directoryProviders.length > 0)
|
||||
@@ -467,7 +587,8 @@ describe('Project', () => {
|
||||
expect(directories[1] instanceof DummyDirectory).toBe(true)
|
||||
|
||||
// It does not add new remote paths that do not exist
|
||||
const nonExistentRemotePath = 'ssh://another-directory:8080/does-not-exist'
|
||||
const nonExistentRemotePath =
|
||||
'ssh://another-directory:8080/does-not-exist'
|
||||
atom.project.addPath(nonExistentRemotePath)
|
||||
expect(atom.project.getDirectories().length).toBe(2)
|
||||
|
||||
@@ -499,7 +620,7 @@ describe('Project', () => {
|
||||
const changeSpy = jasmine.createSpy('atom.project.onDidChangeFiles')
|
||||
const disposable = atom.project.onDidChangeFiles(changeSpy)
|
||||
|
||||
const events = [{action: 'created', path: remotePath + '/test.txt'}]
|
||||
const events = [{ action: 'created', path: remotePath + '/test.txt' }]
|
||||
onDidChangeFilesCallback(events)
|
||||
|
||||
expect(changeSpy).toHaveBeenCalledWith(events)
|
||||
@@ -520,7 +641,11 @@ describe('Project', () => {
|
||||
describe("when given an absolute path that isn't currently open", () => {
|
||||
it("returns a new edit session for the given path and emits 'buffer-created'", () => {
|
||||
let editor = null
|
||||
waitsForPromise(() => atom.workspace.open(absolutePath).then(o => { editor = o }))
|
||||
waitsForPromise(() =>
|
||||
atom.workspace.open(absolutePath).then(o => {
|
||||
editor = o
|
||||
})
|
||||
)
|
||||
|
||||
runs(() => {
|
||||
expect(editor.buffer.getPath()).toBe(absolutePath)
|
||||
@@ -532,7 +657,11 @@ describe('Project', () => {
|
||||
describe("when given a relative path that isn't currently opened", () => {
|
||||
it("returns a new edit session for the given path (relative to the project root) and emits 'buffer-created'", () => {
|
||||
let editor = null
|
||||
waitsForPromise(() => atom.workspace.open(absolutePath).then(o => { editor = o }))
|
||||
waitsForPromise(() =>
|
||||
atom.workspace.open(absolutePath).then(o => {
|
||||
editor = o
|
||||
})
|
||||
)
|
||||
|
||||
runs(() => {
|
||||
expect(editor.buffer.getPath()).toBe(absolutePath)
|
||||
@@ -545,16 +674,22 @@ describe('Project', () => {
|
||||
it('returns a new edit session containing currently opened buffer', () => {
|
||||
let editor = null
|
||||
|
||||
waitsForPromise(() => atom.workspace.open(absolutePath).then(o => { editor = o }))
|
||||
waitsForPromise(() =>
|
||||
atom.workspace.open(absolutePath).then(o => {
|
||||
editor = o
|
||||
})
|
||||
)
|
||||
|
||||
runs(() => newBufferHandler.reset())
|
||||
|
||||
waitsForPromise(() =>
|
||||
atom.workspace.open(absolutePath).then(({buffer}) => expect(buffer).toBe(editor.buffer))
|
||||
atom.workspace
|
||||
.open(absolutePath)
|
||||
.then(({ buffer }) => expect(buffer).toBe(editor.buffer))
|
||||
)
|
||||
|
||||
waitsForPromise(() =>
|
||||
atom.workspace.open('a').then(({buffer}) => {
|
||||
atom.workspace.open('a').then(({ buffer }) => {
|
||||
expect(buffer).toBe(editor.buffer)
|
||||
expect(newBufferHandler).not.toHaveBeenCalled()
|
||||
})
|
||||
@@ -565,7 +700,11 @@ describe('Project', () => {
|
||||
describe('when not passed a path', () => {
|
||||
it("returns a new edit session and emits 'buffer-created'", () => {
|
||||
let editor = null
|
||||
waitsForPromise(() => atom.workspace.open().then(o => { editor = o }))
|
||||
waitsForPromise(() =>
|
||||
atom.workspace.open().then(o => {
|
||||
editor = o
|
||||
})
|
||||
)
|
||||
|
||||
runs(() => {
|
||||
expect(editor.buffer.getPath()).toBeUndefined()
|
||||
@@ -580,7 +719,7 @@ describe('Project', () => {
|
||||
|
||||
beforeEach(() =>
|
||||
waitsForPromise(() =>
|
||||
atom.project.bufferForPath('a').then((o) => {
|
||||
atom.project.bufferForPath('a').then(o => {
|
||||
buffer = o
|
||||
buffer.retain()
|
||||
})
|
||||
@@ -592,11 +731,15 @@ describe('Project', () => {
|
||||
describe('when opening a previously opened path', () => {
|
||||
it('does not create a new buffer', () => {
|
||||
waitsForPromise(() =>
|
||||
atom.project.bufferForPath('a').then(anotherBuffer => expect(anotherBuffer).toBe(buffer))
|
||||
atom.project
|
||||
.bufferForPath('a')
|
||||
.then(anotherBuffer => expect(anotherBuffer).toBe(buffer))
|
||||
)
|
||||
|
||||
waitsForPromise(() =>
|
||||
atom.project.bufferForPath('b').then(anotherBuffer => expect(anotherBuffer).not.toBe(buffer))
|
||||
atom.project
|
||||
.bufferForPath('b')
|
||||
.then(anotherBuffer => expect(anotherBuffer).not.toBe(buffer))
|
||||
)
|
||||
|
||||
waitsForPromise(() =>
|
||||
@@ -610,12 +753,14 @@ describe('Project', () => {
|
||||
})
|
||||
|
||||
it('retries loading the buffer if it previously failed', () => {
|
||||
waitsForPromise({shouldReject: true}, () => {
|
||||
spyOn(TextBuffer, 'load').andCallFake(() => Promise.reject(new Error('Could not open file')))
|
||||
waitsForPromise({ shouldReject: true }, () => {
|
||||
spyOn(TextBuffer, 'load').andCallFake(() =>
|
||||
Promise.reject(new Error('Could not open file'))
|
||||
)
|
||||
return atom.project.bufferForPath('b')
|
||||
})
|
||||
|
||||
waitsForPromise({shouldReject: false}, () => {
|
||||
waitsForPromise({ shouldReject: false }, () => {
|
||||
TextBuffer.load.andCallThrough()
|
||||
return atom.project.bufferForPath('b')
|
||||
})
|
||||
@@ -625,7 +770,9 @@ describe('Project', () => {
|
||||
buffer.release()
|
||||
|
||||
waitsForPromise(() =>
|
||||
atom.project.bufferForPath('b').then(anotherBuffer => expect(anotherBuffer).not.toBe(buffer))
|
||||
atom.project
|
||||
.bufferForPath('b')
|
||||
.then(anotherBuffer => expect(anotherBuffer).not.toBe(buffer))
|
||||
)
|
||||
})
|
||||
})
|
||||
@@ -635,7 +782,7 @@ describe('Project', () => {
|
||||
it('resolves to null when the directory does not have a repository', () => {
|
||||
waitsForPromise(() => {
|
||||
const directory = new Directory('/tmp')
|
||||
return atom.project.repositoryForDirectory(directory).then((result) => {
|
||||
return atom.project.repositoryForDirectory(directory).then(result => {
|
||||
expect(result).toBeNull()
|
||||
expect(atom.project.repositoryProviders.length).toBeGreaterThan(0)
|
||||
expect(atom.project.repositoryPromisesByPath.size).toBe(0)
|
||||
@@ -647,7 +794,7 @@ describe('Project', () => {
|
||||
waitsForPromise(() => {
|
||||
const directory = new Directory(path.join(__dirname, '..'))
|
||||
const promise = atom.project.repositoryForDirectory(directory)
|
||||
return promise.then((result) => {
|
||||
return promise.then(result => {
|
||||
expect(result).toBeInstanceOf(GitRepository)
|
||||
const dirPath = directory.getRealPathSync()
|
||||
expect(result.getPath()).toBe(path.join(dirPath, '.git'))
|
||||
@@ -662,7 +809,11 @@ describe('Project', () => {
|
||||
let repository = null
|
||||
const directory = new Directory(path.join(__dirname, '..'))
|
||||
|
||||
waitsForPromise(() => atom.project.repositoryForDirectory(directory).then(repo => { repository = repo }))
|
||||
waitsForPromise(() =>
|
||||
atom.project.repositoryForDirectory(directory).then(repo => {
|
||||
repository = repo
|
||||
})
|
||||
)
|
||||
|
||||
runs(() => {
|
||||
expect(repository.isDestroyed()).toBe(false)
|
||||
@@ -670,7 +821,11 @@ describe('Project', () => {
|
||||
expect(repository.isDestroyed()).toBe(true)
|
||||
})
|
||||
|
||||
waitsForPromise(() => atom.project.repositoryForDirectory(directory).then(repo => { repository = repo }))
|
||||
waitsForPromise(() =>
|
||||
atom.project.repositoryForDirectory(directory).then(repo => {
|
||||
repository = repo
|
||||
})
|
||||
)
|
||||
|
||||
runs(() => expect(repository.isDestroyed()).toBe(false))
|
||||
})
|
||||
@@ -682,7 +837,9 @@ describe('Project', () => {
|
||||
const filePath = require.resolve('./fixtures/dir/a')
|
||||
atom.project.setPaths([filePath])
|
||||
expect(atom.project.getPaths()[0]).toEqual(path.dirname(filePath))
|
||||
expect(atom.project.getDirectories()[0].path).toEqual(path.dirname(filePath))
|
||||
expect(atom.project.getDirectories()[0].path).toEqual(
|
||||
path.dirname(filePath)
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -692,7 +849,9 @@ describe('Project', () => {
|
||||
const directory2 = temp.mkdirSync('git-repo1')
|
||||
const directory3 = temp.mkdirSync('git-repo2')
|
||||
|
||||
const gitDirPath = fs.absolute(path.join(__dirname, 'fixtures', 'git', 'master.git'))
|
||||
const gitDirPath = fs.absolute(
|
||||
path.join(__dirname, 'fixtures', 'git', 'master.git')
|
||||
)
|
||||
fs.copySync(gitDirPath, path.join(directory2, '.git'))
|
||||
fs.copySync(gitDirPath, path.join(directory3, '.git'))
|
||||
|
||||
@@ -701,16 +860,20 @@ describe('Project', () => {
|
||||
const [repo1, repo2, repo3] = atom.project.getRepositories()
|
||||
expect(repo1).toBeNull()
|
||||
expect(repo2.getShortHead()).toBe('master')
|
||||
expect(repo2.getPath()).toBe(fs.realpathSync(path.join(directory2, '.git')))
|
||||
expect(repo2.getPath()).toBe(
|
||||
fs.realpathSync(path.join(directory2, '.git'))
|
||||
)
|
||||
expect(repo3.getShortHead()).toBe('master')
|
||||
expect(repo3.getPath()).toBe(fs.realpathSync(path.join(directory3, '.git')))
|
||||
expect(repo3.getPath()).toBe(
|
||||
fs.realpathSync(path.join(directory3, '.git'))
|
||||
)
|
||||
})
|
||||
|
||||
it('calls callbacks registered with ::onDidChangePaths', () => {
|
||||
const onDidChangePathsSpy = jasmine.createSpy('onDidChangePaths spy')
|
||||
atom.project.onDidChangePaths(onDidChangePathsSpy)
|
||||
|
||||
const paths = [ temp.mkdirSync('dir1'), temp.mkdirSync('dir2') ]
|
||||
const paths = [temp.mkdirSync('dir1'), temp.mkdirSync('dir2')]
|
||||
atom.project.setPaths(paths)
|
||||
|
||||
expect(onDidChangePathsSpy.callCount).toBe(1)
|
||||
@@ -718,10 +881,15 @@ describe('Project', () => {
|
||||
})
|
||||
|
||||
it('optionally throws an error with any paths that did not exist', () => {
|
||||
const paths = [temp.mkdirSync('exists0'), '/doesnt-exists/0', temp.mkdirSync('exists1'), '/doesnt-exists/1']
|
||||
const paths = [
|
||||
temp.mkdirSync('exists0'),
|
||||
'/doesnt-exists/0',
|
||||
temp.mkdirSync('exists1'),
|
||||
'/doesnt-exists/1'
|
||||
]
|
||||
|
||||
try {
|
||||
atom.project.setPaths(paths, {mustExist: true})
|
||||
atom.project.setPaths(paths, { mustExist: true })
|
||||
expect('no exception thrown').toBeUndefined()
|
||||
} catch (e) {
|
||||
expect(e.missingProjectPaths).toEqual([paths[1], paths[3]])
|
||||
@@ -740,9 +908,17 @@ describe('Project', () => {
|
||||
})
|
||||
|
||||
it('normalizes the path to remove consecutive slashes, ., and .. segments', () => {
|
||||
atom.project.setPaths([`${require.resolve('./fixtures/dir/a')}${path.sep}b${path.sep}${path.sep}..`])
|
||||
expect(atom.project.getPaths()[0]).toEqual(path.dirname(require.resolve('./fixtures/dir/a')))
|
||||
expect(atom.project.getDirectories()[0].path).toEqual(path.dirname(require.resolve('./fixtures/dir/a')))
|
||||
atom.project.setPaths([
|
||||
`${require.resolve('./fixtures/dir/a')}${path.sep}b${path.sep}${
|
||||
path.sep
|
||||
}..`
|
||||
])
|
||||
expect(atom.project.getPaths()[0]).toEqual(
|
||||
path.dirname(require.resolve('./fixtures/dir/a'))
|
||||
)
|
||||
expect(atom.project.getDirectories()[0].path).toEqual(
|
||||
path.dirname(require.resolve('./fixtures/dir/a'))
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -757,7 +933,10 @@ describe('Project', () => {
|
||||
atom.project.addPath(newPath)
|
||||
|
||||
expect(onDidChangePathsSpy.callCount).toBe(1)
|
||||
expect(onDidChangePathsSpy.mostRecentCall.args[0]).toEqual([oldPath, newPath])
|
||||
expect(onDidChangePathsSpy.mostRecentCall.args[0]).toEqual([
|
||||
oldPath,
|
||||
newPath
|
||||
])
|
||||
})
|
||||
|
||||
it("doesn't add redundant paths", () => {
|
||||
@@ -789,7 +968,11 @@ describe('Project', () => {
|
||||
})
|
||||
|
||||
it('optionally throws on non-existent directories', () => {
|
||||
expect(() => atom.project.addPath('/this-definitely/does-not-exist', {mustExist: true})).toThrow()
|
||||
expect(() =>
|
||||
atom.project.addPath('/this-definitely/does-not-exist', {
|
||||
mustExist: true
|
||||
})
|
||||
).toThrow()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -821,7 +1004,9 @@ describe('Project', () => {
|
||||
it("doesn't destroy the repository if it is shared by another root directory", () => {
|
||||
atom.project.setPaths([__dirname, path.join(__dirname, '..', 'src')])
|
||||
atom.project.removePath(__dirname)
|
||||
expect(atom.project.getPaths()).toEqual([path.join(__dirname, '..', 'src')])
|
||||
expect(atom.project.getPaths()).toEqual([
|
||||
path.join(__dirname, '..', 'src')
|
||||
])
|
||||
expect(atom.project.getRepositories()[0].isSubmodule('src')).toBe(false)
|
||||
})
|
||||
|
||||
@@ -829,10 +1014,18 @@ describe('Project', () => {
|
||||
atom.packages.serviceHub.provide('atom.directory-provider', '0.1.0', {
|
||||
directoryForURISync (uri) {
|
||||
return {
|
||||
getPath () { return uri },
|
||||
getSubdirectory () { return {} },
|
||||
isRoot () { return true },
|
||||
existsSync () { return true },
|
||||
getPath () {
|
||||
return uri
|
||||
},
|
||||
getSubdirectory () {
|
||||
return {}
|
||||
},
|
||||
isRoot () {
|
||||
return true
|
||||
},
|
||||
existsSync () {
|
||||
return true
|
||||
},
|
||||
off () {}
|
||||
}
|
||||
}
|
||||
@@ -854,7 +1047,7 @@ describe('Project', () => {
|
||||
let checkCallback = () => {}
|
||||
|
||||
beforeEach(() => {
|
||||
sub = atom.project.onDidChangeFiles((incoming) => {
|
||||
sub = atom.project.onDidChangeFiles(incoming => {
|
||||
events.push(...incoming)
|
||||
checkCallback()
|
||||
})
|
||||
@@ -862,18 +1055,24 @@ describe('Project', () => {
|
||||
|
||||
afterEach(() => sub.dispose())
|
||||
|
||||
const waitForEvents = (paths) => {
|
||||
const remaining = new Set(paths.map((p) => fs.realpathSync(p)))
|
||||
const waitForEvents = paths => {
|
||||
const remaining = new Set(paths.map(p => fs.realpathSync(p)))
|
||||
return new Promise((resolve, reject) => {
|
||||
checkCallback = () => {
|
||||
for (let event of events) { remaining.delete(event.path) }
|
||||
if (remaining.size === 0) { resolve() }
|
||||
for (let event of events) {
|
||||
remaining.delete(event.path)
|
||||
}
|
||||
if (remaining.size === 0) {
|
||||
resolve()
|
||||
}
|
||||
}
|
||||
|
||||
const expire = () => {
|
||||
checkCallback = () => {}
|
||||
console.error('Paths not seen:', remaining)
|
||||
reject(new Error('Expired before all expected events were delivered.'))
|
||||
reject(
|
||||
new Error('Expired before all expected events were delivered.')
|
||||
)
|
||||
}
|
||||
|
||||
checkCallback()
|
||||
@@ -904,7 +1103,9 @@ describe('Project', () => {
|
||||
|
||||
waitsForPromise(() => waitForEvents([fileOne, fileTwo]))
|
||||
|
||||
runs(() => expect(events.some(event => event.path === fileThree)).toBeFalsy())
|
||||
runs(() =>
|
||||
expect(events.some(event => event.path === fileThree)).toBeFalsy()
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -914,7 +1115,8 @@ describe('Project', () => {
|
||||
const added = []
|
||||
|
||||
waitsForPromise(() =>
|
||||
atom.project.buildBuffer(require.resolve('./fixtures/dir/a'))
|
||||
atom.project
|
||||
.buildBuffer(require.resolve('./fixtures/dir/a'))
|
||||
.then(o => buffers.push(o))
|
||||
)
|
||||
|
||||
@@ -924,7 +1126,8 @@ describe('Project', () => {
|
||||
})
|
||||
|
||||
waitsForPromise(() =>
|
||||
atom.project.buildBuffer(require.resolve('./fixtures/dir/b'))
|
||||
atom.project
|
||||
.buildBuffer(require.resolve('./fixtures/dir/b'))
|
||||
.then(o => buffers.push(o))
|
||||
)
|
||||
|
||||
@@ -941,12 +1144,14 @@ describe('Project', () => {
|
||||
const observed = []
|
||||
|
||||
waitsForPromise(() =>
|
||||
atom.project.buildBuffer(require.resolve('./fixtures/dir/a'))
|
||||
atom.project
|
||||
.buildBuffer(require.resolve('./fixtures/dir/a'))
|
||||
.then(o => buffers.push(o))
|
||||
)
|
||||
|
||||
waitsForPromise(() =>
|
||||
atom.project.buildBuffer(require.resolve('./fixtures/dir/b'))
|
||||
atom.project
|
||||
.buildBuffer(require.resolve('./fixtures/dir/b'))
|
||||
.then(o => buffers.push(o))
|
||||
)
|
||||
|
||||
@@ -957,7 +1162,8 @@ describe('Project', () => {
|
||||
})
|
||||
|
||||
waitsForPromise(() =>
|
||||
atom.project.buildBuffer(require.resolve('./fixtures/dir/b'))
|
||||
atom.project
|
||||
.buildBuffer(require.resolve('./fixtures/dir/b'))
|
||||
.then(o => buffers.push(o))
|
||||
)
|
||||
|
||||
@@ -974,22 +1180,38 @@ describe('Project', () => {
|
||||
const observed = []
|
||||
|
||||
const directory1 = temp.mkdirSync('git-repo1')
|
||||
const gitDirPath1 = fs.absolute(path.join(__dirname, 'fixtures', 'git', 'master.git'))
|
||||
const gitDirPath1 = fs.absolute(
|
||||
path.join(__dirname, 'fixtures', 'git', 'master.git')
|
||||
)
|
||||
fs.copySync(gitDirPath1, path.join(directory1, '.git'))
|
||||
|
||||
const directory2 = temp.mkdirSync('git-repo2')
|
||||
const gitDirPath2 = fs.absolute(path.join(__dirname, 'fixtures', 'git', 'repo-with-submodules', 'git.git'))
|
||||
const gitDirPath2 = fs.absolute(
|
||||
path.join(
|
||||
__dirname,
|
||||
'fixtures',
|
||||
'git',
|
||||
'repo-with-submodules',
|
||||
'git.git'
|
||||
)
|
||||
)
|
||||
fs.copySync(gitDirPath2, path.join(directory2, '.git'))
|
||||
|
||||
atom.project.setPaths([directory1])
|
||||
|
||||
const disposable = atom.project.observeRepositories((repo) => observed.push(repo))
|
||||
const disposable = atom.project.observeRepositories(repo =>
|
||||
observed.push(repo)
|
||||
)
|
||||
expect(observed.length).toBe(1)
|
||||
expect(observed[0].getReferenceTarget('refs/heads/master')).toBe('ef046e9eecaa5255ea5e9817132d4001724d6ae1')
|
||||
expect(observed[0].getReferenceTarget('refs/heads/master')).toBe(
|
||||
'ef046e9eecaa5255ea5e9817132d4001724d6ae1'
|
||||
)
|
||||
|
||||
atom.project.addPath(directory2)
|
||||
expect(observed.length).toBe(2)
|
||||
expect(observed[1].getReferenceTarget('refs/heads/master')).toBe('d2b0ad9cbc6f6c4372e8956e5cc5af771b2342e5')
|
||||
expect(observed[1].getReferenceTarget('refs/heads/master')).toBe(
|
||||
'd2b0ad9cbc6f6c4372e8956e5cc5af771b2342e5'
|
||||
)
|
||||
|
||||
disposable.dispose()
|
||||
})
|
||||
@@ -998,25 +1220,35 @@ describe('Project', () => {
|
||||
describe('.onDidAddRepository()', () => {
|
||||
it('invokes callback when a path is added and the path is the root of a repository', () => {
|
||||
const observed = []
|
||||
const disposable = atom.project.onDidAddRepository((repo) => observed.push(repo))
|
||||
const disposable = atom.project.onDidAddRepository(repo =>
|
||||
observed.push(repo)
|
||||
)
|
||||
|
||||
const projectRootPath = temp.mkdirSync()
|
||||
const fixtureRepoPath = fs.absolute(path.join(__dirname, 'fixtures', 'git', 'master.git'))
|
||||
const fixtureRepoPath = fs.absolute(
|
||||
path.join(__dirname, 'fixtures', 'git', 'master.git')
|
||||
)
|
||||
fs.copySync(fixtureRepoPath, path.join(projectRootPath, '.git'))
|
||||
|
||||
atom.project.addPath(projectRootPath)
|
||||
expect(observed.length).toBe(1)
|
||||
expect(observed[0].getOriginURL()).toEqual('https://github.com/example-user/example-repo.git')
|
||||
expect(observed[0].getOriginURL()).toEqual(
|
||||
'https://github.com/example-user/example-repo.git'
|
||||
)
|
||||
|
||||
disposable.dispose()
|
||||
})
|
||||
|
||||
it('invokes callback when a path is added and the path is subdirectory of a repository', () => {
|
||||
const observed = []
|
||||
const disposable = atom.project.onDidAddRepository((repo) => observed.push(repo))
|
||||
const disposable = atom.project.onDidAddRepository(repo =>
|
||||
observed.push(repo)
|
||||
)
|
||||
|
||||
const projectRootPath = temp.mkdirSync()
|
||||
const fixtureRepoPath = fs.absolute(path.join(__dirname, 'fixtures', 'git', 'master.git'))
|
||||
const fixtureRepoPath = fs.absolute(
|
||||
path.join(__dirname, 'fixtures', 'git', 'master.git')
|
||||
)
|
||||
fs.copySync(fixtureRepoPath, path.join(projectRootPath, '.git'))
|
||||
|
||||
const projectSubDirPath = path.join(projectRootPath, 'sub-dir')
|
||||
@@ -1024,14 +1256,18 @@ describe('Project', () => {
|
||||
|
||||
atom.project.addPath(projectSubDirPath)
|
||||
expect(observed.length).toBe(1)
|
||||
expect(observed[0].getOriginURL()).toEqual('https://github.com/example-user/example-repo.git')
|
||||
expect(observed[0].getOriginURL()).toEqual(
|
||||
'https://github.com/example-user/example-repo.git'
|
||||
)
|
||||
|
||||
disposable.dispose()
|
||||
})
|
||||
|
||||
it('does not invoke callback when a path is added and the path is not part of a repository', () => {
|
||||
const observed = []
|
||||
const disposable = atom.project.onDidAddRepository((repo) => observed.push(repo))
|
||||
const disposable = atom.project.onDidAddRepository(repo =>
|
||||
observed.push(repo)
|
||||
)
|
||||
|
||||
atom.project.addPath(temp.mkdirSync('not-a-repository'))
|
||||
expect(observed.length).toBe(0)
|
||||
@@ -1046,11 +1282,15 @@ describe('Project', () => {
|
||||
|
||||
let rootPath = atom.project.getPaths()[0]
|
||||
let childPath = path.join(rootPath, 'some', 'child', 'directory')
|
||||
expect(atom.project.relativize(childPath)).toBe(path.join('some', 'child', 'directory'))
|
||||
expect(atom.project.relativize(childPath)).toBe(
|
||||
path.join('some', 'child', 'directory')
|
||||
)
|
||||
|
||||
rootPath = atom.project.getPaths()[1]
|
||||
childPath = path.join(rootPath, 'some', 'child', 'directory')
|
||||
expect(atom.project.relativize(childPath)).toBe(path.join('some', 'child', 'directory'))
|
||||
expect(atom.project.relativize(childPath)).toBe(
|
||||
path.join('some', 'child', 'directory')
|
||||
)
|
||||
})
|
||||
|
||||
it('returns the given path if it is not in any of the root directories', () => {
|
||||
@@ -1065,17 +1305,26 @@ describe('Project', () => {
|
||||
|
||||
let rootPath = atom.project.getPaths()[0]
|
||||
let childPath = path.join(rootPath, 'some', 'child', 'directory')
|
||||
expect(atom.project.relativizePath(childPath)).toEqual([rootPath, path.join('some', 'child', 'directory')])
|
||||
expect(atom.project.relativizePath(childPath)).toEqual([
|
||||
rootPath,
|
||||
path.join('some', 'child', 'directory')
|
||||
])
|
||||
|
||||
rootPath = atom.project.getPaths()[1]
|
||||
childPath = path.join(rootPath, 'some', 'child', 'directory')
|
||||
expect(atom.project.relativizePath(childPath)).toEqual([rootPath, path.join('some', 'child', 'directory')])
|
||||
expect(atom.project.relativizePath(childPath)).toEqual([
|
||||
rootPath,
|
||||
path.join('some', 'child', 'directory')
|
||||
])
|
||||
})
|
||||
|
||||
describe("when the given path isn't inside of any of the project's path", () => {
|
||||
it('returns null for the root path, and the given path unchanged', () => {
|
||||
const randomPath = path.join('some', 'random', 'path')
|
||||
expect(atom.project.relativizePath(randomPath)).toEqual([null, randomPath])
|
||||
expect(atom.project.relativizePath(randomPath)).toEqual([
|
||||
null,
|
||||
randomPath
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1090,7 +1339,10 @@ describe('Project', () => {
|
||||
it('uses the root folder that is closest to the given path', () => {
|
||||
atom.project.addPath(path.join(atom.project.getPaths()[0], 'a-dir'))
|
||||
|
||||
const inputPath = path.join(atom.project.getPaths()[1], 'somewhere/something.txt')
|
||||
const inputPath = path.join(
|
||||
atom.project.getPaths()[1],
|
||||
'somewhere/something.txt'
|
||||
)
|
||||
|
||||
expect(atom.project.getDirectories()[0].contains(inputPath)).toBe(true)
|
||||
expect(atom.project.getDirectories()[1].contains(inputPath)).toBe(true)
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
/** @babel */
|
||||
|
||||
import {it, fit, ffit, fffit, beforeEach, afterEach} from './async-spec-helpers'
|
||||
import {Emitter, Disposable, CompositeDisposable} from 'event-kit'
|
||||
import { it, beforeEach } from './async-spec-helpers'
|
||||
import { Disposable } from 'event-kit'
|
||||
|
||||
const ReopenProjectMenuManager = require('../src/reopen-project-menu-manager')
|
||||
|
||||
numberRange = (low, high) => {
|
||||
function numberRange (low, high) {
|
||||
const size = high - low
|
||||
const result = new Array(size)
|
||||
for (var i = 0; i < size; i++)
|
||||
result[i] = low + i
|
||||
for (var i = 0; i < size; i++) result[i] = low + i
|
||||
return result
|
||||
}
|
||||
|
||||
describe("ReopenProjectMenuManager", () => {
|
||||
describe('ReopenProjectMenuManager', () => {
|
||||
let menuManager, commandRegistry, config, historyManager, reopenProjects
|
||||
let commandDisposable, configDisposable, historyDisposable
|
||||
let openFunction
|
||||
|
||||
beforeEach(() => {
|
||||
menuManager = jasmine.createSpyObj('MenuManager', ['add'])
|
||||
@@ -28,43 +28,54 @@ describe("ReopenProjectMenuManager", () => {
|
||||
config = jasmine.createSpyObj('Config', ['onDidChange', 'get'])
|
||||
config.get.andReturn(10)
|
||||
configDisposable = jasmine.createSpyObj('Disposable', ['dispose'])
|
||||
config.didChangeListener = { }
|
||||
config.didChangeListener = {}
|
||||
config.onDidChange.andCallFake((key, fn) => {
|
||||
config.didChangeListener[key] = fn
|
||||
return configDisposable
|
||||
})
|
||||
|
||||
historyManager = jasmine.createSpyObj('historyManager', ['getProjects','onDidChangeProjects'])
|
||||
historyManager = jasmine.createSpyObj('historyManager', [
|
||||
'getProjects',
|
||||
'onDidChangeProjects'
|
||||
])
|
||||
historyManager.getProjects.andReturn([])
|
||||
historyDisposable = jasmine.createSpyObj('Disposable', ['dispose'])
|
||||
historyManager.onDidChangeProjects.andCallFake((fn) => {
|
||||
historyManager.onDidChangeProjects.andCallFake(fn => {
|
||||
historyManager.changeProjectsListener = fn
|
||||
return historyDisposable
|
||||
})
|
||||
|
||||
openFunction = jasmine.createSpy()
|
||||
reopenProjects = new ReopenProjectMenuManager({menu:menuManager, commands: commandRegistry, history: historyManager, config, open:openFunction})
|
||||
reopenProjects = new ReopenProjectMenuManager({
|
||||
menu: menuManager,
|
||||
commands: commandRegistry,
|
||||
history: historyManager,
|
||||
config,
|
||||
open: openFunction
|
||||
})
|
||||
})
|
||||
|
||||
describe("constructor", () => {
|
||||
describe('constructor', () => {
|
||||
it("registers the 'reopen-project' command function", () => {
|
||||
expect(commandRegistry.add).toHaveBeenCalled()
|
||||
const cmdCall = commandRegistry.add.calls[0]
|
||||
expect(cmdCall.args.length).toBe(2)
|
||||
expect(cmdCall.args[0]).toBe('atom-workspace')
|
||||
expect(typeof cmdCall.args[1]['application:reopen-project']).toBe('function')
|
||||
expect(typeof cmdCall.args[1]['application:reopen-project']).toBe(
|
||||
'function'
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe("dispose", () => {
|
||||
it("disposes of the history, command and config disposables", () => {
|
||||
describe('dispose', () => {
|
||||
it('disposes of the history, command and config disposables', () => {
|
||||
reopenProjects.dispose()
|
||||
expect(historyDisposable.dispose).toHaveBeenCalled()
|
||||
expect(configDisposable.dispose).toHaveBeenCalled()
|
||||
expect(commandDisposable.dispose).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it("disposes of the menu disposable once used", () => {
|
||||
it('disposes of the menu disposable once used', () => {
|
||||
const menuDisposable = jasmine.createSpyObj('Disposable', ['dispose'])
|
||||
menuManager.add.andReturn(menuDisposable)
|
||||
reopenProjects.update()
|
||||
@@ -74,36 +85,45 @@ describe("ReopenProjectMenuManager", () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe("the command", () => {
|
||||
it("calls open with the paths of the project specified by the detail index", () => {
|
||||
historyManager.getProjects.andReturn([ { paths: ['/a'] }, { paths: ['/b', 'c:\\'] }])
|
||||
describe('the command', () => {
|
||||
it('calls open with the paths of the project specified by the detail index', () => {
|
||||
historyManager.getProjects.andReturn([
|
||||
{ paths: ['/a'] },
|
||||
{ paths: ['/b', 'c:\\'] }
|
||||
])
|
||||
reopenProjects.update()
|
||||
|
||||
reopenProjectCommand = commandRegistry.add.calls[0].args[1]['application:reopen-project']
|
||||
const reopenProjectCommand =
|
||||
commandRegistry.add.calls[0].args[1]['application:reopen-project']
|
||||
reopenProjectCommand({ detail: { index: 1 } })
|
||||
|
||||
expect(openFunction).toHaveBeenCalled()
|
||||
expect(openFunction.calls[0].args[0]).toEqual(['/b', 'c:\\'])
|
||||
})
|
||||
|
||||
it("does not call open when no command detail is supplied", () => {
|
||||
reopenProjectCommand = commandRegistry.add.calls[0].args[1]['application:reopen-project']
|
||||
it('does not call open when no command detail is supplied', () => {
|
||||
const reopenProjectCommand =
|
||||
commandRegistry.add.calls[0].args[1]['application:reopen-project']
|
||||
reopenProjectCommand({})
|
||||
|
||||
expect(openFunction).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it("does not call open when no command detail index is supplied", () => {
|
||||
reopenProjectCommand = commandRegistry.add.calls[0].args[1]['application:reopen-project']
|
||||
it('does not call open when no command detail index is supplied', () => {
|
||||
const reopenProjectCommand =
|
||||
commandRegistry.add.calls[0].args[1]['application:reopen-project']
|
||||
reopenProjectCommand({ detail: { anything: 'here' } })
|
||||
|
||||
expect(openFunction).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
||||
describe("update", () => {
|
||||
it("adds menu items to MenuManager based on projects from HistoryManager", () => {
|
||||
historyManager.getProjects.andReturn([ { paths: ['/a'] }, { paths: ['/b', 'c:\\'] }])
|
||||
describe('update', () => {
|
||||
it('adds menu items to MenuManager based on projects from HistoryManager', () => {
|
||||
historyManager.getProjects.andReturn([
|
||||
{ paths: ['/a'] },
|
||||
{ paths: ['/b', 'c:\\'] }
|
||||
])
|
||||
reopenProjects.update()
|
||||
expect(historyManager.getProjects).toHaveBeenCalled()
|
||||
expect(menuManager.add).toHaveBeenCalled()
|
||||
@@ -127,7 +147,9 @@ describe("ReopenProjectMenuManager", () => {
|
||||
})
|
||||
|
||||
it("adds only the number of menu items specified in the 'core.reopenProjectMenuCount' config", () => {
|
||||
historyManager.getProjects.andReturn(numberRange(1, 100).map(i => ({ paths: [ '/test/' + i ] })))
|
||||
historyManager.getProjects.andReturn(
|
||||
numberRange(1, 100).map(i => ({ paths: ['/test/' + i] }))
|
||||
)
|
||||
reopenProjects.update()
|
||||
expect(menuManager.add).toHaveBeenCalled()
|
||||
const menu = menuManager.add.calls[0].args[0][0]
|
||||
@@ -137,7 +159,7 @@ describe("ReopenProjectMenuManager", () => {
|
||||
expect(menu.submenu[0].submenu.length).toBe(10)
|
||||
})
|
||||
|
||||
it("disposes the previously menu built", () => {
|
||||
it('disposes the previously menu built', () => {
|
||||
const menuDisposable = jasmine.createSpyObj('Disposable', ['dispose'])
|
||||
menuManager.add.andReturn(menuDisposable)
|
||||
reopenProjects.update()
|
||||
@@ -147,10 +169,15 @@ describe("ReopenProjectMenuManager", () => {
|
||||
})
|
||||
|
||||
it("is called when the Config changes for 'core.reopenProjectMenuCount'", () => {
|
||||
historyManager.getProjects.andReturn(numberRange(1, 100).map(i => ({ paths: [ '/test/' + i ] })))
|
||||
historyManager.getProjects.andReturn(
|
||||
numberRange(1, 100).map(i => ({ paths: ['/test/' + i] }))
|
||||
)
|
||||
reopenProjects.update()
|
||||
config.get.andReturn(25)
|
||||
config.didChangeListener['core.reopenProjectMenuCount']({oldValue:10, newValue: 25})
|
||||
config.didChangeListener['core.reopenProjectMenuCount']({
|
||||
oldValue: 10,
|
||||
newValue: 25
|
||||
})
|
||||
|
||||
const finalArgs = menuManager.add.calls[1].args[0]
|
||||
const projectsMenu = finalArgs[0].submenu[0].submenu
|
||||
@@ -160,7 +187,10 @@ describe("ReopenProjectMenuManager", () => {
|
||||
|
||||
it("is called when the HistoryManager's projects change", () => {
|
||||
reopenProjects.update()
|
||||
historyManager.getProjects.andReturn([ { paths: ['/a'] }, { paths: ['/b', 'c:\\'] } ])
|
||||
historyManager.getProjects.andReturn([
|
||||
{ paths: ['/a'] },
|
||||
{ paths: ['/b', 'c:\\'] }
|
||||
])
|
||||
historyManager.changeProjectsListener()
|
||||
expect(menuManager.add.calls.length).toBe(2)
|
||||
|
||||
@@ -179,11 +209,11 @@ describe("ReopenProjectMenuManager", () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe("updateProjects", () => {
|
||||
it("creates correct menu items commands for recent projects", () => {
|
||||
describe('updateProjects', () => {
|
||||
it('creates correct menu items commands for recent projects', () => {
|
||||
const projects = [
|
||||
{ paths: [ '/users/neila' ] },
|
||||
{ paths: [ '/users/buzza', 'users/michaelc' ] }
|
||||
{ paths: ['/users/neila'] },
|
||||
{ paths: ['/users/buzza', 'users/michaelc'] }
|
||||
]
|
||||
|
||||
const menu = ReopenProjectMenuManager.createProjectsMenu(projects)
|
||||
@@ -197,69 +227,81 @@ describe("ReopenProjectMenuManager", () => {
|
||||
const first = recentMenu.submenu[0]
|
||||
expect(first.label).toBe('/users/neila')
|
||||
expect(first.command).toBe('application:reopen-project')
|
||||
expect(first.commandDetail).toEqual({index: 0})
|
||||
expect(first.commandDetail).toEqual({ index: 0 })
|
||||
|
||||
const second = recentMenu.submenu[1]
|
||||
expect(second.label).toBe('buzza, michaelc')
|
||||
expect(second.command).toBe('application:reopen-project')
|
||||
expect(second.commandDetail).toEqual({index: 1})
|
||||
expect(second.commandDetail).toEqual({ index: 1 })
|
||||
})
|
||||
})
|
||||
|
||||
describe("createLabel", () => {
|
||||
it("returns the Unix path unchanged if there is only one", () => {
|
||||
const label = ReopenProjectMenuManager.createLabel({ paths: ['/a/b/c/d/e/f'] })
|
||||
describe('createLabel', () => {
|
||||
it('returns the Unix path unchanged if there is only one', () => {
|
||||
const label = ReopenProjectMenuManager.createLabel({
|
||||
paths: ['/a/b/c/d/e/f']
|
||||
})
|
||||
expect(label).toBe('/a/b/c/d/e/f')
|
||||
})
|
||||
|
||||
it("returns the Windows path unchanged if there is only one", () => {
|
||||
const label = ReopenProjectMenuManager.createLabel({ paths: ['c:\\missions\\apollo11'] })
|
||||
it('returns the Windows path unchanged if there is only one', () => {
|
||||
const label = ReopenProjectMenuManager.createLabel({
|
||||
paths: ['c:\\missions\\apollo11']
|
||||
})
|
||||
expect(label).toBe('c:\\missions\\apollo11')
|
||||
})
|
||||
|
||||
it("returns the URL unchanged if there is only one", () => {
|
||||
const label = ReopenProjectMenuManager.createLabel({ paths: ['https://launch.pad/apollo/11'] })
|
||||
it('returns the URL unchanged if there is only one', () => {
|
||||
const label = ReopenProjectMenuManager.createLabel({
|
||||
paths: ['https://launch.pad/apollo/11']
|
||||
})
|
||||
expect(label).toBe('https://launch.pad/apollo/11')
|
||||
})
|
||||
|
||||
it("returns a comma-separated list of base names if there are multiple", () => {
|
||||
const project = { paths: [ '/var/one', '/usr/bin/two', '/etc/mission/control/three' ] }
|
||||
it('returns a comma-separated list of base names if there are multiple', () => {
|
||||
const project = {
|
||||
paths: ['/var/one', '/usr/bin/two', '/etc/mission/control/three']
|
||||
}
|
||||
const label = ReopenProjectMenuManager.createLabel(project)
|
||||
expect(label).toBe('one, two, three')
|
||||
})
|
||||
|
||||
describe("betterBaseName", () => {
|
||||
it("returns the standard base name for an absolute Unix path", () => {
|
||||
describe('betterBaseName', () => {
|
||||
it('returns the standard base name for an absolute Unix path', () => {
|
||||
const name = ReopenProjectMenuManager.betterBaseName('/one/to/three')
|
||||
expect(name).toBe('three')
|
||||
})
|
||||
|
||||
it("returns the standard base name for a relative Windows path", () => {
|
||||
it('returns the standard base name for a relative Windows path', () => {
|
||||
if (process.platform === 'win32') {
|
||||
const name = ReopenProjectMenuManager.betterBaseName('.\\one\\two')
|
||||
expect(name).toBe('two')
|
||||
}
|
||||
})
|
||||
|
||||
it("returns the standard base name for an absolute Windows path", () => {
|
||||
it('returns the standard base name for an absolute Windows path', () => {
|
||||
if (process.platform === 'win32') {
|
||||
const name = ReopenProjectMenuManager.betterBaseName('c:\\missions\\apollo\\11')
|
||||
const name = ReopenProjectMenuManager.betterBaseName(
|
||||
'c:\\missions\\apollo\\11'
|
||||
)
|
||||
expect(name).toBe('11')
|
||||
}
|
||||
})
|
||||
|
||||
it("returns the drive root for a Windows drive name", () => {
|
||||
it('returns the drive root for a Windows drive name', () => {
|
||||
const name = ReopenProjectMenuManager.betterBaseName('d:')
|
||||
expect(name).toBe('d:\\')
|
||||
})
|
||||
|
||||
it("returns the drive root for a Windows drive root", () => {
|
||||
it('returns the drive root for a Windows drive root', () => {
|
||||
const name = ReopenProjectMenuManager.betterBaseName('e:\\')
|
||||
expect(name).toBe('e:\\')
|
||||
})
|
||||
|
||||
it("returns the final path for a URI", () => {
|
||||
const name = ReopenProjectMenuManager.betterBaseName('https://something/else')
|
||||
it('returns the final path for a URI', () => {
|
||||
const name = ReopenProjectMenuManager.betterBaseName(
|
||||
'https://something/else'
|
||||
)
|
||||
expect(name).toBe('else')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -5,7 +5,7 @@ describe('Selection', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
buffer = atom.project.bufferForPathSync('sample.js')
|
||||
editor = new TextEditor({buffer, tabLength: 2})
|
||||
editor = new TextEditor({ buffer, tabLength: 2 })
|
||||
selection = editor.getLastSelection()
|
||||
})
|
||||
|
||||
@@ -88,23 +88,31 @@ describe('Selection', () => {
|
||||
describe("when the selection's range is moved", () => {
|
||||
it('notifies ::onDidChangeRange observers', () => {
|
||||
selection.setBufferRange([[2, 0], [2, 10]])
|
||||
const changeScreenRangeHandler = jasmine.createSpy('changeScreenRangeHandler')
|
||||
const changeScreenRangeHandler = jasmine.createSpy(
|
||||
'changeScreenRangeHandler'
|
||||
)
|
||||
selection.onDidChangeRange(changeScreenRangeHandler)
|
||||
buffer.insert([2, 5], 'abc')
|
||||
expect(changeScreenRangeHandler).toHaveBeenCalled()
|
||||
expect(changeScreenRangeHandler.mostRecentCall.args[0]).not.toBeUndefined()
|
||||
});
|
||||
});
|
||||
expect(
|
||||
changeScreenRangeHandler.mostRecentCall.args[0]
|
||||
).not.toBeUndefined()
|
||||
})
|
||||
})
|
||||
|
||||
describe("when only the selection's tail is moved (regression)", () => {
|
||||
it('notifies ::onDidChangeRange observers', () => {
|
||||
selection.setBufferRange([[2, 0], [2, 10]], {reversed: true})
|
||||
const changeScreenRangeHandler = jasmine.createSpy('changeScreenRangeHandler')
|
||||
selection.setBufferRange([[2, 0], [2, 10]], { reversed: true })
|
||||
const changeScreenRangeHandler = jasmine.createSpy(
|
||||
'changeScreenRangeHandler'
|
||||
)
|
||||
selection.onDidChangeRange(changeScreenRangeHandler)
|
||||
|
||||
buffer.insert([2, 5], 'abc')
|
||||
expect(changeScreenRangeHandler).toHaveBeenCalled()
|
||||
expect(changeScreenRangeHandler.mostRecentCall.args[0]).not.toBeUndefined()
|
||||
expect(
|
||||
changeScreenRangeHandler.mostRecentCall.args[0]
|
||||
).not.toBeUndefined()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -120,7 +128,7 @@ describe('Selection', () => {
|
||||
describe('.insertText(text, options)', () => {
|
||||
it('allows pasting white space only lines when autoIndent is enabled', () => {
|
||||
selection.setBufferRange([[0, 0], [0, 0]])
|
||||
selection.insertText(' \n \n\n', {autoIndent: true})
|
||||
selection.insertText(' \n \n\n', { autoIndent: true })
|
||||
expect(buffer.lineForRow(0)).toBe(' ')
|
||||
expect(buffer.lineForRow(1)).toBe(' ')
|
||||
expect(buffer.lineForRow(2)).toBe('')
|
||||
@@ -128,19 +136,22 @@ describe('Selection', () => {
|
||||
|
||||
it('auto-indents if only a newline is inserted', () => {
|
||||
selection.setBufferRange([[2, 0], [3, 0]])
|
||||
selection.insertText('\n', {autoIndent: true})
|
||||
selection.insertText('\n', { autoIndent: true })
|
||||
expect(buffer.lineForRow(2)).toBe(' ')
|
||||
})
|
||||
|
||||
it('auto-indents if only a carriage return + newline is inserted', () => {
|
||||
selection.setBufferRange([[2, 0], [3, 0]])
|
||||
selection.insertText('\r\n', {autoIndent: true})
|
||||
selection.insertText('\r\n', { autoIndent: true })
|
||||
expect(buffer.lineForRow(2)).toBe(' ')
|
||||
})
|
||||
|
||||
it('does not adjust the indent of trailing lines if preserveTrailingLineIndentation is true', () => {
|
||||
selection.setBufferRange([[5, 0], [5, 0]])
|
||||
selection.insertText(' foo\n bar\n', {preserveTrailingLineIndentation: true, indentBasis: 1})
|
||||
selection.insertText(' foo\n bar\n', {
|
||||
preserveTrailingLineIndentation: true,
|
||||
indentBasis: 1
|
||||
})
|
||||
expect(buffer.lineForRow(6)).toBe(' bar')
|
||||
})
|
||||
})
|
||||
@@ -152,7 +163,9 @@ describe('Selection', () => {
|
||||
|
||||
expect(selection.getScreenRange()).toEqual([[0, 4], [0, 4]])
|
||||
expect(selection.getBufferRange()).toEqual([[1, 6], [1, 6]])
|
||||
expect(editor.lineTextForScreenRow(0)).toBe(`var${editor.displayLayer.foldCharacter}sort = function(items) {`)
|
||||
expect(editor.lineTextForScreenRow(0)).toBe(
|
||||
`var${editor.displayLayer.foldCharacter}sort = function(items) {`
|
||||
)
|
||||
expect(editor.isFoldedAtBufferRow(0)).toBe(true)
|
||||
})
|
||||
|
||||
@@ -162,7 +175,9 @@ describe('Selection', () => {
|
||||
|
||||
expect(selection.getScreenRange()).toEqual([[0, 3], [0, 3]])
|
||||
expect(selection.getBufferRange()).toEqual([[0, 3], [0, 3]])
|
||||
expect(editor.lineTextForScreenRow(0)).toBe('var quicksort = function () {')
|
||||
expect(editor.lineTextForScreenRow(0)).toBe(
|
||||
'var quicksort = function () {'
|
||||
)
|
||||
expect(editor.isFoldedAtBufferRow(0)).toBe(false)
|
||||
})
|
||||
})
|
||||
@@ -261,11 +276,11 @@ describe('Selection', () => {
|
||||
{
|
||||
name: 'indentSelectedRows',
|
||||
op: opts => selection.indentSelectedRows(opts)
|
||||
},
|
||||
}
|
||||
]
|
||||
|
||||
describe('without bypassReadOnly', () => {
|
||||
for (const {name, op} of modifications) {
|
||||
for (const { name, op } of modifications) {
|
||||
it(`throws an error on ${name}`, () => {
|
||||
expect(op).toThrow()
|
||||
})
|
||||
@@ -273,9 +288,9 @@ describe('Selection', () => {
|
||||
})
|
||||
|
||||
describe('with bypassReadOnly', () => {
|
||||
for (const {name, op} of modifications) {
|
||||
for (const { name, op } of modifications) {
|
||||
it(`permits ${name}`, () => {
|
||||
op({bypassReadOnly: true})
|
||||
op({ bypassReadOnly: true })
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,68 +1,69 @@
|
||||
/** @babel */
|
||||
import {it, fit, ffit, fffit, beforeEach, afterEach} from './async-spec-helpers'
|
||||
import { it } from './async-spec-helpers'
|
||||
|
||||
const StateStore = require('../src/state-store.js')
|
||||
|
||||
describe("StateStore", () => {
|
||||
describe('StateStore', () => {
|
||||
let databaseName = `test-database-${Date.now()}`
|
||||
let version = 1
|
||||
|
||||
it("can save, load, and delete states", () => {
|
||||
it('can save, load, and delete states', () => {
|
||||
const store = new StateStore(databaseName, version)
|
||||
return store.save('key', {foo:'bar'})
|
||||
return store
|
||||
.save('key', { foo: 'bar' })
|
||||
.then(() => store.load('key'))
|
||||
.then((state) => {
|
||||
expect(state).toEqual({foo:'bar'})
|
||||
.then(state => {
|
||||
expect(state).toEqual({ foo: 'bar' })
|
||||
})
|
||||
.then(() => store.delete('key'))
|
||||
.then(() => store.load('key'))
|
||||
.then((value) => {
|
||||
.then(value => {
|
||||
expect(value).toBeNull()
|
||||
})
|
||||
.then(() => store.count())
|
||||
.then((count) => {
|
||||
.then(count => {
|
||||
expect(count).toBe(0)
|
||||
})
|
||||
})
|
||||
|
||||
it("resolves with null when a non-existent key is loaded", () => {
|
||||
it('resolves with null when a non-existent key is loaded', () => {
|
||||
const store = new StateStore(databaseName, version)
|
||||
return store.load('no-such-key').then((value) => {
|
||||
return store.load('no-such-key').then(value => {
|
||||
expect(value).toBeNull()
|
||||
})
|
||||
})
|
||||
|
||||
it("can clear the state object store", () => {
|
||||
it('can clear the state object store', () => {
|
||||
const store = new StateStore(databaseName, version)
|
||||
return store.save('key', {foo:'bar'})
|
||||
return store
|
||||
.save('key', { foo: 'bar' })
|
||||
.then(() => store.count())
|
||||
.then((count) =>
|
||||
expect(count).toBe(1)
|
||||
)
|
||||
.then(count => expect(count).toBe(1))
|
||||
.then(() => store.clear())
|
||||
.then(() => store.count())
|
||||
.then((count) => {
|
||||
.then(count => {
|
||||
expect(count).toBe(0)
|
||||
})
|
||||
})
|
||||
|
||||
describe("when there is an error reading from the database", () => {
|
||||
it("rejects the promise returned by load", () => {
|
||||
describe('when there is an error reading from the database', () => {
|
||||
it('rejects the promise returned by load', () => {
|
||||
const store = new StateStore(databaseName, version)
|
||||
|
||||
const fakeErrorEvent = {target: {errorCode: "Something bad happened"}}
|
||||
const fakeErrorEvent = { target: { errorCode: 'Something bad happened' } }
|
||||
|
||||
spyOn(IDBObjectStore.prototype, 'get').andCallFake((key) => {
|
||||
spyOn(IDBObjectStore.prototype, 'get').andCallFake(key => {
|
||||
let request = {}
|
||||
process.nextTick(() => request.onerror(fakeErrorEvent))
|
||||
return request
|
||||
})
|
||||
|
||||
return store.load('nonexistentKey')
|
||||
return store
|
||||
.load('nonexistentKey')
|
||||
.then(() => {
|
||||
throw new Error("Promise should have been rejected")
|
||||
throw new Error('Promise should have been rejected')
|
||||
})
|
||||
.catch((event) => {
|
||||
.catch(event => {
|
||||
expect(event).toBe(fakeErrorEvent)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -5,13 +5,21 @@ describe('StyleManager', () => {
|
||||
let [styleManager, addEvents, removeEvents, updateEvents] = []
|
||||
|
||||
beforeEach(() => {
|
||||
styleManager = new StyleManager({configDirPath: temp.mkdirSync('atom-config')})
|
||||
styleManager = new StyleManager({
|
||||
configDirPath: temp.mkdirSync('atom-config')
|
||||
})
|
||||
addEvents = []
|
||||
removeEvents = []
|
||||
updateEvents = []
|
||||
styleManager.onDidAddStyleElement((event) => { addEvents.push(event) })
|
||||
styleManager.onDidRemoveStyleElement((event) => { removeEvents.push(event) })
|
||||
styleManager.onDidUpdateStyleElement((event) => { updateEvents.push(event) })
|
||||
styleManager.onDidAddStyleElement(event => {
|
||||
addEvents.push(event)
|
||||
})
|
||||
styleManager.onDidRemoveStyleElement(event => {
|
||||
removeEvents.push(event)
|
||||
})
|
||||
styleManager.onDidUpdateStyleElement(event => {
|
||||
updateEvents.push(event)
|
||||
})
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
@@ -39,7 +47,9 @@ describe('StyleManager', () => {
|
||||
describe('atom-text-editor shadow DOM selectors upgrades', () => {
|
||||
beforeEach(() => {
|
||||
// attach styles element to the DOM to parse CSS rules
|
||||
styleManager.onDidAddStyleElement((styleElement) => { jasmine.attachToDOM(styleElement) })
|
||||
styleManager.onDidAddStyleElement(styleElement => {
|
||||
jasmine.attachToDOM(styleElement)
|
||||
})
|
||||
})
|
||||
|
||||
it('removes the ::shadow pseudo-element from atom-text-editor selectors', () => {
|
||||
@@ -51,25 +61,36 @@ describe('StyleManager', () => {
|
||||
atom-text-editor[data-grammar*=\"js\"]::shadow .class-6 { color: green; }
|
||||
atom-text-editor[mini].is-focused::shadow .class-7 { color: green; }
|
||||
`)
|
||||
expect(Array.from(styleManager.getStyleElements()[0].sheet.cssRules).map((r) => r.selectorText)).toEqual([
|
||||
expect(
|
||||
Array.from(styleManager.getStyleElements()[0].sheet.cssRules).map(
|
||||
r => r.selectorText
|
||||
)
|
||||
).toEqual([
|
||||
'atom-text-editor.editor .class-1, atom-text-editor.editor .class-2',
|
||||
'atom-text-editor.editor > .class-3',
|
||||
'atom-text-editor .class-4',
|
||||
'another-element::shadow .class-5',
|
||||
'atom-text-editor[data-grammar*=\"js\"].editor .class-6',
|
||||
'atom-text-editor[data-grammar*="js"].editor .class-6',
|
||||
'atom-text-editor[mini].is-focused.editor .class-7'
|
||||
])
|
||||
})
|
||||
|
||||
describe('when a selector targets the atom-text-editor shadow DOM', () => {
|
||||
it('prepends "--syntax" to class selectors matching a grammar scope name and not already starting with "syntax--"', () => {
|
||||
styleManager.addStyleSheet(`
|
||||
styleManager.addStyleSheet(
|
||||
`
|
||||
.class-1 { color: red }
|
||||
.source > .js, .source.coffee { color: green }
|
||||
.syntax--source { color: gray }
|
||||
#id-1 { color: blue }
|
||||
`, {context: 'atom-text-editor'})
|
||||
expect(Array.from(styleManager.getStyleElements()[0].sheet.cssRules).map((r) => r.selectorText)).toEqual([
|
||||
`,
|
||||
{ context: 'atom-text-editor' }
|
||||
)
|
||||
expect(
|
||||
Array.from(styleManager.getStyleElements()[0].sheet.cssRules).map(
|
||||
r => r.selectorText
|
||||
)
|
||||
).toEqual([
|
||||
'.class-1',
|
||||
'.syntax--source > .syntax--js, .syntax--source.syntax--coffee',
|
||||
'.syntax--source',
|
||||
@@ -82,7 +103,11 @@ describe('StyleManager', () => {
|
||||
atom-text-editor[mini].is-focused::shadow .source > .js { color: gray }
|
||||
atom-text-editor .source > .js { color: red }
|
||||
`)
|
||||
expect(Array.from(styleManager.getStyleElements()[1].sheet.cssRules).map((r) => r.selectorText)).toEqual([
|
||||
expect(
|
||||
Array.from(styleManager.getStyleElements()[1].sheet.cssRules).map(
|
||||
r => r.selectorText
|
||||
)
|
||||
).toEqual([
|
||||
'.source > .js, .source.coffee',
|
||||
'atom-text-editor.editor .syntax--source > .syntax--js',
|
||||
'atom-text-editor[mini].is-focused.editor .syntax--source > .syntax--js',
|
||||
@@ -92,14 +117,23 @@ describe('StyleManager', () => {
|
||||
})
|
||||
|
||||
it('replaces ":host" with "atom-text-editor" only when the context of a style sheet is "atom-text-editor"', () => {
|
||||
styleManager.addStyleSheet(':host .class-1, :host .class-2 { color: red; }')
|
||||
expect(Array.from(styleManager.getStyleElements()[0].sheet.cssRules).map((r) => r.selectorText)).toEqual([
|
||||
':host .class-1, :host .class-2'
|
||||
])
|
||||
styleManager.addStyleSheet(':host .class-1, :host .class-2 { color: red; }', {context: 'atom-text-editor'})
|
||||
expect(Array.from(styleManager.getStyleElements()[1].sheet.cssRules).map((r) => r.selectorText)).toEqual([
|
||||
'atom-text-editor .class-1, atom-text-editor .class-2'
|
||||
])
|
||||
styleManager.addStyleSheet(
|
||||
':host .class-1, :host .class-2 { color: red; }'
|
||||
)
|
||||
expect(
|
||||
Array.from(styleManager.getStyleElements()[0].sheet.cssRules).map(
|
||||
r => r.selectorText
|
||||
)
|
||||
).toEqual([':host .class-1, :host .class-2'])
|
||||
styleManager.addStyleSheet(
|
||||
':host .class-1, :host .class-2 { color: red; }',
|
||||
{ context: 'atom-text-editor' }
|
||||
)
|
||||
expect(
|
||||
Array.from(styleManager.getStyleElements()[1].sheet.cssRules).map(
|
||||
r => r.selectorText
|
||||
)
|
||||
).toEqual(['atom-text-editor .class-1, atom-text-editor .class-2'])
|
||||
})
|
||||
|
||||
it('does not transform CSS rules with invalid syntax', () => {
|
||||
@@ -110,17 +144,23 @@ describe('StyleManager', () => {
|
||||
})
|
||||
|
||||
it('does not throw exceptions on rules with no selectors', () => {
|
||||
styleManager.addStyleSheet('@media screen {font-size: 10px}', {context: 'atom-text-editor'})
|
||||
styleManager.addStyleSheet('@media screen {font-size: 10px}', {
|
||||
context: 'atom-text-editor'
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('when a sourcePath parameter is specified', () => {
|
||||
it('ensures a maximum of one style element for the given source path, updating a previous if it exists', () => {
|
||||
const disposable1 = styleManager.addStyleSheet('a {color: red}', {sourcePath: '/foo/bar'})
|
||||
styleManager.addStyleSheet('a {color: red}', {
|
||||
sourcePath: '/foo/bar'
|
||||
})
|
||||
expect(addEvents.length).toBe(1)
|
||||
expect(addEvents[0].getAttribute('source-path')).toBe('/foo/bar')
|
||||
|
||||
const disposable2 = styleManager.addStyleSheet('a {color: blue}', {sourcePath: '/foo/bar'})
|
||||
const disposable2 = styleManager.addStyleSheet('a {color: blue}', {
|
||||
sourcePath: '/foo/bar'
|
||||
})
|
||||
expect(addEvents.length).toBe(1)
|
||||
expect(updateEvents.length).toBe(1)
|
||||
expect(updateEvents[0].getAttribute('source-path')).toBe('/foo/bar')
|
||||
@@ -128,7 +168,9 @@ describe('StyleManager', () => {
|
||||
disposable2.dispose()
|
||||
|
||||
addEvents = []
|
||||
styleManager.addStyleSheet('a {color: yellow}', {sourcePath: '/foo/bar'})
|
||||
styleManager.addStyleSheet('a {color: yellow}', {
|
||||
sourcePath: '/foo/bar'
|
||||
})
|
||||
expect(addEvents.length).toBe(1)
|
||||
expect(addEvents[0].getAttribute('source-path')).toBe('/foo/bar')
|
||||
expect(addEvents[0].textContent).toBe('a {color: yellow}')
|
||||
@@ -137,11 +179,13 @@ describe('StyleManager', () => {
|
||||
|
||||
describe('when a priority parameter is specified', () => {
|
||||
it('inserts the style sheet based on the priority', () => {
|
||||
styleManager.addStyleSheet('a {color: red}', {priority: 1})
|
||||
styleManager.addStyleSheet('a {color: blue}', {priority: 0})
|
||||
styleManager.addStyleSheet('a {color: green}', {priority: 2})
|
||||
styleManager.addStyleSheet('a {color: yellow}', {priority: 1})
|
||||
expect(styleManager.getStyleElements().map((elt) => elt.textContent)).toEqual([
|
||||
styleManager.addStyleSheet('a {color: red}', { priority: 1 })
|
||||
styleManager.addStyleSheet('a {color: blue}', { priority: 0 })
|
||||
styleManager.addStyleSheet('a {color: green}', { priority: 2 })
|
||||
styleManager.addStyleSheet('a {color: yellow}', { priority: 1 })
|
||||
expect(
|
||||
styleManager.getStyleElements().map(elt => elt.textContent)
|
||||
).toEqual([
|
||||
'a {color: blue}',
|
||||
'a {color: red}',
|
||||
'a {color: yellow}',
|
||||
|
||||
@@ -5,7 +5,7 @@ describe('SyntaxScopeMap', () => {
|
||||
const map = new SyntaxScopeMap({
|
||||
'a > b > c': 'x',
|
||||
'b > c': 'y',
|
||||
'c': 'z'
|
||||
c: 'z'
|
||||
})
|
||||
|
||||
expect(map.get(['a', 'b', 'c'], [0, 0, 0])).toBe('x')
|
||||
@@ -20,7 +20,7 @@ describe('SyntaxScopeMap', () => {
|
||||
const map = new SyntaxScopeMap({
|
||||
'a > b': 'w',
|
||||
'a > b:nth-child(1)': 'x',
|
||||
'b': 'y',
|
||||
b: 'y',
|
||||
'b:nth-child(2)': 'z'
|
||||
})
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,8 @@
|
||||
const {it, fit, ffit, fffit, beforeEach, afterEach, conditionPromise, timeoutPromise} = require('./async-spec-helpers')
|
||||
const {
|
||||
it,
|
||||
|
||||
beforeEach
|
||||
} = require('./async-spec-helpers')
|
||||
const TextEditor = require('../src/text-editor')
|
||||
const TextEditorElement = require('../src/text-editor-element')
|
||||
|
||||
@@ -9,7 +13,8 @@ describe('TextEditorElement', () => {
|
||||
jasmineContent = document.body.querySelector('#jasmine-content')
|
||||
// Force scrollbars to be visible regardless of local system configuration
|
||||
const scrollbarStyle = document.createElement('style')
|
||||
scrollbarStyle.textContent = 'atom-text-editor ::-webkit-scrollbar { -webkit-appearance: none }'
|
||||
scrollbarStyle.textContent =
|
||||
'atom-text-editor ::-webkit-scrollbar { -webkit-appearance: none }'
|
||||
jasmine.attachToDOM(scrollbarStyle)
|
||||
})
|
||||
|
||||
@@ -53,7 +58,7 @@ describe('TextEditorElement', () => {
|
||||
})
|
||||
|
||||
it("only assigns 'placeholder-text' on the model if the attribute is present", () => {
|
||||
const editor = new TextEditor({placeholderText: 'placeholder'})
|
||||
const editor = new TextEditor({ placeholderText: 'placeholder' })
|
||||
editor.getElement()
|
||||
expect(editor.getPlaceholderText()).toBe('placeholder')
|
||||
})
|
||||
@@ -70,8 +75,8 @@ describe('TextEditorElement', () => {
|
||||
expect(element.getModel().isLineNumberGutterVisible()).toBe(false)
|
||||
})
|
||||
|
||||
it("honors the 'readonly' attribute", async function() {
|
||||
jasmineContent.innerHTML = "<atom-text-editor readonly>"
|
||||
it("honors the 'readonly' attribute", async function () {
|
||||
jasmineContent.innerHTML = '<atom-text-editor readonly>'
|
||||
const element = jasmineContent.firstChild
|
||||
|
||||
expect(element.getComponent().isInputEnabled()).toBe(false)
|
||||
@@ -108,11 +113,10 @@ describe('TextEditorElement', () => {
|
||||
describe('when the model is assigned', () =>
|
||||
it("adds the 'mini' attribute if .isMini() returns true on the model", async () => {
|
||||
const element = buildTextEditorElement()
|
||||
element.getModel().update({mini: true})
|
||||
element.getModel().update({ mini: true })
|
||||
await atom.views.getNextUpdatePromise()
|
||||
expect(element.hasAttribute('mini')).toBe(true)
|
||||
})
|
||||
)
|
||||
}))
|
||||
|
||||
describe('when the editor is attached to the DOM', () =>
|
||||
it('mounts the component and unmounts when removed from the dom', () => {
|
||||
@@ -125,8 +129,7 @@ describe('TextEditorElement', () => {
|
||||
|
||||
jasmine.attachToDOM(element)
|
||||
expect(element.component.attached).toBe(true)
|
||||
})
|
||||
)
|
||||
}))
|
||||
|
||||
describe('when the editor is detached from the DOM and then reattached', () => {
|
||||
it('does not render duplicate line numbers', () => {
|
||||
@@ -145,17 +148,23 @@ describe('TextEditorElement', () => {
|
||||
it('does not render duplicate decorations in custom gutters', () => {
|
||||
const editor = new TextEditor()
|
||||
editor.setText('1\n2\n3')
|
||||
editor.addGutter({name: 'test-gutter'})
|
||||
editor.addGutter({ name: 'test-gutter' })
|
||||
const marker = editor.markBufferRange([[0, 0], [2, 0]])
|
||||
editor.decorateMarker(marker, {type: 'gutter', gutterName: 'test-gutter'})
|
||||
editor.decorateMarker(marker, {
|
||||
type: 'gutter',
|
||||
gutterName: 'test-gutter'
|
||||
})
|
||||
const element = editor.getElement()
|
||||
|
||||
jasmine.attachToDOM(element)
|
||||
const initialDecorationCount = element.querySelectorAll('.decoration').length
|
||||
const initialDecorationCount = element.querySelectorAll('.decoration')
|
||||
.length
|
||||
|
||||
element.remove()
|
||||
jasmine.attachToDOM(element)
|
||||
expect(element.querySelectorAll('.decoration').length).toBe(initialDecorationCount)
|
||||
expect(element.querySelectorAll('.decoration').length).toBe(
|
||||
initialDecorationCount
|
||||
)
|
||||
})
|
||||
|
||||
it('can be re-focused using the previous `document.activeElement`', () => {
|
||||
@@ -194,7 +203,9 @@ describe('TextEditorElement', () => {
|
||||
it("doesn't trigger a blur event on the editor element when focusing an already focused editor element", () => {
|
||||
let blurCalled = false
|
||||
const element = buildTextEditorElement()
|
||||
element.addEventListener('blur', () => { blurCalled = true })
|
||||
element.addEventListener('blur', () => {
|
||||
blurCalled = true
|
||||
})
|
||||
|
||||
jasmineContent.appendChild(element)
|
||||
expect(document.activeElement).toBe(document.body)
|
||||
@@ -216,13 +227,15 @@ describe('TextEditorElement', () => {
|
||||
}
|
||||
}
|
||||
|
||||
document.registerElement('element-that-focuses-child',
|
||||
{prototype: ElementThatFocusesChild.prototype}
|
||||
)
|
||||
document.registerElement('element-that-focuses-child', {
|
||||
prototype: ElementThatFocusesChild.prototype
|
||||
})
|
||||
|
||||
it('proxies the focus event to the hidden input', () => {
|
||||
const element = buildTextEditorElement()
|
||||
const parentElement = document.createElement('element-that-focuses-child')
|
||||
const parentElement = document.createElement(
|
||||
'element-that-focuses-child'
|
||||
)
|
||||
parentElement.appendChild(element)
|
||||
jasmineContent.appendChild(parentElement)
|
||||
expect(document.activeElement).toBe(element.querySelector('input'))
|
||||
@@ -236,7 +249,7 @@ describe('TextEditorElement', () => {
|
||||
parentElement.style.width = '0px'
|
||||
parentElement.style.height = '0px'
|
||||
|
||||
const element = buildTextEditorElement({attach: false})
|
||||
const element = buildTextEditorElement({ attach: false })
|
||||
parentElement.appendChild(element)
|
||||
jasmineContent.appendChild(parentElement)
|
||||
|
||||
@@ -249,7 +262,7 @@ describe('TextEditorElement', () => {
|
||||
describe('::setModel', () => {
|
||||
describe('when the element does not have an editor yet', () => {
|
||||
it('uses the supplied one', () => {
|
||||
const element = buildTextEditorElement({attach: false})
|
||||
const element = buildTextEditorElement({ attach: false })
|
||||
const editor = new TextEditor()
|
||||
element.setModel(editor)
|
||||
jasmine.attachToDOM(element)
|
||||
@@ -260,7 +273,7 @@ describe('TextEditorElement', () => {
|
||||
|
||||
describe('when the element already has an editor', () => {
|
||||
it('unbinds it and then swaps it with the supplied one', async () => {
|
||||
const element = buildTextEditorElement({attach: true})
|
||||
const element = buildTextEditorElement({ attach: true })
|
||||
const previousEditor = element.getModel()
|
||||
expect(previousEditor.element).toBe(element)
|
||||
|
||||
@@ -275,7 +288,7 @@ describe('TextEditorElement', () => {
|
||||
|
||||
describe('::onDidAttach and ::onDidDetach', () =>
|
||||
it('invokes callbacks when the element is attached and detached', () => {
|
||||
const element = buildTextEditorElement({attach: false})
|
||||
const element = buildTextEditorElement({ attach: false })
|
||||
|
||||
const attachedCallback = jasmine.createSpy('attachedCallback')
|
||||
const detachedCallback = jasmine.createSpy('detachedCallback')
|
||||
@@ -292,8 +305,7 @@ describe('TextEditorElement', () => {
|
||||
|
||||
expect(attachedCallback).not.toHaveBeenCalled()
|
||||
expect(detachedCallback).toHaveBeenCalled()
|
||||
})
|
||||
)
|
||||
}))
|
||||
|
||||
describe('::setUpdatedSynchronously', () => {
|
||||
it('controls whether the text editor is updated synchronously', () => {
|
||||
@@ -318,7 +330,7 @@ describe('TextEditorElement', () => {
|
||||
|
||||
describe('::getDefaultCharacterWidth', () => {
|
||||
it('returns 0 before the element is attached', () => {
|
||||
const element = buildTextEditorElement({attach: false})
|
||||
const element = buildTextEditorElement({ attach: false })
|
||||
expect(element.getDefaultCharacterWidth()).toBe(0)
|
||||
})
|
||||
|
||||
@@ -341,7 +353,7 @@ describe('TextEditorElement', () => {
|
||||
const horizontalScrollbarHeight = element.component.getHorizontalScrollbarHeight()
|
||||
|
||||
expect(element.getMaxScrollTop()).toBe(0)
|
||||
await editor.update({autoHeight: false})
|
||||
await editor.update({ autoHeight: false })
|
||||
|
||||
element.style.height = 100 + horizontalScrollbarHeight + 'px'
|
||||
await element.getNextUpdatePromise()
|
||||
@@ -354,13 +366,12 @@ describe('TextEditorElement', () => {
|
||||
element.style.height = 200 + horizontalScrollbarHeight + 'px'
|
||||
await element.getNextUpdatePromise()
|
||||
expect(element.getMaxScrollTop()).toBe(0)
|
||||
})
|
||||
)
|
||||
}))
|
||||
|
||||
describe('::setScrollTop and ::setScrollLeft', () => {
|
||||
it('changes the scroll position', async () => {
|
||||
element = buildTextEditorElement()
|
||||
element.getModel().update({autoHeight: false})
|
||||
const element = buildTextEditorElement()
|
||||
element.getModel().update({ autoHeight: false })
|
||||
element.getModel().setText('lorem\nipsum\ndolor\nsit\namet')
|
||||
element.setHeight(20)
|
||||
await element.getNextUpdatePromise()
|
||||
@@ -387,8 +398,7 @@ describe('TextEditorElement', () => {
|
||||
element.getModel().setMini(false)
|
||||
await element.getNextUpdatePromise()
|
||||
expect(element.hasAttribute('mini')).toBe(false)
|
||||
})
|
||||
)
|
||||
}))
|
||||
|
||||
describe('::intersectsVisibleRowRange(start, end)', () => {
|
||||
it('returns true if the given row range intersects the visible row range', async () => {
|
||||
@@ -396,7 +406,7 @@ describe('TextEditorElement', () => {
|
||||
const editor = element.getModel()
|
||||
const horizontalScrollbarHeight = element.component.getHorizontalScrollbarHeight()
|
||||
|
||||
editor.update({autoHeight: false})
|
||||
editor.update({ autoHeight: false })
|
||||
element.getModel().setText('x\n'.repeat(20))
|
||||
element.style.height = 120 + horizontalScrollbarHeight + 'px'
|
||||
await element.getNextUpdatePromise()
|
||||
@@ -419,7 +429,7 @@ describe('TextEditorElement', () => {
|
||||
const editor = element.getModel()
|
||||
const horizontalScrollbarHeight = element.component.getHorizontalScrollbarHeight()
|
||||
|
||||
editor.update({autoHeight: false})
|
||||
editor.update({ autoHeight: false })
|
||||
element.getModel().setText('xxxxxxxxxxxxxxxxxxxxxx\n'.repeat(20))
|
||||
element.style.height = 120 + horizontalScrollbarHeight + 'px'
|
||||
await element.getNextUpdatePromise()
|
||||
@@ -445,7 +455,7 @@ describe('TextEditorElement', () => {
|
||||
|
||||
beforeEach(async () => {
|
||||
element = buildTextEditorElement()
|
||||
element.getModel().update({autoHeight: false})
|
||||
element.getModel().update({ autoHeight: false })
|
||||
element.getModel().setText('lorem\nipsum\ndolor\nsit\namet')
|
||||
element.setHeight(20)
|
||||
await element.getNextUpdatePromise()
|
||||
@@ -456,7 +466,9 @@ describe('TextEditorElement', () => {
|
||||
describe('::onDidChangeScrollTop(callback)', () =>
|
||||
it('triggers even when subscribing before attaching the element', () => {
|
||||
const positions = []
|
||||
const subscription1 = element.onDidChangeScrollTop(p => positions.push(p))
|
||||
const subscription1 = element.onDidChangeScrollTop(p =>
|
||||
positions.push(p)
|
||||
)
|
||||
element.onDidChangeScrollTop(p => positions.push(p))
|
||||
|
||||
positions.length = 0
|
||||
@@ -475,13 +487,14 @@ describe('TextEditorElement', () => {
|
||||
positions.length = 0
|
||||
element.setScrollTop(30)
|
||||
expect(positions).toEqual([30])
|
||||
})
|
||||
)
|
||||
}))
|
||||
|
||||
describe('::onDidChangeScrollLeft(callback)', () =>
|
||||
it('triggers even when subscribing before attaching the element', () => {
|
||||
const positions = []
|
||||
const subscription1 = element.onDidChangeScrollLeft(p => positions.push(p))
|
||||
const subscription1 = element.onDidChangeScrollLeft(p =>
|
||||
positions.push(p)
|
||||
)
|
||||
element.onDidChangeScrollLeft(p => positions.push(p))
|
||||
|
||||
positions.length = 0
|
||||
@@ -500,7 +513,6 @@ describe('TextEditorElement', () => {
|
||||
positions.length = 0
|
||||
element.setScrollLeft(30)
|
||||
expect(positions).toEqual([30])
|
||||
})
|
||||
)
|
||||
}))
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
const TextEditorRegistry = require('../src/text-editor-registry')
|
||||
const TextEditor = require('../src/text-editor')
|
||||
const TextBuffer = require('text-buffer')
|
||||
const {Point, Range} = TextBuffer
|
||||
const {it, fit, ffit, fffit} = require('./async-spec-helpers')
|
||||
const { Point, Range } = TextBuffer
|
||||
const { it } = require('./async-spec-helpers')
|
||||
const dedent = require('dedent')
|
||||
|
||||
describe('TextEditorRegistry', function () {
|
||||
@@ -15,11 +15,13 @@ describe('TextEditorRegistry', function () {
|
||||
assert: atom.assert,
|
||||
config: atom.config,
|
||||
grammarRegistry: atom.grammars,
|
||||
packageManager: {deferredActivationHooks: null}
|
||||
packageManager: { deferredActivationHooks: null }
|
||||
})
|
||||
|
||||
editor = new TextEditor({autoHeight: false})
|
||||
expect(atom.grammars.assignLanguageMode(editor, 'text.plain.null-grammar')).toBe(true)
|
||||
editor = new TextEditor({ autoHeight: false })
|
||||
expect(
|
||||
atom.grammars.assignLanguageMode(editor, 'text.plain.null-grammar')
|
||||
).toBe(true)
|
||||
})
|
||||
|
||||
afterEach(function () {
|
||||
@@ -68,9 +70,11 @@ describe('TextEditorRegistry', function () {
|
||||
await atom.packages.activatePackage('language-javascript')
|
||||
await atom.packages.activatePackage('language-c')
|
||||
|
||||
atom.config.set('editor.tabLength', 8, {scope: '.source.js'})
|
||||
atom.config.set('editor.tabLength', 8, { scope: '.source.js' })
|
||||
|
||||
const editor = registry.build({buffer: new TextBuffer({filePath: 'test.js'})})
|
||||
const editor = registry.build({
|
||||
buffer: new TextBuffer({ filePath: 'test.js' })
|
||||
})
|
||||
expect(editor.getTabLength()).toBe(8)
|
||||
})
|
||||
})
|
||||
@@ -87,14 +91,22 @@ describe('TextEditorRegistry', function () {
|
||||
registry.maintainConfig(editor2)
|
||||
await initialPackageActivation
|
||||
|
||||
expect(editor.getRootScopeDescriptor().getScopesArray()).toEqual(['text.plain.null-grammar'])
|
||||
expect(editor2.getRootScopeDescriptor().getScopesArray()).toEqual(['source.js'])
|
||||
expect(editor.getRootScopeDescriptor().getScopesArray()).toEqual([
|
||||
'text.plain.null-grammar'
|
||||
])
|
||||
expect(editor2.getRootScopeDescriptor().getScopesArray()).toEqual([
|
||||
'source.js'
|
||||
])
|
||||
|
||||
expect(editor.getEncoding()).toBe('utf8')
|
||||
expect(editor2.getEncoding()).toBe('utf8')
|
||||
|
||||
atom.config.set('core.fileEncoding', 'utf16le', {scopeSelector: '.text.plain.null-grammar'})
|
||||
atom.config.set('core.fileEncoding', 'utf16be', {scopeSelector: '.source.js'})
|
||||
atom.config.set('core.fileEncoding', 'utf16le', {
|
||||
scopeSelector: '.text.plain.null-grammar'
|
||||
})
|
||||
atom.config.set('core.fileEncoding', 'utf16be', {
|
||||
scopeSelector: '.source.js'
|
||||
})
|
||||
|
||||
expect(editor.getEncoding()).toBe('utf16le')
|
||||
expect(editor2.getEncoding()).toBe('utf16be')
|
||||
@@ -131,23 +143,29 @@ describe('TextEditorRegistry', function () {
|
||||
expect(editor.getEncoding()).toBe('utf16be')
|
||||
})
|
||||
|
||||
it('updates the editor\'s settings when its grammar changes', async function () {
|
||||
it("updates the editor's settings when its grammar changes", async function () {
|
||||
await atom.packages.activatePackage('language-javascript')
|
||||
|
||||
registry.maintainConfig(editor)
|
||||
await initialPackageActivation
|
||||
|
||||
atom.config.set('core.fileEncoding', 'utf16be', {scopeSelector: '.source.js'})
|
||||
atom.config.set('core.fileEncoding', 'utf16be', {
|
||||
scopeSelector: '.source.js'
|
||||
})
|
||||
expect(editor.getEncoding()).toBe('utf8')
|
||||
|
||||
atom.config.set('core.fileEncoding', 'utf16le', {scopeSelector: '.source.js'})
|
||||
atom.config.set('core.fileEncoding', 'utf16le', {
|
||||
scopeSelector: '.source.js'
|
||||
})
|
||||
expect(editor.getEncoding()).toBe('utf8')
|
||||
|
||||
atom.grammars.assignLanguageMode(editor, 'source.js')
|
||||
await initialPackageActivation
|
||||
expect(editor.getEncoding()).toBe('utf16le')
|
||||
|
||||
atom.config.set('core.fileEncoding', 'utf16be', {scopeSelector: '.source.js'})
|
||||
atom.config.set('core.fileEncoding', 'utf16be', {
|
||||
scopeSelector: '.source.js'
|
||||
})
|
||||
expect(editor.getEncoding()).toBe('utf16be')
|
||||
|
||||
atom.grammars.assignLanguageMode(editor, 'text.plain.null-grammar')
|
||||
@@ -155,7 +173,7 @@ describe('TextEditorRegistry', function () {
|
||||
expect(editor.getEncoding()).toBe('utf8')
|
||||
})
|
||||
|
||||
it('preserves editor settings that haven\'t changed between previous and current language modes', async function () {
|
||||
it("preserves editor settings that haven't changed between previous and current language modes", async function () {
|
||||
await atom.packages.activatePackage('language-javascript')
|
||||
|
||||
registry.maintainConfig(editor)
|
||||
@@ -182,8 +200,12 @@ describe('TextEditorRegistry', function () {
|
||||
await initialPackageActivation
|
||||
|
||||
expect(editor.getEncoding()).toBe('utf8')
|
||||
atom.config.set('core.fileEncoding', 'utf16be', {scopeSelector: '.text.plain.null-grammar'})
|
||||
atom.config.set('core.fileEncoding', 'utf16le', {scopeSelector: '.source.js'})
|
||||
atom.config.set('core.fileEncoding', 'utf16be', {
|
||||
scopeSelector: '.text.plain.null-grammar'
|
||||
})
|
||||
atom.config.set('core.fileEncoding', 'utf16le', {
|
||||
scopeSelector: '.source.js'
|
||||
})
|
||||
expect(editor.getEncoding()).toBe('utf16be')
|
||||
|
||||
editor.setEncoding('utf8')
|
||||
@@ -194,13 +216,15 @@ describe('TextEditorRegistry', function () {
|
||||
expect(editor.getEncoding()).toBe('utf16le')
|
||||
})
|
||||
|
||||
it('returns a disposable that can be used to stop the registry from updating the editor\'s config', async function () {
|
||||
it("returns a disposable that can be used to stop the registry from updating the editor's config", async function () {
|
||||
await atom.packages.activatePackage('language-javascript')
|
||||
|
||||
const previousSubscriptionCount = getSubscriptionCount(editor)
|
||||
const disposable = registry.maintainConfig(editor)
|
||||
await initialPackageActivation
|
||||
expect(getSubscriptionCount(editor)).toBeGreaterThan(previousSubscriptionCount)
|
||||
expect(getSubscriptionCount(editor)).toBeGreaterThan(
|
||||
previousSubscriptionCount
|
||||
)
|
||||
expect(registry.editorsWithMaintainedConfig.size).toBe(1)
|
||||
|
||||
atom.config.set('core.fileEncoding', 'utf16be')
|
||||
@@ -217,7 +241,7 @@ describe('TextEditorRegistry', function () {
|
||||
})
|
||||
|
||||
it('sets the encoding based on the config', async function () {
|
||||
editor.update({encoding: 'utf8'})
|
||||
editor.update({ encoding: 'utf8' })
|
||||
expect(editor.getEncoding()).toBe('utf8')
|
||||
|
||||
atom.config.set('core.fileEncoding', 'utf16le')
|
||||
@@ -230,7 +254,7 @@ describe('TextEditorRegistry', function () {
|
||||
})
|
||||
|
||||
it('sets the tab length based on the config', async function () {
|
||||
editor.update({tabLength: 4})
|
||||
editor.update({ tabLength: 4 })
|
||||
expect(editor.getTabLength()).toBe(4)
|
||||
|
||||
atom.config.set('editor.tabLength', 8)
|
||||
@@ -257,13 +281,12 @@ describe('TextEditorRegistry', function () {
|
||||
})
|
||||
|
||||
describe('when the "tabType" config setting is "auto"', function () {
|
||||
it('enables or disables soft tabs based on the editor\'s content', async function () {
|
||||
it("enables or disables soft tabs based on the editor's content", async function () {
|
||||
await initialPackageActivation
|
||||
await atom.packages.activatePackage('language-javascript')
|
||||
atom.grammars.assignLanguageMode(editor, 'source.js')
|
||||
atom.config.set('editor.tabType', 'auto')
|
||||
await initialPackageActivation
|
||||
const languageMode = editor.getBuffer().getLanguageMode()
|
||||
|
||||
editor.setText(dedent`
|
||||
{
|
||||
@@ -273,24 +296,30 @@ describe('TextEditorRegistry', function () {
|
||||
let disposable = registry.maintainConfig(editor)
|
||||
expect(editor.getSoftTabs()).toBe(true)
|
||||
|
||||
/* eslint-disable no-tabs */
|
||||
editor.setText(dedent`
|
||||
{
|
||||
hello;
|
||||
}
|
||||
`)
|
||||
/* eslint-enable no-tabs */
|
||||
disposable.dispose()
|
||||
disposable = registry.maintainConfig(editor)
|
||||
expect(editor.getSoftTabs()).toBe(false)
|
||||
|
||||
editor.setTextInBufferRange(new Range(Point.ZERO, Point.ZERO), dedent`
|
||||
editor.setTextInBufferRange(
|
||||
new Range(Point.ZERO, Point.ZERO),
|
||||
dedent`
|
||||
/*
|
||||
* Comment with a leading space.
|
||||
*/
|
||||
` + '\n')
|
||||
` + '\n'
|
||||
)
|
||||
disposable.dispose()
|
||||
disposable = registry.maintainConfig(editor)
|
||||
expect(editor.getSoftTabs()).toBe(false)
|
||||
|
||||
/* eslint-disable no-tabs */
|
||||
editor.setText(dedent`
|
||||
/*
|
||||
* Comment with a leading space.
|
||||
@@ -300,6 +329,7 @@ describe('TextEditorRegistry', function () {
|
||||
hello;
|
||||
}
|
||||
`)
|
||||
/* eslint-enable no-tabs */
|
||||
disposable.dispose()
|
||||
disposable = registry.maintainConfig(editor)
|
||||
expect(editor.getSoftTabs()).toBe(false)
|
||||
@@ -335,7 +365,7 @@ describe('TextEditorRegistry', function () {
|
||||
})
|
||||
|
||||
it('enables or disables soft tabs based on the config', async function () {
|
||||
editor.update({softTabs: true})
|
||||
editor.update({ softTabs: true })
|
||||
expect(editor.getSoftTabs()).toBe(true)
|
||||
|
||||
atom.config.set('editor.tabType', 'hard')
|
||||
@@ -352,7 +382,7 @@ describe('TextEditorRegistry', function () {
|
||||
})
|
||||
|
||||
it('enables or disables atomic soft tabs based on the config', async function () {
|
||||
editor.update({atomicSoftTabs: true})
|
||||
editor.update({ atomicSoftTabs: true })
|
||||
expect(editor.hasAtomicSoftTabs()).toBe(true)
|
||||
|
||||
atom.config.set('editor.atomicSoftTabs', false)
|
||||
@@ -365,7 +395,7 @@ describe('TextEditorRegistry', function () {
|
||||
})
|
||||
|
||||
it('enables or disables cursor on selection visibility based on the config', async function () {
|
||||
editor.update({showCursorOnSelection: true})
|
||||
editor.update({ showCursorOnSelection: true })
|
||||
expect(editor.getShowCursorOnSelection()).toBe(true)
|
||||
|
||||
atom.config.set('editor.showCursorOnSelection', false)
|
||||
@@ -378,7 +408,7 @@ describe('TextEditorRegistry', function () {
|
||||
})
|
||||
|
||||
it('enables or disables line numbers based on the config', async function () {
|
||||
editor.update({showLineNumbers: true})
|
||||
editor.update({ showLineNumbers: true })
|
||||
expect(editor.showLineNumbers).toBe(true)
|
||||
|
||||
atom.config.set('editor.showLineNumbers', false)
|
||||
@@ -391,8 +421,8 @@ describe('TextEditorRegistry', function () {
|
||||
})
|
||||
|
||||
it('sets the invisibles based on the config', async function () {
|
||||
const invisibles1 = {'tab': 'a', 'cr': false, eol: false, space: false}
|
||||
const invisibles2 = {'tab': 'b', 'cr': false, eol: false, space: false}
|
||||
const invisibles1 = { tab: 'a', cr: false, eol: false, space: false }
|
||||
const invisibles2 = { tab: 'b', cr: false, eol: false, space: false }
|
||||
|
||||
editor.update({
|
||||
showInvisibles: true,
|
||||
@@ -414,7 +444,7 @@ describe('TextEditorRegistry', function () {
|
||||
})
|
||||
|
||||
it('enables or disables the indent guide based on the config', async function () {
|
||||
editor.update({showIndentGuide: true})
|
||||
editor.update({ showIndentGuide: true })
|
||||
expect(editor.doesShowIndentGuide()).toBe(true)
|
||||
|
||||
atom.config.set('editor.showIndentGuide', false)
|
||||
@@ -427,7 +457,7 @@ describe('TextEditorRegistry', function () {
|
||||
})
|
||||
|
||||
it('enables or disables soft wrap based on the config', async function () {
|
||||
editor.update({softWrapped: true})
|
||||
editor.update({ softWrapped: true })
|
||||
expect(editor.isSoftWrapped()).toBe(true)
|
||||
|
||||
atom.config.set('editor.softWrap', false)
|
||||
@@ -440,7 +470,7 @@ describe('TextEditorRegistry', function () {
|
||||
})
|
||||
|
||||
it('sets the soft wrap indent length based on the config', async function () {
|
||||
editor.update({softWrapHangingIndentLength: 4})
|
||||
editor.update({ softWrapHangingIndentLength: 4 })
|
||||
expect(editor.getSoftWrapHangingIndentLength()).toBe(4)
|
||||
|
||||
atom.config.set('editor.softWrapHangingIndent', 2)
|
||||
@@ -457,7 +487,7 @@ describe('TextEditorRegistry', function () {
|
||||
softWrapped: true,
|
||||
preferredLineLength: 80,
|
||||
editorWidthInChars: 120,
|
||||
softWrapAtPreferredLineLength: true,
|
||||
softWrapAtPreferredLineLength: true
|
||||
})
|
||||
|
||||
expect(editor.getSoftWrapColumn()).toBe(80)
|
||||
@@ -475,7 +505,7 @@ describe('TextEditorRegistry', function () {
|
||||
it('allows for custom definition of maximum soft wrap based on config', async function () {
|
||||
editor.update({
|
||||
softWrapped: false,
|
||||
maxScreenLineLength: 1500,
|
||||
maxScreenLineLength: 1500
|
||||
})
|
||||
|
||||
expect(editor.getSoftWrapColumn()).toBe(1500)
|
||||
@@ -488,7 +518,7 @@ describe('TextEditorRegistry', function () {
|
||||
})
|
||||
|
||||
it('sets the preferred line length based on the config', async function () {
|
||||
editor.update({preferredLineLength: 80})
|
||||
editor.update({ preferredLineLength: 80 })
|
||||
expect(editor.getPreferredLineLength()).toBe(80)
|
||||
|
||||
atom.config.set('editor.preferredLineLength', 110)
|
||||
@@ -501,7 +531,7 @@ describe('TextEditorRegistry', function () {
|
||||
})
|
||||
|
||||
it('enables or disables auto-indent based on the config', async function () {
|
||||
editor.update({autoIndent: true})
|
||||
editor.update({ autoIndent: true })
|
||||
expect(editor.shouldAutoIndent()).toBe(true)
|
||||
|
||||
atom.config.set('editor.autoIndent', false)
|
||||
@@ -514,7 +544,7 @@ describe('TextEditorRegistry', function () {
|
||||
})
|
||||
|
||||
it('enables or disables auto-indent-on-paste based on the config', async function () {
|
||||
editor.update({autoIndentOnPaste: true})
|
||||
editor.update({ autoIndentOnPaste: true })
|
||||
expect(editor.shouldAutoIndentOnPaste()).toBe(true)
|
||||
|
||||
atom.config.set('editor.autoIndentOnPaste', false)
|
||||
@@ -527,7 +557,7 @@ describe('TextEditorRegistry', function () {
|
||||
})
|
||||
|
||||
it('enables or disables scrolling past the end of the buffer based on the config', async function () {
|
||||
editor.update({scrollPastEnd: true})
|
||||
editor.update({ scrollPastEnd: true })
|
||||
expect(editor.getScrollPastEnd()).toBe(true)
|
||||
|
||||
atom.config.set('editor.scrollPastEnd', false)
|
||||
@@ -540,7 +570,7 @@ describe('TextEditorRegistry', function () {
|
||||
})
|
||||
|
||||
it('sets the undo grouping interval based on the config', async function () {
|
||||
editor.update({undoGroupingInterval: 300})
|
||||
editor.update({ undoGroupingInterval: 300 })
|
||||
expect(editor.getUndoGroupingInterval()).toBe(300)
|
||||
|
||||
atom.config.set('editor.undoGroupingInterval', 600)
|
||||
@@ -553,7 +583,7 @@ describe('TextEditorRegistry', function () {
|
||||
})
|
||||
|
||||
it('sets the scroll sensitivity based on the config', async function () {
|
||||
editor.update({scrollSensitivity: 50})
|
||||
editor.update({ scrollSensitivity: 50 })
|
||||
expect(editor.getScrollSensitivity()).toBe(50)
|
||||
|
||||
atom.config.set('editor.scrollSensitivity', 60)
|
||||
@@ -567,7 +597,7 @@ describe('TextEditorRegistry', function () {
|
||||
|
||||
describe('when called twice with a given editor', function () {
|
||||
it('does nothing the second time', async function () {
|
||||
editor.update({scrollSensitivity: 50})
|
||||
editor.update({ scrollSensitivity: 50 })
|
||||
|
||||
const disposable1 = registry.maintainConfig(editor)
|
||||
const disposable2 = registry.maintainConfig(editor)
|
||||
@@ -589,10 +619,12 @@ describe('TextEditorRegistry', function () {
|
||||
})
|
||||
|
||||
function getSubscriptionCount (editor) {
|
||||
return editor.emitter.getTotalListenerCount() +
|
||||
return (
|
||||
editor.emitter.getTotalListenerCount() +
|
||||
editor.tokenizedBuffer.emitter.getTotalListenerCount() +
|
||||
editor.buffer.emitter.getTotalListenerCount() +
|
||||
editor.displayLayer.emitter.getTotalListenerCount()
|
||||
)
|
||||
}
|
||||
|
||||
function retainedEditorCount (registry) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -4,7 +4,9 @@ describe('text utilities', () => {
|
||||
describe('.hasPairedCharacter(string)', () =>
|
||||
it('returns true when the string contains a surrogate pair, variation sequence, or combined character', () => {
|
||||
expect(textUtils.hasPairedCharacter('abc')).toBe(false)
|
||||
expect(textUtils.hasPairedCharacter('a\uD835\uDF97b\uD835\uDF97c')).toBe(true)
|
||||
expect(textUtils.hasPairedCharacter('a\uD835\uDF97b\uD835\uDF97c')).toBe(
|
||||
true
|
||||
)
|
||||
expect(textUtils.hasPairedCharacter('\uD835\uDF97')).toBe(true)
|
||||
expect(textUtils.hasPairedCharacter('\u2714\uFE0E')).toBe(true)
|
||||
expect(textUtils.hasPairedCharacter('e\u0301')).toBe(true)
|
||||
@@ -16,18 +18,31 @@ describe('text utilities', () => {
|
||||
|
||||
expect(textUtils.hasPairedCharacter('\uFE0E\uFE0E')).toBe(false)
|
||||
expect(textUtils.hasPairedCharacter('\u0301\u0301')).toBe(false)
|
||||
})
|
||||
)
|
||||
}))
|
||||
|
||||
describe('.isPairedCharacter(string, index)', () =>
|
||||
it('returns true when the index is the start of a high/low surrogate pair, variation sequence, or combined character', () => {
|
||||
expect(textUtils.isPairedCharacter('a\uD835\uDF97b\uD835\uDF97c', 0)).toBe(false)
|
||||
expect(textUtils.isPairedCharacter('a\uD835\uDF97b\uD835\uDF97c', 1)).toBe(true)
|
||||
expect(textUtils.isPairedCharacter('a\uD835\uDF97b\uD835\uDF97c', 2)).toBe(false)
|
||||
expect(textUtils.isPairedCharacter('a\uD835\uDF97b\uD835\uDF97c', 3)).toBe(false)
|
||||
expect(textUtils.isPairedCharacter('a\uD835\uDF97b\uD835\uDF97c', 4)).toBe(true)
|
||||
expect(textUtils.isPairedCharacter('a\uD835\uDF97b\uD835\uDF97c', 5)).toBe(false)
|
||||
expect(textUtils.isPairedCharacter('a\uD835\uDF97b\uD835\uDF97c', 6)).toBe(false)
|
||||
expect(
|
||||
textUtils.isPairedCharacter('a\uD835\uDF97b\uD835\uDF97c', 0)
|
||||
).toBe(false)
|
||||
expect(
|
||||
textUtils.isPairedCharacter('a\uD835\uDF97b\uD835\uDF97c', 1)
|
||||
).toBe(true)
|
||||
expect(
|
||||
textUtils.isPairedCharacter('a\uD835\uDF97b\uD835\uDF97c', 2)
|
||||
).toBe(false)
|
||||
expect(
|
||||
textUtils.isPairedCharacter('a\uD835\uDF97b\uD835\uDF97c', 3)
|
||||
).toBe(false)
|
||||
expect(
|
||||
textUtils.isPairedCharacter('a\uD835\uDF97b\uD835\uDF97c', 4)
|
||||
).toBe(true)
|
||||
expect(
|
||||
textUtils.isPairedCharacter('a\uD835\uDF97b\uD835\uDF97c', 5)
|
||||
).toBe(false)
|
||||
expect(
|
||||
textUtils.isPairedCharacter('a\uD835\uDF97b\uD835\uDF97c', 6)
|
||||
).toBe(false)
|
||||
|
||||
expect(textUtils.isPairedCharacter('a\u2714\uFE0E', 0)).toBe(false)
|
||||
expect(textUtils.isPairedCharacter('a\u2714\uFE0E', 1)).toBe(true)
|
||||
@@ -46,8 +61,7 @@ describe('text utilities', () => {
|
||||
expect(textUtils.isPairedCharacter('ae\u0301c', 2)).toBe(false)
|
||||
expect(textUtils.isPairedCharacter('ae\u0301c', 3)).toBe(false)
|
||||
expect(textUtils.isPairedCharacter('ae\u0301c', 4)).toBe(false)
|
||||
})
|
||||
)
|
||||
}))
|
||||
|
||||
describe('.isDoubleWidthCharacter(character)', () =>
|
||||
it('returns true when the character is either japanese, chinese or a full width form', () => {
|
||||
@@ -60,8 +74,7 @@ describe('text utilities', () => {
|
||||
expect(textUtils.isDoubleWidthCharacter('¢')).toBe(true)
|
||||
|
||||
expect(textUtils.isDoubleWidthCharacter('a')).toBe(false)
|
||||
})
|
||||
)
|
||||
}))
|
||||
|
||||
describe('.isHalfWidthCharacter(character)', () =>
|
||||
it('returns true when the character is an half width form', () => {
|
||||
@@ -71,8 +84,7 @@ describe('text utilities', () => {
|
||||
expect(textUtils.isHalfWidthCharacter('■')).toBe(true)
|
||||
|
||||
expect(textUtils.isHalfWidthCharacter('B')).toBe(false)
|
||||
})
|
||||
)
|
||||
}))
|
||||
|
||||
describe('.isKoreanCharacter(character)', () =>
|
||||
it('returns true when the character is a korean character', () => {
|
||||
@@ -82,8 +94,7 @@ describe('text utilities', () => {
|
||||
expect(textUtils.isKoreanCharacter('ㄼ')).toBe(true)
|
||||
|
||||
expect(textUtils.isKoreanCharacter('O')).toBe(false)
|
||||
})
|
||||
)
|
||||
}))
|
||||
|
||||
describe('.isWrapBoundary(previousCharacter, character)', () =>
|
||||
it('returns true when the character is CJK or when the previous character is a space/tab', () => {
|
||||
@@ -105,6 +116,5 @@ describe('text utilities', () => {
|
||||
expect(textUtils.isWrapBoundary(' ', 'h')).toBe(true)
|
||||
expect(textUtils.isWrapBoundary('\t', 'h')).toBe(true)
|
||||
expect(textUtils.isWrapBoundary('a', 'h')).toBe(false)
|
||||
})
|
||||
)
|
||||
}))
|
||||
})
|
||||
|
||||
@@ -29,8 +29,7 @@ describe('atom.themes', function () {
|
||||
it('gets all the loaded themes', function () {
|
||||
const themes = atom.themes.getLoadedThemes()
|
||||
expect(themes.length).toBeGreaterThan(2)
|
||||
})
|
||||
)
|
||||
}))
|
||||
|
||||
describe('getActiveThemes', () =>
|
||||
it('gets all the active themes', function () {
|
||||
@@ -42,8 +41,7 @@ describe('atom.themes', function () {
|
||||
const themes = atom.themes.getActiveThemes()
|
||||
expect(themes).toHaveLength(names.length)
|
||||
})
|
||||
})
|
||||
)
|
||||
}))
|
||||
})
|
||||
|
||||
describe('when the core.themes config value contains invalid entry', () =>
|
||||
@@ -60,13 +58,19 @@ describe('atom.themes', function () {
|
||||
'atom-dark-ui'
|
||||
])
|
||||
|
||||
expect(atom.themes.getEnabledThemeNames()).toEqual(['atom-dark-ui', 'atom-light-ui'])
|
||||
})
|
||||
)
|
||||
expect(atom.themes.getEnabledThemeNames()).toEqual([
|
||||
'atom-dark-ui',
|
||||
'atom-light-ui'
|
||||
])
|
||||
}))
|
||||
|
||||
describe('::getImportPaths()', function () {
|
||||
it('returns the theme directories before the themes are loaded', function () {
|
||||
atom.config.set('core.themes', ['theme-with-index-less', 'atom-dark-ui', 'atom-light-ui'])
|
||||
atom.config.set('core.themes', [
|
||||
'theme-with-index-less',
|
||||
'atom-dark-ui',
|
||||
'atom-light-ui'
|
||||
])
|
||||
|
||||
const paths = atom.themes.getImportPaths()
|
||||
|
||||
@@ -85,7 +89,9 @@ describe('atom.themes', function () {
|
||||
describe('when the core.themes config value changes', function () {
|
||||
it('add/removes stylesheets to reflect the new config value', function () {
|
||||
let didChangeActiveThemesHandler
|
||||
atom.themes.onDidChangeActiveThemes(didChangeActiveThemesHandler = jasmine.createSpy())
|
||||
atom.themes.onDidChangeActiveThemes(
|
||||
(didChangeActiveThemesHandler = jasmine.createSpy())
|
||||
)
|
||||
spyOn(atom.styles, 'getUserStyleSheetPath').andCallFake(() => null)
|
||||
|
||||
waitsForPromise(() => atom.themes.activateThemes())
|
||||
@@ -108,7 +114,11 @@ describe('atom.themes', function () {
|
||||
runs(function () {
|
||||
didChangeActiveThemesHandler.reset()
|
||||
expect(document.querySelectorAll('style[priority="1"]')).toHaveLength(2)
|
||||
expect(document.querySelector('style[priority="1"]').getAttribute('source-path')).toMatch(/atom-dark-ui/)
|
||||
expect(
|
||||
document
|
||||
.querySelector('style[priority="1"]')
|
||||
.getAttribute('source-path')
|
||||
).toMatch(/atom-dark-ui/)
|
||||
atom.config.set('core.themes', ['atom-light-ui', 'atom-dark-ui'])
|
||||
})
|
||||
|
||||
@@ -117,8 +127,16 @@ describe('atom.themes', function () {
|
||||
runs(function () {
|
||||
didChangeActiveThemesHandler.reset()
|
||||
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/)
|
||||
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', [])
|
||||
})
|
||||
|
||||
@@ -128,7 +146,10 @@ describe('atom.themes', function () {
|
||||
didChangeActiveThemesHandler.reset()
|
||||
expect(document.querySelectorAll('style[priority="1"]')).toHaveLength(2)
|
||||
// atom-dark-ui has a directory path, the syntax one doesn't
|
||||
atom.config.set('core.themes', ['theme-with-index-less', 'atom-dark-ui'])
|
||||
atom.config.set('core.themes', [
|
||||
'theme-with-index-less',
|
||||
'atom-dark-ui'
|
||||
])
|
||||
})
|
||||
|
||||
waitsFor(() => didChangeActiveThemesHandler.callCount === 1)
|
||||
@@ -145,15 +166,22 @@ describe('atom.themes', function () {
|
||||
atom.config.set('core.themes', ['atom-dark-ui', 'atom-dark-syntax'])
|
||||
|
||||
let didChangeActiveThemesHandler
|
||||
atom.themes.onDidChangeActiveThemes(didChangeActiveThemesHandler = jasmine.createSpy())
|
||||
atom.themes.onDidChangeActiveThemes(
|
||||
(didChangeActiveThemesHandler = jasmine.createSpy())
|
||||
)
|
||||
waitsForPromise(() => atom.themes.activateThemes())
|
||||
|
||||
const workspaceElement = atom.workspace.getElement()
|
||||
runs(function () {
|
||||
expect(workspaceElement).toHaveClass('theme-atom-dark-ui')
|
||||
|
||||
atom.themes.onDidChangeActiveThemes(didChangeActiveThemesHandler = jasmine.createSpy())
|
||||
atom.config.set('core.themes', ['theme-with-ui-variables', 'theme-with-syntax-variables'])
|
||||
atom.themes.onDidChangeActiveThemes(
|
||||
(didChangeActiveThemesHandler = jasmine.createSpy())
|
||||
)
|
||||
atom.config.set('core.themes', [
|
||||
'theme-with-ui-variables',
|
||||
'theme-with-syntax-variables'
|
||||
])
|
||||
})
|
||||
|
||||
waitsFor(() => didChangeActiveThemesHandler.callCount > 0)
|
||||
@@ -161,7 +189,9 @@ describe('atom.themes', function () {
|
||||
runs(function () {
|
||||
// `theme-` twice as it prefixes the name with `theme-`
|
||||
expect(workspaceElement).toHaveClass('theme-theme-with-ui-variables')
|
||||
expect(workspaceElement).toHaveClass('theme-theme-with-syntax-variables')
|
||||
expect(workspaceElement).toHaveClass(
|
||||
'theme-theme-with-syntax-variables'
|
||||
)
|
||||
expect(workspaceElement).not.toHaveClass('theme-atom-dark-ui')
|
||||
expect(workspaceElement).not.toHaveClass('theme-atom-dark-syntax')
|
||||
})
|
||||
@@ -171,11 +201,14 @@ describe('atom.themes', function () {
|
||||
describe('when a theme fails to load', () =>
|
||||
it('logs a warning', function () {
|
||||
console.warn.reset()
|
||||
atom.packages.activatePackage('a-theme-that-will-not-be-found').then(function () {}, function () {})
|
||||
atom.packages
|
||||
.activatePackage('a-theme-that-will-not-be-found')
|
||||
.then(function () {}, function () {})
|
||||
expect(console.warn.callCount).toBe(1)
|
||||
expect(console.warn.argsForCall[0][0]).toContain("Could not resolve 'a-theme-that-will-not-be-found'")
|
||||
})
|
||||
)
|
||||
expect(console.warn.argsForCall[0][0]).toContain(
|
||||
"Could not resolve 'a-theme-that-will-not-be-found'"
|
||||
)
|
||||
}))
|
||||
|
||||
describe('::requireStylesheet(path)', function () {
|
||||
beforeEach(() => jasmine.snapshotDeprecations())
|
||||
@@ -184,38 +217,60 @@ describe('atom.themes', function () {
|
||||
|
||||
it('synchronously loads css at the given path and installs a style tag for it in the head', function () {
|
||||
let styleElementAddedHandler
|
||||
atom.styles.onDidAddStyleElement(styleElementAddedHandler = jasmine.createSpy('styleElementAddedHandler'))
|
||||
atom.styles.onDidAddStyleElement(
|
||||
(styleElementAddedHandler = jasmine.createSpy(
|
||||
'styleElementAddedHandler'
|
||||
))
|
||||
)
|
||||
|
||||
const cssPath = getAbsolutePath(atom.project.getDirectories()[0], 'css.css')
|
||||
const cssPath = getAbsolutePath(
|
||||
atom.project.getDirectories()[0],
|
||||
'css.css'
|
||||
)
|
||||
const lengthBefore = document.querySelectorAll('head style').length
|
||||
|
||||
atom.themes.requireStylesheet(cssPath)
|
||||
expect(document.querySelectorAll('head style').length).toBe(lengthBefore + 1)
|
||||
expect(document.querySelectorAll('head style').length).toBe(
|
||||
lengthBefore + 1
|
||||
)
|
||||
|
||||
expect(styleElementAddedHandler).toHaveBeenCalled()
|
||||
|
||||
const element = document.querySelector('head style[source-path*="css.css"]')
|
||||
const element = document.querySelector(
|
||||
'head style[source-path*="css.css"]'
|
||||
)
|
||||
expect(element.getAttribute('source-path')).toEqualPath(cssPath)
|
||||
expect(element.textContent).toBe(fs.readFileSync(cssPath, 'utf8'))
|
||||
|
||||
// doesn't append twice
|
||||
styleElementAddedHandler.reset()
|
||||
atom.themes.requireStylesheet(cssPath)
|
||||
expect(document.querySelectorAll('head style').length).toBe(lengthBefore + 1)
|
||||
expect(document.querySelectorAll('head style').length).toBe(
|
||||
lengthBefore + 1
|
||||
)
|
||||
expect(styleElementAddedHandler).not.toHaveBeenCalled()
|
||||
|
||||
document.querySelectorAll('head style[id*="css.css"]').forEach((styleElement) => {
|
||||
styleElement.remove()
|
||||
})
|
||||
document
|
||||
.querySelectorAll('head style[id*="css.css"]')
|
||||
.forEach(styleElement => {
|
||||
styleElement.remove()
|
||||
})
|
||||
})
|
||||
|
||||
it('synchronously loads and parses less files at the given path and installs a style tag for it in the head', function () {
|
||||
const lessPath = getAbsolutePath(atom.project.getDirectories()[0], 'sample.less')
|
||||
const lessPath = getAbsolutePath(
|
||||
atom.project.getDirectories()[0],
|
||||
'sample.less'
|
||||
)
|
||||
const lengthBefore = document.querySelectorAll('head style').length
|
||||
atom.themes.requireStylesheet(lessPath)
|
||||
expect(document.querySelectorAll('head style').length).toBe(lengthBefore + 1)
|
||||
expect(document.querySelectorAll('head style').length).toBe(
|
||||
lengthBefore + 1
|
||||
)
|
||||
|
||||
const element = document.querySelector('head style[source-path*="sample.less"]')
|
||||
const element = document.querySelector(
|
||||
'head style[source-path*="sample.less"]'
|
||||
)
|
||||
expect(element.getAttribute('source-path')).toEqualPath(lessPath)
|
||||
expect(element.textContent.toLowerCase()).toBe(`\
|
||||
#header {
|
||||
@@ -225,24 +280,37 @@ h2 {
|
||||
color: #4d926f;
|
||||
}
|
||||
\
|
||||
`
|
||||
)
|
||||
`)
|
||||
|
||||
// doesn't append twice
|
||||
atom.themes.requireStylesheet(lessPath)
|
||||
expect(document.querySelectorAll('head style').length).toBe(lengthBefore + 1)
|
||||
document.querySelectorAll('head style[id*="sample.less"]').forEach((styleElement) => {
|
||||
styleElement.remove()
|
||||
})
|
||||
expect(document.querySelectorAll('head style').length).toBe(
|
||||
lengthBefore + 1
|
||||
)
|
||||
document
|
||||
.querySelectorAll('head style[id*="sample.less"]')
|
||||
.forEach(styleElement => {
|
||||
styleElement.remove()
|
||||
})
|
||||
})
|
||||
|
||||
it('supports requiring css and less stylesheets without an explicit extension', function () {
|
||||
atom.themes.requireStylesheet(path.join(__dirname, 'fixtures', 'css'))
|
||||
expect(document.querySelector('head style[source-path*="css.css"]').getAttribute('source-path'))
|
||||
.toEqualPath(getAbsolutePath(atom.project.getDirectories()[0], 'css.css'))
|
||||
expect(
|
||||
document
|
||||
.querySelector('head style[source-path*="css.css"]')
|
||||
.getAttribute('source-path')
|
||||
).toEqualPath(
|
||||
getAbsolutePath(atom.project.getDirectories()[0], 'css.css')
|
||||
)
|
||||
atom.themes.requireStylesheet(path.join(__dirname, 'fixtures', 'sample'))
|
||||
expect(document.querySelector('head style[source-path*="sample.less"]').getAttribute('source-path'))
|
||||
.toEqualPath(getAbsolutePath(atom.project.getDirectories()[0], 'sample.less'))
|
||||
expect(
|
||||
document
|
||||
.querySelector('head style[source-path*="sample.less"]')
|
||||
.getAttribute('source-path')
|
||||
).toEqualPath(
|
||||
getAbsolutePath(atom.project.getDirectories()[0], 'sample.less')
|
||||
)
|
||||
|
||||
document.querySelector('head style[source-path*="css.css"]').remove()
|
||||
document.querySelector('head style[source-path*="sample.less"]').remove()
|
||||
@@ -256,7 +324,11 @@ h2 {
|
||||
expect(getComputedStyle(document.body).fontWeight).toBe('bold')
|
||||
|
||||
let styleElementRemovedHandler
|
||||
atom.styles.onDidRemoveStyleElement(styleElementRemovedHandler = jasmine.createSpy('styleElementRemovedHandler'))
|
||||
atom.styles.onDidRemoveStyleElement(
|
||||
(styleElementRemovedHandler = jasmine.createSpy(
|
||||
'styleElementRemovedHandler'
|
||||
))
|
||||
)
|
||||
|
||||
disposable.dispose()
|
||||
|
||||
@@ -277,46 +349,74 @@ h2 {
|
||||
|
||||
it("loads the correct values from the theme's ui-variables file", function () {
|
||||
let didChangeActiveThemesHandler
|
||||
atom.themes.onDidChangeActiveThemes(didChangeActiveThemesHandler = jasmine.createSpy())
|
||||
atom.config.set('core.themes', ['theme-with-ui-variables', 'theme-with-syntax-variables'])
|
||||
atom.themes.onDidChangeActiveThemes(
|
||||
(didChangeActiveThemesHandler = jasmine.createSpy())
|
||||
)
|
||||
atom.config.set('core.themes', [
|
||||
'theme-with-ui-variables',
|
||||
'theme-with-syntax-variables'
|
||||
])
|
||||
|
||||
waitsFor(() => didChangeActiveThemesHandler.callCount > 0)
|
||||
|
||||
runs(function () {
|
||||
// an override loaded in the base css
|
||||
expect(getComputedStyle(atom.workspace.getElement())['background-color']).toBe('rgb(0, 0, 255)')
|
||||
expect(
|
||||
getComputedStyle(atom.workspace.getElement())['background-color']
|
||||
).toBe('rgb(0, 0, 255)')
|
||||
|
||||
// from within the theme itself
|
||||
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')
|
||||
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', function () {
|
||||
let didChangeActiveThemesHandler
|
||||
atom.themes.onDidChangeActiveThemes(didChangeActiveThemesHandler = jasmine.createSpy())
|
||||
atom.config.set('core.themes', ['theme-with-incomplete-ui-variables', 'theme-with-syntax-variables'])
|
||||
atom.themes.onDidChangeActiveThemes(
|
||||
(didChangeActiveThemesHandler = jasmine.createSpy())
|
||||
)
|
||||
atom.config.set('core.themes', [
|
||||
'theme-with-incomplete-ui-variables',
|
||||
'theme-with-syntax-variables'
|
||||
])
|
||||
|
||||
waitsFor(() => didChangeActiveThemesHandler.callCount > 0)
|
||||
|
||||
runs(function () {
|
||||
// an override loaded in the base css
|
||||
expect(getComputedStyle(atom.workspace.getElement())['background-color']).toBe('rgb(0, 0, 255)')
|
||||
expect(
|
||||
getComputedStyle(atom.workspace.getElement())['background-color']
|
||||
).toBe('rgb(0, 0, 255)')
|
||||
|
||||
// from within the theme itself
|
||||
expect(getComputedStyle(document.querySelector('atom-text-editor')).backgroundColor).toBe('rgb(0, 152, 255)')
|
||||
expect(
|
||||
getComputedStyle(document.querySelector('atom-text-editor'))
|
||||
.backgroundColor
|
||||
).toBe('rgb(0, 152, 255)')
|
||||
})
|
||||
})
|
||||
)
|
||||
}))
|
||||
})
|
||||
|
||||
describe('user stylesheet', function () {
|
||||
let userStylesheetPath
|
||||
beforeEach(function () {
|
||||
userStylesheetPath = path.join(temp.mkdirSync('atom'), 'styles.less')
|
||||
fs.writeFileSync(userStylesheetPath, 'body {border-style: dotted !important;}')
|
||||
fs.writeFileSync(
|
||||
userStylesheetPath,
|
||||
'body {border-style: dotted !important;}'
|
||||
)
|
||||
spyOn(atom.styles, 'getUserStyleSheetPath').andReturn(userStylesheetPath)
|
||||
})
|
||||
|
||||
@@ -331,8 +431,16 @@ h2 {
|
||||
waitsForPromise(() => atom.themes.activateThemes())
|
||||
|
||||
runs(function () {
|
||||
atom.styles.onDidRemoveStyleElement(styleElementRemovedHandler = jasmine.createSpy('styleElementRemovedHandler'))
|
||||
atom.styles.onDidAddStyleElement(styleElementAddedHandler = jasmine.createSpy('styleElementAddedHandler'))
|
||||
atom.styles.onDidRemoveStyleElement(
|
||||
(styleElementRemovedHandler = jasmine.createSpy(
|
||||
'styleElementRemovedHandler'
|
||||
))
|
||||
)
|
||||
atom.styles.onDidAddStyleElement(
|
||||
(styleElementAddedHandler = jasmine.createSpy(
|
||||
'styleElementAddedHandler'
|
||||
))
|
||||
)
|
||||
|
||||
spyOn(atom.themes, 'loadUserStylesheet').andCallThrough()
|
||||
|
||||
@@ -346,10 +454,14 @@ h2 {
|
||||
expect(getComputedStyle(document.body).borderStyle).toBe('dashed')
|
||||
|
||||
expect(styleElementRemovedHandler).toHaveBeenCalled()
|
||||
expect(styleElementRemovedHandler.argsForCall[0][0].textContent).toContain('dotted')
|
||||
expect(
|
||||
styleElementRemovedHandler.argsForCall[0][0].textContent
|
||||
).toContain('dotted')
|
||||
|
||||
expect(styleElementAddedHandler).toHaveBeenCalled()
|
||||
expect(styleElementAddedHandler.argsForCall[0][0].textContent).toContain('dashed')
|
||||
expect(
|
||||
styleElementAddedHandler.argsForCall[0][0].textContent
|
||||
).toContain('dashed')
|
||||
|
||||
styleElementRemovedHandler.reset()
|
||||
fs.removeSync(userStylesheetPath)
|
||||
@@ -359,7 +471,9 @@ h2 {
|
||||
|
||||
runs(function () {
|
||||
expect(styleElementRemovedHandler).toHaveBeenCalled()
|
||||
expect(styleElementRemovedHandler.argsForCall[0][0].textContent).toContain('dashed')
|
||||
expect(
|
||||
styleElementRemovedHandler.argsForCall[0][0].textContent
|
||||
).toContain('dashed')
|
||||
expect(getComputedStyle(document.body).borderStyle).toBe('none')
|
||||
})
|
||||
})
|
||||
@@ -372,7 +486,9 @@ h2 {
|
||||
spyOn(atom.themes.lessCache, 'cssForFile').andCallFake(function () {
|
||||
throw new Error('EACCES permission denied "styles.less"')
|
||||
})
|
||||
atom.notifications.onDidAddNotification(addErrorHandler = jasmine.createSpy())
|
||||
atom.notifications.onDidAddNotification(
|
||||
(addErrorHandler = jasmine.createSpy())
|
||||
)
|
||||
})
|
||||
|
||||
it('creates an error notification and does not add the stylesheet', function () {
|
||||
@@ -381,21 +497,25 @@ h2 {
|
||||
const note = addErrorHandler.mostRecentCall.args[0]
|
||||
expect(note.getType()).toBe('error')
|
||||
expect(note.getMessage()).toContain('Error loading')
|
||||
expect(atom.styles.styleElementsBySourcePath[atom.styles.getUserStyleSheetPath()]).toBeUndefined()
|
||||
expect(
|
||||
atom.styles.styleElementsBySourcePath[atom.styles.getUserStyleSheetPath()]
|
||||
).toBeUndefined()
|
||||
})
|
||||
})
|
||||
|
||||
describe('when there is an error watching the user stylesheet', function () {
|
||||
let addErrorHandler = null
|
||||
beforeEach(function () {
|
||||
const {File} = require('pathwatcher')
|
||||
const { File } = require('pathwatcher')
|
||||
spyOn(File.prototype, 'on').andCallFake(function (event) {
|
||||
if (event.indexOf('contents-changed') > -1) {
|
||||
throw new Error('Unable to watch path')
|
||||
}
|
||||
})
|
||||
spyOn(atom.themes, 'loadStylesheet').andReturn('')
|
||||
atom.notifications.onDidAddNotification(addErrorHandler = jasmine.createSpy())
|
||||
atom.notifications.onDidAddNotification(
|
||||
(addErrorHandler = jasmine.createSpy())
|
||||
)
|
||||
})
|
||||
|
||||
it('creates an error notification', function () {
|
||||
@@ -410,16 +530,25 @@ h2 {
|
||||
it("adds a notification when a theme's stylesheet is invalid", function () {
|
||||
const addErrorHandler = jasmine.createSpy()
|
||||
atom.notifications.onDidAddNotification(addErrorHandler)
|
||||
expect(() => atom.packages.activatePackage('theme-with-invalid-styles').then(function () {}, function () {})).not.toThrow()
|
||||
expect(() =>
|
||||
atom.packages
|
||||
.activatePackage('theme-with-invalid-styles')
|
||||
.then(function () {}, function () {})
|
||||
).not.toThrow()
|
||||
expect(addErrorHandler.callCount).toBe(2)
|
||||
expect(addErrorHandler.argsForCall[1][0].message).toContain('Failed to activate the theme-with-invalid-styles theme')
|
||||
expect(addErrorHandler.argsForCall[1][0].message).toContain(
|
||||
'Failed to activate the theme-with-invalid-styles theme'
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('when a non-existent theme is present in the config', function () {
|
||||
beforeEach(function () {
|
||||
console.warn.reset()
|
||||
atom.config.set('core.themes', ['non-existent-dark-ui', 'non-existent-dark-syntax'])
|
||||
atom.config.set('core.themes', [
|
||||
'non-existent-dark-ui',
|
||||
'non-existent-dark-syntax'
|
||||
])
|
||||
|
||||
waitsForPromise(() => atom.themes.activateThemes())
|
||||
})
|
||||
@@ -451,7 +580,10 @@ h2 {
|
||||
|
||||
describe('when the enabled UI and syntax themes are not bundled with Atom', function () {
|
||||
beforeEach(function () {
|
||||
atom.config.set('core.themes', ['installed-dark-ui', 'installed-dark-syntax'])
|
||||
atom.config.set('core.themes', [
|
||||
'installed-dark-ui',
|
||||
'installed-dark-syntax'
|
||||
])
|
||||
|
||||
waitsForPromise(() => atom.themes.activateThemes())
|
||||
})
|
||||
@@ -466,7 +598,10 @@ h2 {
|
||||
|
||||
describe('when the enabled UI theme is not bundled with Atom', function () {
|
||||
beforeEach(function () {
|
||||
atom.config.set('core.themes', ['installed-dark-ui', 'atom-light-syntax'])
|
||||
atom.config.set('core.themes', [
|
||||
'installed-dark-ui',
|
||||
'atom-light-syntax'
|
||||
])
|
||||
|
||||
waitsForPromise(() => atom.themes.activateThemes())
|
||||
})
|
||||
@@ -481,7 +616,10 @@ h2 {
|
||||
|
||||
describe('when the enabled syntax theme is not bundled with Atom', function () {
|
||||
beforeEach(function () {
|
||||
atom.config.set('core.themes', ['atom-light-ui', 'installed-dark-syntax'])
|
||||
atom.config.set('core.themes', [
|
||||
'atom-light-ui',
|
||||
'installed-dark-syntax'
|
||||
])
|
||||
|
||||
waitsForPromise(() => atom.themes.activateThemes())
|
||||
})
|
||||
|
||||
@@ -8,20 +8,28 @@ describe('TitleBar', () => {
|
||||
themes: atom.themes,
|
||||
applicationDelegate: atom.applicationDelegate
|
||||
})
|
||||
expect(titleBar.element.querySelector('.title').textContent).toBe(document.title)
|
||||
expect(titleBar.element.querySelector('.title').textContent).toBe(
|
||||
document.title
|
||||
)
|
||||
|
||||
const paneItem = new FakePaneItem('Title 1')
|
||||
atom.workspace.getActivePane().activateItem(paneItem)
|
||||
expect(document.title).toMatch('Title 1')
|
||||
expect(titleBar.element.querySelector('.title').textContent).toBe(document.title)
|
||||
expect(titleBar.element.querySelector('.title').textContent).toBe(
|
||||
document.title
|
||||
)
|
||||
|
||||
paneItem.setTitle('Title 2')
|
||||
expect(document.title).toMatch('Title 2')
|
||||
expect(titleBar.element.querySelector('.title').textContent).toBe(document.title)
|
||||
expect(titleBar.element.querySelector('.title').textContent).toBe(
|
||||
document.title
|
||||
)
|
||||
|
||||
atom.project.setPaths([temp.mkdirSync('project-1')])
|
||||
expect(document.title).toMatch('project-1')
|
||||
expect(titleBar.element.querySelector('.title').textContent).toBe(document.title)
|
||||
expect(titleBar.element.querySelector('.title').textContent).toBe(
|
||||
document.title
|
||||
)
|
||||
})
|
||||
|
||||
it('can update the sheet offset for the current window based on its height', () => {
|
||||
@@ -46,7 +54,9 @@ class FakePaneItem {
|
||||
onDidChangeTitle (callback) {
|
||||
this.didChangeTitleCallback = callback
|
||||
return {
|
||||
dispose: () => { this.didChangeTitleCallback = null }
|
||||
dispose: () => {
|
||||
this.didChangeTitleCallback = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const {CompositeDisposable} = require('atom')
|
||||
const { CompositeDisposable } = require('atom')
|
||||
const TooltipManager = require('../src/tooltip-manager')
|
||||
const Tooltip = require('../src/tooltip')
|
||||
const _ = require('underscore-plus')
|
||||
@@ -18,25 +18,30 @@ describe('TooltipManager', () => {
|
||||
}
|
||||
|
||||
beforeEach(function () {
|
||||
manager = new TooltipManager({keymapManager: atom.keymaps, viewRegistry: atom.views})
|
||||
manager = new TooltipManager({
|
||||
keymapManager: atom.keymaps,
|
||||
viewRegistry: atom.views
|
||||
})
|
||||
element = createElement('foo')
|
||||
})
|
||||
|
||||
describe('::add(target, options)', () => {
|
||||
describe("when the trigger is 'hover' (the default)", () => {
|
||||
it('creates a tooltip when hovering over the target element', () => {
|
||||
manager.add(element, {title: 'Title'})
|
||||
hover(element, () => expect(document.body.querySelector('.tooltip')).toHaveText('Title'))
|
||||
manager.add(element, { title: 'Title' })
|
||||
hover(element, () =>
|
||||
expect(document.body.querySelector('.tooltip')).toHaveText('Title')
|
||||
)
|
||||
})
|
||||
|
||||
it('displays tooltips immediately when hovering over new elements once a tooltip has been displayed once', () => {
|
||||
const disposables = new CompositeDisposable()
|
||||
const element1 = createElement('foo')
|
||||
disposables.add(manager.add(element1, {title: 'Title'}))
|
||||
disposables.add(manager.add(element1, { title: 'Title' }))
|
||||
const element2 = createElement('bar')
|
||||
disposables.add(manager.add(element2, {title: 'Title'}))
|
||||
disposables.add(manager.add(element2, { title: 'Title' }))
|
||||
const element3 = createElement('baz')
|
||||
disposables.add(manager.add(element3, {title: 'Title'}))
|
||||
disposables.add(manager.add(element3, { title: 'Title' }))
|
||||
|
||||
hover(element1, () => {})
|
||||
expect(document.body.querySelector('.tooltip')).toBeNull()
|
||||
@@ -57,12 +62,17 @@ describe('TooltipManager', () => {
|
||||
})
|
||||
|
||||
it('hides the tooltip on keydown events', () => {
|
||||
const disposable = manager.add(element, { title: 'Title', trigger: 'hover' })
|
||||
const disposable = manager.add(element, {
|
||||
title: 'Title',
|
||||
trigger: 'hover'
|
||||
})
|
||||
hover(element, function () {
|
||||
expect(document.body.querySelector('.tooltip')).not.toBeNull()
|
||||
window.dispatchEvent(new CustomEvent('keydown', {
|
||||
bubbles: true
|
||||
}))
|
||||
window.dispatchEvent(
|
||||
new CustomEvent('keydown', {
|
||||
bubbles: true
|
||||
})
|
||||
)
|
||||
expect(document.body.querySelector('.tooltip')).toBeNull()
|
||||
disposable.dispose()
|
||||
})
|
||||
@@ -71,16 +81,18 @@ describe('TooltipManager', () => {
|
||||
|
||||
describe("when the trigger is 'manual'", () =>
|
||||
it('creates a tooltip immediately and only hides it on dispose', () => {
|
||||
const disposable = manager.add(element, {title: 'Title', trigger: 'manual'})
|
||||
const disposable = manager.add(element, {
|
||||
title: 'Title',
|
||||
trigger: 'manual'
|
||||
})
|
||||
expect(document.body.querySelector('.tooltip')).toHaveText('Title')
|
||||
disposable.dispose()
|
||||
expect(document.body.querySelector('.tooltip')).toBeNull()
|
||||
})
|
||||
)
|
||||
}))
|
||||
|
||||
describe("when the trigger is 'click'", () =>
|
||||
it('shows and hides the tooltip when the target element is clicked', () => {
|
||||
manager.add(element, {title: 'Title', trigger: 'click'})
|
||||
manager.add(element, { title: 'Title', trigger: 'click' })
|
||||
expect(document.body.querySelector('.tooltip')).toBeNull()
|
||||
element.click()
|
||||
expect(document.body.querySelector('.tooltip')).not.toBeNull()
|
||||
@@ -102,16 +114,17 @@ describe('TooltipManager', () => {
|
||||
expect(document.body.querySelector('.tooltip')).not.toBeNull()
|
||||
element.click()
|
||||
expect(document.body.querySelector('.tooltip')).toBeNull()
|
||||
})
|
||||
)
|
||||
}))
|
||||
|
||||
it('does not hide the tooltip on keyboard input', () => {
|
||||
manager.add(element, {title: 'Title', trigger: 'click'})
|
||||
manager.add(element, { title: 'Title', trigger: 'click' })
|
||||
element.click()
|
||||
expect(document.body.querySelector('.tooltip')).not.toBeNull()
|
||||
window.dispatchEvent(new CustomEvent('keydown', {
|
||||
bubbles: true
|
||||
}))
|
||||
window.dispatchEvent(
|
||||
new CustomEvent('keydown', {
|
||||
bubbles: true
|
||||
})
|
||||
)
|
||||
expect(document.body.querySelector('.tooltip')).not.toBeNull()
|
||||
// click again to hide the tooltip because otherwise state leaks
|
||||
// into other tests.
|
||||
@@ -120,13 +133,21 @@ describe('TooltipManager', () => {
|
||||
|
||||
it('allows a custom item to be specified for the content of the tooltip', () => {
|
||||
const tooltipElement = document.createElement('div')
|
||||
manager.add(element, {item: {element: tooltipElement}})
|
||||
hover(element, () => expect(tooltipElement.closest('.tooltip')).not.toBeNull())
|
||||
manager.add(element, { item: { element: tooltipElement } })
|
||||
hover(element, () =>
|
||||
expect(tooltipElement.closest('.tooltip')).not.toBeNull()
|
||||
)
|
||||
})
|
||||
|
||||
it('allows a custom class to be specified for the tooltip', () => {
|
||||
manager.add(element, {title: 'Title', class: 'custom-tooltip-class'})
|
||||
hover(element, () => expect(document.body.querySelector('.tooltip').classList.contains('custom-tooltip-class')).toBe(true))
|
||||
manager.add(element, { title: 'Title', class: 'custom-tooltip-class' })
|
||||
hover(element, () =>
|
||||
expect(
|
||||
document.body
|
||||
.querySelector('.tooltip')
|
||||
.classList.contains('custom-tooltip-class')
|
||||
).toBe(true)
|
||||
)
|
||||
})
|
||||
|
||||
it('allows jQuery elements to be passed as the target', () => {
|
||||
@@ -139,63 +160,71 @@ describe('TooltipManager', () => {
|
||||
length: 2,
|
||||
jquery: 'any-version'
|
||||
}
|
||||
const disposable = manager.add(fakeJqueryWrapper, {title: 'Title'})
|
||||
const disposable = manager.add(fakeJqueryWrapper, { title: 'Title' })
|
||||
|
||||
hover(element, () => expect(document.body.querySelector('.tooltip')).toHaveText('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'))
|
||||
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())
|
||||
hover(element, () =>
|
||||
expect(document.body.querySelector('.tooltip')).toBeNull()
|
||||
)
|
||||
hover(element2, () =>
|
||||
expect(document.body.querySelector('.tooltip')).toBeNull()
|
||||
)
|
||||
})
|
||||
|
||||
describe('when a keyBindingCommand is specified', () => {
|
||||
describe('when a title is specified', () =>
|
||||
it('appends the key binding corresponding to the command to the title', () => {
|
||||
atom.keymaps.add('test', {
|
||||
'.foo': { 'ctrl-x ctrl-y': 'test-command'
|
||||
},
|
||||
'.bar': { 'ctrl-x ctrl-z': 'test-command'
|
||||
}
|
||||
}
|
||||
)
|
||||
'.foo': { 'ctrl-x ctrl-y': 'test-command' },
|
||||
'.bar': { 'ctrl-x ctrl-z': 'test-command' }
|
||||
})
|
||||
|
||||
manager.add(element, {title: 'Title', keyBindingCommand: 'test-command'})
|
||||
manager.add(element, {
|
||||
title: 'Title',
|
||||
keyBindingCommand: 'test-command'
|
||||
})
|
||||
|
||||
hover(element, function () {
|
||||
const tooltipElement = document.body.querySelector('.tooltip')
|
||||
expect(tooltipElement).toHaveText(`Title ${ctrlX} ${ctrlY}`)
|
||||
})
|
||||
})
|
||||
)
|
||||
}))
|
||||
|
||||
describe('when no title is specified', () =>
|
||||
it('shows the key binding corresponding to the command alone', () => {
|
||||
atom.keymaps.add('test', {'.foo': {'ctrl-x ctrl-y': 'test-command'}})
|
||||
atom.keymaps.add('test', {
|
||||
'.foo': { 'ctrl-x ctrl-y': 'test-command' }
|
||||
})
|
||||
|
||||
manager.add(element, {keyBindingCommand: 'test-command'})
|
||||
manager.add(element, { keyBindingCommand: 'test-command' })
|
||||
|
||||
hover(element, function () {
|
||||
const tooltipElement = document.body.querySelector('.tooltip')
|
||||
expect(tooltipElement).toHaveText(`${ctrlX} ${ctrlY}`)
|
||||
})
|
||||
})
|
||||
)
|
||||
}))
|
||||
|
||||
describe('when a keyBindingTarget is specified', () => {
|
||||
it('looks up the key binding relative to the target', () => {
|
||||
atom.keymaps.add('test', {
|
||||
'.bar': { 'ctrl-x ctrl-z': 'test-command'
|
||||
},
|
||||
'.foo': { 'ctrl-x ctrl-y': 'test-command'
|
||||
}
|
||||
}
|
||||
)
|
||||
'.bar': { 'ctrl-x ctrl-z': 'test-command' },
|
||||
'.foo': { 'ctrl-x ctrl-y': 'test-command' }
|
||||
})
|
||||
|
||||
manager.add(element, {keyBindingCommand: 'test-command', keyBindingTarget: element})
|
||||
manager.add(element, {
|
||||
keyBindingCommand: 'test-command',
|
||||
keyBindingTarget: element
|
||||
})
|
||||
|
||||
hover(element, function () {
|
||||
const tooltipElement = document.body.querySelector('.tooltip')
|
||||
@@ -204,7 +233,11 @@ describe('TooltipManager', () => {
|
||||
})
|
||||
|
||||
it('does not display the keybinding if there is nothing mapped to the specified keyBindingCommand', () => {
|
||||
manager.add(element, {title: 'A Title', keyBindingCommand: 'test-command', keyBindingTarget: element})
|
||||
manager.add(element, {
|
||||
title: 'A Title',
|
||||
keyBindingCommand: 'test-command',
|
||||
keyBindingTarget: element
|
||||
})
|
||||
|
||||
hover(element, function () {
|
||||
const tooltipElement = document.body.querySelector('.tooltip')
|
||||
@@ -216,34 +249,36 @@ describe('TooltipManager', () => {
|
||||
|
||||
describe('when .dispose() is called on the returned disposable', () =>
|
||||
it('no longer displays the tooltip on hover', () => {
|
||||
const disposable = manager.add(element, {title: 'Title'})
|
||||
const disposable = manager.add(element, { title: 'Title' })
|
||||
|
||||
hover(element, () => expect(document.body.querySelector('.tooltip')).toHaveText('Title'))
|
||||
hover(element, () =>
|
||||
expect(document.body.querySelector('.tooltip')).toHaveText('Title')
|
||||
)
|
||||
|
||||
disposable.dispose()
|
||||
|
||||
hover(element, () => expect(document.body.querySelector('.tooltip')).toBeNull())
|
||||
})
|
||||
)
|
||||
hover(element, () =>
|
||||
expect(document.body.querySelector('.tooltip')).toBeNull()
|
||||
)
|
||||
}))
|
||||
|
||||
describe('when the window is resized', () =>
|
||||
it('hides the tooltips', () => {
|
||||
const disposable = manager.add(element, {title: 'Title'})
|
||||
const disposable = manager.add(element, { title: 'Title' })
|
||||
hover(element, function () {
|
||||
expect(document.body.querySelector('.tooltip')).not.toBeNull()
|
||||
window.dispatchEvent(new CustomEvent('resize'))
|
||||
expect(document.body.querySelector('.tooltip')).toBeNull()
|
||||
disposable.dispose()
|
||||
})
|
||||
})
|
||||
)
|
||||
}))
|
||||
|
||||
describe('findTooltips', () => {
|
||||
it('adds and remove tooltips correctly', () => {
|
||||
expect(manager.findTooltips(element).length).toBe(0)
|
||||
const disposable1 = manager.add(element, {title: 'elem1'})
|
||||
const disposable1 = manager.add(element, { title: 'elem1' })
|
||||
expect(manager.findTooltips(element).length).toBe(1)
|
||||
const disposable2 = manager.add(element, {title: 'elem2'})
|
||||
const disposable2 = manager.add(element, { title: 'elem2' })
|
||||
expect(manager.findTooltips(element).length).toBe(2)
|
||||
disposable1.dispose()
|
||||
expect(manager.findTooltips(element).length).toBe(1)
|
||||
@@ -252,7 +287,7 @@ describe('TooltipManager', () => {
|
||||
})
|
||||
|
||||
it('lets us hide tooltips programmatically', () => {
|
||||
const disposable = manager.add(element, {title: 'Title'})
|
||||
const disposable = manager.add(element, { title: 'Title' })
|
||||
hover(element, function () {
|
||||
expect(document.body.querySelector('.tooltip')).not.toBeNull()
|
||||
manager.findTooltips(element)[0].hide()
|
||||
@@ -272,11 +307,11 @@ function createElement (className) {
|
||||
}
|
||||
|
||||
function mouseEnter (element) {
|
||||
element.dispatchEvent(new CustomEvent('mouseenter', {bubbles: false}))
|
||||
element.dispatchEvent(new CustomEvent('mouseover', {bubbles: true}))
|
||||
element.dispatchEvent(new CustomEvent('mouseenter', { bubbles: false }))
|
||||
element.dispatchEvent(new CustomEvent('mouseover', { bubbles: true }))
|
||||
}
|
||||
|
||||
function mouseLeave (element) {
|
||||
element.dispatchEvent(new CustomEvent('mouseleave', {bubbles: false}))
|
||||
element.dispatchEvent(new CustomEvent('mouseout', {bubbles: true}))
|
||||
element.dispatchEvent(new CustomEvent('mouseleave', { bubbles: false }))
|
||||
element.dispatchEvent(new CustomEvent('mouseout', { bubbles: true }))
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,12 +1,14 @@
|
||||
/** @babel */
|
||||
/* eslint-env jasmine */
|
||||
|
||||
import {it, fit, ffit, fffit, beforeEach, afterEach} from './async-spec-helpers'
|
||||
import { it, beforeEach, afterEach } from './async-spec-helpers'
|
||||
import path from 'path'
|
||||
import childProcess from 'child_process'
|
||||
import {updateProcessEnv, shouldGetEnvFromShell} from '../src/update-process-env'
|
||||
import {
|
||||
updateProcessEnv,
|
||||
shouldGetEnvFromShell
|
||||
} from '../src/update-process-env'
|
||||
import dedent from 'dedent'
|
||||
import {EventEmitter} from 'events'
|
||||
import mockSpawn from 'mock-spawn'
|
||||
const temp = require('temp').track()
|
||||
|
||||
@@ -46,7 +48,13 @@ describe('updateProcessEnv(launchEnv)', function () {
|
||||
|
||||
const initialProcessEnv = process.env
|
||||
|
||||
await updateProcessEnv({ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true', PWD: '/the/dir', TERM: 'xterm-something', KEY1: 'value1', KEY2: 'value2'})
|
||||
await updateProcessEnv({
|
||||
ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true',
|
||||
PWD: '/the/dir',
|
||||
TERM: 'xterm-something',
|
||||
KEY1: 'value1',
|
||||
KEY2: 'value2'
|
||||
})
|
||||
expect(process.env).toEqual({
|
||||
ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true',
|
||||
PWD: '/the/dir',
|
||||
@@ -74,7 +82,12 @@ describe('updateProcessEnv(launchEnv)', function () {
|
||||
|
||||
const initialProcessEnv = process.env
|
||||
|
||||
await updateProcessEnv({ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true', PROMPT: '$P$G', KEY1: 'value1', KEY2: 'value2'})
|
||||
await updateProcessEnv({
|
||||
ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true',
|
||||
PROMPT: '$P$G',
|
||||
KEY1: 'value1',
|
||||
KEY2: 'value2'
|
||||
})
|
||||
expect(process.env).toEqual({
|
||||
ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true',
|
||||
PROMPT: '$P$G',
|
||||
@@ -103,13 +116,15 @@ describe('updateProcessEnv(launchEnv)', function () {
|
||||
|
||||
await updateProcessEnv({
|
||||
ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true',
|
||||
PSModulePath: 'C:\\Program Files\\WindowsPowerShell\\Modules;C:\\WINDOWS\\system32\\WindowsPowerShell\\v1.0\\Modules\\',
|
||||
PSModulePath:
|
||||
'C:\\Program Files\\WindowsPowerShell\\Modules;C:\\WINDOWS\\system32\\WindowsPowerShell\\v1.0\\Modules\\',
|
||||
KEY1: 'value1',
|
||||
KEY2: 'value2'
|
||||
})
|
||||
expect(process.env).toEqual({
|
||||
ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true',
|
||||
PSModulePath: 'C:\\Program Files\\WindowsPowerShell\\Modules;C:\\WINDOWS\\system32\\WindowsPowerShell\\v1.0\\Modules\\',
|
||||
PSModulePath:
|
||||
'C:\\Program Files\\WindowsPowerShell\\Modules;C:\\WINDOWS\\system32\\WindowsPowerShell\\v1.0\\Modules\\',
|
||||
KEY1: 'value1',
|
||||
KEY2: 'value2',
|
||||
NODE_ENV: 'the-node-env',
|
||||
@@ -133,7 +148,10 @@ describe('updateProcessEnv(launchEnv)', function () {
|
||||
ATOM_HOME: '/the/atom/home'
|
||||
}
|
||||
|
||||
await updateProcessEnv({ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true', PWD: '/the/dir'})
|
||||
await updateProcessEnv({
|
||||
ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true',
|
||||
PWD: '/the/dir'
|
||||
})
|
||||
expect(process.env).toEqual({
|
||||
PWD: '/the/dir',
|
||||
ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true',
|
||||
@@ -142,7 +160,11 @@ describe('updateProcessEnv(launchEnv)', function () {
|
||||
ATOM_HOME: '/the/atom/home'
|
||||
})
|
||||
|
||||
await updateProcessEnv({ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true', PWD: '/the/dir', ATOM_HOME: path.join(newAtomHomePath, 'non-existent')})
|
||||
await updateProcessEnv({
|
||||
ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true',
|
||||
PWD: '/the/dir',
|
||||
ATOM_HOME: path.join(newAtomHomePath, 'non-existent')
|
||||
})
|
||||
expect(process.env).toEqual({
|
||||
ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true',
|
||||
PWD: '/the/dir',
|
||||
@@ -151,7 +173,11 @@ describe('updateProcessEnv(launchEnv)', function () {
|
||||
ATOM_HOME: '/the/atom/home'
|
||||
})
|
||||
|
||||
await updateProcessEnv({ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true', PWD: '/the/dir', ATOM_HOME: newAtomHomePath})
|
||||
await updateProcessEnv({
|
||||
ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true',
|
||||
PWD: '/the/dir',
|
||||
ATOM_HOME: newAtomHomePath
|
||||
})
|
||||
expect(process.env).toEqual({
|
||||
ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true',
|
||||
PWD: '/the/dir',
|
||||
@@ -169,7 +195,13 @@ describe('updateProcessEnv(launchEnv)', function () {
|
||||
ATOM_HOME: '/the/atom/home'
|
||||
}
|
||||
|
||||
await updateProcessEnv({ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true', PWD: '/the/dir', NODE_ENV: 'the-node-env', NODE_PATH: '/the/node/path', ATOM_HOME: '/the/atom/home'})
|
||||
await updateProcessEnv({
|
||||
ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true',
|
||||
PWD: '/the/dir',
|
||||
NODE_ENV: 'the-node-env',
|
||||
NODE_PATH: '/the/node/path',
|
||||
ATOM_HOME: '/the/atom/home'
|
||||
})
|
||||
expect(process.env).toEqual({
|
||||
ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true',
|
||||
PWD: '/the/dir',
|
||||
@@ -178,7 +210,12 @@ describe('updateProcessEnv(launchEnv)', function () {
|
||||
ATOM_HOME: '/the/atom/home'
|
||||
})
|
||||
|
||||
await updateProcessEnv({PWD: '/the/dir', NODE_ENV: 'the-node-env', NODE_PATH: '/the/node/path', ATOM_HOME: '/the/atom/home'})
|
||||
await updateProcessEnv({
|
||||
PWD: '/the/dir',
|
||||
NODE_ENV: 'the-node-env',
|
||||
NODE_PATH: '/the/node/path',
|
||||
ATOM_HOME: '/the/atom/home'
|
||||
})
|
||||
expect(process.env).toEqual({
|
||||
ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true',
|
||||
PWD: '/the/dir',
|
||||
@@ -215,16 +252,21 @@ describe('updateProcessEnv(launchEnv)', function () {
|
||||
|
||||
describe('when the launch environment does not come from a shell', function () {
|
||||
describe('on macOS', function () {
|
||||
it('updates process.env to match the environment in the user\'s login shell', async function () {
|
||||
it("updates process.env to match the environment in the user's login shell", async function () {
|
||||
if (process.platform === 'win32') return // TestsThatFailOnWin32
|
||||
|
||||
process.platform = 'darwin'
|
||||
process.env.SHELL = '/my/custom/bash'
|
||||
spawn.setDefault(spawn.simple(0, dedent`
|
||||
spawn.setDefault(
|
||||
spawn.simple(
|
||||
0,
|
||||
dedent`
|
||||
FOO=BAR=BAZ=QUUX
|
||||
TERM=xterm-something
|
||||
PATH=/usr/bin:/bin:/usr/sbin:/sbin:/crazy/path
|
||||
`))
|
||||
`
|
||||
)
|
||||
)
|
||||
await updateProcessEnv(process.env)
|
||||
expect(spawn.calls.length).toBe(1)
|
||||
expect(spawn.calls[0].command).toBe('/my/custom/bash')
|
||||
@@ -241,16 +283,21 @@ describe('updateProcessEnv(launchEnv)', function () {
|
||||
})
|
||||
|
||||
describe('on linux', function () {
|
||||
it('updates process.env to match the environment in the user\'s login shell', async function () {
|
||||
it("updates process.env to match the environment in the user's login shell", async function () {
|
||||
if (process.platform === 'win32') return // TestsThatFailOnWin32
|
||||
|
||||
process.platform = 'linux'
|
||||
process.env.SHELL = '/my/custom/bash'
|
||||
spawn.setDefault(spawn.simple(0, dedent`
|
||||
spawn.setDefault(
|
||||
spawn.simple(
|
||||
0,
|
||||
dedent`
|
||||
FOO=BAR=BAZ=QUUX
|
||||
TERM=xterm-something
|
||||
PATH=/usr/bin:/bin:/usr/sbin:/sbin:/crazy/path
|
||||
`))
|
||||
`
|
||||
)
|
||||
)
|
||||
await updateProcessEnv(process.env)
|
||||
expect(spawn.calls.length).toBe(1)
|
||||
expect(spawn.calls[0].command).toBe('/my/custom/bash')
|
||||
@@ -270,11 +317,11 @@ describe('updateProcessEnv(launchEnv)', function () {
|
||||
it('does not update process.env', async function () {
|
||||
process.platform = 'win32'
|
||||
spyOn(childProcess, 'spawn')
|
||||
process.env = {FOO: 'bar'}
|
||||
process.env = { FOO: 'bar' }
|
||||
|
||||
await updateProcessEnv(process.env)
|
||||
expect(childProcess.spawn).not.toHaveBeenCalled()
|
||||
expect(process.env).toEqual({FOO: 'bar'})
|
||||
expect(process.env).toEqual({ FOO: 'bar' })
|
||||
})
|
||||
})
|
||||
|
||||
@@ -283,30 +330,52 @@ describe('updateProcessEnv(launchEnv)', function () {
|
||||
if (process.platform === 'win32') return // TestsThatFailOnWin32
|
||||
|
||||
process.platform = 'darwin'
|
||||
expect(shouldGetEnvFromShell({SHELL: '/bin/sh'})).toBe(true)
|
||||
expect(shouldGetEnvFromShell({SHELL: '/usr/local/bin/sh'})).toBe(true)
|
||||
expect(shouldGetEnvFromShell({SHELL: '/bin/bash'})).toBe(true)
|
||||
expect(shouldGetEnvFromShell({SHELL: '/usr/local/bin/bash'})).toBe(true)
|
||||
expect(shouldGetEnvFromShell({SHELL: '/bin/zsh'})).toBe(true)
|
||||
expect(shouldGetEnvFromShell({SHELL: '/usr/local/bin/zsh'})).toBe(true)
|
||||
expect(shouldGetEnvFromShell({SHELL: '/bin/fish'})).toBe(true)
|
||||
expect(shouldGetEnvFromShell({SHELL: '/usr/local/bin/fish'})).toBe(true)
|
||||
expect(shouldGetEnvFromShell({ SHELL: '/bin/sh' })).toBe(true)
|
||||
expect(shouldGetEnvFromShell({ SHELL: '/usr/local/bin/sh' })).toBe(true)
|
||||
expect(shouldGetEnvFromShell({ SHELL: '/bin/bash' })).toBe(true)
|
||||
expect(shouldGetEnvFromShell({ SHELL: '/usr/local/bin/bash' })).toBe(
|
||||
true
|
||||
)
|
||||
expect(shouldGetEnvFromShell({ SHELL: '/bin/zsh' })).toBe(true)
|
||||
expect(shouldGetEnvFromShell({ SHELL: '/usr/local/bin/zsh' })).toBe(
|
||||
true
|
||||
)
|
||||
expect(shouldGetEnvFromShell({ SHELL: '/bin/fish' })).toBe(true)
|
||||
expect(shouldGetEnvFromShell({ SHELL: '/usr/local/bin/fish' })).toBe(
|
||||
true
|
||||
)
|
||||
process.platform = 'linux'
|
||||
expect(shouldGetEnvFromShell({SHELL: '/bin/sh'})).toBe(true)
|
||||
expect(shouldGetEnvFromShell({SHELL: '/usr/local/bin/sh'})).toBe(true)
|
||||
expect(shouldGetEnvFromShell({SHELL: '/bin/bash'})).toBe(true)
|
||||
expect(shouldGetEnvFromShell({SHELL: '/usr/local/bin/bash'})).toBe(true)
|
||||
expect(shouldGetEnvFromShell({SHELL: '/bin/zsh'})).toBe(true)
|
||||
expect(shouldGetEnvFromShell({SHELL: '/usr/local/bin/zsh'})).toBe(true)
|
||||
expect(shouldGetEnvFromShell({SHELL: '/bin/fish'})).toBe(true)
|
||||
expect(shouldGetEnvFromShell({SHELL: '/usr/local/bin/fish'})).toBe(true)
|
||||
expect(shouldGetEnvFromShell({ SHELL: '/bin/sh' })).toBe(true)
|
||||
expect(shouldGetEnvFromShell({ SHELL: '/usr/local/bin/sh' })).toBe(true)
|
||||
expect(shouldGetEnvFromShell({ SHELL: '/bin/bash' })).toBe(true)
|
||||
expect(shouldGetEnvFromShell({ SHELL: '/usr/local/bin/bash' })).toBe(
|
||||
true
|
||||
)
|
||||
expect(shouldGetEnvFromShell({ SHELL: '/bin/zsh' })).toBe(true)
|
||||
expect(shouldGetEnvFromShell({ SHELL: '/usr/local/bin/zsh' })).toBe(
|
||||
true
|
||||
)
|
||||
expect(shouldGetEnvFromShell({ SHELL: '/bin/fish' })).toBe(true)
|
||||
expect(shouldGetEnvFromShell({ SHELL: '/usr/local/bin/fish' })).toBe(
|
||||
true
|
||||
)
|
||||
})
|
||||
|
||||
it('returns false when the environment indicates that Atom was launched from a shell', function () {
|
||||
process.platform = 'darwin'
|
||||
expect(shouldGetEnvFromShell({ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true', SHELL: '/bin/sh'})).toBe(false)
|
||||
expect(
|
||||
shouldGetEnvFromShell({
|
||||
ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true',
|
||||
SHELL: '/bin/sh'
|
||||
})
|
||||
).toBe(false)
|
||||
process.platform = 'linux'
|
||||
expect(shouldGetEnvFromShell({ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true', SHELL: '/bin/sh'})).toBe(false)
|
||||
expect(
|
||||
shouldGetEnvFromShell({
|
||||
ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true',
|
||||
SHELL: '/bin/sh'
|
||||
})
|
||||
).toBe(false)
|
||||
})
|
||||
|
||||
it('returns false when the shell is undefined or empty', function () {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import url from 'url'
|
||||
|
||||
import {it} from './async-spec-helpers'
|
||||
import { it } from './async-spec-helpers'
|
||||
|
||||
import URIHandlerRegistry from '../src/uri-handler-registry'
|
||||
|
||||
@@ -24,11 +24,17 @@ describe('URIHandlerRegistry', () => {
|
||||
expect(otherPackageSpy).not.toHaveBeenCalled()
|
||||
|
||||
registry.handleURI('atom://test-package/path')
|
||||
expect(testPackageSpy).toHaveBeenCalledWith(url.parse('atom://test-package/path', true), 'atom://test-package/path')
|
||||
expect(testPackageSpy).toHaveBeenCalledWith(
|
||||
url.parse('atom://test-package/path', true),
|
||||
'atom://test-package/path'
|
||||
)
|
||||
expect(otherPackageSpy).not.toHaveBeenCalled()
|
||||
|
||||
registry.handleURI('atom://other-package/path')
|
||||
expect(otherPackageSpy).toHaveBeenCalledWith(url.parse('atom://other-package/path', true), 'atom://other-package/path')
|
||||
expect(otherPackageSpy).toHaveBeenCalledWith(
|
||||
url.parse('atom://other-package/path', true),
|
||||
'atom://other-package/path'
|
||||
)
|
||||
})
|
||||
|
||||
it('keeps track of the most recent URIs', () => {
|
||||
@@ -50,9 +56,18 @@ describe('URIHandlerRegistry', () => {
|
||||
uris.forEach(u => registry.handleURI(u))
|
||||
|
||||
expect(changeSpy.callCount).toBe(5)
|
||||
expect(registry.getRecentlyHandledURIs()).toEqual(uris.map((u, idx) => {
|
||||
return {id: idx + 1, uri: u, handled: !u.match(/fake/), host: url.parse(u).host}
|
||||
}).reverse())
|
||||
expect(registry.getRecentlyHandledURIs()).toEqual(
|
||||
uris
|
||||
.map((u, idx) => {
|
||||
return {
|
||||
id: idx + 1,
|
||||
uri: u,
|
||||
handled: !u.match(/fake/),
|
||||
host: url.parse(u).host
|
||||
}
|
||||
})
|
||||
.reverse()
|
||||
)
|
||||
|
||||
registry.handleURI('atom://another/url')
|
||||
expect(changeSpy.callCount).toBe(6)
|
||||
@@ -63,7 +78,7 @@ describe('URIHandlerRegistry', () => {
|
||||
})
|
||||
|
||||
it('refuses to handle bad URLs', () => {
|
||||
[
|
||||
;[
|
||||
'atom:package/path',
|
||||
'atom:8080://package/path',
|
||||
'user:pass@atom://package/path',
|
||||
|
||||
@@ -22,8 +22,7 @@ describe('ViewRegistry', () => {
|
||||
it('returns the given DOM node', () => {
|
||||
const node = document.createElement('div')
|
||||
expect(registry.getView(node)).toBe(node)
|
||||
})
|
||||
)
|
||||
}))
|
||||
|
||||
describe('when passed an object with an element property', () =>
|
||||
it("returns the element property if it's an instance of HTMLElement", () => {
|
||||
@@ -35,8 +34,7 @@ describe('ViewRegistry', () => {
|
||||
|
||||
const component = new TestComponent()
|
||||
expect(registry.getView(component)).toBe(component.element)
|
||||
})
|
||||
)
|
||||
}))
|
||||
|
||||
describe('when passed an object with a getElement function', () =>
|
||||
it("returns the return value of getElement if it's an instance of HTMLElement", () => {
|
||||
@@ -51,8 +49,7 @@ describe('ViewRegistry', () => {
|
||||
|
||||
const component = new TestComponent()
|
||||
expect(registry.getView(component)).toBe(component.myElement)
|
||||
})
|
||||
)
|
||||
}))
|
||||
|
||||
describe('when passed a model object', () => {
|
||||
describe("when a view provider is registered matching the object's constructor", () =>
|
||||
@@ -70,7 +67,7 @@ describe('ViewRegistry', () => {
|
||||
|
||||
const model = new TestModel()
|
||||
|
||||
registry.addViewProvider(TestModel, (model) =>
|
||||
registry.addViewProvider(TestModel, model =>
|
||||
new TestView().initialize(model)
|
||||
)
|
||||
|
||||
@@ -82,12 +79,11 @@ describe('ViewRegistry', () => {
|
||||
const view2 = registry.getView(subclassModel)
|
||||
expect(view2 instanceof TestView).toBe(true)
|
||||
expect(view2.model).toBe(subclassModel)
|
||||
})
|
||||
)
|
||||
}))
|
||||
|
||||
describe('when a view provider is registered generically, and works with the object', () =>
|
||||
it('constructs a view element and assigns the model on it', () => {
|
||||
registry.addViewProvider((model) => {
|
||||
registry.addViewProvider(model => {
|
||||
if (model.a === 'b') {
|
||||
const element = document.createElement('div')
|
||||
element.className = 'test-element'
|
||||
@@ -95,18 +91,16 @@ describe('ViewRegistry', () => {
|
||||
}
|
||||
})
|
||||
|
||||
const view = registry.getView({a: 'b'})
|
||||
const view = registry.getView({ a: 'b' })
|
||||
expect(view.className).toBe('test-element')
|
||||
|
||||
expect(() => registry.getView({a: 'c'})).toThrow()
|
||||
})
|
||||
)
|
||||
expect(() => registry.getView({ a: 'c' })).toThrow()
|
||||
}))
|
||||
|
||||
describe("when no view provider is registered for the object's constructor", () =>
|
||||
it('throws an exception', () => {
|
||||
expect(() => registry.getView({})).toThrow()
|
||||
})
|
||||
)
|
||||
}))
|
||||
})
|
||||
})
|
||||
|
||||
@@ -120,22 +114,23 @@ describe('ViewRegistry', () => {
|
||||
}
|
||||
}
|
||||
|
||||
const disposable = registry.addViewProvider(TestModel, (model) =>
|
||||
const disposable = registry.addViewProvider(TestModel, model =>
|
||||
new TestView().initialize(model)
|
||||
)
|
||||
|
||||
expect(registry.getView(new TestModel()) instanceof TestView).toBe(true)
|
||||
disposable.dispose()
|
||||
expect(() => registry.getView(new TestModel())).toThrow()
|
||||
})
|
||||
)
|
||||
}))
|
||||
|
||||
describe('::updateDocument(fn) and ::readDocument(fn)', () => {
|
||||
let frameRequests = null
|
||||
|
||||
beforeEach(() => {
|
||||
frameRequests = []
|
||||
spyOn(window, 'requestAnimationFrame').andCallFake(fn => frameRequests.push(fn))
|
||||
spyOn(window, 'requestAnimationFrame').andCallFake(fn =>
|
||||
frameRequests.push(fn)
|
||||
)
|
||||
})
|
||||
|
||||
it('performs all pending writes before all pending reads on the next animation frame', () => {
|
||||
@@ -201,16 +196,19 @@ describe('ViewRegistry', () => {
|
||||
let updateCalled = false
|
||||
let readCalled = false
|
||||
|
||||
waitsFor('getNextUpdatePromise to resolve', (done) => {
|
||||
waitsFor('getNextUpdatePromise to resolve', done => {
|
||||
registry.getNextUpdatePromise().then(() => {
|
||||
expect(updateCalled).toBe(true)
|
||||
expect(readCalled).toBe(true)
|
||||
done()
|
||||
})
|
||||
|
||||
registry.updateDocument(() => { updateCalled = true })
|
||||
registry.readDocument(() => { readCalled = true })
|
||||
registry.updateDocument(() => {
|
||||
updateCalled = true
|
||||
})
|
||||
registry.readDocument(() => {
|
||||
readCalled = true
|
||||
})
|
||||
})
|
||||
})
|
||||
)
|
||||
}))
|
||||
})
|
||||
|
||||
@@ -14,7 +14,10 @@ describe('WindowEventHandler', () => {
|
||||
return loadSettings
|
||||
})
|
||||
atom.project.destroy()
|
||||
windowEventHandler = new WindowEventHandler({atomEnvironment: atom, applicationDelegate: atom.applicationDelegate})
|
||||
windowEventHandler = new WindowEventHandler({
|
||||
atomEnvironment: atom,
|
||||
applicationDelegate: atom.applicationDelegate
|
||||
})
|
||||
windowEventHandler.initialize(window, document)
|
||||
})
|
||||
|
||||
@@ -25,45 +28,44 @@ describe('WindowEventHandler', () => {
|
||||
|
||||
describe('when the window is loaded', () =>
|
||||
it("doesn't have .is-blurred on the body tag", () => {
|
||||
if (process.platform === 'win32') { return } // Win32TestFailures - can not steal focus
|
||||
if (process.platform === 'win32') {
|
||||
return
|
||||
} // Win32TestFailures - can not steal focus
|
||||
expect(document.body.className).not.toMatch('is-blurred')
|
||||
})
|
||||
)
|
||||
}))
|
||||
|
||||
describe('when the window is blurred', () => {
|
||||
beforeEach(() => window.dispatchEvent(new CustomEvent('blur')))
|
||||
|
||||
afterEach(() => document.body.classList.remove('is-blurred'))
|
||||
|
||||
it('adds the .is-blurred class on the body', () => expect(document.body.className).toMatch('is-blurred'))
|
||||
it('adds the .is-blurred class on the body', () =>
|
||||
expect(document.body.className).toMatch('is-blurred'))
|
||||
|
||||
describe('when the window is focused again', () =>
|
||||
it('removes the .is-blurred class from the body', () => {
|
||||
window.dispatchEvent(new CustomEvent('focus'))
|
||||
expect(document.body.className).not.toMatch('is-blurred')
|
||||
})
|
||||
)
|
||||
}))
|
||||
})
|
||||
|
||||
|
||||
describe('resize event', () =>
|
||||
it('calls storeWindowDimensions', () => {
|
||||
spyOn(atom, 'storeWindowDimensions')
|
||||
window.dispatchEvent(new CustomEvent('resize'))
|
||||
expect(atom.storeWindowDimensions).toHaveBeenCalled()
|
||||
})
|
||||
)
|
||||
|
||||
}))
|
||||
|
||||
describe('window:close event', () =>
|
||||
it('closes the window', () => {
|
||||
spyOn(atom, 'close')
|
||||
window.dispatchEvent(new CustomEvent('window:close'))
|
||||
expect(atom.close).toHaveBeenCalled()
|
||||
})
|
||||
)
|
||||
}))
|
||||
|
||||
describe('when a link is clicked', () => {
|
||||
it('opens the http/https links in an external application', () => {
|
||||
const {shell} = require('electron')
|
||||
const { shell } = require('electron')
|
||||
spyOn(shell, 'openExternal')
|
||||
|
||||
const link = document.createElement('a')
|
||||
@@ -71,7 +73,11 @@ describe('WindowEventHandler', () => {
|
||||
link.appendChild(linkChild)
|
||||
link.href = 'http://github.com'
|
||||
jasmine.attachToDOM(link)
|
||||
const fakeEvent = {target: linkChild, currentTarget: link, preventDefault: () => {}}
|
||||
const fakeEvent = {
|
||||
target: linkChild,
|
||||
currentTarget: link,
|
||||
preventDefault: () => {}
|
||||
}
|
||||
|
||||
windowEventHandler.handleLinkClick(fakeEvent)
|
||||
expect(shell.openExternal).toHaveBeenCalled()
|
||||
@@ -104,7 +110,11 @@ describe('WindowEventHandler', () => {
|
||||
link.appendChild(linkChild)
|
||||
link.href = 'atom://github.com'
|
||||
jasmine.attachToDOM(link)
|
||||
const fakeEvent = {target: linkChild, currentTarget: link, preventDefault: () => {}}
|
||||
const fakeEvent = {
|
||||
target: linkChild,
|
||||
currentTarget: link,
|
||||
preventDefault: () => {}
|
||||
}
|
||||
|
||||
windowEventHandler.handleLinkClick(fakeEvent)
|
||||
expect(uriHandler.handleURI).toHaveBeenCalled()
|
||||
@@ -118,12 +128,13 @@ describe('WindowEventHandler', () => {
|
||||
jasmine.attachToDOM(form)
|
||||
|
||||
let defaultPrevented = false
|
||||
const event = new CustomEvent('submit', {bubbles: true})
|
||||
event.preventDefault = () => { defaultPrevented = true }
|
||||
const 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', () =>
|
||||
@@ -138,14 +149,17 @@ describe('WindowEventHandler', () => {
|
||||
const elements = wrapperDiv.firstChild
|
||||
jasmine.attachToDOM(elements)
|
||||
|
||||
elements.dispatchEvent(new CustomEvent('core:focus-next', {bubbles: true}))
|
||||
elements.dispatchEvent(
|
||||
new CustomEvent('core:focus-next', { bubbles: true })
|
||||
)
|
||||
expect(document.activeElement.tabIndex).toBe(1)
|
||||
|
||||
document.body.focus()
|
||||
elements.dispatchEvent(new CustomEvent('core:focus-previous', {bubbles: true}))
|
||||
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/lowest tabindex, skipping disabled elements', () => {
|
||||
@@ -166,60 +180,85 @@ describe('WindowEventHandler', () => {
|
||||
|
||||
elements.querySelector('[tabindex="1"]').focus()
|
||||
|
||||
elements.dispatchEvent(new CustomEvent('core:focus-next', {bubbles: true}))
|
||||
elements.dispatchEvent(
|
||||
new CustomEvent('core:focus-next', { bubbles: true })
|
||||
)
|
||||
expect(document.activeElement.tabIndex).toBe(2)
|
||||
|
||||
elements.dispatchEvent(new CustomEvent('core:focus-next', {bubbles: true}))
|
||||
elements.dispatchEvent(
|
||||
new CustomEvent('core:focus-next', { bubbles: true })
|
||||
)
|
||||
expect(document.activeElement.tabIndex).toBe(3)
|
||||
|
||||
elements.dispatchEvent(new CustomEvent('core:focus-next', {bubbles: true}))
|
||||
elements.dispatchEvent(
|
||||
new CustomEvent('core:focus-next', { bubbles: true })
|
||||
)
|
||||
expect(document.activeElement.tabIndex).toBe(5)
|
||||
|
||||
elements.dispatchEvent(new CustomEvent('core:focus-next', {bubbles: true}))
|
||||
elements.dispatchEvent(
|
||||
new CustomEvent('core:focus-next', { bubbles: true })
|
||||
)
|
||||
expect(document.activeElement.tabIndex).toBe(7)
|
||||
|
||||
elements.dispatchEvent(new CustomEvent('core:focus-next', {bubbles: true}))
|
||||
elements.dispatchEvent(
|
||||
new CustomEvent('core:focus-next', { bubbles: true })
|
||||
)
|
||||
expect(document.activeElement.tabIndex).toBe(1)
|
||||
|
||||
elements.dispatchEvent(new CustomEvent('core:focus-previous', {bubbles: true}))
|
||||
elements.dispatchEvent(
|
||||
new CustomEvent('core:focus-previous', { bubbles: true })
|
||||
)
|
||||
expect(document.activeElement.tabIndex).toBe(7)
|
||||
|
||||
elements.dispatchEvent(new CustomEvent('core:focus-previous', {bubbles: true}))
|
||||
elements.dispatchEvent(
|
||||
new CustomEvent('core:focus-previous', { bubbles: true })
|
||||
)
|
||||
expect(document.activeElement.tabIndex).toBe(5)
|
||||
|
||||
elements.dispatchEvent(new CustomEvent('core:focus-previous', {bubbles: true}))
|
||||
elements.dispatchEvent(
|
||||
new CustomEvent('core:focus-previous', { bubbles: true })
|
||||
)
|
||||
expect(document.activeElement.tabIndex).toBe(3)
|
||||
|
||||
elements.dispatchEvent(new CustomEvent('core:focus-previous', {bubbles: true}))
|
||||
elements.dispatchEvent(
|
||||
new CustomEvent('core:focus-previous', { bubbles: true })
|
||||
)
|
||||
expect(document.activeElement.tabIndex).toBe(2)
|
||||
|
||||
elements.dispatchEvent(new CustomEvent('core:focus-previous', {bubbles: true}))
|
||||
elements.dispatchEvent(
|
||||
new CustomEvent('core:focus-previous', { bubbles: true })
|
||||
)
|
||||
expect(document.activeElement.tabIndex).toBe(1)
|
||||
|
||||
elements.dispatchEvent(new CustomEvent('core:focus-previous', {bubbles: true}))
|
||||
elements.dispatchEvent(
|
||||
new CustomEvent('core:focus-previous', { bubbles: true })
|
||||
)
|
||||
expect(document.activeElement.tabIndex).toBe(7)
|
||||
})
|
||||
)
|
||||
}))
|
||||
})
|
||||
|
||||
describe('when keydown events occur on the document', () =>
|
||||
it('dispatches the event via the KeymapManager and CommandRegistry', () => {
|
||||
const dispatchedCommands = []
|
||||
atom.commands.onWillDispatch(command => dispatchedCommands.push(command))
|
||||
atom.commands.add('*', {'foo-command': () => {}})
|
||||
atom.keymaps.add('source-name', {'*': {'x': 'foo-command'}})
|
||||
atom.commands.add('*', { 'foo-command': () => {} })
|
||||
atom.keymaps.add('source-name', { '*': { x: 'foo-command' } })
|
||||
|
||||
const event = KeymapManager.buildKeydownEvent('x', {target: document.createElement('div')})
|
||||
const event = KeymapManager.buildKeydownEvent('x', {
|
||||
target: document.createElement('div')
|
||||
})
|
||||
document.dispatchEvent(event)
|
||||
|
||||
expect(dispatchedCommands.length).toBe(1)
|
||||
expect(dispatchedCommands[0].type).toBe('foo-command')
|
||||
})
|
||||
)
|
||||
}))
|
||||
|
||||
describe('native key bindings', () =>
|
||||
it("correctly dispatches them to active elements with the '.native-key-bindings' class", () => {
|
||||
const webContentsSpy = jasmine.createSpyObj('webContents', ['copy', 'paste'])
|
||||
const webContentsSpy = jasmine.createSpyObj('webContents', [
|
||||
'copy',
|
||||
'paste'
|
||||
])
|
||||
spyOn(atom.applicationDelegate, 'getCurrentWindow').andReturn({
|
||||
webContents: webContentsSpy,
|
||||
on: () => {}
|
||||
@@ -248,6 +287,5 @@ describe('WindowEventHandler', () => {
|
||||
|
||||
expect(webContentsSpy.copy).not.toHaveBeenCalled()
|
||||
expect(webContentsSpy.paste).not.toHaveBeenCalled()
|
||||
})
|
||||
)
|
||||
}))
|
||||
})
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
const TextEditor = require('../src/text-editor')
|
||||
|
||||
import {it, fit, ffit, fffit, beforeEach, afterEach} from './async-spec-helpers'
|
||||
import { it } from './async-spec-helpers'
|
||||
|
||||
describe('WorkspaceCenter', () => {
|
||||
describe('.observeTextEditors()', () => {
|
||||
@@ -12,20 +12,25 @@ describe('WorkspaceCenter', () => {
|
||||
const observed = []
|
||||
|
||||
const editorAddedBeforeRegisteringObserver = new TextEditor()
|
||||
const nonEditorItemAddedBeforeRegisteringObserver = document.createElement('div')
|
||||
const nonEditorItemAddedBeforeRegisteringObserver = document.createElement(
|
||||
'div'
|
||||
)
|
||||
pane.activateItem(editorAddedBeforeRegisteringObserver)
|
||||
pane.activateItem(nonEditorItemAddedBeforeRegisteringObserver)
|
||||
|
||||
workspaceCenter.observeTextEditors(editor => observed.push(editor))
|
||||
|
||||
const editorAddedAfterRegisteringObserver = new TextEditor()
|
||||
const nonEditorItemAddedAfterRegisteringObserver = document.createElement('div')
|
||||
const nonEditorItemAddedAfterRegisteringObserver = document.createElement(
|
||||
'div'
|
||||
)
|
||||
pane.activateItem(editorAddedAfterRegisteringObserver)
|
||||
pane.activateItem(nonEditorItemAddedAfterRegisteringObserver)
|
||||
|
||||
expect(observed).toEqual(
|
||||
[editorAddedBeforeRegisteringObserver, editorAddedAfterRegisteringObserver]
|
||||
)
|
||||
expect(observed).toEqual([
|
||||
editorAddedBeforeRegisteringObserver,
|
||||
editorAddedAfterRegisteringObserver
|
||||
])
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
/** @babel */
|
||||
|
||||
const {ipcRenderer} = require('electron')
|
||||
const { ipcRenderer } = require('electron')
|
||||
const etch = require('etch')
|
||||
const path = require('path')
|
||||
const temp = require('temp').track()
|
||||
const {Disposable} = require('event-kit')
|
||||
const {it, fit, ffit, fffit, beforeEach, afterEach} = require('./async-spec-helpers')
|
||||
const { Disposable } = require('event-kit')
|
||||
const { it, beforeEach, afterEach } = require('./async-spec-helpers')
|
||||
|
||||
const getNextUpdatePromise = () => etch.getScheduler().nextUpdatePromise
|
||||
|
||||
@@ -35,19 +35,39 @@ describe('WorkspaceElement', () => {
|
||||
const dock = atom.workspace.getLeftDock()
|
||||
dock.show()
|
||||
jasmine.attachToDOM(atom.workspace.getElement())
|
||||
expect(atom.workspace.getActivePaneContainer()).toBe(atom.workspace.getCenter())
|
||||
dock.getActivePane().getElement().focus()
|
||||
expect(atom.workspace.getActivePaneContainer()).toBe(
|
||||
atom.workspace.getCenter()
|
||||
)
|
||||
dock
|
||||
.getActivePane()
|
||||
.getElement()
|
||||
.focus()
|
||||
expect(atom.workspace.getActivePaneContainer()).toBe(dock)
|
||||
})
|
||||
})
|
||||
|
||||
describe('finding the nearest visible pane in a specific direction', () => {
|
||||
let pane1, pane2, pane3, pane4, pane5, pane6, pane7, pane8, pane9,
|
||||
leftDockPane, rightDockPane, bottomDockPane, workspace, workspaceElement
|
||||
let nearestPaneElement,
|
||||
pane1,
|
||||
pane2,
|
||||
pane3,
|
||||
pane4,
|
||||
pane5,
|
||||
pane6,
|
||||
pane7,
|
||||
pane8,
|
||||
leftDockPane,
|
||||
rightDockPane,
|
||||
bottomDockPane,
|
||||
workspace,
|
||||
workspaceElement
|
||||
|
||||
beforeEach(function () {
|
||||
atom.config.set('core.destroyEmptyPanes', false)
|
||||
expect(document.hasFocus()).toBe(true, 'Document needs to be focused to run this test')
|
||||
expect(document.hasFocus()).toBe(
|
||||
true,
|
||||
'Document needs to be focused to run this test'
|
||||
)
|
||||
|
||||
workspace = atom.workspace
|
||||
|
||||
@@ -77,7 +97,7 @@ describe('WorkspaceElement', () => {
|
||||
pane6 = pane5.splitRight()
|
||||
|
||||
pane8 = pane7.splitRight()
|
||||
pane9 = pane8.splitRight()
|
||||
pane8.splitRight()
|
||||
|
||||
const leftDock = workspace.getLeftDock()
|
||||
const rightDock = workspace.getRightDock()
|
||||
@@ -104,14 +124,20 @@ describe('WorkspaceElement', () => {
|
||||
describe('finding the nearest pane above', () => {
|
||||
describe('when there are multiple rows above the pane', () => {
|
||||
it('returns the pane in the adjacent row above', () => {
|
||||
nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection('above', pane8)
|
||||
nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection(
|
||||
'above',
|
||||
pane8
|
||||
)
|
||||
expect(nearestPaneElement).toBe(pane5.getElement())
|
||||
})
|
||||
})
|
||||
|
||||
describe('when there are no rows above the pane', () => {
|
||||
it('returns null', () => {
|
||||
nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection('above', pane2)
|
||||
nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection(
|
||||
'above',
|
||||
pane2
|
||||
)
|
||||
expect(nearestPaneElement).toBeUndefined() // TODO Expect toBeNull()
|
||||
})
|
||||
})
|
||||
@@ -119,7 +145,10 @@ describe('WorkspaceElement', () => {
|
||||
describe('when the bottom dock contains the pane', () => {
|
||||
it('returns the pane in the adjacent row above', () => {
|
||||
workspace.getBottomDock().show()
|
||||
nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection('above', bottomDockPane)
|
||||
nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection(
|
||||
'above',
|
||||
bottomDockPane
|
||||
)
|
||||
expect(nearestPaneElement).toBe(pane7.getElement())
|
||||
})
|
||||
})
|
||||
@@ -128,14 +157,20 @@ describe('WorkspaceElement', () => {
|
||||
describe('finding the nearest pane below', () => {
|
||||
describe('when there are multiple rows below the pane', () => {
|
||||
it('returns the pane in the adjacent row below', () => {
|
||||
nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection('below', pane2)
|
||||
nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection(
|
||||
'below',
|
||||
pane2
|
||||
)
|
||||
expect(nearestPaneElement).toBe(pane5.getElement())
|
||||
})
|
||||
})
|
||||
|
||||
describe('when there are no rows below the pane', () => {
|
||||
it('returns null', () => {
|
||||
nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection('below', pane8)
|
||||
nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection(
|
||||
'below',
|
||||
pane8
|
||||
)
|
||||
expect(nearestPaneElement).toBeUndefined() // TODO Expect toBeNull()
|
||||
})
|
||||
})
|
||||
@@ -144,7 +179,10 @@ describe('WorkspaceElement', () => {
|
||||
describe("when the workspace center's bottommost row contains the pane", () => {
|
||||
it("returns the pane in the bottom dock's adjacent row below", () => {
|
||||
workspace.getBottomDock().show()
|
||||
nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection('below', pane8)
|
||||
nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection(
|
||||
'below',
|
||||
pane8
|
||||
)
|
||||
expect(nearestPaneElement).toBe(bottomDockPane.getElement())
|
||||
})
|
||||
})
|
||||
@@ -154,14 +192,20 @@ describe('WorkspaceElement', () => {
|
||||
describe('finding the nearest pane to the left', () => {
|
||||
describe('when there are multiple columns to the left of the pane', () => {
|
||||
it('returns the pane in the adjacent column to the left', () => {
|
||||
nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection('left', pane6)
|
||||
nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection(
|
||||
'left',
|
||||
pane6
|
||||
)
|
||||
expect(nearestPaneElement).toBe(pane5.getElement())
|
||||
})
|
||||
})
|
||||
|
||||
describe('when there are no columns to the left of the pane', () => {
|
||||
it('returns null', () => {
|
||||
nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection('left', pane4)
|
||||
nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection(
|
||||
'left',
|
||||
pane4
|
||||
)
|
||||
expect(nearestPaneElement).toBeUndefined() // TODO Expect toBeNull()
|
||||
})
|
||||
})
|
||||
@@ -169,7 +213,10 @@ describe('WorkspaceElement', () => {
|
||||
describe('when the right dock contains the pane', () => {
|
||||
it('returns the pane in the adjacent column to the left', () => {
|
||||
workspace.getRightDock().show()
|
||||
nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection('left', rightDockPane)
|
||||
nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection(
|
||||
'left',
|
||||
rightDockPane
|
||||
)
|
||||
expect(nearestPaneElement).toBe(pane3.getElement())
|
||||
})
|
||||
})
|
||||
@@ -178,7 +225,10 @@ describe('WorkspaceElement', () => {
|
||||
describe("when the workspace center's leftmost column contains the pane", () => {
|
||||
it("returns the pane in the left dock's adjacent column to the left", () => {
|
||||
workspace.getLeftDock().show()
|
||||
nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection('left', pane4)
|
||||
nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection(
|
||||
'left',
|
||||
pane4
|
||||
)
|
||||
expect(nearestPaneElement).toBe(leftDockPane.getElement())
|
||||
})
|
||||
})
|
||||
@@ -187,7 +237,10 @@ describe('WorkspaceElement', () => {
|
||||
it("returns the pane in the left dock's adjacent column to the left", () => {
|
||||
workspace.getLeftDock().show()
|
||||
workspace.getBottomDock().show()
|
||||
nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection('left', bottomDockPane)
|
||||
nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection(
|
||||
'left',
|
||||
bottomDockPane
|
||||
)
|
||||
expect(nearestPaneElement).toBe(leftDockPane.getElement())
|
||||
})
|
||||
})
|
||||
@@ -197,14 +250,20 @@ describe('WorkspaceElement', () => {
|
||||
describe('finding the nearest pane to the right', () => {
|
||||
describe('when there are multiple columns to the right of the pane', () => {
|
||||
it('returns the pane in the adjacent column to the right', () => {
|
||||
nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection('right', pane4)
|
||||
nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection(
|
||||
'right',
|
||||
pane4
|
||||
)
|
||||
expect(nearestPaneElement).toBe(pane5.getElement())
|
||||
})
|
||||
})
|
||||
|
||||
describe('when there are no columns to the right of the pane', () => {
|
||||
it('returns null', () => {
|
||||
nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection('right', pane6)
|
||||
nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection(
|
||||
'right',
|
||||
pane6
|
||||
)
|
||||
expect(nearestPaneElement).toBeUndefined() // TODO Expect toBeNull()
|
||||
})
|
||||
})
|
||||
@@ -212,7 +271,10 @@ describe('WorkspaceElement', () => {
|
||||
describe('when the left dock contains the pane', () => {
|
||||
it('returns the pane in the adjacent column to the right', () => {
|
||||
workspace.getLeftDock().show()
|
||||
nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection('right', leftDockPane)
|
||||
nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection(
|
||||
'right',
|
||||
leftDockPane
|
||||
)
|
||||
expect(nearestPaneElement).toBe(pane1.getElement())
|
||||
})
|
||||
})
|
||||
@@ -221,7 +283,10 @@ describe('WorkspaceElement', () => {
|
||||
describe("when the workspace center's rightmost column contains the pane", () => {
|
||||
it("returns the pane in the right dock's adjacent column to the right", () => {
|
||||
workspace.getRightDock().show()
|
||||
nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection('right', pane6)
|
||||
nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection(
|
||||
'right',
|
||||
pane6
|
||||
)
|
||||
expect(nearestPaneElement).toBe(rightDockPane.getElement())
|
||||
})
|
||||
})
|
||||
@@ -230,7 +295,10 @@ describe('WorkspaceElement', () => {
|
||||
it("returns the pane in the right dock's adjacent column to the right", () => {
|
||||
workspace.getRightDock().show()
|
||||
workspace.getBottomDock().show()
|
||||
nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection('right', bottomDockPane)
|
||||
nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection(
|
||||
'right',
|
||||
bottomDockPane
|
||||
)
|
||||
expect(nearestPaneElement).toBe(rightDockPane.getElement())
|
||||
})
|
||||
})
|
||||
@@ -243,7 +311,10 @@ describe('WorkspaceElement', () => {
|
||||
|
||||
beforeEach(function () {
|
||||
atom.config.set('core.destroyEmptyPanes', false)
|
||||
expect(document.hasFocus()).toBe(true, 'Document needs to be focused to run this test')
|
||||
expect(document.hasFocus()).toBe(
|
||||
true,
|
||||
'Document needs to be focused to run this test'
|
||||
)
|
||||
|
||||
workspace = atom.workspace
|
||||
expect(workspace.getLeftDock().isVisible()).toBe(false)
|
||||
@@ -267,16 +338,14 @@ describe('WorkspaceElement', () => {
|
||||
startingPane.activate()
|
||||
workspaceElement.focusPaneViewAbove()
|
||||
expect(document.activeElement).toBe(paneAbove.getElement())
|
||||
})
|
||||
)
|
||||
}))
|
||||
|
||||
describe('when there are no rows above the focused pane', () =>
|
||||
it('keeps the current pane focused', function () {
|
||||
startingPane.activate()
|
||||
workspaceElement.focusPaneViewAbove()
|
||||
expect(document.activeElement).toBe(startingPane.getElement())
|
||||
})
|
||||
)
|
||||
}))
|
||||
})
|
||||
|
||||
describe('::focusPaneViewBelow()', function () {
|
||||
@@ -286,16 +355,14 @@ describe('WorkspaceElement', () => {
|
||||
startingPane.activate()
|
||||
workspaceElement.focusPaneViewBelow()
|
||||
expect(document.activeElement).toBe(paneBelow.getElement())
|
||||
})
|
||||
)
|
||||
}))
|
||||
|
||||
describe('when there are no rows below the focused pane', () =>
|
||||
it('keeps the current pane focused', function () {
|
||||
startingPane.activate()
|
||||
workspaceElement.focusPaneViewBelow()
|
||||
expect(document.activeElement).toBe(startingPane.getElement())
|
||||
})
|
||||
)
|
||||
}))
|
||||
})
|
||||
|
||||
describe('::focusPaneViewOnLeft()', function () {
|
||||
@@ -305,16 +372,14 @@ describe('WorkspaceElement', () => {
|
||||
startingPane.activate()
|
||||
workspaceElement.focusPaneViewOnLeft()
|
||||
expect(document.activeElement).toBe(paneOnLeft.getElement())
|
||||
})
|
||||
)
|
||||
}))
|
||||
|
||||
describe('when there are no columns to the left of the focused pane', () =>
|
||||
it('keeps the current pane focused', function () {
|
||||
startingPane.activate()
|
||||
workspaceElement.focusPaneViewOnLeft()
|
||||
expect(document.activeElement).toBe(startingPane.getElement())
|
||||
})
|
||||
)
|
||||
}))
|
||||
})
|
||||
|
||||
describe('::focusPaneViewOnRight()', function () {
|
||||
@@ -324,16 +389,14 @@ describe('WorkspaceElement', () => {
|
||||
startingPane.activate()
|
||||
workspaceElement.focusPaneViewOnRight()
|
||||
expect(document.activeElement).toBe(paneOnRight.getElement())
|
||||
})
|
||||
)
|
||||
}))
|
||||
|
||||
describe('when there are no columns to the right of the focused pane', () =>
|
||||
it('keeps the current pane focused', function () {
|
||||
startingPane.activate()
|
||||
workspaceElement.focusPaneViewOnRight()
|
||||
expect(document.activeElement).toBe(startingPane.getElement())
|
||||
})
|
||||
)
|
||||
}))
|
||||
})
|
||||
|
||||
describe('::moveActiveItemToPaneAbove(keepOriginal)', function () {
|
||||
@@ -346,8 +409,7 @@ describe('WorkspaceElement', () => {
|
||||
workspaceElement.moveActiveItemToPaneAbove()
|
||||
expect(workspace.paneForItem(item)).toBe(paneAbove)
|
||||
expect(paneAbove.getActiveItem()).toBe(item)
|
||||
})
|
||||
)
|
||||
}))
|
||||
|
||||
describe('when there are no rows above the focused pane', () =>
|
||||
it('keeps the active pane focused', function () {
|
||||
@@ -356,8 +418,7 @@ describe('WorkspaceElement', () => {
|
||||
startingPane.activateItem(item)
|
||||
workspaceElement.moveActiveItemToPaneAbove()
|
||||
expect(workspace.paneForItem(item)).toBe(startingPane)
|
||||
})
|
||||
)
|
||||
}))
|
||||
|
||||
describe('when `keepOriginal: true` is passed in the params', () =>
|
||||
it('keeps the item and adds a copy of it to the adjacent pane', function () {
|
||||
@@ -367,11 +428,10 @@ describe('WorkspaceElement', () => {
|
||||
const paneAbove = startingPane.splitUp()
|
||||
startingPane.activate()
|
||||
startingPane.activateItem(itemA)
|
||||
workspaceElement.moveActiveItemToPaneAbove({keepOriginal: true})
|
||||
workspaceElement.moveActiveItemToPaneAbove({ keepOriginal: true })
|
||||
expect(workspace.paneForItem(itemA)).toBe(startingPane)
|
||||
expect(paneAbove.getActiveItem()).toBe(itemB)
|
||||
})
|
||||
)
|
||||
}))
|
||||
})
|
||||
|
||||
describe('::moveActiveItemToPaneBelow(keepOriginal)', function () {
|
||||
@@ -384,8 +444,7 @@ describe('WorkspaceElement', () => {
|
||||
workspaceElement.moveActiveItemToPaneBelow()
|
||||
expect(workspace.paneForItem(item)).toBe(paneBelow)
|
||||
expect(paneBelow.getActiveItem()).toBe(item)
|
||||
})
|
||||
)
|
||||
}))
|
||||
|
||||
describe('when there are no rows below the focused pane', () =>
|
||||
it('keeps the active item in the focused pane', function () {
|
||||
@@ -394,8 +453,7 @@ describe('WorkspaceElement', () => {
|
||||
startingPane.activateItem(item)
|
||||
workspaceElement.moveActiveItemToPaneBelow()
|
||||
expect(workspace.paneForItem(item)).toBe(startingPane)
|
||||
})
|
||||
)
|
||||
}))
|
||||
|
||||
describe('when `keepOriginal: true` is passed in the params', () =>
|
||||
it('keeps the item and adds a copy of it to the adjacent pane', function () {
|
||||
@@ -405,11 +463,10 @@ describe('WorkspaceElement', () => {
|
||||
const paneBelow = startingPane.splitDown()
|
||||
startingPane.activate()
|
||||
startingPane.activateItem(itemA)
|
||||
workspaceElement.moveActiveItemToPaneBelow({keepOriginal: true})
|
||||
workspaceElement.moveActiveItemToPaneBelow({ keepOriginal: true })
|
||||
expect(workspace.paneForItem(itemA)).toBe(startingPane)
|
||||
expect(paneBelow.getActiveItem()).toBe(itemB)
|
||||
})
|
||||
)
|
||||
}))
|
||||
})
|
||||
|
||||
describe('::moveActiveItemToPaneOnLeft(keepOriginal)', function () {
|
||||
@@ -422,8 +479,7 @@ describe('WorkspaceElement', () => {
|
||||
workspaceElement.moveActiveItemToPaneOnLeft()
|
||||
expect(workspace.paneForItem(item)).toBe(paneOnLeft)
|
||||
expect(paneOnLeft.getActiveItem()).toBe(item)
|
||||
})
|
||||
)
|
||||
}))
|
||||
|
||||
describe('when there are no columns to the left of the focused pane', () =>
|
||||
it('keeps the active item in the focused pane', function () {
|
||||
@@ -432,8 +488,7 @@ describe('WorkspaceElement', () => {
|
||||
startingPane.activateItem(item)
|
||||
workspaceElement.moveActiveItemToPaneOnLeft()
|
||||
expect(workspace.paneForItem(item)).toBe(startingPane)
|
||||
})
|
||||
)
|
||||
}))
|
||||
|
||||
describe('when `keepOriginal: true` is passed in the params', () =>
|
||||
it('keeps the item and adds a copy of it to the adjacent pane', function () {
|
||||
@@ -443,11 +498,10 @@ describe('WorkspaceElement', () => {
|
||||
const paneOnLeft = startingPane.splitLeft()
|
||||
startingPane.activate()
|
||||
startingPane.activateItem(itemA)
|
||||
workspaceElement.moveActiveItemToPaneOnLeft({keepOriginal: true})
|
||||
workspaceElement.moveActiveItemToPaneOnLeft({ keepOriginal: true })
|
||||
expect(workspace.paneForItem(itemA)).toBe(startingPane)
|
||||
expect(paneOnLeft.getActiveItem()).toBe(itemB)
|
||||
})
|
||||
)
|
||||
}))
|
||||
})
|
||||
|
||||
describe('::moveActiveItemToPaneOnRight(keepOriginal)', function () {
|
||||
@@ -460,8 +514,7 @@ describe('WorkspaceElement', () => {
|
||||
workspaceElement.moveActiveItemToPaneOnRight()
|
||||
expect(workspace.paneForItem(item)).toBe(paneOnRight)
|
||||
expect(paneOnRight.getActiveItem()).toBe(item)
|
||||
})
|
||||
)
|
||||
}))
|
||||
|
||||
describe('when there are no columns to the right of the focused pane', () =>
|
||||
it('keeps the active item in the focused pane', function () {
|
||||
@@ -470,8 +523,7 @@ describe('WorkspaceElement', () => {
|
||||
startingPane.activateItem(item)
|
||||
workspaceElement.moveActiveItemToPaneOnRight()
|
||||
expect(workspace.paneForItem(item)).toBe(startingPane)
|
||||
})
|
||||
)
|
||||
}))
|
||||
|
||||
describe('when `keepOriginal: true` is passed in the params', () =>
|
||||
it('keeps the item and adds a copy of it to the adjacent pane', function () {
|
||||
@@ -481,11 +533,10 @@ describe('WorkspaceElement', () => {
|
||||
const paneOnRight = startingPane.splitRight()
|
||||
startingPane.activate()
|
||||
startingPane.activateItem(itemA)
|
||||
workspaceElement.moveActiveItemToPaneOnRight({keepOriginal: true})
|
||||
workspaceElement.moveActiveItemToPaneOnRight({ keepOriginal: true })
|
||||
expect(workspace.paneForItem(itemA)).toBe(startingPane)
|
||||
expect(paneOnRight.getActiveItem()).toBe(itemB)
|
||||
})
|
||||
)
|
||||
}))
|
||||
})
|
||||
|
||||
describe('::moveActiveItemToNearestPaneInDirection(direction, params)', () => {
|
||||
@@ -499,10 +550,14 @@ describe('WorkspaceElement', () => {
|
||||
workspace.getBottomDock().show()
|
||||
startingPane.activate()
|
||||
startingPane.activateItem(item)
|
||||
workspaceElement.moveActiveItemToNearestPaneInDirection('below', {keepOriginal: false})
|
||||
workspaceElement.moveActiveItemToNearestPaneInDirection('below', {
|
||||
keepOriginal: false
|
||||
})
|
||||
expect(workspace.paneForItem(item)).toBe(startingPane)
|
||||
|
||||
workspaceElement.moveActiveItemToNearestPaneInDirection('below', {keepOriginal: true})
|
||||
workspaceElement.moveActiveItemToNearestPaneInDirection('below', {
|
||||
keepOriginal: true
|
||||
})
|
||||
expect(workspace.paneForItem(item)).toBe(startingPane)
|
||||
})
|
||||
})
|
||||
@@ -516,7 +571,9 @@ describe('WorkspaceElement', () => {
|
||||
startingPane.activate()
|
||||
startingPane.activateItem(item)
|
||||
workspaceElement.focusPaneViewAbove()
|
||||
workspaceElement.moveActiveItemToNearestPaneInDirection('below', {keepOriginal: true})
|
||||
workspaceElement.moveActiveItemToNearestPaneInDirection('below', {
|
||||
keepOriginal: true
|
||||
})
|
||||
expect(workspace.paneForItem(item)).toBe(startingPane)
|
||||
expect(paneBelow.getItems().length).toEqual(0)
|
||||
})
|
||||
@@ -538,18 +595,30 @@ describe('WorkspaceElement', () => {
|
||||
await Promise.all([
|
||||
atom.workspace.open({
|
||||
element: document.createElement('div'),
|
||||
getDefaultLocation() { return 'left' },
|
||||
getPreferredWidth() { return 150 }
|
||||
getDefaultLocation () {
|
||||
return 'left'
|
||||
},
|
||||
getPreferredWidth () {
|
||||
return 150
|
||||
}
|
||||
}),
|
||||
atom.workspace.open({
|
||||
element: document.createElement('div'),
|
||||
getDefaultLocation() { return 'right' },
|
||||
getPreferredWidth() { return 150 }
|
||||
getDefaultLocation () {
|
||||
return 'right'
|
||||
},
|
||||
getPreferredWidth () {
|
||||
return 150
|
||||
}
|
||||
}),
|
||||
atom.workspace.open({
|
||||
element: document.createElement('div'),
|
||||
getDefaultLocation() { return 'bottom' },
|
||||
getPreferredHeight() { return 100 }
|
||||
getDefaultLocation () {
|
||||
return 'bottom'
|
||||
},
|
||||
getPreferredHeight () {
|
||||
return 100
|
||||
}
|
||||
})
|
||||
])
|
||||
|
||||
@@ -567,21 +636,21 @@ describe('WorkspaceElement', () => {
|
||||
// --- Right Dock ---
|
||||
|
||||
// Mouse over where the toggle button would be if the dock were hovered
|
||||
moveMouse({clientX: 440, clientY: 150})
|
||||
moveMouse({ clientX: 440, clientY: 150 })
|
||||
await getNextUpdatePromise()
|
||||
expectToggleButtonHidden(leftDock)
|
||||
expectToggleButtonHidden(rightDock)
|
||||
expectToggleButtonHidden(bottomDock)
|
||||
|
||||
// Mouse over the dock
|
||||
moveMouse({clientX: 460, clientY: 150})
|
||||
moveMouse({ clientX: 460, clientY: 150 })
|
||||
await getNextUpdatePromise()
|
||||
expectToggleButtonHidden(leftDock)
|
||||
expectToggleButtonVisible(rightDock, 'icon-chevron-right')
|
||||
expectToggleButtonHidden(bottomDock)
|
||||
|
||||
// Mouse over the toggle button
|
||||
moveMouse({clientX: 440, clientY: 150})
|
||||
moveMouse({ clientX: 440, clientY: 150 })
|
||||
await getNextUpdatePromise()
|
||||
expectToggleButtonHidden(leftDock)
|
||||
expectToggleButtonVisible(rightDock, 'icon-chevron-right')
|
||||
@@ -594,10 +663,10 @@ describe('WorkspaceElement', () => {
|
||||
expectToggleButtonHidden(rightDock)
|
||||
|
||||
// Mouse to edge of the window
|
||||
moveMouse({clientX: 575, clientY: 150})
|
||||
moveMouse({ clientX: 575, clientY: 150 })
|
||||
await getNextUpdatePromise()
|
||||
expectToggleButtonHidden(rightDock)
|
||||
moveMouse({clientX: 598, clientY: 150})
|
||||
moveMouse({ clientX: 598, clientY: 150 })
|
||||
await getNextUpdatePromise()
|
||||
expectToggleButtonVisible(rightDock, 'icon-chevron-left')
|
||||
|
||||
@@ -610,21 +679,21 @@ describe('WorkspaceElement', () => {
|
||||
// --- Left Dock ---
|
||||
|
||||
// Mouse over where the toggle button would be if the dock were hovered
|
||||
moveMouse({clientX: 160, clientY: 150})
|
||||
moveMouse({ clientX: 160, clientY: 150 })
|
||||
await getNextUpdatePromise()
|
||||
expectToggleButtonHidden(leftDock)
|
||||
expectToggleButtonHidden(rightDock)
|
||||
expectToggleButtonHidden(bottomDock)
|
||||
|
||||
// Mouse over the dock
|
||||
moveMouse({clientX: 140, clientY: 150})
|
||||
moveMouse({ clientX: 140, clientY: 150 })
|
||||
await getNextUpdatePromise()
|
||||
expectToggleButtonVisible(leftDock, 'icon-chevron-left')
|
||||
expectToggleButtonHidden(rightDock)
|
||||
expectToggleButtonHidden(bottomDock)
|
||||
|
||||
// Mouse over the toggle button
|
||||
moveMouse({clientX: 160, clientY: 150})
|
||||
moveMouse({ clientX: 160, clientY: 150 })
|
||||
await getNextUpdatePromise()
|
||||
expectToggleButtonVisible(leftDock, 'icon-chevron-left')
|
||||
expectToggleButtonHidden(rightDock)
|
||||
@@ -637,10 +706,10 @@ describe('WorkspaceElement', () => {
|
||||
expectToggleButtonHidden(leftDock)
|
||||
|
||||
// Mouse to edge of the window
|
||||
moveMouse({clientX: 25, clientY: 150})
|
||||
moveMouse({ clientX: 25, clientY: 150 })
|
||||
await getNextUpdatePromise()
|
||||
expectToggleButtonHidden(leftDock)
|
||||
moveMouse({clientX: 2, clientY: 150})
|
||||
moveMouse({ clientX: 2, clientY: 150 })
|
||||
await getNextUpdatePromise()
|
||||
expectToggleButtonVisible(leftDock, 'icon-chevron-right')
|
||||
|
||||
@@ -653,21 +722,21 @@ describe('WorkspaceElement', () => {
|
||||
// --- Bottom Dock ---
|
||||
|
||||
// Mouse over where the toggle button would be if the dock were hovered
|
||||
moveMouse({clientX: 300, clientY: 190})
|
||||
moveMouse({ clientX: 300, clientY: 190 })
|
||||
await getNextUpdatePromise()
|
||||
expectToggleButtonHidden(leftDock)
|
||||
expectToggleButtonHidden(rightDock)
|
||||
expectToggleButtonHidden(bottomDock)
|
||||
|
||||
// Mouse over the dock
|
||||
moveMouse({clientX: 300, clientY: 210})
|
||||
moveMouse({ clientX: 300, clientY: 210 })
|
||||
await getNextUpdatePromise()
|
||||
expectToggleButtonHidden(leftDock)
|
||||
expectToggleButtonHidden(rightDock)
|
||||
expectToggleButtonVisible(bottomDock, 'icon-chevron-down')
|
||||
|
||||
// Mouse over the toggle button
|
||||
moveMouse({clientX: 300, clientY: 195})
|
||||
moveMouse({ clientX: 300, clientY: 195 })
|
||||
await getNextUpdatePromise()
|
||||
expectToggleButtonHidden(leftDock)
|
||||
expectToggleButtonHidden(rightDock)
|
||||
@@ -680,10 +749,10 @@ describe('WorkspaceElement', () => {
|
||||
expectToggleButtonHidden(bottomDock)
|
||||
|
||||
// Mouse to edge of the window
|
||||
moveMouse({clientX: 300, clientY: 290})
|
||||
moveMouse({ clientX: 300, clientY: 290 })
|
||||
await getNextUpdatePromise()
|
||||
expectToggleButtonHidden(leftDock)
|
||||
moveMouse({clientX: 300, clientY: 299})
|
||||
moveMouse({ clientX: 300, clientY: 299 })
|
||||
await getNextUpdatePromise()
|
||||
expectToggleButtonVisible(bottomDock, 'icon-chevron-up')
|
||||
|
||||
@@ -699,12 +768,16 @@ describe('WorkspaceElement', () => {
|
||||
advanceClock(100)
|
||||
}
|
||||
|
||||
function expectToggleButtonHidden(dock) {
|
||||
expect(dock.refs.toggleButton.element).not.toHaveClass('atom-dock-toggle-button-visible')
|
||||
function expectToggleButtonHidden (dock) {
|
||||
expect(dock.refs.toggleButton.element).not.toHaveClass(
|
||||
'atom-dock-toggle-button-visible'
|
||||
)
|
||||
}
|
||||
|
||||
function expectToggleButtonVisible(dock, iconClass) {
|
||||
expect(dock.refs.toggleButton.element).toHaveClass('atom-dock-toggle-button-visible')
|
||||
function expectToggleButtonVisible (dock, iconClass) {
|
||||
expect(dock.refs.toggleButton.element).toHaveClass(
|
||||
'atom-dock-toggle-button-visible'
|
||||
)
|
||||
expect(dock.refs.toggleButton.refs.iconElement).toHaveClass(iconClass)
|
||||
}
|
||||
})
|
||||
@@ -713,10 +786,12 @@ describe('WorkspaceElement', () => {
|
||||
it('has a class based on the style of the scrollbar', () => {
|
||||
let observeCallback
|
||||
const scrollbarStyle = require('scrollbar-style')
|
||||
spyOn(scrollbarStyle, 'observePreferredScrollbarStyle').andCallFake(cb => {
|
||||
observeCallback = cb
|
||||
return new Disposable(() => {})
|
||||
})
|
||||
spyOn(scrollbarStyle, 'observePreferredScrollbarStyle').andCallFake(
|
||||
cb => {
|
||||
observeCallback = cb
|
||||
return new Disposable(() => {})
|
||||
}
|
||||
)
|
||||
|
||||
const workspaceElement = atom.workspace.getElement()
|
||||
observeCallback('legacy')
|
||||
@@ -741,11 +816,15 @@ describe('WorkspaceElement', () => {
|
||||
|
||||
it("updates the font-size based on the 'editor.fontSize' config value", async () => {
|
||||
const initialCharWidth = editor.getDefaultCharWidth()
|
||||
expect(getComputedStyle(editorElement).fontSize).toBe(atom.config.get('editor.fontSize') + 'px')
|
||||
expect(getComputedStyle(editorElement).fontSize).toBe(
|
||||
atom.config.get('editor.fontSize') + 'px'
|
||||
)
|
||||
|
||||
atom.config.set('editor.fontSize', atom.config.get('editor.fontSize') + 5)
|
||||
await editorElement.component.getNextUpdatePromise()
|
||||
expect(getComputedStyle(editorElement).fontSize).toBe(atom.config.get('editor.fontSize') + 'px')
|
||||
expect(getComputedStyle(editorElement).fontSize).toBe(
|
||||
atom.config.get('editor.fontSize') + 'px'
|
||||
)
|
||||
expect(editor.getDefaultCharWidth()).toBeGreaterThan(initialCharWidth)
|
||||
})
|
||||
|
||||
@@ -765,7 +844,9 @@ describe('WorkspaceElement', () => {
|
||||
const initialLineHeight = editor.getLineHeightInPixels()
|
||||
atom.config.set('editor.lineHeight', '30px')
|
||||
await editorElement.component.getNextUpdatePromise()
|
||||
expect(getComputedStyle(editorElement).lineHeight).toBe(atom.config.get('editor.lineHeight'))
|
||||
expect(getComputedStyle(editorElement).lineHeight).toBe(
|
||||
atom.config.get('editor.lineHeight')
|
||||
)
|
||||
expect(editor.getLineHeightInPixels()).not.toBe(initialLineHeight)
|
||||
})
|
||||
|
||||
@@ -774,37 +855,47 @@ describe('WorkspaceElement', () => {
|
||||
atom.config.set('editor.fontSize', 12)
|
||||
|
||||
// Zoom out
|
||||
editorElement.querySelector('span').dispatchEvent(new WheelEvent('mousewheel', {
|
||||
wheelDeltaY: -10,
|
||||
ctrlKey: true
|
||||
}))
|
||||
editorElement.querySelector('span').dispatchEvent(
|
||||
new WheelEvent('mousewheel', {
|
||||
wheelDeltaY: -10,
|
||||
ctrlKey: true
|
||||
})
|
||||
)
|
||||
expect(atom.config.get('editor.fontSize')).toBe(11)
|
||||
|
||||
// Zoom in
|
||||
editorElement.querySelector('span').dispatchEvent(new WheelEvent('mousewheel', {
|
||||
wheelDeltaY: 10,
|
||||
ctrlKey: true
|
||||
}))
|
||||
editorElement.querySelector('span').dispatchEvent(
|
||||
new WheelEvent('mousewheel', {
|
||||
wheelDeltaY: 10,
|
||||
ctrlKey: true
|
||||
})
|
||||
)
|
||||
expect(atom.config.get('editor.fontSize')).toBe(12)
|
||||
|
||||
// Not on an atom-text-editor
|
||||
workspaceElement.dispatchEvent(new WheelEvent('mousewheel', {
|
||||
wheelDeltaY: 10,
|
||||
ctrlKey: true
|
||||
}))
|
||||
workspaceElement.dispatchEvent(
|
||||
new WheelEvent('mousewheel', {
|
||||
wheelDeltaY: 10,
|
||||
ctrlKey: true
|
||||
})
|
||||
)
|
||||
expect(atom.config.get('editor.fontSize')).toBe(12)
|
||||
|
||||
// No ctrl key
|
||||
editorElement.querySelector('span').dispatchEvent(new WheelEvent('mousewheel', {
|
||||
wheelDeltaY: 10
|
||||
}))
|
||||
editorElement.querySelector('span').dispatchEvent(
|
||||
new WheelEvent('mousewheel', {
|
||||
wheelDeltaY: 10
|
||||
})
|
||||
)
|
||||
expect(atom.config.get('editor.fontSize')).toBe(12)
|
||||
|
||||
atom.config.set('editor.zoomFontWhenCtrlScrolling', false)
|
||||
editorElement.querySelector('span').dispatchEvent(new WheelEvent('mousewheel', {
|
||||
wheelDeltaY: 10,
|
||||
ctrlKey: true
|
||||
}))
|
||||
editorElement.querySelector('span').dispatchEvent(
|
||||
new WheelEvent('mousewheel', {
|
||||
wheelDeltaY: 10,
|
||||
ctrlKey: true
|
||||
})
|
||||
)
|
||||
expect(atom.config.get('editor.fontSize')).toBe(12)
|
||||
})
|
||||
})
|
||||
@@ -813,22 +904,40 @@ describe('WorkspaceElement', () => {
|
||||
it('inserts panel container elements in the correct places in the DOM', () => {
|
||||
const workspaceElement = atom.workspace.getElement()
|
||||
|
||||
const leftContainer = workspaceElement.querySelector('atom-panel-container.left')
|
||||
const rightContainer = workspaceElement.querySelector('atom-panel-container.right')
|
||||
const leftContainer = workspaceElement.querySelector(
|
||||
'atom-panel-container.left'
|
||||
)
|
||||
const rightContainer = workspaceElement.querySelector(
|
||||
'atom-panel-container.right'
|
||||
)
|
||||
expect(leftContainer.nextSibling).toBe(workspaceElement.verticalAxis)
|
||||
expect(rightContainer.previousSibling).toBe(workspaceElement.verticalAxis)
|
||||
|
||||
const topContainer = workspaceElement.querySelector('atom-panel-container.top')
|
||||
const bottomContainer = workspaceElement.querySelector('atom-panel-container.bottom')
|
||||
const topContainer = workspaceElement.querySelector(
|
||||
'atom-panel-container.top'
|
||||
)
|
||||
const bottomContainer = workspaceElement.querySelector(
|
||||
'atom-panel-container.bottom'
|
||||
)
|
||||
expect(topContainer.nextSibling).toBe(workspaceElement.paneContainer)
|
||||
expect(bottomContainer.previousSibling).toBe(workspaceElement.paneContainer)
|
||||
expect(bottomContainer.previousSibling).toBe(
|
||||
workspaceElement.paneContainer
|
||||
)
|
||||
|
||||
const headerContainer = workspaceElement.querySelector('atom-panel-container.header')
|
||||
const footerContainer = workspaceElement.querySelector('atom-panel-container.footer')
|
||||
const headerContainer = workspaceElement.querySelector(
|
||||
'atom-panel-container.header'
|
||||
)
|
||||
const footerContainer = workspaceElement.querySelector(
|
||||
'atom-panel-container.footer'
|
||||
)
|
||||
expect(headerContainer.nextSibling).toBe(workspaceElement.horizontalAxis)
|
||||
expect(footerContainer.previousSibling).toBe(workspaceElement.horizontalAxis)
|
||||
expect(footerContainer.previousSibling).toBe(
|
||||
workspaceElement.horizontalAxis
|
||||
)
|
||||
|
||||
const modalContainer = workspaceElement.querySelector('atom-panel-container.modal')
|
||||
const modalContainer = workspaceElement.querySelector(
|
||||
'atom-panel-container.modal'
|
||||
)
|
||||
expect(modalContainer.parentNode).toBe(workspaceElement)
|
||||
})
|
||||
|
||||
@@ -838,18 +947,20 @@ describe('WorkspaceElement', () => {
|
||||
expect(workspaceElement.offsetWidth).toBeGreaterThan(0)
|
||||
|
||||
const headerItem = document.createElement('div')
|
||||
atom.workspace.addHeaderPanel({item: headerItem})
|
||||
atom.workspace.addHeaderPanel({ item: headerItem })
|
||||
expect(headerItem.offsetWidth).toEqual(workspaceElement.offsetWidth)
|
||||
|
||||
const footerItem = document.createElement('div')
|
||||
atom.workspace.addFooterPanel({item: footerItem})
|
||||
atom.workspace.addFooterPanel({ item: footerItem })
|
||||
expect(footerItem.offsetWidth).toEqual(workspaceElement.offsetWidth)
|
||||
})
|
||||
|
||||
it('shrinks horizontal axis according to header/footer panels height', () => {
|
||||
const workspaceElement = atom.workspace.getElement()
|
||||
workspaceElement.style.height = '100px'
|
||||
const horizontalAxisElement = workspaceElement.querySelector('atom-workspace-axis.horizontal')
|
||||
const horizontalAxisElement = workspaceElement.querySelector(
|
||||
'atom-workspace-axis.horizontal'
|
||||
)
|
||||
jasmine.attachToDOM(workspaceElement)
|
||||
|
||||
const originalHorizontalAxisHeight = horizontalAxisElement.offsetHeight
|
||||
@@ -858,15 +969,19 @@ describe('WorkspaceElement', () => {
|
||||
|
||||
const headerItem = document.createElement('div')
|
||||
headerItem.style.height = '10px'
|
||||
atom.workspace.addHeaderPanel({item: headerItem})
|
||||
atom.workspace.addHeaderPanel({ item: headerItem })
|
||||
expect(headerItem.offsetHeight).toBeGreaterThan(0)
|
||||
|
||||
const footerItem = document.createElement('div')
|
||||
footerItem.style.height = '15px'
|
||||
atom.workspace.addFooterPanel({item: footerItem})
|
||||
atom.workspace.addFooterPanel({ item: footerItem })
|
||||
expect(footerItem.offsetHeight).toBeGreaterThan(0)
|
||||
|
||||
expect(horizontalAxisElement.offsetHeight).toEqual(originalHorizontalAxisHeight - headerItem.offsetHeight - footerItem.offsetHeight)
|
||||
expect(horizontalAxisElement.offsetHeight).toEqual(
|
||||
originalHorizontalAxisHeight -
|
||||
headerItem.offsetHeight -
|
||||
footerItem.offsetHeight
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -895,39 +1010,60 @@ describe('WorkspaceElement', () => {
|
||||
|
||||
// No active item. Use first project directory.
|
||||
atom.commands.dispatch(workspaceElement, 'window:run-package-specs')
|
||||
expect(ipcRenderer.send).toHaveBeenCalledWith('run-package-specs', path.join(projectPaths[0], 'spec'), {})
|
||||
expect(ipcRenderer.send).toHaveBeenCalledWith(
|
||||
'run-package-specs',
|
||||
path.join(projectPaths[0], 'spec'),
|
||||
{}
|
||||
)
|
||||
ipcRenderer.send.reset()
|
||||
|
||||
// Active item doesn't implement ::getPath(). Use first project directory.
|
||||
const item = document.createElement('div')
|
||||
atom.workspace.getActivePane().activateItem(item)
|
||||
atom.commands.dispatch(workspaceElement, 'window:run-package-specs')
|
||||
expect(ipcRenderer.send).toHaveBeenCalledWith('run-package-specs', path.join(projectPaths[0], 'spec'), {})
|
||||
expect(ipcRenderer.send).toHaveBeenCalledWith(
|
||||
'run-package-specs',
|
||||
path.join(projectPaths[0], 'spec'),
|
||||
{}
|
||||
)
|
||||
ipcRenderer.send.reset()
|
||||
|
||||
// Active item has no path. Use first project directory.
|
||||
item.getPath = () => null
|
||||
atom.commands.dispatch(workspaceElement, 'window:run-package-specs')
|
||||
expect(ipcRenderer.send).toHaveBeenCalledWith('run-package-specs', path.join(projectPaths[0], 'spec'), {})
|
||||
expect(ipcRenderer.send).toHaveBeenCalledWith(
|
||||
'run-package-specs',
|
||||
path.join(projectPaths[0], 'spec'),
|
||||
{}
|
||||
)
|
||||
ipcRenderer.send.reset()
|
||||
|
||||
// Active item has path. Use project path for item path.
|
||||
item.getPath = () => path.join(projectPaths[1], 'a-file.txt')
|
||||
atom.commands.dispatch(workspaceElement, 'window:run-package-specs')
|
||||
expect(ipcRenderer.send).toHaveBeenCalledWith('run-package-specs', path.join(projectPaths[1], 'spec'), {})
|
||||
expect(ipcRenderer.send).toHaveBeenCalledWith(
|
||||
'run-package-specs',
|
||||
path.join(projectPaths[1], 'spec'),
|
||||
{}
|
||||
)
|
||||
ipcRenderer.send.reset()
|
||||
})
|
||||
|
||||
it("passes additional options to the spec window", () => {
|
||||
it('passes additional options to the spec window', () => {
|
||||
const workspaceElement = atom.workspace.getElement()
|
||||
spyOn(ipcRenderer, 'send')
|
||||
|
||||
const projectPath = temp.mkdirSync('dir1-')
|
||||
atom.project.setPaths([projectPath])
|
||||
workspaceElement.runPackageSpecs({env: {ATOM_GITHUB_BABEL_ENV: 'coverage'}})
|
||||
workspaceElement.runPackageSpecs({
|
||||
env: { ATOM_GITHUB_BABEL_ENV: 'coverage' }
|
||||
})
|
||||
|
||||
expect(ipcRenderer.send).toHaveBeenCalledWith(
|
||||
'run-package-specs', path.join(projectPath, 'spec'), {env: {ATOM_GITHUB_BABEL_ENV: 'coverage'}})
|
||||
'run-package-specs',
|
||||
path.join(projectPath, 'spec'),
|
||||
{ env: { ATOM_GITHUB_BABEL_ENV: 'coverage' } }
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user